diff options
Diffstat (limited to 'source/Plugins')
525 files changed, 19647 insertions, 14855 deletions
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp index e0e293d7ae68..9055660f2d6c 100644 --- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp +++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp @@ -9,19 +9,13 @@ #include "ABIMacOSX_arm.h" -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Symbol/UnwindPlan.h" @@ -30,6 +24,8 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/ConstString.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" #include "Plugins/Process/Utility/ARMDefines.h" @@ -1327,16 +1323,13 @@ size_t ABIMacOSX_arm::GetRedZoneSize() const { return 0; } ABISP ABIMacOSX_arm::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; 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::arm) || (arch_type == llvm::Triple::thumb)) { - if (!g_abi_sp) - g_abi_sp.reset(new ABIMacOSX_arm(process_sp)); - return g_abi_sp; + return ABISP(new ABIMacOSX_arm(process_sp)); } } @@ -1477,14 +1470,16 @@ bool ABIMacOSX_arm::GetArgumentValues(Thread &thread, ValueList &values) const { if (compiler_type) { bool is_signed = false; size_t bit_width = 0; - if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - bit_width = compiler_type.GetBitSize(&thread); - } else if (compiler_type.IsPointerOrReferenceType()) { - bit_width = compiler_type.GetBitSize(&thread); - } else { + llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread); + if (!bit_size) + return false; + if (compiler_type.IsIntegerOrEnumerationType(is_signed)) + bit_width = *bit_size; + else if (compiler_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 < 4) { @@ -1581,9 +1576,11 @@ ValueObjectSP ABIMacOSX_arm::GetReturnValueObjectImpl( const RegisterInfo *r0_reg_info = reg_ctx->GetRegisterInfoByName("r0", 0); if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - size_t bit_width = compiler_type.GetBitSize(&thread); + llvm::Optional<uint64_t> bit_width = compiler_type.GetBitSize(&thread); + if (!bit_width) + return return_valobj_sp; - switch (bit_width) { + switch (*bit_width) { default: return return_valobj_sp; case 128: @@ -1599,14 +1596,17 @@ ValueObjectSP ABIMacOSX_arm::GetReturnValueObjectImpl( const RegisterInfo *r3_reg_info = reg_ctx->GetRegisterInfoByName("r3", 0); if (r1_reg_info && r2_reg_info && r3_reg_info) { - const size_t byte_size = compiler_type.GetByteSize(&thread); + llvm::Optional<uint64_t> byte_size = + compiler_type.GetByteSize(&thread); + if (!byte_size) + return return_valobj_sp; ProcessSP process_sp(thread.GetProcess()); - if (byte_size <= r0_reg_info->byte_size + r1_reg_info->byte_size + - r2_reg_info->byte_size + - r3_reg_info->byte_size && + if (*byte_size <= r0_reg_info->byte_size + r1_reg_info->byte_size + + r2_reg_info->byte_size + + r3_reg_info->byte_size && process_sp) { std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = process_sp->GetByteOrder(); RegisterValue r0_reg_value; RegisterValue r1_reg_value; diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h index d3c20e1e618f..94f1e31a1235 100644 --- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h +++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABIMacOSX_arm_h_ #define liblldb_ABIMacOSX_arm_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp index 85f864ec7561..d8706c4a9cdd 100644 --- a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp +++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp @@ -9,18 +9,13 @@ #include "ABIMacOSX_arm64.h" -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Symbol/UnwindPlan.h" @@ -30,6 +25,8 @@ #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" @@ -1667,15 +1664,12 @@ size_t ABIMacOSX_arm64::GetRedZoneSize() const { return 128; } ABISP ABIMacOSX_arm64::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; 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) { - if (!g_abi_sp) - g_abi_sp.reset(new ABIMacOSX_arm64(process_sp)); - return g_abi_sp; + return ABISP(new ABIMacOSX_arm64(process_sp)); } } @@ -1768,90 +1762,92 @@ bool ABIMacOSX_arm64::GetArgumentValues(Thread &thread, return false; CompilerType value_type = value->GetCompilerType(); - if (value_type) { - bool is_signed = false; - size_t bit_width = 0; - if (value_type.IsIntegerOrEnumerationType(is_signed)) { - bit_width = value_type.GetBitSize(&thread); - } else if (value_type.IsPointerOrReferenceType()) { - bit_width = value_type.GetBitSize(&thread); - } else { - // We only handle integer, pointer and reference types currently... - return false; - } + llvm::Optional<uint64_t> bit_size = value_type.GetBitSize(&thread); + if (!bit_size) + 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; - } + 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_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) + 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; } - - // 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; + } 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; + } - sp += arg_byte_size; - // Align up to the next 8 byte boundary if needed - if (sp % 8) { - sp >>= 3; - sp += 1; - sp <<= 3; - } + // 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; } } } @@ -2115,13 +2111,12 @@ static bool LoadValueFromConsecutiveGPRRegisters( uint32_t &NGRN, // NGRN (see ABI documentation) uint32_t &NSRN, // NSRN (see ABI documentation) DataExtractor &data) { - const size_t byte_size = value_type.GetByteSize(nullptr); - - if (byte_size == 0) + llvm::Optional<uint64_t> byte_size = value_type.GetByteSize(nullptr); + if (!byte_size || *byte_size == 0) return false; std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); Status error; @@ -2133,7 +2128,9 @@ static bool LoadValueFromConsecutiveGPRRegisters( if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) { if (!base_type) return false; - const size_t base_byte_size = base_type.GetByteSize(nullptr); + 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) { @@ -2144,7 +2141,7 @@ static bool LoadValueFromConsecutiveGPRRegisters( if (reg_info == nullptr) return false; - if (base_byte_size > reg_info->byte_size) + if (*base_byte_size > reg_info->byte_size) return false; RegisterValue reg_value; @@ -2153,11 +2150,11 @@ static bool LoadValueFromConsecutiveGPRRegisters( return false; // Make sure we have enough room in "heap_data_ap" - if ((data_offset + base_byte_size) <= heap_data_ap->GetByteSize()) { + if ((data_offset + *base_byte_size) <= heap_data_ap->GetByteSize()) { const size_t bytes_copied = reg_value.GetAsMemoryData( - reg_info, heap_data_ap->GetBytes() + data_offset, base_byte_size, + reg_info, heap_data_ap->GetBytes() + data_offset, *base_byte_size, byte_order, error); - if (bytes_copied != base_byte_size) + if (bytes_copied != *base_byte_size) return false; data_offset += bytes_copied; ++NSRN; @@ -2172,10 +2169,10 @@ static bool LoadValueFromConsecutiveGPRRegisters( } const size_t max_reg_byte_size = 16; - if (byte_size <= max_reg_byte_size) { - size_t bytes_left = byte_size; + if (*byte_size <= max_reg_byte_size) { + size_t bytes_left = *byte_size; uint32_t data_offset = 0; - while (data_offset < byte_size) { + while (data_offset < *byte_size) { if (NGRN >= 8) return false; @@ -2267,7 +2264,10 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( if (!reg_ctx) return return_valobj_sp; - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + 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) { @@ -2276,7 +2276,7 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( 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) { + if (*byte_size <= 8) { const RegisterInfo *x0_reg_info = reg_ctx->GetRegisterInfoByName("x0", 0); if (x0_reg_info) { @@ -2284,7 +2284,7 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, 0); const bool is_signed = (type_flags & eTypeIsSigned) != 0; - switch (byte_size) { + switch (*byte_size) { default: break; case 16: // uint128_t @@ -2294,10 +2294,10 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( reg_ctx->GetRegisterInfoByName("x1", 0); if (x1_reg_info) { - if (byte_size <= + if (*byte_size <= x0_reg_info->byte_size + x1_reg_info->byte_size) { std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); RegisterValue x0_reg_value; @@ -2362,7 +2362,7 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( if (type_flags & eTypeIsComplex) { // Don't handle complex yet. } else { - if (byte_size <= sizeof(long double)) { + if (*byte_size <= sizeof(long double)) { const RegisterInfo *v0_reg_info = reg_ctx->GetRegisterInfoByName("v0", 0); RegisterValue v0_value; @@ -2370,13 +2370,13 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( DataExtractor data; if (v0_value.GetData(data)) { lldb::offset_t offset = 0; - if (byte_size == sizeof(float)) { + if (*byte_size == sizeof(float)) { value.GetScalar() = data.GetFloat(&offset); success = true; - } else if (byte_size == sizeof(double)) { + } else if (*byte_size == sizeof(double)) { value.GetScalar() = data.GetDouble(&offset); success = true; - } else if (byte_size == sizeof(long double)) { + } else if (*byte_size == sizeof(long double)) { value.GetScalar() = data.GetLongDouble(&offset); success = true; } @@ -2390,14 +2390,14 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsVector) { - if (byte_size > 0) { + if (*byte_size > 0) { const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); if (v0_info) { - if (byte_size <= v0_info->byte_size) { + if (*byte_size <= v0_info->byte_size) { std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); RegisterValue reg_value; if (reg_ctx->ReadRegister(v0_info, reg_value)) { diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h index 2dd7337542db..7a9444c775f4 100644 --- a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h +++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABIMacOSX_arm64_h_ #define liblldb_ABIMacOSX_arm64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/Utility/ConstString.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp index 9e5e39ec28ca..a297bd1473b2 100644 --- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp +++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp @@ -9,19 +9,13 @@ #include "ABIMacOSX_i386.h" -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" @@ -29,6 +23,8 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/ConstString.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" using namespace lldb; @@ -714,13 +710,10 @@ size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; } ABISP ABIMacOSX_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; if ((arch.GetTriple().getArch() == llvm::Triple::x86) && (arch.GetTriple().isMacOSX() || arch.GetTriple().isiOS() || arch.GetTriple().isWatchOS())) { - if (!g_abi_sp) - g_abi_sp.reset(new ABIMacOSX_i386(process_sp)); - return g_abi_sp; + return ABISP(new ABIMacOSX_i386(process_sp)); } return ABISP(); } @@ -831,18 +824,15 @@ bool ABIMacOSX_i386::GetArgumentValues(Thread &thread, // We currently only support extracting values with Clang QualTypes. Do we // care about others? CompilerType compiler_type(value->GetCompilerType()); - if (compiler_type) { + llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread); + if (bit_size) { bool is_signed; - - if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - ReadIntegerArgument(value->GetScalar(), - compiler_type.GetBitSize(&thread), is_signed, + if (compiler_type.IsIntegerOrEnumerationType(is_signed)) + ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, thread.GetProcess().get(), current_stack_argument); - } else if (compiler_type.IsPointerType()) { - ReadIntegerArgument(value->GetScalar(), - compiler_type.GetBitSize(&thread), false, + else if (compiler_type.IsPointerType()) + ReadIntegerArgument(value->GetScalar(), *bit_size, false, thread.GetProcess().get(), current_stack_argument); - } } } @@ -943,14 +933,15 @@ ABIMacOSX_i386::GetReturnValueObjectImpl(Thread &thread, bool is_signed; if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - size_t bit_width = compiler_type.GetBitSize(&thread); - + llvm::Optional<uint64_t> bit_width = compiler_type.GetBitSize(&thread); + if (!bit_width) + return return_valobj_sp; unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB]; unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB]; - switch (bit_width) { + switch (*bit_width) { default: case 128: // Scalar can't hold 128-bit literals, so we don't handle this diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h index e026e3248672..536132d02586 100644 --- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h +++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABIMacOSX_i386_h_ #define liblldb_ABIMacOSX_i386_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Value.h" #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp b/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp index af7ac469e6db..b93a8525010c 100644 --- a/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp +++ b/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp @@ -9,19 +9,13 @@ #include "ABISysV_arm.h" -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Symbol/UnwindPlan.h" @@ -30,6 +24,8 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/ConstString.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" #include "Plugins/Process/Utility/ARMDefines.h" @@ -1328,16 +1324,13 @@ size_t ABISysV_arm::GetRedZoneSize() const { return 0; } ABISP ABISysV_arm::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; 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::arm) || (arch_type == llvm::Triple::thumb)) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_arm(process_sp)); - return g_abi_sp; + return ABISP(new ABISysV_arm(process_sp)); } } @@ -1447,10 +1440,7 @@ bool ABISysV_arm::PrepareTrivialCall(Thread &thread, addr_t sp, ~1ull; // clear bit zero since the CPSR will take care of the mode for us // Set "pc" to the address requested - if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, function_addr)) - return false; - - return true; + return reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, function_addr); } bool ABISysV_arm::GetArgumentValues(Thread &thread, ValueList &values) const { @@ -1481,10 +1471,10 @@ bool ABISysV_arm::GetArgumentValues(Thread &thread, ValueList &values) const { if (compiler_type) { bool is_signed = false; size_t bit_width = 0; - if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - bit_width = compiler_type.GetBitSize(&thread); - } else if (compiler_type.IsPointerOrReferenceType()) { - bit_width = compiler_type.GetBitSize(&thread); + if (compiler_type.IsIntegerOrEnumerationType(is_signed) || + compiler_type.IsPointerOrReferenceType()) { + if (llvm::Optional<uint64_t> size = compiler_type.GetBitSize(&thread)) + bit_width = *size; } else { // We only handle integer, pointer and reference types currently... return false; @@ -1590,11 +1580,13 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( const RegisterInfo *r0_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); - size_t bit_width = compiler_type.GetBitSize(&thread); - size_t byte_size = compiler_type.GetByteSize(&thread); + llvm::Optional<uint64_t> bit_width = compiler_type.GetBitSize(&thread); + llvm::Optional<uint64_t> byte_size = compiler_type.GetByteSize(&thread); + if (!bit_width || !byte_size) + return return_valobj_sp; if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - switch (bit_width) { + switch (*bit_width) { default: return return_valobj_sp; case 64: { @@ -1641,28 +1633,28 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( UINT32_MAX; value.GetScalar() = ptr; } else if (compiler_type.IsVectorType(nullptr, nullptr)) { - if (IsArmHardFloat(thread) && (byte_size == 8 || byte_size == 16)) { + if (IsArmHardFloat(thread) && (*byte_size == 8 || *byte_size == 16)) { is_vfp_candidate = true; vfp_byte_size = 8; - vfp_count = (byte_size == 8 ? 1 : 2); - } else if (byte_size <= 16) { + vfp_count = (*byte_size == 8 ? 1 : 2); + } else if (*byte_size <= 16) { DataBufferHeap buffer(16, 0); uint32_t *buffer_ptr = (uint32_t *)buffer.GetBytes(); - for (uint32_t i = 0; 4 * i < byte_size; ++i) { + for (uint32_t i = 0; 4 * i < *byte_size; ++i) { const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); buffer_ptr[i] = reg_ctx->ReadRegisterAsUnsigned(reg_info, 0) & UINT32_MAX; } - value.SetBytes(buffer.GetBytes(), byte_size); + value.SetBytes(buffer.GetBytes(), *byte_size); } else { - if (!GetReturnValuePassedInMemory(thread, reg_ctx, byte_size, value)) + if (!GetReturnValuePassedInMemory(thread, reg_ctx, *byte_size, value)) return return_valobj_sp; } } else if (compiler_type.IsFloatingPointType(float_count, is_complex)) { if (float_count == 1 && !is_complex) { - switch (bit_width) { + switch (*bit_width) { default: return return_valobj_sp; case 64: { @@ -1710,9 +1702,9 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( } else if (is_complex && float_count == 2) { if (IsArmHardFloat(thread)) { is_vfp_candidate = true; - vfp_byte_size = byte_size / 2; + vfp_byte_size = *byte_size / 2; vfp_count = 2; - } else if (!GetReturnValuePassedInMemory(thread, reg_ctx, bit_width / 8, + } else if (!GetReturnValuePassedInMemory(thread, reg_ctx, *bit_width / 8, value)) return return_valobj_sp; } else @@ -1725,19 +1717,21 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( compiler_type.IsHomogeneousAggregate(&base_type); if (homogeneous_count > 0 && homogeneous_count <= 4) { + llvm::Optional<uint64_t> base_byte_size = + base_type.GetByteSize(nullptr); if (base_type.IsVectorType(nullptr, nullptr)) { - uint64_t base_byte_size = base_type.GetByteSize(nullptr); - if (base_byte_size == 8 || base_byte_size == 16) { + if (base_byte_size && + (*base_byte_size == 8 || *base_byte_size == 16)) { is_vfp_candidate = true; vfp_byte_size = 8; - vfp_count = - (base_type.GetByteSize(nullptr) == 8 ? homogeneous_count - : homogeneous_count * 2); + vfp_count = (*base_byte_size == 8 ? homogeneous_count + : homogeneous_count * 2); } } else if (base_type.IsFloatingPointType(float_count, is_complex)) { if (float_count == 1 && !is_complex) { is_vfp_candidate = true; - vfp_byte_size = base_type.GetByteSize(nullptr); + if (base_byte_size) + vfp_byte_size = *base_byte_size; vfp_count = homogeneous_count; } } @@ -1752,12 +1746,14 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( compiler_type.GetFieldAtIndex(index, name, NULL, NULL, NULL); if (base_type.IsFloatingPointType(float_count, is_complex)) { + llvm::Optional<uint64_t> base_byte_size = + base_type.GetByteSize(nullptr); if (float_count == 2 && is_complex) { - if (index != 0 && - vfp_byte_size != base_type.GetByteSize(nullptr)) + if (index != 0 && base_byte_size && + vfp_byte_size != *base_byte_size) break; - else - vfp_byte_size = base_type.GetByteSize(nullptr); + else if (base_byte_size) + vfp_byte_size = *base_byte_size; } else break; } else @@ -1773,13 +1769,13 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( } } - if (byte_size <= 4) { + if (*byte_size <= 4) { RegisterValue r0_reg_value; uint32_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX; - value.SetBytes(&raw_value, byte_size); + value.SetBytes(&raw_value, *byte_size); } else if (!is_vfp_candidate) { - if (!GetReturnValuePassedInMemory(thread, reg_ctx, byte_size, value)) + if (!GetReturnValuePassedInMemory(thread, reg_ctx, *byte_size, value)) return return_valobj_sp; } } else { @@ -1791,7 +1787,7 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( ProcessSP process_sp(thread.GetProcess()); ByteOrder byte_order = process_sp->GetByteOrder(); - DataBufferSP data_sp(new DataBufferHeap(byte_size, 0)); + DataBufferSP data_sp(new DataBufferHeap(*byte_size, 0)); uint32_t data_offset = 0; for (uint32_t reg_index = 0; reg_index < vfp_count; reg_index++) { @@ -1826,7 +1822,7 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( } } - if (data_offset == byte_size) { + if (data_offset == *byte_size) { DataExtractor data; data.SetByteOrder(byte_order); data.SetAddressByteSize(process_sp->GetAddressByteSize()); diff --git a/source/Plugins/ABI/SysV-arm/ABISysV_arm.h b/source/Plugins/ABI/SysV-arm/ABISysV_arm.h index f046968c213d..7f2d658541ab 100644 --- a/source/Plugins/ABI/SysV-arm/ABISysV_arm.h +++ b/source/Plugins/ABI/SysV-arm/ABISysV_arm.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABISysV_arm_h_ #define liblldb_ABISysV_arm_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp index 2c221689954c..dd3f47303be5 100644 --- a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp +++ b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp @@ -9,19 +9,13 @@ #include "ABISysV_arm64.h" -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Symbol/UnwindPlan.h" @@ -31,6 +25,8 @@ #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" @@ -1671,15 +1667,12 @@ size_t ABISysV_arm64::GetRedZoneSize() const { return 128; } ABISP ABISysV_arm64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; 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) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_arm64(process_sp)); - return g_abi_sp; + return ABISP(new ABISysV_arm64(process_sp)); } } @@ -1774,10 +1767,13 @@ bool ABISysV_arm64::GetArgumentValues(Thread &thread, ValueList &values) const { 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 = value_type.GetBitSize(&thread); + bit_width = *bit_size; } else if (value_type.IsPointerOrReferenceType()) { - bit_width = value_type.GetBitSize(&thread); + bit_width = *bit_size; } else { // We only handle integer, pointer and reference types currently... return false; @@ -2090,13 +2086,13 @@ static bool LoadValueFromConsecutiveGPRRegisters( uint32_t &NGRN, // NGRN (see ABI documentation) uint32_t &NSRN, // NSRN (see ABI documentation) DataExtractor &data) { - const size_t byte_size = value_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> byte_size = value_type.GetByteSize(nullptr); - if (byte_size == 0) + if (byte_size || *byte_size == 0) return false; std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); Status error; @@ -2108,7 +2104,9 @@ static bool LoadValueFromConsecutiveGPRRegisters( if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) { if (!base_type) return false; - const size_t base_byte_size = base_type.GetByteSize(nullptr); + 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) { @@ -2119,7 +2117,7 @@ static bool LoadValueFromConsecutiveGPRRegisters( if (reg_info == nullptr) return false; - if (base_byte_size > reg_info->byte_size) + if (*base_byte_size > reg_info->byte_size) return false; RegisterValue reg_value; @@ -2128,11 +2126,11 @@ static bool LoadValueFromConsecutiveGPRRegisters( return false; // Make sure we have enough room in "heap_data_ap" - if ((data_offset + base_byte_size) <= heap_data_ap->GetByteSize()) { + if ((data_offset + *base_byte_size) <= heap_data_ap->GetByteSize()) { const size_t bytes_copied = reg_value.GetAsMemoryData( - reg_info, heap_data_ap->GetBytes() + data_offset, base_byte_size, + reg_info, heap_data_ap->GetBytes() + data_offset, *base_byte_size, byte_order, error); - if (bytes_copied != base_byte_size) + if (bytes_copied != *base_byte_size) return false; data_offset += bytes_copied; ++NSRN; @@ -2147,10 +2145,10 @@ static bool LoadValueFromConsecutiveGPRRegisters( } const size_t max_reg_byte_size = 16; - if (byte_size <= max_reg_byte_size) { - size_t bytes_left = byte_size; + if (*byte_size <= max_reg_byte_size) { + size_t bytes_left = *byte_size; uint32_t data_offset = 0; - while (data_offset < byte_size) { + while (data_offset < *byte_size) { if (NGRN >= 8) return false; @@ -2235,7 +2233,10 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( if (!reg_ctx) return return_valobj_sp; - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + 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) { @@ -2244,7 +2245,7 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( 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) { + if (*byte_size <= 8) { const RegisterInfo *x0_reg_info = nullptr; x0_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); @@ -2253,7 +2254,7 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, 0); const bool is_signed = (type_flags & eTypeIsSigned) != 0; - switch (byte_size) { + switch (*byte_size) { default: break; case 16: // uint128_t @@ -2264,10 +2265,10 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( LLDB_REGNUM_GENERIC_ARG2); if (x1_reg_info) { - if (byte_size <= + if (*byte_size <= x0_reg_info->byte_size + x1_reg_info->byte_size) { std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); RegisterValue x0_reg_value; @@ -2332,7 +2333,7 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( if (type_flags & eTypeIsComplex) { // Don't handle complex yet. } else { - if (byte_size <= sizeof(long double)) { + if (*byte_size <= sizeof(long double)) { const RegisterInfo *v0_reg_info = reg_ctx->GetRegisterInfoByName("v0", 0); RegisterValue v0_value; @@ -2340,13 +2341,13 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( DataExtractor data; if (v0_value.GetData(data)) { lldb::offset_t offset = 0; - if (byte_size == sizeof(float)) { + if (*byte_size == sizeof(float)) { value.GetScalar() = data.GetFloat(&offset); success = true; - } else if (byte_size == sizeof(double)) { + } else if (*byte_size == sizeof(double)) { value.GetScalar() = data.GetDouble(&offset); success = true; - } else if (byte_size == sizeof(long double)) { + } else if (*byte_size == sizeof(long double)) { value.GetScalar() = data.GetLongDouble(&offset); success = true; } @@ -2359,13 +2360,13 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( 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) { + } 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_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); RegisterValue reg_value; if (reg_ctx->ReadRegister(v0_info, reg_value)) { @@ -2382,7 +2383,7 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( } } } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass || - (type_flags & eTypeIsVector && byte_size > 16)) { + (type_flags & eTypeIsVector && *byte_size > 16)) { DataExtractor data; uint32_t NGRN = 0; // Search ABI docs for NGRN diff --git a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h index 8d23c2419bab..b36b4547e626 100644 --- a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h +++ b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABISysV_arm64_h_ #define liblldb_ABISysV_arm64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp index a30416cf5a8e..ca40e9a04d7c 100644 --- a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp +++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp @@ -9,16 +9,11 @@ #include "ABISysV_hexagon.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/Triple.h" #include "llvm/IR/DerivedTypes.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" @@ -32,6 +27,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" using namespace lldb; @@ -1020,11 +1016,8 @@ size_t ABISysV_hexagon::GetRedZoneSize() const { return 0; } ABISP ABISysV_hexagon::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; if (arch.GetTriple().getArch() == llvm::Triple::hexagon) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_hexagon(process_sp)); - return g_abi_sp; + return ABISP(new ABISysV_hexagon(process_sp)); } return ABISP(); } diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h index 5a6809371d9f..6e39c0792e2a 100644 --- a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h +++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h @@ -11,10 +11,6 @@ #ifndef liblldb_ABISysV_hexagon_h_ #define liblldb_ABISysV_hexagon_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp b/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp index e7ddfccea338..3358eb8c2774 100644 --- a/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp +++ b/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp @@ -8,16 +8,11 @@ #include "ABISysV_i386.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" @@ -31,6 +26,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" using namespace lldb; @@ -203,12 +199,9 @@ ABISysV_i386::GetRegisterInfoArray(uint32_t &count) { ABISP ABISysV_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; if (arch.GetTriple().getVendor() != llvm::Triple::Apple) { if (arch.GetTriple().getArch() == llvm::Triple::x86) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_i386(process_sp)); - return g_abi_sp; + return ABISP(new ABISysV_i386(process_sp)); } } return ABISP(); @@ -315,15 +308,14 @@ bool ABISysV_i386::GetArgumentValues(Thread &thread, ValueList &values) const { // Currently: Support for extracting values with Clang QualTypes only. CompilerType compiler_type(value->GetCompilerType()); - if (compiler_type) { + llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread); + if (bit_size) { bool is_signed; if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - ReadIntegerArgument(value->GetScalar(), - compiler_type.GetBitSize(&thread), is_signed, + ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, thread.GetProcess().get(), current_stack_argument); } else if (compiler_type.IsPointerType()) { - ReadIntegerArgument(value->GetScalar(), - compiler_type.GetBitSize(&thread), false, + ReadIntegerArgument(value->GetScalar(), *bit_size, false, thread.GetProcess().get(), current_stack_argument); } } @@ -521,7 +513,10 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point' { value.SetValueType(Value::eValueTypeScalar); - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (!byte_size) + return return_valobj_sp; bool success = false; if (type_flags & eTypeIsInteger) // 'Integral' except enum @@ -535,7 +530,7 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( 0xffffffff) << 32; - switch (byte_size) { + switch (*byte_size) { default: break; @@ -591,7 +586,7 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsFloat) // 'Floating Point' { - if (byte_size <= 12) // handles float, double, long double, __float80 + if (*byte_size <= 12) // handles float, double, long double, __float80 { const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0); RegisterValue st0_value; @@ -602,21 +597,20 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( lldb::offset_t offset = 0; long double value_long_double = data.GetLongDouble(&offset); - if (byte_size == 4) // float is 4 bytes - { + // float is 4 bytes. + if (*byte_size == 4) { float value_float = (float)value_long_double; value.GetScalar() = value_float; success = true; - } else if (byte_size == 8) // double is 8 bytes - { + } else if (*byte_size == 8) { + // double is 8 bytes // On Android Platform: long double is also 8 bytes It will be // handled here only. double value_double = (double)value_long_double; value.GetScalar() = value_double; success = true; - } else if (byte_size == - 12) // long double and __float80 are 12 bytes on i386 - { + } else if (*byte_size == 12) { + // long double and __float80 are 12 bytes on i386. value.GetScalar() = value_long_double; success = true; } @@ -626,7 +620,7 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( if (success) return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); - } else if (byte_size == 16) // handles __float128 + } else if (*byte_size == 16) // handles __float128 { lldb::addr_t storage_addr = (uint32_t)( thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & @@ -644,18 +638,19 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( // ToDo: Yet to be implemented } else if (type_flags & eTypeIsVector) // 'Packed' { - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); - if (byte_size > 0) { + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (byte_size && *byte_size > 0) { const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0); if (vec_reg == nullptr) vec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0); if (vec_reg) { - if (byte_size <= vec_reg->byte_size) { + if (*byte_size <= vec_reg->byte_size) { ProcessSP process_sp(thread.GetProcess()); if (process_sp) { std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = process_sp->GetByteOrder(); RegisterValue reg_value; if (reg_ctx->ReadRegister(vec_reg, reg_value)) { @@ -672,14 +667,14 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( } } } - } else if (byte_size <= vec_reg->byte_size * 2) { + } else if (*byte_size <= vec_reg->byte_size * 2) { const RegisterInfo *vec_reg2 = reg_ctx->GetRegisterInfoByName("xmm1", 0); if (vec_reg2) { ProcessSP process_sp(thread.GetProcess()); if (process_sp) { std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = process_sp->GetByteOrder(); RegisterValue reg_value; RegisterValue reg_value2; diff --git a/source/Plugins/ABI/SysV-i386/ABISysV_i386.h b/source/Plugins/ABI/SysV-i386/ABISysV_i386.h index 4dce54c4f073..336a2754c6ca 100644 --- a/source/Plugins/ABI/SysV-i386/ABISysV_i386.h +++ b/source/Plugins/ABI/SysV-i386/ABISysV_i386.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABISysV_i386_h_ #define liblldb_ABISysV_i386_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp b/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp index ce02f8677a63..6f3d2e3b3696 100644 --- a/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp +++ b/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp @@ -9,16 +9,11 @@ #include "ABISysV_mips.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" @@ -32,6 +27,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" using namespace lldb; @@ -560,13 +556,10 @@ size_t ABISysV_mips::GetRedZoneSize() const { return 0; } ABISP ABISysV_mips::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch(); if ((arch_type == llvm::Triple::mips) || (arch_type == llvm::Triple::mipsel)) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_mips(process_sp)); - return g_abi_sp; + return ABISP(new ABISysV_mips(process_sp)); } return ABISP(); } @@ -819,9 +812,11 @@ ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl( // In MIPS register "r2" (v0) holds the integer function return values const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoByName("r2", 0); - size_t bit_width = return_compiler_type.GetBitSize(&thread); + llvm::Optional<uint64_t> bit_width = return_compiler_type.GetBitSize(&thread); + if (!bit_width) + return return_valobj_sp; if (return_compiler_type.IsIntegerOrEnumerationType(is_signed)) { - switch (bit_width) { + switch (*bit_width) { default: return return_valobj_sp; case 64: { @@ -880,7 +875,7 @@ ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl( uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); if (count != 1 && is_complex) return return_valobj_sp; - switch (bit_width) { + switch (*bit_width) { default: return return_valobj_sp; case 32: @@ -912,7 +907,7 @@ ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl( lldb::offset_t offset = 0; if (count == 1 && !is_complex) { - switch (bit_width) { + switch (*bit_width) { default: return return_valobj_sp; case 64: { diff --git a/source/Plugins/ABI/SysV-mips/ABISysV_mips.h b/source/Plugins/ABI/SysV-mips/ABISysV_mips.h index 0de8e7751fce..d23dbe9d97bd 100644 --- a/source/Plugins/ABI/SysV-mips/ABISysV_mips.h +++ b/source/Plugins/ABI/SysV-mips/ABISysV_mips.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABISysV_mips_h_ #define liblldb_ABISysV_mips_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp index b958abf25637..1d6738d9fda9 100644 --- a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp +++ b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp @@ -9,16 +9,11 @@ #include "ABISysV_mips64.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" @@ -32,6 +27,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" using namespace lldb; @@ -560,13 +556,10 @@ size_t ABISysV_mips64::GetRedZoneSize() const { return 0; } ABISP ABISysV_mips64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch(); if ((arch_type == llvm::Triple::mips64) || (arch_type == llvm::Triple::mips64el)) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_mips64(process_sp)); - return g_abi_sp; + return ABISP(new ABISysV_mips64(process_sp)); } return ABISP(); } @@ -769,7 +762,10 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( Target *target = exe_ctx.GetTargetPtr(); const ArchSpec target_arch = target->GetArchitecture(); ByteOrder target_byte_order = target_arch.GetByteOrder(); - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + 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); uint32_t fp_flag = target_arch.GetFlags() & lldb_private::ArchSpec::eMIPS_ABI_FP_mask; @@ -788,7 +784,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0); const bool is_signed = (type_flags & eTypeIsSigned) != 0; - switch (byte_size) { + switch (*byte_size) { default: break; @@ -829,7 +825,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( // Don't handle complex yet. } else if (IsSoftFloat(fp_flag)) { uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0); - switch (byte_size) { + switch (*byte_size) { case 4: value.GetScalar() = *((float *)(&raw_value)); success = true; @@ -854,7 +850,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( } } else { - if (byte_size <= sizeof(long double)) { + if (*byte_size <= sizeof(long double)) { const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); RegisterValue f0_value; @@ -865,13 +861,13 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( f0_value.GetData(f0_data); lldb::offset_t offset = 0; - if (byte_size == sizeof(float)) { + if (*byte_size == sizeof(float)) { value.GetScalar() = (float)f0_data.GetFloat(&offset); success = true; - } else if (byte_size == sizeof(double)) { + } else if (*byte_size == sizeof(double)) { value.GetScalar() = (double)f0_data.GetDouble(&offset); success = true; - } else if (byte_size == sizeof(long double)) { + } else if (*byte_size == sizeof(long double)) { const RegisterInfo *f2_info = reg_ctx->GetRegisterInfoByName("f2", 0); RegisterValue f2_value; @@ -886,21 +882,21 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( if (target_byte_order == eByteOrderLittle) { copy_from_extractor = &f0_data; copy_from_extractor->CopyByteOrderedData( - 0, 8, data_sp->GetBytes(), byte_size - 8, target_byte_order); + 0, 8, data_sp->GetBytes(), *byte_size - 8, target_byte_order); f2_value.GetData(f2_data); copy_from_extractor = &f2_data; copy_from_extractor->CopyByteOrderedData( - 0, 8, data_sp->GetBytes() + 8, byte_size - 8, + 0, 8, data_sp->GetBytes() + 8, *byte_size - 8, target_byte_order); } else { copy_from_extractor = &f0_data; copy_from_extractor->CopyByteOrderedData( - 0, 8, data_sp->GetBytes() + 8, byte_size - 8, + 0, 8, data_sp->GetBytes() + 8, *byte_size - 8, target_byte_order); f2_value.GetData(f2_data); copy_from_extractor = &f2_data; copy_from_extractor->CopyByteOrderedData( - 0, 8, data_sp->GetBytes(), byte_size - 8, target_byte_order); + 0, 8, data_sp->GetBytes(), *byte_size - 8, target_byte_order); } return_valobj_sp = ValueObjectConstResult::Create( @@ -917,7 +913,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass || type_flags & eTypeIsVector) { // Any structure of up to 16 bytes in size is returned in the registers. - if (byte_size <= 16) { + if (*byte_size <= 16) { DataBufferSP data_sp(new DataBufferHeap(16, 0)); DataExtractor return_ext(data_sp, target_byte_order, target->GetArchitecture().GetAddressByteSize()); @@ -975,8 +971,10 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( idx, name, &field_bit_offset, nullptr, nullptr); - const size_t field_byte_width = + llvm::Optional<uint64_t> field_byte_width = field_compiler_type.GetByteSize(nullptr); + if (!field_byte_width) + return return_valobj_sp; DataExtractor *copy_from_extractor = nullptr; uint64_t return_value[2]; @@ -984,7 +982,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( if (idx == 0) { // This case is for long double type. - if (field_byte_width == 16) { + if (*field_byte_width == 16) { // If structure contains long double type, then it is returned // in fp0/fp1 registers. @@ -1002,7 +1000,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( return_value[0] = f1_data.GetU64(&offset); } - f0_data.SetData(return_value, field_byte_width, + f0_data.SetData(return_value, *field_byte_width, target_byte_order); } copy_from_extractor = &f0_data; // This is in f0, copy from @@ -1016,13 +1014,13 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( // Sanity check to avoid crash if (!copy_from_extractor || - field_byte_width > copy_from_extractor->GetByteSize()) + *field_byte_width > copy_from_extractor->GetByteSize()) return return_valobj_sp; // copy the register contents into our data buffer copy_from_extractor->CopyByteOrderedData( - 0, field_byte_width, - data_sp->GetBytes() + (field_bit_offset / 8), field_byte_width, + 0, *field_byte_width, + data_sp->GetBytes() + (field_bit_offset / 8), *field_byte_width, target_byte_order); } @@ -1045,12 +1043,12 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( idx, name, &field_bit_offset, nullptr, nullptr); - const size_t field_byte_width = + llvm::Optional<uint64_t> field_byte_width = field_compiler_type.GetByteSize(nullptr); // if we don't know the size of the field (e.g. invalid type), just // bail out - if (field_byte_width == 0) + if (!field_byte_width || *field_byte_width == 0) break; uint32_t field_byte_offset = field_bit_offset / 8; @@ -1062,24 +1060,24 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( if (integer_bytes < 8) { // We have not yet consumed r2 completely. - if (integer_bytes + field_byte_width + padding <= 8) { + if (integer_bytes + *field_byte_width + padding <= 8) { // This field fits in r2, copy its value from r2 to our result // structure - integer_bytes = integer_bytes + field_byte_width + + integer_bytes = integer_bytes + *field_byte_width + padding; // Increase the consumed bytes. use_r2 = 1; } else { // There isn't enough space left in r2 for this field, so this // will be in r3. - integer_bytes = integer_bytes + field_byte_width + + integer_bytes = integer_bytes + *field_byte_width + padding; // Increase the consumed bytes. use_r3 = 1; } } // We already have consumed at-least 8 bytes that means r2 is done, // and this field will be in r3. Check if this field can fit in r3. - else if (integer_bytes + field_byte_width + padding <= 16) { - integer_bytes = integer_bytes + field_byte_width + padding; + else if (integer_bytes + *field_byte_width + padding <= 16) { + integer_bytes = integer_bytes + *field_byte_width + padding; use_r3 = 1; } else { // There isn't any space left for this field, this should not @@ -1092,7 +1090,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( } // Vector types up to 16 bytes are returned in GP return registers if (type_flags & eTypeIsVector) { - if (byte_size <= 8) + if (*byte_size <= 8) use_r2 = 1; else { use_r2 = 1; diff --git a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h index 6258c08e35f9..c7670f467114 100644 --- a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h +++ b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABISysV_mips64_h_ #define liblldb_ABISysV_mips64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp index e93dcdbe1a59..1fe7a6718a91 100644 --- a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp +++ b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp @@ -9,16 +9,11 @@ #include "ABISysV_ppc.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" @@ -32,6 +27,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" using namespace lldb; @@ -224,11 +220,8 @@ size_t ABISysV_ppc::GetRedZoneSize() const { return 224; } ABISP ABISysV_ppc::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; if (arch.GetTriple().getArch() == llvm::Triple::ppc) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_ppc(process_sp)); - return g_abi_sp; + return ABISP(new ABISysV_ppc(process_sp)); } return ABISP(); } @@ -405,19 +398,18 @@ bool ABISysV_ppc::GetArgumentValues(Thread &thread, ValueList &values) const { // We currently only support extracting values with Clang QualTypes. Do we // care about others? CompilerType compiler_type = value->GetCompilerType(); - if (!compiler_type) + llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread); + if (!bit_size) return false; bool is_signed; - - if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), - is_signed, thread, argument_register_ids, - current_argument_register, current_stack_argument); - } else if (compiler_type.IsPointerType()) { - ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), - false, thread, argument_register_ids, - current_argument_register, current_stack_argument); - } + if (compiler_type.IsIntegerOrEnumerationType(is_signed)) + ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, thread, + argument_register_ids, current_argument_register, + current_stack_argument); + else if (compiler_type.IsPointerType()) + ReadIntegerArgument(value->GetScalar(), *bit_size, false, thread, + argument_register_ids, current_argument_register, + current_stack_argument); } return true; @@ -474,8 +466,13 @@ Status ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp, error.SetErrorString( "We don't support returning complex values at present"); else { - size_t bit_width = compiler_type.GetBitSize(frame_sp.get()); - if (bit_width <= 64) { + llvm::Optional<uint64_t> bit_width = + compiler_type.GetBitSize(frame_sp.get()); + if (!bit_width) { + error.SetErrorString("can't get type size"); + return error; + } + if (*bit_width <= 64) { DataExtractor data; Status data_error; size_t num_bytes = new_value_sp->GetData(data, data_error); @@ -533,11 +530,14 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple( if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (!byte_size) + return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( reg_ctx->GetRegisterInfoByName("r3", 0), 0); const bool is_signed = (type_flags & eTypeIsSigned) != 0; - switch (byte_size) { + switch (*byte_size) { default: break; @@ -577,18 +577,19 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple( if (type_flags & eTypeIsComplex) { // Don't handle complex yet. } else { - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); - if (byte_size <= sizeof(long double)) { + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); RegisterValue f1_value; if (reg_ctx->ReadRegister(f1_info, f1_value)) { DataExtractor data; if (f1_value.GetData(data)) { lldb::offset_t offset = 0; - if (byte_size == sizeof(float)) { + if (*byte_size == sizeof(float)) { value.GetScalar() = (float)data.GetFloat(&offset); success = true; - } else if (byte_size == sizeof(double)) { + } else if (*byte_size == sizeof(double)) { value.GetScalar() = (double)data.GetDouble(&offset); success = true; } @@ -610,15 +611,16 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple( return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsVector) { - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); - if (byte_size > 0) { + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (byte_size && *byte_size > 0) { const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v2", 0); if (altivec_reg) { - if (byte_size <= altivec_reg->byte_size) { + if (*byte_size <= altivec_reg->byte_size) { ProcessSP process_sp(thread.GetProcess()); if (process_sp) { std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = process_sp->GetByteOrder(); RegisterValue reg_value; if (reg_ctx->ReadRegister(altivec_reg, reg_value)) { @@ -627,9 +629,10 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple( altivec_reg, heap_data_ap->GetBytes(), heap_data_ap->GetByteSize(), byte_order, error)) { DataExtractor data(DataBufferSP(heap_data_ap.release()), - byte_order, process_sp->GetTarget() - .GetArchitecture() - .GetAddressByteSize()); + byte_order, + process_sp->GetTarget() + .GetArchitecture() + .GetAddressByteSize()); return_valobj_sp = ValueObjectConstResult::Create( &thread, return_compiler_type, ConstString(""), data); } @@ -659,11 +662,13 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( if (!reg_ctx_sp) return return_valobj_sp; - const size_t bit_width = return_compiler_type.GetBitSize(&thread); + llvm::Optional<uint64_t> bit_width = return_compiler_type.GetBitSize(&thread); + if (!bit_width) + return return_valobj_sp; if (return_compiler_type.IsAggregateType()) { Target *target = exe_ctx.GetTargetPtr(); bool is_memory = true; - if (bit_width <= 128) { + if (*bit_width <= 128) { ByteOrder target_byte_order = target->GetArchitecture().GetByteOrder(); DataBufferSP data_sp(new DataBufferHeap(16, 0)); DataExtractor return_ext(data_sp, target_byte_order, @@ -701,15 +706,18 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( idx, name, &field_bit_offset, nullptr, nullptr); - const size_t field_bit_width = field_compiler_type.GetBitSize(&thread); + llvm::Optional<uint64_t> field_bit_width = + field_compiler_type.GetBitSize(&thread); + if (!field_bit_width) + return return_valobj_sp; // If there are any unaligned fields, this is stored in memory. - if (field_bit_offset % field_bit_width != 0) { + if (field_bit_offset % *field_bit_width != 0) { is_memory = true; break; } - uint32_t field_byte_width = field_bit_width / 8; + uint32_t field_byte_width = *field_bit_width / 8; uint32_t field_byte_offset = field_bit_offset / 8; DataExtractor *copy_from_extractor = nullptr; @@ -742,13 +750,13 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( } } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) { // Structs with long doubles are always passed in memory. - if (field_bit_width == 128) { + if (*field_bit_width == 128) { is_memory = true; break; - } else if (field_bit_width == 64) { + } else if (*field_bit_width == 64) { copy_from_offset = 0; fp_bytes += field_byte_width; - } else if (field_bit_width == 32) { + } else if (*field_bit_width == 32) { // This one is kind of complicated. If we are in an "eightbyte" // with another float, we'll be stuffed into an xmm register with // it. If we are in an "eightbyte" with one or more ints, then we diff --git a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h index df3ebe83faf8..3559cbb45200 100644 --- a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h +++ b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABISysV_ppc_h_ #define liblldb_ABISysV_ppc_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp index d0140a0c894a..fb46b7dc7fb6 100644 --- a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp +++ b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp @@ -9,18 +9,13 @@ #include "ABISysV_ppc64.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -// Project includes #include "Utility/PPC64LE_DWARF_Registers.h" #include "Utility/PPC64_DWARF_Registers.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" @@ -35,6 +30,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "clang/AST/ASTContext.h" @@ -284,18 +280,19 @@ bool ABISysV_ppc64::GetArgumentValues(Thread &thread, ValueList &values) const { // We currently only support extracting values with Clang QualTypes. Do we // care about others? CompilerType compiler_type = value->GetCompilerType(); - if (!compiler_type) + llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread); + if (!bit_size) return false; bool is_signed; if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), - is_signed, thread, argument_register_ids, - current_argument_register, current_stack_argument); + ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, thread, + argument_register_ids, current_argument_register, + current_stack_argument); } else if (compiler_type.IsPointerType()) { - ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), - false, thread, argument_register_ids, - current_argument_register, current_stack_argument); + ReadIntegerArgument(value->GetScalar(), *bit_size, false, thread, + argument_register_ids, current_argument_register, + current_stack_argument); } } @@ -353,8 +350,13 @@ Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, error.SetErrorString( "We don't support returning complex values at present"); else { - size_t bit_width = compiler_type.GetBitSize(frame_sp.get()); - if (bit_width <= 64) { + llvm::Optional<uint64_t> bit_width = + compiler_type.GetBitSize(frame_sp.get()); + if (!bit_width) { + error.SetErrorString("can't get size of type"); + return error; + } + if (*bit_width <= 64) { DataExtractor data; Status data_error; size_t num_bytes = new_value_sp->GetData(data, data_error); @@ -575,7 +577,7 @@ private: ReturnValueExtractor(Thread &thread, CompilerType &type, RegisterContext *reg_ctx, ProcessSP process_sp) : m_thread(thread), m_type(type), - m_byte_size(m_type.GetByteSize(nullptr)), + m_byte_size(m_type.GetByteSize(nullptr).getValueOr(0)), m_data_ap(new DataBufferHeap(m_byte_size, 0)), m_reg_ctx(reg_ctx), m_process_sp(process_sp), m_byte_order(process_sp->GetByteOrder()), m_addr_size( @@ -643,7 +645,7 @@ private: uint64_t raw_data; auto reg = GetFPR(reg_index); if (!reg.GetRawData(raw_data)) - return ValueSP(); + return {}; // build value from data ValueSP value_sp(NewScalarValue(type)); @@ -651,8 +653,10 @@ private: DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size); offset_t offset = 0; - size_t byte_size = type.GetByteSize(nullptr); - switch (byte_size) { + llvm::Optional<uint64_t> byte_size = type.GetByteSize(nullptr); + if (!byte_size) + return {}; + switch (*byte_size) { case sizeof(float): value_sp->GetScalar() = (float)de.GetDouble(&offset); break; @@ -759,7 +763,7 @@ private: uint64_t addr; auto reg = GetGPR(0); if (!reg.GetRawData(addr)) - return ValueObjectSP(); + return {}; Status error; size_t rc = m_process_sp->ReadMemory(addr, m_data_ap->GetBytes(), @@ -773,37 +777,39 @@ private: // get number of children const bool omit_empty_base_classes = true; - uint32_t n = m_type.GetNumChildren(omit_empty_base_classes); + uint32_t n = m_type.GetNumChildren(omit_empty_base_classes, nullptr); if (!n) { LLDB_LOG(m_log, LOG_PREFIX "No children found in struct"); - return ValueObjectSP(); + return {}; } // case 2: homogeneous double or float aggregate CompilerType elem_type; if (m_type.IsHomogeneousAggregate(&elem_type)) { uint32_t type_flags = elem_type.GetTypeInfo(); - uint64_t elem_size = elem_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> elem_size = elem_type.GetByteSize(nullptr); + if (!elem_size) + return {}; if (type_flags & eTypeIsComplex || !(type_flags & eTypeIsFloat)) { LLDB_LOG(m_log, LOG_PREFIX "Unexpected type found in homogeneous aggregate"); - return ValueObjectSP(); + return {}; } for (uint32_t i = 0; i < n; i++) { ValueSP val_sp = GetFloatValue(elem_type, i); if (!val_sp) - return ValueObjectSP(); + return {}; // copy to buffer Status error; size_t rc = val_sp->GetScalar().GetAsMemoryData( - m_data_ap->GetBytes() + m_dst_offs, elem_size, m_byte_order, error); - if (rc != elem_size) { + m_data_ap->GetBytes() + m_dst_offs, *elem_size, m_byte_order, error); + if (rc != *elem_size) { LLDB_LOG(m_log, LOG_PREFIX "Failed to get float data"); - return ValueObjectSP(); + return {}; } - m_dst_offs += elem_size; + m_dst_offs += *elem_size; } return BuildValueObject(); } diff --git a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h index 52765a773c0b..54f461e1001b 100644 --- a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h +++ b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABISysV_ppc64_h_ #define liblldb_ABISysV_ppc64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp b/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp index 31e2825c0fa2..d8056ea7d356 100644 --- a/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp +++ b/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp @@ -9,16 +9,11 @@ #include "ABISysV_s390x.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" @@ -32,6 +27,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" using namespace lldb; @@ -206,11 +202,8 @@ size_t ABISysV_s390x::GetRedZoneSize() const { return 0; } ABISP ABISysV_s390x::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; if (arch.GetTriple().getArch() == llvm::Triple::systemz) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_s390x(process_sp)); - return g_abi_sp; + return ABISP(new ABISysV_s390x(process_sp)); } return ABISP(); } @@ -383,18 +376,19 @@ bool ABISysV_s390x::GetArgumentValues(Thread &thread, ValueList &values) const { // We currently only support extracting values with Clang QualTypes. Do we // care about others? CompilerType compiler_type = value->GetCompilerType(); - if (!compiler_type) + llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread); + if (!bit_size) return false; bool is_signed; if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), - is_signed, thread, argument_register_ids, - current_argument_register, current_stack_argument); + ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, thread, + argument_register_ids, current_argument_register, + current_stack_argument); } else if (compiler_type.IsPointerType()) { - ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), - false, thread, argument_register_ids, - current_argument_register, current_stack_argument); + ReadIntegerArgument(value->GetScalar(), *bit_size, false, thread, + argument_register_ids, current_argument_register, + current_stack_argument); } } @@ -452,8 +446,13 @@ Status ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp, error.SetErrorString( "We don't support returning complex values at present"); else { - size_t bit_width = compiler_type.GetBitSize(frame_sp.get()); - if (bit_width <= 64) { + llvm::Optional<uint64_t> bit_width = + compiler_type.GetBitSize(frame_sp.get()); + if (!bit_width) { + error.SetErrorString("can't get type size"); + return error; + } + if (*bit_width <= 64) { const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); RegisterValue f0_value; DataExtractor data; @@ -513,13 +512,15 @@ ValueObjectSP ABISysV_s390x::GetReturnValueObjectSimple( bool success = false; if (type_flags & eTypeIsInteger) { - // Extract the register context so we can read arguments from registers - - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + // Extract the register context so we can read arguments from registers. + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (!byte_size) + return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( reg_ctx->GetRegisterInfoByName("r2", 0), 0); const bool is_signed = (type_flags & eTypeIsSigned) != 0; - switch (byte_size) { + switch (*byte_size) { default: break; @@ -559,21 +560,22 @@ ValueObjectSP ABISysV_s390x::GetReturnValueObjectSimple( if (type_flags & eTypeIsComplex) { // Don't handle complex yet. } else { - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); - if (byte_size <= sizeof(long double)) { + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); RegisterValue f0_value; if (reg_ctx->ReadRegister(f0_info, f0_value)) { DataExtractor data; if (f0_value.GetData(data)) { lldb::offset_t offset = 0; - if (byte_size == sizeof(float)) { + if (*byte_size == sizeof(float)) { value.GetScalar() = (float)data.GetFloat(&offset); success = true; - } else if (byte_size == sizeof(double)) { + } else if (*byte_size == sizeof(double)) { value.GetScalar() = (double)data.GetDouble(&offset); success = true; - } else if (byte_size == sizeof(long double)) { + } else if (*byte_size == sizeof(long double)) { // Don't handle long double yet. } } diff --git a/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h b/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h index 5e3d20d7898b..5433ebb4593e 100644 --- a/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h +++ b/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABISysV_s390x_h_ #define liblldb_ABISysV_s390x_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" @@ -61,9 +57,7 @@ public: bool CodeAddressIsValid(lldb::addr_t pc) override { // Code addressed must be 2 byte aligned - if (pc & 1ull) - return false; - return true; + return (pc & 1ull) == 0; } const lldb_private::RegisterInfo * diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp index 36ae3a49827c..dc3e475e3b8e 100644 --- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp +++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp @@ -9,17 +9,12 @@ #include "ABISysV_x86_64.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" @@ -33,6 +28,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" using namespace lldb; @@ -1095,11 +1091,8 @@ size_t ABISysV_x86_64::GetRedZoneSize() const { return 128; } ABISP ABISysV_x86_64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; if (arch.GetTriple().getArch() == llvm::Triple::x86_64) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_x86_64(process_sp)); - return g_abi_sp; + return ABISP(new ABISysV_x86_64(process_sp)); } return ABISP(); } @@ -1270,18 +1263,19 @@ bool ABISysV_x86_64::GetArgumentValues(Thread &thread, // We currently only support extracting values with Clang QualTypes. Do we // care about others? CompilerType compiler_type = value->GetCompilerType(); - if (!compiler_type) + llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread); + if (!bit_size) return false; bool is_signed; if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { - ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), - is_signed, thread, argument_register_ids, - current_argument_register, current_stack_argument); + ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, thread, + argument_register_ids, current_argument_register, + current_stack_argument); } else if (compiler_type.IsPointerType()) { - ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), - false, thread, argument_register_ids, - current_argument_register, current_stack_argument); + ReadIntegerArgument(value->GetScalar(), *bit_size, false, thread, + argument_register_ids, current_argument_register, + current_stack_argument); } } @@ -1339,8 +1333,13 @@ Status ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, error.SetErrorString( "We don't support returning complex values at present"); else { - size_t bit_width = compiler_type.GetBitSize(frame_sp.get()); - if (bit_width <= 64) { + llvm::Optional<uint64_t> bit_width = + compiler_type.GetBitSize(frame_sp.get()); + if (!bit_width) { + error.SetErrorString("can't get type size"); + return error; + } + if (*bit_width <= 64) { const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0); RegisterValue xmm0_value; @@ -1403,11 +1402,14 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (!byte_size) + return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( reg_ctx->GetRegisterInfoByName("rax", 0), 0); const bool is_signed = (type_flags & eTypeIsSigned) != 0; - switch (byte_size) { + switch (*byte_size) { default: break; @@ -1447,8 +1449,9 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( if (type_flags & eTypeIsComplex) { // Don't handle complex yet. } else { - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); - if (byte_size <= sizeof(long double)) { + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0); RegisterValue xmm0_value; @@ -1456,13 +1459,13 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( DataExtractor data; if (xmm0_value.GetData(data)) { lldb::offset_t offset = 0; - if (byte_size == sizeof(float)) { + if (*byte_size == sizeof(float)) { value.GetScalar() = (float)data.GetFloat(&offset); success = true; - } else if (byte_size == sizeof(double)) { + } else if (*byte_size == sizeof(double)) { value.GetScalar() = (double)data.GetDouble(&offset); success = true; - } else if (byte_size == sizeof(long double)) { + } else if (*byte_size == sizeof(long double)) { // Don't handle long double since that can be encoded as 80 bit // floats... } @@ -1485,19 +1488,20 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsVector) { - const size_t byte_size = return_compiler_type.GetByteSize(nullptr); - if (byte_size > 0) { + llvm::Optional<uint64_t> byte_size = + return_compiler_type.GetByteSize(nullptr); + if (byte_size && *byte_size > 0) { const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0); if (altivec_reg == nullptr) altivec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0); if (altivec_reg) { - if (byte_size <= altivec_reg->byte_size) { + if (*byte_size <= altivec_reg->byte_size) { ProcessSP process_sp(thread.GetProcess()); if (process_sp) { std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = process_sp->GetByteOrder(); RegisterValue reg_value; if (reg_ctx->ReadRegister(altivec_reg, reg_value)) { @@ -1514,14 +1518,14 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( } } } - } else if (byte_size <= altivec_reg->byte_size * 2) { + } else if (*byte_size <= altivec_reg->byte_size * 2) { const RegisterInfo *altivec_reg2 = reg_ctx->GetRegisterInfoByName("xmm1", 0); if (altivec_reg2) { ProcessSP process_sp(thread.GetProcess()); if (process_sp) { std::unique_ptr<DataBufferHeap> heap_data_ap( - new DataBufferHeap(byte_size, 0)); + new DataBufferHeap(*byte_size, 0)); const ByteOrder byte_order = process_sp->GetByteOrder(); RegisterValue reg_value; RegisterValue reg_value2; @@ -1571,11 +1575,13 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( if (!reg_ctx_sp) return return_valobj_sp; - const size_t bit_width = return_compiler_type.GetBitSize(&thread); + llvm::Optional<uint64_t> bit_width = return_compiler_type.GetBitSize(&thread); + if (!bit_width) + return return_valobj_sp; if (return_compiler_type.IsAggregateType()) { Target *target = exe_ctx.GetTargetPtr(); bool is_memory = true; - if (bit_width <= 128) { + if (*bit_width <= 128) { ByteOrder target_byte_order = target->GetArchitecture().GetByteOrder(); DataBufferSP data_sp(new DataBufferHeap(16, 0)); DataExtractor return_ext(data_sp, target_byte_order, @@ -1622,20 +1628,21 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( idx, name, &field_bit_offset, nullptr, nullptr); - const size_t field_bit_width = field_compiler_type.GetBitSize(&thread); + llvm::Optional<uint64_t> field_bit_width = + field_compiler_type.GetBitSize(&thread); // if we don't know the size of the field (e.g. invalid type), just // bail out - if (field_bit_width == 0) + if (!field_bit_width || *field_bit_width == 0) break; // If there are any unaligned fields, this is stored in memory. - if (field_bit_offset % field_bit_width != 0) { + if (field_bit_offset % *field_bit_width != 0) { is_memory = true; break; } - uint32_t field_byte_width = field_bit_width / 8; + uint32_t field_byte_width = *field_bit_width / 8; uint32_t field_byte_offset = field_bit_offset / 8; DataExtractor *copy_from_extractor = nullptr; @@ -1668,10 +1675,10 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( } } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) { // Structs with long doubles are always passed in memory. - if (field_bit_width == 128) { + if (*field_bit_width == 128) { is_memory = true; break; - } else if (field_bit_width == 64) { + } else if (*field_bit_width == 64) { // These have to be in a single xmm register. if (fp_bytes == 0) copy_from_extractor = &xmm0_data; @@ -1680,7 +1687,7 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( copy_from_offset = 0; fp_bytes += field_byte_width; - } else if (field_bit_width == 32) { + } else if (*field_bit_width == 32) { // This one is kind of complicated. If we are in an "eightbyte" // with another float, we'll be stuffed into an xmm register with // it. If we are in an "eightbyte" with one or more ints, then we diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h index 5b67e8656d36..4afc8c4cad62 100644 --- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h +++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h @@ -10,10 +10,6 @@ #ifndef liblldb_ABISysV_x86_64_h_ #define liblldb_ABISysV_x86_64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Architecture/Arm/ArchitectureArm.cpp b/source/Plugins/Architecture/Arm/ArchitectureArm.cpp index 1b7ecc88c35e..6993222ba5d4 100644 --- a/source/Plugins/Architecture/Arm/ArchitectureArm.cpp +++ b/source/Plugins/Architecture/Arm/ArchitectureArm.cpp @@ -126,3 +126,33 @@ void ArchitectureArm::OverrideStopInfo(Thread &thread) const { } } } + +addr_t ArchitectureArm::GetCallableLoadAddress(addr_t code_addr, + AddressClass addr_class) const { + bool is_alternate_isa = false; + + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + case AddressClass::eCodeAlternateISA: + is_alternate_isa = true; + break; + default: break; + } + + if ((code_addr & 2u) || is_alternate_isa) + return code_addr | 1u; + return code_addr; +} + +addr_t ArchitectureArm::GetOpcodeLoadAddress(addr_t opcode_addr, + AddressClass addr_class) const { + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + default: break; + } + return opcode_addr & ~(1ull); +} diff --git a/source/Plugins/Architecture/Arm/ArchitectureArm.h b/source/Plugins/Architecture/Arm/ArchitectureArm.h index 484c4a52fcc6..1a052c76b2c9 100644 --- a/source/Plugins/Architecture/Arm/ArchitectureArm.h +++ b/source/Plugins/Architecture/Arm/ArchitectureArm.h @@ -25,6 +25,12 @@ public: void OverrideStopInfo(Thread &thread) const override; + lldb::addr_t GetCallableLoadAddress(lldb::addr_t load_addr, + AddressClass addr_class) const override; + + lldb::addr_t GetOpcodeLoadAddress(lldb::addr_t load_addr, + AddressClass addr_class) const override; + private: static std::unique_ptr<Architecture> Create(const ArchSpec &arch); ArchitectureArm() = default; diff --git a/source/Plugins/Architecture/CMakeLists.txt b/source/Plugins/Architecture/CMakeLists.txt index 01365a64cf96..14ad91644595 100644 --- a/source/Plugins/Architecture/CMakeLists.txt +++ b/source/Plugins/Architecture/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(Arm) +add_subdirectory(Mips) add_subdirectory(PPC64) diff --git a/source/Plugins/Architecture/Mips/ArchitectureMips.cpp b/source/Plugins/Architecture/Mips/ArchitectureMips.cpp new file mode 100644 index 000000000000..0cbbd9922321 --- /dev/null +++ b/source/Plugins/Architecture/Mips/ArchitectureMips.cpp @@ -0,0 +1,241 @@ +//===-- ArchitectureMips.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/Architecture/Mips/ArchitectureMips.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Log.h" + +using namespace lldb_private; +using namespace lldb; + +ConstString ArchitectureMips::GetPluginNameStatic() { + return ConstString("mips"); +} + +void ArchitectureMips::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "Mips-specific algorithms", + &ArchitectureMips::Create); +} + +void ArchitectureMips::Terminate() { + PluginManager::UnregisterPlugin(&ArchitectureMips::Create); +} + +std::unique_ptr<Architecture> ArchitectureMips::Create(const ArchSpec &arch) { + return arch.IsMIPS() ? + std::unique_ptr<Architecture>(new ArchitectureMips(arch)) : nullptr; +} + +ConstString ArchitectureMips::GetPluginName() { return GetPluginNameStatic(); } +uint32_t ArchitectureMips::GetPluginVersion() { return 1; } + +addr_t ArchitectureMips::GetCallableLoadAddress(addr_t code_addr, + AddressClass addr_class) const { + bool is_alternate_isa = false; + + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + case AddressClass::eCodeAlternateISA: + is_alternate_isa = true; + break; + default: break; + } + + if ((code_addr & 2ull) || is_alternate_isa) + return code_addr | 1u; + return code_addr; +} + +addr_t ArchitectureMips::GetOpcodeLoadAddress(addr_t opcode_addr, + AddressClass addr_class) const { + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + default: break; + } + return opcode_addr & ~(1ull); +} + +lldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr, + Target &target) const { + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + Address resolved_addr; + + SectionLoadList §ion_load_list = target.GetSectionLoadList(); + if (section_load_list.IsEmpty()) + // No sections are loaded, so we must assume we are not running yet and + // need to operate only on file address. + target.ResolveFileAddress(addr, resolved_addr); + else + target.ResolveLoadAddress(addr, resolved_addr); + + addr_t current_offset = 0; + + // Get the function boundaries to make sure we don't scan back before the + // beginning of the current function. + ModuleSP temp_addr_module_sp(resolved_addr.GetModule()); + if (temp_addr_module_sp) { + SymbolContext sc; + SymbolContextItem resolve_scope = + eSymbolContextFunction | eSymbolContextSymbol; + temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, + resolve_scope, sc); + Address sym_addr; + if (sc.function) + sym_addr = sc.function->GetAddressRange().GetBaseAddress(); + else if (sc.symbol) + sym_addr = sc.symbol->GetAddress(); + + addr_t function_start = sym_addr.GetLoadAddress(&target); + if (function_start == LLDB_INVALID_ADDRESS) + function_start = sym_addr.GetFileAddress(); + + if (function_start) + current_offset = addr - function_start; + } + + // If breakpoint address is start of function then we dont have to do + // anything. + if (current_offset == 0) + return addr; + + ExecutionContext ctx; + target.CalculateExecutionContext(ctx); + auto insn = GetInstructionAtAddress(ctx, current_offset, addr); + + if (nullptr == insn || !insn->HasDelaySlot()) + return addr; + + // Adjust the breakable address + uint64_t breakable_addr = addr - insn->GetOpcode().GetByteSize(); + if (log) + log->Printf("Target::%s Breakpoint at 0x%8.8" PRIx64 + " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n", + __FUNCTION__, addr, breakable_addr); + + return breakable_addr; +} + +Instruction *ArchitectureMips::GetInstructionAtAddress( + const ExecutionContext &exe_ctx, const Address &resolved_addr, + addr_t symbol_offset) const { + + auto loop_count = symbol_offset / 2; + + uint32_t arch_flags = m_arch.GetFlags(); + bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16; + bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips; + + if (loop_count > 3) { + // Scan previous 6 bytes + if (IsMips16 | IsMicromips) + loop_count = 3; + // For mips-only, instructions are always 4 bytes, so scan previous 4 + // bytes only. + else + loop_count = 2; + } + + // Create Disassembler Instance + lldb::DisassemblerSP disasm_sp( + Disassembler::FindPlugin(m_arch, nullptr, nullptr)); + + InstructionList instruction_list; + InstructionSP prev_insn; + bool prefer_file_cache = true; // Read from file + uint32_t inst_to_choose = 0; + + Address addr = resolved_addr; + + 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); + + uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); + if (num_insns) { + prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0); + insn_size = prev_insn->GetOpcode().GetByteSize(); + if (i == 1 && insn_size == 2) { + // This looks like a valid 2-byte instruction (but it could be a part + // of upper 4 byte instruction). + instruction_list.Append(prev_insn); + inst_to_choose = 1; + } + else if (i == 2) { + // Here we may get one 4-byte instruction or two 2-byte instructions. + if (num_insns == 2) { + // Looks like there are two 2-byte instructions above our + // breakpoint target address. Now the upper 2-byte instruction is + // either a valid 2-byte instruction or could be a part of it's + // upper 4-byte instruction. In both cases we don't care because in + // this case lower 2-byte instruction is definitely a valid + // instruction and whatever i=1 iteration has found out is true. + inst_to_choose = 1; + break; + } + else if (insn_size == 4) { + // This instruction claims its a valid 4-byte instruction. But it + // could be a part of it's upper 4-byte instruction. Lets try + // scanning upper 2 bytes to verify this. + instruction_list.Append(prev_insn); + inst_to_choose = 2; + } + } + else if (i == 3) { + if (insn_size == 4) + // FIXME: We reached here that means instruction at [target - 4] has + // already claimed to be a 4-byte instruction, and now instruction + // at [target - 6] is also claiming that it's a 4-byte instruction. + // This can not be true. In this case we can not decide the valid + // previous instruction so we let lldb set the breakpoint at the + // address given by user. + inst_to_choose = 0; + else + // This is straight-forward + inst_to_choose = 2; + break; + } + } + else { + // Decode failed, bytes do not form a valid instruction. So whatever + // previous iteration has found out is true. + if (i > 1) { + inst_to_choose = i - 1; + break; + } + } + } + + // Check if we are able to find any valid instruction. + if (inst_to_choose) { + if (inst_to_choose > instruction_list.GetSize()) + inst_to_choose--; + return instruction_list.GetInstructionAtIndex(inst_to_choose - 1).get(); + } + + return nullptr; +} diff --git a/source/Plugins/Architecture/Mips/ArchitectureMips.h b/source/Plugins/Architecture/Mips/ArchitectureMips.h new file mode 100644 index 000000000000..2338daf2e468 --- /dev/null +++ b/source/Plugins/Architecture/Mips/ArchitectureMips.h @@ -0,0 +1,52 @@ +//===-- ArchitectureMips.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGIN_ARCHITECTURE_MIPS_H +#define LLDB_PLUGIN_ARCHITECTURE_MIPS_H + +#include "lldb/Core/Architecture.h" +#include "lldb/Utility/ArchSpec.h" + +namespace lldb_private { + +class ArchitectureMips : public Architecture { +public: + static ConstString GetPluginNameStatic(); + static void Initialize(); + static void Terminate(); + + ConstString GetPluginName() override; + uint32_t GetPluginVersion() override; + + void OverrideStopInfo(Thread &thread) const override {} + + lldb::addr_t GetBreakableLoadAddress(lldb::addr_t addr, + Target &) const override; + + lldb::addr_t GetCallableLoadAddress(lldb::addr_t load_addr, + AddressClass addr_class) const override; + + lldb::addr_t GetOpcodeLoadAddress(lldb::addr_t load_addr, + AddressClass addr_class) const override; + +private: + Instruction *GetInstructionAtAddress(const ExecutionContext &exe_ctx, + 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) {} + + ArchSpec m_arch; +}; + +} // namespace lldb_private + +#endif // LLDB_PLUGIN_ARCHITECTURE_MIPS_H diff --git a/source/Plugins/Architecture/Mips/CMakeLists.txt b/source/Plugins/Architecture/Mips/CMakeLists.txt new file mode 100644 index 000000000000..9734edc6b12b --- /dev/null +++ b/source/Plugins/Architecture/Mips/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginArchitectureMips PLUGIN + ArchitectureMips.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbUtility + LINK_COMPONENTS + Support + ) diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp index 9b381dd3b96c..5df842250591 100644 --- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -7,12 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Project includes #include "DisassemblerLLVMC.h" -// Other libraries and framework includes #include "llvm-c/Disassembler.h" #include "llvm/ADT/SmallString.h" #include "llvm/MC/MCAsmInfo.h" @@ -98,16 +94,15 @@ public: bool DoesBranch() override { if (m_does_branch == eLazyBoolCalculate) { - std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler()); - if (disasm_sp) { - disasm_sp->Lock(this, NULL); + 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); + GetDisasmToUse(is_alternate_isa, disasm); const uint8_t *opcode_data = data.GetDataStart(); const size_t opcode_data_len = data.GetByteSize(); llvm::MCInst inst; @@ -125,7 +120,6 @@ public: m_does_branch = eLazyBoolNo; } } - disasm_sp->Unlock(); } } return m_does_branch == eLazyBoolYes; @@ -133,16 +127,15 @@ public: bool HasDelaySlot() override { if (m_has_delay_slot == eLazyBoolCalculate) { - std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler()); - if (disasm_sp) { - disasm_sp->Lock(this, NULL); + 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); + GetDisasmToUse(is_alternate_isa, disasm); const uint8_t *opcode_data = data.GetDataStart(); const size_t opcode_data_len = data.GetByteSize(); llvm::MCInst inst; @@ -160,27 +153,14 @@ public: m_has_delay_slot = eLazyBoolNo; } } - disasm_sp->Unlock(); } } return m_has_delay_slot == eLazyBoolYes; } DisassemblerLLVMC::MCDisasmInstance *GetDisasmToUse(bool &is_alternate_isa) { - is_alternate_isa = false; - std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler()); - if (disasm_sp) { - if (disasm_sp->m_alternate_disasm_up) { - const AddressClass address_class = GetAddressClass(); - - if (address_class == AddressClass::eCodeAlternateISA) { - is_alternate_isa = true; - return disasm_sp->m_alternate_disasm_up.get(); - } - } - return disasm_sp->m_disasm_up.get(); - } - return nullptr; + DisassemblerScope disasm(*this); + return GetDisasmToUse(is_alternate_isa, disasm); } size_t Decode(const lldb_private::Disassembler &disassembler, @@ -189,9 +169,9 @@ public: // All we have to do is read the opcode which can be easy for some // architectures bool got_op = false; - std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler()); - if (disasm_sp) { - const ArchSpec &arch = disasm_sp->GetArchitecture(); + DisassemblerScope disasm(*this); + if (disasm) { + const ArchSpec &arch = disasm->GetArchitecture(); const lldb::ByteOrder byte_order = data.GetByteOrder(); const uint32_t min_op_byte_size = arch.GetMinimumOpcodeByteSize(); @@ -232,7 +212,7 @@ public: if (!got_op) { bool is_alternate_isa = false; DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr = - GetDisasmToUse(is_alternate_isa); + GetDisasmToUse(is_alternate_isa, disasm); const llvm::Triple::ArchType machine = arch.GetMachine(); if (machine == llvm::Triple::arm || machine == llvm::Triple::thumb) { @@ -261,10 +241,8 @@ public: const addr_t pc = m_address.GetFileAddress(); llvm::MCInst inst; - disasm_sp->Lock(this, NULL); const size_t inst_size = mc_disasm_ptr->GetMCInst(opcode_data, opcode_data_len, pc, inst); - disasm_sp->Unlock(); if (inst_size == 0) m_opcode.Clear(); else { @@ -296,19 +274,19 @@ public: std::string out_string; std::string comment_string; - std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler()); - if (disasm_sp) { + DisassemblerScope disasm(*this, exe_ctx); + if (disasm) { DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr; if (address_class == AddressClass::eCodeAlternateISA) - mc_disasm_ptr = disasm_sp->m_alternate_disasm_up.get(); + mc_disasm_ptr = disasm->m_alternate_disasm_up.get(); else - mc_disasm_ptr = disasm_sp->m_disasm_up.get(); + mc_disasm_ptr = disasm->m_disasm_up.get(); lldb::addr_t pc = m_address.GetFileAddress(); m_using_file_addr = true; - const bool data_from_file = disasm_sp->m_data_from_file; + const bool data_from_file = disasm->m_data_from_file; bool use_hex_immediates = true; Disassembler::HexImmediateStyle hex_style = Disassembler::eHexStyleC; @@ -328,8 +306,6 @@ public: } } - disasm_sp->Lock(this, exe_ctx); - const uint8_t *opcode_data = data.GetDataStart(); const size_t opcode_data_len = data.GetByteSize(); llvm::MCInst inst; @@ -345,8 +321,6 @@ public: } } - disasm_sp->Unlock(); - if (inst_size == 0) { m_comment.assign("unknown opcode"); inst_size = m_opcode.GetByteSize(); @@ -423,9 +397,27 @@ public: bool UsingFileAddress() const { return m_using_file_addr; } size_t GetByteSize() const { return m_opcode.GetByteSize(); } - std::shared_ptr<DisassemblerLLVMC> GetDisassembler() { - return m_disasm_wp.lock(); - } + /// Grants exclusive access to the disassembler and initializes it with the + /// given InstructionLLVMC and an optional ExecutionContext. + class DisassemblerScope { + std::shared_ptr<DisassemblerLLVMC> m_disasm; + + public: + explicit DisassemblerScope( + InstructionLLVMC &i, + const lldb_private::ExecutionContext *exe_ctx = nullptr) + : m_disasm(i.m_disasm_wp.lock()) { + m_disasm->m_mutex.lock(); + m_disasm->m_inst = &i; + m_disasm->m_exe_ctx = exe_ctx; + } + ~DisassemblerScope() { m_disasm->m_mutex.unlock(); } + + /// Evaluates to true if this scope contains a valid disassembler. + operator bool() const { return static_cast<bool>(m_disasm); } + + std::shared_ptr<DisassemblerLLVMC> operator->() { return m_disasm; } + }; static llvm::StringRef::const_iterator ConsumeWhitespace(llvm::StringRef::const_iterator osi, @@ -876,16 +868,15 @@ public: bool IsCall() override { if (m_is_call == eLazyBoolCalculate) { - std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler()); - if (disasm_sp) { - disasm_sp->Lock(this, NULL); + 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); + GetDisasmToUse(is_alternate_isa, disasm); const uint8_t *opcode_data = data.GetDataStart(); const size_t opcode_data_len = data.GetByteSize(); llvm::MCInst inst; @@ -900,7 +891,6 @@ public: m_is_call = eLazyBoolNo; } } - disasm_sp->Unlock(); } } return m_is_call == eLazyBoolYes; @@ -913,6 +903,24 @@ protected: LazyBool m_is_call; bool m_is_valid; bool m_using_file_addr; + +private: + DisassemblerLLVMC::MCDisasmInstance * + GetDisasmToUse(bool &is_alternate_isa, DisassemblerScope &disasm) { + is_alternate_isa = false; + if (disasm) { + if (disasm->m_alternate_disasm_up) { + const AddressClass address_class = GetAddressClass(); + + if (address_class == AddressClass::eCodeAlternateISA) { + is_alternate_isa = true; + return disasm->m_alternate_disasm_up.get(); + } + } + return disasm->m_disasm_up.get(); + } + return nullptr; + } }; std::unique_ptr<DisassemblerLLVMC::MCDisasmInstance> @@ -1114,11 +1122,13 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, triple.getSubArch() == llvm::Triple::NoSubArch) triple.setArchName("armv8.2a"); + std::string features_str = ""; const char *triple_str = triple.getTriple().c_str(); // ARM Cortex M0-M7 devices only execute thumb instructions if (arch.IsAlwaysThumbInstructions()) { triple_str = thumb_arch.GetTriple().getTriple().c_str(); + features_str += "+fp-armv8,"; } const char *cpu = ""; @@ -1169,7 +1179,6 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, break; } - std::string features_str = ""; if (triple.getArch() == llvm::Triple::mips || triple.getArch() == llvm::Triple::mipsel || triple.getArch() == llvm::Triple::mips64 || @@ -1201,7 +1210,8 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, if (llvm_arch == llvm::Triple::arm) { std::string thumb_triple(thumb_arch.GetTriple().getTriple()); m_alternate_disasm_up = - MCDisasmInstance::Create(thumb_triple.c_str(), "", "", flavor, *this); + MCDisasmInstance::Create(thumb_triple.c_str(), "", features_str.c_str(), + flavor, *this); if (!m_alternate_disasm_up) m_disasm_up.reset(); @@ -1326,10 +1336,7 @@ bool DisassemblerLLVMC::FlavorValidForArchSpec( if (triple.getArch() == llvm::Triple::x86 || triple.getArch() == llvm::Triple::x86_64) { - if (strcmp(flavor, "intel") == 0 || strcmp(flavor, "att") == 0) - return true; - else - return false; + return strcmp(flavor, "intel") == 0 || strcmp(flavor, "att") == 0; } else return false; } @@ -1368,7 +1375,7 @@ const char *DisassemblerLLVMC::SymbolLookup(uint64_t value, uint64_t *type_ptr, } SymbolContext sym_ctx; - const uint32_t resolve_scope = + const SymbolContextItem resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; if (pc_so_addr.IsValid() && pc_so_addr.GetModule()) { pc_so_addr.GetModule()->ResolveSymbolContextForAddress( diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h index b7e9ccb34701..8b9f7c37d2b8 100644 --- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h +++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h @@ -10,13 +10,10 @@ #ifndef liblldb_DisassemblerLLVMC_h_ #define liblldb_DisassemblerLLVMC_h_ -// C Includes -// C++ Includes #include <memory> #include <mutex> #include <string> -// Project includes #include "lldb/Core/Address.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/PluginManager.h" @@ -77,19 +74,6 @@ protected: uint64_t ReferencePC, const char **ReferenceName); - void Lock(InstructionLLVMC *inst, - const lldb_private::ExecutionContext *exe_ctx) { - m_mutex.lock(); - m_inst = inst; - m_exe_ctx = exe_ctx; - } - - void Unlock() { - m_inst = NULL; - m_exe_ctx = NULL; - m_mutex.unlock(); - } - const lldb_private::ExecutionContext *m_exe_ctx; InstructionLLVMC *m_inst; std::mutex m_mutex; diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 8999000dff8c..3a80c68dd4d7 100644 --- a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -15,7 +15,6 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Core/State.h" #include "lldb/Core/StreamFile.h" #include "lldb/Host/Symbols.h" #include "lldb/Interpreter/OptionValueProperties.h" @@ -29,6 +28,7 @@ #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "DynamicLoaderDarwinKernel.h" @@ -58,7 +58,7 @@ enum KASLRScanType { // range looking for a kernel }; -OptionEnumValueElement g_kaslr_kernel_scan_enum_values[] = { +static constexpr OptionEnumValueElement g_kaslr_kernel_scan_enum_values[] = { {eKASLRScanNone, "none", "Do not read memory looking for a Darwin kernel when attaching."}, {eKASLRScanLowgloAddresses, "basic", "Check for the Darwin kernel's load " @@ -68,17 +68,15 @@ OptionEnumValueElement g_kaslr_kernel_scan_enum_values[] = { "the Darwin kernel's load address."}, {eKASLRScanExhaustiveScan, "exhaustive-scan", "Scan through the entire potential address range of Darwin kernel (only " - "on 32-bit targets)."}, - {0, NULL, NULL}}; + "on 32-bit targets)."}}; -static PropertyDefinition g_properties[] = { - {"load-kexts", OptionValue::eTypeBoolean, true, true, NULL, NULL, +static constexpr PropertyDefinition g_properties[] = { + {"load-kexts", OptionValue::eTypeBoolean, true, true, NULL, {}, "Automatically loads kext images when attaching to a kernel."}, {"scan-type", OptionValue::eTypeEnum, true, eKASLRScanNearPC, NULL, - g_kaslr_kernel_scan_enum_values, "Control how many reads lldb will make " - "while searching for a Darwin kernel on " - "attach."}, - {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; + OptionEnumValues(g_kaslr_kernel_scan_enum_values), + "Control how many reads lldb will make while searching for a Darwin " + "kernel on attach."}}; enum { ePropertyLoadKexts, ePropertyScanType }; @@ -149,6 +147,7 @@ DynamicLoader *DynamicLoaderDarwinKernel::CreateInstance(Process *process, case llvm::Triple::IOS: case llvm::Triple::TvOS: case llvm::Triple::WatchOS: + // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: if (triple_ref.getVendor() != llvm::Triple::Apple) { return NULL; } @@ -212,13 +211,13 @@ DynamicLoaderDarwinKernel::SearchForKernelAtSameLoadAddr(Process *process) { exe_objfile->GetStrata() != ObjectFile::eStrataKernel) return LLDB_INVALID_ADDRESS; - if (!exe_objfile->GetHeaderAddress().IsValid()) + if (!exe_objfile->GetBaseAddress().IsValid()) return LLDB_INVALID_ADDRESS; if (CheckForKernelImageAtAddress( - exe_objfile->GetHeaderAddress().GetFileAddress(), process) == + exe_objfile->GetBaseAddress().GetFileAddress(), process) == exe_module->GetUUID()) - return exe_objfile->GetHeaderAddress().GetFileAddress(); + return exe_objfile->GetBaseAddress().GetFileAddress(); return LLDB_INVALID_ADDRESS; } @@ -294,6 +293,18 @@ DynamicLoaderDarwinKernel::SearchForKernelNearPC(Process *process) { return LLDB_INVALID_ADDRESS; addr_t pc = thread->GetRegisterContext()->GetPC(LLDB_INVALID_ADDRESS); + // The kernel is always loaded in high memory, if the top bit is zero, + // this isn't a kernel. + if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 8) { + if ((pc & (1ULL << 63)) == 0) { + return LLDB_INVALID_ADDRESS; + } + } else { + if ((pc & (1ULL << 31)) == 0) { + return LLDB_INVALID_ADDRESS; + } + } + if (pc == LLDB_INVALID_ADDRESS) return LLDB_INVALID_ADDRESS; @@ -308,12 +319,13 @@ DynamicLoaderDarwinKernel::SearchForKernelNearPC(Process *process) { // Search backwards 32 megabytes, looking for the start of the kernel at each // one-megabyte boundary. for (int i = 0; i < 32; i++, addr -= 0x100000) { + // x86_64 kernels are at offset 0 if (CheckForKernelImageAtAddress(addr, process).IsValid()) return addr; + // 32-bit arm kernels are at offset 0x1000 (one 4k page) if (CheckForKernelImageAtAddress(addr + 0x1000, process).IsValid()) return addr + 0x1000; - if (CheckForKernelImageAtAddress(addr + 0x2000, process).IsValid()) - return addr + 0x2000; + // 64-bit arm kernels are at offset 0x4000 (one 16k page) if (CheckForKernelImageAtAddress(addr + 0x4000, process).IsValid()) return addr + 0x4000; } @@ -352,12 +364,13 @@ lldb::addr_t DynamicLoaderDarwinKernel::SearchForKernelViaExhaustiveSearch( addr_t addr = kernel_range_low; while (addr >= kernel_range_low && addr < kernel_range_high) { + // x86_64 kernels are at offset 0 if (CheckForKernelImageAtAddress(addr, process).IsValid()) return addr; + // 32-bit arm kernels are at offset 0x1000 (one 4k page) if (CheckForKernelImageAtAddress(addr + 0x1000, process).IsValid()) return addr + 0x1000; - if (CheckForKernelImageAtAddress(addr + 0x2000, process).IsValid()) - return addr + 0x2000; + // 64-bit arm kernels are at offset 0x4000 (one 16k page) if (CheckForKernelImageAtAddress(addr + 0x4000, process).IsValid()) return addr + 0x4000; addr += 0x100000; @@ -388,8 +401,8 @@ DynamicLoaderDarwinKernel::ReadMachHeader(addr_t addr, Process *process, llvm::M if (::memcmp (&header.magic, &magicks[i], sizeof (uint32_t)) == 0) found_matching_pattern = true; - if (found_matching_pattern == false) - return false; + if (!found_matching_pattern) + return false; if (header.magic == llvm::MachO::MH_CIGAM || header.magic == llvm::MachO::MH_CIGAM_64) { @@ -425,7 +438,7 @@ DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress(lldb::addr_t addr, llvm::MachO::mach_header header; - if (ReadMachHeader (addr, process, header) == false) + if (!ReadMachHeader(addr, process, header)) return UUID(); // First try a quick test -- read the first 4 bytes and see if there is a @@ -436,8 +449,8 @@ DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress(lldb::addr_t addr, if (header.filetype == llvm::MachO::MH_EXECUTE && (header.flags & llvm::MachO::MH_DYLDLINK) == 0) { // Create a full module to get the UUID - ModuleSP memory_module_sp = process->ReadModuleFromMemory( - FileSpec("temp_mach_kernel", false), addr); + ModuleSP memory_module_sp = + process->ReadModuleFromMemory(FileSpec("temp_mach_kernel"), addr); if (!memory_module_sp.get()) return UUID(); @@ -605,16 +618,10 @@ void DynamicLoaderDarwinKernel::KextImageInfo::SetProcessStopId( bool DynamicLoaderDarwinKernel::KextImageInfo:: operator==(const KextImageInfo &rhs) { if (m_uuid.IsValid() || rhs.GetUUID().IsValid()) { - if (m_uuid == rhs.GetUUID()) { - return true; - } - return false; + return m_uuid == rhs.GetUUID(); } - if (m_name == rhs.GetName() && m_load_address == rhs.GetLoadAddress()) - return true; - - return false; + return m_name == rhs.GetName() && m_load_address == rhs.GetLoadAddress(); } void DynamicLoaderDarwinKernel::KextImageInfo::SetName(const char *name) { @@ -647,16 +654,16 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::ReadMemoryModule( if (m_load_address == LLDB_INVALID_ADDRESS) return false; - FileSpec file_spec; - file_spec.SetFile(m_name.c_str(), false, FileSpec::Style::native); + FileSpec file_spec(m_name.c_str()); llvm::MachO::mach_header mh; size_t size_to_read = 512; - if (ReadMachHeader (m_load_address, process, mh)) { - if (mh.magic == llvm::MachO::MH_CIGAM || llvm::MachO::MH_MAGIC) - size_to_read = sizeof (llvm::MachO::mach_header) + mh.sizeofcmds; - if (mh.magic == llvm::MachO::MH_CIGAM_64 || llvm::MachO::MH_MAGIC_64) - size_to_read = sizeof (llvm::MachO::mach_header_64) + mh.sizeofcmds; + if (ReadMachHeader(m_load_address, process, mh)) { + if (mh.magic == llvm::MachO::MH_CIGAM || mh.magic == llvm::MachO::MH_MAGIC) + size_to_read = sizeof(llvm::MachO::mach_header) + mh.sizeofcmds; + if (mh.magic == llvm::MachO::MH_CIGAM_64 || + mh.magic == llvm::MachO::MH_MAGIC_64) + size_to_read = sizeof(llvm::MachO::mach_header_64) + mh.sizeofcmds; } ModuleSP memory_module_sp = @@ -732,7 +739,7 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::ReadMemoryModule( } bool DynamicLoaderDarwinKernel::KextImageInfo::IsKernel() const { - return m_kernel_image == true; + return m_kernel_image; } void DynamicLoaderDarwinKernel::KextImageInfo::SetIsKernel(bool is_kernel) { @@ -784,7 +791,7 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( // to do anything useful. This will force a clal to if (IsKernel()) { if (Symbols::DownloadObjectAndSymbolFile(module_spec, true)) { - if (module_spec.GetFileSpec().Exists()) { + if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { m_module_sp.reset(new Module(module_spec.GetFileSpec(), target.GetArchitecture())); if (m_module_sp.get() && @@ -807,7 +814,7 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( PlatformDarwinKernel::GetPluginNameStatic()); if (platform_name == g_platform_name) { ModuleSpec kext_bundle_module_spec(module_spec); - FileSpec kext_filespec(m_name.c_str(), false); + FileSpec kext_filespec(m_name.c_str()); kext_bundle_module_spec.GetFileSpec() = kext_filespec; platform_sp->GetSharedModule( kext_bundle_module_spec, process, m_module_sp, @@ -847,7 +854,7 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( target.GetImages().AppendIfNeeded(m_module_sp); if (IsKernel() && target.GetExecutableModulePointer() != m_module_sp.get()) { - target.SetExecutableModule(m_module_sp, false); + target.SetExecutableModule(m_module_sp, eLoadDependentsNo); } } } @@ -932,7 +939,7 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( ObjectFile *kernel_object_file = m_module_sp->GetObjectFile(); if (kernel_object_file) { addr_t file_address = - kernel_object_file->GetHeaderAddress().GetFileAddress(); + kernel_object_file->GetBaseAddress().GetFileAddress(); if (m_load_address != LLDB_INVALID_ADDRESS && file_address != LLDB_INVALID_ADDRESS) { s->Printf("Kernel slid 0x%" PRIx64 " in memory.\n", @@ -1006,10 +1013,10 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() { ObjectFile *kernel_object_file = m_kernel.GetModule()->GetObjectFile(); if (kernel_object_file) { addr_t load_address = - kernel_object_file->GetHeaderAddress().GetLoadAddress( + kernel_object_file->GetBaseAddress().GetLoadAddress( &m_process->GetTarget()); addr_t file_address = - kernel_object_file->GetHeaderAddress().GetFileAddress(); + kernel_object_file->GetBaseAddress().GetFileAddress(); if (load_address != LLDB_INVALID_ADDRESS && load_address != 0) { m_kernel.SetLoadAddress(load_address); if (load_address != file_address) { @@ -1281,7 +1288,7 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries( const uint32_t num_of_new_kexts = kext_summaries.size(); for (uint32_t new_kext = 0; new_kext < num_of_new_kexts; new_kext++) { - if (to_be_added[new_kext] == true) { + if (to_be_added[new_kext]) { KextImageInfo &image_info = kext_summaries[new_kext]; if (load_kexts) { if (!image_info.LoadImageUsingMemoryModule(m_process)) { diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h index 75998f1cc3be..7aacebd9b50f 100644 --- a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h +++ b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h @@ -10,17 +10,13 @@ #ifndef liblldb_DynamicLoaderDarwinKernel_h_ #define liblldb_DynamicLoaderDarwinKernel_h_ -// C Includes -// C++ Includes #include <mutex> #include <string> #include <vector> -// Other libraries and framework includes -#include "lldb/Utility/SafeMachO.h" +#include "lldb/Host/SafeMachO.h" -// Project includes #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Utility/FileSpec.h" diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp index 5ca20229d018..81eab8fdd970 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp @@ -7,9 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" @@ -179,7 +176,7 @@ ModuleSP DynamicLoaderHexagonDYLD::GetTargetExecutable() { return executable; // The target executable file does not exits - if (!executable->GetFileSpec().Exists()) + if (!FileSystem::Instance().Exists(executable->GetFileSpec())) return executable; // Prep module for loading @@ -205,8 +202,7 @@ ModuleSP DynamicLoaderHexagonDYLD::GetTargetExecutable() { if (executable.get() != target.GetExecutableModulePointer()) { // Don't load dependent images since we are in dyld where we will know and // find out about all images that are loaded - const bool get_dependent_images = false; - target.SetExecutableModule(executable, get_dependent_images); + target.SetExecutableModule(executable, eLoadDependentsNo); } return executable; @@ -368,7 +364,8 @@ void DynamicLoaderHexagonDYLD::RefreshModules() { E = m_rendezvous.loaded_end(); for (I = m_rendezvous.loaded_begin(); I != E; ++I) { - FileSpec file(I->path, true); + FileSpec file(I->path); + FileSystem::Instance().Resolve(file); ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr, true); if (module_sp.get()) { @@ -392,7 +389,8 @@ void DynamicLoaderHexagonDYLD::RefreshModules() { E = m_rendezvous.unloaded_end(); for (I = m_rendezvous.unloaded_begin(); I != E; ++I) { - FileSpec file(I->path, true); + FileSpec file(I->path); + FileSystem::Instance().Resolve(file); ModuleSpec module_spec(file); ModuleSP module_sp = loaded_modules.FindFirstModule(module_spec); @@ -455,7 +453,7 @@ DynamicLoaderHexagonDYLD::GetStepThroughTrampolinePlan(Thread &thread, AddressVector::iterator start = addrs.begin(); AddressVector::iterator end = addrs.end(); - std::sort(start, end); + llvm::sort(start, end); addrs.erase(std::unique(start, end), end); thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop)); } @@ -486,7 +484,7 @@ void DynamicLoaderHexagonDYLD::LoadAllCurrentModules() { for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) { const char *module_path = I->path.c_str(); - FileSpec file(module_path, false); + FileSpec file(module_path); ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr, true); if (module_sp.get()) { diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h index 200a4171bd1c..d39f14e8b3fb 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h @@ -10,10 +10,6 @@ #ifndef liblldb_DynamicLoaderHexagonDYLD_h_ #define liblldb_DynamicLoaderHexagonDYLD_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Target/DynamicLoader.h" diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h index bdf6bae75197..758f358dc618 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h @@ -10,14 +10,11 @@ #ifndef liblldb_HexagonDYLDRendezvous_H_ #define liblldb_HexagonDYLDRendezvous_H_ -// C Includes -#include <limits.h> // for PATH_MAX -// C++ Includes +#include <limits.h> #include <list> #include <map> #include <string> -// Other libraries and framework includes #include "lldb/lldb-defines.h" #include "lldb/lldb-types.h" diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index c6439a30c8a3..944be9633e00 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -15,7 +15,6 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Core/State.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/ClangASTContext.h" @@ -32,6 +31,7 @@ #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF @@ -115,7 +115,7 @@ ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo( // No UUID, we must rely upon the cached module modification time and the // modification time of the file on disk if (module_sp->GetModificationTime() != - FileSystem::GetModificationTime(module_sp->GetFileSpec())) + FileSystem::Instance().GetModificationTime(module_sp->GetFileSpec())) module_sp.reset(); } @@ -359,22 +359,24 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo( if (image_sp.get() == nullptr || image_sp->GetAsDictionary() == nullptr) return false; StructuredData::Dictionary *image = image_sp->GetAsDictionary(); - if (image->HasKey("load_address") == false || - image->HasKey("pathname") == false || - image->HasKey("mod_date") == false || - image->HasKey("mach_header") == false || + // clang-format off + if (!image->HasKey("load_address") || + !image->HasKey("pathname") || + !image->HasKey("mod_date") || + !image->HasKey("mach_header") || image->GetValueForKey("mach_header")->GetAsDictionary() == nullptr || - image->HasKey("segments") == false || + !image->HasKey("segments") || image->GetValueForKey("segments")->GetAsArray() == nullptr || - image->HasKey("uuid") == false) { + !image->HasKey("uuid")) { return false; } + // clang-format on image_infos[i].address = image->GetValueForKey("load_address")->GetAsInteger()->GetValue(); image_infos[i].mod_date = image->GetValueForKey("mod_date")->GetAsInteger()->GetValue(); image_infos[i].file_spec.SetFile( - image->GetValueForKey("pathname")->GetAsString()->GetValue(), false, + image->GetValueForKey("pathname")->GetAsString()->GetValue(), FileSpec::Style::native); StructuredData::Dictionary *mh = @@ -400,6 +402,8 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo( image_infos[i].os_type = llvm::Triple::TvOS; else if (os_name == "watchos") image_infos[i].os_type = llvm::Triple::WatchOS; + // NEED_BRIDGEOS_TRIPLE else if (os_name == "bridgeos") + // NEED_BRIDGEOS_TRIPLE image_infos[i].os_type = llvm::Triple::BridgeOS; } if (image->HasKey("min_version_os_sdk")) { image_infos[i].min_version_os_sdk = @@ -513,11 +517,12 @@ void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos( const size_t image_infos_size = image_infos.size(); for (size_t i = 0; i < image_infos_size; i++) { if (image_infos[i].header.filetype == llvm::MachO::MH_DYLINKER) { - // In a "simulator" process (an x86 process that is ios/tvos/watchos) we - // will have two dyld modules -- a "dyld" that we want to keep track of, - // and a "dyld_sim" which we don't need to keep track of here. If the - // target is an x86 system and the OS of the dyld binary is - // ios/tvos/watchos, then we are looking at dyld_sym. + // In a "simulator" process (an x86 process that is + // ios/tvos/watchos/bridgeos) we will have two dyld modules -- + // a "dyld" that we want to keep track of, and a "dyld_sim" which + // we don't need to keep track of here. If the target is an x86 + // system and the OS of the dyld binary is ios/tvos/watchos/bridgeos, + // then we are looking at dyld_sym. // debugserver has only recently (late 2016) started sending up the os // type for each binary it sees -- so if we don't have an os type, use a @@ -531,6 +536,7 @@ void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos( if (image_infos[i].os_type != llvm::Triple::OSType::IOS && image_infos[i].os_type != llvm::Triple::TvOS && image_infos[i].os_type != llvm::Triple::WatchOS) { + // NEED_BRIDGEOS_TRIPLE image_infos[i].os_type != llvm::Triple::BridgeOS) { dyld_idx = i; } } @@ -555,8 +561,7 @@ void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos( target.GetImages().AppendIfNeeded(exe_module_sp); UpdateImageLoadAddress(exe_module_sp.get(), image_infos[exe_idx]); if (exe_module_sp.get() != target.GetExecutableModulePointer()) { - const bool get_dependent_images = false; - target.SetExecutableModule(exe_module_sp, get_dependent_images); + target.SetExecutableModule(exe_module_sp, eLoadDependentsNo); } } } @@ -709,11 +714,7 @@ bool DynamicLoaderDarwin::AlwaysRelyOnEHUnwindInfo(SymbolContext &sym_ctx) { return false; ObjCLanguageRuntime *objc_runtime = m_process->GetObjCLanguageRuntime(); - if (objc_runtime != NULL && objc_runtime->IsModuleObjCLibrary(module_sp)) { - return true; - } - - return false; + return objc_runtime != NULL && objc_runtime->IsModuleObjCLibrary(module_sp); } //---------------------------------------------------------------------- @@ -1124,6 +1125,10 @@ bool DynamicLoaderDarwin::UseDYLDSPI(Process *process) { // watchOS 3 and newer if (os_type == llvm::Triple::WatchOS && version >= llvm::VersionTuple(3)) use_new_spi_interface = true; + + // NEED_BRIDGEOS_TRIPLE // Any BridgeOS + // NEED_BRIDGEOS_TRIPLE if (os_type == llvm::Triple::BridgeOS) + // NEED_BRIDGEOS_TRIPLE use_new_spi_interface = true; } if (log) { diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h index a02d1ad9bee3..690253ba5ff2 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h @@ -10,18 +10,14 @@ #ifndef liblldb_DynamicLoaderDarwin_h_ #define liblldb_DynamicLoaderDarwin_h_ -// C Includes -// C++ Includes #include <map> #include <mutex> #include <vector> -// Other libraries and framework includes -// Project includes +#include "lldb/Host/SafeMachO.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/SafeMachO.h" #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp index 4a8ad38d1785..1ff0ec2c7937 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp @@ -12,7 +12,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Core/State.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" @@ -21,6 +20,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "DynamicLoaderDarwin.h" #include "DynamicLoaderMacOS.h" @@ -55,6 +55,7 @@ DynamicLoader *DynamicLoaderMacOS::CreateInstance(Process *process, case llvm::Triple::IOS: case llvm::Triple::TvOS: case llvm::Triple::WatchOS: + // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: create = triple_ref.getVendor() == llvm::Triple::Apple; break; default: @@ -64,7 +65,7 @@ DynamicLoader *DynamicLoaderMacOS::CreateInstance(Process *process, } } - if (UseDYLDSPI(process) == false) { + if (!UseDYLDSPI(process)) { create = false; } @@ -78,7 +79,8 @@ DynamicLoader *DynamicLoaderMacOS::CreateInstance(Process *process, //---------------------------------------------------------------------- DynamicLoaderMacOS::DynamicLoaderMacOS(Process *process) : DynamicLoaderDarwin(process), m_image_infos_stop_id(UINT32_MAX), - m_break_id(LLDB_INVALID_BREAK_ID), m_mutex() {} + m_break_id(LLDB_INVALID_BREAK_ID), m_mutex(), + m_maybe_image_infos_address(LLDB_INVALID_ADDRESS) {} //---------------------------------------------------------------------- // Destructor @@ -94,16 +96,31 @@ bool DynamicLoaderMacOS::ProcessDidExec() { if (m_process) { // If we are stopped after an exec, we will have only one thread... if (m_process->GetThreadList().GetSize() == 1) { - // See if we are stopped at '_dyld_start' - ThreadSP thread_sp(m_process->GetThreadList().GetThreadAtIndex(0)); - if (thread_sp) { - lldb::StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); - if (frame_sp) { - const Symbol *symbol = - frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol; - if (symbol) { - if (symbol->GetName() == ConstString("_dyld_start")) - did_exec = true; + // Maybe we still have an image infos address around? If so see + // if that has changed, and if so we have exec'ed. + if (m_maybe_image_infos_address != LLDB_INVALID_ADDRESS) { + lldb::addr_t image_infos_address = m_process->GetImageInfoAddress(); + if (image_infos_address != m_maybe_image_infos_address) { + // We don't really have to reset this here, since we are going to + // call DoInitialImageFetch right away to handle the exec. But in + // case anybody looks at it in the meantime, it can't hurt. + m_maybe_image_infos_address = image_infos_address; + did_exec = true; + } + } + + if (!did_exec) { + // See if we are stopped at '_dyld_start' + ThreadSP thread_sp(m_process->GetThreadList().GetThreadAtIndex(0)); + if (thread_sp) { + lldb::StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); + if (frame_sp) { + const Symbol *symbol = + frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol; + if (symbol) { + if (symbol->GetName() == ConstString("_dyld_start")) + did_exec = true; + } } } } @@ -179,6 +196,7 @@ void DynamicLoaderMacOS::DoInitialImageFetch() { } m_dyld_image_infos_stop_id = m_process->GetStopID(); + m_maybe_image_infos_address = m_process->GetImageInfoAddress(); } bool DynamicLoaderMacOS::NeedToDoInitialImageFetch() { return true; } @@ -485,8 +503,7 @@ bool DynamicLoaderMacOS::GetSharedCacheInformation( info_dict->GetValueForKey("shared_cache_uuid")->GetStringValue(); if (!uuid_str.empty()) uuid.SetFromStringRef(uuid_str); - if (info_dict->GetValueForKey("no_shared_cache")->GetBooleanValue() == - false) + if (!info_dict->GetValueForKey("no_shared_cache")->GetBooleanValue()) using_shared_cache = eLazyBoolYes; else using_shared_cache = eLazyBoolNo; diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h index db90966e5615..6303c066511c 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // This is the DynamicLoader plugin for Darwin (macOS / iPhoneOS / tvOS / -// watchOS) +// watchOS / BridgeOS) // platforms late 2016 and newer, where lldb will call dyld SPI functions to get // information about shared libraries, information about the shared cache, and // the _dyld_debugger_notification function we put a breakpoint on give us an @@ -18,17 +18,12 @@ #ifndef liblldb_DynamicLoaderMacOS_h_ #define liblldb_DynamicLoaderMacOS_h_ -// C Includes -// C++ Includes #include <mutex> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/SafeMachO.h" #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" @@ -109,6 +104,12 @@ protected: // loaded/unloaded images lldb::user_id_t m_break_id; mutable std::recursive_mutex m_mutex; + lldb::addr_t m_maybe_image_infos_address; // If dyld is still maintaining the + // all_image_infos address, store it + // here so we can use it to detect + // exec's when talking to + // debugservers that don't support + // the "reason:exec" annotation. private: DISALLOW_COPY_AND_ASSIGN(DynamicLoaderMacOS); diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index 265f19d0ca06..ec459a783f94 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -13,7 +13,6 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Core/State.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" @@ -27,6 +26,7 @@ #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "DynamicLoaderDarwin.h" #include "DynamicLoaderMacOSXDYLD.h" @@ -75,6 +75,7 @@ DynamicLoader *DynamicLoaderMacOSXDYLD::CreateInstance(Process *process, case llvm::Triple::IOS: case llvm::Triple::TvOS: case llvm::Triple::WatchOS: + // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: create = triple_ref.getVendor() == llvm::Triple::Apple; break; default: @@ -84,7 +85,7 @@ DynamicLoader *DynamicLoaderMacOSXDYLD::CreateInstance(Process *process, } } - if (UseDYLDSPI(process) == true) { + if (UseDYLDSPI(process)) { create = false; } @@ -121,12 +122,12 @@ bool DynamicLoaderMacOSXDYLD::ProcessDidExec() { // value differs from the Process' image info address. When a process // execs itself it might cause a change if ASLR is enabled. const addr_t shlib_addr = m_process->GetImageInfoAddress(); - if (m_process_image_addr_is_all_images_infos == true && + if (m_process_image_addr_is_all_images_infos && shlib_addr != m_dyld_all_image_infos_addr) { // The image info address from the process is the // 'dyld_all_image_infos' address and it has changed. did_exec = true; - } else if (m_process_image_addr_is_all_images_infos == false && + } else if (!m_process_image_addr_is_all_images_infos && shlib_addr == m_dyld.address) { // The image info address from the process is the mach_header address // for dyld and it has changed. @@ -692,9 +693,7 @@ bool DynamicLoaderMacOSXDYLD::ReadImageInfos( error); // don't resolve the path if (error.Success()) { - const bool resolve_path = false; - image_infos[i].file_spec.SetFile(raw_path, resolve_path, - FileSpec::Style::native); + image_infos[i].file_spec.SetFile(raw_path, FileSpec::Style::native); } } return true; @@ -893,7 +892,8 @@ uint32_t DynamicLoaderMacOSXDYLD::ParseLoadCommands(const DataExtractor &data, const lldb::offset_t name_offset = load_cmd_offset + data.GetU32(&offset); const char *path = data.PeekCStr(name_offset); - lc_id_dylinker->SetFile(path, true, FileSpec::Style::native); + lc_id_dylinker->SetFile(path, FileSpec::Style::native); + FileSystem::Instance().Resolve(*lc_id_dylinker); } break; @@ -975,9 +975,8 @@ void DynamicLoaderMacOSXDYLD::UpdateImageInfosHeaderAndLoadCommands( // re-add it back to make sure it is always in the list. ModuleSP dyld_module_sp(GetDYLDModule()); - const bool get_dependent_images = false; m_process->GetTarget().SetExecutableModule(exe_module_sp, - get_dependent_images); + eLoadDependentsNo); if (dyld_module_sp) { if (target.GetImages().AppendIfNeeded(dyld_module_sp)) { diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h index 8b5052e4e230..3dc0f15bddf7 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // This is the DynamicLoader plugin for Darwin (macOS / iPhoneOS / tvOS / -// watchOS) +// watchOS / BridgeOS) // platforms earlier than 2016, where lldb would read the "dyld_all_image_infos" // dyld internal structure to understand where things were loaded and the // solib loaded/unloaded notification function we put a breakpoint on gives us @@ -21,17 +21,13 @@ #ifndef liblldb_DynamicLoaderMacOSXDYLD_h_ #define liblldb_DynamicLoaderMacOSXDYLD_h_ -// C Includes -// C++ Includes #include <mutex> #include <vector> -// Other libraries and framework includes -// Project includes +#include "lldb/Host/SafeMachO.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/SafeMachO.h" #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp index 7dd2b57da0cb..8068795df53a 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp @@ -100,7 +100,7 @@ const char *AuxVector::GetEntryName(EntryType type) { #define ENTRY_NAME(_type) \ _type: \ - name = #_type + 5 + name = &#_type[5] switch (type) { case ENTRY_NAME(AUXV_AT_NULL); break; case ENTRY_NAME(AUXV_AT_IGNORE); break; diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h index 3b06fe18f0c6..25446e33afd4 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h @@ -10,11 +10,8 @@ #ifndef liblldb_AuxVector_H_ #define liblldb_AuxVector_H_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes #include "lldb/lldb-forward.h" namespace lldb_private { diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp index b1513b51a90a..b30a1ab2cf1f 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -243,7 +243,7 @@ bool DYLDRendezvous::FillSOEntryFromModuleInfo( entry.base_addr = base_addr; entry.dyn_addr = dyn_addr; - entry.file_spec.SetFile(name, false, FileSpec::Style::native); + entry.file_spec.SetFile(name, FileSpec::Style::native); UpdateBaseAddrIfNecessary(entry, name); @@ -455,14 +455,10 @@ static bool isLoadBiasIncorrect(Target &target, const std::string &file_path) { // On Android L (API 21, 22) the load address of the "/system/bin/linker" // isn't filled in correctly. unsigned os_major = target.GetPlatform()->GetOSVersion().getMajor(); - if (target.GetArchitecture().GetTriple().isAndroid() && - (os_major == 21 || os_major == 22) && - (file_path == "/system/bin/linker" || - file_path == "/system/bin/linker64")) { - return true; - } - - return false; + return target.GetArchitecture().GetTriple().isAndroid() && + (os_major == 21 || os_major == 22) && + (file_path == "/system/bin/linker" || + file_path == "/system/bin/linker64"); } void DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry, @@ -517,7 +513,7 @@ bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) { return false; std::string file_path = ReadStringFromMemory(entry.path_addr); - entry.file_spec.SetFile(file_path, false, FileSpec::Style::native); + entry.file_spec.SetFile(file_path, FileSpec::Style::native); UpdateBaseAddrIfNecessary(entry, file_path); diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h index a7071801f569..f1a62c3bf9d8 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h @@ -10,12 +10,9 @@ #ifndef liblldb_Rendezvous_H_ #define liblldb_Rendezvous_H_ -// C Includes -// C++ Includes #include <list> #include <string> -// Other libraries and framework includes #include "lldb/Utility/FileSpec.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-types.h" diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 26825d879f04..6774b4fd1291 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -10,10 +10,8 @@ // Main header include #include "DynamicLoaderPOSIXDYLD.h" -// Project includes #include "AuxVector.h" -// Other libraries and framework includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" @@ -29,8 +27,6 @@ #include "lldb/Target/ThreadPlanRunToAddress.h" #include "lldb/Utility/Log.h" -// C++ Includes -// C Includes using namespace lldb; using namespace lldb_private; @@ -121,7 +117,7 @@ void DynamicLoaderPOSIXDYLD::DidAttach() { EvalSpecialModulesStatus(); // if we dont have a load address we cant re-base - bool rebase_exec = (load_offset == LLDB_INVALID_ADDRESS) ? false : true; + bool rebase_exec = load_offset != LLDB_INVALID_ADDRESS; // if we have a valid executable if (executable_sp.get()) { @@ -500,7 +496,7 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, AddressVector::iterator start = addrs.begin(); AddressVector::iterator end = addrs.end(); - std::sort(start, end); + llvm::sort(start, end); addrs.erase(std::unique(start, end), end); thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop)); } @@ -512,7 +508,7 @@ void DynamicLoaderPOSIXDYLD::LoadVDSO() { if (m_vdso_base == LLDB_INVALID_ADDRESS) return; - FileSpec file("[vdso]", false); + FileSpec file("[vdso]"); MemoryRegionInfo info; Status status = m_process->GetMemoryRegionInfo(m_vdso_base, info); @@ -543,7 +539,7 @@ ModuleSP DynamicLoaderPOSIXDYLD::LoadInterpreterModule() { return nullptr; } - FileSpec file(info.GetName().GetCString(), false); + FileSpec file(info.GetName().GetCString()); ModuleSpec module_spec(file, target.GetArchitecture()); if (ModuleSP module_sp = target.GetSharedModule(module_spec)) { @@ -756,7 +752,7 @@ void DynamicLoaderPOSIXDYLD::ResolveExecutableModule( return; } - target.SetExecutableModule(module_sp, false); + target.SetExecutableModule(module_sp, eLoadDependentsNo); } bool DynamicLoaderPOSIXDYLD::AlwaysRelyOnEHUnwindInfo( diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index 0456baf4a658..c5f2d3bcffbc 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -10,13 +10,9 @@ #ifndef liblldb_DynamicLoaderPOSIXDYLD_h_ #define liblldb_DynamicLoaderPOSIXDYLD_h_ -// C Includes -// C++ Includes #include <map> #include <memory> -// Other libraries and framework includes -// Project includes #include "DYLDRendezvous.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/ModuleList.h" diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h index 2d18ec86afd3..7f8f82c76f72 100644 --- a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h +++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h @@ -10,10 +10,6 @@ #ifndef liblldb_DynamicLoaderStatic_h_ #define liblldb_DynamicLoaderStatic_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Utility/FileSpec.h" diff --git a/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp index 6502d7a7a58c..9405b1a5cfdc 100644 --- a/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp +++ b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp @@ -10,12 +10,14 @@ #include "DynamicLoaderWindowsDYLD.h" +#include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadPlanStepInstruction.h" +#include "lldb/Utility/Log.h" #include "llvm/ADT/Triple.h" @@ -60,7 +62,39 @@ DynamicLoader *DynamicLoaderWindowsDYLD::CreateInstance(Process *process, return nullptr; } -void DynamicLoaderWindowsDYLD::DidAttach() {} +void DynamicLoaderWindowsDYLD::DidAttach() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderWindowsDYLD::%s()", __FUNCTION__); + + ModuleSP executable = GetTargetExecutable(); + + if (!executable.get()) + return; + + // Try to fetch the load address of the file from the process, since there + // could be randomization of the load address. + + // It might happen that the remote has a different dir for the file, so we + // only send the basename of the executable in the query. I think this is safe + // because I doubt that two executables with the same basenames are loaded in + // memory... + FileSpec file_spec( + executable->GetPlatformFileSpec().GetFilename().GetCString()); + bool is_loaded; + addr_t base_addr = 0; + lldb::addr_t load_addr; + Status error = m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr); + if (error.Success() && is_loaded) { + base_addr = load_addr; + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, base_addr, false); + } + + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + m_process->LoadModules(); +} void DynamicLoaderWindowsDYLD::DidLaunch() {} diff --git a/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h index de6e295f7891..342b32b10927 100644 --- a/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h +++ b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h @@ -10,10 +10,6 @@ #ifndef liblldb_Plugins_Process_Windows_DynamicLoaderWindowsDYLD_h_ #define liblldb_Plugins_Process_Windows_DynamicLoaderWindowsDYLD_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/DynamicLoader.h" #include "lldb/lldb-forward.h" diff --git a/source/Plugins/ExpressionParser/CMakeLists.txt b/source/Plugins/ExpressionParser/CMakeLists.txt index dc0540ad30a1..17c40aee44cc 100644 --- a/source/Plugins/ExpressionParser/CMakeLists.txt +++ b/source/Plugins/ExpressionParser/CMakeLists.txt @@ -1,2 +1 @@ add_subdirectory(Clang) -add_subdirectory(Go) diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index fa49a51f32a6..c2bc18a04e95 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -87,7 +87,8 @@ void ASTResultSynthesizer::TransformTopLevelDecl(Decl *D) { SynthesizeObjCMethodResult(method_decl); } } else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D)) { - if (m_ast_context && + // When completing user input the body of the function may be a nullptr. + if (m_ast_context && function_decl->hasBody() && !function_decl->getNameInfo().getAsString().compare("$__lldb_expr")) { RecordPersistentTypes(function_decl); SynthesizeFunctionResult(function_decl); diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index d98a2b25fbb7..84771e59531d 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -332,11 +332,9 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { TypeList types; - SymbolContext null_sc; ConstString name(tag_decl->getName().str().c_str()); - i->first->FindTypesInNamespace(null_sc, name, &i->second, UINT32_MAX, - types); + i->first->FindTypesInNamespace(name, &i->second, UINT32_MAX, types); for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) { lldb::TypeSP type = types.GetTypeAtIndex(ti); @@ -366,7 +364,6 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { } else { TypeList types; - SymbolContext null_sc; ConstString name(tag_decl->getName().str().c_str()); CompilerDeclContext namespace_decl; @@ -374,7 +371,7 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { bool exact_match = false; llvm::DenseSet<SymbolFile *> searched_symbol_files; - module_list.FindTypes(null_sc, name, exact_match, UINT32_MAX, + module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX, searched_symbol_files, types); for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) { @@ -771,18 +768,16 @@ bool ClangASTSource::IgnoreName(const ConstString name, static const ConstString id_name("id"); static const ConstString Class_name("Class"); - if (name == id_name || name == Class_name) - return true; + if (m_ast_context->getLangOpts().ObjC) + if (name == id_name || name == Class_name) + return true; StringRef name_string_ref = name.GetStringRef(); // The ClangASTSource is not responsible for finding $-names. - if (name_string_ref.empty() || - (ignore_all_dollar_names && name_string_ref.startswith("$")) || - name_string_ref.startswith("_$")) - return true; - - return false; + return name_string_ref.empty() || + (ignore_all_dollar_names && name_string_ref.startswith("$")) || + name_string_ref.startswith("_$"); } void ClangASTSource::FindExternalVisibleDecls( @@ -804,10 +799,8 @@ void ClangASTSource::FindExternalVisibleDecls( SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor(); if (symbol_vendor) { - SymbolContext null_sc; - found_namespace_decl = - symbol_vendor->FindNamespace(null_sc, name, &namespace_decl); + symbol_vendor->FindNamespace(name, &namespace_decl); if (found_namespace_decl) { context.m_namespace_map->push_back( @@ -837,10 +830,8 @@ void ClangASTSource::FindExternalVisibleDecls( if (!symbol_vendor) continue; - SymbolContext null_sc; - found_namespace_decl = - symbol_vendor->FindNamespace(null_sc, name, &namespace_decl); + symbol_vendor->FindNamespace(name, &namespace_decl); if (found_namespace_decl) { context.m_namespace_map->push_back( @@ -860,15 +851,12 @@ void ClangASTSource::FindExternalVisibleDecls( break; TypeList types; - SymbolContext null_sc; const bool exact_match = true; llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files; if (module_sp && namespace_decl) - module_sp->FindTypesInNamespace(null_sc, name, &namespace_decl, 1, types); + module_sp->FindTypesInNamespace(name, &namespace_decl, 1, types); else { - SymbolContext sc; - sc.module_sp = module_sp; - m_target->GetImages().FindTypes(sc, name, exact_match, 1, + m_target->GetImages().FindTypes(module_sp.get(), name, exact_match, 1, searched_symbol_files, types); } @@ -1655,10 +1643,10 @@ static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map, std::vector<PairType> sorted_items; sorted_items.reserve(source_map.size()); sorted_items.assign(source_map.begin(), source_map.end()); - std::sort(sorted_items.begin(), sorted_items.end(), - [](const PairType &lhs, const PairType &rhs) { - return lhs.second < rhs.second; - }); + llvm::sort(sorted_items.begin(), sorted_items.end(), + [](const PairType &lhs, const PairType &rhs) { + return lhs.second < rhs.second; + }); for (const auto &item : sorted_items) { DeclFromUser<D> user_decl(const_cast<D *>(item.first)); @@ -1883,10 +1871,8 @@ void ClangASTSource::CompleteNamespaceMap( if (!symbol_vendor) continue; - SymbolContext null_sc; - - found_namespace_decl = symbol_vendor->FindNamespace( - null_sc, name, &module_parent_namespace_decl); + found_namespace_decl = + symbol_vendor->FindNamespace(name, &module_parent_namespace_decl); if (!found_namespace_decl) continue; @@ -1918,10 +1904,8 @@ void ClangASTSource::CompleteNamespaceMap( if (!symbol_vendor) continue; - SymbolContext null_sc; - found_namespace_decl = - symbol_vendor->FindNamespace(null_sc, name, &null_namespace_decl); + symbol_vendor->FindNamespace(name, &null_namespace_decl); if (!found_namespace_decl) continue; diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 0811a7999920..9c2f8c4b6c92 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -17,7 +17,6 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/Materializer.h" @@ -44,6 +43,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-private.h" #include "clang/AST/ASTConsumer.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index b67387930190..93fa57876bce 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -10,18 +10,14 @@ #ifndef liblldb_ClangExpressionDeclMap_h_ #define liblldb_ClangExpressionDeclMap_h_ -// C Includes #include <signal.h> #include <stdint.h> -// C++ Includes #include <vector> #include "ClangASTSource.h" #include "ClangExpressionVariable.h" -// Other libraries and framework includes -// Project includes #include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Expression/Materializer.h" @@ -325,12 +321,6 @@ public: /// @param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. /// - /// @param[in] name - /// The name as a plain C string. The NameSearchContext contains - /// a DeclarationName for the name so at first the name may seem - /// redundant, but ClangExpressionDeclMap operates in RTTI land so - /// it can't access DeclarationName. - /// /// @param[in] current_id /// The ID for the current FindExternalVisibleDecls invocation, /// for logging purposes. diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h index e0d3ace15bd1..b5b640c9185f 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h @@ -10,14 +10,10 @@ #ifndef liblldb_ClangExpression_h_ #define liblldb_ClangExpression_h_ -// C Includes -// C++ Includes #include <map> #include <string> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Core/ClangForward.h" #include "lldb/Expression/ExpressionTypeSystemHelper.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index c5406fcc3340..6650c0db967f 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -7,12 +7,11 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes +#include <cctype> #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/AST/PrettyPrinter.h" #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceLocation.h" @@ -34,6 +33,8 @@ #include "clang/Parse/ParseAST.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/Rewrite/Frontend/FrontendActions.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" #include "llvm/ADT/StringRef.h" @@ -55,7 +56,6 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Signals.h" -// Project includes #include "ClangDiagnostic.h" #include "ClangExpressionParser.h" @@ -222,7 +222,7 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, Expression &expr, bool generate_debug_info) : ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(), - m_code_generator(), m_pp_callbacks(nullptr) { + m_pp_callbacks(nullptr) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // We can't compile expressions without a target. So if the exe_scope is @@ -377,8 +377,7 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, m_compiler->getLangOpts().CPlusPlus = true; break; case lldb::eLanguageTypeObjC: - m_compiler->getLangOpts().ObjC1 = true; - m_compiler->getLangOpts().ObjC2 = true; + m_compiler->getLangOpts().ObjC = true; // FIXME: the following language option is a temporary workaround, // to "ask for ObjC, get ObjC++" (see comment above). m_compiler->getLangOpts().CPlusPlus = true; @@ -399,16 +398,14 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, LLVM_FALLTHROUGH; case lldb::eLanguageTypeC_plus_plus_03: m_compiler->getLangOpts().CPlusPlus = true; - // FIXME: the following language option is a temporary workaround, - // to "ask for C++, get ObjC++". Apple hopes to remove this requirement on - // non-Apple platforms, but for now it is needed. - m_compiler->getLangOpts().ObjC1 = true; + if (process_sp) + m_compiler->getLangOpts().ObjC = + process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC) != nullptr; break; case lldb::eLanguageTypeObjC_plus_plus: case lldb::eLanguageTypeUnknown: default: - m_compiler->getLangOpts().ObjC1 = true; - m_compiler->getLangOpts().ObjC2 = true; + m_compiler->getLangOpts().ObjC = true; m_compiler->getLangOpts().CPlusPlus = true; m_compiler->getLangOpts().CPlusPlus11 = true; m_compiler->getHeaderSearchOpts().UseLibcxx = true; @@ -432,7 +429,7 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, // long time parsing and importing debug information. m_compiler->getLangOpts().SpellChecking = false; - if (process_sp && m_compiler->getLangOpts().ObjC1) { + if (process_sp && m_compiler->getLangOpts().ObjC) { if (process_sp->GetObjCLanguageRuntime()) { if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() == ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2) @@ -452,6 +449,10 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, false; // Debuggers get universal access m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name + // We enable all builtin functions beside the builtins from libc/libm (e.g. + // 'fopen'). Those libc functions are already correctly handled by LLDB, and + // additionally enabling them as expandable builtins is breaking Clang. + m_compiler->getLangOpts().NoBuiltin = true; // Set CodeGen options m_compiler->getCodeGenOpts().EmitDeclMetadata = true; @@ -507,15 +508,14 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, // 8. Most of this we get from the CompilerInstance, but we also want to give // the context an ExternalASTSource. - m_selector_table.reset(new SelectorTable()); - m_builtin_context.reset(new Builtin::Context()); - std::unique_ptr<clang::ASTContext> ast_context( - new ASTContext(m_compiler->getLangOpts(), m_compiler->getSourceManager(), - m_compiler->getPreprocessor().getIdentifierTable(), - *m_selector_table.get(), *m_builtin_context.get())); + auto &PP = m_compiler->getPreprocessor(); + auto &builtin_context = PP.getBuiltinInfo(); + builtin_context.initializeBuiltins(PP.getIdentifierTable(), + m_compiler->getLangOpts()); - ast_context->InitBuiltinTypes(m_compiler->getTarget()); + m_compiler->createASTContext(); + clang::ASTContext &ast_context = m_compiler->getASTContext(); ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); @@ -524,14 +524,13 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, if (decl_map) { llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source( decl_map->CreateProxy()); - decl_map->InstallASTContext(*ast_context, m_compiler->getFileManager()); - ast_context->setExternalSource(ast_source); + decl_map->InstallASTContext(ast_context, m_compiler->getFileManager()); + ast_context.setExternalSource(ast_source); } m_ast_context.reset( new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str())); - m_ast_context->setASTContext(ast_context.get()); - m_compiler->setASTContext(ast_context.release()); + m_ast_context->setASTContext(&ast_context); std::string module_name("$__lldb_module"); @@ -544,7 +543,270 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, ClangExpressionParser::~ClangExpressionParser() {} +namespace { + +//---------------------------------------------------------------------- +/// @class CodeComplete +/// +/// A code completion consumer for the clang Sema that is responsible for +/// creating the completion suggestions when a user requests completion +/// of an incomplete `expr` invocation. +//---------------------------------------------------------------------- +class CodeComplete : public CodeCompleteConsumer { + CodeCompletionTUInfo m_info; + + 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; + + /// 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. + /// + /// Note: lldb uses '$' in its internal identifiers, so we also allow this. + static bool IsIdChar(char c) { + return c == '_' || std::isalnum(c) || c == '$'; + } + + /// Returns true if the given character is used to separate arguments + /// in the command line of lldb. + static bool IsTokenSeparator(char c) { return c == ' ' || c == '\t'; } + + /// 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) { + if (cmd.empty()) + return cmd; + + // If we are at the start of a word, then all tokens are unrelated to + // the current completion logic. + if (IsTokenSeparator(cmd.back())) + return StringRef(); + + // Remove all previous tokens from the string as they are unrelated + // to completing the current token. + StringRef to_remove = cmd; + while (!to_remove.empty() && !IsTokenSeparator(to_remove.back())) { + to_remove = to_remove.drop_back(); + } + cmd = cmd.drop_front(to_remove.size()); + + return cmd; + } + + /// Removes the last identifier token from the given cmd line. + StringRef removeLastToken(StringRef cmd) { + while (!cmd.empty() && IsIdChar(cmd.back())) { + cmd = cmd.drop_back(); + } + return cmd; + } + + /// Attemps 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 existing_command = existing.substr(0, pos); + // We rewrite the last token with the completion, so let's drop that + // token from the command. + existing_command = removeLastToken(existing_command); + // We also should remove all previous tokens from the command as they + // would otherwise be added to the completion that already has the + // completion. + existing_command = dropUnrelatedFrontTokens(existing_command); + return existing_command.str() + completion.str(); + } + +public: + /// Constructs a CodeComplete consumer that can be attached to a Sema. + /// @param[out] matches + /// The list of matches that the lldb completion API expects as a result. + /// This may already contain matches, so it's only allowed to append + /// to this variable. + /// @param[out] expr + /// The whole expression string that we are currently parsing. This + /// string needs to be equal to the input the user typed, and NOT the + /// final code that Clang is parsing. + /// @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) + : CodeCompleteConsumer(CodeCompleteOptions(), false), + m_info(std::make_shared<GlobalCodeCompletionAllocator>()), m_expr(expr), + m_position(position), m_request(request), m_desc_policy(ops) { + + // Ensure that the printing policy is producing a description that is as + // short as possible. + m_desc_policy.SuppressScope = true; + m_desc_policy.SuppressTagKeyword = true; + m_desc_policy.FullyQualifiedName = false; + m_desc_policy.TerseOutput = true; + m_desc_policy.IncludeNewlines = false; + m_desc_policy.UseVoidForZeroParams = false; + m_desc_policy.Bool = true; + } + + /// Deregisters and destroys this code-completion consumer. + virtual ~CodeComplete() {} + + /// \name Code-completion filtering + /// Check if the result should be filtered out. + bool isResultFilteredOut(StringRef Filter, + CodeCompletionResult Result) override { + // This code is mostly copied from CodeCompleteConsumer. + switch (Result.Kind) { + case CodeCompletionResult::RK_Declaration: + return !( + Result.Declaration->getIdentifier() && + Result.Declaration->getIdentifier()->getName().startswith(Filter)); + case CodeCompletionResult::RK_Keyword: + return !StringRef(Result.Keyword).startswith(Filter); + case CodeCompletionResult::RK_Macro: + return !Result.Macro->getName().startswith(Filter); + case CodeCompletionResult::RK_Pattern: + return !StringRef(Result.Pattern->getAsString()).startswith(Filter); + } + // If we trigger this assert or the above switch yields a warning, then + // CodeCompletionResult has been enhanced with more kinds of completion + // results. Expand the switch above in this case. + assert(false && "Unknown completion result type?"); + // If we reach this, then we should just ignore whatever kind of unknown + // result we got back. We probably can't turn it into any kind of useful + // completion suggestion with the existing code. + return true; + } + + /// \name Code-completion callbacks + /// Process the finalized code-completion results. + void ProcessCodeCompleteResults(Sema &SemaRef, CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) override { + + // The Sema put the incomplete token we try to complete in here during + // lexing, so we need to retrieve it here to know what we are completing. + StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter(); + + // Iterate over all the results. Filter out results we don't want and + // process the rest. + for (unsigned I = 0; I != NumResults; ++I) { + // Filter the results with the information from the Sema. + if (!Filter.empty() && isResultFilteredOut(Filter, Results[I])) + 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_")) + 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); + } + } + } + + /// \param S the semantic-analyzer object for which code-completion is being + /// done. + /// + /// \param CurrentArg the index of the current argument. + /// + /// \param Candidates an array of overload candidates. + /// + /// \param NumCandidates the number of overload candidates + void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates, + SourceLocation OpenParLoc) override { + // At the moment we don't filter out any overloaded candidates. + } + + CodeCompletionAllocator &getAllocator() override { + return m_info.getAllocator(); + } + + CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return m_info; } +}; +} // namespace + +bool ClangExpressionParser::Complete(CompletionRequest &request, unsigned line, + unsigned pos, unsigned typed_pos) { + DiagnosticManager mgr; + // We need the raw user expression here because that's what the CodeComplete + // class uses to provide completion suggestions. + // However, the `Text` method only gives us the transformed expression here. + // To actually get the raw user input here, we have to cast our expression to + // the LLVMUserExpression which exposes the right API. This should never fail + // as we always have a ClangUserExpression whenever we call this. + LLVMUserExpression &llvm_expr = *static_cast<LLVMUserExpression *>(&m_expr); + CodeComplete CC(request, 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); + return true; +} + unsigned ClangExpressionParser::Parse(DiagnosticManager &diagnostic_manager) { + return ParseInternal(diagnostic_manager); +} + +unsigned +ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, + CodeCompleteConsumer *completion_consumer, + unsigned completion_line, + unsigned completion_column) { ClangDiagnosticManagerAdapter *adapter = static_cast<ClangDiagnosticManagerAdapter *>( m_compiler->getDiagnostics().getClient()); @@ -557,10 +819,20 @@ unsigned ClangExpressionParser::Parse(DiagnosticManager &diagnostic_manager) { clang::SourceManager &source_mgr = m_compiler->getSourceManager(); bool created_main_file = false; - if (m_compiler->getCodeGenOpts().getDebugInfo() == - codegenoptions::FullDebugInfo) { + + // Clang wants to do completion on a real file known by Clang's file manager, + // so we have to create one to make this work. + // TODO: We probably could also simulate to Clang's file manager that there + // is a real file that contains our code. + bool should_create_file = completion_consumer != nullptr; + + // We also want a real file on disk if we generate full debug info. + should_create_file |= m_compiler->getCodeGenOpts().getDebugInfo() == + codegenoptions::FullDebugInfo; + + if (should_create_file) { int temp_fd = -1; - llvm::SmallString<PATH_MAX> result_path; + llvm::SmallString<128> result_path; if (FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir()) { tmpdir_file_spec.AppendPathComponent("lldb-%%%%%%.expr"); std::string temp_source_path = tmpdir_file_spec.GetPath(); @@ -603,14 +875,30 @@ unsigned ClangExpressionParser::Parse(DiagnosticManager &diagnostic_manager) { if (ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap()) decl_map->InstallCodeGenerator(m_code_generator.get()); + // If we want to parse for code completion, we need to attach our code + // completion consumer to the Sema and specify a completion position. + // While parsing the Sema will call this consumer with the provided + // completion suggestions. + if (completion_consumer) { + auto main_file = source_mgr.getFileEntryForID(source_mgr.getMainFileID()); + auto &PP = m_compiler->getPreprocessor(); + // Lines and columns start at 1 in Clang, but code completion positions are + // indexed from 0, so we need to add 1 to the line and column here. + ++completion_line; + ++completion_column; + PP.SetCodeCompletionPoint(main_file, completion_line, completion_column); + } + if (ast_transformer) { ast_transformer->Initialize(m_compiler->getASTContext()); ParseAST(m_compiler->getPreprocessor(), ast_transformer, - m_compiler->getASTContext()); + m_compiler->getASTContext(), false, TU_Complete, + completion_consumer); } else { m_code_generator->Initialize(m_compiler->getASTContext()); ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), - m_compiler->getASTContext()); + m_compiler->getASTContext(), false, TU_Complete, + completion_consumer); } diag_buf->EndSourceFile(); @@ -891,9 +1179,9 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( if (!dynamic_checkers->Install(install_diagnostics, exe_ctx)) { if (install_diagnostics.Diagnostics().size()) - err.SetErrorString("couldn't install checkers, unknown error"); - else err.SetErrorString(install_diagnostics.GetString().c_str()); + else + err.SetErrorString("couldn't install checkers, unknown error"); return err; } diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h index 4058ec1270b3..03ff55f614d5 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h @@ -20,6 +20,10 @@ #include <string> #include <vector> +namespace clang { +class CodeCompleteConsumer; +} + namespace lldb_private { class IRExecutionUnit; @@ -58,6 +62,9 @@ public: //------------------------------------------------------------------ ~ClangExpressionParser() override; + bool Complete(CompletionRequest &request, unsigned line, unsigned pos, + unsigned typed_pos) override; + //------------------------------------------------------------------ /// Parse a single expression and convert it to IR using Clang. Don't wrap /// the expression in anything at all. @@ -143,16 +150,39 @@ public: std::string GetClangTargetABI(const ArchSpec &target_arch); private: + //------------------------------------------------------------------ + /// Parses the expression. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager that should receive the diagnostics + /// from the parsing process. + /// + /// @param[in] completion + /// The completion consumer that should be used during parsing + /// (or a nullptr if no consumer should be attached). + /// + /// @param[in] completion_line + /// The line in which the completion marker should be placed. + /// The first line is represented by the value 0. + /// + /// @param[in] completion_column + /// The column in which the completion marker should be placed. + /// The first column is represented by the value 0. + /// + /// @return + /// The number of parsing errors. + //------------------------------------------------------------------- + unsigned ParseInternal(DiagnosticManager &diagnostic_manager, + clang::CodeCompleteConsumer *completion = nullptr, + unsigned completion_line = 0, + unsigned completion_column = 0); + std::unique_ptr<llvm::LLVMContext> m_llvm_context; ///< The LLVM context to generate IR into std::unique_ptr<clang::FileManager> m_file_manager; ///< The Clang file manager object used by the compiler std::unique_ptr<clang::CompilerInstance> m_compiler; ///< The Clang compiler used to parse expressions into IR - std::unique_ptr<clang::Builtin::Context> - m_builtin_context; ///< Context for Clang built-ins - std::unique_ptr<clang::SelectorTable> - m_selector_table; ///< Selector table for Objective-C methods std::unique_ptr<clang::CodeGenerator> m_code_generator; ///< The Clang object that generates IR diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h index 7d5ced5b4705..6886f0940adb 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h @@ -10,20 +10,16 @@ #ifndef liblldb_ClangExpressionVariable_h_ #define liblldb_ClangExpressionVariable_h_ -// C Includes #include <signal.h> #include <stdint.h> #include <string.h> -// C++ Includes #include <map> #include <string> #include <vector> -// Other libraries and framework includes #include "llvm/Support/Casting.h" -// Project includes #include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Expression/ExpressionVariable.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index e3e0ed49181e..8ec9ff2235f5 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -12,9 +12,6 @@ #include "ASTStructExtractor.h" #include "ClangExpressionParser.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" #include "clang/CodeGen/CodeGenAction.h" @@ -25,9 +22,7 @@ #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/IR/Module.h" -// Project includes #include "lldb/Core/Module.h" -#include "lldb/Core/State.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/IRExecutionUnit.h" @@ -44,6 +39,7 @@ #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" using namespace lldb_private; diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h index 438cf0c713da..9d933bfa6095 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h +++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h @@ -10,10 +10,6 @@ #ifndef liblldb_ClangFunctionCaller_h_ #define liblldb_ClangFunctionCaller_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "ClangExpressionHelper.h" #include "lldb/Core/Address.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 4251d2ee75b9..44a13353818a 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -17,7 +17,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Threading.h" -// Project includes +#include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #if !defined(_WIN32) #include "lldb/Host/posix/HostInfoPosix.h" @@ -42,7 +42,7 @@ static bool DefaultComputeClangDirectory(FileSpec &file_spec) { #if defined(__APPLE__) static bool VerifyClangPath(const llvm::Twine &clang_path) { - if (llvm::sys::fs::is_directory(clang_path)) + if (FileSystem::Instance().IsDirectory(clang_path)) return true; Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) @@ -84,7 +84,8 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, "Developer/Toolchains/XcodeDefault.xctoolchain", swift_clang_resource_dir); if (!verify || VerifyClangPath(clang_path)) { - file_spec.SetFile(clang_path.c_str(), true, FileSpec::Style::native); + file_spec.SetFile(clang_path.c_str(), FileSpec::Style::native); + FileSystem::Instance().Resolve(file_spec); return true; } } else if (parent != r_end && *parent == "PrivateFrameworks" && @@ -98,7 +99,8 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, raw_path.resize(parent - r_end); llvm::sys::path::append(clang_path, raw_path, swift_clang_resource_dir); if (!verify || VerifyClangPath(clang_path)) { - file_spec.SetFile(clang_path.c_str(), true, FileSpec::Style::native); + file_spec.SetFile(clang_path.c_str(), FileSpec::Style::native); + FileSystem::Instance().Resolve(file_spec); return true; } raw_path = lldb_shlib_spec.GetPath(); @@ -110,7 +112,8 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, // Fall back to the Clang resource directory inside the framework. raw_path.append("LLDB.framework/Resources/Clang"); - file_spec.SetFile(raw_path.c_str(), true, FileSpec::Style::native); + file_spec.SetFile(raw_path.c_str(), FileSpec::Style::native); + FileSystem::Instance().Resolve(file_spec); return true; } diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 665195f01774..ced21dfe0dda 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -7,11 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes #include <mutex> -// Other libraries and framework includes #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" @@ -24,7 +21,6 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Threading.h" -// Project includes #include "ClangHost.h" #include "ClangModulesDeclVendor.h" @@ -601,7 +597,7 @@ ClangModulesDeclVendor::Create(Target &target) { { FileSpec clang_resource_dir = GetClangResourceDir(); - if (llvm::sys::fs::is_directory(clang_resource_dir.GetPath())) { + if (FileSystem::Instance().IsDirectory(clang_resource_dir.GetPath())) { compiler_invocation_arguments.push_back("-resource-dir"); compiler_invocation_arguments.push_back(clang_resource_dir.GetPath()); } @@ -612,7 +608,8 @@ ClangModulesDeclVendor::Create(Target &target) { new StoringDiagnosticConsumer); std::vector<const char *> compiler_invocation_argument_cstrs; - + compiler_invocation_argument_cstrs.reserve( + compiler_invocation_arguments.size()); for (const std::string &arg : compiler_invocation_arguments) { compiler_invocation_argument_cstrs.push_back(arg.c_str()); } diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index 59126974616d..c4438c7e2203 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -10,12 +10,8 @@ #ifndef liblldb_ClangPersistentVariables_h_ #define liblldb_ClangPersistentVariables_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/DenseMap.h" -// Project includes #include "ClangExpressionVariable.h" #include "ClangModulesDeclVendor.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 2e61f704127a..f42955df07aa 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -376,9 +376,9 @@ static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) { } } -llvm::Optional<lldb::LanguageType> ClangUserExpression::GetLanguageForExpr( +void ClangUserExpression::UpdateLanguageForExpr( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { - lldb::LanguageType lang_type = lldb::LanguageType::eLanguageTypeUnknown; + m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown; std::string prefix = m_expr_prefix; @@ -390,20 +390,29 @@ llvm::Optional<lldb::LanguageType> ClangUserExpression::GetLanguageForExpr( m_expr_text.c_str())); if (m_in_cplusplus_method) - lang_type = lldb::eLanguageTypeC_plus_plus; + m_expr_lang = lldb::eLanguageTypeC_plus_plus; else if (m_in_objectivec_method) - lang_type = lldb::eLanguageTypeObjC; + m_expr_lang = lldb::eLanguageTypeObjC; else - lang_type = lldb::eLanguageTypeC; + m_expr_lang = lldb::eLanguageTypeC; - if (!source_code->GetText(m_transformed_text, lang_type, m_in_static_method, - exe_ctx)) { + if (!source_code->GetText(m_transformed_text, m_expr_lang, + m_in_static_method, exe_ctx)) { diagnostic_manager.PutString(eDiagnosticSeverityError, "couldn't construct expression body"); - return llvm::Optional<lldb::LanguageType>(); + return; + } + + // Find and store the start position of the original code inside the + // transformed code. We need this later for the code completion. + std::size_t original_start; + std::size_t original_end; + bool found_bounds = source_code->GetOriginalBodyBounds( + m_transformed_text, m_expr_lang, original_start, original_end); + if (found_bounds) { + m_user_expression_start_pos = original_start; } } - return lang_type; } bool ClangUserExpression::PrepareForParsing( @@ -427,6 +436,8 @@ bool ClangUserExpression::PrepareForParsing( ApplyObjcCastHack(m_expr_text); SetupDeclVendor(exe_ctx, m_target); + + UpdateLanguageForExpr(diagnostic_manager, exe_ctx); return true; } @@ -440,11 +451,6 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, if (!PrepareForParsing(diagnostic_manager, exe_ctx)) return false; - lldb::LanguageType lang_type = lldb::LanguageType::eLanguageTypeUnknown; - if (auto new_lang = GetLanguageForExpr(diagnostic_manager, exe_ctx)) { - lang_type = new_lang.getValue(); - } - if (log) log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str()); @@ -504,7 +510,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, const std::string &fixed_expression = diagnostic_manager.GetFixedExpression(); if (ExpressionSourceCode::GetOriginalBodyBounds( - fixed_expression, lang_type, fixed_start, fixed_end)) + fixed_expression, m_expr_lang, fixed_start, fixed_end)) m_fixed_text = fixed_expression.substr(fixed_start, fixed_end - fixed_start); } @@ -591,6 +597,116 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, return true; } +//------------------------------------------------------------------ +/// Converts an absolute position inside a given code string into +/// a column/line pair. +/// +/// @param[in] abs_pos +/// A absolute position in the code string that we want to convert +/// to a column/line pair. +/// +/// @param[in] code +/// A multi-line string usually representing source code. +/// +/// @param[out] line +/// The line in the code that contains the given absolute position. +/// The first line in the string is indexed as 1. +/// +/// @param[out] column +/// The column in the line that contains the absolute position. +/// The first character in a line is indexed as 0. +//------------------------------------------------------------------ +static void AbsPosToLineColumnPos(size_t abs_pos, llvm::StringRef code, + unsigned &line, unsigned &column) { + // Reset to code position to beginning of the file. + line = 0; + column = 0; + + assert(abs_pos <= code.size() && "Absolute position outside code string?"); + + // We have to walk up to the position and count lines/columns. + for (std::size_t i = 0; i < abs_pos; ++i) { + // If we hit a line break, we go back to column 0 and enter a new line. + // We only handle \n because that's what we internally use to make new + // lines for our temporary code strings. + if (code[i] == '\n') { + ++line; + column = 0; + continue; + } + ++column; + } +} + +bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, + CompletionRequest &request, + unsigned complete_pos) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + // We don't want any visible feedback when completing an expression. Mostly + // because the results we get from an incomplete invocation are probably not + // correct. + DiagnosticManager diagnostic_manager; + + if (!PrepareForParsing(diagnostic_manager, exe_ctx)) + return false; + + if (log) + log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str()); + + ////////////////////////// + // Parse the expression + // + + m_materializer_ap.reset(new Materializer()); + + ResetDeclMap(exe_ctx, m_result_delegate, /*keep result in memory*/ true); + + OnExit on_exit([this]() { ResetDeclMap(); }); + + if (!DeclMap()->WillParse(exe_ctx, m_materializer_ap.get())) { + diagnostic_manager.PutString( + eDiagnosticSeverityError, + "current process state is unsuitable for expression parsing"); + + return false; + } + + if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) { + DeclMap()->SetLookupsEnabled(true); + } + + Process *process = exe_ctx.GetProcessPtr(); + ExecutionContextScope *exe_scope = process; + + if (!exe_scope) + exe_scope = exe_ctx.GetTargetPtr(); + + ClangExpressionParser parser(exe_scope, *this, false); + + // We have to find the source code location where the user text is inside + // the transformed expression code. When creating the transformed text, we + // already stored the absolute position in the m_transformed_text string. The + // only thing left to do is to transform it into the line:column format that + // Clang expects. + + // The line and column of the user expression inside the transformed source + // code. + unsigned user_expr_line, user_expr_column; + if (m_user_expression_start_pos.hasValue()) + AbsPosToLineColumnPos(*m_user_expression_start_pos, m_transformed_text, + user_expr_line, user_expr_column); + else + return false; + + // The actual column where we have to complete is the start column of the + // user expression + the offset inside the user code that we were given. + const unsigned completion_column = user_expr_column + complete_pos; + parser.Complete(request, user_expr_line, completion_column, complete_pos); + + return true; +} + bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx, std::vector<lldb::addr_t> &args, lldb::addr_t struct_address, diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index ac363bf91747..7e4cba661850 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -10,12 +10,8 @@ #ifndef liblldb_ClangUserExpression_h_ #define liblldb_ClangUserExpression_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "ASTResultSynthesizer.h" #include "ASTStructExtractor.h" #include "ClangExpressionDeclMap.h" @@ -143,6 +139,9 @@ public: lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, bool generate_debug_info) override; + bool Complete(ExecutionContext &exe_ctx, CompletionRequest &request, + unsigned complete_pos) override; + ExpressionTypeSystemHelper *GetTypeSystemHelper() override { return &m_type_system_helper; } @@ -174,8 +173,8 @@ private: lldb::addr_t struct_address, DiagnosticManager &diagnostic_manager) override; - llvm::Optional<lldb::LanguageType> GetLanguageForExpr( - DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx); + void UpdateLanguageForExpr(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx); bool SetupPersistentState(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx); bool PrepareForParsing(DiagnosticManager &diagnostic_manager, @@ -198,6 +197,13 @@ private: lldb::TargetSP m_target_sp; }; + /// The language type of the current expression. + lldb::LanguageType m_expr_lang = lldb::eLanguageTypeUnknown; + + /// The absolute character position in the transformed source code where the + /// user code (as typed by the user) starts. If the variable is empty, then we + /// were not able to calculate this position. + llvm::Optional<size_t> m_user_expression_start_pos; ResultDelegate m_result_delegate; }; diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index 0f2aeef27e57..fe6ca450a79d 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -11,13 +11,11 @@ #include "ClangExpressionDeclMap.h" #include "ClangExpressionParser.h" -// C Includes #include <stdio.h> #if HAVE_SYS_TYPES_H #include <sys/types.h> #endif -// C++ Includes #include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index a897a2b17087..b0650f0eda02 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -10,14 +10,10 @@ #ifndef liblldb_ClangUtilityFunction_h_ #define liblldb_ClangUtilityFunction_h_ -// C Includes -// C++ Includes #include <map> #include <string> #include <vector> -// Other libraries and framework includes -// Project includes #include "ClangExpressionHelper.h" #include "lldb/Core/ClangForward.h" diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index e51c9ee07b9f..3a7cd58b70ab 100644 --- a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -25,7 +25,6 @@ #include "clang/AST/ASTContext.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/dwarf.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" @@ -36,6 +35,7 @@ #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/StreamString.h" #include <map> @@ -310,12 +310,14 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { lldb::TargetSP target_sp(m_execution_unit.GetTarget()); lldb_private::ExecutionContext exe_ctx(target_sp, true); - if (m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()) == 0) { + llvm::Optional<uint64_t> bit_size = + m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()); + if (!bit_size) { lldb_private::StreamString type_desc_stream; m_result_type.DumpTypeDescription(&type_desc_stream); if (log) - log->Printf("Result type has size 0"); + log->Printf("Result type has unknown size"); m_error_stream.Printf("Error [IRForTarget]: Size of result type '%s' " "couldn't be determined\n", @@ -334,7 +336,8 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { if (log) log->Printf("Creating a new result global: \"%s\" with size 0x%" PRIx64, - m_result_name.GetCString(), m_result_type.GetByteSize(nullptr)); + m_result_name.GetCString(), + m_result_type.GetByteSize(nullptr).getValueOr(0)); // Construct a new result global and set up its metadata @@ -778,11 +781,8 @@ bool IRForTarget::RewriteObjCConstStrings() { static bool IsObjCSelectorRef(Value *value) { GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value); - if (!global_variable || !global_variable->hasName() || - !global_variable->getName().startswith("OBJC_SELECTOR_REFERENCES_")) - return false; - - return true; + return !(!global_variable || !global_variable->hasName() || + !global_variable->getName().startswith("OBJC_SELECTOR_REFERENCES_")); } // This function does not report errors; its callers are responsible. @@ -953,11 +953,8 @@ bool IRForTarget::RewriteObjCSelectors(BasicBlock &basic_block) { static bool IsObjCClassReference(Value *value) { GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value); - if (!global_variable || !global_variable->hasName() || - !global_variable->getName().startswith("OBJC_CLASS_REFERENCES_")) - return false; - - return true; + return !(!global_variable || !global_variable->hasName() || + !global_variable->getName().startswith("OBJC_CLASS_REFERENCES_")); } // This function does not report errors; its callers are responsible. @@ -1259,12 +1256,9 @@ bool IRForTarget::MaterializeInitializer(uint8_t *data, Constant *initializer) { llvm::NextPowerOf2(constant_size) * 8); lldb_private::Status get_data_error; - if (!scalar.GetAsMemoryData(data, constant_size, - lldb_private::endian::InlHostByteOrder(), - get_data_error)) - return false; - - return true; + return scalar.GetAsMemoryData(data, constant_size, + lldb_private::endian::InlHostByteOrder(), + get_data_error) != 0; } else if (ConstantDataArray *array_initializer = dyn_cast<ConstantDataArray>(initializer)) { if (array_initializer->isString()) { @@ -1376,7 +1370,9 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { value_type = global_variable->getType(); } - const uint64_t value_size = compiler_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> value_size = compiler_type.GetByteSize(nullptr); + if (!value_size) + return false; lldb::offset_t value_alignment = (compiler_type.GetTypeBitAlign() + 7ull) / 8ull; @@ -1387,13 +1383,13 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { lldb_private::ClangUtil::GetQualType(compiler_type) .getAsString() .c_str(), - PrintType(value_type).c_str(), value_size, value_alignment); + PrintType(value_type).c_str(), *value_size, value_alignment); } if (named_decl && !m_decl_map->AddValueToStruct( named_decl, lldb_private::ConstString(name.c_str()), llvm_value_ptr, - value_size, value_alignment)) { + *value_size, value_alignment)) { if (!global_variable->hasExternalLinkage()) return true; else diff --git a/source/Plugins/ExpressionParser/Go/CMakeLists.txt b/source/Plugins/ExpressionParser/Go/CMakeLists.txt deleted file mode 100644 index 3d552aafa0d7..000000000000 --- a/source/Plugins/ExpressionParser/Go/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_lldb_library(lldbPluginExpressionParserGo PLUGIN - GoLexer.cpp - GoParser.cpp - GoUserExpression.cpp - - LINK_LIBS - lldbCore - lldbExpression - lldbSymbol - lldbTarget - LINK_COMPONENTS - Support - ) diff --git a/source/Plugins/ExpressionParser/Go/GoAST.h b/source/Plugins/ExpressionParser/Go/GoAST.h deleted file mode 100644 index d24e6c548718..000000000000 --- a/source/Plugins/ExpressionParser/Go/GoAST.h +++ /dev/null @@ -1,1977 +0,0 @@ -//===-- GoAST.h -------------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// DO NOT EDIT. -// Generated by gen_go_ast.py - -#ifndef liblldb_GoAST_h -#define liblldb_GoAST_h - -#include "Plugins/ExpressionParser/Go/GoLexer.h" -#include "lldb/lldb-forward.h" -#include "lldb/lldb-private.h" -#include "llvm/Support/Casting.h" - -namespace lldb_private { - -class GoASTNode { -public: - typedef GoLexer::TokenType TokenType; - typedef GoLexer::Token Token; - enum ChanDir { - eChanBidir, - eChanSend, - eChanRecv, - }; - enum NodeKind { - eBadDecl, - eFuncDecl, - eGenDecl, - eArrayType, - eBadExpr, - eBasicLit, - eBinaryExpr, - eIdent, - eCallExpr, - eChanType, - eCompositeLit, - eEllipsis, - eFuncType, - eFuncLit, - eIndexExpr, - eInterfaceType, - eKeyValueExpr, - eMapType, - eParenExpr, - eSelectorExpr, - eSliceExpr, - eStarExpr, - eStructType, - eTypeAssertExpr, - eUnaryExpr, - eImportSpec, - eTypeSpec, - eValueSpec, - eAssignStmt, - eBadStmt, - eBlockStmt, - eBranchStmt, - eCaseClause, - eCommClause, - eDeclStmt, - eDeferStmt, - eEmptyStmt, - eExprStmt, - eForStmt, - eGoStmt, - eIfStmt, - eIncDecStmt, - eLabeledStmt, - eRangeStmt, - eReturnStmt, - eSelectStmt, - eSendStmt, - eSwitchStmt, - eTypeSwitchStmt, - eField, - eFieldList, - }; - - virtual ~GoASTNode() = default; - - NodeKind GetKind() const { return m_kind; } - - virtual const char *GetKindName() const = 0; - - template <typename V> void WalkChildren(V &v); - -protected: - explicit GoASTNode(NodeKind kind) : m_kind(kind) {} - -private: - const NodeKind m_kind; - - GoASTNode(const GoASTNode &) = delete; - const GoASTNode &operator=(const GoASTNode &) = delete; -}; - -class GoASTDecl : public GoASTNode { -public: - template <typename R, typename V> R Visit(V *v) const; - - static bool classof(const GoASTNode *n) { - return n->GetKind() >= eBadDecl && n->GetKind() <= eGenDecl; - } - -protected: - explicit GoASTDecl(NodeKind kind) : GoASTNode(kind) {} - -private: - GoASTDecl(const GoASTDecl &) = delete; - const GoASTDecl &operator=(const GoASTDecl &) = delete; -}; - -class GoASTExpr : public GoASTNode { -public: - template <typename R, typename V> R Visit(V *v) const; - - static bool classof(const GoASTNode *n) { - return n->GetKind() >= eArrayType && n->GetKind() <= eUnaryExpr; - } - -protected: - explicit GoASTExpr(NodeKind kind) : GoASTNode(kind) {} - -private: - GoASTExpr(const GoASTExpr &) = delete; - const GoASTExpr &operator=(const GoASTExpr &) = delete; -}; - -class GoASTSpec : public GoASTNode { -public: - template <typename R, typename V> R Visit(V *v) const; - - static bool classof(const GoASTNode *n) { - return n->GetKind() >= eImportSpec && n->GetKind() <= eValueSpec; - } - -protected: - explicit GoASTSpec(NodeKind kind) : GoASTNode(kind) {} - -private: - GoASTSpec(const GoASTSpec &) = delete; - const GoASTSpec &operator=(const GoASTSpec &) = delete; -}; - -class GoASTStmt : public GoASTNode { -public: - template <typename R, typename V> R Visit(V *v) const; - - static bool classof(const GoASTNode *n) { - return n->GetKind() >= eAssignStmt && n->GetKind() <= eTypeSwitchStmt; - } - -protected: - explicit GoASTStmt(NodeKind kind) : GoASTNode(kind) {} - -private: - GoASTStmt(const GoASTStmt &) = delete; - const GoASTStmt &operator=(const GoASTStmt &) = delete; -}; - -class GoASTArrayType : public GoASTExpr { -public: - GoASTArrayType(GoASTExpr *len, GoASTExpr *elt) - : GoASTExpr(eArrayType), m_len_up(len), m_elt_up(elt) {} - ~GoASTArrayType() override = default; - - const char *GetKindName() const override { return "ArrayType"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eArrayType; } - - const GoASTExpr *GetLen() const { return m_len_up.get(); } - void SetLen(GoASTExpr *len) { m_len_up.reset(len); } - - const GoASTExpr *GetElt() const { return m_elt_up.get(); } - void SetElt(GoASTExpr *elt) { m_elt_up.reset(elt); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_len_up; - std::unique_ptr<GoASTExpr> m_elt_up; - - GoASTArrayType(const GoASTArrayType &) = delete; - const GoASTArrayType &operator=(const GoASTArrayType &) = delete; -}; - -class GoASTAssignStmt : public GoASTStmt { -public: - explicit GoASTAssignStmt(bool define) - : GoASTStmt(eAssignStmt), m_define(define) {} - ~GoASTAssignStmt() override = default; - - const char *GetKindName() const override { return "AssignStmt"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eAssignStmt; - } - - size_t NumLhs() const { return m_lhs.size(); } - const GoASTExpr *GetLhs(int i) const { return m_lhs[i].get(); } - void AddLhs(GoASTExpr *lhs) { - m_lhs.push_back(std::unique_ptr<GoASTExpr>(lhs)); - } - - size_t NumRhs() const { return m_rhs.size(); } - const GoASTExpr *GetRhs(int i) const { return m_rhs[i].get(); } - void AddRhs(GoASTExpr *rhs) { - m_rhs.push_back(std::unique_ptr<GoASTExpr>(rhs)); - } - - bool GetDefine() const { return m_define; } - void SetDefine(bool define) { m_define = define; } - -private: - friend class GoASTNode; - std::vector<std::unique_ptr<GoASTExpr>> m_lhs; - std::vector<std::unique_ptr<GoASTExpr>> m_rhs; - bool m_define; - - GoASTAssignStmt(const GoASTAssignStmt &) = delete; - const GoASTAssignStmt &operator=(const GoASTAssignStmt &) = delete; -}; - -class GoASTBadDecl : public GoASTDecl { -public: - GoASTBadDecl() : GoASTDecl(eBadDecl) {} - ~GoASTBadDecl() override = default; - - const char *GetKindName() const override { return "BadDecl"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eBadDecl; } - - GoASTBadDecl(const GoASTBadDecl &) = delete; - const GoASTBadDecl &operator=(const GoASTBadDecl &) = delete; -}; - -class GoASTBadExpr : public GoASTExpr { -public: - GoASTBadExpr() : GoASTExpr(eBadExpr) {} - ~GoASTBadExpr() override = default; - - const char *GetKindName() const override { return "BadExpr"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eBadExpr; } - - GoASTBadExpr(const GoASTBadExpr &) = delete; - const GoASTBadExpr &operator=(const GoASTBadExpr &) = delete; -}; - -class GoASTBadStmt : public GoASTStmt { -public: - GoASTBadStmt() : GoASTStmt(eBadStmt) {} - ~GoASTBadStmt() override = default; - - const char *GetKindName() const override { return "BadStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eBadStmt; } - - GoASTBadStmt(const GoASTBadStmt &) = delete; - const GoASTBadStmt &operator=(const GoASTBadStmt &) = delete; -}; - -class GoASTBasicLit : public GoASTExpr { -public: - explicit GoASTBasicLit(Token value) : GoASTExpr(eBasicLit), m_value(value) {} - ~GoASTBasicLit() override = default; - - const char *GetKindName() const override { return "BasicLit"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eBasicLit; } - - Token GetValue() const { return m_value; } - void SetValue(Token value) { m_value = value; } - -private: - friend class GoASTNode; - Token m_value; - - GoASTBasicLit(const GoASTBasicLit &) = delete; - const GoASTBasicLit &operator=(const GoASTBasicLit &) = delete; -}; - -class GoASTBinaryExpr : public GoASTExpr { -public: - GoASTBinaryExpr(GoASTExpr *x, GoASTExpr *y, TokenType op) - : GoASTExpr(eBinaryExpr), m_x_up(x), m_y_up(y), m_op(op) {} - ~GoASTBinaryExpr() override = default; - - const char *GetKindName() const override { return "BinaryExpr"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eBinaryExpr; - } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - - const GoASTExpr *GetY() const { return m_y_up.get(); } - void SetY(GoASTExpr *y) { m_y_up.reset(y); } - - TokenType GetOp() const { return m_op; } - void SetOp(TokenType op) { m_op = op; } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_x_up; - std::unique_ptr<GoASTExpr> m_y_up; - TokenType m_op; - - GoASTBinaryExpr(const GoASTBinaryExpr &) = delete; - const GoASTBinaryExpr &operator=(const GoASTBinaryExpr &) = delete; -}; - -class GoASTBlockStmt : public GoASTStmt { -public: - GoASTBlockStmt() : GoASTStmt(eBlockStmt) {} - ~GoASTBlockStmt() override = default; - - const char *GetKindName() const override { return "BlockStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eBlockStmt; } - - size_t NumList() const { return m_list.size(); } - const GoASTStmt *GetList(int i) const { return m_list[i].get(); } - void AddList(GoASTStmt *list) { - m_list.push_back(std::unique_ptr<GoASTStmt>(list)); - } - -private: - friend class GoASTNode; - std::vector<std::unique_ptr<GoASTStmt>> m_list; - - GoASTBlockStmt(const GoASTBlockStmt &) = delete; - const GoASTBlockStmt &operator=(const GoASTBlockStmt &) = delete; -}; - -class GoASTIdent : public GoASTExpr { -public: - explicit GoASTIdent(Token name) : GoASTExpr(eIdent), m_name(name) {} - ~GoASTIdent() override = default; - - const char *GetKindName() const override { return "Ident"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eIdent; } - - Token GetName() const { return m_name; } - void SetName(Token name) { m_name = name; } - -private: - friend class GoASTNode; - Token m_name; - - GoASTIdent(const GoASTIdent &) = delete; - const GoASTIdent &operator=(const GoASTIdent &) = delete; -}; - -class GoASTBranchStmt : public GoASTStmt { -public: - GoASTBranchStmt(GoASTIdent *label, TokenType tok) - : GoASTStmt(eBranchStmt), m_label_up(label), m_tok(tok) {} - ~GoASTBranchStmt() override = default; - - const char *GetKindName() const override { return "BranchStmt"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eBranchStmt; - } - - const GoASTIdent *GetLabel() const { return m_label_up.get(); } - void SetLabel(GoASTIdent *label) { m_label_up.reset(label); } - - TokenType GetTok() const { return m_tok; } - void SetTok(TokenType tok) { m_tok = tok; } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTIdent> m_label_up; - TokenType m_tok; - - GoASTBranchStmt(const GoASTBranchStmt &) = delete; - const GoASTBranchStmt &operator=(const GoASTBranchStmt &) = delete; -}; - -class GoASTCallExpr : public GoASTExpr { -public: - explicit GoASTCallExpr(bool ellipsis) - : GoASTExpr(eCallExpr), m_ellipsis(ellipsis) {} - ~GoASTCallExpr() override = default; - - const char *GetKindName() const override { return "CallExpr"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eCallExpr; } - - const GoASTExpr *GetFun() const { return m_fun_up.get(); } - void SetFun(GoASTExpr *fun) { m_fun_up.reset(fun); } - - size_t NumArgs() const { return m_args.size(); } - const GoASTExpr *GetArgs(int i) const { return m_args[i].get(); } - void AddArgs(GoASTExpr *args) { - m_args.push_back(std::unique_ptr<GoASTExpr>(args)); - } - - bool GetEllipsis() const { return m_ellipsis; } - void SetEllipsis(bool ellipsis) { m_ellipsis = ellipsis; } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_fun_up; - std::vector<std::unique_ptr<GoASTExpr>> m_args; - bool m_ellipsis; - - GoASTCallExpr(const GoASTCallExpr &) = delete; - const GoASTCallExpr &operator=(const GoASTCallExpr &) = delete; -}; - -class GoASTCaseClause : public GoASTStmt { -public: - GoASTCaseClause() : GoASTStmt(eCaseClause) {} - ~GoASTCaseClause() override = default; - - const char *GetKindName() const override { return "CaseClause"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eCaseClause; - } - - size_t NumList() const { return m_list.size(); } - const GoASTExpr *GetList(int i) const { return m_list[i].get(); } - void AddList(GoASTExpr *list) { - m_list.push_back(std::unique_ptr<GoASTExpr>(list)); - } - - size_t NumBody() const { return m_body.size(); } - const GoASTStmt *GetBody(int i) const { return m_body[i].get(); } - void AddBody(GoASTStmt *body) { - m_body.push_back(std::unique_ptr<GoASTStmt>(body)); - } - -private: - friend class GoASTNode; - std::vector<std::unique_ptr<GoASTExpr>> m_list; - std::vector<std::unique_ptr<GoASTStmt>> m_body; - - GoASTCaseClause(const GoASTCaseClause &) = delete; - const GoASTCaseClause &operator=(const GoASTCaseClause &) = delete; -}; - -class GoASTChanType : public GoASTExpr { -public: - GoASTChanType(ChanDir dir, GoASTExpr *value) - : GoASTExpr(eChanType), m_dir(dir), m_value_up(value) {} - ~GoASTChanType() override = default; - - const char *GetKindName() const override { return "ChanType"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eChanType; } - - ChanDir GetDir() const { return m_dir; } - void SetDir(ChanDir dir) { m_dir = dir; } - - const GoASTExpr *GetValue() const { return m_value_up.get(); } - void SetValue(GoASTExpr *value) { m_value_up.reset(value); } - -private: - friend class GoASTNode; - ChanDir m_dir; - std::unique_ptr<GoASTExpr> m_value_up; - - GoASTChanType(const GoASTChanType &) = delete; - const GoASTChanType &operator=(const GoASTChanType &) = delete; -}; - -class GoASTCommClause : public GoASTStmt { -public: - GoASTCommClause() : GoASTStmt(eCommClause) {} - ~GoASTCommClause() override = default; - - const char *GetKindName() const override { return "CommClause"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eCommClause; - } - - const GoASTStmt *GetComm() const { return m_comm_up.get(); } - void SetComm(GoASTStmt *comm) { m_comm_up.reset(comm); } - - size_t NumBody() const { return m_body.size(); } - const GoASTStmt *GetBody(int i) const { return m_body[i].get(); } - void AddBody(GoASTStmt *body) { - m_body.push_back(std::unique_ptr<GoASTStmt>(body)); - } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTStmt> m_comm_up; - std::vector<std::unique_ptr<GoASTStmt>> m_body; - - GoASTCommClause(const GoASTCommClause &) = delete; - const GoASTCommClause &operator=(const GoASTCommClause &) = delete; -}; - -class GoASTCompositeLit : public GoASTExpr { -public: - GoASTCompositeLit() : GoASTExpr(eCompositeLit) {} - ~GoASTCompositeLit() override = default; - - const char *GetKindName() const override { return "CompositeLit"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eCompositeLit; - } - - const GoASTExpr *GetType() const { return m_type_up.get(); } - void SetType(GoASTExpr *type) { m_type_up.reset(type); } - - size_t NumElts() const { return m_elts.size(); } - const GoASTExpr *GetElts(int i) const { return m_elts[i].get(); } - void AddElts(GoASTExpr *elts) { - m_elts.push_back(std::unique_ptr<GoASTExpr>(elts)); - } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_type_up; - std::vector<std::unique_ptr<GoASTExpr>> m_elts; - - GoASTCompositeLit(const GoASTCompositeLit &) = delete; - const GoASTCompositeLit &operator=(const GoASTCompositeLit &) = delete; -}; - -class GoASTDeclStmt : public GoASTStmt { -public: - explicit GoASTDeclStmt(GoASTDecl *decl) - : GoASTStmt(eDeclStmt), m_decl_up(decl) {} - ~GoASTDeclStmt() override = default; - - const char *GetKindName() const override { return "DeclStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eDeclStmt; } - - const GoASTDecl *GetDecl() const { return m_decl_up.get(); } - void SetDecl(GoASTDecl *decl) { m_decl_up.reset(decl); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTDecl> m_decl_up; - - GoASTDeclStmt(const GoASTDeclStmt &) = delete; - const GoASTDeclStmt &operator=(const GoASTDeclStmt &) = delete; -}; - -class GoASTDeferStmt : public GoASTStmt { -public: - explicit GoASTDeferStmt(GoASTCallExpr *call) - : GoASTStmt(eDeferStmt), m_call_up(call) {} - ~GoASTDeferStmt() override = default; - - const char *GetKindName() const override { return "DeferStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eDeferStmt; } - - const GoASTCallExpr *GetCall() const { return m_call_up.get(); } - void SetCall(GoASTCallExpr *call) { m_call_up.reset(call); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTCallExpr> m_call_up; - - GoASTDeferStmt(const GoASTDeferStmt &) = delete; - const GoASTDeferStmt &operator=(const GoASTDeferStmt &) = delete; -}; - -class GoASTEllipsis : public GoASTExpr { -public: - explicit GoASTEllipsis(GoASTExpr *elt) - : GoASTExpr(eEllipsis), m_elt_up(elt) {} - ~GoASTEllipsis() override = default; - - const char *GetKindName() const override { return "Ellipsis"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eEllipsis; } - - const GoASTExpr *GetElt() const { return m_elt_up.get(); } - void SetElt(GoASTExpr *elt) { m_elt_up.reset(elt); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_elt_up; - - GoASTEllipsis(const GoASTEllipsis &) = delete; - const GoASTEllipsis &operator=(const GoASTEllipsis &) = delete; -}; - -class GoASTEmptyStmt : public GoASTStmt { -public: - GoASTEmptyStmt() : GoASTStmt(eEmptyStmt) {} - ~GoASTEmptyStmt() override = default; - - const char *GetKindName() const override { return "EmptyStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eEmptyStmt; } - - GoASTEmptyStmt(const GoASTEmptyStmt &) = delete; - const GoASTEmptyStmt &operator=(const GoASTEmptyStmt &) = delete; -}; - -class GoASTExprStmt : public GoASTStmt { -public: - explicit GoASTExprStmt(GoASTExpr *x) : GoASTStmt(eExprStmt), m_x_up(x) {} - ~GoASTExprStmt() override = default; - - const char *GetKindName() const override { return "ExprStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eExprStmt; } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_x_up; - - GoASTExprStmt(const GoASTExprStmt &) = delete; - const GoASTExprStmt &operator=(const GoASTExprStmt &) = delete; -}; - -class GoASTField : public GoASTNode { -public: - GoASTField() : GoASTNode(eField) {} - ~GoASTField() override = default; - - const char *GetKindName() const override { return "Field"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eField; } - - size_t NumNames() const { return m_names.size(); } - const GoASTIdent *GetNames(int i) const { return m_names[i].get(); } - void AddNames(GoASTIdent *names) { - m_names.push_back(std::unique_ptr<GoASTIdent>(names)); - } - - const GoASTExpr *GetType() const { return m_type_up.get(); } - void SetType(GoASTExpr *type) { m_type_up.reset(type); } - - const GoASTBasicLit *GetTag() const { return m_tag_up.get(); } - void SetTag(GoASTBasicLit *tag) { m_tag_up.reset(tag); } - -private: - friend class GoASTNode; - std::vector<std::unique_ptr<GoASTIdent>> m_names; - std::unique_ptr<GoASTExpr> m_type_up; - std::unique_ptr<GoASTBasicLit> m_tag_up; - - GoASTField(const GoASTField &) = delete; - const GoASTField &operator=(const GoASTField &) = delete; -}; - -class GoASTFieldList : public GoASTNode { -public: - GoASTFieldList() : GoASTNode(eFieldList) {} - ~GoASTFieldList() override = default; - - const char *GetKindName() const override { return "FieldList"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eFieldList; } - - size_t NumList() const { return m_list.size(); } - const GoASTField *GetList(int i) const { return m_list[i].get(); } - void AddList(GoASTField *list) { - m_list.push_back(std::unique_ptr<GoASTField>(list)); - } - -private: - friend class GoASTNode; - std::vector<std::unique_ptr<GoASTField>> m_list; - - GoASTFieldList(const GoASTFieldList &) = delete; - const GoASTFieldList &operator=(const GoASTFieldList &) = delete; -}; - -class GoASTForStmt : public GoASTStmt { -public: - GoASTForStmt(GoASTStmt *init, GoASTExpr *cond, GoASTStmt *post, - GoASTBlockStmt *body) - : GoASTStmt(eForStmt), m_init_up(init), m_cond_up(cond), m_post_up(post), - m_body_up(body) {} - ~GoASTForStmt() override = default; - - const char *GetKindName() const override { return "ForStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eForStmt; } - - const GoASTStmt *GetInit() const { return m_init_up.get(); } - void SetInit(GoASTStmt *init) { m_init_up.reset(init); } - - const GoASTExpr *GetCond() const { return m_cond_up.get(); } - void SetCond(GoASTExpr *cond) { m_cond_up.reset(cond); } - - const GoASTStmt *GetPost() const { return m_post_up.get(); } - void SetPost(GoASTStmt *post) { m_post_up.reset(post); } - - const GoASTBlockStmt *GetBody() const { return m_body_up.get(); } - void SetBody(GoASTBlockStmt *body) { m_body_up.reset(body); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTStmt> m_init_up; - std::unique_ptr<GoASTExpr> m_cond_up; - std::unique_ptr<GoASTStmt> m_post_up; - std::unique_ptr<GoASTBlockStmt> m_body_up; - - GoASTForStmt(const GoASTForStmt &) = delete; - const GoASTForStmt &operator=(const GoASTForStmt &) = delete; -}; - -class GoASTFuncType : public GoASTExpr { -public: - GoASTFuncType(GoASTFieldList *params, GoASTFieldList *results) - : GoASTExpr(eFuncType), m_params_up(params), m_results_up(results) {} - ~GoASTFuncType() override = default; - - const char *GetKindName() const override { return "FuncType"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eFuncType; } - - const GoASTFieldList *GetParams() const { return m_params_up.get(); } - void SetParams(GoASTFieldList *params) { m_params_up.reset(params); } - - const GoASTFieldList *GetResults() const { return m_results_up.get(); } - void SetResults(GoASTFieldList *results) { m_results_up.reset(results); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTFieldList> m_params_up; - std::unique_ptr<GoASTFieldList> m_results_up; - - GoASTFuncType(const GoASTFuncType &) = delete; - const GoASTFuncType &operator=(const GoASTFuncType &) = delete; -}; - -class GoASTFuncDecl : public GoASTDecl { -public: - GoASTFuncDecl(GoASTFieldList *recv, GoASTIdent *name, GoASTFuncType *type, - GoASTBlockStmt *body) - : GoASTDecl(eFuncDecl), m_recv_up(recv), m_name_up(name), m_type_up(type), - m_body_up(body) {} - ~GoASTFuncDecl() override = default; - - const char *GetKindName() const override { return "FuncDecl"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eFuncDecl; } - - const GoASTFieldList *GetRecv() const { return m_recv_up.get(); } - void SetRecv(GoASTFieldList *recv) { m_recv_up.reset(recv); } - - const GoASTIdent *GetName() const { return m_name_up.get(); } - void SetName(GoASTIdent *name) { m_name_up.reset(name); } - - const GoASTFuncType *GetType() const { return m_type_up.get(); } - void SetType(GoASTFuncType *type) { m_type_up.reset(type); } - - const GoASTBlockStmt *GetBody() const { return m_body_up.get(); } - void SetBody(GoASTBlockStmt *body) { m_body_up.reset(body); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTFieldList> m_recv_up; - std::unique_ptr<GoASTIdent> m_name_up; - std::unique_ptr<GoASTFuncType> m_type_up; - std::unique_ptr<GoASTBlockStmt> m_body_up; - - GoASTFuncDecl(const GoASTFuncDecl &) = delete; - const GoASTFuncDecl &operator=(const GoASTFuncDecl &) = delete; -}; - -class GoASTFuncLit : public GoASTExpr { -public: - GoASTFuncLit(GoASTFuncType *type, GoASTBlockStmt *body) - : GoASTExpr(eFuncLit), m_type_up(type), m_body_up(body) {} - ~GoASTFuncLit() override = default; - - const char *GetKindName() const override { return "FuncLit"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eFuncLit; } - - const GoASTFuncType *GetType() const { return m_type_up.get(); } - void SetType(GoASTFuncType *type) { m_type_up.reset(type); } - - const GoASTBlockStmt *GetBody() const { return m_body_up.get(); } - void SetBody(GoASTBlockStmt *body) { m_body_up.reset(body); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTFuncType> m_type_up; - std::unique_ptr<GoASTBlockStmt> m_body_up; - - GoASTFuncLit(const GoASTFuncLit &) = delete; - const GoASTFuncLit &operator=(const GoASTFuncLit &) = delete; -}; - -class GoASTGenDecl : public GoASTDecl { -public: - explicit GoASTGenDecl(TokenType tok) : GoASTDecl(eGenDecl), m_tok(tok) {} - ~GoASTGenDecl() override = default; - - const char *GetKindName() const override { return "GenDecl"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eGenDecl; } - - TokenType GetTok() const { return m_tok; } - void SetTok(TokenType tok) { m_tok = tok; } - - size_t NumSpecs() const { return m_specs.size(); } - const GoASTSpec *GetSpecs(int i) const { return m_specs[i].get(); } - void AddSpecs(GoASTSpec *specs) { - m_specs.push_back(std::unique_ptr<GoASTSpec>(specs)); - } - -private: - friend class GoASTNode; - TokenType m_tok; - std::vector<std::unique_ptr<GoASTSpec>> m_specs; - - GoASTGenDecl(const GoASTGenDecl &) = delete; - const GoASTGenDecl &operator=(const GoASTGenDecl &) = delete; -}; - -class GoASTGoStmt : public GoASTStmt { -public: - explicit GoASTGoStmt(GoASTCallExpr *call) - : GoASTStmt(eGoStmt), m_call_up(call) {} - ~GoASTGoStmt() override = default; - - const char *GetKindName() const override { return "GoStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eGoStmt; } - - const GoASTCallExpr *GetCall() const { return m_call_up.get(); } - void SetCall(GoASTCallExpr *call) { m_call_up.reset(call); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTCallExpr> m_call_up; - - GoASTGoStmt(const GoASTGoStmt &) = delete; - const GoASTGoStmt &operator=(const GoASTGoStmt &) = delete; -}; - -class GoASTIfStmt : public GoASTStmt { -public: - GoASTIfStmt(GoASTStmt *init, GoASTExpr *cond, GoASTBlockStmt *body, - GoASTStmt *els) - : GoASTStmt(eIfStmt), m_init_up(init), m_cond_up(cond), m_body_up(body), - m_els_up(els) {} - ~GoASTIfStmt() override = default; - - const char *GetKindName() const override { return "IfStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eIfStmt; } - - const GoASTStmt *GetInit() const { return m_init_up.get(); } - void SetInit(GoASTStmt *init) { m_init_up.reset(init); } - - const GoASTExpr *GetCond() const { return m_cond_up.get(); } - void SetCond(GoASTExpr *cond) { m_cond_up.reset(cond); } - - const GoASTBlockStmt *GetBody() const { return m_body_up.get(); } - void SetBody(GoASTBlockStmt *body) { m_body_up.reset(body); } - - const GoASTStmt *GetEls() const { return m_els_up.get(); } - void SetEls(GoASTStmt *els) { m_els_up.reset(els); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTStmt> m_init_up; - std::unique_ptr<GoASTExpr> m_cond_up; - std::unique_ptr<GoASTBlockStmt> m_body_up; - std::unique_ptr<GoASTStmt> m_els_up; - - GoASTIfStmt(const GoASTIfStmt &) = delete; - const GoASTIfStmt &operator=(const GoASTIfStmt &) = delete; -}; - -class GoASTImportSpec : public GoASTSpec { -public: - GoASTImportSpec(GoASTIdent *name, GoASTBasicLit *path) - : GoASTSpec(eImportSpec), m_name_up(name), m_path_up(path) {} - ~GoASTImportSpec() override = default; - - const char *GetKindName() const override { return "ImportSpec"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eImportSpec; - } - - const GoASTIdent *GetName() const { return m_name_up.get(); } - void SetName(GoASTIdent *name) { m_name_up.reset(name); } - - const GoASTBasicLit *GetPath() const { return m_path_up.get(); } - void SetPath(GoASTBasicLit *path) { m_path_up.reset(path); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTIdent> m_name_up; - std::unique_ptr<GoASTBasicLit> m_path_up; - - GoASTImportSpec(const GoASTImportSpec &) = delete; - const GoASTImportSpec &operator=(const GoASTImportSpec &) = delete; -}; - -class GoASTIncDecStmt : public GoASTStmt { -public: - GoASTIncDecStmt(GoASTExpr *x, TokenType tok) - : GoASTStmt(eIncDecStmt), m_x_up(x), m_tok(tok) {} - ~GoASTIncDecStmt() override = default; - - const char *GetKindName() const override { return "IncDecStmt"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eIncDecStmt; - } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - - TokenType GetTok() const { return m_tok; } - void SetTok(TokenType tok) { m_tok = tok; } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_x_up; - TokenType m_tok; - - GoASTIncDecStmt(const GoASTIncDecStmt &) = delete; - const GoASTIncDecStmt &operator=(const GoASTIncDecStmt &) = delete; -}; - -class GoASTIndexExpr : public GoASTExpr { -public: - GoASTIndexExpr(GoASTExpr *x, GoASTExpr *index) - : GoASTExpr(eIndexExpr), m_x_up(x), m_index_up(index) {} - ~GoASTIndexExpr() override = default; - - const char *GetKindName() const override { return "IndexExpr"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eIndexExpr; } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - - const GoASTExpr *GetIndex() const { return m_index_up.get(); } - void SetIndex(GoASTExpr *index) { m_index_up.reset(index); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_x_up; - std::unique_ptr<GoASTExpr> m_index_up; - - GoASTIndexExpr(const GoASTIndexExpr &) = delete; - const GoASTIndexExpr &operator=(const GoASTIndexExpr &) = delete; -}; - -class GoASTInterfaceType : public GoASTExpr { -public: - explicit GoASTInterfaceType(GoASTFieldList *methods) - : GoASTExpr(eInterfaceType), m_methods_up(methods) {} - ~GoASTInterfaceType() override = default; - - const char *GetKindName() const override { return "InterfaceType"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eInterfaceType; - } - - const GoASTFieldList *GetMethods() const { return m_methods_up.get(); } - void SetMethods(GoASTFieldList *methods) { m_methods_up.reset(methods); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTFieldList> m_methods_up; - - GoASTInterfaceType(const GoASTInterfaceType &) = delete; - const GoASTInterfaceType &operator=(const GoASTInterfaceType &) = delete; -}; - -class GoASTKeyValueExpr : public GoASTExpr { -public: - GoASTKeyValueExpr(GoASTExpr *key, GoASTExpr *value) - : GoASTExpr(eKeyValueExpr), m_key_up(key), m_value_up(value) {} - ~GoASTKeyValueExpr() override = default; - - const char *GetKindName() const override { return "KeyValueExpr"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eKeyValueExpr; - } - - const GoASTExpr *GetKey() const { return m_key_up.get(); } - void SetKey(GoASTExpr *key) { m_key_up.reset(key); } - - const GoASTExpr *GetValue() const { return m_value_up.get(); } - void SetValue(GoASTExpr *value) { m_value_up.reset(value); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_key_up; - std::unique_ptr<GoASTExpr> m_value_up; - - GoASTKeyValueExpr(const GoASTKeyValueExpr &) = delete; - const GoASTKeyValueExpr &operator=(const GoASTKeyValueExpr &) = delete; -}; - -class GoASTLabeledStmt : public GoASTStmt { -public: - GoASTLabeledStmt(GoASTIdent *label, GoASTStmt *stmt) - : GoASTStmt(eLabeledStmt), m_label_up(label), m_stmt_up(stmt) {} - ~GoASTLabeledStmt() override = default; - - const char *GetKindName() const override { return "LabeledStmt"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eLabeledStmt; - } - - const GoASTIdent *GetLabel() const { return m_label_up.get(); } - void SetLabel(GoASTIdent *label) { m_label_up.reset(label); } - - const GoASTStmt *GetStmt() const { return m_stmt_up.get(); } - void SetStmt(GoASTStmt *stmt) { m_stmt_up.reset(stmt); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTIdent> m_label_up; - std::unique_ptr<GoASTStmt> m_stmt_up; - - GoASTLabeledStmt(const GoASTLabeledStmt &) = delete; - const GoASTLabeledStmt &operator=(const GoASTLabeledStmt &) = delete; -}; - -class GoASTMapType : public GoASTExpr { -public: - GoASTMapType(GoASTExpr *key, GoASTExpr *value) - : GoASTExpr(eMapType), m_key_up(key), m_value_up(value) {} - ~GoASTMapType() override = default; - - const char *GetKindName() const override { return "MapType"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eMapType; } - - const GoASTExpr *GetKey() const { return m_key_up.get(); } - void SetKey(GoASTExpr *key) { m_key_up.reset(key); } - - const GoASTExpr *GetValue() const { return m_value_up.get(); } - void SetValue(GoASTExpr *value) { m_value_up.reset(value); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_key_up; - std::unique_ptr<GoASTExpr> m_value_up; - - GoASTMapType(const GoASTMapType &) = delete; - const GoASTMapType &operator=(const GoASTMapType &) = delete; -}; - -class GoASTParenExpr : public GoASTExpr { -public: - explicit GoASTParenExpr(GoASTExpr *x) : GoASTExpr(eParenExpr), m_x_up(x) {} - ~GoASTParenExpr() override = default; - - const char *GetKindName() const override { return "ParenExpr"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eParenExpr; } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_x_up; - - GoASTParenExpr(const GoASTParenExpr &) = delete; - const GoASTParenExpr &operator=(const GoASTParenExpr &) = delete; -}; - -class GoASTRangeStmt : public GoASTStmt { -public: - GoASTRangeStmt(GoASTExpr *key, GoASTExpr *value, bool define, GoASTExpr *x, - GoASTBlockStmt *body) - : GoASTStmt(eRangeStmt), m_key_up(key), m_value_up(value), - m_define(define), m_x_up(x), m_body_up(body) {} - ~GoASTRangeStmt() override = default; - - const char *GetKindName() const override { return "RangeStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eRangeStmt; } - - const GoASTExpr *GetKey() const { return m_key_up.get(); } - void SetKey(GoASTExpr *key) { m_key_up.reset(key); } - - const GoASTExpr *GetValue() const { return m_value_up.get(); } - void SetValue(GoASTExpr *value) { m_value_up.reset(value); } - - bool GetDefine() const { return m_define; } - void SetDefine(bool define) { m_define = define; } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - - const GoASTBlockStmt *GetBody() const { return m_body_up.get(); } - void SetBody(GoASTBlockStmt *body) { m_body_up.reset(body); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_key_up; - std::unique_ptr<GoASTExpr> m_value_up; - bool m_define; - std::unique_ptr<GoASTExpr> m_x_up; - std::unique_ptr<GoASTBlockStmt> m_body_up; - - GoASTRangeStmt(const GoASTRangeStmt &) = delete; - const GoASTRangeStmt &operator=(const GoASTRangeStmt &) = delete; -}; - -class GoASTReturnStmt : public GoASTStmt { -public: - GoASTReturnStmt() : GoASTStmt(eReturnStmt) {} - ~GoASTReturnStmt() override = default; - - const char *GetKindName() const override { return "ReturnStmt"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eReturnStmt; - } - - size_t NumResults() const { return m_results.size(); } - const GoASTExpr *GetResults(int i) const { return m_results[i].get(); } - void AddResults(GoASTExpr *results) { - m_results.push_back(std::unique_ptr<GoASTExpr>(results)); - } - -private: - friend class GoASTNode; - std::vector<std::unique_ptr<GoASTExpr>> m_results; - - GoASTReturnStmt(const GoASTReturnStmt &) = delete; - const GoASTReturnStmt &operator=(const GoASTReturnStmt &) = delete; -}; - -class GoASTSelectStmt : public GoASTStmt { -public: - explicit GoASTSelectStmt(GoASTBlockStmt *body) - : GoASTStmt(eSelectStmt), m_body_up(body) {} - ~GoASTSelectStmt() override = default; - - const char *GetKindName() const override { return "SelectStmt"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eSelectStmt; - } - - const GoASTBlockStmt *GetBody() const { return m_body_up.get(); } - void SetBody(GoASTBlockStmt *body) { m_body_up.reset(body); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTBlockStmt> m_body_up; - - GoASTSelectStmt(const GoASTSelectStmt &) = delete; - const GoASTSelectStmt &operator=(const GoASTSelectStmt &) = delete; -}; - -class GoASTSelectorExpr : public GoASTExpr { -public: - GoASTSelectorExpr(GoASTExpr *x, GoASTIdent *sel) - : GoASTExpr(eSelectorExpr), m_x_up(x), m_sel_up(sel) {} - ~GoASTSelectorExpr() override = default; - - const char *GetKindName() const override { return "SelectorExpr"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eSelectorExpr; - } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - - const GoASTIdent *GetSel() const { return m_sel_up.get(); } - void SetSel(GoASTIdent *sel) { m_sel_up.reset(sel); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_x_up; - std::unique_ptr<GoASTIdent> m_sel_up; - - GoASTSelectorExpr(const GoASTSelectorExpr &) = delete; - const GoASTSelectorExpr &operator=(const GoASTSelectorExpr &) = delete; -}; - -class GoASTSendStmt : public GoASTStmt { -public: - GoASTSendStmt(GoASTExpr *chan, GoASTExpr *value) - : GoASTStmt(eSendStmt), m_chan_up(chan), m_value_up(value) {} - ~GoASTSendStmt() override = default; - - const char *GetKindName() const override { return "SendStmt"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eSendStmt; } - - const GoASTExpr *GetChan() const { return m_chan_up.get(); } - void SetChan(GoASTExpr *chan) { m_chan_up.reset(chan); } - - const GoASTExpr *GetValue() const { return m_value_up.get(); } - void SetValue(GoASTExpr *value) { m_value_up.reset(value); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_chan_up; - std::unique_ptr<GoASTExpr> m_value_up; - - GoASTSendStmt(const GoASTSendStmt &) = delete; - const GoASTSendStmt &operator=(const GoASTSendStmt &) = delete; -}; - -class GoASTSliceExpr : public GoASTExpr { -public: - GoASTSliceExpr(GoASTExpr *x, GoASTExpr *low, GoASTExpr *high, GoASTExpr *max, - bool slice3) - : GoASTExpr(eSliceExpr), m_x_up(x), m_low_up(low), m_high_up(high), - m_max_up(max), m_slice3(slice3) {} - ~GoASTSliceExpr() override = default; - - const char *GetKindName() const override { return "SliceExpr"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eSliceExpr; } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - - const GoASTExpr *GetLow() const { return m_low_up.get(); } - void SetLow(GoASTExpr *low) { m_low_up.reset(low); } - - const GoASTExpr *GetHigh() const { return m_high_up.get(); } - void SetHigh(GoASTExpr *high) { m_high_up.reset(high); } - - const GoASTExpr *GetMax() const { return m_max_up.get(); } - void SetMax(GoASTExpr *max) { m_max_up.reset(max); } - - bool GetSlice3() const { return m_slice3; } - void SetSlice3(bool slice3) { m_slice3 = slice3; } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_x_up; - std::unique_ptr<GoASTExpr> m_low_up; - std::unique_ptr<GoASTExpr> m_high_up; - std::unique_ptr<GoASTExpr> m_max_up; - bool m_slice3; - - GoASTSliceExpr(const GoASTSliceExpr &) = delete; - const GoASTSliceExpr &operator=(const GoASTSliceExpr &) = delete; -}; - -class GoASTStarExpr : public GoASTExpr { -public: - explicit GoASTStarExpr(GoASTExpr *x) : GoASTExpr(eStarExpr), m_x_up(x) {} - ~GoASTStarExpr() override = default; - - const char *GetKindName() const override { return "StarExpr"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eStarExpr; } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_x_up; - - GoASTStarExpr(const GoASTStarExpr &) = delete; - const GoASTStarExpr &operator=(const GoASTStarExpr &) = delete; -}; - -class GoASTStructType : public GoASTExpr { -public: - explicit GoASTStructType(GoASTFieldList *fields) - : GoASTExpr(eStructType), m_fields_up(fields) {} - ~GoASTStructType() override = default; - - const char *GetKindName() const override { return "StructType"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eStructType; - } - - const GoASTFieldList *GetFields() const { return m_fields_up.get(); } - void SetFields(GoASTFieldList *fields) { m_fields_up.reset(fields); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTFieldList> m_fields_up; - - GoASTStructType(const GoASTStructType &) = delete; - const GoASTStructType &operator=(const GoASTStructType &) = delete; -}; - -class GoASTSwitchStmt : public GoASTStmt { -public: - GoASTSwitchStmt(GoASTStmt *init, GoASTExpr *tag, GoASTBlockStmt *body) - : GoASTStmt(eSwitchStmt), m_init_up(init), m_tag_up(tag), - m_body_up(body) {} - ~GoASTSwitchStmt() override = default; - - const char *GetKindName() const override { return "SwitchStmt"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eSwitchStmt; - } - - const GoASTStmt *GetInit() const { return m_init_up.get(); } - void SetInit(GoASTStmt *init) { m_init_up.reset(init); } - - const GoASTExpr *GetTag() const { return m_tag_up.get(); } - void SetTag(GoASTExpr *tag) { m_tag_up.reset(tag); } - - const GoASTBlockStmt *GetBody() const { return m_body_up.get(); } - void SetBody(GoASTBlockStmt *body) { m_body_up.reset(body); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTStmt> m_init_up; - std::unique_ptr<GoASTExpr> m_tag_up; - std::unique_ptr<GoASTBlockStmt> m_body_up; - - GoASTSwitchStmt(const GoASTSwitchStmt &) = delete; - const GoASTSwitchStmt &operator=(const GoASTSwitchStmt &) = delete; -}; - -class GoASTTypeAssertExpr : public GoASTExpr { -public: - GoASTTypeAssertExpr(GoASTExpr *x, GoASTExpr *type) - : GoASTExpr(eTypeAssertExpr), m_x_up(x), m_type_up(type) {} - ~GoASTTypeAssertExpr() override = default; - - const char *GetKindName() const override { return "TypeAssertExpr"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eTypeAssertExpr; - } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - - const GoASTExpr *GetType() const { return m_type_up.get(); } - void SetType(GoASTExpr *type) { m_type_up.reset(type); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTExpr> m_x_up; - std::unique_ptr<GoASTExpr> m_type_up; - - GoASTTypeAssertExpr(const GoASTTypeAssertExpr &) = delete; - const GoASTTypeAssertExpr &operator=(const GoASTTypeAssertExpr &) = delete; -}; - -class GoASTTypeSpec : public GoASTSpec { -public: - GoASTTypeSpec(GoASTIdent *name, GoASTExpr *type) - : GoASTSpec(eTypeSpec), m_name_up(name), m_type_up(type) {} - ~GoASTTypeSpec() override = default; - - const char *GetKindName() const override { return "TypeSpec"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eTypeSpec; } - - const GoASTIdent *GetName() const { return m_name_up.get(); } - void SetName(GoASTIdent *name) { m_name_up.reset(name); } - - const GoASTExpr *GetType() const { return m_type_up.get(); } - void SetType(GoASTExpr *type) { m_type_up.reset(type); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTIdent> m_name_up; - std::unique_ptr<GoASTExpr> m_type_up; - - GoASTTypeSpec(const GoASTTypeSpec &) = delete; - const GoASTTypeSpec &operator=(const GoASTTypeSpec &) = delete; -}; - -class GoASTTypeSwitchStmt : public GoASTStmt { -public: - GoASTTypeSwitchStmt(GoASTStmt *init, GoASTStmt *assign, GoASTBlockStmt *body) - : GoASTStmt(eTypeSwitchStmt), m_init_up(init), m_assign_up(assign), - m_body_up(body) {} - ~GoASTTypeSwitchStmt() override = default; - - const char *GetKindName() const override { return "TypeSwitchStmt"; } - - static bool classof(const GoASTNode *n) { - return n->GetKind() == eTypeSwitchStmt; - } - - const GoASTStmt *GetInit() const { return m_init_up.get(); } - void SetInit(GoASTStmt *init) { m_init_up.reset(init); } - - const GoASTStmt *GetAssign() const { return m_assign_up.get(); } - void SetAssign(GoASTStmt *assign) { m_assign_up.reset(assign); } - - const GoASTBlockStmt *GetBody() const { return m_body_up.get(); } - void SetBody(GoASTBlockStmt *body) { m_body_up.reset(body); } - -private: - friend class GoASTNode; - std::unique_ptr<GoASTStmt> m_init_up; - std::unique_ptr<GoASTStmt> m_assign_up; - std::unique_ptr<GoASTBlockStmt> m_body_up; - - GoASTTypeSwitchStmt(const GoASTTypeSwitchStmt &) = delete; - const GoASTTypeSwitchStmt &operator=(const GoASTTypeSwitchStmt &) = delete; -}; - -class GoASTUnaryExpr : public GoASTExpr { -public: - GoASTUnaryExpr(TokenType op, GoASTExpr *x) - : GoASTExpr(eUnaryExpr), m_op(op), m_x_up(x) {} - ~GoASTUnaryExpr() override = default; - - const char *GetKindName() const override { return "UnaryExpr"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eUnaryExpr; } - - TokenType GetOp() const { return m_op; } - void SetOp(TokenType op) { m_op = op; } - - const GoASTExpr *GetX() const { return m_x_up.get(); } - void SetX(GoASTExpr *x) { m_x_up.reset(x); } - -private: - friend class GoASTNode; - TokenType m_op; - std::unique_ptr<GoASTExpr> m_x_up; - - GoASTUnaryExpr(const GoASTUnaryExpr &) = delete; - const GoASTUnaryExpr &operator=(const GoASTUnaryExpr &) = delete; -}; - -class GoASTValueSpec : public GoASTSpec { -public: - GoASTValueSpec() : GoASTSpec(eValueSpec) {} - ~GoASTValueSpec() override = default; - - const char *GetKindName() const override { return "ValueSpec"; } - - static bool classof(const GoASTNode *n) { return n->GetKind() == eValueSpec; } - - size_t NumNames() const { return m_names.size(); } - const GoASTIdent *GetNames(int i) const { return m_names[i].get(); } - void AddNames(GoASTIdent *names) { - m_names.push_back(std::unique_ptr<GoASTIdent>(names)); - } - - const GoASTExpr *GetType() const { return m_type_up.get(); } - void SetType(GoASTExpr *type) { m_type_up.reset(type); } - - size_t NumValues() const { return m_values.size(); } - const GoASTExpr *GetValues(int i) const { return m_values[i].get(); } - void AddValues(GoASTExpr *values) { - m_values.push_back(std::unique_ptr<GoASTExpr>(values)); - } - -private: - friend class GoASTNode; - std::vector<std::unique_ptr<GoASTIdent>> m_names; - std::unique_ptr<GoASTExpr> m_type_up; - std::vector<std::unique_ptr<GoASTExpr>> m_values; - - GoASTValueSpec(const GoASTValueSpec &) = delete; - const GoASTValueSpec &operator=(const GoASTValueSpec &) = delete; -}; - -template <typename R, typename V> R GoASTDecl::Visit(V *v) const { - switch (GetKind()) { - case eBadDecl: - return v->VisitBadDecl(llvm::cast<const GoASTBadDecl>(this)); - case eFuncDecl: - return v->VisitFuncDecl(llvm::cast<const GoASTFuncDecl>(this)); - case eGenDecl: - return v->VisitGenDecl(llvm::cast<const GoASTGenDecl>(this)); - default: - assert(false && "Invalid kind"); - } -} - -template <typename R, typename V> R GoASTExpr::Visit(V *v) const { - switch (GetKind()) { - case eArrayType: - return v->VisitArrayType(llvm::cast<const GoASTArrayType>(this)); - case eBadExpr: - return v->VisitBadExpr(llvm::cast<const GoASTBadExpr>(this)); - case eBasicLit: - return v->VisitBasicLit(llvm::cast<const GoASTBasicLit>(this)); - case eBinaryExpr: - return v->VisitBinaryExpr(llvm::cast<const GoASTBinaryExpr>(this)); - case eIdent: - return v->VisitIdent(llvm::cast<const GoASTIdent>(this)); - case eCallExpr: - return v->VisitCallExpr(llvm::cast<const GoASTCallExpr>(this)); - case eChanType: - return v->VisitChanType(llvm::cast<const GoASTChanType>(this)); - case eCompositeLit: - return v->VisitCompositeLit(llvm::cast<const GoASTCompositeLit>(this)); - case eEllipsis: - return v->VisitEllipsis(llvm::cast<const GoASTEllipsis>(this)); - case eFuncType: - return v->VisitFuncType(llvm::cast<const GoASTFuncType>(this)); - case eFuncLit: - return v->VisitFuncLit(llvm::cast<const GoASTFuncLit>(this)); - case eIndexExpr: - return v->VisitIndexExpr(llvm::cast<const GoASTIndexExpr>(this)); - case eInterfaceType: - return v->VisitInterfaceType(llvm::cast<const GoASTInterfaceType>(this)); - case eKeyValueExpr: - return v->VisitKeyValueExpr(llvm::cast<const GoASTKeyValueExpr>(this)); - case eMapType: - return v->VisitMapType(llvm::cast<const GoASTMapType>(this)); - case eParenExpr: - return v->VisitParenExpr(llvm::cast<const GoASTParenExpr>(this)); - case eSelectorExpr: - return v->VisitSelectorExpr(llvm::cast<const GoASTSelectorExpr>(this)); - case eSliceExpr: - return v->VisitSliceExpr(llvm::cast<const GoASTSliceExpr>(this)); - case eStarExpr: - return v->VisitStarExpr(llvm::cast<const GoASTStarExpr>(this)); - case eStructType: - return v->VisitStructType(llvm::cast<const GoASTStructType>(this)); - case eTypeAssertExpr: - return v->VisitTypeAssertExpr(llvm::cast<const GoASTTypeAssertExpr>(this)); - case eUnaryExpr: - return v->VisitUnaryExpr(llvm::cast<const GoASTUnaryExpr>(this)); - default: - assert(false && "Invalid kind"); - return R(); - } -} - -template <typename R, typename V> R GoASTSpec::Visit(V *v) const { - switch (GetKind()) { - case eImportSpec: - return v->VisitImportSpec(llvm::cast<const GoASTImportSpec>(this)); - case eTypeSpec: - return v->VisitTypeSpec(llvm::cast<const GoASTTypeSpec>(this)); - case eValueSpec: - return v->VisitValueSpec(llvm::cast<const GoASTValueSpec>(this)); - default: - assert(false && "Invalid kind"); - } -} - -template <typename R, typename V> R GoASTStmt::Visit(V *v) const { - switch (GetKind()) { - case eAssignStmt: - return v->VisitAssignStmt(llvm::cast<const GoASTAssignStmt>(this)); - case eBadStmt: - return v->VisitBadStmt(llvm::cast<const GoASTBadStmt>(this)); - case eBlockStmt: - return v->VisitBlockStmt(llvm::cast<const GoASTBlockStmt>(this)); - case eBranchStmt: - return v->VisitBranchStmt(llvm::cast<const GoASTBranchStmt>(this)); - case eCaseClause: - return v->VisitCaseClause(llvm::cast<const GoASTCaseClause>(this)); - case eCommClause: - return v->VisitCommClause(llvm::cast<const GoASTCommClause>(this)); - case eDeclStmt: - return v->VisitDeclStmt(llvm::cast<const GoASTDeclStmt>(this)); - case eDeferStmt: - return v->VisitDeferStmt(llvm::cast<const GoASTDeferStmt>(this)); - case eEmptyStmt: - return v->VisitEmptyStmt(llvm::cast<const GoASTEmptyStmt>(this)); - case eExprStmt: - return v->VisitExprStmt(llvm::cast<const GoASTExprStmt>(this)); - case eForStmt: - return v->VisitForStmt(llvm::cast<const GoASTForStmt>(this)); - case eGoStmt: - return v->VisitGoStmt(llvm::cast<const GoASTGoStmt>(this)); - case eIfStmt: - return v->VisitIfStmt(llvm::cast<const GoASTIfStmt>(this)); - case eIncDecStmt: - return v->VisitIncDecStmt(llvm::cast<const GoASTIncDecStmt>(this)); - case eLabeledStmt: - return v->VisitLabeledStmt(llvm::cast<const GoASTLabeledStmt>(this)); - case eRangeStmt: - return v->VisitRangeStmt(llvm::cast<const GoASTRangeStmt>(this)); - case eReturnStmt: - return v->VisitReturnStmt(llvm::cast<const GoASTReturnStmt>(this)); - case eSelectStmt: - return v->VisitSelectStmt(llvm::cast<const GoASTSelectStmt>(this)); - case eSendStmt: - return v->VisitSendStmt(llvm::cast<const GoASTSendStmt>(this)); - case eSwitchStmt: - return v->VisitSwitchStmt(llvm::cast<const GoASTSwitchStmt>(this)); - case eTypeSwitchStmt: - return v->VisitTypeSwitchStmt(llvm::cast<const GoASTTypeSwitchStmt>(this)); - default: - assert(false && "Invalid kind"); - } -} - -template <typename V> void GoASTNode::WalkChildren(V &v) { - switch (m_kind) { - - case eArrayType: { - GoASTArrayType *n = llvm::cast<GoASTArrayType>(this); - (void)n; - v(n->m_len_up.get()); - v(n->m_elt_up.get()); - return; - } - case eAssignStmt: { - GoASTAssignStmt *n = llvm::cast<GoASTAssignStmt>(this); - (void)n; - for (auto &e : n->m_lhs) { - v(e.get()); - } - for (auto &e : n->m_rhs) { - v(e.get()); - } - return; - } - case eBasicLit: { - GoASTBasicLit *n = llvm::cast<GoASTBasicLit>(this); - (void)n; - return; - } - case eBinaryExpr: { - GoASTBinaryExpr *n = llvm::cast<GoASTBinaryExpr>(this); - (void)n; - v(n->m_x_up.get()); - v(n->m_y_up.get()); - return; - } - case eBlockStmt: { - GoASTBlockStmt *n = llvm::cast<GoASTBlockStmt>(this); - (void)n; - for (auto &e : n->m_list) { - v(e.get()); - } - return; - } - case eIdent: { - GoASTIdent *n = llvm::cast<GoASTIdent>(this); - (void)n; - return; - } - case eBranchStmt: { - GoASTBranchStmt *n = llvm::cast<GoASTBranchStmt>(this); - (void)n; - v(n->m_label_up.get()); - return; - } - case eCallExpr: { - GoASTCallExpr *n = llvm::cast<GoASTCallExpr>(this); - (void)n; - v(n->m_fun_up.get()); - for (auto &e : n->m_args) { - v(e.get()); - } - return; - } - case eCaseClause: { - GoASTCaseClause *n = llvm::cast<GoASTCaseClause>(this); - (void)n; - for (auto &e : n->m_list) { - v(e.get()); - } - for (auto &e : n->m_body) { - v(e.get()); - } - return; - } - case eChanType: { - GoASTChanType *n = llvm::cast<GoASTChanType>(this); - (void)n; - v(n->m_value_up.get()); - return; - } - case eCommClause: { - GoASTCommClause *n = llvm::cast<GoASTCommClause>(this); - (void)n; - v(n->m_comm_up.get()); - for (auto &e : n->m_body) { - v(e.get()); - } - return; - } - case eCompositeLit: { - GoASTCompositeLit *n = llvm::cast<GoASTCompositeLit>(this); - (void)n; - v(n->m_type_up.get()); - for (auto &e : n->m_elts) { - v(e.get()); - } - return; - } - case eDeclStmt: { - GoASTDeclStmt *n = llvm::cast<GoASTDeclStmt>(this); - (void)n; - v(n->m_decl_up.get()); - return; - } - case eDeferStmt: { - GoASTDeferStmt *n = llvm::cast<GoASTDeferStmt>(this); - (void)n; - v(n->m_call_up.get()); - return; - } - case eEllipsis: { - GoASTEllipsis *n = llvm::cast<GoASTEllipsis>(this); - (void)n; - v(n->m_elt_up.get()); - return; - } - case eExprStmt: { - GoASTExprStmt *n = llvm::cast<GoASTExprStmt>(this); - (void)n; - v(n->m_x_up.get()); - return; - } - case eField: { - GoASTField *n = llvm::cast<GoASTField>(this); - (void)n; - for (auto &e : n->m_names) { - v(e.get()); - } - v(n->m_type_up.get()); - v(n->m_tag_up.get()); - return; - } - case eFieldList: { - GoASTFieldList *n = llvm::cast<GoASTFieldList>(this); - (void)n; - for (auto &e : n->m_list) { - v(e.get()); - } - return; - } - case eForStmt: { - GoASTForStmt *n = llvm::cast<GoASTForStmt>(this); - (void)n; - v(n->m_init_up.get()); - v(n->m_cond_up.get()); - v(n->m_post_up.get()); - v(n->m_body_up.get()); - return; - } - case eFuncType: { - GoASTFuncType *n = llvm::cast<GoASTFuncType>(this); - (void)n; - v(n->m_params_up.get()); - v(n->m_results_up.get()); - return; - } - case eFuncDecl: { - GoASTFuncDecl *n = llvm::cast<GoASTFuncDecl>(this); - (void)n; - v(n->m_recv_up.get()); - v(n->m_name_up.get()); - v(n->m_type_up.get()); - v(n->m_body_up.get()); - return; - } - case eFuncLit: { - GoASTFuncLit *n = llvm::cast<GoASTFuncLit>(this); - (void)n; - v(n->m_type_up.get()); - v(n->m_body_up.get()); - return; - } - case eGenDecl: { - GoASTGenDecl *n = llvm::cast<GoASTGenDecl>(this); - (void)n; - for (auto &e : n->m_specs) { - v(e.get()); - } - return; - } - case eGoStmt: { - GoASTGoStmt *n = llvm::cast<GoASTGoStmt>(this); - (void)n; - v(n->m_call_up.get()); - return; - } - case eIfStmt: { - GoASTIfStmt *n = llvm::cast<GoASTIfStmt>(this); - (void)n; - v(n->m_init_up.get()); - v(n->m_cond_up.get()); - v(n->m_body_up.get()); - v(n->m_els_up.get()); - return; - } - case eImportSpec: { - GoASTImportSpec *n = llvm::cast<GoASTImportSpec>(this); - (void)n; - v(n->m_name_up.get()); - v(n->m_path_up.get()); - return; - } - case eIncDecStmt: { - GoASTIncDecStmt *n = llvm::cast<GoASTIncDecStmt>(this); - (void)n; - v(n->m_x_up.get()); - return; - } - case eIndexExpr: { - GoASTIndexExpr *n = llvm::cast<GoASTIndexExpr>(this); - (void)n; - v(n->m_x_up.get()); - v(n->m_index_up.get()); - return; - } - case eInterfaceType: { - GoASTInterfaceType *n = llvm::cast<GoASTInterfaceType>(this); - (void)n; - v(n->m_methods_up.get()); - return; - } - case eKeyValueExpr: { - GoASTKeyValueExpr *n = llvm::cast<GoASTKeyValueExpr>(this); - (void)n; - v(n->m_key_up.get()); - v(n->m_value_up.get()); - return; - } - case eLabeledStmt: { - GoASTLabeledStmt *n = llvm::cast<GoASTLabeledStmt>(this); - (void)n; - v(n->m_label_up.get()); - v(n->m_stmt_up.get()); - return; - } - case eMapType: { - GoASTMapType *n = llvm::cast<GoASTMapType>(this); - (void)n; - v(n->m_key_up.get()); - v(n->m_value_up.get()); - return; - } - case eParenExpr: { - GoASTParenExpr *n = llvm::cast<GoASTParenExpr>(this); - (void)n; - v(n->m_x_up.get()); - return; - } - case eRangeStmt: { - GoASTRangeStmt *n = llvm::cast<GoASTRangeStmt>(this); - (void)n; - v(n->m_key_up.get()); - v(n->m_value_up.get()); - v(n->m_x_up.get()); - v(n->m_body_up.get()); - return; - } - case eReturnStmt: { - GoASTReturnStmt *n = llvm::cast<GoASTReturnStmt>(this); - (void)n; - for (auto &e : n->m_results) { - v(e.get()); - } - return; - } - case eSelectStmt: { - GoASTSelectStmt *n = llvm::cast<GoASTSelectStmt>(this); - (void)n; - v(n->m_body_up.get()); - return; - } - case eSelectorExpr: { - GoASTSelectorExpr *n = llvm::cast<GoASTSelectorExpr>(this); - (void)n; - v(n->m_x_up.get()); - v(n->m_sel_up.get()); - return; - } - case eSendStmt: { - GoASTSendStmt *n = llvm::cast<GoASTSendStmt>(this); - (void)n; - v(n->m_chan_up.get()); - v(n->m_value_up.get()); - return; - } - case eSliceExpr: { - GoASTSliceExpr *n = llvm::cast<GoASTSliceExpr>(this); - (void)n; - v(n->m_x_up.get()); - v(n->m_low_up.get()); - v(n->m_high_up.get()); - v(n->m_max_up.get()); - return; - } - case eStarExpr: { - GoASTStarExpr *n = llvm::cast<GoASTStarExpr>(this); - (void)n; - v(n->m_x_up.get()); - return; - } - case eStructType: { - GoASTStructType *n = llvm::cast<GoASTStructType>(this); - (void)n; - v(n->m_fields_up.get()); - return; - } - case eSwitchStmt: { - GoASTSwitchStmt *n = llvm::cast<GoASTSwitchStmt>(this); - (void)n; - v(n->m_init_up.get()); - v(n->m_tag_up.get()); - v(n->m_body_up.get()); - return; - } - case eTypeAssertExpr: { - GoASTTypeAssertExpr *n = llvm::cast<GoASTTypeAssertExpr>(this); - (void)n; - v(n->m_x_up.get()); - v(n->m_type_up.get()); - return; - } - case eTypeSpec: { - GoASTTypeSpec *n = llvm::cast<GoASTTypeSpec>(this); - (void)n; - v(n->m_name_up.get()); - v(n->m_type_up.get()); - return; - } - case eTypeSwitchStmt: { - GoASTTypeSwitchStmt *n = llvm::cast<GoASTTypeSwitchStmt>(this); - (void)n; - v(n->m_init_up.get()); - v(n->m_assign_up.get()); - v(n->m_body_up.get()); - return; - } - case eUnaryExpr: { - GoASTUnaryExpr *n = llvm::cast<GoASTUnaryExpr>(this); - (void)n; - v(n->m_x_up.get()); - return; - } - case eValueSpec: { - GoASTValueSpec *n = llvm::cast<GoASTValueSpec>(this); - (void)n; - for (auto &e : n->m_names) { - v(e.get()); - } - v(n->m_type_up.get()); - for (auto &e : n->m_values) { - v(e.get()); - } - return; - } - - case eEmptyStmt: - case eBadDecl: - case eBadExpr: - case eBadStmt: - break; - } -} - -} // namespace lldb_private - -#endif diff --git a/source/Plugins/ExpressionParser/Go/GoLexer.cpp b/source/Plugins/ExpressionParser/Go/GoLexer.cpp deleted file mode 100644 index 63e267eaadc2..000000000000 --- a/source/Plugins/ExpressionParser/Go/GoLexer.cpp +++ /dev/null @@ -1,350 +0,0 @@ -//===-- GoLexer.cpp ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <string.h> - -#include "GoLexer.h" - -using namespace lldb_private; - -llvm::StringMap<GoLexer::TokenType> *GoLexer::m_keywords; - -GoLexer::GoLexer(const char *src) - : m_src(src), m_end(src + strlen(src)), m_last_token(TOK_INVALID, "") {} - -bool GoLexer::SkipWhitespace() { - bool saw_newline = false; - for (; m_src < m_end; ++m_src) { - if (*m_src == '\n') - saw_newline = true; - if (*m_src == '/' && !SkipComment()) - return saw_newline; - else if (!IsWhitespace(*m_src)) - return saw_newline; - } - return saw_newline; -} - -bool GoLexer::SkipComment() { - if (m_src[0] == '/' && m_src[1] == '/') { - for (const char *c = m_src + 2; c < m_end; ++c) { - if (*c == '\n') { - m_src = c - 1; - return true; - } - } - return true; - } else if (m_src[0] == '/' && m_src[1] == '*') { - for (const char *c = m_src + 2; c < m_end; ++c) { - if (c[0] == '*' && c[1] == '/') { - m_src = c + 1; - return true; - } - } - } - return false; -} - -const GoLexer::Token &GoLexer::Lex() { - bool newline = SkipWhitespace(); - const char *start = m_src; - m_last_token.m_type = InternalLex(newline); - m_last_token.m_value = llvm::StringRef(start, m_src - start); - return m_last_token; -} - -GoLexer::TokenType GoLexer::InternalLex(bool newline) { - if (m_src >= m_end) { - return TOK_EOF; - } - if (newline) { - switch (m_last_token.m_type) { - case TOK_IDENTIFIER: - case LIT_FLOAT: - case LIT_IMAGINARY: - case LIT_INTEGER: - case LIT_RUNE: - case LIT_STRING: - case KEYWORD_BREAK: - case KEYWORD_CONTINUE: - case KEYWORD_FALLTHROUGH: - case KEYWORD_RETURN: - case OP_PLUS_PLUS: - case OP_MINUS_MINUS: - case OP_RPAREN: - case OP_RBRACK: - case OP_RBRACE: - return OP_SEMICOLON; - default: - break; - } - } - char c = *m_src; - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return DoNumber(); - case '+': - case '-': - case '*': - case '/': - case '%': - case '&': - case '|': - case '^': - case '<': - case '>': - case '!': - case ':': - case ';': - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - case ',': - case '=': - return DoOperator(); - case '.': - if (IsDecimal(m_src[1])) - return DoNumber(); - return DoOperator(); - case '$': - // For lldb persistent vars. - return DoIdent(); - case '"': - case '`': - return DoString(); - case '\'': - return DoRune(); - default: - break; - } - if (IsLetterOrDigit(c)) - return DoIdent(); - ++m_src; - return TOK_INVALID; -} - -GoLexer::TokenType GoLexer::DoOperator() { - TokenType t = TOK_INVALID; - if (m_end - m_src > 2) { - t = LookupKeyword(llvm::StringRef(m_src, 3)); - if (t != TOK_INVALID) - m_src += 3; - } - if (t == TOK_INVALID && m_end - m_src > 1) { - t = LookupKeyword(llvm::StringRef(m_src, 2)); - if (t != TOK_INVALID) - m_src += 2; - } - if (t == TOK_INVALID) { - t = LookupKeyword(llvm::StringRef(m_src, 1)); - ++m_src; - } - return t; -} - -GoLexer::TokenType GoLexer::DoIdent() { - const char *start = m_src++; - while (m_src < m_end && IsLetterOrDigit(*m_src)) { - ++m_src; - } - TokenType kw = LookupKeyword(llvm::StringRef(start, m_src - start)); - if (kw != TOK_INVALID) - return kw; - return TOK_IDENTIFIER; -} - -GoLexer::TokenType GoLexer::DoNumber() { - if (m_src[0] == '0' && (m_src[1] == 'x' || m_src[1] == 'X')) { - m_src += 2; - while (IsHexChar(*m_src)) - ++m_src; - return LIT_INTEGER; - } - bool dot_ok = true; - bool e_ok = true; - while (true) { - while (IsDecimal(*m_src)) - ++m_src; - switch (*m_src) { - case 'i': - ++m_src; - return LIT_IMAGINARY; - case '.': - if (!dot_ok) - return LIT_FLOAT; - ++m_src; - dot_ok = false; - break; - case 'e': - case 'E': - if (!e_ok) - return LIT_FLOAT; - dot_ok = e_ok = false; - ++m_src; - if (*m_src == '+' || *m_src == '-') - ++m_src; - break; - default: - if (dot_ok) - return LIT_INTEGER; - return LIT_FLOAT; - } - } -} - -GoLexer::TokenType GoLexer::DoRune() { - while (++m_src < m_end) { - switch (*m_src) { - case '\'': - ++m_src; - return LIT_RUNE; - case '\n': - return TOK_INVALID; - case '\\': - if (m_src[1] == '\n') - return TOK_INVALID; - ++m_src; - } - } - return TOK_INVALID; -} - -GoLexer::TokenType GoLexer::DoString() { - if (*m_src == '`') { - while (++m_src < m_end) { - if (*m_src == '`') { - ++m_src; - return LIT_STRING; - } - } - return TOK_INVALID; - } - while (++m_src < m_end) { - switch (*m_src) { - case '"': - ++m_src; - return LIT_STRING; - case '\n': - return TOK_INVALID; - case '\\': - if (m_src[1] == '\n') - return TOK_INVALID; - ++m_src; - } - } - return TOK_INVALID; -} - -GoLexer::TokenType GoLexer::LookupKeyword(llvm::StringRef id) { - if (m_keywords == nullptr) - m_keywords = InitKeywords(); - const auto &it = m_keywords->find(id); - if (it == m_keywords->end()) - return TOK_INVALID; - return it->second; -} - -llvm::StringRef GoLexer::LookupToken(TokenType t) { - if (m_keywords == nullptr) - m_keywords = InitKeywords(); - for (const auto &e : *m_keywords) { - if (e.getValue() == t) - return e.getKey(); - } - return ""; -} - -llvm::StringMap<GoLexer::TokenType> *GoLexer::InitKeywords() { - auto &result = *new llvm::StringMap<TokenType>(128); - result["break"] = KEYWORD_BREAK; - result["default"] = KEYWORD_DEFAULT; - result["func"] = KEYWORD_FUNC; - result["interface"] = KEYWORD_INTERFACE; - result["select"] = KEYWORD_SELECT; - result["case"] = KEYWORD_CASE; - result["defer"] = KEYWORD_DEFER; - result["go"] = KEYWORD_GO; - result["map"] = KEYWORD_MAP; - result["struct"] = KEYWORD_STRUCT; - result["chan"] = KEYWORD_CHAN; - result["else"] = KEYWORD_ELSE; - result["goto"] = KEYWORD_GOTO; - result["package"] = KEYWORD_PACKAGE; - result["switch"] = KEYWORD_SWITCH; - result["const"] = KEYWORD_CONST; - result["fallthrough"] = KEYWORD_FALLTHROUGH; - result["if"] = KEYWORD_IF; - result["range"] = KEYWORD_RANGE; - result["type"] = KEYWORD_TYPE; - result["continue"] = KEYWORD_CONTINUE; - result["for"] = KEYWORD_FOR; - result["import"] = KEYWORD_IMPORT; - result["return"] = KEYWORD_RETURN; - result["var"] = KEYWORD_VAR; - result["+"] = OP_PLUS; - result["-"] = OP_MINUS; - result["*"] = OP_STAR; - result["/"] = OP_SLASH; - result["%"] = OP_PERCENT; - result["&"] = OP_AMP; - result["|"] = OP_PIPE; - result["^"] = OP_CARET; - result["<<"] = OP_LSHIFT; - result[">>"] = OP_RSHIFT; - result["&^"] = OP_AMP_CARET; - result["+="] = OP_PLUS_EQ; - result["-="] = OP_MINUS_EQ; - result["*="] = OP_STAR_EQ; - result["/="] = OP_SLASH_EQ; - result["%="] = OP_PERCENT_EQ; - result["&="] = OP_AMP_EQ; - result["|="] = OP_PIPE_EQ; - result["^="] = OP_CARET_EQ; - result["<<="] = OP_LSHIFT_EQ; - result[">>="] = OP_RSHIFT_EQ; - result["&^="] = OP_AMP_CARET_EQ; - result["&&"] = OP_AMP_AMP; - result["||"] = OP_PIPE_PIPE; - result["<-"] = OP_LT_MINUS; - result["++"] = OP_PLUS_PLUS; - result["--"] = OP_MINUS_MINUS; - result["=="] = OP_EQ_EQ; - result["<"] = OP_LT; - result[">"] = OP_GT; - result["="] = OP_EQ; - result["!"] = OP_BANG; - result["!="] = OP_BANG_EQ; - result["<="] = OP_LT_EQ; - result[">="] = OP_GT_EQ; - result[":="] = OP_COLON_EQ; - result["..."] = OP_DOTS; - result["("] = OP_LPAREN; - result["["] = OP_LBRACK; - result["{"] = OP_LBRACE; - result[","] = OP_COMMA; - result["."] = OP_DOT; - result[")"] = OP_RPAREN; - result["]"] = OP_RBRACK; - result["}"] = OP_RBRACE; - result[";"] = OP_SEMICOLON; - result[":"] = OP_COLON; - return &result; -} diff --git a/source/Plugins/ExpressionParser/Go/GoLexer.h b/source/Plugins/ExpressionParser/Go/GoLexer.h deleted file mode 100644 index f0b5b336fbe9..000000000000 --- a/source/Plugins/ExpressionParser/Go/GoLexer.h +++ /dev/null @@ -1,181 +0,0 @@ -//===-- GoLexer.h -----------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_GoLexer_h -#define liblldb_GoLexer_h - -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" - -namespace lldb_private { - -class GoLexer { -public: - explicit GoLexer(const char *src); - - enum TokenType { - TOK_EOF, - TOK_INVALID, - TOK_IDENTIFIER, - LIT_INTEGER, - LIT_FLOAT, - LIT_IMAGINARY, - LIT_RUNE, - LIT_STRING, - KEYWORD_BREAK, - KEYWORD_DEFAULT, - KEYWORD_FUNC, - KEYWORD_INTERFACE, - KEYWORD_SELECT, - KEYWORD_CASE, - KEYWORD_DEFER, - KEYWORD_GO, - KEYWORD_MAP, - KEYWORD_STRUCT, - KEYWORD_CHAN, - KEYWORD_ELSE, - KEYWORD_GOTO, - KEYWORD_PACKAGE, - KEYWORD_SWITCH, - KEYWORD_CONST, - KEYWORD_FALLTHROUGH, - KEYWORD_IF, - KEYWORD_RANGE, - KEYWORD_TYPE, - KEYWORD_CONTINUE, - KEYWORD_FOR, - KEYWORD_IMPORT, - KEYWORD_RETURN, - KEYWORD_VAR, - OP_PLUS, - OP_MINUS, - OP_STAR, - OP_SLASH, - OP_PERCENT, - OP_AMP, - OP_PIPE, - OP_CARET, - OP_LSHIFT, - OP_RSHIFT, - OP_AMP_CARET, - OP_PLUS_EQ, - OP_MINUS_EQ, - OP_STAR_EQ, - OP_SLASH_EQ, - OP_PERCENT_EQ, - OP_AMP_EQ, - OP_PIPE_EQ, - OP_CARET_EQ, - OP_LSHIFT_EQ, - OP_RSHIFT_EQ, - OP_AMP_CARET_EQ, - OP_AMP_AMP, - OP_PIPE_PIPE, - OP_LT_MINUS, - OP_PLUS_PLUS, - OP_MINUS_MINUS, - OP_EQ_EQ, - OP_LT, - OP_GT, - OP_EQ, - OP_BANG, - OP_BANG_EQ, - OP_LT_EQ, - OP_GT_EQ, - OP_COLON_EQ, - OP_DOTS, - OP_LPAREN, - OP_LBRACK, - OP_LBRACE, - OP_COMMA, - OP_DOT, - OP_RPAREN, - OP_RBRACK, - OP_RBRACE, - OP_SEMICOLON, - OP_COLON, - }; - - struct Token { - explicit Token(TokenType t, llvm::StringRef text) - : m_type(t), m_value(text) {} - TokenType m_type; - llvm::StringRef m_value; - }; - - const Token &Lex(); - - size_t BytesRemaining() const { return m_end - m_src; } - llvm::StringRef GetString(int len) const { - return llvm::StringRef(m_src, len); - } - - static TokenType LookupKeyword(llvm::StringRef id); - static llvm::StringRef LookupToken(TokenType t); - -private: - bool IsDecimal(char c) { return c >= '0' && c <= '9'; } - bool IsHexChar(char c) { - if (c >= '0' && c <= '9') - return true; - if (c >= 'A' && c <= 'F') - return true; - if (c >= 'a' && c <= 'f') - return true; - return false; - } - bool IsLetterOrDigit(char c) { - if (c >= 'a' && c <= 'z') - return true; - if (c >= 'A' && c <= 'Z') - return true; - if (c == '_') - return true; - if (c >= '0' && c <= '9') - return true; - // Treat all non-ascii chars as letters for simplicity. - return 0 != (c & 0x80); - } - bool IsWhitespace(char c) { - switch (c) { - case ' ': - case '\t': - case '\r': - return true; - } - return false; - } - - bool SkipWhitespace(); - bool SkipComment(); - - TokenType InternalLex(bool newline); - - TokenType DoOperator(); - - TokenType DoIdent(); - - TokenType DoNumber(); - - TokenType DoRune(); - - TokenType DoString(); - - static llvm::StringMap<TokenType> *InitKeywords(); - - static llvm::StringMap<TokenType> *m_keywords; - - const char *m_src; - const char *m_end; - Token m_last_token; -}; - -} // namespace lldb_private - -#endif diff --git a/source/Plugins/ExpressionParser/Go/GoParser.cpp b/source/Plugins/ExpressionParser/Go/GoParser.cpp deleted file mode 100644 index 9c845d02bca0..000000000000 --- a/source/Plugins/ExpressionParser/Go/GoParser.cpp +++ /dev/null @@ -1,886 +0,0 @@ -//===-- GoParser.cpp ---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <vector> - -#include "GoParser.h" - -#include "Plugins/ExpressionParser/Go/GoAST.h" -#include "lldb/Utility/Status.h" -#include "llvm/ADT/SmallString.h" - -using namespace lldb_private; -using namespace lldb; - -namespace { -llvm::StringRef DescribeToken(GoLexer::TokenType t) { - switch (t) { - case GoLexer::TOK_EOF: - return "<eof>"; - case GoLexer::TOK_IDENTIFIER: - return "identifier"; - case GoLexer::LIT_FLOAT: - return "float"; - case GoLexer::LIT_IMAGINARY: - return "imaginary"; - case GoLexer::LIT_INTEGER: - return "integer"; - case GoLexer::LIT_RUNE: - return "rune"; - case GoLexer::LIT_STRING: - return "string"; - default: - return GoLexer::LookupToken(t); - } -} -} // namespace - -class GoParser::Rule { -public: - Rule(llvm::StringRef name, GoParser *p) - : m_name(name), m_parser(p), m_pos(p->m_pos) {} - - std::nullptr_t error() { - if (!m_parser->m_failed) { - // Set m_error in case this is the top level. - if (m_parser->m_last_tok == GoLexer::TOK_INVALID) - m_parser->m_error = m_parser->m_last; - else - m_parser->m_error = DescribeToken(m_parser->m_last_tok); - // And set m_last in case it isn't. - m_parser->m_last = m_name; - m_parser->m_last_tok = GoLexer::TOK_INVALID; - m_parser->m_pos = m_pos; - } - return nullptr; - } - -private: - llvm::StringRef m_name; - GoParser *m_parser; - size_t m_pos; -}; - -GoParser::GoParser(const char *src) - : m_lexer(src), m_pos(0), m_last_tok(GoLexer::TOK_INVALID), - m_failed(false) {} - -GoASTStmt *GoParser::Statement() { - Rule r("Statement", this); - GoLexer::TokenType t = peek(); - GoASTStmt *ret = nullptr; - switch (t) { - case GoLexer::TOK_EOF: - case GoLexer::OP_SEMICOLON: - case GoLexer::OP_RPAREN: - case GoLexer::OP_RBRACE: - case GoLexer::TOK_INVALID: - return EmptyStmt(); - case GoLexer::OP_LBRACE: - return Block(); - - /* TODO: -case GoLexer::KEYWORD_GO: - return GoStmt(); -case GoLexer::KEYWORD_RETURN: - return ReturnStmt(); -case GoLexer::KEYWORD_BREAK: -case GoLexer::KEYWORD_CONTINUE: -case GoLexer::KEYWORD_GOTO: -case GoLexer::KEYWORD_FALLTHROUGH: - return BranchStmt(); -case GoLexer::KEYWORD_IF: - return IfStmt(); -case GoLexer::KEYWORD_SWITCH: - return SwitchStmt(); -case GoLexer::KEYWORD_SELECT: - return SelectStmt(); -case GoLexer::KEYWORD_FOR: - return ForStmt(); -case GoLexer::KEYWORD_DEFER: - return DeferStmt(); -case GoLexer::KEYWORD_CONST: -case GoLexer::KEYWORD_TYPE: -case GoLexer::KEYWORD_VAR: - return DeclStmt(); -case GoLexer::TOK_IDENTIFIER: - if ((ret = LabeledStmt()) || - (ret = ShortVarDecl())) - { - return ret; - } -*/ - default: - break; - } - GoASTExpr *expr = Expression(); - if (expr == nullptr) - return r.error(); - if (/*(ret = SendStmt(expr)) ||*/ - (ret = IncDecStmt(expr)) || (ret = Assignment(expr)) || - (ret = ExpressionStmt(expr))) { - return ret; - } - delete expr; - return r.error(); -} - -GoASTStmt *GoParser::ExpressionStmt(GoASTExpr *e) { - if (Semicolon()) - return new GoASTExprStmt(e); - return nullptr; -} - -GoASTStmt *GoParser::IncDecStmt(GoASTExpr *e) { - Rule r("IncDecStmt", this); - if (match(GoLexer::OP_PLUS_PLUS)) - return Semicolon() ? new GoASTIncDecStmt(e, GoLexer::OP_PLUS_PLUS) - : r.error(); - if (match(GoLexer::OP_MINUS_MINUS)) - return Semicolon() ? new GoASTIncDecStmt(e, GoLexer::OP_MINUS_MINUS) - : r.error(); - return nullptr; -} - -GoASTStmt *GoParser::Assignment(lldb_private::GoASTExpr *e) { - Rule r("Assignment", this); - std::vector<std::unique_ptr<GoASTExpr>> lhs; - for (GoASTExpr *l = MoreExpressionList(); l; l = MoreExpressionList()) - lhs.push_back(std::unique_ptr<GoASTExpr>(l)); - switch (peek()) { - case GoLexer::OP_EQ: - case GoLexer::OP_PLUS_EQ: - case GoLexer::OP_MINUS_EQ: - case GoLexer::OP_PIPE_EQ: - case GoLexer::OP_CARET_EQ: - case GoLexer::OP_STAR_EQ: - case GoLexer::OP_SLASH_EQ: - case GoLexer::OP_PERCENT_EQ: - case GoLexer::OP_LSHIFT_EQ: - case GoLexer::OP_RSHIFT_EQ: - case GoLexer::OP_AMP_EQ: - case GoLexer::OP_AMP_CARET_EQ: - break; - default: - return r.error(); - } - // We don't want to own e until we know this is an assignment. - std::unique_ptr<GoASTAssignStmt> stmt(new GoASTAssignStmt(false)); - stmt->AddLhs(e); - for (auto &l : lhs) - stmt->AddLhs(l.release()); - for (GoASTExpr *r = Expression(); r; r = MoreExpressionList()) - stmt->AddRhs(r); - if (!Semicolon() || stmt->NumRhs() == 0) - return new GoASTBadStmt; - return stmt.release(); -} - -GoASTStmt *GoParser::EmptyStmt() { - if (match(GoLexer::TOK_EOF)) - return nullptr; - if (Semicolon()) - return new GoASTEmptyStmt; - return nullptr; -} - -GoASTStmt *GoParser::GoStmt() { - if (match(GoLexer::KEYWORD_GO)) { - if (GoASTCallExpr *e = - llvm::dyn_cast_or_null<GoASTCallExpr>(Expression())) { - return FinishStmt(new GoASTGoStmt(e)); - } - m_last = "call expression"; - m_failed = true; - return new GoASTBadStmt(); - } - return nullptr; -} - -GoASTStmt *GoParser::ReturnStmt() { - if (match(GoLexer::KEYWORD_RETURN)) { - std::unique_ptr<GoASTReturnStmt> r(new GoASTReturnStmt()); - for (GoASTExpr *e = Expression(); e; e = MoreExpressionList()) - r->AddResults(e); - return FinishStmt(r.release()); - } - return nullptr; -} - -GoASTStmt *GoParser::BranchStmt() { - GoLexer::Token *tok; - if ((tok = match(GoLexer::KEYWORD_BREAK)) || - (tok = match(GoLexer::KEYWORD_CONTINUE)) || - (tok = match(GoLexer::KEYWORD_GOTO))) { - auto *e = Identifier(); - if (tok->m_type == GoLexer::KEYWORD_GOTO && !e) - return syntaxerror(); - return FinishStmt(new GoASTBranchStmt(e, tok->m_type)); - } - if ((tok = match(GoLexer::KEYWORD_FALLTHROUGH))) - return FinishStmt(new GoASTBranchStmt(nullptr, tok->m_type)); - - return nullptr; -} - -GoASTIdent *GoParser::Identifier() { - if (auto *tok = match(GoLexer::TOK_IDENTIFIER)) - return new GoASTIdent(*tok); - return nullptr; -} - -GoASTExpr *GoParser::MoreExpressionList() { - if (match(GoLexer::OP_COMMA)) { - auto *e = Expression(); - if (!e) - return syntaxerror(); - return e; - } - return nullptr; -} - -GoASTIdent *GoParser::MoreIdentifierList() { - if (match(GoLexer::OP_COMMA)) { - auto *i = Identifier(); - if (!i) - return syntaxerror(); - return i; - } - return nullptr; -} - -GoASTExpr *GoParser::Expression() { - Rule r("Expression", this); - if (GoASTExpr *ret = OrExpr()) - return ret; - return r.error(); -} - -GoASTExpr *GoParser::UnaryExpr() { - switch (peek()) { - case GoLexer::OP_PLUS: - case GoLexer::OP_MINUS: - case GoLexer::OP_BANG: - case GoLexer::OP_CARET: - case GoLexer::OP_STAR: - case GoLexer::OP_AMP: - case GoLexer::OP_LT_MINUS: { - const GoLexer::Token t = next(); - if (GoASTExpr *e = UnaryExpr()) { - if (t.m_type == GoLexer::OP_STAR) - return new GoASTStarExpr(e); - else - return new GoASTUnaryExpr(t.m_type, e); - } - return syntaxerror(); - } - default: - return PrimaryExpr(); - } -} - -GoASTExpr *GoParser::OrExpr() { - std::unique_ptr<GoASTExpr> l(AndExpr()); - if (l) { - while (match(GoLexer::OP_PIPE_PIPE)) { - GoASTExpr *r = AndExpr(); - if (r) - l.reset(new GoASTBinaryExpr(l.release(), r, GoLexer::OP_PIPE_PIPE)); - else - return syntaxerror(); - } - return l.release(); - } - return nullptr; -} - -GoASTExpr *GoParser::AndExpr() { - std::unique_ptr<GoASTExpr> l(RelExpr()); - if (l) { - while (match(GoLexer::OP_AMP_AMP)) { - GoASTExpr *r = RelExpr(); - if (r) - l.reset(new GoASTBinaryExpr(l.release(), r, GoLexer::OP_AMP_AMP)); - else - return syntaxerror(); - } - return l.release(); - } - return nullptr; -} - -GoASTExpr *GoParser::RelExpr() { - std::unique_ptr<GoASTExpr> l(AddExpr()); - if (l) { - for (GoLexer::Token *t; - (t = match(GoLexer::OP_EQ_EQ)) || (t = match(GoLexer::OP_BANG_EQ)) || - (t = match(GoLexer::OP_LT)) || (t = match(GoLexer::OP_LT_EQ)) || - (t = match(GoLexer::OP_GT)) || (t = match(GoLexer::OP_GT_EQ));) { - GoLexer::TokenType op = t->m_type; - GoASTExpr *r = AddExpr(); - if (r) - l.reset(new GoASTBinaryExpr(l.release(), r, op)); - else - return syntaxerror(); - } - return l.release(); - } - return nullptr; -} - -GoASTExpr *GoParser::AddExpr() { - std::unique_ptr<GoASTExpr> l(MulExpr()); - if (l) { - for (GoLexer::Token *t; - (t = match(GoLexer::OP_PLUS)) || (t = match(GoLexer::OP_MINUS)) || - (t = match(GoLexer::OP_PIPE)) || (t = match(GoLexer::OP_CARET));) { - GoLexer::TokenType op = t->m_type; - GoASTExpr *r = MulExpr(); - if (r) - l.reset(new GoASTBinaryExpr(l.release(), r, op)); - else - return syntaxerror(); - } - return l.release(); - } - return nullptr; -} - -GoASTExpr *GoParser::MulExpr() { - std::unique_ptr<GoASTExpr> l(UnaryExpr()); - if (l) { - for (GoLexer::Token *t; - (t = match(GoLexer::OP_STAR)) || (t = match(GoLexer::OP_SLASH)) || - (t = match(GoLexer::OP_PERCENT)) || (t = match(GoLexer::OP_LSHIFT)) || - (t = match(GoLexer::OP_RSHIFT)) || (t = match(GoLexer::OP_AMP)) || - (t = match(GoLexer::OP_AMP_CARET));) { - GoLexer::TokenType op = t->m_type; - GoASTExpr *r = UnaryExpr(); - if (r) - l.reset(new GoASTBinaryExpr(l.release(), r, op)); - else - return syntaxerror(); - } - return l.release(); - } - return nullptr; -} - -GoASTExpr *GoParser::PrimaryExpr() { - GoASTExpr *l; - GoASTExpr *r; - (l = Conversion()) || (l = Operand()); - if (!l) - return nullptr; - while ((r = Selector(l)) || (r = IndexOrSlice(l)) || (r = TypeAssertion(l)) || - (r = Arguments(l))) { - l = r; - } - return l; -} - -GoASTExpr *GoParser::Operand() { - GoLexer::Token *lit; - if ((lit = match(GoLexer::LIT_INTEGER)) || - (lit = match(GoLexer::LIT_FLOAT)) || - (lit = match(GoLexer::LIT_IMAGINARY)) || - (lit = match(GoLexer::LIT_RUNE)) || (lit = match(GoLexer::LIT_STRING))) - return new GoASTBasicLit(*lit); - if (match(GoLexer::OP_LPAREN)) { - GoASTExpr *e; - if (!((e = Expression()) && match(GoLexer::OP_RPAREN))) - return syntaxerror(); - return e; - } - // MethodExpr should be handled by Selector - if (GoASTExpr *e = CompositeLit()) - return e; - if (GoASTExpr *n = Name()) - return n; - return FunctionLit(); -} - -GoASTExpr *GoParser::FunctionLit() { - if (!match(GoLexer::KEYWORD_FUNC)) - return nullptr; - auto *sig = Signature(); - if (!sig) - return syntaxerror(); - auto *body = Block(); - if (!body) { - delete sig; - return syntaxerror(); - } - return new GoASTFuncLit(sig, body); -} - -GoASTBlockStmt *GoParser::Block() { - if (!match(GoLexer::OP_LBRACE)) - return nullptr; - std::unique_ptr<GoASTBlockStmt> block(new GoASTBlockStmt); - for (auto *s = Statement(); s; s = Statement()) - block->AddList(s); - if (!match(GoLexer::OP_RBRACE)) - return syntaxerror(); - return block.release(); -} - -GoASTExpr *GoParser::CompositeLit() { - Rule r("CompositeLit", this); - GoASTExpr *type; - (type = StructType()) || (type = ArrayOrSliceType(true)) || - (type = MapType()) || (type = Name()); - if (!type) - return r.error(); - GoASTCompositeLit *lit = LiteralValue(); - if (!lit) { - delete type; - return r.error(); - } - lit->SetType(type); - return lit; -} - -GoASTCompositeLit *GoParser::LiteralValue() { - if (!match(GoLexer::OP_LBRACE)) - return nullptr; - std::unique_ptr<GoASTCompositeLit> lit(new GoASTCompositeLit); - for (GoASTExpr *e = Element(); e; e = Element()) { - lit->AddElts(e); - if (!match(GoLexer::OP_COMMA)) - break; - } - if (!mustMatch(GoLexer::OP_RBRACE)) - return nullptr; - return lit.release(); -} - -GoASTExpr *GoParser::Element() { - GoASTExpr *key; - if (!((key = Expression()) || (key = LiteralValue()))) - return nullptr; - if (!match(GoLexer::OP_COLON)) - return key; - GoASTExpr *value; - if ((value = Expression()) || (value = LiteralValue())) - return new GoASTKeyValueExpr(key, value); - delete key; - return syntaxerror(); -} - -GoASTExpr *GoParser::Selector(GoASTExpr *e) { - Rule r("Selector", this); - if (match(GoLexer::OP_DOT)) { - if (auto *name = Identifier()) - return new GoASTSelectorExpr(e, name); - } - return r.error(); -} - -GoASTExpr *GoParser::IndexOrSlice(GoASTExpr *e) { - Rule r("IndexOrSlice", this); - if (match(GoLexer::OP_LBRACK)) { - std::unique_ptr<GoASTExpr> i1(Expression()), i2, i3; - bool slice = false; - if (match(GoLexer::OP_COLON)) { - slice = true; - i2.reset(Expression()); - if (i2 && match(GoLexer::OP_COLON)) { - i3.reset(Expression()); - if (!i3) - return syntaxerror(); - } - } - if (!(slice || i1)) - return syntaxerror(); - if (!mustMatch(GoLexer::OP_RBRACK)) - return nullptr; - if (slice) { - bool slice3 = i3.get(); - return new GoASTSliceExpr(e, i1.release(), i2.release(), i3.release(), - slice3); - } - return new GoASTIndexExpr(e, i1.release()); - } - return r.error(); -} - -GoASTExpr *GoParser::TypeAssertion(GoASTExpr *e) { - Rule r("TypeAssertion", this); - if (match(GoLexer::OP_DOT) && match(GoLexer::OP_LPAREN)) { - if (auto *t = Type()) { - if (!mustMatch(GoLexer::OP_RPAREN)) - return nullptr; - return new GoASTTypeAssertExpr(e, t); - } - return syntaxerror(); - } - return r.error(); -} - -GoASTExpr *GoParser::Arguments(GoASTExpr *e) { - if (match(GoLexer::OP_LPAREN)) { - std::unique_ptr<GoASTCallExpr> call(new GoASTCallExpr(false)); - GoASTExpr *arg; - // ( ExpressionList | Type [ "," ExpressionList ] ) - for ((arg = Expression()) || (arg = Type()); arg; - arg = MoreExpressionList()) { - call->AddArgs(arg); - } - if (match(GoLexer::OP_DOTS)) - call->SetEllipsis(true); - - // Eat trailing comma - match(GoLexer::OP_COMMA); - - if (!mustMatch(GoLexer::OP_RPAREN)) - return nullptr; - call->SetFun(e); - return call.release(); - } - return nullptr; -} - -GoASTExpr *GoParser::Conversion() { - Rule r("Conversion", this); - if (GoASTExpr *t = Type2()) { - std::unique_ptr<GoASTExpr> owner(t); - if (match(GoLexer::OP_LPAREN)) { - GoASTExpr *v = Expression(); - if (!v) - return syntaxerror(); - match(GoLexer::OP_COMMA); - if (!mustMatch(GoLexer::OP_RPAREN)) - return r.error(); - GoASTCallExpr *call = new GoASTCallExpr(false); - call->SetFun(t); - owner.release(); - call->AddArgs(v); - return call; - } - } - return r.error(); -} - -GoASTExpr *GoParser::Type2() { - switch (peek()) { - case GoLexer::OP_LBRACK: - return ArrayOrSliceType(false); - case GoLexer::KEYWORD_STRUCT: - return StructType(); - case GoLexer::KEYWORD_FUNC: - return FunctionType(); - case GoLexer::KEYWORD_INTERFACE: - return InterfaceType(); - case GoLexer::KEYWORD_MAP: - return MapType(); - case GoLexer::KEYWORD_CHAN: - return ChanType2(); - default: - return nullptr; - } -} - -GoASTExpr *GoParser::ArrayOrSliceType(bool allowEllipsis) { - Rule r("ArrayType", this); - if (match(GoLexer::OP_LBRACK)) { - std::unique_ptr<GoASTExpr> len; - if (allowEllipsis && match(GoLexer::OP_DOTS)) { - len.reset(new GoASTEllipsis(nullptr)); - } else { - len.reset(Expression()); - } - - if (!match(GoLexer::OP_RBRACK)) - return r.error(); - GoASTExpr *elem = Type(); - if (!elem) - return syntaxerror(); - return new GoASTArrayType(len.release(), elem); - } - return r.error(); -} - -GoASTExpr *GoParser::StructType() { - if (!(match(GoLexer::KEYWORD_STRUCT) && mustMatch(GoLexer::OP_LBRACE))) - return nullptr; - std::unique_ptr<GoASTFieldList> fields(new GoASTFieldList); - while (auto *field = FieldDecl()) - fields->AddList(field); - if (!mustMatch(GoLexer::OP_RBRACE)) - return nullptr; - return new GoASTStructType(fields.release()); -} - -GoASTField *GoParser::FieldDecl() { - std::unique_ptr<GoASTField> f(new GoASTField); - GoASTExpr *t = FieldNamesAndType(f.get()); - if (!t) - t = AnonymousFieldType(); - if (!t) - return nullptr; - - if (auto *tok = match(GoLexer::LIT_STRING)) - f->SetTag(new GoASTBasicLit(*tok)); - if (!Semicolon()) - return syntaxerror(); - return f.release(); -} - -GoASTExpr *GoParser::FieldNamesAndType(GoASTField *field) { - Rule r("FieldNames", this); - for (auto *id = Identifier(); id; id = MoreIdentifierList()) - field->AddNames(id); - if (m_failed) - return nullptr; - GoASTExpr *t = Type(); - if (t) - return t; - return r.error(); -} - -GoASTExpr *GoParser::AnonymousFieldType() { - bool pointer = match(GoLexer::OP_STAR); - GoASTExpr *t = Type(); - if (!t) - return nullptr; - if (pointer) - return new GoASTStarExpr(t); - return t; -} - -GoASTExpr *GoParser::FunctionType() { - if (!match(GoLexer::KEYWORD_FUNC)) - return nullptr; - return Signature(); -} - -GoASTFuncType *GoParser::Signature() { - auto *params = Params(); - if (!params) - return syntaxerror(); - auto *result = Params(); - if (!result) { - if (auto *t = Type()) { - result = new GoASTFieldList; - auto *f = new GoASTField; - f->SetType(t); - result->AddList(f); - } - } - return new GoASTFuncType(params, result); -} - -GoASTFieldList *GoParser::Params() { - if (!match(GoLexer::OP_LPAREN)) - return nullptr; - std::unique_ptr<GoASTFieldList> l(new GoASTFieldList); - while (GoASTField *p = ParamDecl()) { - l->AddList(p); - if (!match(GoLexer::OP_COMMA)) - break; - } - if (!mustMatch(GoLexer::OP_RPAREN)) - return nullptr; - return l.release(); -} - -GoASTField *GoParser::ParamDecl() { - std::unique_ptr<GoASTField> field(new GoASTField); - GoASTIdent *id = Identifier(); - if (id) { - // Try `IdentifierList [ "..." ] Type`. - // If that fails, backtrack and try `[ "..." ] Type`. - Rule r("NamedParam", this); - for (; id; id = MoreIdentifierList()) - field->AddNames(id); - GoASTExpr *t = ParamType(); - if (t) { - field->SetType(t); - return field.release(); - } - field.reset(new GoASTField); - r.error(); - } - GoASTExpr *t = ParamType(); - if (t) { - field->SetType(t); - return field.release(); - } - return nullptr; -} - -GoASTExpr *GoParser::ParamType() { - bool dots = match(GoLexer::OP_DOTS); - GoASTExpr *t = Type(); - if (!dots) - return t; - if (!t) - return syntaxerror(); - return new GoASTEllipsis(t); -} - -GoASTExpr *GoParser::InterfaceType() { - if (!match(GoLexer::KEYWORD_INTERFACE) || !mustMatch(GoLexer::OP_LBRACE)) - return nullptr; - std::unique_ptr<GoASTFieldList> methods(new GoASTFieldList); - while (true) { - Rule r("MethodSpec", this); - // ( identifier Signature | TypeName ) ; - std::unique_ptr<GoASTIdent> id(Identifier()); - if (!id) - break; - GoASTExpr *type = Signature(); - if (!type) { - r.error(); - id.reset(); - type = Name(); - } - if (!Semicolon()) - return syntaxerror(); - auto *f = new GoASTField; - if (id) - f->AddNames(id.release()); - f->SetType(type); - methods->AddList(f); - } - if (!mustMatch(GoLexer::OP_RBRACE)) - return nullptr; - return new GoASTInterfaceType(methods.release()); -} - -GoASTExpr *GoParser::MapType() { - if (!(match(GoLexer::KEYWORD_MAP) && mustMatch(GoLexer::OP_LBRACK))) - return nullptr; - std::unique_ptr<GoASTExpr> key(Type()); - if (!key) - return syntaxerror(); - if (!mustMatch(GoLexer::OP_RBRACK)) - return nullptr; - auto *elem = Type(); - if (!elem) - return syntaxerror(); - return new GoASTMapType(key.release(), elem); -} - -GoASTExpr *GoParser::ChanType() { - Rule r("chan", this); - if (match(GoLexer::OP_LT_MINUS)) { - if (match(GoLexer::KEYWORD_CHAN)) { - auto *elem = Type(); - if (!elem) - return syntaxerror(); - return new GoASTChanType(GoASTNode::eChanRecv, elem); - } - return r.error(); - } - return ChanType2(); -} - -GoASTExpr *GoParser::ChanType2() { - if (!match(GoLexer::KEYWORD_CHAN)) - return nullptr; - auto dir = GoASTNode::eChanBidir; - if (match(GoLexer::OP_LT_MINUS)) - dir = GoASTNode::eChanSend; - auto *elem = Type(); - if (!elem) - return syntaxerror(); - return new GoASTChanType(dir, elem); -} - -GoASTExpr *GoParser::Type() { - if (GoASTExpr *t = Type2()) - return t; - if (GoASTExpr *t = Name()) - return t; - if (GoASTExpr *t = ChanType()) - return t; - if (match(GoLexer::OP_STAR)) { - GoASTExpr *t = Type(); - if (!t) - return syntaxerror(); - return new GoASTStarExpr(t); - } - if (match(GoLexer::OP_LPAREN)) { - std::unique_ptr<GoASTExpr> t(Type()); - if (!t || !match(GoLexer::OP_RPAREN)) - return syntaxerror(); - return t.release(); - } - return nullptr; -} - -bool GoParser::Semicolon() { - if (match(GoLexer::OP_SEMICOLON)) - return true; - switch (peek()) { - case GoLexer::OP_RPAREN: - case GoLexer::OP_RBRACE: - case GoLexer::TOK_EOF: - return true; - default: - return false; - } -} - -GoASTExpr *GoParser::Name() { - if (auto *id = Identifier()) { - if (GoASTExpr *qual = QualifiedIdent(id)) - return qual; - return id; - } - return nullptr; -} - -GoASTExpr *GoParser::QualifiedIdent(lldb_private::GoASTIdent *p) { - Rule r("QualifiedIdent", this); - llvm::SmallString<32> path(p->GetName().m_value); - GoLexer::Token *next; - bool have_slashes = false; - // LLDB extension: support full/package/path.name - while (match(GoLexer::OP_SLASH) && (next = match(GoLexer::TOK_IDENTIFIER))) { - have_slashes = true; - path.append("/"); - path.append(next->m_value); - } - if (match(GoLexer::OP_DOT)) { - auto *name = Identifier(); - if (name) { - if (have_slashes) { - p->SetName(GoLexer::Token(GoLexer::TOK_IDENTIFIER, CopyString(path))); - } - return new GoASTSelectorExpr(p, name); - } - } - return r.error(); -} - -llvm::StringRef GoParser::CopyString(llvm::StringRef s) { - return m_strings.insert(std::make_pair(s, 'x')).first->getKey(); -} - -void GoParser::GetError(Status &error) { - llvm::StringRef want; - if (m_failed) - want = - m_last_tok == GoLexer::TOK_INVALID ? DescribeToken(m_last_tok) : m_last; - else - want = m_error; - size_t len = m_lexer.BytesRemaining(); - if (len > 10) - len = 10; - llvm::StringRef got; - if (len == 0) - got = "<eof>"; - else - got = m_lexer.GetString(len); - error.SetErrorStringWithFormat("Syntax error: expected %s before '%s'.", - want.str().c_str(), got.str().c_str()); -} diff --git a/source/Plugins/ExpressionParser/Go/GoParser.h b/source/Plugins/ExpressionParser/Go/GoParser.h deleted file mode 100644 index 9ed2ae2033bd..000000000000 --- a/source/Plugins/ExpressionParser/Go/GoParser.h +++ /dev/null @@ -1,145 +0,0 @@ -//===-- GoParser.h -----------------------------------------------*- C++ -//-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_GoParser_h -#define liblldb_GoParser_h - -#include "Plugins/ExpressionParser/Go/GoAST.h" -#include "Plugins/ExpressionParser/Go/GoLexer.h" -#include "lldb/lldb-private.h" - -namespace lldb_private { -class GoParser { -public: - explicit GoParser(const char *src); - - GoASTStmt *Statement(); - - GoASTStmt *GoStmt(); - GoASTStmt *ReturnStmt(); - GoASTStmt *BranchStmt(); - GoASTStmt *EmptyStmt(); - GoASTStmt *ExpressionStmt(GoASTExpr *e); - GoASTStmt *IncDecStmt(GoASTExpr *e); - GoASTStmt *Assignment(GoASTExpr *e); - GoASTBlockStmt *Block(); - - GoASTExpr *MoreExpressionList(); // ["," Expression] - GoASTIdent *MoreIdentifierList(); // ["," Identifier] - - GoASTExpr *Expression(); - GoASTExpr *UnaryExpr(); - GoASTExpr *OrExpr(); - GoASTExpr *AndExpr(); - GoASTExpr *RelExpr(); - GoASTExpr *AddExpr(); - GoASTExpr *MulExpr(); - GoASTExpr *PrimaryExpr(); - GoASTExpr *Operand(); - GoASTExpr *Conversion(); - - GoASTExpr *Selector(GoASTExpr *e); - GoASTExpr *IndexOrSlice(GoASTExpr *e); - GoASTExpr *TypeAssertion(GoASTExpr *e); - GoASTExpr *Arguments(GoASTExpr *e); - - GoASTExpr *Type(); - GoASTExpr *Type2(); - GoASTExpr *ArrayOrSliceType(bool allowEllipsis); - GoASTExpr *StructType(); - GoASTExpr *FunctionType(); - GoASTExpr *InterfaceType(); - GoASTExpr *MapType(); - GoASTExpr *ChanType(); - GoASTExpr *ChanType2(); - - GoASTExpr *Name(); - GoASTExpr *QualifiedIdent(GoASTIdent *p); - GoASTIdent *Identifier(); - - GoASTField *FieldDecl(); - GoASTExpr *AnonymousFieldType(); - GoASTExpr *FieldNamesAndType(GoASTField *f); - - GoASTFieldList *Params(); - GoASTField *ParamDecl(); - GoASTExpr *ParamType(); - GoASTFuncType *Signature(); - GoASTExpr *CompositeLit(); - GoASTExpr *FunctionLit(); - GoASTExpr *Element(); - GoASTCompositeLit *LiteralValue(); - - bool Failed() const { return m_failed; } - bool AtEOF() const { - return m_lexer.BytesRemaining() == 0 && m_pos == m_tokens.size(); - } - - void GetError(Status &error); - -private: - class Rule; - friend class Rule; - - std::nullptr_t syntaxerror() { - m_failed = true; - return nullptr; - } - GoLexer::Token &next() { - if (m_pos >= m_tokens.size()) { - if (m_pos != 0 && (m_tokens.back().m_type == GoLexer::TOK_EOF || - m_tokens.back().m_type == GoLexer::TOK_INVALID)) - return m_tokens.back(); - m_pos = m_tokens.size(); - m_tokens.push_back(m_lexer.Lex()); - } - return m_tokens[m_pos++]; - } - GoLexer::TokenType peek() { - GoLexer::Token &tok = next(); - --m_pos; - return tok.m_type; - } - GoLexer::Token *match(GoLexer::TokenType t) { - GoLexer::Token &tok = next(); - if (tok.m_type == t) - return &tok; - --m_pos; - m_last_tok = t; - return nullptr; - } - GoLexer::Token *mustMatch(GoLexer::TokenType t) { - GoLexer::Token *tok = match(t); - if (tok) - return tok; - return syntaxerror(); - } - bool Semicolon(); - - GoASTStmt *FinishStmt(GoASTStmt *s) { - if (!Semicolon()) - m_failed = true; - return s; - } - - llvm::StringRef CopyString(llvm::StringRef s); - - GoLexer m_lexer; - std::vector<GoLexer::Token> m_tokens; - size_t m_pos; - llvm::StringRef m_error; - llvm::StringRef m_last; - GoLexer::TokenType m_last_tok; - llvm::StringMap<uint8_t> m_strings; - bool m_failed; -}; -} - -#endif diff --git a/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp b/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp deleted file mode 100644 index 3a10a1dc767a..000000000000 --- a/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp +++ /dev/null @@ -1,668 +0,0 @@ -//===-- GoUserExpression.cpp ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// C Includes -#include <stdio.h> -#if HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -// C++ Includes -#include <cstdlib> -#include <memory> -#include <string> -#include <vector> - -// Other libraries and framework includes -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" - -// Project includes -#include "GoUserExpression.h" - -#include "lldb/Core/Module.h" -#include "lldb/Core/StreamFile.h" -#include "lldb/Core/ValueObjectConstResult.h" -#include "lldb/Core/ValueObjectRegister.h" -#include "lldb/Expression/DiagnosticManager.h" -#include "lldb/Expression/ExpressionVariable.h" -#include "lldb/Symbol/GoASTContext.h" -#include "lldb/Symbol/SymbolFile.h" -#include "lldb/Symbol/TypeList.h" -#include "lldb/Symbol/VariableList.h" -#include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/StackFrame.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/ThreadPlan.h" -#include "lldb/Target/ThreadPlanCallUserExpression.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/DataEncoder.h" -#include "lldb/Utility/DataExtractor.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/StreamString.h" -#include "lldb/lldb-private.h" - -#include "Plugins/ExpressionParser/Go/GoAST.h" -#include "Plugins/ExpressionParser/Go/GoParser.h" - -using namespace lldb_private; -using namespace lldb; - -class GoUserExpression::GoInterpreter { -public: - GoInterpreter(ExecutionContext &exe_ctx, const char *expr) - : m_exe_ctx(exe_ctx), m_frame(exe_ctx.GetFrameSP()), m_parser(expr) { - if (m_frame) { - const SymbolContext &ctx = - m_frame->GetSymbolContext(eSymbolContextFunction); - ConstString fname = ctx.GetFunctionName(); - if (fname.GetLength() > 0) { - size_t dot = fname.GetStringRef().find('.'); - if (dot != llvm::StringRef::npos) - m_package = llvm::StringRef(fname.AsCString(), dot); - } - } - } - - void set_use_dynamic(DynamicValueType use_dynamic) { - m_use_dynamic = use_dynamic; - } - - bool Parse(); - lldb::ValueObjectSP Evaluate(ExecutionContext &exe_ctx); - lldb::ValueObjectSP EvaluateStatement(const GoASTStmt *s); - lldb::ValueObjectSP EvaluateExpr(const GoASTExpr *e); - - ValueObjectSP VisitBadExpr(const GoASTBadExpr *e) { - m_parser.GetError(m_error); - return nullptr; - } - - ValueObjectSP VisitParenExpr(const GoASTParenExpr *e); - ValueObjectSP VisitIdent(const GoASTIdent *e); - ValueObjectSP VisitStarExpr(const GoASTStarExpr *e); - ValueObjectSP VisitSelectorExpr(const GoASTSelectorExpr *e); - ValueObjectSP VisitBasicLit(const GoASTBasicLit *e); - ValueObjectSP VisitIndexExpr(const GoASTIndexExpr *e); - ValueObjectSP VisitUnaryExpr(const GoASTUnaryExpr *e); - ValueObjectSP VisitCallExpr(const GoASTCallExpr *e); - - ValueObjectSP VisitTypeAssertExpr(const GoASTTypeAssertExpr *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitBinaryExpr(const GoASTBinaryExpr *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitArrayType(const GoASTArrayType *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitChanType(const GoASTChanType *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitCompositeLit(const GoASTCompositeLit *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitEllipsis(const GoASTEllipsis *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitFuncType(const GoASTFuncType *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitFuncLit(const GoASTFuncLit *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitInterfaceType(const GoASTInterfaceType *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitKeyValueExpr(const GoASTKeyValueExpr *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitMapType(const GoASTMapType *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitSliceExpr(const GoASTSliceExpr *e) { - return NotImplemented(e); - } - - ValueObjectSP VisitStructType(const GoASTStructType *e) { - return NotImplemented(e); - } - - CompilerType EvaluateType(const GoASTExpr *e); - - Status &error() { return m_error; } - -private: - std::nullptr_t NotImplemented(const GoASTExpr *e) { - m_error.SetErrorStringWithFormat("%s node not implemented", - e->GetKindName()); - return nullptr; - } - - ExecutionContext m_exe_ctx; - lldb::StackFrameSP m_frame; - GoParser m_parser; - DynamicValueType m_use_dynamic; - Status m_error; - llvm::StringRef m_package; - std::vector<std::unique_ptr<GoASTStmt>> m_statements; -}; - -VariableSP FindGlobalVariable(TargetSP target, llvm::Twine name) { - ConstString fullname(name.str()); - VariableList variable_list; - if (!target) { - return nullptr; - } - const uint32_t match_count = - target->GetImages().FindGlobalVariables(fullname, 1, variable_list); - if (match_count == 1) { - return variable_list.GetVariableAtIndex(0); - } - return nullptr; -} - -CompilerType LookupType(TargetSP target, ConstString name) { - if (!target) - return CompilerType(); - SymbolContext sc; - TypeList type_list; - llvm::DenseSet<SymbolFile *> searched_symbol_files; - uint32_t num_matches = target->GetImages().FindTypes( - sc, name, false, 2, searched_symbol_files, type_list); - if (num_matches > 0) { - return type_list.GetTypeAtIndex(0)->GetFullCompilerType(); - } - return CompilerType(); -} - -GoUserExpression::GoUserExpression(ExecutionContextScope &exe_scope, - llvm::StringRef expr, llvm::StringRef prefix, - lldb::LanguageType language, - ResultType desired_type, - const EvaluateExpressionOptions &options) - : UserExpression(exe_scope, expr, prefix, language, desired_type, options) { -} - -bool GoUserExpression::Parse(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx, - lldb_private::ExecutionPolicy execution_policy, - bool keep_result_in_memory, - bool generate_debug_info) { - InstallContext(exe_ctx); - m_interpreter.reset(new GoInterpreter(exe_ctx, GetUserText())); - if (m_interpreter->Parse()) - return true; - const char *error_cstr = m_interpreter->error().AsCString(); - if (error_cstr && error_cstr[0]) - diagnostic_manager.PutString(eDiagnosticSeverityError, error_cstr); - else - diagnostic_manager.Printf(eDiagnosticSeverityError, - "expression can't be interpreted or run"); - return false; -} - -lldb::ExpressionResults -GoUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx, - const EvaluateExpressionOptions &options, - lldb::UserExpressionSP &shared_ptr_to_me, - lldb::ExpressionVariableSP &result) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS | - LIBLLDB_LOG_STEP)); - - lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); - lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; - - Process *process = exe_ctx.GetProcessPtr(); - Target *target = exe_ctx.GetTargetPtr(); - - if (target == nullptr || process == nullptr || - process->GetState() != lldb::eStateStopped) { - if (execution_policy == eExecutionPolicyAlways) { - if (log) - log->Printf("== [GoUserExpression::Evaluate] Expression may not run, " - "but is not constant =="); - - diagnostic_manager.PutString(eDiagnosticSeverityError, - "expression needed to run but couldn't"); - - return execution_results; - } - } - - m_interpreter->set_use_dynamic(options.GetUseDynamic()); - ValueObjectSP result_val_sp = m_interpreter->Evaluate(exe_ctx); - Status err = m_interpreter->error(); - m_interpreter.reset(); - - if (!result_val_sp) { - const char *error_cstr = err.AsCString(); - if (error_cstr && error_cstr[0]) - diagnostic_manager.PutString(eDiagnosticSeverityError, error_cstr); - else - diagnostic_manager.PutString(eDiagnosticSeverityError, - "expression can't be interpreted or run"); - return lldb::eExpressionDiscarded; - } - result.reset(new ExpressionVariable(ExpressionVariable::eKindGo)); - result->m_live_sp = result->m_frozen_sp = result_val_sp; - result->m_flags |= ExpressionVariable::EVIsProgramReference; - PersistentExpressionState *pv = - target->GetPersistentExpressionStateForLanguage(eLanguageTypeGo); - if (pv != nullptr) { - result->SetName(pv->GetNextPersistentVariableName( - *target, pv->GetPersistentVariablePrefix())); - pv->AddVariable(result); - } - return lldb::eExpressionCompleted; -} - -bool GoUserExpression::GoInterpreter::Parse() { - for (std::unique_ptr<GoASTStmt> stmt(m_parser.Statement()); stmt; - stmt.reset(m_parser.Statement())) { - if (m_parser.Failed()) - break; - m_statements.emplace_back(std::move(stmt)); - } - if (m_parser.Failed() || !m_parser.AtEOF()) - m_parser.GetError(m_error); - - return m_error.Success(); -} - -ValueObjectSP -GoUserExpression::GoInterpreter::Evaluate(ExecutionContext &exe_ctx) { - m_exe_ctx = exe_ctx; - ValueObjectSP result; - for (const std::unique_ptr<GoASTStmt> &stmt : m_statements) { - result = EvaluateStatement(stmt.get()); - if (m_error.Fail()) - return nullptr; - } - return result; -} - -ValueObjectSP GoUserExpression::GoInterpreter::EvaluateStatement( - const lldb_private::GoASTStmt *stmt) { - ValueObjectSP result; - switch (stmt->GetKind()) { - case GoASTNode::eBlockStmt: { - const GoASTBlockStmt *block = llvm::cast<GoASTBlockStmt>(stmt); - for (size_t i = 0; i < block->NumList(); ++i) - result = EvaluateStatement(block->GetList(i)); - break; - } - case GoASTNode::eBadStmt: - m_parser.GetError(m_error); - break; - case GoASTNode::eExprStmt: { - const GoASTExprStmt *expr = llvm::cast<GoASTExprStmt>(stmt); - return EvaluateExpr(expr->GetX()); - } - default: - m_error.SetErrorStringWithFormat("%s node not supported", - stmt->GetKindName()); - } - return result; -} - -ValueObjectSP GoUserExpression::GoInterpreter::EvaluateExpr( - const lldb_private::GoASTExpr *e) { - if (e) - return e->Visit<ValueObjectSP>(this); - return ValueObjectSP(); -} - -ValueObjectSP GoUserExpression::GoInterpreter::VisitParenExpr( - const lldb_private::GoASTParenExpr *e) { - return EvaluateExpr(e->GetX()); -} - -ValueObjectSP GoUserExpression::GoInterpreter::VisitIdent(const GoASTIdent *e) { - ValueObjectSP val; - if (m_frame) { - VariableSP var_sp; - std::string varname = e->GetName().m_value.str(); - if (varname.size() > 1 && varname[0] == '$') { - RegisterContextSP reg_ctx_sp = m_frame->GetRegisterContext(); - const RegisterInfo *reg = - reg_ctx_sp->GetRegisterInfoByName(varname.c_str() + 1); - if (reg) { - std::string type; - switch (reg->encoding) { - case lldb::eEncodingSint: - type.append("int"); - break; - case lldb::eEncodingUint: - type.append("uint"); - break; - case lldb::eEncodingIEEE754: - type.append("float"); - break; - default: - m_error.SetErrorString("Invalid register encoding"); - return nullptr; - } - switch (reg->byte_size) { - case 8: - type.append("64"); - break; - case 4: - type.append("32"); - break; - case 2: - type.append("16"); - break; - case 1: - type.append("8"); - break; - default: - m_error.SetErrorString("Invalid register size"); - return nullptr; - } - ValueObjectSP regVal = ValueObjectRegister::Create( - m_frame.get(), reg_ctx_sp, reg->kinds[eRegisterKindLLDB]); - CompilerType goType = - LookupType(m_frame->CalculateTarget(), ConstString(type)); - if (regVal) { - regVal = regVal->Cast(goType); - return regVal; - } - } - m_error.SetErrorString("Invalid register name"); - return nullptr; - } - VariableListSP var_list_sp(m_frame->GetInScopeVariableList(false)); - if (var_list_sp) { - var_sp = var_list_sp->FindVariable(ConstString(varname)); - if (var_sp) - val = m_frame->GetValueObjectForFrameVariable(var_sp, m_use_dynamic); - else { - // When a variable is on the heap instead of the stack, go records a - // variable '&x' instead of 'x'. - var_sp = var_list_sp->FindVariable(ConstString("&" + varname)); - if (var_sp) { - val = m_frame->GetValueObjectForFrameVariable(var_sp, m_use_dynamic); - if (val) - val = val->Dereference(m_error); - if (m_error.Fail()) - return nullptr; - } - } - } - if (!val) { - m_error.Clear(); - TargetSP target = m_frame->CalculateTarget(); - if (!target) { - m_error.SetErrorString("No target"); - return nullptr; - } - var_sp = - FindGlobalVariable(target, m_package + "." + e->GetName().m_value); - if (var_sp) - return m_frame->TrackGlobalVariable(var_sp, m_use_dynamic); - } - } - if (!val) - m_error.SetErrorStringWithFormat("Unknown variable %s", - e->GetName().m_value.str().c_str()); - return val; -} - -ValueObjectSP -GoUserExpression::GoInterpreter::VisitStarExpr(const GoASTStarExpr *e) { - ValueObjectSP target = EvaluateExpr(e->GetX()); - if (!target) - return nullptr; - return target->Dereference(m_error); -} - -ValueObjectSP GoUserExpression::GoInterpreter::VisitSelectorExpr( - const lldb_private::GoASTSelectorExpr *e) { - ValueObjectSP target = EvaluateExpr(e->GetX()); - if (target) { - if (target->GetCompilerType().IsPointerType()) { - target = target->Dereference(m_error); - if (m_error.Fail()) - return nullptr; - } - ConstString field(e->GetSel()->GetName().m_value); - ValueObjectSP result = target->GetChildMemberWithName(field, true); - if (!result) - m_error.SetErrorStringWithFormat("Unknown child %s", field.AsCString()); - return result; - } - if (const GoASTIdent *package = llvm::dyn_cast<GoASTIdent>(e->GetX())) { - if (VariableSP global = FindGlobalVariable( - m_exe_ctx.GetTargetSP(), package->GetName().m_value + "." + - e->GetSel()->GetName().m_value)) { - if (m_frame) { - m_error.Clear(); - return m_frame->GetValueObjectForFrameVariable(global, m_use_dynamic); - } - } - } - if (const GoASTBasicLit *packageLit = - llvm::dyn_cast<GoASTBasicLit>(e->GetX())) { - if (packageLit->GetValue().m_type == GoLexer::LIT_STRING) { - std::string value = packageLit->GetValue().m_value.str(); - value = value.substr(1, value.size() - 2); - if (VariableSP global = FindGlobalVariable( - m_exe_ctx.GetTargetSP(), - value + "." + e->GetSel()->GetName().m_value)) { - if (m_frame) { - m_error.Clear(); - return m_frame->TrackGlobalVariable(global, m_use_dynamic); - } - } - } - } - // EvaluateExpr should have already set m_error. - return target; -} - -ValueObjectSP GoUserExpression::GoInterpreter::VisitBasicLit( - const lldb_private::GoASTBasicLit *e) { - std::string value = e->GetValue().m_value.str(); - if (e->GetValue().m_type != GoLexer::LIT_INTEGER) { - m_error.SetErrorStringWithFormat("Unsupported literal %s", value.c_str()); - return nullptr; - } - errno = 0; - int64_t intvalue = strtol(value.c_str(), nullptr, 0); - if (errno != 0) { - m_error.SetErrorToErrno(); - return nullptr; - } - DataBufferSP buf(new DataBufferHeap(sizeof(intvalue), 0)); - TargetSP target = m_exe_ctx.GetTargetSP(); - if (!target) { - m_error.SetErrorString("No target"); - return nullptr; - } - ByteOrder order = target->GetArchitecture().GetByteOrder(); - uint8_t addr_size = target->GetArchitecture().GetAddressByteSize(); - DataEncoder enc(buf, order, addr_size); - enc.PutU64(0, static_cast<uint64_t>(intvalue)); - DataExtractor data(buf, order, addr_size); - - CompilerType type = LookupType(target, ConstString("int64")); - return ValueObject::CreateValueObjectFromData(llvm::StringRef(), data, - m_exe_ctx, type); -} - -ValueObjectSP GoUserExpression::GoInterpreter::VisitIndexExpr( - const lldb_private::GoASTIndexExpr *e) { - ValueObjectSP target = EvaluateExpr(e->GetX()); - if (!target) - return nullptr; - ValueObjectSP index = EvaluateExpr(e->GetIndex()); - if (!index) - return nullptr; - bool is_signed; - if (!index->GetCompilerType().IsIntegerType(is_signed)) { - m_error.SetErrorString("Unsupported index"); - return nullptr; - } - size_t idx; - if (is_signed) - idx = index->GetValueAsSigned(0); - else - idx = index->GetValueAsUnsigned(0); - if (GoASTContext::IsGoSlice(target->GetCompilerType())) { - target = target->GetStaticValue(); - ValueObjectSP cap = - target->GetChildMemberWithName(ConstString("cap"), true); - if (cap) { - uint64_t capval = cap->GetValueAsUnsigned(0); - if (idx >= capval) { - m_error.SetErrorStringWithFormat("Invalid index %" PRIu64 - " , cap = %" PRIu64, - uint64_t(idx), capval); - return nullptr; - } - } - target = target->GetChildMemberWithName(ConstString("array"), true); - if (target && m_use_dynamic != eNoDynamicValues) { - ValueObjectSP dynamic = target->GetDynamicValue(m_use_dynamic); - if (dynamic) - target = dynamic; - } - if (!target) - return nullptr; - return target->GetSyntheticArrayMember(idx, true); - } - return target->GetChildAtIndex(idx, true); -} - -ValueObjectSP -GoUserExpression::GoInterpreter::VisitUnaryExpr(const GoASTUnaryExpr *e) { - ValueObjectSP x = EvaluateExpr(e->GetX()); - if (!x) - return nullptr; - switch (e->GetOp()) { - case GoLexer::OP_AMP: { - CompilerType type = x->GetCompilerType().GetPointerType(); - uint64_t address = x->GetAddressOf(); - return ValueObject::CreateValueObjectFromAddress(llvm::StringRef(), address, - m_exe_ctx, type); - } - case GoLexer::OP_PLUS: - return x; - default: - m_error.SetErrorStringWithFormat( - "Operator %s not supported", - GoLexer::LookupToken(e->GetOp()).str().c_str()); - return nullptr; - } -} - -CompilerType GoUserExpression::GoInterpreter::EvaluateType(const GoASTExpr *e) { - TargetSP target = m_exe_ctx.GetTargetSP(); - if (auto *id = llvm::dyn_cast<GoASTIdent>(e)) { - CompilerType result = - LookupType(target, ConstString(id->GetName().m_value)); - if (result.IsValid()) - return result; - std::string fullname = (m_package + "." + id->GetName().m_value).str(); - result = LookupType(target, ConstString(fullname)); - if (!result) - m_error.SetErrorStringWithFormat("Unknown type %s", fullname.c_str()); - return result; - } - if (auto *sel = llvm::dyn_cast<GoASTSelectorExpr>(e)) { - std::string package; - if (auto *pkg_node = llvm::dyn_cast<GoASTIdent>(sel->GetX())) { - package = pkg_node->GetName().m_value.str(); - } else if (auto *str_node = llvm::dyn_cast<GoASTBasicLit>(sel->GetX())) { - if (str_node->GetValue().m_type == GoLexer::LIT_STRING) { - package = str_node->GetValue().m_value.substr(1).str(); - package.resize(package.length() - 1); - } - } - if (package.empty()) { - m_error.SetErrorStringWithFormat("Invalid %s in type expression", - sel->GetX()->GetKindName()); - return CompilerType(); - } - std::string fullname = - (package + "." + sel->GetSel()->GetName().m_value).str(); - CompilerType result = LookupType(target, ConstString(fullname)); - if (!result) - m_error.SetErrorStringWithFormat("Unknown type %s", fullname.c_str()); - return result; - } - if (auto *star = llvm::dyn_cast<GoASTStarExpr>(e)) { - CompilerType elem = EvaluateType(star->GetX()); - return elem.GetPointerType(); - } - if (auto *paren = llvm::dyn_cast<GoASTParenExpr>(e)) - return EvaluateType(paren->GetX()); - if (auto *array = llvm::dyn_cast<GoASTArrayType>(e)) { - CompilerType elem = EvaluateType(array->GetElt()); - } - - m_error.SetErrorStringWithFormat("Invalid %s in type expression", - e->GetKindName()); - return CompilerType(); -} - -ValueObjectSP GoUserExpression::GoInterpreter::VisitCallExpr( - const lldb_private::GoASTCallExpr *e) { - ValueObjectSP x = EvaluateExpr(e->GetFun()); - if (x || e->NumArgs() != 1) { - m_error.SetErrorStringWithFormat("Code execution not supported"); - return nullptr; - } - m_error.Clear(); - CompilerType type = EvaluateType(e->GetFun()); - if (!type) { - return nullptr; - } - ValueObjectSP value = EvaluateExpr(e->GetArgs(0)); - if (!value) - return nullptr; - // TODO: Handle special conversions - return value->Cast(type); -} - -GoPersistentExpressionState::GoPersistentExpressionState() - : PersistentExpressionState(eKindGo) {} - -void GoPersistentExpressionState::RemovePersistentVariable( - lldb::ExpressionVariableSP variable) { - RemoveVariable(variable); - - const char *name = variable->GetName().AsCString(); - - if (*(name++) != '$') - return; - if (*(name++) != 'g') - return; - if (*(name++) != 'o') - return; - - if (strtoul(name, nullptr, 0) == m_next_persistent_variable_id - 1) - m_next_persistent_variable_id--; -} diff --git a/source/Plugins/ExpressionParser/Go/GoUserExpression.h b/source/Plugins/ExpressionParser/Go/GoUserExpression.h deleted file mode 100644 index e2839da9bfdd..000000000000 --- a/source/Plugins/ExpressionParser/Go/GoUserExpression.h +++ /dev/null @@ -1,94 +0,0 @@ -//===-- GoUserExpression.h --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_GoUserExpression_h_ -#define liblldb_GoUserExpression_h_ - -// C Includes -// C++ Includes -#include <memory> - -// Other libraries and framework includes -// Project includes -#include "lldb/Expression/ExpressionVariable.h" -#include "lldb/Expression/UserExpression.h" -#include "lldb/Target/ExecutionContext.h" -#include "lldb/lldb-forward.h" -#include "lldb/lldb-private.h" - -namespace lldb_private { -class GoParser; - -class GoPersistentExpressionState : public PersistentExpressionState { -public: - GoPersistentExpressionState(); - - llvm::StringRef - GetPersistentVariablePrefix(bool is_error) const override { - return "$go"; - } - void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override; - - lldb::addr_t LookupSymbol(const ConstString &name) override { - return LLDB_INVALID_ADDRESS; - } - - static bool classof(const PersistentExpressionState *pv) { - return pv->getKind() == PersistentExpressionState::eKindGo; - } - -private: - uint32_t m_next_persistent_variable_id; ///< The counter used by - ///GetNextResultName(). -}; - -//---------------------------------------------------------------------- -/// @class GoUserExpression GoUserExpression.h -/// "lldb/Expression/GoUserExpression.h" Encapsulates a single expression for -/// use with Go -/// -/// LLDB uses expressions for various purposes, notably to call functions -/// and as a backend for the expr command. GoUserExpression encapsulates the -/// objects needed to parse and interpret an expression. -//---------------------------------------------------------------------- -class GoUserExpression : public UserExpression { -public: - GoUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, - llvm::StringRef prefix, lldb::LanguageType language, - ResultType desired_type, - const EvaluateExpressionOptions &options); - - bool Parse(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, - lldb_private::ExecutionPolicy execution_policy, - bool keep_result_in_memory, bool generate_debug_info) override; - - bool CanInterpret() override { return true; } - bool FinalizeJITExecution( - DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, - lldb::ExpressionVariableSP &result, - lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, - lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS) override { - return true; - } - -protected: - lldb::ExpressionResults - DoExecute(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, - const EvaluateExpressionOptions &options, - lldb::UserExpressionSP &shared_ptr_to_me, - lldb::ExpressionVariableSP &result) override; - -private: - class GoInterpreter; - std::unique_ptr<GoInterpreter> m_interpreter; -}; - -} // namespace lldb_private - -#endif // liblldb_GoUserExpression_h_ diff --git a/source/Plugins/ExpressionParser/Go/gen_go_ast.py b/source/Plugins/ExpressionParser/Go/gen_go_ast.py deleted file mode 100644 index 3be0e5f506ee..000000000000 --- a/source/Plugins/ExpressionParser/Go/gen_go_ast.py +++ /dev/null @@ -1,464 +0,0 @@ -import StringIO - - -def addNodes(): - addNode("ArrayType", "Expr", "len", "Expr", "elt", "Expr") - addNode( - "AssignStmt", - "Stmt", - "lhs", - "[]Expr", - "rhs", - "[]Expr", - "define", - "bool") - addNode("BadDecl", "Decl") - addNode("BadExpr", "Expr") - addNode("BadStmt", "Stmt") - addNode("BasicLit", "Expr", "value", "Token") - addNode("BinaryExpr", "Expr", "x", "Expr", "y", "Expr", "op", "TokenType") - addNode("BlockStmt", "Stmt", "list", "[]Stmt") - addNode("Ident", "Expr", "name", "Token") - addNode("BranchStmt", "Stmt", "label", "Ident", "tok", "TokenType") - addNode( - "CallExpr", - "Expr", - "fun", - "Expr", - "args", - "[]Expr", - "ellipsis", - "bool") - addNode("CaseClause", "Stmt", "list", "[]Expr", "body", "[]Stmt") - addNode("ChanType", "Expr", "dir", "ChanDir", "value", "Expr") - addNode("CommClause", "Stmt", "comm", "Stmt", "body", "[]Stmt") - addNode("CompositeLit", "Expr", "type", "Expr", "elts", "[]Expr") - addNode("DeclStmt", "Stmt", "decl", "Decl") - addNode("DeferStmt", "Stmt", "call", "CallExpr") - addNode("Ellipsis", "Expr", "elt", "Expr") - addNode("EmptyStmt", "Stmt") - addNode("ExprStmt", "Stmt", "x", "Expr") - addNode( - "Field", - "Node", - "names", - "[]Ident", - "type", - "Expr", - "tag", - "BasicLit") - addNode("FieldList", "Node", "list", "[]Field") - addNode( - "ForStmt", - "Stmt", - "init", - "Stmt", - "cond", - "Expr", - "post", - "Stmt", - "body", - "BlockStmt") - addNode("FuncType", "Expr", "params", "FieldList", "results", "FieldList") - addNode( - "FuncDecl", - "Decl", - "recv", - "FieldList", - "name", - "Ident", - "type", - "FuncType", - "body", - "BlockStmt") - addNode("FuncLit", "Expr", "type", "FuncType", "body", "BlockStmt") - addNode("GenDecl", "Decl", "tok", "TokenType", "specs", "[]Spec") - addNode("GoStmt", "Stmt", "call", "CallExpr") - addNode( - "IfStmt", - "Stmt", - "init", - "Stmt", - "cond", - "Expr", - "body", - "BlockStmt", - "els", - "Stmt") - addNode("ImportSpec", "Spec", "name", "Ident", "path", "BasicLit") - addNode("IncDecStmt", "Stmt", "x", "Expr", "tok", "TokenType") - addNode("IndexExpr", "Expr", "x", "Expr", "index", "Expr") - addNode("InterfaceType", "Expr", "methods", "FieldList") - addNode("KeyValueExpr", "Expr", "key", "Expr", "value", "Expr") - addNode("LabeledStmt", "Stmt", "label", "Ident", "stmt", "Stmt") - addNode("MapType", "Expr", "key", "Expr", "value", "Expr") - addNode("ParenExpr", "Expr", "x", "Expr") - addNode( - "RangeStmt", - "Stmt", - "key", - "Expr", - "value", - "Expr", - "define", - "bool", - "x", - "Expr", - "body", - "BlockStmt") - addNode("ReturnStmt", "Stmt", "results", "[]Expr") - addNode("SelectStmt", "Stmt", "body", "BlockStmt") - addNode("SelectorExpr", "Expr", "x", "Expr", "sel", "Ident") - addNode("SendStmt", "Stmt", "chan", "Expr", "value", "Expr") - addNode( - "SliceExpr", - "Expr", - "x", - "Expr", - "low", - "Expr", - "high", - "Expr", - "max", - "Expr", - "slice3", - "bool") - addNode("StarExpr", "Expr", "x", "Expr") - addNode("StructType", "Expr", "fields", "FieldList") - addNode( - "SwitchStmt", - "Stmt", - "init", - "Stmt", - "tag", - "Expr", - "body", - "BlockStmt") - addNode("TypeAssertExpr", "Expr", "x", "Expr", "type", "Expr") - addNode("TypeSpec", "Spec", "name", "Ident", "type", "Expr") - addNode( - "TypeSwitchStmt", - "Stmt", - "init", - "Stmt", - "assign", - "Stmt", - "body", - "BlockStmt") - addNode("UnaryExpr", "Expr", "op", "TokenType", "x", "Expr") - addNode( - "ValueSpec", - "Spec", - "names", - "[]Ident", - "type", - "Expr", - "values", - "[]Expr") - addParent("Decl", "Node") - addParent("Expr", "Node") - addParent("Spec", "Node") - addParent("Stmt", "Node") - - -class Member(object): - - def __init__(self, name, typename): - self.title = name.title() - self.sname = name - self.mname = 'm_' + name - self.is_list = typename.startswith("[]") - self.is_value = isValueType(typename) - if self.is_value: - self.argtype = typename - self.mtype = typename - elif self.is_list: - self.argtype = 'GoAST' + typename[2:] - self.mtype = 'std::vector<std::unique_ptr<%s> >' % self.argtype - else: - self.argtype = 'GoAST' + typename - self.mtype = 'std::unique_ptr<%s>' % self.argtype - self.mname = self.mname + '_up' - - -kinds = {} -parentClasses = StringIO.StringIO() -childClasses = StringIO.StringIO() -walker = StringIO.StringIO() - - -def startClass(name, parent, out): - out.write(""" -class GoAST%s : public GoAST%s -{ - public: -""" % (name, parent)) - - -def endClass(name, out): - out.write(""" - %(name)s(const %(name)s &) = delete; - const %(name)s &operator=(const %(name)s &) = delete; -}; -""" % {'name': 'GoAST' + name}) - - -def addNode(name, parent, *children): - startClass(name, parent, childClasses) - l = kinds.setdefault(parent, []) - l.append(name) - children = createMembers(name, children) - addConstructor(name, parent, children) - childClasses.write(""" - const char * - GetKindName() const override - { - return "%(name)s"; - } - - static bool - classof(const GoASTNode *n) - { - return n->GetKind() == e%(name)s; - } - """ % {'name': name}) - addChildren(name, children) - endClass(name, childClasses) - - -def isValueType(typename): - if typename[0].islower(): - return True - if typename[0].isupper(): - return typename.startswith('Token') or typename == 'ChanDir' - return False - - -def createMembers(name, children): - l = len(children) - if (l % 2) != 0: - raise Exception("Invalid children for %s: %s" % (name, children)) - return [Member(children[i], children[i + 1]) for i in xrange(0, l, 2)] - - -def addConstructor(name, parent, children): - for c in children: - if c.is_list: - children = [x for x in children if x.is_value] - break - childClasses.write(' ') - if len(children) == 1: - childClasses.write('explicit ') - childClasses.write('GoAST%s(' % name) - for i in xrange(len(children)): - if i > 0: - childClasses.write(', ') - - c = children[i] - if c.is_value: - childClasses.write(c.argtype) - childClasses.write(' ') - else: - childClasses.write('%s *' % c.argtype) - childClasses.write(c.sname) - childClasses.write(') : GoAST%s(e%s)' % (parent, name)) - for c in children: - childClasses.write(', ') - childClasses.write('%(mname)s(%(sname)s)' % c.__dict__) - childClasses.write(""" {} - ~GoAST%s() override = default; -""" % name) - - -def addChildren(name, children): - if len(children) == 0: - return - walker.write(""" - case e%(n)s: - { - GoAST%(n)s *n = llvm::cast<GoAST%(n)s>(this); - (void)n;""" % {'n': name}) - for c in children: - if c.is_list: - childClasses.write(""" - size_t - Num%(title)s() const - { - return %(mname)s.size(); - } - const %(argtype)s * - Get%(title)s(int i) const - { - return %(mname)s[i].get(); - } - void - Add%(title)s(%(argtype)s *%(sname)s) - { - %(mname)s.push_back(std::unique_ptr<%(argtype)s>(%(sname)s)); - } -""" % c.__dict__) - walker.write(""" - for (auto& e : n->%s) { v(e.get()); }""" % c.mname) - else: - const = '' - get = '' - set = '' - t = c.argtype - if isValueType(t): - set = '%(mname)s = %(sname)s' % c.__dict__ - t = t + ' ' - else: - t = t + ' *' - const = 'const ' - get = '.get()' - set = '%(mname)s.reset(%(sname)s)' % c.__dict__ - walker.write(""" - v(n->%s.get());""" % c.mname) - childClasses.write(""" - %(const)s%(type)s - Get%(title)s() const - { - return %(mname)s%(get)s; - } - void - Set%(title)s(%(type)s%(sname)s) - { - %(set)s; - } -""" % {'const': const, 'title': c.title, 'sname': c.sname, 'get': get, 'set': set, 'type': t, 'mname': c.mname}) - childClasses.write('\n private:\n friend class GoASTNode;\n') - walker.write(""" - return; - }""") - for c in children: - childClasses.write(' %s %s;\n' % (c.mtype, c.mname)) - - -def addParent(name, parent): - startClass(name, parent, parentClasses) - l = kinds[name] - minName = l[0] - maxName = l[-1] - parentClasses.write(""" template <typename R, typename V> R Visit(V *v) const; - - static bool - classof(const GoASTNode *n) - { - return n->GetKind() >= e%s && n->GetKind() <= e%s; - } - - protected: - explicit GoAST%s(NodeKind kind) : GoASTNode(kind) { } - private: -""" % (minName, maxName, name)) - endClass(name, parentClasses) - -addNodes() - -print """//===-- GoAST.h -------------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// DO NOT EDIT. -// Generated by gen_go_ast.py - -#ifndef liblldb_GoAST_h -#define liblldb_GoAST_h - -#include "lldb/lldb-forward.h" -#include "lldb/lldb-private.h" -#include "llvm/Support/Casting.h" -#include "Plugins/ExpressionParser/Go/GoLexer.h" - -namespace lldb_private -{ - -class GoASTNode -{ - public: - typedef GoLexer::TokenType TokenType; - typedef GoLexer::Token Token; - enum ChanDir - { - eChanBidir, - eChanSend, - eChanRecv, - }; - enum NodeKind - {""" -for l in kinds.itervalues(): - for x in l: - print " e%s," % x -print """ }; - - virtual ~GoASTNode() = default; - - NodeKind - GetKind() const - { - return m_kind; - } - - virtual const char *GetKindName() const = 0; - - template <typename V> void WalkChildren(V &v); - - protected: - explicit GoASTNode(NodeKind kind) : m_kind(kind) { } - - private: - const NodeKind m_kind; - - GoASTNode(const GoASTNode &) = delete; - const GoASTNode &operator=(const GoASTNode &) = delete; -}; -""" - - -print parentClasses.getvalue() -print childClasses.getvalue() - -for k, l in kinds.iteritems(): - if k == 'Node': - continue - print """ -template <typename R, typename V> -R GoAST%s::Visit(V* v) const -{ - switch(GetKind()) - {""" % k - for subtype in l: - print """ case e%(n)s: - return v->Visit%(n)s(llvm::cast<const GoAST%(n)s>(this));""" % {'n': subtype} - - print """ default: - assert(false && "Invalid kind"); - } -}""" - -print """ -template <typename V> -void GoASTNode::WalkChildren(V &v) -{ - switch (m_kind) - { -""" -print walker.getvalue() -print""" - case eEmptyStmt: - case eBadDecl: - case eBadExpr: - case eBadStmt: - break; - } -} - -} // namespace lldb_private - -#endif -""" diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index 86744520ad63..85bc4a61c9d4 100644 --- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -26,8 +26,7 @@ #include "Utility/ARM_DWARF_Registers.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Support/MathExtras.h" // for SignExtend32 template function - // and countTrailingZeros function +#include "llvm/Support/MathExtras.h" using namespace lldb; using namespace lldb_private; @@ -777,10 +776,7 @@ bool EmulateInstructionARM::WriteBits32UnknownToMemory(addr_t address) { uint32_t random_data = rand(); const uint32_t addr_byte_size = GetAddressByteSize(); - if (!MemAWrite(context, address, random_data, addr_byte_size)) - return false; - - return true; + return MemAWrite(context, address, random_data, addr_byte_size); } // Write "bits (32) UNKNOWN" to register n. Helper function for many ARM @@ -850,6 +846,7 @@ uint32_t EmulateInstructionARM::GetFramePointerRegisterNumber() const { case llvm::Triple::IOS: case llvm::Triple::TvOS: case llvm::Triple::WatchOS: + // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: is_apple = true; break; default: @@ -3340,10 +3337,7 @@ bool EmulateInstructionARM::EmulateCMNImm(const uint32_t opcode, EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) - return false; - - return true; + return WriteFlags(context, res.result, res.carry_out, res.overflow); } // Compare Negative (register) adds a register value and an optionally-shifted @@ -3410,10 +3404,7 @@ bool EmulateInstructionARM::EmulateCMNReg(const uint32_t opcode, EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) - return false; - - return true; + return WriteFlags(context, res.result, res.carry_out, res.overflow); } // Compare (immediate) subtracts an immediate value from a register value. It @@ -3463,10 +3454,7 @@ bool EmulateInstructionARM::EmulateCMPImm(const uint32_t opcode, EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) - return false; - - return true; + return WriteFlags(context, res.result, res.carry_out, res.overflow); } // Compare (register) subtracts an optionally-shifted register value from a @@ -3542,10 +3530,7 @@ bool EmulateInstructionARM::EmulateCMPReg(const uint32_t opcode, EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) - return false; - - return true; + return WriteFlags(context, res.result, res.carry_out, res.overflow); } // Arithmetic Shift Right (immediate) shifts a register value right by an @@ -9245,11 +9230,8 @@ bool EmulateInstructionARM::EmulateRSBImm(const uint32_t opcode, context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, - res.carry_out, res.overflow)) - return false; - - return true; + return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, + res.carry_out, res.overflow); } // Reverse Subtract (register) subtracts a register value from an optionally- @@ -9326,11 +9308,8 @@ bool EmulateInstructionARM::EmulateRSBReg(const uint32_t opcode, EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, - res.carry_out, res.overflow)) - return false; - - return true; + return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, + res.carry_out, res.overflow); } // Reverse Subtract with Carry (immediate) subtracts a register value and the @@ -9388,11 +9367,8 @@ bool EmulateInstructionARM::EmulateRSCImm(const uint32_t opcode, context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, - res.carry_out, res.overflow)) - return false; - - return true; + return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, + res.carry_out, res.overflow); } // Reverse Subtract with Carry (register) subtracts a register value and the @@ -9460,11 +9436,8 @@ bool EmulateInstructionARM::EmulateRSCReg(const uint32_t opcode, EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, - res.carry_out, res.overflow)) - return false; - - return true; + return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, + res.carry_out, res.overflow); } // Subtract with Carry (immediate) subtracts an immediate value and the value @@ -9531,11 +9504,8 @@ bool EmulateInstructionARM::EmulateSBCImm(const uint32_t opcode, context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, - res.carry_out, res.overflow)) - return false; - - return true; + return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, + res.carry_out, res.overflow); } // Subtract with Carry (register) subtracts an optionally-shifted register @@ -9620,11 +9590,8 @@ bool EmulateInstructionARM::EmulateSBCReg(const uint32_t opcode, EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, - res.carry_out, res.overflow)) - return false; - - return true; + return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, + res.carry_out, res.overflow); } // This instruction subtracts an immediate value from a register value, and @@ -9713,11 +9680,8 @@ bool EmulateInstructionARM::EmulateSUBImmThumb(const uint32_t opcode, context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); - if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, - res.carry_out, res.overflow)) - return false; - - return true; + return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, + res.carry_out, res.overflow); } // This instruction subtracts an immediate value from a register value, and @@ -14153,11 +14117,8 @@ bool EmulateInstructionARM::BranchWritePC(const Context &context, else target = addr & 0xfffffffe; - if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC, target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC, target); } // As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by @@ -14191,11 +14152,8 @@ bool EmulateInstructionARM::BXWritePC(Context &context, uint32_t addr) { LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr)) return false; } - if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC, target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC, target); } // Dispatches to either BXWritePC or BranchWritePC based on architecture @@ -14408,14 +14366,14 @@ bool EmulateInstructionARM::EvaluateInstruction(uint32_t evaluate_options) { evaluate_options & eEmulateInstructionOptionIgnoreConditions; bool success = false; - if (m_opcode_cpsr == 0 || m_ignore_conditions == false) { + if (m_opcode_cpsr == 0 || !m_ignore_conditions) { m_opcode_cpsr = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_cpsr, 0, &success); } // Only return false if we are unable to read the CPSR if we care about // conditions - if (success == false && m_ignore_conditions == false) + if (!success && !m_ignore_conditions) return false; uint32_t orig_pc_value = 0; diff --git a/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/source/Plugins/Instruction/ARM/EmulationStateARM.cpp index d1032f56f31c..d770b3bdc52e 100644 --- a/source/Plugins/Instruction/ARM/EmulationStateARM.cpp +++ b/source/Plugins/Instruction/ARM/EmulationStateARM.cpp @@ -9,12 +9,12 @@ #include "EmulationStateARM.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Interpreter/OptionValueArray.h" #include "lldb/Interpreter/OptionValueDictionary.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "Utility/ARM_DWARF_Registers.h" diff --git a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp index 2f484ab5ea97..661a651c56c2 100644 --- a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp +++ b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp @@ -13,10 +13,10 @@ #include "lldb/Core/Address.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/ConstString.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Stream.h" #include "Plugins/Process/Utility/ARMDefines.h" @@ -41,8 +41,7 @@ #include "Plugins/Process/Utility/RegisterInfos_arm64.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Support/MathExtras.h" // for SignExtend32 template function - // and CountTrailingZeros_32 function +#include "llvm/Support/MathExtras.h" #include "Plugins/Process/Utility/InstructionUtils.h" @@ -437,7 +436,7 @@ bool EmulateInstructionARM64::EvaluateInstruction(uint32_t evaluate_options) { // Only return false if we are unable to read the CPSR if we care about // conditions - if (success == false && m_ignore_conditions == false) + if (!success && !m_ignore_conditions) return false; uint32_t orig_pc_value = 0; @@ -547,11 +546,8 @@ bool EmulateInstructionARM64::BranchTo(const Context &context, uint32_t N, } else return false; - if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC, addr)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC, addr); } bool EmulateInstructionARM64::ConditionHolds(const uint32_t cond) { @@ -1097,9 +1093,7 @@ bool EmulateInstructionARM64::EmulateB(const uint32_t opcode) { return false; } - if (!BranchTo(context, 64, target)) - return false; - return true; + return BranchTo(context, 64, target); } bool EmulateInstructionARM64::EmulateBcond(const uint32_t opcode) { diff --git a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h index 253bb935bca7..1d1bd74d3f61 100644 --- a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h +++ b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h @@ -10,10 +10,6 @@ #ifndef EmulateInstructionARM64_h_ #define EmulateInstructionARM64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "Plugins/Process/Utility/ARMDefines.h" #include "lldb/Core/EmulateInstruction.h" #include "lldb/Interpreter/OptionValue.h" diff --git a/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp index b65747e12890..7fccb2311026 100644 --- a/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp +++ b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp @@ -14,12 +14,12 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Opcode.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Stream.h" #include "llvm-c/Disassembler.h" #include "llvm/MC/MCAsmInfo.h" @@ -35,7 +35,7 @@ #include "llvm/ADT/STLExtras.h" #include "Plugins/Process/Utility/InstructionUtils.h" -#include "Plugins/Process/Utility/RegisterContext_mips.h" //mips32 has same registers nos as mips64 +#include "Plugins/Process/Utility/RegisterContext_mips.h" using namespace lldb; using namespace lldb_private; @@ -220,10 +220,8 @@ EmulateInstructionMIPS::CreateInstance(const ArchSpec &arch, } bool EmulateInstructionMIPS::SetTargetTriple(const ArchSpec &arch) { - if (arch.GetTriple().getArch() == llvm::Triple::mips || - arch.GetTriple().getArch() == llvm::Triple::mipsel) - return true; - return false; + return arch.GetTriple().getArch() == llvm::Triple::mips || + arch.GetTriple().getArch() == llvm::Triple::mipsel; } const char *EmulateInstructionMIPS::GetRegisterName(unsigned reg_num, @@ -1350,10 +1348,7 @@ bool EmulateInstructionMIPS::Emulate_LW(llvm::MCInst &insn) { context.type = eContextPopRegisterOffStack; context.SetAddress(address); - if (!WriteRegister(context, ®_info_src, data_src)) - return false; - - return true; + return WriteRegister(context, ®_info_src, data_src); } return false; @@ -1450,11 +1445,8 @@ bool EmulateInstructionMIPS::Emulate_LUI(llvm::MCInst &insn) { context.SetImmediateSigned(imm); context.type = eContextImmediate; - if (WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_zero_mips + rt, - imm)) - return true; - - return false; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, + dwarf_zero_mips + rt, imm); } bool EmulateInstructionMIPS::Emulate_ADDIUSP(llvm::MCInst &insn) { @@ -1697,10 +1689,7 @@ bool EmulateInstructionMIPS::Emulate_LWSP(llvm::MCInst &insn) { context.type = eContextPopRegisterOffStack; context.SetAddress(base_address); - if (!WriteRegister(context, ®_info_src, data_src)) - return false; - - return true; + return WriteRegister(context, ®_info_src, data_src); } return false; @@ -1807,11 +1796,8 @@ bool EmulateInstructionMIPS::Emulate_JRADDIUSP(llvm::MCInst &insn) { context.type = eContextAdjustStackPointer; // update SP - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips, - result)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips, + result); } static int IsAdd64bitOverflow(int32_t a, int32_t b) { @@ -1864,11 +1850,8 @@ bool EmulateInstructionMIPS::Emulate_BXX_3ops(llvm::MCInst &insn) { context.type = eContextRelativeBranchImmediate; context.SetImmediate(offset); - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } /* @@ -1947,11 +1930,8 @@ bool EmulateInstructionMIPS::Emulate_BXX_3ops_C(llvm::MCInst &insn) { context.type = eContextRelativeBranchImmediate; context.SetImmediate(current_inst_size + offset); - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } /* @@ -2122,11 +2102,8 @@ bool EmulateInstructionMIPS::Emulate_BXX_2ops(llvm::MCInst &insn) { context.type = eContextRelativeBranchImmediate; context.SetImmediate(offset); - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } /* @@ -2189,11 +2166,8 @@ bool EmulateInstructionMIPS::Emulate_BXX_2ops_C(llvm::MCInst &insn) { context.type = eContextRelativeBranchImmediate; context.SetImmediate(current_inst_size + offset); - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } bool EmulateInstructionMIPS::Emulate_B16_MM(llvm::MCInst &insn) { @@ -2214,11 +2188,8 @@ bool EmulateInstructionMIPS::Emulate_B16_MM(llvm::MCInst &insn) { context.type = eContextRelativeBranchImmediate; context.SetImmediate(current_inst_size + offset); - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } /* @@ -2529,11 +2500,8 @@ bool EmulateInstructionMIPS::Emulate_BC(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } bool EmulateInstructionMIPS::Emulate_J(llvm::MCInst &insn) { @@ -2556,10 +2524,7 @@ bool EmulateInstructionMIPS::Emulate_J(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, pc)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, pc); } bool EmulateInstructionMIPS::Emulate_JAL(llvm::MCInst &insn) { @@ -2688,11 +2653,8 @@ bool EmulateInstructionMIPS::Emulate_JIC(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } bool EmulateInstructionMIPS::Emulate_JR(llvm::MCInst &insn) { @@ -2713,11 +2675,8 @@ bool EmulateInstructionMIPS::Emulate_JR(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - rs_val)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + rs_val); } /* @@ -2758,11 +2717,8 @@ bool EmulateInstructionMIPS::Emulate_FP_branch(llvm::MCInst &insn) { } Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } bool EmulateInstructionMIPS::Emulate_BC1EQZ(llvm::MCInst &insn) { @@ -2797,11 +2753,8 @@ bool EmulateInstructionMIPS::Emulate_BC1EQZ(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } bool EmulateInstructionMIPS::Emulate_BC1NEZ(llvm::MCInst &insn) { @@ -2836,11 +2789,8 @@ bool EmulateInstructionMIPS::Emulate_BC1NEZ(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } /* @@ -2898,11 +2848,8 @@ bool EmulateInstructionMIPS::Emulate_3D_branch(llvm::MCInst &insn) { } Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } bool EmulateInstructionMIPS::Emulate_BNZB(llvm::MCInst &insn) { @@ -2993,11 +2940,8 @@ bool EmulateInstructionMIPS::Emulate_MSA_Branch_DF(llvm::MCInst &insn, Context context; context.type = eContextRelativeBranchImmediate; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } bool EmulateInstructionMIPS::Emulate_BNZV(llvm::MCInst &insn) { @@ -3039,11 +2983,8 @@ bool EmulateInstructionMIPS::Emulate_MSA_Branch_V(llvm::MCInst &insn, Context context; context.type = eContextRelativeBranchImmediate; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, + target); } bool EmulateInstructionMIPS::Emulate_LDST_Imm(llvm::MCInst &insn) { diff --git a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp index 5af12ad141aa..9d178dd97ddf 100644 --- a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp +++ b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp @@ -14,12 +14,12 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Opcode.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Host/PosixApi.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Stream.h" #include "llvm-c/Disassembler.h" #include "llvm/MC/MCAsmInfo.h" @@ -207,10 +207,8 @@ EmulateInstructionMIPS64::CreateInstance(const ArchSpec &arch, } bool EmulateInstructionMIPS64::SetTargetTriple(const ArchSpec &arch) { - if (arch.GetTriple().getArch() == llvm::Triple::mips64 || - arch.GetTriple().getArch() == llvm::Triple::mips64el) - return true; - return false; + return arch.GetTriple().getArch() == llvm::Triple::mips64 || + arch.GetTriple().getArch() == llvm::Triple::mips64el; } const char *EmulateInstructionMIPS64::GetRegisterName(unsigned reg_num, @@ -1099,13 +1097,24 @@ bool EmulateInstructionMIPS64::Emulate_DADDiu(llvm::MCInst &insn) { Context context; /* read <src> register */ - const int64_t src_opd_val = ReadRegisterUnsigned( + const uint64_t src_opd_val = ReadRegisterUnsigned( eRegisterKindDWARF, dwarf_zero_mips64 + src, 0, &success); if (!success) return false; /* Check if this is daddiu sp, sp, imm16 */ if (dst == dwarf_sp_mips64) { + /* + * From the MIPS IV spec: + * + * The term “unsigned” in the instruction name is a misnomer; this + * operation is 64-bit modulo arithmetic that does not trap on overflow. + * It is appropriate for arithmetic which is not signed, such as address + * arithmetic, or integer arithmetic environments that ignore overflow, + * such as “C” language arithmetic. + * + * Assume 2's complement and rely on unsigned overflow here. + */ uint64_t result = src_opd_val + imm; RegisterInfo reg_info_sp; @@ -1229,10 +1238,7 @@ bool EmulateInstructionMIPS64::Emulate_LD(llvm::MCInst &insn) { Context context; context.type = eContextRegisterLoad; - if (!WriteRegister(context, ®_info_src, data_src)) - return false; - - return true; + return WriteRegister(context, ®_info_src, data_src); } return false; @@ -1251,11 +1257,8 @@ bool EmulateInstructionMIPS64::Emulate_LUI(llvm::MCInst &insn) { context.SetImmediateSigned(imm); context.type = eContextImmediate; - if (WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_zero_mips64 + rt, - imm)) - return true; - - return false; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, + dwarf_zero_mips64 + rt, imm); } bool EmulateInstructionMIPS64::Emulate_DSUBU_DADDU(llvm::MCInst &insn) { @@ -1383,11 +1386,8 @@ bool EmulateInstructionMIPS64::Emulate_BXX_3ops(llvm::MCInst &insn) { context.type = eContextRelativeBranchImmediate; context.SetImmediate(offset); - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } /* @@ -1622,11 +1622,8 @@ bool EmulateInstructionMIPS64::Emulate_BXX_2ops(llvm::MCInst &insn) { context.type = eContextRelativeBranchImmediate; context.SetImmediate(offset); - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } bool EmulateInstructionMIPS64::Emulate_BC(llvm::MCInst &insn) { @@ -1648,11 +1645,8 @@ bool EmulateInstructionMIPS64::Emulate_BC(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } static int IsAdd64bitOverflow(int64_t a, int64_t b) { @@ -1736,11 +1730,8 @@ bool EmulateInstructionMIPS64::Emulate_BXX_3ops_C(llvm::MCInst &insn) { context.type = eContextRelativeBranchImmediate; context.SetImmediate(current_inst_size + offset); - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } /* @@ -1803,11 +1794,8 @@ bool EmulateInstructionMIPS64::Emulate_BXX_2ops_C(llvm::MCInst &insn) { context.type = eContextRelativeBranchImmediate; context.SetImmediate(current_inst_size + offset); - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } bool EmulateInstructionMIPS64::Emulate_J(llvm::MCInst &insn) { @@ -1830,10 +1818,8 @@ bool EmulateInstructionMIPS64::Emulate_J(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, pc)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + pc); } bool EmulateInstructionMIPS64::Emulate_JAL(llvm::MCInst &insn) { @@ -1962,11 +1948,8 @@ bool EmulateInstructionMIPS64::Emulate_JIC(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } bool EmulateInstructionMIPS64::Emulate_JR(llvm::MCInst &insn) { @@ -1987,11 +1970,8 @@ bool EmulateInstructionMIPS64::Emulate_JR(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - rs_val)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + rs_val); } /* @@ -2041,11 +2021,8 @@ bool EmulateInstructionMIPS64::Emulate_FP_branch(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } bool EmulateInstructionMIPS64::Emulate_BC1EQZ(llvm::MCInst &insn) { @@ -2080,11 +2057,8 @@ bool EmulateInstructionMIPS64::Emulate_BC1EQZ(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } bool EmulateInstructionMIPS64::Emulate_BC1NEZ(llvm::MCInst &insn) { @@ -2119,11 +2093,8 @@ bool EmulateInstructionMIPS64::Emulate_BC1NEZ(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } /* @@ -2182,11 +2153,8 @@ bool EmulateInstructionMIPS64::Emulate_3D_branch(llvm::MCInst &insn) { Context context; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } bool EmulateInstructionMIPS64::Emulate_BNZB(llvm::MCInst &insn) { @@ -2277,11 +2245,8 @@ bool EmulateInstructionMIPS64::Emulate_MSA_Branch_DF(llvm::MCInst &insn, Context context; context.type = eContextRelativeBranchImmediate; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } bool EmulateInstructionMIPS64::Emulate_BNZV(llvm::MCInst &insn) { @@ -2323,11 +2288,8 @@ bool EmulateInstructionMIPS64::Emulate_MSA_Branch_V(llvm::MCInst &insn, Context context; context.type = eContextRelativeBranchImmediate; - if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, - target)) - return false; - - return true; + return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips64, + target); } bool EmulateInstructionMIPS64::Emulate_LDST_Imm(llvm::MCInst &insn) { diff --git a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h index c2433d59830e..e9783633ac7d 100644 --- a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h +++ b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h @@ -10,10 +10,6 @@ #ifndef EmulateInstructionMIPS64_h_ #define EmulateInstructionMIPS64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/EmulateInstruction.h" #include "lldb/Interpreter/OptionValue.h" #include "lldb/Utility/Status.h" diff --git a/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h index be65de9a5063..e9a1da6dd394 100644 --- a/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h +++ b/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -10,10 +10,6 @@ #ifndef EmulateInstructionPPC64_h_ #define EmulateInstructionPPC64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/EmulateInstruction.h" #include "lldb/Interpreter/OptionValue.h" #include "lldb/Utility/Log.h" diff --git a/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h b/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h index e9af5a6cdc74..1439f86e586f 100644 --- a/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h +++ b/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h @@ -10,10 +10,6 @@ #ifndef liblldb_AddressSanitizerRuntime_h_ #define liblldb_AddressSanitizerRuntime_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/InstrumentationRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Utility/StructuredData.h" diff --git a/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h b/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h index dc737d22a67a..e6482d394efa 100644 --- a/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h +++ b/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h @@ -10,10 +10,6 @@ #ifndef liblldb_ThreadSanitizerRuntime_h_ #define liblldb_ThreadSanitizerRuntime_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/Target/InstrumentationRuntime.h" #include "lldb/Utility/StructuredData.h" diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 7ef3aecdb89f..3040b8b39052 100644 --- a/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes #include "llvm/Support/MathExtras.h" @@ -59,10 +58,9 @@ template <typename ptr_t> struct jit_descriptor { namespace { -PropertyDefinition g_properties[] = { +static constexpr PropertyDefinition g_properties[] = { {"enable-jit-breakpoint", OptionValue::eTypeBoolean, true, true, nullptr, - nullptr, "Enable breakpoint on __jit_debug_register_code."}, - {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}}; + {}, "Enable breakpoint on __jit_debug_register_code."}}; enum { ePropertyEnableJITBreakpoint }; @@ -316,7 +314,7 @@ bool JITLoaderGDB::ReadJITDescriptorImpl(bool all_entries) { char jit_name[64]; snprintf(jit_name, 64, "JIT(0x%" PRIx64 ")", symbolfile_addr); module_sp = m_process->ReadModuleFromMemory( - FileSpec(jit_name, false), symbolfile_addr, symbolfile_size); + FileSpec(jit_name), symbolfile_addr, symbolfile_size); if (module_sp && module_sp->GetObjectFile()) { // load the symbol table right away diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.h b/source/Plugins/JITLoader/GDB/JITLoaderGDB.h index 6269860825db..a22016601293 100644 --- a/source/Plugins/JITLoader/GDB/JITLoaderGDB.h +++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.h @@ -10,12 +10,8 @@ #ifndef liblldb_JITLoaderGDB_h_ #define liblldb_JITLoaderGDB_h_ -// C Includes -// C++ Includes #include <map> -// Other libraries and framework includes -// Project includes #include "lldb/Target/JITLoader.h" #include "lldb/Target/Process.h" diff --git a/source/Plugins/Language/CMakeLists.txt b/source/Plugins/Language/CMakeLists.txt index 4b92a8ef866b..7869074566d1 100644 --- a/source/Plugins/Language/CMakeLists.txt +++ b/source/Plugins/Language/CMakeLists.txt @@ -1,6 +1,4 @@ +add_subdirectory(ClangCommon) add_subdirectory(CPlusPlus) -add_subdirectory(Go) -add_subdirectory(Java) add_subdirectory(ObjC) add_subdirectory(ObjCPlusPlus) -add_subdirectory(OCaml) diff --git a/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/source/Plugins/Language/CPlusPlus/BlockPointer.cpp index 82b7ac1675fa..40200503a8a7 100644 --- a/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "BlockPointer.h" #include "lldb/Core/ValueObject.h" @@ -89,7 +85,7 @@ public: size_t CalculateNumChildren() override { const bool omit_empty_base_classes = false; - return m_block_struct_type.GetNumChildren(omit_empty_base_classes); + return m_block_struct_type.GetNumChildren(omit_empty_base_classes, nullptr); } lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { diff --git a/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/source/Plugins/Language/CPlusPlus/CMakeLists.txt index 180440a244a4..bc357aa52b84 100644 --- a/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -9,13 +9,16 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN LibCxxInitializerList.cpp LibCxxList.cpp LibCxxMap.cpp + LibCxxOptional.cpp LibCxxQueue.cpp LibCxxTuple.cpp LibCxxUnorderedMap.cpp + LibCxxVariant.cpp LibCxxVector.cpp LibStdcpp.cpp LibStdcppTuple.cpp LibStdcppUniquePointer.cpp + MSVCUndecoratedNameParser.cpp LINK_LIBS lldbCore @@ -24,6 +27,8 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN lldbSymbol lldbTarget lldbUtility + lldbPluginClangCommon + LINK_COMPONENTS Support ) diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 2c63e6467d4c..982b286d0f05 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -9,20 +9,17 @@ #include "CPlusPlusLanguage.h" -// C Includes #include <cctype> #include <cstring> -// C++ Includes #include <functional> #include <memory> #include <mutex> #include <set> -// Other libraries and framework includes #include "llvm/ADT/StringRef.h" +#include "llvm/Demangle/ItaniumDemangle.h" -// Project includes #include "lldb/Core/PluginManager.h" #include "lldb/Core/UniqueCStringMap.h" #include "lldb/DataFormatters/CXXFunctionPointer.h" @@ -30,7 +27,6 @@ #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/VectorType.h" #include "lldb/Utility/ConstString.h" -#include "lldb/Utility/FastDemangle.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" @@ -39,7 +35,9 @@ #include "CxxStringTypes.h" #include "LibCxx.h" #include "LibCxxAtomic.h" +#include "LibCxxVariant.h" #include "LibStdcpp.h" +#include "MSVCUndecoratedNameParser.h" using namespace lldb; using namespace lldb_private; @@ -143,10 +141,7 @@ static bool IsTrivialBasename(const llvm::StringRef &basename) { } // We processed all characters. It is a vaild basename. - if (idx == basename.size()) - return true; - - return false; + return idx == basename.size(); } bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() { @@ -251,19 +246,23 @@ std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() { bool CPlusPlusLanguage::IsCPPMangledName(const char *name) { // FIXME!! we should really run through all the known C++ Language plugins // and ask each one if this is a C++ mangled name - + if (name == nullptr) return false; - - // MSVC style mangling + + // MSVC style mangling if (name[0] == '?') return true; - + return (name[0] != '\0' && name[0] == '_' && name[1] == 'Z'); } bool CPlusPlusLanguage::ExtractContextAndIdentifier( const char *name, llvm::StringRef &context, llvm::StringRef &identifier) { + if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name)) + return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context, + identifier); + CPlusPlusNameParser parser(name); if (auto full_name = parser.ParseAsFullName()) { identifier = full_name.getValue().basename; @@ -273,53 +272,89 @@ bool CPlusPlusLanguage::ExtractContextAndIdentifier( return false; } -/// Given a mangled function `mangled`, replace all the primitive function type -/// arguments of `search` with type `replace`. -static ConstString SubsPrimitiveParmItanium(llvm::StringRef mangled, - llvm::StringRef search, - llvm::StringRef replace) { - Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); - - const size_t max_len = - mangled.size() + mangled.count(search) * replace.size() + 1; - - // Make a temporary buffer to fix up the mangled parameter types and copy the - // original there - std::string output_buf; - output_buf.reserve(max_len); - output_buf.insert(0, mangled.str()); - ptrdiff_t replaced_offset = 0; - - auto swap_parms_hook = [&](const char *parsee) { - if (!parsee || !*parsee) - return; - - // Check whether we've found a substitutee - llvm::StringRef s(parsee); - if (s.startswith(search)) { - // account for the case where a replacement is of a different length to - // the original - replaced_offset += replace.size() - search.size(); - - ptrdiff_t replace_idx = (mangled.size() - s.size()) + replaced_offset; - output_buf.erase(replace_idx, search.size()); - output_buf.insert(replace_idx, replace.str()); +namespace { +class NodeAllocator { + llvm::BumpPtrAllocator Alloc; + +public: + void reset() { Alloc.Reset(); } + + template <typename T, typename... Args> T *makeNode(Args &&... args) { + return new (Alloc.Allocate(sizeof(T), alignof(T))) + T(std::forward<Args>(args)...); + } + + void *allocateNodeArray(size_t sz) { + return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz, + alignof(llvm::itanium_demangle::Node *)); + } +}; + +/// Given a mangled function `Mangled`, replace all the primitive function type +/// arguments of `Search` with type `Replace`. +class TypeSubstitutor + : public llvm::itanium_demangle::AbstractManglingParser<TypeSubstitutor, + NodeAllocator> { + /// Input character until which we have constructed the respective output + /// already + const char *Written; + + llvm::StringRef Search; + llvm::StringRef Replace; + llvm::SmallString<128> Result; + + /// Whether we have performed any substitutions. + bool Substituted; + + void reset(llvm::StringRef Mangled, llvm::StringRef Search, + llvm::StringRef Replace) { + AbstractManglingParser::reset(Mangled.begin(), Mangled.end()); + Written = Mangled.begin(); + this->Search = Search; + this->Replace = Replace; + Result.clear(); + Substituted = false; + } + + void appendUnchangedInput() { + Result += llvm::StringRef(Written, First - Written); + Written = First; + } + +public: + TypeSubstitutor() : AbstractManglingParser(nullptr, nullptr) {} + + ConstString substitute(llvm::StringRef Mangled, llvm::StringRef From, + llvm::StringRef To) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); + + reset(Mangled, From, To); + if (parse() == nullptr) { + LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled); + return ConstString(); } - }; + if (!Substituted) + return ConstString(); - // FastDemangle will call our hook for each instance of a primitive type, - // allowing us to perform substitution - char *const demangled = - FastDemangle(mangled.str().c_str(), mangled.size(), swap_parms_hook); + // Append any trailing unmodified input. + appendUnchangedInput(); + LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result); + return ConstString(Result); + } - if (log) - log->Printf("substituted mangling for %s:{%s} %s:{%s}\n", - mangled.str().c_str(), demangled, output_buf.c_str(), - FastDemangle(output_buf.c_str())); - // FastDemangle malloc'd this string. - free(demangled); + llvm::itanium_demangle::Node *parseType() { + if (llvm::StringRef(First, numLeft()).startswith(Search)) { + // We found a match. Append unmodified input up to this point. + appendUnchangedInput(); - return output_buf == mangled ? ConstString() : ConstString(output_buf); + // And then perform the replacement. + Result += Replace; + Written += Search.size(); + Substituted = true; + } + return AbstractManglingParser::parseType(); + } +}; } uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings( @@ -348,23 +383,24 @@ uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings( alternates.insert(ConstString(fixed_scratch)); } + TypeSubstitutor TS; // `char` is implementation defined as either `signed` or `unsigned`. As a // result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed // char, 'h'-unsigned char. If we're looking for symbols with a signed char // parameter, try finding matches which have the general case 'c'. if (ConstString char_fixup = - SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "a", "c")) + TS.substitute(mangled_name.GetStringRef(), "a", "c")) alternates.insert(char_fixup); // long long parameter mangling 'x', may actually just be a long 'l' argument if (ConstString long_fixup = - SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "x", "l")) + TS.substitute(mangled_name.GetStringRef(), "x", "l")) alternates.insert(long_fixup); // unsigned long long parameter mangling 'y', may actually just be unsigned // long 'm' argument if (ConstString ulong_fixup = - SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "y", "m")) + TS.substitute(mangled_name.GetStringRef(), "y", "m")) alternates.insert(ulong_fixup); return alternates.size() - start_size; @@ -385,8 +421,17 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { #ifndef LLDB_DISABLE_PYTHON lldb::TypeSummaryImplSP std_string_summary_sp(new CXXFunctionSummaryFormat( - stl_summary_flags, lldb_private::formatters::LibcxxStringSummaryProvider, + stl_summary_flags, + lldb_private::formatters::LibcxxStringSummaryProviderASCII, "std::string summary provider")); + lldb::TypeSummaryImplSP std_stringu16_summary_sp(new CXXFunctionSummaryFormat( + stl_summary_flags, + lldb_private::formatters::LibcxxStringSummaryProviderUTF16, + "std::u16string summary provider")); + lldb::TypeSummaryImplSP std_stringu32_summary_sp(new CXXFunctionSummaryFormat( + stl_summary_flags, + lldb_private::formatters::LibcxxStringSummaryProviderUTF32, + "std::u32string summary provider")); lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat( stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider, "std::wstring summary provider")); @@ -400,6 +445,16 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "std::__1::allocator<char> >"), std_string_summary_sp); cpp_category_sp->GetTypeSummariesContainer()->Add( + ConstString( + "std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, " + "std::__1::allocator<char16_t> >"), + std_stringu16_summary_sp); + cpp_category_sp->GetTypeSummariesContainer()->Add( + ConstString( + "std::__1::basic_string<char32_t, std::__1::char_traits<char32_t>, " + "std::__1::allocator<char32_t> >"), + std_stringu32_summary_sp); + cpp_category_sp->GetTypeSummariesContainer()->Add( ConstString("std::__ndk1::basic_string<char, " "std::__ndk1::char_traits<char>, " "std::__ndk1::allocator<char> >"), @@ -493,6 +548,14 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "libc++ std::tuple synthetic children", ConstString("^std::__(ndk)?1::tuple<.*>(( )?&)?$"), stl_synth_flags, true); + AddCXXSynthetic(cpp_category_sp, LibcxxOptionalFrontEndCreator, + "libc++ std::optional synthetic children", + ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"), + stl_synth_flags, true); + AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator, + "libc++ std::variant synthetic children", + ConstString("^std::__(ndk)?1::variant<.+>(( )?&)?$"), + stl_synth_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator, @@ -519,6 +582,11 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { ConstString("^(std::__(ndk)?1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true); + AddCXXSummary( + cpp_category_sp, lldb_private::formatters::LibcxxFunctionSummaryProvider, + "libc++ std::function summary provider", + ConstString("^std::__(ndk)?1::function<.+>$"), stl_summary_flags, true); + stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(false); AddCXXSummary(cpp_category_sp, @@ -584,6 +652,16 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { cpp_category_sp, lldb_private::formatters::LibCxxAtomicSummaryProvider, "libc++ std::atomic summary provider", ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxOptionalSummaryProvider, + "libc++ std::optional summary provider", + ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"), + stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxVariantSummaryProvider, + "libc++ std::variant summary provider", + ConstString("^std::__(ndk)?1::variant<.+>(( )?&)?$"), + stl_summary_flags, true); stl_summary_flags.SetSkipPointers(true); @@ -610,11 +688,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "std::map iterator synthetic children", ConstString("^std::__(ndk)?1::__map_iterator<.+>$"), stl_synth_flags, true); - - AddCXXSynthetic( - cpp_category_sp, lldb_private::formatters::LibcxxFunctionFrontEndCreator, - "std::function synthetic value provider", - ConstString("^std::__(ndk)?1::function<.+>$"), stl_synth_flags, true); #endif } @@ -1002,3 +1075,16 @@ CPlusPlusLanguage::GetHardcodedSynthetics() { return g_formatters; } + +bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const { + const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c", + ".h", ".hh", ".hpp", ".hxx", ".h++"}; + for (auto suffix : suffixes) { + if (file_path.endswith_lower(suffix)) + return true; + } + + // Check if we're in a STL path (where the files usually have no extension + // that we could check for. + return file_path.contains("/usr/include/c++/"); +} diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h index 7380ef321305..3c8ca96e81f6 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -10,15 +10,12 @@ #ifndef liblldb_CPlusPlusLanguage_h_ #define liblldb_CPlusPlusLanguage_h_ -// C Includes -// C++ Includes #include <set> #include <vector> -// Other libraries and framework includes #include "llvm/ADT/StringRef.h" -// Project includes +#include "Plugins/Language/ClangCommon/ClangHighlighter.h" #include "lldb/Target/Language.h" #include "lldb/Utility/ConstString.h" #include "lldb/lldb-private.h" @@ -26,6 +23,8 @@ namespace lldb_private { class CPlusPlusLanguage : public Language { + ClangHighlighter m_highlighter; + public: class MethodName { public: @@ -90,6 +89,10 @@ public: HardcodedFormatters::HardcodedSyntheticFinder GetHardcodedSynthetics() override; + bool IsSourceFile(llvm::StringRef file_path) const override; + + const Highlighter *GetHighlighter() const override { return &m_highlighter; } + //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h index fe1d46f32c17..d46a53a7a704 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h @@ -10,16 +10,12 @@ #ifndef liblldb_CPlusPlusNameParser_h_ #define liblldb_CPlusPlusNameParser_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes #include "clang/Lex/Lexer.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -// Project includes #include "lldb/Utility/ConstString.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp index 0f6fb54e8384..24185b314466 100644 --- a/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp +++ b/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp @@ -100,8 +100,11 @@ bool lldb_private::formatters::WCharStringSummaryProvider( if (!wchar_compiler_type) return false; - const uint32_t wchar_size = wchar_compiler_type.GetBitSize( - nullptr); // Safe to pass NULL for exe_scope here + // Safe to pass nullptr for exe_scope here. + llvm::Optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr); + if (!size) + return false; + const uint32_t wchar_size = *size; StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); options.SetLocation(valobj_addr); @@ -194,8 +197,11 @@ bool lldb_private::formatters::WCharSummaryProvider( if (!wchar_compiler_type) return false; - const uint32_t wchar_size = wchar_compiler_type.GetBitSize( - nullptr); // Safe to pass NULL for exe_scope here + // Safe to pass nullptr for exe_scope here. + llvm::Optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr); + if (!size) + return false; + const uint32_t wchar_size = *size; StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); options.SetData(data); diff --git a/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 95e02a473cd7..7e8c06bd4c75 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -9,10 +9,7 @@ #include "LibCxx.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes +#include "llvm/ADT/ScopeExit.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/FormatEntity.h" #include "lldb/Core/ValueObject.h" @@ -22,7 +19,9 @@ #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/DataFormatters/VectorIterator.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Target/CPPLanguageRuntime.h" #include "lldb/Target/ProcessStructReader.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" @@ -33,6 +32,76 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; +bool lldb_private::formatters::LibcxxOptionalSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + // An optional either contains a value or not, the member __engaged_ is + // a bool flag, it is true if the optional has a value and false otherwise. + ValueObjectSP engaged_sp( + valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true)); + + if (!engaged_sp) + return false; + + llvm::StringRef engaged_as_cstring( + engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false"); + + stream.Printf(" Has Value=%s ", engaged_as_cstring.data()); + + return true; +} + +bool lldb_private::formatters::LibcxxFunctionSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + + if (!valobj_sp) + return false; + + ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + + if (process == nullptr) + return false; + + CPPLanguageRuntime *cpp_runtime = process->GetCPPLanguageRuntime(); + + if (!cpp_runtime) + return false; + + CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info = + cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp); + + switch (callable_info.callable_case) { + case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid: + stream.Printf(" __f_ = %" PRIu64, callable_info.member__f_pointer_value); + return false; + break; + case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda: + stream.Printf( + " Lambda in File %s at Line %u", + callable_info.callable_line_entry.file.GetFilename().GetCString(), + callable_info.callable_line_entry.line); + break; + case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject: + stream.Printf( + " Function in File %s at Line %u", + callable_info.callable_line_entry.file.GetFilename().GetCString(), + callable_info.callable_line_entry.line); + break; + case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction: + stream.Printf(" Function = %s ", + callable_info.callable_symbol.GetName().GetCString()); + break; + } + + return true; +} + bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); @@ -120,9 +189,9 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { if (!valobj_sp) return false; - + static ConstString g___i_("__i_"); - + // this must be a ValueObject* because it is a child of the ValueObject we // are producing children for it if were a ValueObjectSP, we would end up // with a loop (iterator -> synthetic -> child -> parent == iterator) and @@ -156,37 +225,53 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { m_pair_ptr = nullptr; return false; } - CompilerType pair_type(__i_->GetCompilerType().GetTypeTemplateArgument(0)); - std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr; - pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); + CompilerType pair_type( + __i_->GetCompilerType().GetTypeTemplateArgument(0)); + std::string name; + uint64_t bit_offset_ptr; + uint32_t bitfield_bit_size_ptr; + bool is_bitfield_ptr; + pair_type = pair_type.GetFieldAtIndex( + 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); if (!pair_type) { m_pair_ptr = nullptr; return false; } - + 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()); + if (addr && addr != LLDB_INVALID_ADDRESS) { + ClangASTContext *ast_ctx = + llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem()); if (!ast_ctx) return false; - CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), { - {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, - {"payload",pair_type} - }); - DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0)); + CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( + ConstString(), + {{"ptr0", + ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, + {"ptr1", + ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, + {"ptr2", + ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, + {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, + {"payload", pair_type}}); + llvm::Optional<uint64_t> size = tree_node_type.GetByteSize(nullptr); + if (!size) + return false; + DataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); ProcessSP process_sp(target_sp->GetProcessSP()); Status error; - process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error); + process_sp->ReadMemory(addr, buffer_sp->GetBytes(), + buffer_sp->GetByteSize(), error); if (error.Fail()) return false; - DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); - auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type); + DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), + process_sp->GetAddressByteSize()); + auto pair_sp = CreateValueObjectFromData( + "pair", extractor, valobj_sp->GetExecutionContextRef(), + tree_node_type); if (pair_sp) - m_pair_sp = pair_sp->GetChildAtIndex(4,true); + m_pair_sp = pair_sp->GetChildAtIndex(4, true); } } } @@ -491,6 +576,8 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( ->GetScratchClangASTContext() ->GetBasicType(lldb::eBasicTypeWChar) .GetByteSize(nullptr); + if (!wchar_t_size) + return false; options.SetData(extractor); options.SetStream(&stream); @@ -499,7 +586,7 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( options.SetSourceSize(size); options.SetBinaryZeroIsTerminator(false); - switch (wchar_t_size) { + switch (*wchar_t_size) { case 1: StringPrinter::ReadBufferAndDumpToStream< lldb_private::formatters::StringPrinter::StringElementType::UTF8>( @@ -526,9 +613,10 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( return true; } -bool lldb_private::formatters::LibcxxStringSummaryProvider( - ValueObject &valobj, Stream &stream, - const TypeSummaryOptions &summary_options) { +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; @@ -557,31 +645,37 @@ bool lldb_private::formatters::LibcxxStringSummaryProvider( options.SetData(extractor); options.SetStream(&stream); - options.SetPrefixToken(nullptr); + + if (prefix_token.empty()) + options.SetPrefixToken(nullptr); + else + options.SetPrefixToken(prefix_token); + options.SetQuote('"'); options.SetSourceSize(size); options.SetBinaryZeroIsTerminator(false); - StringPrinter::ReadBufferAndDumpToStream< - StringPrinter::StringElementType::ASCII>(options); + StringPrinter::ReadBufferAndDumpToStream<element_type>(options); return true; } -class LibcxxFunctionFrontEnd : public SyntheticValueProviderFrontEnd { -public: - LibcxxFunctionFrontEnd(ValueObject &backend) - : SyntheticValueProviderFrontEnd(backend) {} +bool lldb_private::formatters::LibcxxStringSummaryProviderASCII( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return LibcxxStringSummaryProvider<StringPrinter::StringElementType::ASCII>( + valobj, stream, summary_options); +} - lldb::ValueObjectSP GetSyntheticValue() override { - static ConstString g___f_("__f_"); - return m_backend.GetChildMemberWithName(g___f_, true); - } -}; +bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF16>( + valobj, stream, summary_options, "u"); +} -SyntheticChildrenFrontEnd * -lldb_private::formatters::LibcxxFunctionFrontEndCreator( - CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { - if (valobj_sp) - return new LibcxxFunctionFrontEnd(*valobj_sp); - return nullptr; +bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF32>( + valobj, stream, summary_options, "U"); } diff --git a/source/Plugins/Language/CPlusPlus/LibCxx.h b/source/Plugins/Language/CPlusPlus/LibCxx.h index 3f6e0d6e14d7..224a540eda04 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -19,19 +19,35 @@ namespace lldb_private { namespace formatters { -bool LibcxxStringSummaryProvider( +bool LibcxxStringSummaryProviderASCII( ValueObject &valobj, Stream &stream, - const TypeSummaryOptions &options); // libc++ std::string + const TypeSummaryOptions &summary_options); // libc++ std::string + +bool LibcxxStringSummaryProviderUTF16( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options); // libc++ std::u16string + +bool LibcxxStringSummaryProviderUTF32( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options); // libc++ std::u32string bool LibcxxWStringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::wstring +bool LibcxxOptionalSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); // libc++ std::optional<> + bool LibcxxSmartPointerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::shared_ptr<> and std::weak_ptr<> +bool LibcxxFunctionSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); // libc++ std::function<> + SyntheticChildrenFrontEnd * LibcxxVectorBoolSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -124,15 +140,20 @@ SyntheticChildrenFrontEnd * LibcxxInitializerListSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); -SyntheticChildrenFrontEnd *LibcxxFunctionFrontEndCreator(CXXSyntheticChildren *, - lldb::ValueObjectSP); - SyntheticChildrenFrontEnd *LibcxxQueueFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); SyntheticChildrenFrontEnd *LibcxxTupleFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +SyntheticChildrenFrontEnd * +LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp); + +SyntheticChildrenFrontEnd * +LibcxxVariantFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp); + } // namespace formatters } // namespace lldb_private diff --git a/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp b/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp index 0cdb0b26cf3b..489ac4d96072 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp @@ -79,17 +79,24 @@ ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) { CompilerType type; ValueObjectSP chunk; // For small bitsets __first_ is not an array, but a plain size_t. - if (m_first->GetCompilerType().IsArrayType(&type, nullptr, nullptr)) - chunk = m_first->GetChildAtIndex( - idx / type.GetBitSize(ctx.GetBestExecutionContextScope()), true); - else { + if (m_first->GetCompilerType().IsArrayType(&type, nullptr, nullptr)) { + llvm::Optional<uint64_t> bit_size = + type.GetBitSize(ctx.GetBestExecutionContextScope()); + if (!bit_size || *bit_size == 0) + return {}; + chunk = m_first->GetChildAtIndex(idx / *bit_size, true); + } else { type = m_first->GetCompilerType(); chunk = m_first; } if (!type || !chunk) - return ValueObjectSP(); + return {}; - size_t chunk_idx = idx % type.GetBitSize(ctx.GetBestExecutionContextScope()); + llvm::Optional<uint64_t> bit_size = + type.GetBitSize(ctx.GetBestExecutionContextScope()); + if (!bit_size || *bit_size == 0) + return {}; + size_t chunk_idx = idx % *bit_size; uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx)); DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size); diff --git a/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp b/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp index 5823f6f3e038..390483d02668 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "LibCxx.h" #include "lldb/Core/ValueObject.h" @@ -98,12 +94,11 @@ bool lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd:: if (!m_element_type.IsValid()) return false; - m_element_size = m_element_type.GetByteSize(nullptr); - - if (m_element_size > 0) - m_start = - m_backend.GetChildMemberWithName(g___begin_, true) - .get(); // store raw pointers or end up with a circular dependency + if (llvm::Optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) { + m_element_size = *size; + // Store raw pointers or end up with a circular dependency. + m_start = m_backend.GetChildMemberWithName(g___begin_, true).get(); + } return false; } diff --git a/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 6066f14b18cc..81606b573cea 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "LibCxx.h" #include "lldb/Core/ValueObject.h" diff --git a/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index 8f82bdcbfd59..429569d57928 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "LibCxx.h" #include "lldb/Core/ValueObject.h" diff --git a/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp b/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp new file mode 100644 index 000000000000..762b824f262a --- /dev/null +++ b/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp @@ -0,0 +1,85 @@ +//===-- LibCxxOptional.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LibCxx.h" +#include "lldb/DataFormatters/FormattersHelpers.h" + +using namespace lldb; +using namespace lldb_private; + +namespace { + +class OptionalFrontEnd : public SyntheticChildrenFrontEnd { +public: + OptionalFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) { + Update(); + } + + size_t GetIndexOfChildWithName(const ConstString &name) override { + return formatters::ExtractIndexFromString(name.GetCString()); + } + + bool MightHaveChildren() override { return true; } + bool Update() override; + size_t CalculateNumChildren() override { return m_size; } + ValueObjectSP GetChildAtIndex(size_t idx) override; + +private: + size_t m_size = 0; + ValueObjectSP m_base_sp; +}; +} // namespace + +bool OptionalFrontEnd::Update() { + ValueObjectSP engaged_sp( + m_backend.GetChildMemberWithName(ConstString("__engaged_"), true)); + + if (!engaged_sp) + return false; + + // __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); + + return false; +} + +ValueObjectSP OptionalFrontEnd::GetChildAtIndex(size_t idx) { + if (idx >= m_size) + return ValueObjectSP(); + + // __val_ contains the underlying value of an optional if it has one. + // Currently because it is part of an anonymous union GetChildMemberWithName() + // does not peer through and find it unless we are at the parent itself. + // We can obtain the parent through __engaged_. + ValueObjectSP val_sp( + m_backend.GetChildMemberWithName(ConstString("__engaged_"), true) + ->GetParent() + ->GetChildAtIndex(0, true) + ->GetChildMemberWithName(ConstString("__val_"), true)); + + if (!val_sp) + return ValueObjectSP(); + + CompilerType holder_type = val_sp->GetCompilerType(); + + if (!holder_type) + return ValueObjectSP(); + + return val_sp->Clone(ConstString(llvm::formatv("Value").str())); +} + +SyntheticChildrenFrontEnd * +formatters::LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp) { + if (valobj_sp) + return new OptionalFrontEnd(*valobj_sp); + return nullptr; +} diff --git a/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index 0f1c2537d651..51ae8cb3184c 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "LibCxx.h" #include "lldb/Core/ValueObject.h" diff --git a/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp b/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp new file mode 100644 index 000000000000..e874616c3251 --- /dev/null +++ b/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp @@ -0,0 +1,256 @@ +//===-- LibCxxVariant.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LibCxxVariant.h" +#include "lldb/DataFormatters/FormattersHelpers.h" + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/ScopeExit.h" + +using namespace lldb; +using namespace lldb_private; + +// libc++ variant implementation contains two members that we care about both +// are contained in the __impl member. +// - __index which tells us which of the variadic template types is the active +// type for the variant +// - __data is a variadic union which recursively contains itself as member +// which refers to the tailing variadic types. +// - __head which refers to the leading non pack type +// - __value refers to the actual value contained +// - __tail which refers to the remaining pack types +// +// e.g. given std::variant<int,double,char> v1 +// +// (lldb) frame var -R v1.__impl.__data +//(... __union<... 0, int, double, char>) v1.__impl.__data = { +// ... +// __head = { +// __value = ... +// } +// __tail = { +// ... +// __head = { +// __value = ... +// } +// __tail = { +// ... +// __head = { +// __value = ... +// ... +// +// So given +// - __index equal to 0 the active value is contained in +// +// __data.__head.__value +// +// - __index equal to 1 the active value is contained in +// +// __data.__tail.__head.__value +// +// - __index equal to 2 the active value is contained in +// +// __data.__tail.__tail.__head.__value +// + +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 }; + +LibcxxVariantIndexValidity +LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) { + ValueObjectSP index_sp( + impl_sp->GetChildMemberWithName(ConstString("__index"), true)); + + if (!index_sp) + return LibcxxVariantIndexValidity::INVALID; + + int64_t index_value = index_sp->GetValueAsSigned(0); + + if (index_value == -1) + return LibcxxVariantIndexValidity::NPOS; + + return LibcxxVariantIndexValidity::VALID; +} + +llvm::Optional<uint64_t> LibcxxVariantIndexValue(ValueObjectSP &impl_sp) { + ValueObjectSP index_sp( + impl_sp->GetChildMemberWithName(ConstString("__index"), true)); + + if (!index_sp) + return {}; + + return {index_sp->GetValueAsUnsigned(0)}; +} + +ValueObjectSP LibcxxVariantGetNthHead(ValueObjectSP &impl_sp, uint64_t index) { + ValueObjectSP data_sp( + impl_sp->GetChildMemberWithName(ConstString("__data"), true)); + + if (!data_sp) + return ValueObjectSP{}; + + ValueObjectSP current_level = data_sp; + for (uint64_t n = index; n != 0; --n) { + ValueObjectSP tail_sp( + current_level->GetChildMemberWithName(ConstString("__tail"), true)); + + if (!tail_sp) + return ValueObjectSP{}; + + current_level = tail_sp; + } + + return current_level->GetChildMemberWithName(ConstString("__head"), true); +} +} // namespace + +namespace lldb_private { +namespace formatters { +bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + ValueObjectSP impl_sp( + valobj_sp->GetChildMemberWithName(ConstString("__impl"), true)); + + if (!impl_sp) + return false; + + LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp); + + if (validity == LibcxxVariantIndexValidity::INVALID) + return false; + + if (validity == LibcxxVariantIndexValidity::NPOS) { + stream.Printf(" No Value"); + return true; + } + + auto optional_index_value = LibcxxVariantIndexValue(impl_sp); + + if (!optional_index_value) + return false; + + uint64_t index_value = *optional_index_value; + + ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value); + + if (!nth_head) + return false; + + CompilerType head_type = nth_head->GetCompilerType(); + + if (!head_type) + return false; + + CompilerType template_type = head_type.GetTypeTemplateArgument(1); + + if (!template_type) + return false; + + stream.Printf(" Active Type = %s ", template_type.GetTypeName().GetCString()); + + return true; +} +} // namespace formatters +} // namespace lldb_private + +namespace { +class VariantFrontEnd : public SyntheticChildrenFrontEnd { +public: + VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) { + Update(); + } + + size_t GetIndexOfChildWithName(const ConstString &name) override { + return formatters::ExtractIndexFromString(name.GetCString()); + } + + bool MightHaveChildren() override { return true; } + bool Update() override; + size_t CalculateNumChildren() override { return m_size; } + ValueObjectSP GetChildAtIndex(size_t idx) override; + +private: + size_t m_size = 0; + ValueObjectSP m_base_sp; +}; +} // namespace + +bool VariantFrontEnd::Update() { + m_size = 0; + ValueObjectSP impl_sp( + m_backend.GetChildMemberWithName(ConstString("__impl"), true)); + if (!impl_sp) + return false; + + LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp); + + if (validity == LibcxxVariantIndexValidity::INVALID) + return false; + + if (validity == LibcxxVariantIndexValidity::NPOS) + return true; + + m_size = 1; + + return false; +} + +ValueObjectSP VariantFrontEnd::GetChildAtIndex(size_t idx) { + if (idx >= m_size) + return ValueObjectSP(); + + ValueObjectSP impl_sp( + m_backend.GetChildMemberWithName(ConstString("__impl"), true)); + + auto optional_index_value = LibcxxVariantIndexValue(impl_sp); + + if (!optional_index_value) + return ValueObjectSP(); + + uint64_t index_value = *optional_index_value; + + ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value); + + if (!nth_head) + return ValueObjectSP(); + + CompilerType head_type = nth_head->GetCompilerType(); + + if (!head_type) + return ValueObjectSP(); + + CompilerType template_type = head_type.GetTypeTemplateArgument(1); + + if (!template_type) + return ValueObjectSP(); + + ValueObjectSP head_value( + nth_head->GetChildMemberWithName(ConstString("__value"), true)); + + if (!head_value) + return ValueObjectSP(); + + return head_value->Clone(ConstString(ConstString("Value").AsCString())); +} + +SyntheticChildrenFrontEnd * +formatters::LibcxxVariantFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp) { + if (valobj_sp) + return new VariantFrontEnd(*valobj_sp); + return nullptr; +} diff --git a/source/Plugins/Language/CPlusPlus/LibCxxVariant.h b/source/Plugins/Language/CPlusPlus/LibCxxVariant.h new file mode 100644 index 000000000000..04834581963f --- /dev/null +++ b/source/Plugins/Language/CPlusPlus/LibCxxVariant.h @@ -0,0 +1,31 @@ +//===-- LibCxxVariant.h -------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_LibCxxVariant_h_ +#define liblldb_LibCxxVariant_h_ + +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/DataFormatters/TypeSynthetic.h" +#include "lldb/Utility/Stream.h" + +namespace lldb_private { +namespace formatters { +bool LibcxxVariantSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); // libc++ std::variant<> + +SyntheticChildrenFrontEnd *LibcxxVariantFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + +} // namespace formatters +} // namespace lldb_private + +#endif // liblldb_LibCxxVariant_h_ diff --git a/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp index 711130639cd2..ed405c875174 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "LibCxx.h" #include "lldb/Core/ValueObject.h" @@ -149,14 +145,16 @@ bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() { if (!data_type_finder_sp) return false; m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType(); - m_element_size = m_element_type.GetByteSize(nullptr); - - if (m_element_size > 0) { - // store raw pointers or end up with a circular dependency - m_start = - m_backend.GetChildMemberWithName(ConstString("__begin_"), true).get(); - m_finish = - m_backend.GetChildMemberWithName(ConstString("__end_"), true).get(); + if (llvm::Optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) { + m_element_size = *size; + + if (m_element_size > 0) { + // store raw pointers or end up with a circular dependency + m_start = + m_backend.GetChildMemberWithName(ConstString("__begin_"), true).get(); + m_finish = + m_backend.GetChildMemberWithName(ConstString("__end_"), true).get(); + } } return false; } @@ -196,27 +194,29 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex( if (iter != end) return iter->second; if (idx >= m_count) - return ValueObjectSP(); + return {}; if (m_base_data_address == 0 || m_count == 0) - return ValueObjectSP(); + return {}; if (!m_bool_type) - return ValueObjectSP(); + return {}; size_t byte_idx = (idx >> 3); // divide by 8 to get byte index size_t bit_index = (idx & 7); // efficient idx % 8 for bit index lldb::addr_t byte_location = m_base_data_address + byte_idx; ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP()); if (!process_sp) - return ValueObjectSP(); + return {}; uint8_t byte = 0; uint8_t mask = 0; Status err; size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err); if (err.Fail() || bytes_read == 0) - return ValueObjectSP(); + return {}; mask = 1 << bit_index; bool bit_set = ((byte & mask) != 0); - DataBufferSP buffer_sp( - new DataBufferHeap(m_bool_type.GetByteSize(nullptr), 0)); + llvm::Optional<uint64_t> size = m_bool_type.GetByteSize(nullptr); + if (!size) + return {}; + DataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); if (bit_set && buffer_sp && buffer_sp->GetBytes()) { // regardless of endianness, anything non-zero is true *(buffer_sp->GetBytes()) = 1; diff --git a/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp index 3e2b7159f894..695371fc3992 100644 --- a/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -9,10 +9,6 @@ #include "LibStdcpp.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/StringPrinter.h" @@ -301,8 +297,11 @@ bool lldb_private::formatters::LibStdcppWStringSummaryProvider( if (!wchar_compiler_type) return false; - const uint32_t wchar_size = wchar_compiler_type.GetBitSize( - nullptr); // Safe to pass NULL for exe_scope here + // Safe to pass nullptr for exe_scope here. + llvm::Optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr); + if (!size) + return false; + const uint32_t wchar_size = *size; StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); Status error; diff --git a/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp b/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp new file mode 100644 index 000000000000..84f03e0e3016 --- /dev/null +++ b/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp @@ -0,0 +1,99 @@ +//===-- MSVCUndecoratedNameParser.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MSVCUndecoratedNameParser.h" + +#include <stack> + +MSVCUndecoratedNameParser::MSVCUndecoratedNameParser(llvm::StringRef name) { + std::size_t last_base_start = 0; + + std::stack<std::size_t> stack; + unsigned int open_angle_brackets = 0; + for (size_t i = 0; i < name.size(); i++) { + switch (name[i]) { + case '<': + // Do not treat `operator<' and `operator<<' as templates + // (sometimes they represented as `<' and `<<' in the name). + if (i == last_base_start || + (i == last_base_start + 1 && name[last_base_start] == '<')) + break; + + stack.push(i); + open_angle_brackets++; + + break; + case '>': + if (!stack.empty() && name[stack.top()] == '<') { + open_angle_brackets--; + stack.pop(); + } + + break; + case '`': + stack.push(i); + + break; + case '\'': + while (!stack.empty()) { + std::size_t top = stack.top(); + if (name[top] == '<') + open_angle_brackets--; + + stack.pop(); + + if (name[top] == '`') + break; + } + + break; + case ':': + if (open_angle_brackets) + break; + if (i == 0 || name[i - 1] != ':') + break; + + m_specifiers.emplace_back(name.take_front(i - 1), + name.slice(last_base_start, i - 1)); + + last_base_start = i + 1; + break; + default: + break; + } + } + + m_specifiers.emplace_back(name, name.drop_front(last_base_start)); +} + +bool MSVCUndecoratedNameParser::IsMSVCUndecoratedName(llvm::StringRef name) { + return name.find('`') != llvm::StringRef::npos; +} + +bool MSVCUndecoratedNameParser::ExtractContextAndIdentifier( + llvm::StringRef name, llvm::StringRef &context, + llvm::StringRef &identifier) { + MSVCUndecoratedNameParser parser(name); + llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers(); + + std::size_t count = specs.size(); + identifier = count > 0 ? specs[count - 1].GetBaseName() : ""; + context = count > 1 ? specs[count - 2].GetFullName() : ""; + + return count; +} + +llvm::StringRef MSVCUndecoratedNameParser::DropScope(llvm::StringRef name) { + MSVCUndecoratedNameParser parser(name); + llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers(); + if (specs.empty()) + return ""; + + return specs[specs.size() - 1].GetBaseName(); +} diff --git a/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h b/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h new file mode 100644 index 000000000000..0c49100d8d49 --- /dev/null +++ b/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h @@ -0,0 +1,51 @@ +//===-- MSVCUndecoratedNameParser.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_MSVCUndecoratedNameParser_h_ +#define liblldb_MSVCUndecoratedNameParser_h_ + +#include <vector> + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +class MSVCUndecoratedNameSpecifier { +public: + MSVCUndecoratedNameSpecifier(llvm::StringRef full_name, + llvm::StringRef base_name) + : m_full_name(full_name), m_base_name(base_name) {} + + llvm::StringRef GetFullName() const { return m_full_name; } + llvm::StringRef GetBaseName() const { return m_base_name; } + +private: + llvm::StringRef m_full_name; + llvm::StringRef m_base_name; +}; + +class MSVCUndecoratedNameParser { +public: + explicit MSVCUndecoratedNameParser(llvm::StringRef name); + + llvm::ArrayRef<MSVCUndecoratedNameSpecifier> GetSpecifiers() const { + return m_specifiers; + } + + static bool IsMSVCUndecoratedName(llvm::StringRef name); + static bool ExtractContextAndIdentifier(llvm::StringRef name, + llvm::StringRef &context, + llvm::StringRef &identifier); + + static llvm::StringRef DropScope(llvm::StringRef name); + +private: + std::vector<MSVCUndecoratedNameSpecifier> m_specifiers; +}; + +#endif diff --git a/source/Plugins/Language/ClangCommon/CMakeLists.txt b/source/Plugins/Language/ClangCommon/CMakeLists.txt new file mode 100644 index 000000000000..854320dd312e --- /dev/null +++ b/source/Plugins/Language/ClangCommon/CMakeLists.txt @@ -0,0 +1,9 @@ +add_lldb_library(lldbPluginClangCommon PLUGIN + ClangHighlighter.cpp + + LINK_LIBS + lldbCore + lldbUtility + LINK_COMPONENTS + Support +) diff --git a/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp b/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp new file mode 100644 index 000000000000..1fe8482263eb --- /dev/null +++ b/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp @@ -0,0 +1,237 @@ +//===-- ClangHighlighter.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClangHighlighter.h" + +#include "lldb/Target/Language.h" +#include "lldb/Utility/AnsiTerminal.h" +#include "lldb/Utility/StreamString.h" + +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace lldb_private; + +bool ClangHighlighter::isKeyword(llvm::StringRef token) const { + return keywords.find(token) != keywords.end(); +} + +ClangHighlighter::ClangHighlighter() { +#define KEYWORD(X, N) keywords.insert(#X); +#include "clang/Basic/TokenKinds.def" +} + +/// Determines which style should be applied to the given token. +/// \param highlighter +/// The current highlighter that should use the style. +/// \param token +/// The current token. +/// \param tok_str +/// The string in the source code the token represents. +/// \param options +/// The style we use for coloring the source code. +/// \param in_pp_directive +/// If we are currently in a preprocessor directive. NOTE: This is +/// passed by reference and will be updated if the current token starts +/// or ends a preprocessor directive. +/// \return +/// The ColorStyle that should be applied to the token. +static HighlightStyle::ColorStyle +determineClangStyle(const ClangHighlighter &highlighter, + const clang::Token &token, llvm::StringRef tok_str, + const HighlightStyle &options, bool &in_pp_directive) { + using namespace clang; + + if (token.is(tok::comment)) { + // If we were in a preprocessor directive before, we now left it. + in_pp_directive = false; + return options.comment; + } else if (in_pp_directive || token.getKind() == tok::hash) { + // Let's assume that the rest of the line is a PP directive. + in_pp_directive = true; + // Preprocessor directives are hard to match, so we have to hack this in. + return options.pp_directive; + } else if (tok::isStringLiteral(token.getKind())) + return options.string_literal; + else if (tok::isLiteral(token.getKind())) + return options.scalar_literal; + else if (highlighter.isKeyword(tok_str)) + return options.keyword; + else + switch (token.getKind()) { + case tok::raw_identifier: + case tok::identifier: + return options.identifier; + case tok::l_brace: + case tok::r_brace: + return options.braces; + case tok::l_square: + case tok::r_square: + return options.square_brackets; + case tok::l_paren: + case tok::r_paren: + return options.parentheses; + case tok::comma: + return options.comma; + case tok::coloncolon: + case tok::colon: + return options.colon; + + case tok::amp: + case tok::ampamp: + case tok::ampequal: + case tok::star: + case tok::starequal: + case tok::plus: + case tok::plusplus: + case tok::plusequal: + case tok::minus: + case tok::arrow: + case tok::minusminus: + case tok::minusequal: + case tok::tilde: + case tok::exclaim: + case tok::exclaimequal: + case tok::slash: + case tok::slashequal: + case tok::percent: + case tok::percentequal: + case tok::less: + case tok::lessless: + case tok::lessequal: + case tok::lesslessequal: + case tok::spaceship: + case tok::greater: + case tok::greatergreater: + case tok::greaterequal: + case tok::greatergreaterequal: + case tok::caret: + case tok::caretequal: + case tok::pipe: + case tok::pipepipe: + case tok::pipeequal: + case tok::question: + case tok::equal: + case tok::equalequal: + return options.operators; + default: + break; + } + return HighlightStyle::ColorStyle(); +} + +void ClangHighlighter::Highlight(const HighlightStyle &options, + llvm::StringRef line, + llvm::Optional<size_t> cursor_pos, + llvm::StringRef previous_lines, + Stream &result) const { + using namespace clang; + + FileSystemOptions file_opts; + FileManager file_mgr(file_opts); + + unsigned line_number = previous_lines.count('\n') + 1U; + + // Let's build the actual source code Clang needs and setup some utility + // objects. + std::string full_source = previous_lines.str() + line.str(); + llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts( + new DiagnosticOptions()); + DiagnosticsEngine diags(diag_ids, diags_opts); + clang::SourceManager SM(diags, file_mgr); + auto buf = llvm::MemoryBuffer::getMemBuffer(full_source); + + FileID FID = SM.createFileID(clang::SourceManager::Unowned, buf.get()); + + // Let's just enable the latest ObjC and C++ which should get most tokens + // right. + LangOptions Opts; + Opts.ObjC = true; + // FIXME: This should probably set CPlusPlus, CPlusPlus11, ... too + Opts.CPlusPlus17 = true; + Opts.LineComment = true; + + Lexer lex(FID, buf.get(), SM, Opts); + // The lexer should keep whitespace around. + lex.SetKeepWhitespaceMode(true); + + // Keeps track if we have entered a PP directive. + bool in_pp_directive = false; + + // True once we actually lexed the user provided line. + bool found_user_line = false; + + // True if we already highlighted the token under the cursor, false otherwise. + bool highlighted_cursor = false; + Token token; + bool exit = false; + while (!exit) { + // Returns true if this is the last token we get from the lexer. + exit = lex.LexFromRawLexer(token); + + bool invalid = false; + unsigned current_line_number = + SM.getSpellingLineNumber(token.getLocation(), &invalid); + if (current_line_number != line_number) + continue; + found_user_line = true; + + // We don't need to print any tokens without a spelling line number. + if (invalid) + continue; + + // Same as above but with the column number. + invalid = false; + unsigned start = SM.getSpellingColumnNumber(token.getLocation(), &invalid); + if (invalid) + continue; + // Column numbers start at 1, but indexes in our string start at 0. + --start; + + // Annotations don't have a length, so let's skip them. + if (token.isAnnotation()) + continue; + + // Extract the token string from our source code. + llvm::StringRef tok_str = line.substr(start, token.getLength()); + + // If the token is just an empty string, we can skip all the work below. + if (tok_str.empty()) + continue; + + // If the cursor is inside this token, we have to apply the 'selected' + // highlight style before applying the actual token color. + llvm::StringRef to_print = tok_str; + StreamString storage; + auto end = start + token.getLength(); + if (cursor_pos && end > *cursor_pos && !highlighted_cursor) { + highlighted_cursor = true; + options.selected.Apply(storage, tok_str); + to_print = storage.GetString(); + } + + // See how we are supposed to highlight this token. + HighlightStyle::ColorStyle color = + determineClangStyle(*this, token, tok_str, options, in_pp_directive); + + color.Apply(result, to_print); + } + + // If we went over the whole file but couldn't find our own file, then + // somehow our setup was wrong. When we're in release mode we just give the + // user the normal line and pretend we don't know how to highlight it. In + // debug mode we bail out with an assert as this should never happen. + if (!found_user_line) { + result << line; + assert(false && "We couldn't find the user line in the input file?"); + } +} diff --git a/source/Plugins/Language/ClangCommon/ClangHighlighter.h b/source/Plugins/Language/ClangCommon/ClangHighlighter.h new file mode 100644 index 000000000000..579c4315228f --- /dev/null +++ b/source/Plugins/Language/ClangCommon/ClangHighlighter.h @@ -0,0 +1,38 @@ +//===-- ClangHighlighter.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ClangHighlighter_h_ +#define liblldb_ClangHighlighter_h_ + +#include "lldb/Utility/Stream.h" +#include "llvm/ADT/StringSet.h" + +#include "lldb/Core/Highlighter.h" + +namespace lldb_private { + +class ClangHighlighter : public Highlighter { + llvm::StringSet<> keywords; + +public: + ClangHighlighter(); + llvm::StringRef GetName() const override { return "clang"; } + + void Highlight(const HighlightStyle &options, llvm::StringRef line, + llvm::Optional<size_t> cursor_pos, + llvm::StringRef previous_lines, Stream &s) const override; + + /// Returns true if the given string represents a keywords in any Clang + /// supported language. + bool isKeyword(llvm::StringRef token) const; +}; + +} // namespace lldb_private + +#endif // liblldb_ClangHighlighter_h_ diff --git a/source/Plugins/Language/Go/CMakeLists.txt b/source/Plugins/Language/Go/CMakeLists.txt deleted file mode 100644 index 793e417a618a..000000000000 --- a/source/Plugins/Language/Go/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_lldb_library(lldbPluginGoLanguage PLUGIN - GoLanguage.cpp - GoFormatterFunctions.cpp - - LINK_LIBS - clangAST - lldbCore - lldbDataFormatters - lldbSymbol - lldbTarget - LINK_COMPONENTS - Support -) diff --git a/source/Plugins/Language/Go/GoFormatterFunctions.cpp b/source/Plugins/Language/Go/GoFormatterFunctions.cpp deleted file mode 100644 index aac75205c6ef..000000000000 --- a/source/Plugins/Language/Go/GoFormatterFunctions.cpp +++ /dev/null @@ -1,152 +0,0 @@ -//===-- GoFormatterFunctions.cpp---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// C Includes -// C++ Includes -#include <map> - -// Other libraries and framework includes -// Project includes -#include "GoFormatterFunctions.h" -#include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/DataFormatters/StringPrinter.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::formatters; - -namespace { -class GoSliceSyntheticFrontEnd : public SyntheticChildrenFrontEnd { -public: - GoSliceSyntheticFrontEnd(ValueObject &valobj) - : SyntheticChildrenFrontEnd(valobj) { - Update(); - } - - ~GoSliceSyntheticFrontEnd() override = default; - - size_t CalculateNumChildren() override { return m_len; } - - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { - if (idx < m_len) { - ValueObjectSP &cached = m_children[idx]; - if (!cached) { - StreamString idx_name; - idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); - lldb::addr_t object_at_idx = m_base_data_address; - object_at_idx += idx * m_type.GetByteSize(nullptr); - cached = CreateValueObjectFromAddress( - idx_name.GetString(), object_at_idx, - m_backend.GetExecutionContextRef(), m_type); - } - return cached; - } - return ValueObjectSP(); - } - - bool Update() override { - size_t old_count = m_len; - - ConstString array_const_str("array"); - ValueObjectSP array_sp = - m_backend.GetChildMemberWithName(array_const_str, true); - if (!array_sp) { - m_children.clear(); - return old_count == 0; - } - m_type = array_sp->GetCompilerType().GetPointeeType(); - m_base_data_address = array_sp->GetPointerValue(); - - ConstString len_const_str("len"); - ValueObjectSP len_sp = - m_backend.GetChildMemberWithName(len_const_str, true); - if (len_sp) { - m_len = len_sp->GetValueAsUnsigned(0); - m_children.clear(); - } - - return old_count == m_len; - } - - bool MightHaveChildren() override { return true; } - - size_t GetIndexOfChildWithName(const ConstString &name) override { - return ExtractIndexFromString(name.AsCString()); - } - -private: - CompilerType m_type; - lldb::addr_t m_base_data_address; - size_t m_len; - std::map<size_t, lldb::ValueObjectSP> m_children; -}; - -} // anonymous namespace - -bool lldb_private::formatters::GoStringSummaryProvider( - ValueObject &valobj, Stream &stream, const TypeSummaryOptions &opts) { - ProcessSP process_sp = valobj.GetProcessSP(); - if (!process_sp) - return false; - - if (valobj.IsPointerType()) { - Status err; - ValueObjectSP deref = valobj.Dereference(err); - if (!err.Success()) - return false; - return GoStringSummaryProvider(*deref, stream, opts); - } - - ConstString str_name("str"); - ConstString len_name("len"); - - ValueObjectSP data_sp = valobj.GetChildMemberWithName(str_name, true); - ValueObjectSP len_sp = valobj.GetChildMemberWithName(len_name, true); - if (!data_sp || !len_sp) - return false; - bool success; - lldb::addr_t valobj_addr = data_sp->GetValueAsUnsigned(0, &success); - - if (!success) - return false; - - uint64_t length = len_sp->GetValueAsUnsigned(0); - if (length == 0) { - stream.Printf("\"\""); - return true; - } - - StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); - options.SetLocation(valobj_addr); - options.SetProcessSP(process_sp); - options.SetStream(&stream); - options.SetSourceSize(length); - options.SetNeedsZeroTermination(false); - options.SetLanguage(eLanguageTypeGo); - - if (!StringPrinter::ReadStringAndDumpToStream< - StringPrinter::StringElementType::UTF8>(options)) { - stream.Printf("Summary Unavailable"); - return true; - } - - return true; -} - -SyntheticChildrenFrontEnd * -lldb_private::formatters::GoSliceSyntheticFrontEndCreator( - CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { - if (!valobj_sp) - return nullptr; - - lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); - if (!process_sp) - return nullptr; - return new GoSliceSyntheticFrontEnd(*valobj_sp); -} diff --git a/source/Plugins/Language/Go/GoFormatterFunctions.h b/source/Plugins/Language/Go/GoFormatterFunctions.h deleted file mode 100644 index 1bf1892d6669..000000000000 --- a/source/Plugins/Language/Go/GoFormatterFunctions.h +++ /dev/null @@ -1,43 +0,0 @@ -//===-- GoFormatterFunctions.h-----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_GoFormatterFunctions_h_ -#define liblldb_GoFormatterFunctions_h_ - -// C Includes -#include <stdint.h> -#include <time.h> - -// C++ Includes -// Other libraries and framework includes -#include "clang/AST/ASTContext.h" - -// Project includes -#include "lldb/lldb-forward.h" - -#include "lldb/DataFormatters/FormatClasses.h" -#include "lldb/DataFormatters/TypeSynthetic.h" -#include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/ObjCLanguageRuntime.h" -#include "lldb/Target/Target.h" -#include "lldb/Utility/ConstString.h" - -namespace lldb_private { -namespace formatters { - -bool GoStringSummaryProvider(ValueObject &valobj, Stream &stream, - const TypeSummaryOptions &options); - -SyntheticChildrenFrontEnd * -GoSliceSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); - -} // namespace formatters -} // namespace lldb_private - -#endif // liblldb_GoFormatterFunctions_h_ diff --git a/source/Plugins/Language/Go/GoLanguage.cpp b/source/Plugins/Language/Go/GoLanguage.cpp deleted file mode 100644 index 66b4530abc76..000000000000 --- a/source/Plugins/Language/Go/GoLanguage.cpp +++ /dev/null @@ -1,127 +0,0 @@ -//===-- GoLanguage.cpp ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// C Includes -#include <string.h> -// C++ Includes -#include <functional> -#include <mutex> - -// Other libraries and framework includes -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Threading.h" - -// Project includes -#include "GoLanguage.h" -#include "Plugins/Language/Go/GoFormatterFunctions.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/GoASTContext.h" -#include "lldb/Utility/ConstString.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::formatters; - -void GoLanguage::Initialize() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), "Go Language", - CreateInstance); -} - -void GoLanguage::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -lldb_private::ConstString GoLanguage::GetPluginNameStatic() { - static ConstString g_name("Go"); - return g_name; -} - -//------------------------------------------------------------------ -// PluginInterface protocol -//------------------------------------------------------------------ -lldb_private::ConstString GoLanguage::GetPluginName() { - return GetPluginNameStatic(); -} - -uint32_t GoLanguage::GetPluginVersion() { return 1; } - -//------------------------------------------------------------------ -// Static Functions -//------------------------------------------------------------------ -Language *GoLanguage::CreateInstance(lldb::LanguageType language) { - if (language == eLanguageTypeGo) - return new GoLanguage(); - return nullptr; -} - -HardcodedFormatters::HardcodedSummaryFinder -GoLanguage::GetHardcodedSummaries() { - static llvm::once_flag g_initialize; - static HardcodedFormatters::HardcodedSummaryFinder g_formatters; - - llvm::call_once(g_initialize, []() -> void { - g_formatters.push_back( - [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, - FormatManager &) -> TypeSummaryImpl::SharedPointer { - static CXXFunctionSummaryFormat::SharedPointer formatter_sp( - new CXXFunctionSummaryFormat( - TypeSummaryImpl::Flags().SetDontShowChildren(true), - lldb_private::formatters::GoStringSummaryProvider, - "Go string summary provider")); - if (GoASTContext::IsGoString(valobj.GetCompilerType())) { - return formatter_sp; - } - if (GoASTContext::IsGoString( - valobj.GetCompilerType().GetPointeeType())) { - return formatter_sp; - } - return nullptr; - }); - g_formatters.push_back( - [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, - FormatManager &) -> TypeSummaryImpl::SharedPointer { - static lldb::TypeSummaryImplSP formatter_sp(new StringSummaryFormat( - TypeSummaryImpl::Flags().SetHideItemNames(true), - "(len ${var.len}, cap ${var.cap})")); - if (GoASTContext::IsGoSlice(valobj.GetCompilerType())) { - return formatter_sp; - } - if (GoASTContext::IsGoSlice( - valobj.GetCompilerType().GetPointeeType())) { - return formatter_sp; - } - return nullptr; - }); - }); - return g_formatters; -} - -HardcodedFormatters::HardcodedSyntheticFinder -GoLanguage::GetHardcodedSynthetics() { - static llvm::once_flag g_initialize; - static HardcodedFormatters::HardcodedSyntheticFinder g_formatters; - - llvm::call_once(g_initialize, []() -> void { - g_formatters.push_back( - [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, - FormatManager &fmt_mgr) -> SyntheticChildren::SharedPointer { - static CXXSyntheticChildren::SharedPointer formatter_sp( - new CXXSyntheticChildren( - SyntheticChildren::Flags(), "slice synthetic children", - lldb_private::formatters::GoSliceSyntheticFrontEndCreator)); - if (GoASTContext::IsGoSlice(valobj.GetCompilerType())) { - return formatter_sp; - } - return nullptr; - }); - }); - - return g_formatters; -} diff --git a/source/Plugins/Language/Go/GoLanguage.h b/source/Plugins/Language/Go/GoLanguage.h deleted file mode 100644 index ebec1d7205fa..000000000000 --- a/source/Plugins/Language/Go/GoLanguage.h +++ /dev/null @@ -1,63 +0,0 @@ -//===-- GoLanguage.h --------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_GoLanguage_h_ -#define liblldb_GoLanguage_h_ - -// C Includes -// C++ Includes -#include <vector> - -// Other libraries and framework includes -#include "llvm/ADT/StringRef.h" - -// Project includes -#include "lldb/Target/Language.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/lldb-private.h" - -namespace lldb_private { - -class GoLanguage : public Language { -public: - GoLanguage() = default; - - ~GoLanguage() override = default; - - lldb::LanguageType GetLanguageType() const override { - return lldb::eLanguageTypeGo; - } - - HardcodedFormatters::HardcodedSummaryFinder GetHardcodedSummaries() override; - - HardcodedFormatters::HardcodedSyntheticFinder - GetHardcodedSynthetics() override; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void Initialize(); - - static void Terminate(); - - static lldb_private::Language *CreateInstance(lldb::LanguageType language); - - static lldb_private::ConstString GetPluginNameStatic(); - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; -}; - -} // namespace lldb_private - -#endif // liblldb_GoLanguage_h_ diff --git a/source/Plugins/Language/Java/CMakeLists.txt b/source/Plugins/Language/Java/CMakeLists.txt deleted file mode 100644 index f0cbcd8d3f59..000000000000 --- a/source/Plugins/Language/Java/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_lldb_library(lldbPluginJavaLanguage PLUGIN - JavaFormatterFunctions.cpp - JavaLanguage.cpp - - LINK_LIBS - lldbCore - lldbDataFormatters - lldbSymbol - lldbTarget - LINK_COMPONENTS - Support -) diff --git a/source/Plugins/Language/Java/JavaFormatterFunctions.cpp b/source/Plugins/Language/Java/JavaFormatterFunctions.cpp deleted file mode 100644 index 498795c90be8..000000000000 --- a/source/Plugins/Language/Java/JavaFormatterFunctions.cpp +++ /dev/null @@ -1,167 +0,0 @@ -//===-- JavaFormatterFunctions.cpp-------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes -#include "JavaFormatterFunctions.h" -#include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/DataFormatters/StringPrinter.h" -#include "lldb/Symbol/JavaASTContext.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::formatters; - -namespace { - -class JavaArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd { -public: - JavaArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) - : SyntheticChildrenFrontEnd(*valobj_sp) { - if (valobj_sp) - Update(); - } - - size_t CalculateNumChildren() override { - ValueObjectSP valobj = GetDereferencedValueObject(); - if (!valobj) - return 0; - - CompilerType type = valobj->GetCompilerType(); - uint32_t size = JavaASTContext::CalculateArraySize(type, *valobj); - if (size == UINT32_MAX) - return 0; - return size; - } - - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { - ValueObjectSP valobj = GetDereferencedValueObject(); - if (!valobj) - return nullptr; - - ProcessSP process_sp = valobj->GetProcessSP(); - if (!process_sp) - return nullptr; - - CompilerType type = valobj->GetCompilerType(); - CompilerType element_type = type.GetArrayElementType(); - lldb::addr_t address = - valobj->GetAddressOf() + - JavaASTContext::CalculateArrayElementOffset(type, idx); - - Status error; - size_t byte_size = element_type.GetByteSize(nullptr); - DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0)); - size_t bytes_read = process_sp->ReadMemory(address, buffer_sp->GetBytes(), - byte_size, error); - if (error.Fail() || byte_size != bytes_read) - return nullptr; - - StreamString name; - name.Printf("[%" PRIu64 "]", (uint64_t)idx); - DataExtractor data(buffer_sp, process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()); - return CreateValueObjectFromData( - name.GetString(), data, valobj->GetExecutionContextRef(), element_type); - } - - bool Update() override { return false; } - - bool MightHaveChildren() override { return true; } - - size_t GetIndexOfChildWithName(const ConstString &name) override { - return ExtractIndexFromString(name.GetCString()); - } - -private: - ValueObjectSP GetDereferencedValueObject() { - if (!m_backend.IsPointerOrReferenceType()) - return m_backend.GetSP(); - - Status error; - return m_backend.Dereference(error); - } -}; - -} // end of anonymous namespace - -bool lldb_private::formatters::JavaStringSummaryProvider( - ValueObject &valobj, Stream &stream, const TypeSummaryOptions &opts) { - if (valobj.IsPointerOrReferenceType()) { - Status error; - ValueObjectSP deref = valobj.Dereference(error); - if (error.Fail()) - return false; - return JavaStringSummaryProvider(*deref, stream, opts); - } - - ProcessSP process_sp = valobj.GetProcessSP(); - if (!process_sp) - return false; - - ConstString data_name("value"); - ConstString length_name("count"); - - ValueObjectSP length_sp = valobj.GetChildMemberWithName(length_name, true); - ValueObjectSP data_sp = valobj.GetChildMemberWithName(data_name, true); - if (!data_sp || !length_sp) - return false; - - bool success = false; - uint64_t length = length_sp->GetValueAsUnsigned(0, &success); - if (!success) - return false; - - if (length == 0) { - stream.Printf("\"\""); - return true; - } - lldb::addr_t valobj_addr = data_sp->GetAddressOf(); - - StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); - options.SetLocation(valobj_addr); - options.SetProcessSP(process_sp); - options.SetStream(&stream); - options.SetSourceSize(length); - options.SetNeedsZeroTermination(false); - options.SetLanguage(eLanguageTypeJava); - - if (StringPrinter::ReadStringAndDumpToStream< - StringPrinter::StringElementType::UTF16>(options)) - return true; - - stream.Printf("Summary Unavailable"); - return true; -} - -bool lldb_private::formatters::JavaArraySummaryProvider( - ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { - if (valobj.IsPointerOrReferenceType()) { - Status error; - ValueObjectSP deref = valobj.Dereference(error); - if (error.Fail()) - return false; - return JavaArraySummaryProvider(*deref, stream, options); - } - - CompilerType type = valobj.GetCompilerType(); - uint32_t size = JavaASTContext::CalculateArraySize(type, valobj); - if (size == UINT32_MAX) - return false; - stream.Printf("[%u]{...}", size); - return true; -} - -SyntheticChildrenFrontEnd * -lldb_private::formatters::JavaArraySyntheticFrontEndCreator( - CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { - return valobj_sp ? new JavaArraySyntheticFrontEnd(valobj_sp) : nullptr; -} diff --git a/source/Plugins/Language/Java/JavaFormatterFunctions.h b/source/Plugins/Language/Java/JavaFormatterFunctions.h deleted file mode 100644 index d1983429529c..000000000000 --- a/source/Plugins/Language/Java/JavaFormatterFunctions.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-- JavaFormatterFunctions.h---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_JavaFormatterFunctions_h_ -#define liblldb_JavaFormatterFunctions_h_ - -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes -#include "lldb/lldb-forward.h" - -namespace lldb_private { -namespace formatters { - -bool JavaStringSummaryProvider(ValueObject &valobj, Stream &stream, - const TypeSummaryOptions &options); - -bool JavaArraySummaryProvider(ValueObject &valobj, Stream &stream, - const TypeSummaryOptions &options); - -SyntheticChildrenFrontEnd * -JavaArraySyntheticFrontEndCreator(CXXSyntheticChildren *, - lldb::ValueObjectSP valobj_sp); - -} // namespace formatters -} // namespace lldb_private - -#endif // liblldb_JavaFormatterFunctions_h_ diff --git a/source/Plugins/Language/Java/JavaLanguage.cpp b/source/Plugins/Language/Java/JavaLanguage.cpp deleted file mode 100644 index b17862f0b6a2..000000000000 --- a/source/Plugins/Language/Java/JavaLanguage.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===-- JavaLanguage.cpp ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// C Includes -#include <string.h> -// C++ Includes -#include <functional> -#include <mutex> - -// Other libraries and framework includes -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Threading.h" - -// Project includes -#include "JavaFormatterFunctions.h" -#include "JavaLanguage.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/DataFormatters/DataVisualization.h" -#include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/JavaASTContext.h" -#include "lldb/Utility/ConstString.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::formatters; - -void JavaLanguage::Initialize() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), "Java Language", - CreateInstance); -} - -void JavaLanguage::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -lldb_private::ConstString JavaLanguage::GetPluginNameStatic() { - static ConstString g_name("Java"); - return g_name; -} - -lldb_private::ConstString JavaLanguage::GetPluginName() { - return GetPluginNameStatic(); -} - -uint32_t JavaLanguage::GetPluginVersion() { return 1; } - -Language *JavaLanguage::CreateInstance(lldb::LanguageType language) { - if (language == eLanguageTypeJava) - return new JavaLanguage(); - return nullptr; -} - -bool JavaLanguage::IsNilReference(ValueObject &valobj) { - if (!valobj.GetCompilerType().IsReferenceType()) - return false; - - // If we failed to read the value then it is not a nil reference. - return valobj.GetValueAsUnsigned(UINT64_MAX) == 0; -} - -lldb::TypeCategoryImplSP JavaLanguage::GetFormatters() { - static llvm::once_flag g_initialize; - static TypeCategoryImplSP g_category; - - llvm::call_once(g_initialize, [this]() -> void { - DataVisualization::Categories::GetCategory(GetPluginName(), g_category); - if (g_category) { - llvm::StringRef array_regexp("^.*\\[\\]&?$"); - - lldb::TypeSummaryImplSP string_summary_sp(new CXXFunctionSummaryFormat( - TypeSummaryImpl::Flags().SetDontShowChildren(true), - lldb_private::formatters::JavaStringSummaryProvider, - "java.lang.String summary provider")); - g_category->GetTypeSummariesContainer()->Add( - ConstString("java::lang::String"), string_summary_sp); - - lldb::TypeSummaryImplSP array_summary_sp(new CXXFunctionSummaryFormat( - TypeSummaryImpl::Flags().SetDontShowChildren(true), - lldb_private::formatters::JavaArraySummaryProvider, - "Java array summary provider")); - g_category->GetRegexTypeSummariesContainer()->Add( - RegularExpressionSP(new RegularExpression(array_regexp)), - array_summary_sp); - -#ifndef LLDB_DISABLE_PYTHON - AddCXXSynthetic( - g_category, - lldb_private::formatters::JavaArraySyntheticFrontEndCreator, - "Java array synthetic children", ConstString(array_regexp), - SyntheticChildren::Flags().SetCascades(true), true); -#endif - } - }); - return g_category; -} diff --git a/source/Plugins/Language/Java/JavaLanguage.h b/source/Plugins/Language/Java/JavaLanguage.h deleted file mode 100644 index 5b652502a3d1..000000000000 --- a/source/Plugins/Language/Java/JavaLanguage.h +++ /dev/null @@ -1,52 +0,0 @@ -//===-- JavaLanguage.h ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_JavaLanguage_h_ -#define liblldb_JavaLanguage_h_ - -// C Includes -// C++ Includes -#include <vector> - -// Other libraries and framework includes -#include "llvm/ADT/StringRef.h" - -// Project includes -#include "lldb/Target/Language.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/lldb-private.h" - -namespace lldb_private { - -class JavaLanguage : public Language { -public: - lldb::LanguageType GetLanguageType() const override { - return lldb::eLanguageTypeJava; - } - - static void Initialize(); - - static void Terminate(); - - static lldb_private::Language *CreateInstance(lldb::LanguageType language); - - static lldb_private::ConstString GetPluginNameStatic(); - - ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; - - bool IsNilReference(ValueObject &valobj) override; - - lldb::TypeCategoryImplSP GetFormatters() override; -}; - -} // namespace lldb_private - -#endif // liblldb_JavaLanguage_h_ diff --git a/source/Plugins/Language/OCaml/CMakeLists.txt b/source/Plugins/Language/OCaml/CMakeLists.txt deleted file mode 100644 index e779ae2acd08..000000000000 --- a/source/Plugins/Language/OCaml/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_lldb_library(lldbPluginOCamlLanguage PLUGIN - OCamlLanguage.cpp - - LINK_LIBS - lldbCore - lldbDataFormatters - lldbSymbol - lldbTarget - LINK_COMPONENTS - Support -) - diff --git a/source/Plugins/Language/OCaml/OCamlLanguage.cpp b/source/Plugins/Language/OCaml/OCamlLanguage.cpp deleted file mode 100644 index ec24a36fe8f3..000000000000 --- a/source/Plugins/Language/OCaml/OCamlLanguage.cpp +++ /dev/null @@ -1,63 +0,0 @@ -//===-- OCamlLanguage.cpp ----------------------------------------*- C++ -//-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// C Includes -#include <string.h> -// C++ Includes -#include <functional> -#include <mutex> - -// Other libraries and framework includes -#include "llvm/ADT/StringRef.h" - -// Project includes -#include "OCamlLanguage.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/DataFormatters/DataVisualization.h" -#include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/OCamlASTContext.h" -#include "lldb/Utility/ConstString.h" - -using namespace lldb; -using namespace lldb_private; - -void OCamlLanguage::Initialize() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), "OCaml Language", - CreateInstance); -} - -void OCamlLanguage::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -lldb_private::ConstString OCamlLanguage::GetPluginNameStatic() { - static ConstString g_name("OCaml"); - return g_name; -} - -lldb_private::ConstString OCamlLanguage::GetPluginName() { - return GetPluginNameStatic(); -} - -uint32_t OCamlLanguage::GetPluginVersion() { return 1; } - -Language *OCamlLanguage::CreateInstance(lldb::LanguageType language) { - if (language == eLanguageTypeOCaml) - return new OCamlLanguage(); - return nullptr; -} - -bool OCamlLanguage::IsNilReference(ValueObject &valobj) { - if (!valobj.GetCompilerType().IsReferenceType()) - return false; - - // If we failed to read the value then it is not a nil reference. - return valobj.GetValueAsUnsigned(UINT64_MAX) == 0; -} diff --git a/source/Plugins/Language/OCaml/OCamlLanguage.h b/source/Plugins/Language/OCaml/OCamlLanguage.h deleted file mode 100644 index 21837fe5add4..000000000000 --- a/source/Plugins/Language/OCaml/OCamlLanguage.h +++ /dev/null @@ -1,51 +0,0 @@ -//===-- OCamlLanguage.h ------------------------------------------*- C++ -//-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_OCamlLanguage_h_ -#define liblldb_OCamlLanguage_h_ - -// C Includes -// C++ Includes -#include <vector> - -// Other libraries and framework includes -#include "llvm/ADT/StringRef.h" - -// Project includes -#include "lldb/Target/Language.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/lldb-private.h" - -namespace lldb_private { - -class OCamlLanguage : public Language { -public: - lldb::LanguageType GetLanguageType() const override { - return lldb::eLanguageTypeOCaml; - } - - static void Initialize(); - - static void Terminate(); - - static lldb_private::Language *CreateInstance(lldb::LanguageType language); - - static lldb_private::ConstString GetPluginNameStatic(); - - ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; - - bool IsNilReference(ValueObject &valobj) override; -}; - -} // namespace lldb_private - -#endif // liblldb_OCamlLanguage_h_ diff --git a/source/Plugins/Language/ObjC/CF.cpp b/source/Plugins/Language/ObjC/CF.cpp index 9bb8eeab1d2e..e3dab5a1442d 100644 --- a/source/Plugins/Language/ObjC/CF.cpp +++ b/source/Plugins/Language/ObjC/CF.cpp @@ -149,7 +149,7 @@ bool lldb_private::formatters::CFBitVectorSummaryProvider( } } - if (is_type_ok == false) + if (!is_type_ok) return false; Status error; diff --git a/source/Plugins/Language/ObjC/CMakeLists.txt b/source/Plugins/Language/ObjC/CMakeLists.txt index 95ace3a3633a..afb68d4de831 100644 --- a/source/Plugins/Language/ObjC/CMakeLists.txt +++ b/source/Plugins/Language/ObjC/CMakeLists.txt @@ -31,6 +31,7 @@ add_lldb_library(lldbPluginObjCLanguage PLUGIN lldbTarget lldbUtility lldbPluginAppleObjCRuntime + lldbPluginClangCommon EXTRA_CXXFLAGS ${EXTRA_CXXFLAGS} ) diff --git a/source/Plugins/Language/ObjC/Cocoa.cpp b/source/Plugins/Language/ObjC/Cocoa.cpp index 8f278fc2d513..48085378939e 100644 --- a/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/source/Plugins/Language/ObjC/Cocoa.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "Cocoa.h" #include "lldb/Core/Mangled.h" @@ -746,6 +742,59 @@ bool lldb_private::formatters::NSURLSummaryProvider( return false; } +/// Bias value for tagged pointer exponents. +/// Recommended values: +/// 0x3e3: encodes all dates between distantPast and distantFuture +/// except for the range within about 1e-28 second of the reference date. +/// 0x3ef: encodes all dates for a few million years beyond distantPast and +/// distantFuture, except within about 1e-25 second of the reference date. +const int TAGGED_DATE_EXPONENT_BIAS = 0x3ef; + +typedef union { + struct { + uint64_t fraction:52; // unsigned + uint64_t exponent:11; // signed + uint64_t sign:1; + }; + uint64_t i; + double d; +} DoubleBits; +typedef union { + struct { + uint64_t fraction:52; // unsigned + uint64_t exponent:7; // signed + uint64_t sign:1; + uint64_t unused:4; // placeholder for pointer tag bits + }; + uint64_t i; +} TaggedDoubleBits; + +static uint64_t decodeExponent(uint64_t exp) { + // Tagged exponent field is 7-bit signed. Sign-extend the value to 64 bits + // before performing arithmetic. + return llvm::SignExtend64<7>(exp) + TAGGED_DATE_EXPONENT_BIAS; +} + +static uint64_t decodeTaggedTimeInterval(uint64_t encodedTimeInterval) { + if (encodedTimeInterval == 0) + return 0.0; + if (encodedTimeInterval == std::numeric_limits<uint64_t>::max()) + return (uint64_t)-0.0; + + TaggedDoubleBits encodedBits = {}; + encodedBits.i = encodedTimeInterval; + DoubleBits decodedBits; + + // Sign and fraction are represented exactly. + // Exponent is encoded. + assert(encodedBits.unused == 0); + decodedBits.sign = encodedBits.sign; + decodedBits.fraction = encodedBits.fraction; + decodedBits.exponent = decodeExponent(encodedBits.exponent); + + return decodedBits.d; +} + bool lldb_private::formatters::NSDateSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { ProcessSP process_sp = valobj.GetProcessSP(); @@ -785,9 +834,9 @@ bool lldb_private::formatters::NSDateSummaryProvider( 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)) { - uint64_t info_bits = 0, value_bits = 0; 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)); @@ -817,6 +866,14 @@ bool lldb_private::formatters::NSDateSummaryProvider( stream.Printf("0001-12-30 00:00:00 +0000"); return true; } + + // Accomodate for the __NSTaggedDate format introduced in Foundation 1600. + if (class_name == g___NSTaggedDate) { + auto *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime()); + if (runtime && runtime->GetFoundationVersion() >= 1600) + date_value = decodeTaggedTimeInterval(value_bits << 4); + } + // this snippet of code assumes that time_t == seconds since Jan-1-1970 this // is generally true and POSIXly happy, but might break if a library vendor // decides to get creative diff --git a/source/Plugins/Language/ObjC/NSArray.cpp b/source/Plugins/Language/ObjC/NSArray.cpp index f6d159201951..6c110da9ecc2 100644 --- a/source/Plugins/Language/ObjC/NSArray.cpp +++ b/source/Plugins/Language/ObjC/NSArray.cpp @@ -7,12 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes #include "clang/AST/ASTContext.h" -// Project includes #include "Cocoa.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" @@ -218,6 +214,25 @@ namespace Foundation1437 { } +namespace CallStackArray { +struct DataDescriptor_32 { + uint32_t _data; + uint32_t _used; + uint32_t _offset; + const uint32_t _size = 0; +}; + +struct DataDescriptor_64 { + uint64_t _data; + uint64_t _used; + uint64_t _offset; + const uint64_t _size = 0; +}; + +using NSCallStackArraySyntheticFrontEnd = + GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; +} // namespace CallStackArray + template <typename D32, typename D64, bool Inline> class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: @@ -368,6 +383,7 @@ bool lldb_private::formatters::NSArraySummaryProvider( static const ConstString g_NSArrayCF("__NSCFArray"); static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy"); static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable"); + static const ConstString g_NSCallStackArray("_NSCallStackArray"); if (class_name.IsEmpty()) return false; @@ -417,7 +433,9 @@ bool lldb_private::formatters::NSArraySummaryProvider( value = 0; } else if (class_name == g_NSArray1) { value = 1; - } else if (class_name == g_NSArrayCF) { + } else if (class_name == g_NSArrayCF || class_name == g_NSCallStackArray) { + // __NSCFArray and _NSCallStackArray store the number of elements as a + // pointer-sized value at offset `2 * ptr_size`. Status error; value = process_sp->ReadUnsignedIntegerFromMemory( valobj_addr + 2 * ptr_size, ptr_size, 0, error); @@ -817,6 +835,7 @@ lldb_private::formatters::NSArraySyntheticFrontEndCreator( static const ConstString g_NSArray1("__NSSingleObjectArrayI"); static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy"); static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable"); + static const ConstString g_NSCallStackArray("_NSCallStackArray"); if (class_name.IsEmpty()) return nullptr; @@ -846,6 +865,8 @@ lldb_private::formatters::NSArraySyntheticFrontEndCreator( return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp)); else return (new Foundation109::NSArrayMSyntheticFrontEnd(valobj_sp)); + } else if (class_name == g_NSCallStackArray) { + return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp)); } else { auto &map(NSArray_Additionals::GetAdditionalSynthetics()); auto iter = map.find(class_name), end = map.end(); diff --git a/source/Plugins/Language/ObjC/NSDictionary.cpp b/source/Plugins/Language/ObjC/NSDictionary.cpp index 5be051b46bd6..9a7fc2bd97cb 100644 --- a/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -7,14 +7,10 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes #include <mutex> -// Other libraries and framework includes #include "clang/AST/DeclCXX.h" -// Project includes #include "NSDictionary.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" diff --git a/source/Plugins/Language/ObjC/NSError.cpp b/source/Plugins/Language/ObjC/NSError.cpp index 77721e2db326..975bda5179f2 100644 --- a/source/Plugins/Language/ObjC/NSError.cpp +++ b/source/Plugins/Language/ObjC/NSError.cpp @@ -7,12 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes #include "clang/AST/DeclCXX.h" -// Project includes #include "Cocoa.h" #include "lldb/Core/ValueObject.h" diff --git a/source/Plugins/Language/ObjC/NSException.cpp b/source/Plugins/Language/ObjC/NSException.cpp index c6970efae4d3..2404ef9d1003 100644 --- a/source/Plugins/Language/ObjC/NSException.cpp +++ b/source/Plugins/Language/ObjC/NSException.cpp @@ -7,12 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes #include "clang/AST/DeclCXX.h" -// Project includes #include "Cocoa.h" #include "lldb/Core/ValueObject.h" @@ -33,52 +29,78 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; -bool lldb_private::formatters::NSException_SummaryProvider( - ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { +static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp, + ValueObjectSP *reason_sp, ValueObjectSP *userinfo_sp, + ValueObjectSP *reserved_sp) { ProcessSP process_sp(valobj.GetProcessSP()); if (!process_sp) return false; - lldb::addr_t ptr_value = LLDB_INVALID_ADDRESS; + lldb::addr_t ptr = LLDB_INVALID_ADDRESS; CompilerType valobj_type(valobj.GetCompilerType()); Flags type_flags(valobj_type.GetTypeInfo()); if (type_flags.AllClear(eTypeHasValue)) { if (valobj.IsBaseClass() && valobj.GetParent()) - ptr_value = valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); - } else - ptr_value = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + ptr = valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + } else { + ptr = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + } - if (ptr_value == LLDB_INVALID_ADDRESS) + if (ptr == LLDB_INVALID_ADDRESS) return false; size_t ptr_size = process_sp->GetAddressByteSize(); - lldb::addr_t name_location = ptr_value + 1 * ptr_size; - lldb::addr_t reason_location = ptr_value + 2 * ptr_size; Status error; - lldb::addr_t name = process_sp->ReadPointerFromMemory(name_location, error); + auto name = process_sp->ReadPointerFromMemory(ptr + 1 * ptr_size, error); if (error.Fail() || name == LLDB_INVALID_ADDRESS) return false; - - lldb::addr_t reason = - process_sp->ReadPointerFromMemory(reason_location, error); + auto reason = process_sp->ReadPointerFromMemory(ptr + 2 * ptr_size, error); if (error.Fail() || reason == LLDB_INVALID_ADDRESS) return false; + auto userinfo = process_sp->ReadPointerFromMemory(ptr + 3 * ptr_size, error); + if (error.Fail() || userinfo == LLDB_INVALID_ADDRESS) + return false; + auto reserved = process_sp->ReadPointerFromMemory(ptr + 4 * ptr_size, error); + if (error.Fail() || reserved == LLDB_INVALID_ADDRESS) + return false; InferiorSizedWord name_isw(name, *process_sp); InferiorSizedWord reason_isw(reason, *process_sp); + InferiorSizedWord userinfo_isw(userinfo, *process_sp); + InferiorSizedWord reserved_isw(reserved, *process_sp); CompilerType voidstar = process_sp->GetTarget() .GetScratchClangASTContext() ->GetBasicType(lldb::eBasicTypeVoid) .GetPointerType(); - ValueObjectSP name_sp = ValueObject::CreateValueObjectFromData( - "name_str", name_isw.GetAsData(process_sp->GetByteOrder()), - valobj.GetExecutionContextRef(), voidstar); - ValueObjectSP reason_sp = ValueObject::CreateValueObjectFromData( - "reason_str", reason_isw.GetAsData(process_sp->GetByteOrder()), - valobj.GetExecutionContextRef(), voidstar); + if (name_sp) + *name_sp = ValueObject::CreateValueObjectFromData( + "name", name_isw.GetAsData(process_sp->GetByteOrder()), + valobj.GetExecutionContextRef(), voidstar); + if (reason_sp) + *reason_sp = ValueObject::CreateValueObjectFromData( + "reason", reason_isw.GetAsData(process_sp->GetByteOrder()), + valobj.GetExecutionContextRef(), voidstar); + if (userinfo_sp) + *userinfo_sp = ValueObject::CreateValueObjectFromData( + "userInfo", userinfo_isw.GetAsData(process_sp->GetByteOrder()), + valobj.GetExecutionContextRef(), voidstar); + if (reserved_sp) + *reserved_sp = ValueObject::CreateValueObjectFromData( + "reserved", reserved_isw.GetAsData(process_sp->GetByteOrder()), + valobj.GetExecutionContextRef(), voidstar); + + return true; +} + +bool lldb_private::formatters::NSException_SummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + lldb::ValueObjectSP name_sp; + lldb::ValueObjectSP reason_sp; + if (!ExtractFields(valobj, &name_sp, &reason_sp, nullptr, nullptr)) + return false; if (!name_sp || !reason_sp) return false; @@ -101,83 +123,55 @@ public: : SyntheticChildrenFrontEnd(*valobj_sp) {} ~NSExceptionSyntheticFrontEnd() override = default; - // no need to delete m_child_ptr - it's kept alive by the cluster manager on - // our behalf size_t CalculateNumChildren() override { - if (m_child_ptr) - return 1; - if (m_child_sp) - return 1; - return 0; + return 4; } lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { - if (idx != 0) - return lldb::ValueObjectSP(); - - if (m_child_ptr) - return m_child_ptr->GetSP(); - return m_child_sp; + switch (idx) { + case 0: return m_name_sp; + case 1: return m_reason_sp; + case 2: return m_userinfo_sp; + case 3: return m_reserved_sp; + } + return lldb::ValueObjectSP(); } bool Update() override { - m_child_ptr = nullptr; - m_child_sp.reset(); - - ProcessSP process_sp(m_backend.GetProcessSP()); - if (!process_sp) - return false; - - lldb::addr_t userinfo_location = LLDB_INVALID_ADDRESS; - - CompilerType valobj_type(m_backend.GetCompilerType()); - Flags type_flags(valobj_type.GetTypeInfo()); - if (type_flags.AllClear(eTypeHasValue)) { - if (m_backend.IsBaseClass() && m_backend.GetParent()) - userinfo_location = - m_backend.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); - } else - userinfo_location = m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); - - if (userinfo_location == LLDB_INVALID_ADDRESS) - return false; - - size_t ptr_size = process_sp->GetAddressByteSize(); - - userinfo_location += 3 * ptr_size; - Status error; - lldb::addr_t userinfo = - process_sp->ReadPointerFromMemory(userinfo_location, error); - if (userinfo == LLDB_INVALID_ADDRESS || error.Fail()) - return false; - InferiorSizedWord isw(userinfo, *process_sp); - m_child_sp = CreateValueObjectFromData( - "userInfo", isw.GetAsData(process_sp->GetByteOrder()), - m_backend.GetExecutionContextRef(), - process_sp->GetTarget().GetScratchClangASTContext()->GetBasicType( - lldb::eBasicTypeObjCID)); - return false; + m_name_sp.reset(); + m_reason_sp.reset(); + m_userinfo_sp.reset(); + m_reserved_sp.reset(); + + return ExtractFields(m_backend, &m_name_sp, &m_reason_sp, &m_userinfo_sp, + &m_reserved_sp); } bool MightHaveChildren() override { return true; } size_t GetIndexOfChildWithName(const ConstString &name) override { + // NSException has 4 members: + // NSString *name; + // NSString *reason; + // NSDictionary *userInfo; + // id reserved; + static ConstString g___name("name"); + static ConstString g___reason("reason"); static ConstString g___userInfo("userInfo"); - if (name == g___userInfo) - return 0; + static ConstString g___reserved("reserved"); + if (name == g___name) return 0; + if (name == g___reason) return 1; + if (name == g___userInfo) return 2; + if (name == g___reserved) return 3; return UINT32_MAX; } private: - // the child here can be "real" (i.e. an actual child of the root) or - // synthetized from raw memory if the former, I need to store a plain pointer - // to it - or else a loop of references will cause this entire hierarchy of - // values to leak if the latter, then I need to store a SharedPointer to it - - // so that it only goes away when everyone else in the cluster goes away oh - // joy! - ValueObject *m_child_ptr; - ValueObjectSP m_child_sp; + ValueObjectSP m_name_sp; + ValueObjectSP m_reason_sp; + ValueObjectSP m_userinfo_sp; + ValueObjectSP m_reserved_sp; }; SyntheticChildrenFrontEnd * diff --git a/source/Plugins/Language/ObjC/NSIndexPath.cpp b/source/Plugins/Language/ObjC/NSIndexPath.cpp index 9533e96004a5..41df9abb3eb2 100644 --- a/source/Plugins/Language/ObjC/NSIndexPath.cpp +++ b/source/Plugins/Language/ObjC/NSIndexPath.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "Cocoa.h" #include "lldb/Core/ValueObject.h" @@ -130,11 +126,7 @@ public: return false; } - bool MightHaveChildren() override { - if (m_impl.m_mode == Mode::Invalid) - return false; - return true; - } + bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; } size_t GetIndexOfChildWithName(const ConstString &name) override { const char *item_name = name.GetCString(); diff --git a/source/Plugins/Language/ObjC/NSSet.cpp b/source/Plugins/Language/ObjC/NSSet.cpp index 2da4bc034f32..7e03d7574af0 100644 --- a/source/Plugins/Language/ObjC/NSSet.cpp +++ b/source/Plugins/Language/ObjC/NSSet.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "NSSet.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" diff --git a/source/Plugins/Language/ObjC/NSString.cpp b/source/Plugins/Language/ObjC/NSString.cpp index 0b12edb53d7a..f882b2adc260 100644 --- a/source/Plugins/Language/ObjC/NSString.cpp +++ b/source/Plugins/Language/ObjC/NSString.cpp @@ -225,10 +225,10 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); - options.SetNeedsZeroTermination(has_explicit_length == false); + options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); - options.SetBinaryZeroIsTerminator(has_explicit_length == false); + options.SetBinaryZeroIsTerminator(!has_explicit_length); options.SetLanguage(summary_options.GetLanguage()); return StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::UTF16>(options); @@ -245,10 +245,10 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); - options.SetNeedsZeroTermination(has_explicit_length == false); + options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); - options.SetBinaryZeroIsTerminator(has_explicit_length == false); + options.SetBinaryZeroIsTerminator(!has_explicit_length); options.SetLanguage(summary_options.GetLanguage()); return StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::UTF16>(options); @@ -260,10 +260,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( Status error; explicit_length = process_sp->ReadUnsignedIntegerFromMemory(location, 1, 0, error); - if (error.Fail() || explicit_length == 0) - has_explicit_length = false; - else - has_explicit_length = true; + has_explicit_length = !(error.Fail() || explicit_length == 0); location++; } options.SetLocation(location); diff --git a/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/source/Plugins/Language/ObjC/ObjCLanguage.cpp index 47874b3be8fd..0598d69f6ebb 100644 --- a/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -7,12 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes #include <mutex> -// Other libraries and framework includes -// Project includes #include "ObjCLanguage.h" #include "lldb/Core/PluginManager.h" @@ -413,6 +409,9 @@ static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { "NSArray summary provider", ConstString("__NSCFArray"), appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, + "NSArray summary provider", ConstString("_NSCallStackArray"), appkit_flags); + AddCXXSummary( + objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", ConstString("CFArrayRef"), appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, @@ -532,6 +531,10 @@ static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, + "NSArray synthetic children", ConstString("_NSCallStackArray"), + ScriptedSyntheticChildren::Flags()); + AddCXXSynthetic(objc_category_sp, + lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", ConstString("CFMutableArrayRef"), ScriptedSyntheticChildren::Flags()); @@ -1102,3 +1105,12 @@ bool ObjCLanguage::IsNilReference(ValueObject &valobj) { bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0; return canReadValue && isZero; } + +bool ObjCLanguage::IsSourceFile(llvm::StringRef file_path) const { + const auto suffixes = {".h", ".m", ".M"}; + for (auto suffix : suffixes) { + if (file_path.endswith_lower(suffix)) + return true; + } + return false; +} diff --git a/source/Plugins/Language/ObjC/ObjCLanguage.h b/source/Plugins/Language/ObjC/ObjCLanguage.h index 9782c5da0d67..114f9323de02 100644 --- a/source/Plugins/Language/ObjC/ObjCLanguage.h +++ b/source/Plugins/Language/ObjC/ObjCLanguage.h @@ -10,13 +10,10 @@ #ifndef liblldb_ObjCLanguage_h_ #define liblldb_ObjCLanguage_h_ -// C Includes -// C++ Includes #include <cstring> #include <vector> -// Other libraries and framework includes -// Project includes +#include "Plugins/Language/ClangCommon/ClangHighlighter.h" #include "lldb/Target/Language.h" #include "lldb/Utility/ConstString.h" #include "lldb/lldb-private.h" @@ -24,6 +21,8 @@ namespace lldb_private { class ObjCLanguage : public Language { + ClangHighlighter m_highlighter; + public: class MethodName { public: @@ -121,6 +120,10 @@ public: bool IsNilReference(ValueObject &valobj) override; + bool IsSourceFile(llvm::StringRef file_path) const override; + + const Highlighter *GetHighlighter() const override { return &m_highlighter; } + //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ diff --git a/source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt b/source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt index 75df9794d75d..1aa5cc1ed488 100644 --- a/source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt +++ b/source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt @@ -1,7 +1,8 @@ add_lldb_library(lldbPluginObjCPlusPlusLanguage PLUGIN ObjCPlusPlusLanguage.cpp - + LINK_LIBS lldbCore lldbTarget + lldbPluginClangCommon ) diff --git a/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp b/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp index bfc22c9ee650..5e6d86e05318 100644 --- a/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp +++ b/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp @@ -16,6 +16,15 @@ using namespace lldb; using namespace lldb_private; +bool ObjCPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const { + const auto suffixes = {".h", ".mm"}; + for (auto suffix : suffixes) { + if (file_path.endswith_lower(suffix)) + return true; + } + return false; +} + void ObjCPlusPlusLanguage::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), "Objective-C++ Language", CreateInstance); diff --git a/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h b/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h index 588b52215c10..b64f0f81e001 100644 --- a/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h +++ b/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h @@ -10,16 +10,15 @@ #ifndef liblldb_ObjCPlusPlusLanguage_h_ #define liblldb_ObjCPlusPlusLanguage_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes +#include "Plugins/Language/ClangCommon/ClangHighlighter.h" #include "lldb/Target/Language.h" #include "lldb/lldb-private.h" namespace lldb_private { class ObjCPlusPlusLanguage : public Language { + ClangHighlighter m_highlighter; + public: ObjCPlusPlusLanguage() = default; @@ -29,6 +28,10 @@ public: return lldb::eLanguageTypeObjC_plus_plus; } + bool IsSourceFile(llvm::StringRef file_path) const override; + + const Highlighter *GetHighlighter() const override { return &m_highlighter; } + //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ diff --git a/source/Plugins/LanguageRuntime/CMakeLists.txt b/source/Plugins/LanguageRuntime/CMakeLists.txt index 2cf579212ec1..c62791445a9a 100644 --- a/source/Plugins/LanguageRuntime/CMakeLists.txt +++ b/source/Plugins/LanguageRuntime/CMakeLists.txt @@ -1,5 +1,3 @@ add_subdirectory(CPlusPlus) add_subdirectory(ObjC) -add_subdirectory(Go) -add_subdirectory(Java) add_subdirectory(RenderScript) diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index fc661bbbf2c9..49a3d40d7b37 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -14,9 +14,11 @@ #include "lldb/Core/Mangled.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectMemory.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Expression/DiagnosticManager.h" +#include "lldb/Expression/FunctionCaller.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -32,6 +34,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" #include <vector> @@ -98,7 +101,7 @@ TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( llvm::DenseSet<SymbolFile *> searched_symbol_files; if (sc.module_sp) { num_matches = sc.module_sp->FindTypes( - sc, ConstString(lookup_name), exact_match, 1, + ConstString(lookup_name), exact_match, 1, searched_symbol_files, class_types); } @@ -106,7 +109,7 @@ TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( // list in the target and get as many unique matches as possible if (num_matches == 0) { num_matches = target.GetImages().FindTypes( - sc, ConstString(lookup_name), exact_match, UINT32_MAX, + nullptr, ConstString(lookup_name), exact_match, UINT32_MAX, searched_symbol_files, class_types); } @@ -204,71 +207,71 @@ bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( // Only a pointer or reference type can have a different dynamic and static // type: - if (CouldHaveDynamicValue(in_value)) { - // First job, pull out the address at 0 offset from the object. - AddressType address_type; - lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); - if (original_ptr == LLDB_INVALID_ADDRESS) - return false; + if (!CouldHaveDynamicValue(in_value)) + return false; - ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); + // First job, pull out the address at 0 offset from the object. + AddressType address_type; + lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); + if (original_ptr == LLDB_INVALID_ADDRESS) + return false; - Process *process = exe_ctx.GetProcessPtr(); + ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); - if (process == nullptr) - return false; + Process *process = exe_ctx.GetProcessPtr(); - Status error; - const lldb::addr_t vtable_address_point = - process->ReadPointerFromMemory(original_ptr, error); + if (process == nullptr) + return false; - if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS) { - return false; - } + Status error; + const lldb::addr_t vtable_address_point = + process->ReadPointerFromMemory(original_ptr, error); - class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, - vtable_address_point); - - if (class_type_or_name) { - TypeSP type_sp = class_type_or_name.GetTypeSP(); - // There can only be one type with a given name, so we've just found - // duplicate definitions, and this one will do as well as any other. We - // don't consider something to have a dynamic type if it is the same as - // the static type. So compare against the value we were handed. - if (type_sp) { - if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), - type_sp->GetForwardCompilerType())) { - // The dynamic type we found was the same type, so we don't have a - // dynamic type here... - return false; - } + if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS) + return false; - // The offset_to_top is two pointers above the vtable pointer. - const uint32_t addr_byte_size = process->GetAddressByteSize(); - const lldb::addr_t offset_to_top_location = - vtable_address_point - 2 * addr_byte_size; - // Watch for underflow, offset_to_top_location should be less than - // vtable_address_point - if (offset_to_top_location >= vtable_address_point) - return false; - const int64_t offset_to_top = process->ReadSignedIntegerFromMemory( - offset_to_top_location, addr_byte_size, INT64_MIN, error); - - if (offset_to_top == INT64_MIN) - return false; - // So the dynamic type is a value that starts at offset_to_top above - // the original address. - lldb::addr_t dynamic_addr = original_ptr + offset_to_top; - if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress( - dynamic_addr, dynamic_address)) { - dynamic_address.SetRawAddress(dynamic_addr); - } - return true; - } - } + class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, + vtable_address_point); + + if (!class_type_or_name) + return false; + + TypeSP type_sp = class_type_or_name.GetTypeSP(); + // There can only be one type with a given name, so we've just found + // duplicate definitions, and this one will do as well as any other. We + // don't consider something to have a dynamic type if it is the same as + // the static type. So compare against the value we were handed. + if (!type_sp) + return true; + + if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), + type_sp->GetForwardCompilerType())) { + // The dynamic type we found was the same type, so we don't have a + // dynamic type here... + return false; } - return class_type_or_name.IsEmpty() == false; + // The offset_to_top is two pointers above the vtable pointer. + const uint32_t addr_byte_size = process->GetAddressByteSize(); + const lldb::addr_t offset_to_top_location = + vtable_address_point - 2 * addr_byte_size; + // Watch for underflow, offset_to_top_location should be less than + // vtable_address_point + if (offset_to_top_location >= vtable_address_point) + return false; + const int64_t offset_to_top = process->ReadSignedIntegerFromMemory( + offset_to_top_location, addr_byte_size, INT64_MIN, error); + + if (offset_to_top == INT64_MIN) + return false; + // So the dynamic type is a value that starts at offset_to_top above + // the original address. + lldb::addr_t dynamic_addr = original_ptr + offset_to_top; + if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress( + dynamic_addr, dynamic_address)) { + dynamic_address.SetRawAddress(dynamic_addr); + } + return true; } TypeAndOrName ItaniumABILanguageRuntime::FixUpDynamicType( @@ -309,10 +312,7 @@ bool ItaniumABILanguageRuntime::IsVTableName(const char *name) { return false; // Can we maybe ask Clang about this? - if (strstr(name, "_vptr$") == name) - return true; - else - return false; + return strstr(name, "_vptr$") == name; } //------------------------------------------------------------------ @@ -483,8 +483,8 @@ lldb::SearchFilterSP ItaniumABILanguageRuntime::CreateExceptionSearchFilter() { // Limit the number of modules that are searched for these breakpoints for // Apple binaries. FileSpecList filter_modules; - filter_modules.Append(FileSpec("libc++abi.dylib", false)); - filter_modules.Append(FileSpec("libSystem.B.dylib", false)); + filter_modules.Append(FileSpec("libc++abi.dylib")); + filter_modules.Append(FileSpec("libSystem.B.dylib")); return target.GetSearchFilterForModuleList(&filter_modules); } else { return LanguageRuntime::CreateExceptionSearchFilter(); @@ -552,6 +552,64 @@ bool ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop( break_site_id, m_cxx_exception_bp_sp->GetID()); } +ValueObjectSP ItaniumABILanguageRuntime::GetExceptionObjectForThread( + ThreadSP thread_sp) { + if (!thread_sp->SafeToCallFunctions()) + return {}; + + ClangASTContext *clang_ast_context = + m_process->GetTarget().GetScratchClangASTContext(); + CompilerType voidstar = + clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + + DiagnosticManager diagnostics; + ExecutionContext exe_ctx; + EvaluateExpressionOptions options; + + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetStopOthers(true); + options.SetTimeout(std::chrono::milliseconds(500)); + options.SetTryAllThreads(false); + thread_sp->CalculateExecutionContext(exe_ctx); + + const ModuleList &modules = m_process->GetTarget().GetImages(); + SymbolContextList contexts; + SymbolContext context; + + modules.FindSymbolsWithNameAndType( + ConstString("__cxa_current_exception_type"), eSymbolTypeCode, contexts); + contexts.GetContextAtIndex(0, context); + Address addr = context.symbol->GetAddress(); + + Status error; + FunctionCaller *function_caller = + m_process->GetTarget().GetFunctionCallerForLanguage( + eLanguageTypeC, voidstar, addr, ValueList(), "caller", error); + + ExpressionResults func_call_ret; + Value results; + func_call_ret = function_caller->ExecuteFunction(exe_ctx, nullptr, options, + diagnostics, results); + if (func_call_ret != eExpressionCompleted || !error.Success()) { + return ValueObjectSP(); + } + + size_t ptr_size = m_process->GetAddressByteSize(); + addr_t result_ptr = results.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + addr_t exception_addr = + m_process->ReadPointerFromMemory(result_ptr - ptr_size, error); + + lldb_private::formatters::InferiorSizedWord exception_isw(exception_addr, + *m_process); + ValueObjectSP exception = ValueObject::CreateValueObjectFromData( + "exception", exception_isw.GetAsData(m_process->GetByteOrder()), exe_ctx, + voidstar); + exception = exception->GetDynamicValue(eDynamicDontRunTarget); + + return exception; +} + TypeAndOrName ItaniumABILanguageRuntime::GetDynamicTypeInfo( const lldb_private::Address &vtable_addr) { std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h index 480c32691c8b..abed3706c6b8 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h @@ -10,14 +10,10 @@ #ifndef liblldb_ItaniumABILanguageRuntime_h_ #define liblldb_ItaniumABILanguageRuntime_h_ -// C Includes -// C++ Includes #include <map> #include <mutex> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointResolver.h" #include "lldb/Core/Value.h" #include "lldb/Symbol/Type.h" @@ -69,6 +65,9 @@ public: bool throw_bp) override; lldb::SearchFilterSP CreateExceptionSearchFilter() override; + + lldb::ValueObjectSP GetExceptionObjectForThread( + lldb::ThreadSP thread_sp) override; //------------------------------------------------------------------ // PluginInterface protocol diff --git a/source/Plugins/LanguageRuntime/Go/CMakeLists.txt b/source/Plugins/LanguageRuntime/Go/CMakeLists.txt index 16756d5c985a..62418def58f6 100644 --- a/source/Plugins/LanguageRuntime/Go/CMakeLists.txt +++ b/source/Plugins/LanguageRuntime/Go/CMakeLists.txt @@ -1,8 +1,6 @@ set(LLVM_NO_RTTI 1) add_lldb_library(lldbPluginLanguageRuntimeGo PLUGIN - GoLanguageRuntime.cpp - LINK_LIBS lldbBreakpoint lldbCore diff --git a/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp b/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp deleted file mode 100644 index 6670f89dde5f..000000000000 --- a/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp +++ /dev/null @@ -1,215 +0,0 @@ -//===-- GoLanguageRuntime.cpp --------------------------------------*- C++ -//-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "GoLanguageRuntime.h" - -#include "lldb/Breakpoint/BreakpointLocation.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/Scalar.h" -#include "lldb/Core/ValueObject.h" -#include "lldb/Core/ValueObjectMemory.h" -#include "lldb/Symbol/GoASTContext.h" -#include "lldb/Symbol/Symbol.h" -#include "lldb/Symbol/SymbolFile.h" -#include "lldb/Symbol/TypeList.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/SectionLoadList.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.h" -#include "llvm/ADT/Twine.h" - -#include <vector> - -using namespace lldb; -using namespace lldb_private; - -namespace { -ValueObjectSP GetChild(ValueObject &obj, const char *name, - bool dereference = true) { - ConstString name_const_str(name); - ValueObjectSP result = obj.GetChildMemberWithName(name_const_str, true); - if (dereference && result && result->IsPointerType()) { - Status err; - result = result->Dereference(err); - if (err.Fail()) - result.reset(); - } - return result; -} - -ConstString ReadString(ValueObject &str, Process *process) { - ConstString result; - ValueObjectSP data = GetChild(str, "str", false); - ValueObjectSP len = GetChild(str, "len"); - if (len && data) { - Status err; - lldb::addr_t addr = data->GetPointerValue(); - if (addr == LLDB_INVALID_ADDRESS) - return result; - uint64_t byte_size = len->GetValueAsUnsigned(0); - char *buf = new char[byte_size + 1]; - buf[byte_size] = 0; - size_t bytes_read = process->ReadMemory(addr, buf, byte_size, err); - if (!(err.Fail() || bytes_read != byte_size)) - result = ConstString(buf, bytes_read); - delete[] buf; - } - return result; -} - -ConstString ReadTypeName(ValueObjectSP type, Process *process) { - if (ValueObjectSP uncommon = GetChild(*type, "x")) { - ValueObjectSP name = GetChild(*uncommon, "name"); - ValueObjectSP package = GetChild(*uncommon, "pkgpath"); - if (name && name->GetPointerValue() != 0 && package && - package->GetPointerValue() != 0) { - ConstString package_const_str = ReadString(*package, process); - ConstString name_const_str = ReadString(*name, process); - if (package_const_str.GetLength() == 0) - return name_const_str; - return ConstString((package_const_str.GetStringRef() + "." + - name_const_str.GetStringRef()) - .str()); - } - } - ValueObjectSP name = GetChild(*type, "_string"); - if (name) - return ReadString(*name, process); - return ConstString(""); -} - -CompilerType LookupRuntimeType(ValueObjectSP type, ExecutionContext *exe_ctx, - bool *is_direct) { - uint8_t kind = GetChild(*type, "kind")->GetValueAsUnsigned(0); - *is_direct = GoASTContext::IsDirectIface(kind); - if (GoASTContext::IsPointerKind(kind)) { - CompilerType type_ptr = type->GetCompilerType().GetPointerType(); - Status err; - ValueObjectSP elem = - type->CreateValueObjectFromAddress("elem", type->GetAddressOf() + - type->GetByteSize(), - *exe_ctx, type_ptr) - ->Dereference(err); - if (err.Fail()) - return CompilerType(); - bool tmp_direct; - return LookupRuntimeType(elem, exe_ctx, &tmp_direct).GetPointerType(); - } - Target *target = exe_ctx->GetTargetPtr(); - Process *process = exe_ctx->GetProcessPtr(); - - ConstString const_typename = ReadTypeName(type, process); - if (const_typename.GetLength() == 0) - return CompilerType(); - - SymbolContext sc; - TypeList type_list; - llvm::DenseSet<SymbolFile *> searched_symbol_files; - uint32_t num_matches = target->GetImages().FindTypes( - sc, const_typename, false, 2, searched_symbol_files, type_list); - if (num_matches > 0) { - return type_list.GetTypeAtIndex(0)->GetFullCompilerType(); - } - return CompilerType(); -} -} - -bool GoLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { - return GoASTContext::IsGoInterface(in_value.GetCompilerType()); -} - -bool GoLanguageRuntime::GetDynamicTypeAndAddress( - ValueObject &in_value, lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, Address &dynamic_address, - Value::ValueType &value_type) { - value_type = Value::eValueTypeScalar; - class_type_or_name.Clear(); - if (CouldHaveDynamicValue(in_value)) { - Status err; - ValueObjectSP iface = in_value.GetStaticValue(); - ValueObjectSP data_sp = GetChild(*iface, "data", false); - if (!data_sp) - return false; - - if (ValueObjectSP tab = GetChild(*iface, "tab")) - iface = tab; - ValueObjectSP type = GetChild(*iface, "_type"); - if (!type) { - return false; - } - - bool direct; - ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); - CompilerType final_type = LookupRuntimeType(type, &exe_ctx, &direct); - if (!final_type) - return false; - if (direct) { - class_type_or_name.SetCompilerType(final_type); - } else { - // TODO: implement reference types or fix caller to support dynamic types - // that aren't pointers - // so we don't have to introduce this extra pointer. - class_type_or_name.SetCompilerType(final_type.GetPointerType()); - } - - dynamic_address.SetLoadAddress(data_sp->GetPointerValue(), - exe_ctx.GetTargetPtr()); - - return true; - } - return false; -} - -TypeAndOrName -GoLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, - ValueObject &static_value) { - return type_and_or_name; -} - -//------------------------------------------------------------------ -// Static Functions -//------------------------------------------------------------------ -LanguageRuntime * -GoLanguageRuntime::CreateInstance(Process *process, - lldb::LanguageType language) { - if (language == eLanguageTypeGo) - return new GoLanguageRuntime(process); - else - return NULL; -} - -void GoLanguageRuntime::Initialize() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), "Go Language Runtime", - CreateInstance); -} - -void GoLanguageRuntime::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -lldb_private::ConstString GoLanguageRuntime::GetPluginNameStatic() { - static ConstString g_name("golang"); - return g_name; -} - -//------------------------------------------------------------------ -// PluginInterface protocol -//------------------------------------------------------------------ -lldb_private::ConstString GoLanguageRuntime::GetPluginName() { - return GetPluginNameStatic(); -} - -uint32_t GoLanguageRuntime::GetPluginVersion() { return 1; } diff --git a/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.h b/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.h deleted file mode 100644 index 9c2ee15cff65..000000000000 --- a/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.h +++ /dev/null @@ -1,86 +0,0 @@ -//===-- GoLanguageRuntime.h -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_GoLanguageRuntime_h_ -#define liblldb_GoLanguageRuntime_h_ - -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes -#include "lldb/Breakpoint/BreakpointResolver.h" -#include "lldb/Core/Value.h" -#include "lldb/Target/LanguageRuntime.h" -#include "lldb/lldb-private.h" - -namespace lldb_private { - -class GoLanguageRuntime : public lldb_private::LanguageRuntime { -public: - ~GoLanguageRuntime() override = default; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void Initialize(); - - static void Terminate(); - - static lldb_private::LanguageRuntime * - CreateInstance(Process *process, lldb::LanguageType language); - - static lldb_private::ConstString GetPluginNameStatic(); - - lldb::LanguageType GetLanguageType() const override { - return lldb::eLanguageTypeGo; - } - - bool GetObjectDescription(Stream &str, ValueObject &object) override { - // TODO(ribrdb): Maybe call String() method? - return false; - } - - bool GetObjectDescription(Stream &str, Value &value, - ExecutionContextScope *exe_scope) override { - return false; - } - - bool GetDynamicTypeAndAddress(ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) override; - - bool CouldHaveDynamicValue(ValueObject &in_value) override; - - lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, - bool catch_bp, - bool throw_bp) override { - return lldb::BreakpointResolverSP(); - } - - TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, - ValueObject &static_value) override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; - -private: - GoLanguageRuntime(Process *process) - : lldb_private::LanguageRuntime(process) { - } // Call CreateInstance instead. -}; - -} // namespace lldb_private - -#endif // liblldb_GoLanguageRuntime_h_ diff --git a/source/Plugins/LanguageRuntime/Java/CMakeLists.txt b/source/Plugins/LanguageRuntime/Java/CMakeLists.txt deleted file mode 100644 index ec87718752e7..000000000000 --- a/source/Plugins/LanguageRuntime/Java/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_lldb_library(lldbPluginLanguageRuntimeJava PLUGIN - JavaLanguageRuntime.cpp - - LINK_LIBS - lldbCore - lldbSymbol - lldbTarget - LINK_COMPONENTS - Support - ) diff --git a/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.cpp b/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.cpp deleted file mode 100644 index 36c30a99ff87..000000000000 --- a/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.cpp +++ /dev/null @@ -1,157 +0,0 @@ -//===-- JavaLanguageRuntime.cpp ---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "JavaLanguageRuntime.h" - -#include "lldb/Core/PluginManager.h" -#include "lldb/Symbol/JavaASTContext.h" -#include "lldb/Symbol/Symbol.h" -#include "lldb/Symbol/SymbolContext.h" -#include "lldb/Symbol/SymbolFile.h" -#include "lldb/Symbol/Type.h" -#include "lldb/Symbol/TypeList.h" -#include "lldb/Target/SectionLoadList.h" -#include "lldb/Target/Target.h" -#include "llvm/ADT/StringRef.h" - -using namespace lldb; -using namespace lldb_private; - -JavaLanguageRuntime::JavaLanguageRuntime(Process *process) - : LanguageRuntime(process) {} - -LanguageRuntime * -JavaLanguageRuntime::CreateInstance(Process *process, - lldb::LanguageType language) { - if (language == eLanguageTypeJava) - return new JavaLanguageRuntime(process); - return nullptr; -} - -void JavaLanguageRuntime::Initialize() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), "Java language runtime", - CreateInstance); -} - -void JavaLanguageRuntime::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -lldb_private::ConstString JavaLanguageRuntime::GetPluginNameStatic() { - static ConstString g_name("java"); - return g_name; -} - -lldb_private::ConstString JavaLanguageRuntime::GetPluginName() { - return GetPluginNameStatic(); -} - -uint32_t JavaLanguageRuntime::GetPluginVersion() { return 1; } - -bool JavaLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { - return true; -} - -static ConstString GetDynamicTypeId(ExecutionContext *exe_ctx, Target *target, - ValueObject &in_value) { - SymbolContext sc; - TypeList class_types; - llvm::DenseSet<SymbolFile *> searched_symbol_files; - size_t num_matches = target->GetImages().FindTypes( - sc, ConstString("Object"), - true, // name_is_fully_qualified - UINT32_MAX, searched_symbol_files, class_types); - for (size_t i = 0; i < num_matches; ++i) { - TypeSP type_sp = class_types.GetTypeAtIndex(i); - CompilerType compiler_type = type_sp->GetFullCompilerType(); - - if (compiler_type.GetMinimumLanguage() != eLanguageTypeJava || - compiler_type.GetTypeName() != ConstString("java::lang::Object")) - continue; - - if (compiler_type.GetCompleteType() && compiler_type.IsCompleteType()) { - uint64_t type_id = JavaASTContext::CalculateDynamicTypeId( - exe_ctx, compiler_type, in_value); - if (type_id != UINT64_MAX) { - char id[32]; - snprintf(id, sizeof(id), "0x%" PRIX64, type_id); - return ConstString(id); - } - } - } - return ConstString(); -} - -bool JavaLanguageRuntime::GetDynamicTypeAndAddress( - ValueObject &in_value, lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, Address &dynamic_address, - Value::ValueType &value_type) { - class_type_or_name.Clear(); - - // null references don't have a dynamic type - if (in_value.IsNilReference()) - return false; - - ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); - Target *target = exe_ctx.GetTargetPtr(); - if (!target) - return false; - - ConstString linkage_name; - CompilerType in_type = in_value.GetCompilerType(); - if (in_type.IsPossibleDynamicType(nullptr, false, false)) - linkage_name = GetDynamicTypeId(&exe_ctx, target, in_value); - else - linkage_name = JavaASTContext::GetLinkageName(in_type); - - if (!linkage_name) - return false; - - class_type_or_name.SetName(in_type.GetNonReferenceType().GetTypeName()); - - SymbolContext sc; - TypeList class_types; - llvm::DenseSet<SymbolFile *> searched_symbol_files; - size_t num_matches = target->GetImages().FindTypes( - sc, linkage_name, - true, // name_is_fully_qualified - UINT32_MAX, searched_symbol_files, class_types); - - for (size_t i = 0; i < num_matches; ++i) { - TypeSP type_sp = class_types.GetTypeAtIndex(i); - CompilerType compiler_type = type_sp->GetFullCompilerType(); - - if (compiler_type.GetMinimumLanguage() != eLanguageTypeJava) - continue; - - if (compiler_type.GetCompleteType() && compiler_type.IsCompleteType()) { - class_type_or_name.SetTypeSP(type_sp); - - Value &value = in_value.GetValue(); - value_type = value.GetValueType(); - dynamic_address.SetRawAddress(value.GetScalar().ULongLong(0)); - return true; - } - } - return false; -} - -TypeAndOrName -JavaLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, - ValueObject &static_value) { - CompilerType static_type(static_value.GetCompilerType()); - - TypeAndOrName ret(type_and_or_name); - if (type_and_or_name.HasType()) { - CompilerType orig_type = type_and_or_name.GetCompilerType(); - if (static_type.IsReferenceType()) - ret.SetCompilerType(orig_type.GetLValueReferenceType()); - } - return ret; -} diff --git a/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.h b/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.h deleted file mode 100644 index 6eeb4041572a..000000000000 --- a/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.h +++ /dev/null @@ -1,78 +0,0 @@ -//===-- JavaLanguageRuntime.h -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_JavaLanguageRuntime_h_ -#define liblldb_JavaLanguageRuntime_h_ - -// C Includes -// C++ Includes -#include <vector> -// Other libraries and framework includes -// Project includes -#include "lldb/Core/PluginInterface.h" -#include "lldb/Target/LanguageRuntime.h" -#include "lldb/lldb-private.h" - -namespace lldb_private { - -class JavaLanguageRuntime : public LanguageRuntime { -public: - static void Initialize(); - - static void Terminate(); - - static lldb_private::LanguageRuntime * - CreateInstance(Process *process, lldb::LanguageType language); - - static lldb_private::ConstString GetPluginNameStatic(); - - lldb_private::ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; - - lldb::LanguageType GetLanguageType() const override { - return lldb::eLanguageTypeJava; - } - - bool GetObjectDescription(Stream &str, ValueObject &object) override { - return false; - } - - bool GetObjectDescription(Stream &str, Value &value, - ExecutionContextScope *exe_scope) override { - return false; - } - - lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, - bool catch_bp, - bool throw_bp) override { - return nullptr; - } - - TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, - ValueObject &static_value) override; - - bool CouldHaveDynamicValue(ValueObject &in_value) override; - - bool GetDynamicTypeAndAddress(ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) override; - -protected: - JavaLanguageRuntime(Process *process); - -private: - DISALLOW_COPY_AND_ASSIGN(JavaLanguageRuntime); -}; - -} // namespace lldb_private - -#endif // liblldb_JavaLanguageRuntime_h_ diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp index edb29e735ca9..679c3c850e5b 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp @@ -264,11 +264,7 @@ bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr) { } process->ReadCStringFromMemory(m_types_ptr, m_types, error); - if (error.Fail()) { - return false; - } - - return true; + return !error.Fail(); } bool ClassDescriptorV2::ivar_list_t::Read(Process *process, lldb::addr_t addr) { @@ -323,11 +319,7 @@ bool ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) { } process->ReadCStringFromMemory(m_type_ptr, m_type, error); - if (error.Fail()) { - return false; - } - - return true; + return !error.Fail(); } bool ClassDescriptorV2::Describe( @@ -524,7 +516,8 @@ void ClassDescriptorV2::iVarsStorage::fill(AppleObjCRuntimeV2 &runtime, LLDB_LOGV(log, "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = " "{3}, type_size = {4}", - name, type, offset_ptr, size, ivar_type.GetByteSize(nullptr)); + name, type, offset_ptr, size, + ivar_type.GetByteSize(nullptr).getValueOr(0)); Scalar offset_scalar; Status error; const int offset_ptr_size = 4; diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h index 787423b54766..308ff1426fb2 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h @@ -10,12 +10,8 @@ #ifndef liblldb_AppleObjCClassDescriptorV2_h_ #define liblldb_AppleObjCClassDescriptorV2_h_ -// C Includes -// C++ Includes #include <mutex> -// Other libraries and framework includes -// Project includes #include "AppleObjCRuntimeV2.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp index 105c088b9e91..4fc340b23c2c 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -558,7 +558,7 @@ AppleObjCDeclVendor::FindDecls(const ConstString &name, bool append, LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? if (log) - log->Printf("AppleObjCDeclVendor::FindTypes [%u] ('%s', %s, %u, )", + log->Printf("AppleObjCDeclVendor::FindDecls [%u] ('%s', %s, %u, )", current_id, (const char *)name.AsCString(), append ? "true" : "false", max_matches); diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h index 2f087da16bc1..7f5c0bf3eb63 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h @@ -10,10 +10,6 @@ #ifndef liblldb_AppleObjCDeclVendor_h_ #define liblldb_AppleObjCDeclVendor_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/DeclVendor.h" #include "lldb/Target/ObjCLanguageRuntime.h" diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index fef42c78b24f..ed47b481a810 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -17,13 +17,15 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/Section.h" #include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectConstResult.h" +#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/CPPLanguageRuntime.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -32,9 +34,13 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" +#include "Plugins/Process/Utility/HistoryThread.h" +#include "Plugins/Language/ObjC/NSString.h" + #include <vector> using namespace lldb; @@ -167,6 +173,7 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, options.SetStopOthers(true); options.SetIgnoreBreakpoints(true); options.SetTimeout(g_po_function_timeout); + options.SetIsForUtilityExpr(true); ExpressionResults results = m_print_object_caller_up->ExecuteFunction( exe_ctx, &wrapper_struct_addr, options, diagnostics, ret); @@ -440,13 +447,10 @@ bool AppleObjCRuntime::CalculateHasNewLiteralsAndIndexing() { SymbolContextList sc_list; - if (target.GetImages().FindSymbolsWithNameAndType(s_method_signature, - eSymbolTypeCode, sc_list) || - target.GetImages().FindSymbolsWithNameAndType(s_arclite_method_signature, - eSymbolTypeCode, sc_list)) - return true; - else - return false; + return target.GetImages().FindSymbolsWithNameAndType( + s_method_signature, eSymbolTypeCode, sc_list) || + target.GetImages().FindSymbolsWithNameAndType( + s_arclite_method_signature, eSymbolTypeCode, sc_list); } lldb::SearchFilterSP AppleObjCRuntime::CreateExceptionSearchFilter() { @@ -454,13 +458,115 @@ lldb::SearchFilterSP AppleObjCRuntime::CreateExceptionSearchFilter() { if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) { FileSpecList filter_modules; - filter_modules.Append(FileSpec("libobjc.A.dylib", false)); + filter_modules.Append(std::get<0>(GetExceptionThrowLocation())); return target.GetSearchFilterForModuleList(&filter_modules); } else { return LanguageRuntime::CreateExceptionSearchFilter(); } } +ValueObjectSP AppleObjCRuntime::GetExceptionObjectForThread( + ThreadSP thread_sp) { + auto cpp_runtime = m_process->GetCPPLanguageRuntime(); + if (!cpp_runtime) return ValueObjectSP(); + auto cpp_exception = cpp_runtime->GetExceptionObjectForThread(thread_sp); + if (!cpp_exception) return ValueObjectSP(); + + auto descriptor = GetClassDescriptor(*cpp_exception.get()); + if (!descriptor || !descriptor->IsValid()) return ValueObjectSP(); + + while (descriptor) { + ConstString class_name(descriptor->GetClassName()); + if (class_name == ConstString("NSException")) return cpp_exception; + descriptor = descriptor->GetSuperclass(); + } + + return ValueObjectSP(); +} + +ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException( + lldb::ValueObjectSP exception_sp) { + ValueObjectSP reserved_dict = + exception_sp->GetChildMemberWithName(ConstString("reserved"), true); + if (!reserved_dict) return ThreadSP(); + + reserved_dict = reserved_dict->GetSyntheticValue(); + if (!reserved_dict) return ThreadSP(); + + CompilerType objc_id = + exception_sp->GetTargetSP()->GetScratchClangASTContext()->GetBasicType( + lldb::eBasicTypeObjCID); + ValueObjectSP return_addresses; + + auto objc_object_from_address = [&exception_sp, &objc_id](uint64_t addr, + const char *name) { + Value value(addr); + value.SetCompilerType(objc_id); + auto object = ValueObjectConstResult::Create( + exception_sp->GetTargetSP().get(), value, ConstString(name)); + object = object->GetDynamicValue(eDynamicDontRunTarget); + return object; + }; + + for (size_t idx = 0; idx < reserved_dict->GetNumChildren(); idx++) { + ValueObjectSP dict_entry = reserved_dict->GetChildAtIndex(idx, true); + + DataExtractor data; + data.SetAddressByteSize(dict_entry->GetProcessSP()->GetAddressByteSize()); + Status error; + dict_entry->GetData(data, error); + 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 key_nsstring = objc_object_from_address(dict_entry_key, "key"); + StreamString key_summary; + if (lldb_private::formatters::NSStringSummaryProvider( + *key_nsstring, key_summary, TypeSummaryOptions()) && + !key_summary.Empty()) { + if (key_summary.GetString() == "\"callStackReturnAddresses\"") { + return_addresses = objc_object_from_address(dict_entry_value, + "callStackReturnAddresses"); + break; + } + } + } + + if (!return_addresses) return ThreadSP(); + auto frames_value = + return_addresses->GetChildMemberWithName(ConstString("_frames"), true); + addr_t frames_addr = frames_value->GetValueAsUnsigned(0); + auto count_value = + return_addresses->GetChildMemberWithName(ConstString("_cnt"), true); + size_t count = count_value->GetValueAsUnsigned(0); + auto ignore_value = + return_addresses->GetChildMemberWithName(ConstString("_ignore"), true); + size_t ignore = ignore_value->GetValueAsUnsigned(0); + + size_t ptr_size = m_process->GetAddressByteSize(); + std::vector<lldb::addr_t> pcs; + for (size_t idx = 0; idx < count; idx++) { + Status error; + addr_t pc = m_process->ReadPointerFromMemory( + frames_addr + (ignore + idx) * ptr_size, error); + pcs.push_back(pc); + } + + if (pcs.empty()) return ThreadSP(); + + ThreadSP new_thread_sp(new HistoryThread(*m_process, 0, pcs, 0, false)); + m_process->GetExtendedThreadList().AddThread(new_thread_sp); + return new_thread_sp; +} + +std::tuple<FileSpec, ConstString> +AppleObjCRuntime::GetExceptionThrowLocation() { + return std::make_tuple( + FileSpec("libobjc.A.dylib"), ConstString("objc_exception_throw")); +} + void AppleObjCRuntime::ReadObjCLibraryIfNeeded(const ModuleList &module_list) { if (!HasReadObjCLibrary()) { std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h index 1b22ee4c3be1..866064600149 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h @@ -10,12 +10,8 @@ #ifndef liblldb_AppleObjCRuntime_h_ #define liblldb_AppleObjCRuntime_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/Optional.h" -// Project includes #include "AppleObjCTrampolineHandler.h" #include "AppleThreadPlanStepThroughObjCTrampoline.h" #include "lldb/Target/LanguageRuntime.h" @@ -90,6 +86,14 @@ public: bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override; lldb::SearchFilterSP CreateExceptionSearchFilter() override; + + static std::tuple<FileSpec, ConstString> GetExceptionThrowLocation(); + + lldb::ValueObjectSP GetExceptionObjectForThread( + lldb::ThreadSP thread_sp) override; + + lldb::ThreadSP GetBacktraceThreadFromException( + lldb::ValueObjectSP thread_sp) override; uint32_t GetFoundationVersion(); diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 5001c0461b3b..1cfc7a1a022b 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -17,7 +17,6 @@ #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/Scalar.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" #include "lldb/Symbol/ClangASTContext.h" @@ -29,6 +28,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" @@ -58,7 +58,7 @@ bool AppleObjCRuntimeV1::GetDynamicTypeAndAddress( class_type_or_name.SetName(class_descriptor->GetClassName()); } } - return class_type_or_name.IsEmpty() == false; + return !class_type_or_name.IsEmpty(); } //------------------------------------------------------------------ @@ -113,8 +113,9 @@ AppleObjCRuntimeV1::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, if (throw_bp) resolver_sp.reset(new BreakpointResolverName( - bkpt, "objc_exception_throw", eFunctionNameTypeBase, - eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo)); + bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(), + eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0, + eLazyBoolNo)); // FIXME: don't do catch yet. return resolver_sp; } diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h index 52eec0f692fb..442a3a1fb5e1 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h @@ -10,10 +10,6 @@ #ifndef liblldb_AppleObjCRuntimeV1_h_ #define liblldb_AppleObjCRuntimeV1_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "AppleObjCRuntime.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index d217ed3ff325..b6ed2fe376d3 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -7,18 +7,14 @@ // //===----------------------------------------------------------------------===// -// C Includes #include <stdint.h> -// C++ Includes #include <string> #include <vector> -// Other libraries and framework includes #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" -// Project includes #include "lldb/Core/ClangForward.h" #include "lldb/Host/OptionParser.h" #include "lldb/Symbol/CompilerType.h" @@ -28,8 +24,8 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/Section.h" +#include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" @@ -44,14 +40,17 @@ #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" @@ -377,6 +376,8 @@ ExtractRuntimeGlobalSymbol(Process *process, ConstString name, } } +static void RegisterObjCExceptionRecognizer(); + AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process, const ModuleSP &objc_module_sp) : AppleObjCRuntime(process), m_get_class_info_code(), @@ -397,6 +398,7 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process, static const ConstString g_gdb_object_getClass("gdb_object_getClass"); m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType( g_gdb_object_getClass, eSymbolTypeCode) != NULL); + RegisterObjCExceptionRecognizer(); } bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress( @@ -452,7 +454,7 @@ bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress( } } } - return class_type_or_name.IsEmpty() == false; + return !class_type_or_name.IsEmpty(); } //------------------------------------------------------------------ @@ -475,9 +477,9 @@ LanguageRuntime *AppleObjCRuntimeV2::CreateInstance(Process *process, return NULL; } -static OptionDefinition g_objc_classtable_dump_options[] = { +static constexpr OptionDefinition g_objc_classtable_dump_options[] = { {LLDB_OPT_SET_ALL, false, "verbose", 'v', OptionParser::eNoArgument, - nullptr, nullptr, 0, eArgTypeNone, + nullptr, {}, 0, eArgTypeNone, "Print ivar and method information in detail"}}; class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed { @@ -803,8 +805,9 @@ AppleObjCRuntimeV2::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, if (throw_bp) resolver_sp.reset(new BreakpointResolverName( - bkpt, "objc_exception_throw", eFunctionNameTypeBase, - eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo)); + bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(), + eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0, + eLazyBoolNo)); // FIXME: We don't do catch breakpoints for ObjC yet. // Should there be some way for the runtime to specify what it can do in this // regard? @@ -1409,6 +1412,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( options.SetStopOthers(true); options.SetIgnoreBreakpoints(true); options.SetTimeout(g_utility_function_timeout); + options.SetIsForUtilityExpr(true); Value return_value; return_value.SetValueType(Value::eValueTypeScalar); @@ -1659,6 +1663,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { options.SetStopOthers(true); options.SetIgnoreBreakpoints(true); options.SetTimeout(g_utility_function_timeout); + options.SetIsForUtilityExpr(true); Value return_value; return_value.SetValueType(Value::eValueTypeScalar); @@ -1847,8 +1852,8 @@ void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() { // warn if: // - we could not run either expression // - we found fewer than num_classes_to_warn_at classes total - if ((false == shared_cache_update_result.m_update_ran) || - (false == dynamic_update_result.m_update_ran)) + if ((!shared_cache_update_result.m_update_ran) || + (!dynamic_update_result.m_update_ran)) WarnIfNoClassesCached( SharedCacheWarningReason::eExpressionExecutionFailure); else if (dynamic_update_result.m_num_found + @@ -2423,7 +2428,7 @@ AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache( ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor(ObjCISA isa) { ObjCISA real_isa = 0; - if (EvaluateNonPointerISA(isa, real_isa) == false) + if (!EvaluateNonPointerISA(isa, real_isa)) return ObjCLanguageRuntime::ClassDescriptorSP(); auto cache_iter = m_cache.find(real_isa); if (cache_iter != m_cache.end()) @@ -2447,7 +2452,7 @@ bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( // If all of the indexed ISA variables are set, then its possible that this // ISA is indexed, and we should first try to get its value using the index. - // Note, we check these varaibles first as the ObjC runtime will set at least + // Note, we check these variables first as the ObjC runtime will set at least // one of their values to 0 if they aren't needed. if (m_objc_debug_indexed_isa_magic_mask && m_objc_debug_indexed_isa_magic_value && @@ -2534,7 +2539,7 @@ bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( return false; } - // Definately not an indexed ISA, so try to use a mask to extract the pointer + // Definitely not an indexed ISA, so try to use a mask to extract the pointer // from the ISA. if ((isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value) { ret_isa = isa & m_objc_debug_isa_class_mask; @@ -2594,3 +2599,62 @@ void AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, } else this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false); } + +#pragma mark Frame recognizers + +class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame { + public: + ObjCExceptionRecognizedStackFrame(StackFrameSP frame_sp) { + ThreadSP thread_sp = frame_sp->GetThread(); + ProcessSP process_sp = thread_sp->GetProcess(); + + const lldb::ABISP &abi = process_sp->GetABI(); + if (!abi) return; + + CompilerType voidstar = process_sp->GetTarget() + .GetScratchClangASTContext() + ->GetBasicType(lldb::eBasicTypeVoid) + .GetPointerType(); + + ValueList args; + Value input_value; + input_value.SetCompilerType(voidstar); + args.PushValue(input_value); + + if (!abi->GetArgumentValues(*thread_sp, args)) return; + + addr_t exception_addr = args.GetValueAtIndex(0)->GetScalar().ULongLong(); + + Value value(exception_addr); + value.SetCompilerType(voidstar); + exception = ValueObjectConstResult::Create(frame_sp.get(), value, + ConstString("exception")); + exception = exception->GetDynamicValue(eDynamicDontRunTarget); + + m_arguments = ValueObjectListSP(new ValueObjectList()); + m_arguments->Append(exception); + } + + ValueObjectSP exception; + + lldb::ValueObjectSP GetExceptionObject() override { return exception; } +}; + +class ObjCExceptionThrowFrameRecognizer : public StackFrameRecognizer { + lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame) { + return lldb::RecognizedStackFrameSP( + new ObjCExceptionRecognizedStackFrame(frame)); + }; +}; + +static void RegisterObjCExceptionRecognizer() { + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, []() { + FileSpec module; + ConstString function; + std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation(); + StackFrameRecognizerManager::AddRecognizer( + StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()), + module.GetFilename(), function, /*first_instruction_only*/ true); + }); +} diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index 487b67ca6271..aa91f857219b 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -10,14 +10,10 @@ #ifndef liblldb_AppleObjCRuntimeV2_h_ #define liblldb_AppleObjCRuntimeV2_h_ -// C Includes -// C++ Includes #include <map> #include <memory> #include <mutex> -// Other libraries and framework includes -// Project includes #include "AppleObjCRuntime.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index c75fa71ba131..e9182c590977 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -10,10 +10,6 @@ #include "AppleObjCTrampolineHandler.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "AppleThreadPlanStepThroughObjCTrampoline.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" @@ -80,7 +76,7 @@ extern \"C\" void * __lldb_objc_find_implementation_for_selector ( \n\ void *super_ptr; \n\ }; \n\ struct __lldb_objc_super { \n\ - void *reciever; \n\ + void *receiver; \n\ struct __lldb_objc_class *class_ptr; \n\ }; \n\ struct __lldb_msg_ref { \n\ @@ -202,7 +198,7 @@ extern \"C\" void * __lldb_objc_find_implementation_for_selector (void *object, void *super_ptr; \n\ }; \n\ struct __lldb_objc_super { \n\ - void *reciever; \n\ + void *receiver; \n\ struct __lldb_objc_class *class_ptr; \n\ }; \n\ struct __lldb_msg_ref { \n\ diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h index dc58a8bc1eb6..fe3390757d08 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h @@ -10,14 +10,10 @@ #ifndef lldb_AppleObjCTrampolineHandler_h_ #define lldb_AppleObjCTrampolineHandler_h_ -// C Includes -// C++ Includes #include <map> #include <mutex> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Expression/UtilityFunction.h" #include "lldb/lldb-public.h" diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h index 4da84dd92c3f..fac564e33165 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h @@ -10,12 +10,8 @@ #ifndef liblldb_AppleObjCTypeEncodingParser_h_ #define liblldb_AppleObjCTypeEncodingParser_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes #include "clang/AST/ASTContext.h" -// Project includes #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index 75b670739427..2b54d0a542d9 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -8,10 +8,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "AppleThreadPlanStepThroughObjCTrampoline.h" #include "AppleObjCTrampolineHandler.h" #include "lldb/Expression/DiagnosticManager.h" @@ -161,13 +157,15 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { SymbolContext sc = m_thread.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( abort_other_plans, &sc, first_insn, m_stop_others, eVoteNoOpinion, - eVoteNoOpinion, frame_idx); - m_run_to_sp->SetPrivate(true); + eVoteNoOpinion, frame_idx, status); + if (m_run_to_sp && status.Success()) + m_run_to_sp->SetPrivate(true); return false; } @@ -202,10 +200,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { // The base class MischiefManaged does some cleanup - so you have to call it in // your MischiefManaged derived class. bool AppleThreadPlanStepThroughObjCTrampoline::MischiefManaged() { - if (IsPlanComplete()) - return true; - else - return false; + return IsPlanComplete(); } bool AppleThreadPlanStepThroughObjCTrampoline::WillStop() { return true; } diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h index 60c8b92d9cc7..5758e19f83ca 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h @@ -10,10 +10,6 @@ #ifndef lldb_AppleThreadPlanStepThroughObjCTrampoline_h_ #define lldb_AppleThreadPlanStepThroughObjCTrampoline_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "AppleObjCTrampolineHandler.h" #include "lldb/Core/Value.h" #include "lldb/Target/ThreadPlan.h" diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp index cbbc35f1c08a..2c12cf9af637 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp @@ -7,11 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes #include "llvm/ADT/None.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/Instruction.h" @@ -24,7 +21,6 @@ #include "clang/Basic/TargetOptions.h" -// Project includes #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Log.h" diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h index f45ff83c5a2b..647558171d1c 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h @@ -10,15 +10,11 @@ #ifndef LLDB_RENDERSCRIPT_EXPROPTS_H #define LLDB_RENDERSCRIPT_EXPROPTS_H -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/IR/Module.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" -// Project includes #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp index 4eb15369aa1e..fa775d9bfa94 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -7,12 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/StringSwitch.h" -// Project includes #include "RenderScriptRuntime.h" #include "RenderScriptScriptGroup.h" @@ -20,7 +16,6 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/DumpDataExtractor.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/DataFormatters/DumpValueObjectOptions.h" #include "lldb/Expression/UserExpression.h" @@ -41,8 +36,8 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/ConstString.h" -#include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Status.h" @@ -2079,10 +2074,8 @@ bool RenderScriptRuntime::JITElementPacked(Element &elem, // If this Element has subelements then JIT rsaElementGetSubElements() for // details about its fields - if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr)) - return false; - - return true; + return !(*elem.field_count.get() > 0 && + !JITSubelements(elem, context, frame_ptr)); } // JITs the RS runtime for information about the subelements/fields of a struct @@ -2305,10 +2298,7 @@ bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *alloc, SetElementSize(alloc->element); // Use GetOffsetPointer() to infer size of the allocation - if (!JITAllocationSize(alloc, frame_ptr)) - return false; - - return true; + return JITAllocationSize(alloc, frame_ptr); } // Function attempts to set the type_name member of the paramaterised Element @@ -2529,21 +2519,22 @@ bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, "Allocation information not available"); // Check we can read from file - FileSpec file(path, true); - if (!file.Exists()) { + FileSpec file(path); + FileSystem::Instance().Resolve(file); + if (!FileSystem::Instance().Exists(file)) { strm.Printf("Error: File %s does not exist", path); strm.EOL(); return false; } - if (!file.Readable()) { + if (!FileSystem::Instance().Readable(file)) { strm.Printf("Error: File %s does not have readable permissions", path); strm.EOL(); return false; } // Read file into data buffer - auto data_sp = DataBufferLLVM::CreateFromPath(file.GetPath()); + auto data_sp = FileSystem::Instance().CreateDataBuffer(file.GetPath()); // Cast start of buffer to FileHeader and use pointer to read metadata void *file_buf = data_sp->GetBytes(); @@ -2753,9 +2744,14 @@ bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, "Allocation information not available"); // Check we can create writable file - FileSpec file_spec(path, true); - File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | - File::eOpenOptionTruncate); + FileSpec file_spec(path); + FileSystem::Instance().Resolve(file_spec); + File file; + FileSystem::Instance().Open(file, file_spec, + File::eOpenOptionWrite | + File::eOpenOptionCanCreate | + File::eOpenOptionTruncate); + if (!file) { strm.Printf("Error: Failed to open '%s' for writing", path); strm.EOL(); @@ -3079,7 +3075,8 @@ bool RSModuleDescriptor::ParseRSInfo() { const addr_t size = info_sym->GetByteSize(); const FileSpec fs = m_module->GetFileSpec(); - auto buffer = DataBufferLLVM::CreateSliceFromPath(fs.GetPath(), size, addr); + auto buffer = + FileSystem::Instance().CreateDataBuffer(fs.GetPath(), size, addr); if (!buffer) return false; @@ -3718,7 +3715,8 @@ bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, continue; // Find the function name - const SymbolContext sym_ctx = frame_sp->GetSymbolContext(false); + const SymbolContext sym_ctx = + frame_sp->GetSymbolContext(eSymbolContextFunction); const ConstString func_name = sym_ctx.GetFunctionName(); if (!func_name) continue; @@ -4171,13 +4169,13 @@ public: } }; -static OptionDefinition g_renderscript_reduction_bp_set_options[] = { +static constexpr OptionDefinition g_renderscript_reduction_bp_set_options[] = { {LLDB_OPT_SET_1, false, "function-role", 't', - OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOneLiner, + OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOneLiner, "Break on a comma separated set of reduction kernel types " "(accumulator,outcoverter,combiner,initializer"}, {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, - nullptr, nullptr, 0, eArgTypeValue, + nullptr, {}, 0, eArgTypeValue, "Set a breakpoint on a single invocation of the kernel with specified " "coordinate.\n" "Coordinate takes the form 'x[,y][,z] where x,y,z are positive " @@ -4330,9 +4328,9 @@ private: CommandOptions m_options; }; -static OptionDefinition g_renderscript_kernel_bp_set_options[] = { +static constexpr OptionDefinition g_renderscript_kernel_bp_set_options[] = { {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, - nullptr, nullptr, 0, eArgTypeValue, + nullptr, {}, 0, eArgTypeValue, "Set a breakpoint on a single invocation of the kernel with specified " "coordinate.\n" "Coordinate takes the form 'x[,y][,z] where x,y,z are positive " @@ -4602,9 +4600,9 @@ public: } }; -static OptionDefinition g_renderscript_runtime_alloc_dump_options[] = { +static constexpr OptionDefinition g_renderscript_runtime_alloc_dump_options[] = { {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, - nullptr, nullptr, 0, eArgTypeFilename, + nullptr, {}, 0, eArgTypeFilename, "Print results to specified file instead of command line."}}; class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword { @@ -4650,8 +4648,9 @@ public: switch (short_option) { case 'f': - m_outfile.SetFile(option_arg, true, FileSpec::Style::native); - if (m_outfile.Exists()) { + m_outfile.SetFile(option_arg, FileSpec::Style::native); + FileSystem::Instance().Resolve(m_outfile); + if (FileSystem::Instance().Exists(m_outfile)) { m_outfile.Clear(); err.SetErrorStringWithFormat("file already exists: '%s'", option_arg.str().c_str()); @@ -4706,16 +4705,17 @@ public: m_options.m_outfile; // Dump allocation to file instead if (outfile_spec) { // Open output file - char path[256]; - outfile_spec.GetPath(path, sizeof(path)); - if (outfile_stream.GetFile() - .Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate) - .Success()) { + std::string path = outfile_spec.GetPath(); + auto error = FileSystem::Instance().Open( + outfile_stream.GetFile(), outfile_spec, + File::eOpenOptionWrite | File::eOpenOptionCanCreate); + if (error.Success()) { output_strm = &outfile_stream; - result.GetOutputStream().Printf("Results written to '%s'", path); + result.GetOutputStream().Printf("Results written to '%s'", + path.c_str()); result.GetOutputStream().EOL(); } else { - result.AppendErrorWithFormat("Couldn't open file '%s'", path); + result.AppendErrorWithFormat("Couldn't open file '%s'", path.c_str()); result.SetStatus(eReturnStatusFailed); return false; } @@ -4738,9 +4738,9 @@ private: CommandOptions m_options; }; -static OptionDefinition g_renderscript_runtime_alloc_list_options[] = { +static constexpr OptionDefinition g_renderscript_runtime_alloc_list_options[] = { {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, nullptr, - nullptr, 0, eArgTypeIndex, + {}, 0, eArgTypeIndex, "Only show details of a single allocation with specified id."}}; class CommandObjectRenderScriptRuntimeAllocationList diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h index 0fe9134ce9e4..31714dd4a453 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h @@ -10,18 +10,14 @@ #ifndef liblldb_RenderScriptRuntime_h_ #define liblldb_RenderScriptRuntime_h_ -// C Includes -// C++ Includes #include <array> #include <map> #include <memory> #include <string> #include <vector> -// Other libraries and framework includes #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -// Project includes #include "lldb/Core/Module.h" #include "lldb/Expression/LLVMUserExpression.h" #include "lldb/Target/CPPLanguageRuntime.h" @@ -74,7 +70,7 @@ public: SymbolContext &context, Address *addr, bool containing) override; - Searcher::Depth GetDepth() override { return Searcher::eDepthModule; } + lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } lldb::BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override { @@ -124,7 +120,7 @@ public: SymbolContext &context, Address *addr, bool containing) override; - Searcher::Depth GetDepth() override { return Searcher::eDepthModule; } + lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } lldb::BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override { @@ -269,7 +265,7 @@ public: SymbolContext &context, Address *addr, bool containing) override; - Searcher::Depth GetDepth() override { return Searcher::eDepthModule; } + lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } lldb::BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override { diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp index e1f8ea648414..0b298c90a50b 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp @@ -7,11 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes #include <set> -// Other libraries and framework includes #include "llvm/ADT/StringRef.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" @@ -23,7 +20,6 @@ #include "llvm/IRReader/IRReader.h" #include "llvm/Pass.h" -// Project includes #include "lldb/Target/Process.h" #include "lldb/Utility/Log.h" diff --git a/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h b/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h index 31e9873fb1ee..c08acd0151ef 100644 --- a/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h +++ b/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h @@ -10,10 +10,6 @@ #ifndef liblldb_MemoryHistoryASan_h_ #define liblldb_MemoryHistoryASan_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/ABI.h" #include "lldb/Target/MemoryHistory.h" #include "lldb/Target/Process.h" diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 275f1fa2f70b..391ab7546967 100644 --- a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -33,7 +33,6 @@ typedef struct ar_hdr { #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" @@ -208,7 +207,7 @@ ObjectContainerBSDArchive::Archive::FindCachedArchive( while (pos != archive_map.end() && pos->first == file) { bool match = true; if (arch.IsValid() && - pos->second->GetArchitecture().IsCompatibleMatch(arch) == false) + !pos->second->GetArchitecture().IsCompatibleMatch(arch)) match = false; else if (file_offset != LLDB_INVALID_OFFSET && pos->second->GetFileOffset() != file_offset) @@ -313,7 +312,7 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance( // file gets updated by a new build while this .a file is being used for // debugging DataBufferSP archive_data_sp = - DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset); + FileSystem::Instance().CreateDataBuffer(*file, length, file_offset); if (!archive_data_sp) return nullptr; @@ -461,14 +460,14 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( return 0; const size_t initial_count = specs.GetSize(); - llvm::sys::TimePoint<> file_mod_time = FileSystem::GetModificationTime(file); + llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file); Archive::shared_ptr archive_sp( Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset)); bool set_archive_arch = false; if (!archive_sp) { set_archive_arch = true; data_sp = - DataBufferLLVM::CreateSliceFromPath(file.GetPath(), file_size, file_offset); + FileSystem::Instance().CreateDataBuffer(file, file_size, file_offset); if (data_sp) { data.SetData(data_sp, 0, data_sp->GetByteSize()); archive_sp = Archive::ParseAndCacheArchiveForFile( diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h index cb63eccff65e..86eaee1375a6 100644 --- a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h +++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h @@ -16,11 +16,8 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" -// Other libraries and framework includes #include "llvm/Support/Chrono.h" -// C Includes -// C++ Includes #include <map> #include <memory> #include <mutex> diff --git a/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h index d3c0a080a6f9..d6e4fe1747cf 100644 --- a/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h +++ b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h @@ -10,13 +10,9 @@ #ifndef liblldb_ObjectContainerUniversalMachO_h_ #define liblldb_ObjectContainerUniversalMachO_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes +#include "lldb/Host/SafeMachO.h" #include "lldb/Symbol/ObjectContainer.h" #include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/SafeMachO.h" class ObjectContainerUniversalMachO : public lldb_private::ObjectContainer { public: diff --git a/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt b/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt new file mode 100644 index 000000000000..2f51b2c8719a --- /dev/null +++ b/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt @@ -0,0 +1,11 @@ +add_lldb_library(lldbPluginObjectFileBreakpad PLUGIN + ObjectFileBreakpad.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbUtility + LINK_COMPONENTS + Support + ) diff --git a/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp new file mode 100644 index 000000000000..917025030ada --- /dev/null +++ b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp @@ -0,0 +1,315 @@ +//===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Utility/DataBuffer.h" +#include "llvm/ADT/StringExtras.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::breakpad; + +namespace { +struct Header { + ArchSpec arch; + UUID uuid; + static llvm::Optional<Header> parse(llvm::StringRef text); +}; + +enum class Token { Unknown, Module, Info, File, Func, Public, Stack }; +} // namespace + +static Token toToken(llvm::StringRef str) { + return llvm::StringSwitch<Token>(str) + .Case("MODULE", Token::Module) + .Case("INFO", Token::Info) + .Case("FILE", Token::File) + .Case("FUNC", Token::Func) + .Case("PUBLIC", Token::Public) + .Case("STACK", Token::Stack) + .Default(Token::Unknown); +} + +static llvm::StringRef toString(Token t) { + switch (t) { + case Token::Unknown: + return ""; + case Token::Module: + return "MODULE"; + case Token::Info: + return "INFO"; + case Token::File: + return "FILE"; + case Token::Func: + return "FUNC"; + case Token::Public: + return "PUBLIC"; + case Token::Stack: + return "STACK"; + } + llvm_unreachable("Unknown token!"); +} + +static llvm::Triple::OSType toOS(llvm::StringRef str) { + using llvm::Triple; + return llvm::StringSwitch<Triple::OSType>(str) + .Case("Linux", Triple::Linux) + .Case("mac", Triple::MacOSX) + .Case("windows", Triple::Win32) + .Default(Triple::UnknownOS); +} + +static llvm::Triple::ArchType toArch(llvm::StringRef str) { + using llvm::Triple; + return llvm::StringSwitch<Triple::ArchType>(str) + .Case("arm", Triple::arm) + .Case("arm64", Triple::aarch64) + .Case("mips", Triple::mips) + .Case("ppc", Triple::ppc) + .Case("ppc64", Triple::ppc64) + .Case("s390", Triple::systemz) + .Case("sparc", Triple::sparc) + .Case("sparcv9", Triple::sparcv9) + .Case("x86", Triple::x86) + .Case("x86_64", Triple::x86_64) + .Default(Triple::UnknownArch); +} + +static llvm::StringRef consume_front(llvm::StringRef &str, size_t n) { + llvm::StringRef result = str.take_front(n); + str = str.drop_front(n); + return result; +} + +static UUID parseModuleId(llvm::Triple::OSType os, llvm::StringRef str) { + struct uuid_data { + llvm::support::ulittle32_t uuid1; + llvm::support::ulittle16_t uuid2[2]; + uint8_t uuid3[8]; + llvm::support::ulittle32_t age; + } data; + static_assert(sizeof(data) == 20, ""); + // The textual module id encoding should be between 33 and 40 bytes long, + // depending on the size of the age field, which is of variable length. + // The first three chunks of the id are encoded in big endian, so we need to + // byte-swap those. + if (str.size() < 33 || str.size() > 40) + return UUID(); + uint32_t t; + if (to_integer(consume_front(str, 8), t, 16)) + data.uuid1 = t; + else + return UUID(); + for (int i = 0; i < 2; ++i) { + if (to_integer(consume_front(str, 4), t, 16)) + data.uuid2[i] = t; + else + return UUID(); + } + for (int i = 0; i < 8; ++i) { + if (!to_integer(consume_front(str, 2), data.uuid3[i], 16)) + return UUID(); + } + if (to_integer(str, t, 16)) + data.age = t; + else + return UUID(); + + // On non-windows, the age field should always be zero, so we don't include to + // match the native uuid format of these platforms. + return UUID::fromData(&data, os == llvm::Triple::Win32 ? 20 : 16); +} + +llvm::Optional<Header> Header::parse(llvm::StringRef text) { + // A valid module should start with something like: + // MODULE Linux x86_64 E5894855C35DCCCCCCCCCCCCCCCCCCCC0 a.out + // optionally followed by + // INFO CODE_ID 554889E55DC3CCCCCCCCCCCCCCCCCCCC [a.exe] + llvm::StringRef token, line; + std::tie(line, text) = text.split('\n'); + std::tie(token, line) = getToken(line); + if (toToken(token) != Token::Module) + return llvm::None; + + std::tie(token, line) = getToken(line); + llvm::Triple triple; + triple.setOS(toOS(token)); + if (triple.getOS() == llvm::Triple::UnknownOS) + return llvm::None; + + std::tie(token, line) = getToken(line); + triple.setArch(toArch(token)); + if (triple.getArch() == llvm::Triple::UnknownArch) + return llvm::None; + + llvm::StringRef module_id; + std::tie(module_id, line) = getToken(line); + + std::tie(line, text) = text.split('\n'); + std::tie(token, line) = getToken(line); + if (token == "INFO") { + std::tie(token, line) = getToken(line); + if (token != "CODE_ID") + return llvm::None; + + std::tie(token, line) = getToken(line); + // If we don't have any text following the code id (e.g. on linux), we + // should use the module id as UUID. Otherwise, we revert back to the module + // id. + if (line.trim().empty()) { + UUID uuid; + if (uuid.SetFromStringRef(token, token.size() / 2) != token.size()) + return llvm::None; + + return Header{ArchSpec(triple), uuid}; + } + } + + // We reach here if we don't have a INFO CODE_ID section, or we chose not to + // use it. In either case, we need to properly decode the module id, whose + // fields are encoded in big-endian. + UUID uuid = parseModuleId(triple.getOS(), module_id); + if (!uuid) + return llvm::None; + + return Header{ArchSpec(triple), uuid}; +} + +void ObjectFileBreakpad::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileBreakpad::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString ObjectFileBreakpad::GetPluginNameStatic() { + static ConstString g_name("breakpad"); + return g_name; +} + +ObjectFile *ObjectFileBreakpad::CreateInstance( + const ModuleSP &module_sp, DataBufferSP &data_sp, offset_t data_offset, + const FileSpec *file, offset_t file_offset, offset_t length) { + if (!data_sp) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + auto text = toStringRef(data_sp->GetData()); + llvm::Optional<Header> header = Header::parse(text); + if (!header) + return nullptr; + + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) + return nullptr; + data_offset = 0; + } + + return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file, + file_offset, length, std::move(header->arch), + std::move(header->uuid)); +} + +ObjectFile *ObjectFileBreakpad::CreateMemoryInstance( + const ModuleSP &module_sp, DataBufferSP &data_sp, + const ProcessSP &process_sp, addr_t header_addr) { + return nullptr; +} + +size_t ObjectFileBreakpad::GetModuleSpecifications( + const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, + offset_t file_offset, offset_t length, ModuleSpecList &specs) { + auto text = toStringRef(data_sp->GetData()); + llvm::Optional<Header> header = Header::parse(text); + if (!header) + return 0; + ModuleSpec spec(file, std::move(header->arch)); + spec.GetUUID() = std::move(header->uuid); + specs.Append(spec); + return 1; +} + +ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp, + DataBufferSP &data_sp, + offset_t data_offset, + const FileSpec *file, offset_t offset, + offset_t length, ArchSpec arch, + UUID uuid) + : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), + m_arch(std::move(arch)), m_uuid(std::move(uuid)) {} + +bool ObjectFileBreakpad::ParseHeader() { + // We already parsed the header during initialization. + return true; +} + +Symtab *ObjectFileBreakpad::GetSymtab() { + // TODO + return nullptr; +} + +bool ObjectFileBreakpad::GetUUID(UUID *uuid) { + *uuid = m_uuid; + return true; +} + +void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) { + if (m_sections_ap) + return; + m_sections_ap = llvm::make_unique<SectionList>(); + + Token current_section = Token::Unknown; + offset_t section_start; + llvm::StringRef text = toStringRef(m_data.GetData()); + uint32_t next_section_id = 1; + auto maybe_add_section = [&](const uint8_t *end_ptr) { + if (current_section == Token::Unknown) + return; // We have been called before parsing the first line. + + offset_t end_offset = end_ptr - m_data.GetDataStart(); + auto section_sp = std::make_shared<Section>( + GetModule(), this, next_section_id++, + ConstString(toString(current_section)), eSectionTypeOther, + /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start, + end_offset - section_start, /*log2align*/ 0, /*flags*/ 0); + m_sections_ap->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + }; + while (!text.empty()) { + llvm::StringRef line; + std::tie(line, text) = text.split('\n'); + + Token token = toToken(getToken(line).first); + if (token == Token::Unknown) { + // We assume this is a line record, which logically belongs to the Func + // section. Errors will be handled when parsing the Func section. + token = Token::Func; + } + if (token == current_section) + continue; + + // Changing sections, finish off the previous one, if there was any. + maybe_add_section(line.bytes_begin()); + // And start a new one. + current_section = token; + section_start = line.bytes_begin() - m_data.GetDataStart(); + } + // Finally, add the last section. + maybe_add_section(m_data.GetDataEnd()); +} diff --git a/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h new file mode 100644 index 000000000000..ba2a3ad30e5f --- /dev/null +++ b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h @@ -0,0 +1,109 @@ +//===-- ObjectFileBreakpad.h ---------------------------------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H +#define LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "llvm/ADT/Triple.h" + +namespace lldb_private { +namespace breakpad { + +class ObjectFileBreakpad : public ObjectFile { +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + static void Terminate(); + + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic() { + return "Breakpad 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; } + + //------------------------------------------------------------------ + // 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 false; } + + void CreateSections(SectionList &unified_section_list) override; + + void Dump(Stream *s) override {} + + ArchSpec GetArchitecture() override { return m_arch; } + + bool GetUUID(UUID *uuid) override; + + FileSpecList GetDebugSymbolFilePaths() override { return FileSpecList(); } + + uint32_t GetDependentModules(FileSpecList &files) override { return 0; } + + Type CalculateType() override { return eTypeDebugInfo; } + + Strata CalculateStrata() override { return eStrataUser; } + +private: + ArchSpec m_arch; + UUID m_uuid; + + ObjectFileBreakpad(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, ArchSpec arch, UUID uuid); +}; + +} // namespace breakpad +} // namespace lldb_private +#endif // LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H diff --git a/source/Plugins/ObjectFile/CMakeLists.txt b/source/Plugins/ObjectFile/CMakeLists.txt index 06aa01c4f004..4edd667b9723 100644 --- a/source/Plugins/ObjectFile/CMakeLists.txt +++ b/source/Plugins/ObjectFile/CMakeLists.txt @@ -1,4 +1,5 @@ +add_subdirectory(Breakpad) add_subdirectory(ELF) add_subdirectory(Mach-O) add_subdirectory(PECOFF) -add_subdirectory(JIT)
\ No newline at end of file +add_subdirectory(JIT) diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index 16cbb6e5753b..3d4735286bf2 100644 --- a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -38,7 +38,7 @@ static bool GetMaxU64(const lldb_private::DataExtractor &data, lldb::offset_t saved_offset = *offset; for (uint32_t i = 0; i < count; ++i, ++value) { - if (GetMaxU64(data, offset, value, byte_size) == false) { + if (!GetMaxU64(data, offset, value, byte_size)) { *offset = saved_offset; return false; } @@ -60,7 +60,7 @@ static bool GetMaxS64(const lldb_private::DataExtractor &data, lldb::offset_t saved_offset = *offset; for (uint32_t i = 0; i < count; ++i, ++value) { - if (GetMaxS64(data, offset, value, byte_size) == false) { + if (!GetMaxS64(data, offset, value, byte_size)) { *offset = saved_offset; return false; } @@ -133,7 +133,7 @@ bool ELFHeader::Parse(lldb_private::DataExtractor &data, return false; // Read e_entry, e_phoff and e_shoff. - if (GetMaxU64(data, offset, &e_entry, byte_size, 3) == false) + if (!GetMaxU64(data, offset, &e_entry, byte_size, 3)) return false; // Read e_flags. @@ -232,11 +232,11 @@ bool ELFSectionHeader::Parse(const lldb_private::DataExtractor &data, return false; // Read sh_flags. - if (GetMaxU64(data, offset, &sh_flags, byte_size) == false) + if (!GetMaxU64(data, offset, &sh_flags, byte_size)) return false; // Read sh_addr, sh_off and sh_size. - if (GetMaxU64(data, offset, &sh_addr, byte_size, 3) == false) + if (!GetMaxU64(data, offset, &sh_addr, byte_size, 3)) return false; // Read sh_link and sh_info. @@ -244,7 +244,7 @@ bool ELFSectionHeader::Parse(const lldb_private::DataExtractor &data, return false; // Read sh_addralign and sh_entsize. - if (GetMaxU64(data, offset, &sh_addralign, byte_size, 2) == false) + if (!GetMaxU64(data, offset, &sh_addralign, byte_size, 2)) return false; return true; @@ -332,7 +332,7 @@ bool ELFSymbol::Parse(const lldb_private::DataExtractor &data, if (parsing_32) { // Read st_value and st_size. - if (GetMaxU64(data, offset, &st_value, byte_size, 2) == false) + if (!GetMaxU64(data, offset, &st_value, byte_size, 2)) return false; // Read st_info and st_other. @@ -376,7 +376,7 @@ bool ELFProgramHeader::Parse(const lldb_private::DataExtractor &data, if (parsing_32) { // Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz. - if (GetMaxU64(data, offset, &p_offset, byte_size, 5) == false) + if (!GetMaxU64(data, offset, &p_offset, byte_size, 5)) return false; // Read p_flags. @@ -384,7 +384,7 @@ bool ELFProgramHeader::Parse(const lldb_private::DataExtractor &data, return false; // Read p_align. - if (GetMaxU64(data, offset, &p_align, byte_size) == false) + if (!GetMaxU64(data, offset, &p_align, byte_size)) return false; } else { // Read p_flags. @@ -392,7 +392,7 @@ bool ELFProgramHeader::Parse(const lldb_private::DataExtractor &data, return false; // Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align. - if (GetMaxU64(data, offset, &p_offset, byte_size, 6) == false) + if (!GetMaxU64(data, offset, &p_offset, byte_size, 6)) return false; } @@ -420,10 +420,7 @@ bool ELFRel::Parse(const lldb_private::DataExtractor &data, const unsigned byte_size = data.GetAddressByteSize(); // Read r_offset and r_info. - if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false) - return false; - - return true; + return GetMaxU64(data, offset, &r_offset, byte_size, 2) != false; } //------------------------------------------------------------------------------ @@ -436,11 +433,11 @@ bool ELFRela::Parse(const lldb_private::DataExtractor &data, const unsigned byte_size = data.GetAddressByteSize(); // Read r_offset and r_info. - if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false) + if (!GetMaxU64(data, offset, &r_offset, byte_size, 2)) return false; // Read r_addend; - if (GetMaxS64(data, offset, &r_addend, byte_size) == false) + if (!GetMaxS64(data, offset, &r_addend, byte_size)) return false; return true; diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 8701908378f1..9a6563afa0a0 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -17,7 +17,9 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/RangeMap.h" #include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/SectionLoadList.h" @@ -29,6 +31,7 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" +#include "llvm/ADT/IntervalMap.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/Decompressor.h" @@ -235,6 +238,8 @@ unsigned ELFRelocation::RelocAddend64(const ELFRelocation &rel) { } // end anonymous namespace +static user_id_t SegmentID(size_t PHdrIndex) { return ~PHdrIndex; } + bool ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) { // Read all fields. if (data.GetU32(offset, &n_namesz, 3) == NULL) @@ -433,9 +438,8 @@ ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp, if (address_size == 4 || address_size == 8) { std::unique_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF( module_sp, data_sp, data_offset, file, file_offset, length)); - ArchSpec spec; - if (objfile_ap->GetArchitecture(spec) && - objfile_ap->SetModulesArchitecture(spec)) + ArchSpec spec = objfile_ap->GetArchitecture(); + if (spec && objfile_ap->SetModulesArchitecture(spec)) return objfile_ap.release(); } @@ -452,9 +456,8 @@ ObjectFile *ObjectFileELF::CreateMemoryInstance( if (address_size == 4 || address_size == 8) { std::unique_ptr<ObjectFileELF> objfile_ap( new ObjectFileELF(module_sp, data_sp, process_sp, header_addr)); - ArchSpec spec; - if (objfile_ap->GetArchitecture(spec) && - objfile_ap->SetModulesArchitecture(spec)) + ArchSpec spec = objfile_ap->GetArchitecture(); + if (spec && objfile_ap->SetModulesArchitecture(spec)) return objfile_ap.release(); } } @@ -538,14 +541,13 @@ static uint32_t calc_gnu_debuglink_crc32(const void *buf, size_t size) { uint32_t ObjectFileELF::CalculateELFNotesSegmentsCRC32( const ProgramHeaderColl &program_headers, DataExtractor &object_data) { - typedef ProgramHeaderCollConstIter Iter; uint32_t core_notes_crc = 0; - for (Iter I = program_headers.begin(); I != program_headers.end(); ++I) { - if (I->p_type == llvm::ELF::PT_NOTE) { - const elf_off ph_offset = I->p_offset; - const size_t ph_size = I->p_filesz; + for (const ELFProgramHeader &H : program_headers) { + if (H.p_type == llvm::ELF::PT_NOTE) { + const elf_off ph_offset = H.p_offset; + const size_t ph_size = H.p_filesz; DataExtractor segment_data; if (segment_data.SetData(object_data, ph_offset, ph_size) != ph_size) { @@ -713,7 +715,8 @@ size_t ObjectFileELF::GetModuleSpecifications( func_cat, "Calculating module crc32 %s with size %" PRIu64 " KiB", file.GetLastPathComponent().AsCString(), - (file.GetByteSize() - file_offset) / 1024); + (FileSystem::Instance().GetByteSize(file) - file_offset) / + 1024); // For core files - which usually don't happen to have a // gnu_debuglink, and are pretty bulky - calculating whole @@ -803,21 +806,10 @@ bool ObjectFileELF::SetLoadAddress(Target &target, lldb::addr_t value, SectionList *section_list = GetSectionList(); if (section_list) { if (!value_is_offset) { - bool found_offset = false; - for (size_t i = 1, count = GetProgramHeaderCount(); i <= count; ++i) { - const elf::ELFProgramHeader *header = GetProgramHeaderByIndex(i); - if (header == nullptr) - continue; - - if (header->p_type != PT_LOAD || header->p_offset != 0) - continue; - - value = value - header->p_vaddr; - found_offset = true; - break; - } - if (!found_offset) + addr_t base = GetBaseAddress().GetFileAddress(); + if (base == LLDB_INVALID_ADDRESS) return false; + value -= base; } const size_t num_sections = section_list->GetSize(); @@ -827,7 +819,8 @@ bool ObjectFileELF::SetLoadAddress(Target &target, lldb::addr_t value, // Iterate through the object file sections to find all of the sections // that have SHF_ALLOC in their flag bits. SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); - if (section_sp && section_sp->Test(SHF_ALLOC)) { + if (section_sp->Test(SHF_ALLOC) || + section_sp->GetType() == eSectionTypeContainer) { lldb::addr_t load_addr = section_sp->GetFileAddress(); // We don't want to update the load address of a section with type // eSectionTypeAbsoluteAddress as they already have the absolute load @@ -892,11 +885,11 @@ AddressClass ObjectFileELF::GetAddressClass(addr_t file_addr) { } size_t ObjectFileELF::SectionIndex(const SectionHeaderCollIter &I) { - return std::distance(m_section_headers.begin(), I) + 1u; + return std::distance(m_section_headers.begin(), I); } size_t ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const { - return std::distance(m_section_headers.begin(), I) + 1u; + return std::distance(m_section_headers.begin(), I); } bool ObjectFileELF::ParseHeader() { @@ -953,7 +946,7 @@ lldb_private::FileSpecList ObjectFileELF::GetDebugSymbolFilePaths() { FileSpecList file_spec_list; if (!m_gnu_debuglink_file.empty()) { - FileSpec file_spec(m_gnu_debuglink_file, false); + FileSpec file_spec(m_gnu_debuglink_file); file_spec_list.Append(file_spec); } return file_spec_list; @@ -1055,6 +1048,18 @@ lldb_private::Address ObjectFileELF::GetEntryPointAddress() { return m_entry_point_address; } +Address ObjectFileELF::GetBaseAddress() { + for (const auto &EnumPHdr : llvm::enumerate(ProgramHeaders())) { + const ELFProgramHeader &H = EnumPHdr.value(); + if (H.p_type != PT_LOAD) + continue; + + return Address( + GetSectionList()->FindSectionByID(SegmentID(EnumPHdr.index())), 0); + } + return LLDB_INVALID_ADDRESS; +} + //---------------------------------------------------------------------- // ParseDependentModules //---------------------------------------------------------------------- @@ -1084,7 +1089,7 @@ size_t ObjectFileELF::ParseDependentModules() { return 0; // sh_link: section header index of string table used by entries in the // section. - Section *dynstr = section_list->FindSectionByID(header->sh_link + 1).get(); + Section *dynstr = section_list->FindSectionByID(header->sh_link).get(); if (!dynstr) return 0; @@ -1107,7 +1112,9 @@ size_t ObjectFileELF::ParseDependentModules() { uint32_t str_index = static_cast<uint32_t>(symbol.d_val); const char *lib_name = dynstr_data.PeekCStr(str_index); - m_filespec_ap->Append(FileSpec(lib_name, true)); + FileSpec file_spec(lib_name); + FileSystem::Instance().Resolve(file_spec); + m_filespec_ap->Append(file_spec); } } @@ -1141,7 +1148,7 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, uint32_t idx; lldb::offset_t offset; for (idx = 0, offset = 0; idx < header.e_phnum; ++idx) { - if (program_headers[idx].Parse(data, &offset) == false) + if (!program_headers[idx].Parse(data, &offset)) break; } @@ -1154,8 +1161,8 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, //---------------------------------------------------------------------- // ParseProgramHeaders //---------------------------------------------------------------------- -size_t ObjectFileELF::ParseProgramHeaders() { - return GetProgramHeaderInfo(m_program_headers, m_data, m_header); +bool ObjectFileELF::ParseProgramHeaders() { + return GetProgramHeaderInfo(m_program_headers, m_data, m_header) != 0; } lldb_private::Status @@ -1390,7 +1397,7 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, arch_spec.GetTriple().getOS() == llvm::Triple::OSType::UnknownOS) // In case of MIPSR6, the LLDB_NT_OWNER_GNU note is missing for some // cases (e.g. compile with -nostdlib) Hence set OS to Linux - arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); } } @@ -1494,7 +1501,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, const uint32_t sub_type = subTypeFromElfHeader(header); arch_spec.SetArchitecture(eArchTypeELF, header.e_machine, sub_type, header.e_ident[EI_OSABI]); - + // Validate if it is ok to remove GetOsFromOSABI. Note, that now the OS is // determined based on EI_OSABI flag and the info extracted from ELF notes // (see RefineModuleDetailsFromNote). However in some cases that still @@ -1553,7 +1560,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, uint32_t idx; lldb::offset_t offset; for (idx = 0, offset = 0; idx < header.e_shnum; ++idx) { - if (section_headers[idx].Parse(sh_data, &offset) == false) + if (!section_headers[idx].Parse(sh_data, &offset)) break; } if (idx < section_headers.size()) @@ -1701,27 +1708,6 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, return 0; } -size_t ObjectFileELF::GetProgramHeaderCount() { return ParseProgramHeaders(); } - -const elf::ELFProgramHeader * -ObjectFileELF::GetProgramHeaderByIndex(lldb::user_id_t id) { - if (!id || !ParseProgramHeaders()) - return NULL; - - if (--id < m_program_headers.size()) - return &m_program_headers[id]; - - return NULL; -} - -DataExtractor ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id) { - const elf::ELFProgramHeader *segment_header = GetProgramHeaderByIndex(id); - if (segment_header == NULL) - return DataExtractor(); - return DataExtractor(m_data, segment_header->p_offset, - segment_header->p_filesz); -} - llvm::StringRef ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { size_t pos = symbol_name.find('@'); @@ -1739,10 +1725,10 @@ size_t ObjectFileELF::ParseSectionHeaders() { const ObjectFileELF::ELFSectionHeaderInfo * ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id) { - if (!id || !ParseSectionHeaders()) + if (!ParseSectionHeaders()) return NULL; - if (--id < m_section_headers.size()) + if (id < m_section_headers.size()) return &m_section_headers[id]; return NULL; @@ -1757,233 +1743,273 @@ lldb::user_id_t ObjectFileELF::GetSectionIndexByName(const char *name) { return 0; } -void ObjectFileELF::CreateSections(SectionList &unified_section_list) { - if (!m_sections_ap.get() && ParseSectionHeaders()) { - m_sections_ap.reset(new SectionList()); - - // Object files frequently have 0 for every section address, meaning we - // need to compute synthetic addresses in order for "file addresses" from - // different sections to not overlap - bool synthaddrs = (CalculateType() == ObjectFile::Type::eTypeObjectFile); - uint64_t nextaddr = 0; - - for (SectionHeaderCollIter I = m_section_headers.begin(); - I != m_section_headers.end(); ++I) { - const ELFSectionHeaderInfo &header = *I; - - ConstString &name = I->section_name; - const uint64_t file_size = - header.sh_type == SHT_NOBITS ? 0 : header.sh_size; - const uint64_t vm_size = header.sh_flags & SHF_ALLOC ? header.sh_size : 0; - - static ConstString g_sect_name_text(".text"); - static ConstString g_sect_name_data(".data"); - static ConstString g_sect_name_bss(".bss"); - static ConstString g_sect_name_tdata(".tdata"); - static ConstString g_sect_name_tbss(".tbss"); - static ConstString g_sect_name_dwarf_debug_abbrev(".debug_abbrev"); - static ConstString g_sect_name_dwarf_debug_addr(".debug_addr"); - static ConstString g_sect_name_dwarf_debug_aranges(".debug_aranges"); - static ConstString g_sect_name_dwarf_debug_cu_index(".debug_cu_index"); - static ConstString g_sect_name_dwarf_debug_frame(".debug_frame"); - static ConstString g_sect_name_dwarf_debug_info(".debug_info"); - static ConstString g_sect_name_dwarf_debug_line(".debug_line"); - static ConstString g_sect_name_dwarf_debug_loc(".debug_loc"); - static ConstString g_sect_name_dwarf_debug_macinfo(".debug_macinfo"); - static ConstString g_sect_name_dwarf_debug_macro(".debug_macro"); - static ConstString g_sect_name_dwarf_debug_names(".debug_names"); - static ConstString g_sect_name_dwarf_debug_pubnames(".debug_pubnames"); - static ConstString g_sect_name_dwarf_debug_pubtypes(".debug_pubtypes"); - static ConstString g_sect_name_dwarf_debug_ranges(".debug_ranges"); - static ConstString g_sect_name_dwarf_debug_str(".debug_str"); - static ConstString g_sect_name_dwarf_debug_str_offsets( - ".debug_str_offsets"); - static ConstString g_sect_name_dwarf_debug_abbrev_dwo( - ".debug_abbrev.dwo"); - static ConstString g_sect_name_dwarf_debug_info_dwo(".debug_info.dwo"); - static ConstString g_sect_name_dwarf_debug_line_dwo(".debug_line.dwo"); - static ConstString g_sect_name_dwarf_debug_macro_dwo(".debug_macro.dwo"); - static ConstString g_sect_name_dwarf_debug_loc_dwo(".debug_loc.dwo"); - static ConstString g_sect_name_dwarf_debug_str_dwo(".debug_str.dwo"); - static ConstString g_sect_name_dwarf_debug_str_offsets_dwo( - ".debug_str_offsets.dwo"); - static ConstString g_sect_name_dwarf_debug_types(".debug_types"); - static ConstString g_sect_name_eh_frame(".eh_frame"); - static ConstString g_sect_name_arm_exidx(".ARM.exidx"); - static ConstString g_sect_name_arm_extab(".ARM.extab"); - static ConstString g_sect_name_go_symtab(".gosymtab"); - static ConstString g_sect_name_dwarf_gnu_debugaltlink(".gnu_debugaltlink"); - - SectionType sect_type = eSectionTypeOther; - - bool is_thread_specific = false; - - if (name == g_sect_name_text) - sect_type = eSectionTypeCode; - else if (name == g_sect_name_data) - sect_type = eSectionTypeData; - else if (name == g_sect_name_bss) - sect_type = eSectionTypeZeroFill; - else if (name == g_sect_name_tdata) { - sect_type = eSectionTypeData; - is_thread_specific = true; - } else if (name == g_sect_name_tbss) { - sect_type = eSectionTypeZeroFill; - is_thread_specific = true; - } - // .debug_abbrev – Abbreviations used in the .debug_info section - // .debug_aranges – Lookup table for mapping addresses to compilation - // units .debug_frame – Call frame information .debug_info – The core - // DWARF information section .debug_line – Line number information - // .debug_loc – Location lists used in DW_AT_location attributes - // .debug_macinfo – Macro information .debug_pubnames – Lookup table - // for mapping object and function names to compilation units - // .debug_pubtypes – Lookup table for mapping type names to compilation - // units .debug_ranges – Address ranges used in DW_AT_ranges attributes - // .debug_str – String table used in .debug_info MISSING? - // .gnu_debugdata - "mini debuginfo / MiniDebugInfo" section, - // http://sourceware.org/gdb/onlinedocs/gdb/MiniDebugInfo.html MISSING? - // .debug-index - http://src.chromium.org/viewvc/chrome/trunk/src/build - // /gdb-add-index?pathrev=144644 MISSING? .debug_types - Type - // descriptions from DWARF 4? See - // http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo - else if (name == g_sect_name_dwarf_debug_abbrev) - sect_type = eSectionTypeDWARFDebugAbbrev; - else if (name == g_sect_name_dwarf_debug_addr) - sect_type = eSectionTypeDWARFDebugAddr; - else if (name == g_sect_name_dwarf_debug_aranges) - sect_type = eSectionTypeDWARFDebugAranges; - else if (name == g_sect_name_dwarf_debug_cu_index) - sect_type = eSectionTypeDWARFDebugCuIndex; - else if (name == g_sect_name_dwarf_debug_frame) - sect_type = eSectionTypeDWARFDebugFrame; - else if (name == g_sect_name_dwarf_debug_info) - sect_type = eSectionTypeDWARFDebugInfo; - else if (name == g_sect_name_dwarf_debug_line) - sect_type = eSectionTypeDWARFDebugLine; - else if (name == g_sect_name_dwarf_debug_loc) - sect_type = eSectionTypeDWARFDebugLoc; - else if (name == g_sect_name_dwarf_debug_macinfo) - sect_type = eSectionTypeDWARFDebugMacInfo; - else if (name == g_sect_name_dwarf_debug_macro) - sect_type = eSectionTypeDWARFDebugMacro; - else if (name == g_sect_name_dwarf_debug_names) - sect_type = eSectionTypeDWARFDebugNames; - else if (name == g_sect_name_dwarf_debug_pubnames) - sect_type = eSectionTypeDWARFDebugPubNames; - else if (name == g_sect_name_dwarf_debug_pubtypes) - sect_type = eSectionTypeDWARFDebugPubTypes; - else if (name == g_sect_name_dwarf_debug_ranges) - sect_type = eSectionTypeDWARFDebugRanges; - else if (name == g_sect_name_dwarf_debug_str) - sect_type = eSectionTypeDWARFDebugStr; - else if (name == g_sect_name_dwarf_debug_types) - sect_type = eSectionTypeDWARFDebugTypes; - else if (name == g_sect_name_dwarf_debug_str_offsets) - sect_type = eSectionTypeDWARFDebugStrOffsets; - else if (name == g_sect_name_dwarf_debug_abbrev_dwo) - sect_type = eSectionTypeDWARFDebugAbbrev; - else if (name == g_sect_name_dwarf_debug_info_dwo) - sect_type = eSectionTypeDWARFDebugInfo; - else if (name == g_sect_name_dwarf_debug_line_dwo) - sect_type = eSectionTypeDWARFDebugLine; - else if (name == g_sect_name_dwarf_debug_macro_dwo) - sect_type = eSectionTypeDWARFDebugMacro; - else if (name == g_sect_name_dwarf_debug_loc_dwo) - sect_type = eSectionTypeDWARFDebugLoc; - else if (name == g_sect_name_dwarf_debug_str_dwo) - sect_type = eSectionTypeDWARFDebugStr; - else if (name == g_sect_name_dwarf_debug_str_offsets_dwo) - sect_type = eSectionTypeDWARFDebugStrOffsets; - else if (name == g_sect_name_eh_frame) - sect_type = eSectionTypeEHFrame; - else if (name == g_sect_name_arm_exidx) - sect_type = eSectionTypeARMexidx; - else if (name == g_sect_name_arm_extab) - sect_type = eSectionTypeARMextab; - else if (name == g_sect_name_go_symtab) - sect_type = eSectionTypeGoSymtab; - else if (name == g_sect_name_dwarf_gnu_debugaltlink) - sect_type = eSectionTypeDWARFGNUDebugAltLink; - - const uint32_t permissions = - ((header.sh_flags & SHF_ALLOC) ? ePermissionsReadable : 0u) | - ((header.sh_flags & SHF_WRITE) ? ePermissionsWritable : 0u) | - ((header.sh_flags & SHF_EXECINSTR) ? ePermissionsExecutable : 0u); - switch (header.sh_type) { - case SHT_SYMTAB: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFSymbolTable; - break; - case SHT_DYNSYM: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFDynamicSymbols; - break; - case SHT_RELA: - case SHT_REL: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFRelocationEntries; - break; - case SHT_DYNAMIC: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFDynamicLinkInfo; - break; - } +static SectionType GetSectionTypeFromName(llvm::StringRef Name) { + return llvm::StringSwitch<SectionType>(Name) + .Case(".ARM.exidx", eSectionTypeARMexidx) + .Case(".ARM.extab", eSectionTypeARMextab) + .Cases(".bss", ".tbss", eSectionTypeZeroFill) + .Cases(".data", ".tdata", eSectionTypeData) + .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev) + .Case(".debug_abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo) + .Case(".debug_addr", eSectionTypeDWARFDebugAddr) + .Case(".debug_aranges", eSectionTypeDWARFDebugAranges) + .Case(".debug_cu_index", eSectionTypeDWARFDebugCuIndex) + .Case(".debug_frame", eSectionTypeDWARFDebugFrame) + .Case(".debug_info", eSectionTypeDWARFDebugInfo) + .Case(".debug_info.dwo", eSectionTypeDWARFDebugInfoDwo) + .Cases(".debug_line", ".debug_line.dwo", eSectionTypeDWARFDebugLine) + .Cases(".debug_line_str", ".debug_line_str.dwo", + eSectionTypeDWARFDebugLineStr) + .Cases(".debug_loc", ".debug_loc.dwo", eSectionTypeDWARFDebugLoc) + .Cases(".debug_loclists", ".debug_loclists.dwo", + eSectionTypeDWARFDebugLocLists) + .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo) + .Cases(".debug_macro", ".debug_macro.dwo", 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.dwo", eSectionTypeDWARFDebugStrDwo) + .Case(".debug_str_offsets", eSectionTypeDWARFDebugStrOffsets) + .Case(".debug_str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo) + .Case(".debug_types", eSectionTypeDWARFDebugTypes) + .Case(".eh_frame", eSectionTypeEHFrame) + .Case(".gnu_debugaltlink", eSectionTypeDWARFGNUDebugAltLink) + .Case(".gosymtab", eSectionTypeGoSymtab) + .Case(".text", eSectionTypeCode) + .Default(eSectionTypeOther); +} + +SectionType ObjectFileELF::GetSectionType(const ELFSectionHeaderInfo &H) const { + switch (H.sh_type) { + case SHT_PROGBITS: + if (H.sh_flags & SHF_EXECINSTR) + return eSectionTypeCode; + break; + case SHT_SYMTAB: + return eSectionTypeELFSymbolTable; + case SHT_DYNSYM: + return eSectionTypeELFDynamicSymbols; + case SHT_RELA: + case SHT_REL: + return eSectionTypeELFRelocationEntries; + case SHT_DYNAMIC: + return eSectionTypeELFDynamicLinkInfo; + } + SectionType Type = GetSectionTypeFromName(H.section_name.GetStringRef()); + if (Type == eSectionTypeOther) { + // the kalimba toolchain assumes that ELF section names are free-form. + // It does support linkscripts which (can) give rise to various + // arbitrarily named sections being "Code" or "Data". + Type = kalimbaSectionType(m_header, H); + } + return Type; +} + +static uint32_t GetTargetByteSize(SectionType Type, const ArchSpec &arch) { + switch (Type) { + case eSectionTypeData: + case eSectionTypeZeroFill: + return arch.GetDataByteSize(); + case eSectionTypeCode: + return arch.GetCodeByteSize(); + default: + return 1; + } +} - if (eSectionTypeOther == sect_type) { - // the kalimba toolchain assumes that ELF section names are free-form. - // It does support linkscripts which (can) give rise to various - // arbitrarily named sections being "Code" or "Data". - sect_type = kalimbaSectionType(m_header, header); - } +static Permissions GetPermissions(const ELFSectionHeader &H) { + Permissions Perm = Permissions(0); + if (H.sh_flags & SHF_ALLOC) + Perm |= ePermissionsReadable; + if (H.sh_flags & SHF_WRITE) + Perm |= ePermissionsWritable; + if (H.sh_flags & SHF_EXECINSTR) + Perm |= ePermissionsExecutable; + return Perm; +} - // In common case ELF code section can have arbitrary name (for example, - // we can specify it using section attribute for particular function) so - // assume that section is a code section if it has SHF_EXECINSTR flag set - // and has SHT_PROGBITS type. - if (eSectionTypeOther == sect_type && - llvm::ELF::SHT_PROGBITS == header.sh_type && - (header.sh_flags & SHF_EXECINSTR)) { - sect_type = eSectionTypeCode; - } +static Permissions GetPermissions(const ELFProgramHeader &H) { + Permissions Perm = Permissions(0); + if (H.p_flags & PF_R) + Perm |= ePermissionsReadable; + if (H.p_flags & PF_W) + Perm |= ePermissionsWritable; + if (H.p_flags & PF_X) + Perm |= ePermissionsExecutable; + return Perm; +} - const uint32_t target_bytes_size = - (eSectionTypeData == sect_type || eSectionTypeZeroFill == sect_type) - ? m_arch_spec.GetDataByteSize() - : eSectionTypeCode == sect_type ? m_arch_spec.GetCodeByteSize() - : 1; - elf::elf_xword log2align = - (header.sh_addralign == 0) ? 0 : llvm::Log2_64(header.sh_addralign); - - uint64_t addr = header.sh_addr; - - if ((header.sh_flags & SHF_ALLOC) && synthaddrs) { - nextaddr = - (nextaddr + header.sh_addralign - 1) & ~(header.sh_addralign - 1); - addr = nextaddr; - nextaddr += vm_size; - } +namespace { + +using VMRange = lldb_private::Range<addr_t, addr_t>; - 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. - SectionIndex(I), // Section ID. - name, // Section name. - sect_type, // Section type. - addr, // VM address. - vm_size, // VM size in bytes of this section. - header.sh_offset, // Offset of this section in the file. - file_size, // Size of the section as found in the file. - log2align, // Alignment of the section - header.sh_flags, // Flags for this section. - target_bytes_size)); // Number of host bytes per target byte - - section_sp->SetPermissions(permissions); - if (is_thread_specific) - section_sp->SetIsThreadSpecific(is_thread_specific); - m_sections_ap->AddSection(section_sp); +struct SectionAddressInfo { + SectionSP Segment; + VMRange Range; +}; + +// (Unlinked) ELF object files usually have 0 for every section address, meaning +// we need to compute synthetic addresses in order for "file addresses" from +// different sections to not overlap. This class handles that logic. +class VMAddressProvider { + using VMMap = llvm::IntervalMap<addr_t, SectionSP, 4, + llvm::IntervalMapHalfOpenInfo<addr_t>>; + + ObjectFile::Type ObjectType; + addr_t NextVMAddress = 0; + VMMap::Allocator Alloc; + VMMap Segments = VMMap(Alloc); + VMMap Sections = VMMap(Alloc); + lldb_private::Log *Log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); + + VMRange GetVMRange(const ELFSectionHeader &H) { + addr_t Address = H.sh_addr; + addr_t Size = H.sh_flags & SHF_ALLOC ? H.sh_size : 0; + if (ObjectType == ObjectFile::Type::eTypeObjectFile && Segments.empty() && (H.sh_flags & SHF_ALLOC)) { + NextVMAddress = + llvm::alignTo(NextVMAddress, std::max<addr_t>(H.sh_addralign, 1)); + Address = NextVMAddress; + NextVMAddress += Size; } + return VMRange(Address, Size); + } + +public: + VMAddressProvider(ObjectFile::Type Type) : ObjectType(Type) {} + + llvm::Optional<VMRange> GetAddressInfo(const ELFProgramHeader &H) { + if (H.p_memsz == 0) { + LLDB_LOG(Log, + "Ignoring zero-sized PT_LOAD segment. Corrupt object file?"); + return llvm::None; + } + + if (Segments.overlaps(H.p_vaddr, H.p_vaddr + H.p_memsz)) { + LLDB_LOG(Log, + "Ignoring overlapping PT_LOAD segment. Corrupt object file?"); + return llvm::None; + } + return VMRange(H.p_vaddr, H.p_memsz); + } + + llvm::Optional<SectionAddressInfo> GetAddressInfo(const ELFSectionHeader &H) { + VMRange Range = GetVMRange(H); + SectionSP Segment; + auto It = Segments.find(Range.GetRangeBase()); + if ((H.sh_flags & SHF_ALLOC) && It.valid()) { + addr_t MaxSize; + if (It.start() <= Range.GetRangeBase()) { + MaxSize = It.stop() - Range.GetRangeBase(); + Segment = *It; + } else + MaxSize = It.start() - Range.GetRangeBase(); + if (Range.GetByteSize() > MaxSize) { + LLDB_LOG(Log, "Shortening section crossing segment boundaries. " + "Corrupt object file?"); + Range.SetByteSize(MaxSize); + } + } + if (Range.GetByteSize() > 0 && + Sections.overlaps(Range.GetRangeBase(), Range.GetRangeEnd())) { + LLDB_LOG(Log, "Ignoring overlapping section. Corrupt object file?"); + return llvm::None; + } + if (Segment) + Range.Slide(-Segment->GetFileAddress()); + return SectionAddressInfo{Segment, Range}; + } + + void AddSegment(const VMRange &Range, SectionSP Seg) { + Segments.insert(Range.GetRangeBase(), Range.GetRangeEnd(), std::move(Seg)); + } + + void AddSection(SectionAddressInfo Info, SectionSP Sect) { + if (Info.Range.GetByteSize() == 0) + return; + if (Info.Segment) + Info.Range.Slide(Info.Segment->GetFileAddress()); + Sections.insert(Info.Range.GetRangeBase(), Info.Range.GetRangeEnd(), + std::move(Sect)); + } +}; +} + +void ObjectFileELF::CreateSections(SectionList &unified_section_list) { + if (m_sections_ap) + return; + + m_sections_ap = llvm::make_unique<SectionList>(); + VMAddressProvider address_provider(CalculateType()); + + size_t LoadID = 0; + for (const auto &EnumPHdr : llvm::enumerate(ProgramHeaders())) { + const ELFProgramHeader &PHdr = EnumPHdr.value(); + if (PHdr.p_type != PT_LOAD) + continue; + + auto InfoOr = address_provider.GetAddressInfo(PHdr); + if (!InfoOr) + continue; + + ConstString Name(("PT_LOAD[" + llvm::Twine(LoadID++) + "]").str()); + uint32_t Log2Align = llvm::Log2_64(std::max<elf_xword>(PHdr.p_align, 1)); + SectionSP Segment = std::make_shared<Section>( + GetModule(), this, SegmentID(EnumPHdr.index()), Name, + eSectionTypeContainer, InfoOr->GetRangeBase(), InfoOr->GetByteSize(), + PHdr.p_offset, PHdr.p_filesz, Log2Align, /*flags*/ 0); + Segment->SetPermissions(GetPermissions(PHdr)); + m_sections_ap->AddSection(Segment); + + address_provider.AddSegment(*InfoOr, std::move(Segment)); + } + + ParseSectionHeaders(); + if (m_section_headers.empty()) + return; + + for (SectionHeaderCollIter I = std::next(m_section_headers.begin()); + I != m_section_headers.end(); ++I) { + const ELFSectionHeaderInfo &header = *I; + + ConstString &name = I->section_name; + const uint64_t file_size = + header.sh_type == SHT_NOBITS ? 0 : header.sh_size; + + auto InfoOr = address_provider.GetAddressInfo(header); + if (!InfoOr) + continue; + + SectionType sect_type = GetSectionType(header); + + const uint32_t target_bytes_size = + GetTargetByteSize(sect_type, m_arch_spec); + + elf::elf_xword log2align = + (header.sh_addralign == 0) ? 0 : llvm::Log2_64(header.sh_addralign); + + SectionSP section_sp(new Section( + InfoOr->Segment, GetModule(), // Module to which this section belongs. + this, // ObjectFile to which this section belongs and should + // read section data from. + SectionIndex(I), // Section ID. + name, // Section name. + sect_type, // Section type. + InfoOr->Range.GetRangeBase(), // VM address. + InfoOr->Range.GetByteSize(), // VM size in bytes of this section. + header.sh_offset, // Offset of this section in the file. + file_size, // Size of the section as found in the file. + log2align, // Alignment of the section + header.sh_flags, // Flags for this section. + target_bytes_size)); // Number of host bytes per target byte + + section_sp->SetPermissions(GetPermissions(header)); + section_sp->SetIsThreadSpecific(header.sh_flags & SHF_TLS); + (InfoOr->Segment ? InfoOr->Segment->GetChildren() : *m_sections_ap) + .AddSection(section_sp); + address_provider.AddSection(std::move(*InfoOr), std::move(section_sp)); } // For eTypeDebugInfo files, the Symbol Vendor will take care of updating the @@ -2050,8 +2076,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, bool skip_oatdata_oatexec = file_extension == ConstString(".oat") || file_extension == ConstString(".odex"); - ArchSpec arch; - GetArchitecture(arch); + ArchSpec arch = GetArchitecture(); ModuleSP module_sp(GetModule()); SectionList *module_section_list = module_sp ? module_sp->GetSectionList() : nullptr; @@ -2063,7 +2088,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, unsigned i; for (i = 0; i < num_symbols; ++i) { - if (symbol.Parse(symtab_data, &offset) == false) + if (!symbol.Parse(symtab_data, &offset)) break; const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); @@ -2083,9 +2108,9 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, SectionSP symbol_section_sp; SymbolType symbol_type = eSymbolTypeInvalid; - Elf64_Half section_idx = symbol.st_shndx; + Elf64_Half shndx = symbol.st_shndx; - switch (section_idx) { + switch (shndx) { case SHN_ABS: symbol_type = eSymbolTypeAbsolute; break; @@ -2093,7 +2118,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, symbol_type = eSymbolTypeUndefined; break; default: - symbol_section_sp = section_list->GetSectionAtIndex(section_idx); + symbol_section_sp = section_list->FindSectionByID(shndx); break; } @@ -2262,7 +2287,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, // symbols. See above for more details. uint64_t symbol_value = symbol.st_value + symbol_value_offset; - if (symbol_section_sp == nullptr && section_idx == SHN_ABS && + if (symbol_section_sp == nullptr && shndx == SHN_ABS && symbol.st_size != 0) { // We don't have a section for a symbol with non-zero size. Create a new // section for it so the address range covered by the symbol is also @@ -2375,9 +2400,8 @@ unsigned ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, assert(symtab_hdr->sh_type == SHT_SYMTAB || symtab_hdr->sh_type == SHT_DYNSYM); - // sh_link: section header index of associated string table. Section ID's are - // ones based. - user_id_t strtab_id = symtab_hdr->sh_link + 1; + // sh_link: section header index of associated string table. + user_id_t strtab_id = symtab_hdr->sh_link; Section *strtab = section_list->FindSectionByID(strtab_id).get(); if (symtab && strtab) { @@ -2529,7 +2553,7 @@ static unsigned ParsePLTRelocations( unsigned slot_type = hdr->GetRelocationJumpSlotType(); unsigned i; for (i = 0; i < num_relocations; ++i) { - if (rel.Parse(rel_data, &offset) == false) + if (!rel.Parse(rel_data, &offset)) break; if (reloc_type(rel) != slot_type) @@ -2587,10 +2611,6 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, user_id_t start_id, if (!symtab_id || !plt_id) return 0; - // Section ID's are ones based; - symtab_id++; - plt_id++; - const ELFSectionHeaderInfo *plt_hdr = GetSectionHeaderByIndex(plt_id); if (!plt_hdr) return 0; @@ -2616,7 +2636,7 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, user_id_t start_id, return 0; // sh_link points to associated string table. - Section *strtab = section_list->FindSectionByID(sym_hdr->sh_link + 1).get(); + Section *strtab = section_list->FindSectionByID(sym_hdr->sh_link).get(); if (!strtab) return 0; @@ -2662,7 +2682,7 @@ unsigned ObjectFileELF::ApplyRelocations( } for (unsigned i = 0; i < num_relocations; ++i) { - if (rel.Parse(rel_data, &offset) == false) + if (!rel.Parse(rel_data, &offset)) break; Symbol *symbol = NULL; @@ -2684,6 +2704,7 @@ unsigned ObjectFileELF::ApplyRelocations( } } else { switch (reloc_type(rel)) { + case R_AARCH64_ABS64: case R_X86_64_64: { symbol = symtab->FindSymbolByID(reloc_symbol(rel)); if (symbol) { @@ -2692,26 +2713,34 @@ unsigned ObjectFileELF::ApplyRelocations( uint64_t *dst = reinterpret_cast<uint64_t *>( data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset64(rel)); - *dst = value + ELFRelocation::RelocAddend64(rel); + uint64_t val_offset = value + ELFRelocation::RelocAddend64(rel); + memcpy(dst, &val_offset, sizeof(uint64_t)); } break; } case R_X86_64_32: - case R_X86_64_32S: { + case R_X86_64_32S: + case R_AARCH64_ABS32: { symbol = symtab->FindSymbolByID(reloc_symbol(rel)); if (symbol) { addr_t value = symbol->GetAddressRef().GetFileAddress(); value += ELFRelocation::RelocAddend32(rel); - assert( - (reloc_type(rel) == R_X86_64_32 && (value <= UINT32_MAX)) || + if ((reloc_type(rel) == R_X86_64_32 && (value > UINT32_MAX)) || (reloc_type(rel) == R_X86_64_32S && - ((int64_t)value <= INT32_MAX && (int64_t)value >= INT32_MIN))); + ((int64_t)value > INT32_MAX && (int64_t)value < INT32_MIN)) || + (reloc_type(rel) == R_AARCH64_ABS32 && + ((int64_t)value > INT32_MAX && (int64_t)value < INT32_MIN))) { + Log *log = + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); + log->Printf("Failed to apply debug info relocations"); + break; + } uint32_t truncated_addr = (value & 0xFFFFFFFF); DataBufferSP &data_buffer_sp = debug_data.GetSharedDataBuffer(); uint32_t *dst = reinterpret_cast<uint32_t *>( data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset32(rel)); - *dst = truncated_addr; + memcpy(dst, &truncated_addr, sizeof(uint32_t)); } break; } @@ -2735,9 +2764,8 @@ unsigned ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, if (!section_list) return 0; - // Section ID's are ones based. - user_id_t symtab_id = rel_hdr->sh_link + 1; - user_id_t debug_id = rel_hdr->sh_info + 1; + user_id_t symtab_id = rel_hdr->sh_link; + user_id_t debug_id = rel_hdr->sh_info; const ELFSectionHeader *symtab_hdr = GetSectionHeaderByIndex(symtab_id); if (!symtab_hdr) @@ -2975,8 +3003,7 @@ void ObjectFileELF::Dump(Stream *s) { s->Indent(); s->PutCString("ObjectFileELF"); - ArchSpec header_arch; - GetArchitecture(header_arch); + ArchSpec header_arch = GetArchitecture(); *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n"; @@ -3153,11 +3180,9 @@ void ObjectFileELF::DumpELFProgramHeaders(Stream *s) { s->PutCString("==== --------------- -------- -------- -------- " "-------- -------- ------------------------- --------\n"); - uint32_t idx = 0; - for (ProgramHeaderCollConstIter I = m_program_headers.begin(); - I != m_program_headers.end(); ++I, ++idx) { - s->Printf("[%2u] ", idx); - ObjectFileELF::DumpELFProgramHeader(s, *I); + for (const auto &H : llvm::enumerate(m_program_headers)) { + s->Format("[{0,2}] ", H.index()); + ObjectFileELF::DumpELFProgramHeader(s, H.value()); s->EOL(); } } @@ -3264,9 +3289,9 @@ void ObjectFileELF::DumpDependentModules(lldb_private::Stream *s) { } } -bool ObjectFileELF::GetArchitecture(ArchSpec &arch) { +ArchSpec ObjectFileELF::GetArchitecture() { if (!ParseHeader()) - return false; + return ArchSpec(); if (m_section_headers.empty()) { // Allow elf notes to be parsed which may affect the detected architecture. @@ -3277,23 +3302,17 @@ bool ObjectFileELF::GetArchitecture(ArchSpec &arch) { m_arch_spec.TripleOSIsUnspecifiedUnknown()) { // Core files don't have section headers yet they have PT_NOTE program // headers that might shed more light on the architecture - if (ParseProgramHeaders()) { - for (size_t i = 1, count = GetProgramHeaderCount(); i <= count; ++i) { - const elf::ELFProgramHeader *header = GetProgramHeaderByIndex(i); - if (header && header->p_type == PT_NOTE && header->p_offset != 0 && - header->p_filesz > 0) { - DataExtractor data; - if (data.SetData(m_data, header->p_offset, header->p_filesz) == - header->p_filesz) { - lldb_private::UUID uuid; - RefineModuleDetailsFromNote(data, m_arch_spec, uuid); - } - } + for (const elf::ELFProgramHeader &H : ProgramHeaders()) { + if (H.p_type != PT_NOTE || H.p_offset == 0 || H.p_filesz == 0) + continue; + DataExtractor data; + if (data.SetData(m_data, H.p_offset, H.p_filesz) == H.p_filesz) { + UUID uuid; + RefineModuleDetailsFromNote(data, m_arch_spec, uuid); } } } - arch = m_arch_spec; - return true; + return m_arch_spec; } ObjectFile::Type ObjectFileELF::CalculateType() { @@ -3385,8 +3404,6 @@ size_t ObjectFileELF::ReadSectionData(Section *section, if (section->GetObjectFile() != this) return section->GetObjectFile()->ReadSectionData(section, section_data); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); - size_t result = ObjectFile::ReadSectionData(section, section_data); if (result == 0 || !section->Test(SHF_COMPRESSED)) return result; @@ -3397,29 +3414,43 @@ size_t ObjectFileELF::ReadSectionData(Section *section, size_t(section_data.GetByteSize())}, GetByteOrder() == eByteOrderLittle, GetAddressByteSize() == 8); if (!Decompressor) { - LLDB_LOG_ERROR(log, Decompressor.takeError(), - "Unable to initialize decompressor for section {0}", - section->GetName()); - return result; + GetModule()->ReportWarning( + "Unable to initialize decompressor for section '%s': %s", + section->GetName().GetCString(), + llvm::toString(Decompressor.takeError()).c_str()); + section_data.Clear(); + return 0; } + auto buffer_sp = std::make_shared<DataBufferHeap>(Decompressor->getDecompressedSize(), 0); - if (auto Error = Decompressor->decompress( + if (auto error = Decompressor->decompress( {reinterpret_cast<char *>(buffer_sp->GetBytes()), size_t(buffer_sp->GetByteSize())})) { - LLDB_LOG_ERROR(log, std::move(Error), "Decompression of section {0} failed", - section->GetName()); - return result; + GetModule()->ReportWarning( + "Decompression of section '%s' failed: %s", + section->GetName().GetCString(), + llvm::toString(std::move(error)).c_str()); + section_data.Clear(); + return 0; } + section_data.SetData(buffer_sp); return buffer_sp->GetByteSize(); } +llvm::ArrayRef<ELFProgramHeader> ObjectFileELF::ProgramHeaders() { + ParseProgramHeaders(); + return m_program_headers; +} + +DataExtractor ObjectFileELF::GetSegmentData(const ELFProgramHeader &H) { + return DataExtractor(m_data, H.p_offset, H.p_filesz); +} + bool ObjectFileELF::AnySegmentHasPhysicalAddress() { - size_t header_count = ParseProgramHeaders(); - for (size_t i = 1; i <= header_count; ++i) { - auto header = GetProgramHeaderByIndex(i); - if (header->p_paddr != 0) + for (const ELFProgramHeader &H : ProgramHeaders()) { + if (H.p_paddr != 0) return true; } return false; @@ -3430,19 +3461,17 @@ ObjectFileELF::GetLoadableData(Target &target) { // Create a list of loadable data from loadable segments, using physical // addresses if they aren't all null std::vector<LoadableData> loadables; - size_t header_count = ParseProgramHeaders(); bool should_use_paddr = AnySegmentHasPhysicalAddress(); - for (size_t i = 1; i <= header_count; ++i) { + for (const ELFProgramHeader &H : ProgramHeaders()) { LoadableData loadable; - auto header = GetProgramHeaderByIndex(i); - if (header->p_type != llvm::ELF::PT_LOAD) + if (H.p_type != llvm::ELF::PT_LOAD) continue; - loadable.Dest = should_use_paddr ? header->p_paddr : header->p_vaddr; + loadable.Dest = should_use_paddr ? H.p_paddr : H.p_vaddr; if (loadable.Dest == LLDB_INVALID_ADDRESS) continue; - if (header->p_filesz == 0) + if (H.p_filesz == 0) continue; - auto segment_data = GetSegmentDataByIndex(i); + auto segment_data = GetSegmentData(H); loadable.Contents = llvm::ArrayRef<uint8_t>(segment_data.GetDataStart(), segment_data.GetByteSize()); loadables.push_back(loadable); diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 2664595fd81d..08fd5bdc60a9 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -10,10 +10,8 @@ #ifndef liblldb_ObjectFileELF_h_ #define liblldb_ObjectFileELF_h_ -// C Includes #include <stdint.h> -// C++ Includes #include <vector> #include "lldb/Symbol/ObjectFile.h" @@ -123,7 +121,7 @@ public: void Dump(lldb_private::Stream *s) override; - bool GetArchitecture(lldb_private::ArchSpec &arch) override; + lldb_private::ArchSpec GetArchitecture() override; bool GetUUID(lldb_private::UUID *uuid) override; @@ -136,6 +134,8 @@ public: lldb_private::Address GetEntryPointAddress() override; + lldb_private::Address GetBaseAddress() override; + ObjectFile::Type CalculateType() override; ObjectFile::Strata CalculateStrata() override; @@ -147,14 +147,8 @@ public: size_t ReadSectionData(lldb_private::Section *section, lldb_private::DataExtractor §ion_data) override; - // Returns number of program headers found in the ELF file. - size_t GetProgramHeaderCount(); - - // Returns the program header with the given index. - const elf::ELFProgramHeader *GetProgramHeaderByIndex(lldb::user_id_t id); - - // Returns segment data for the given index. - lldb_private::DataExtractor GetSegmentDataByIndex(lldb::user_id_t id); + llvm::ArrayRef<elf::ELFProgramHeader> ProgramHeaders(); + lldb_private::DataExtractor GetSegmentData(const elf::ELFProgramHeader &H); llvm::StringRef StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; @@ -176,8 +170,6 @@ private: const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl; - typedef ProgramHeaderColl::iterator ProgramHeaderCollIter; - typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter; struct ELFSectionHeaderInfo : public elf::ELFSectionHeader { lldb_private::ConstString section_name; @@ -230,10 +222,10 @@ private: /// The address class for each symbol in the elf file FileAddressToAddressClassMap m_address_class_map; - /// Returns a 1 based index of the given section header. + /// Returns the index of the given section header. size_t SectionIndex(const SectionHeaderCollIter &I); - /// Returns a 1 based index of the given section header. + /// Returns the index of the given section header. size_t SectionIndex(const SectionHeaderCollConstIter &I) const; // Parses the ELF program headers. @@ -248,14 +240,16 @@ private: /// Parses all section headers present in this object file and populates /// m_program_headers. This method will compute the header list only once. - /// Returns the number of headers parsed. - size_t ParseProgramHeaders(); + /// Returns true iff the headers have been successfully parsed. + bool ParseProgramHeaders(); /// Parses all section headers present in this object file and populates /// m_section_headers. This method will compute the header list only once. /// Returns the number of headers parsed. size_t ParseSectionHeaders(); + lldb::SectionType GetSectionType(const ELFSectionHeaderInfo &H) const; + static void ParseARMAttributes(lldb_private::DataExtractor &data, uint64_t length, lldb_private::ArchSpec &arch_spec); diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp index af040322ec52..cfe61992be0d 100644 --- a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp +++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -153,8 +153,7 @@ void ObjectFileJIT::Dump(Stream *s) { s->Indent(); s->PutCString("ObjectFileJIT"); - ArchSpec arch; - if (GetArchitecture(arch)) + if (ArchSpec arch = GetArchitecture()) *s << ", arch = " << arch.GetArchitectureName(); s->EOL(); @@ -184,17 +183,16 @@ lldb_private::Address ObjectFileJIT::GetEntryPointAddress() { return Address(); } -lldb_private::Address ObjectFileJIT::GetHeaderAddress() { return Address(); } +lldb_private::Address ObjectFileJIT::GetBaseAddress() { return Address(); } ObjectFile::Type ObjectFileJIT::CalculateType() { return eTypeJIT; } ObjectFile::Strata ObjectFileJIT::CalculateStrata() { return eStrataJIT; } -bool ObjectFileJIT::GetArchitecture(ArchSpec &arch) { - ObjectFileJITDelegateSP delegate_sp(m_delegate_wp.lock()); - if (delegate_sp) - return delegate_sp->GetArchitecture(arch); - return false; +ArchSpec ObjectFileJIT::GetArchitecture() { + if (ObjectFileJITDelegateSP delegate_sp = m_delegate_wp.lock()) + return delegate_sp->GetArchitecture(); + return ArchSpec(); } //------------------------------------------------------------------ @@ -218,7 +216,7 @@ bool ObjectFileJIT::SetLoadAddress(Target &target, lldb::addr_t value, // that size on disk (to avoid __PAGEZERO) and load them SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); if (section_sp && section_sp->GetFileSize() > 0 && - section_sp->IsThreadSpecific() == false) { + !section_sp->IsThreadSpecific()) { if (target.GetSectionLoadList().SetSectionLoadAddress( section_sp, section_sp->GetFileAddress() + value)) ++num_loaded_sections; diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h index c964906a5e8e..3d9e4748d3df 100644 --- a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h +++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h @@ -10,10 +10,6 @@ #ifndef liblldb_ObjectFileJIT_h_ #define liblldb_ObjectFileJIT_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Address.h" #include "lldb/Symbol/ObjectFile.h" @@ -77,7 +73,7 @@ public: void Dump(lldb_private::Stream *s) override; - bool GetArchitecture(lldb_private::ArchSpec &arch) override; + lldb_private::ArchSpec GetArchitecture() override; bool GetUUID(lldb_private::UUID *uuid) override; @@ -93,7 +89,7 @@ public: lldb_private::Address GetEntryPointAddress() override; - lldb_private::Address GetHeaderAddress() override; + lldb_private::Address GetBaseAddress() override; ObjectFile::Type CalculateType() override; diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 91e7f3353270..06908fecf984 100644 --- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -7,12 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/StringRef.h" -// Project includes #include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" #include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" #include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" @@ -23,7 +19,6 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/RangeMap.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamFile.h" #include "lldb/Host/Host.h" @@ -41,12 +36,13 @@ #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" #include "lldb/Utility/UUID.h" -#include "lldb/Utility/SafeMachO.h" +#include "lldb/Host/SafeMachO.h" #include "llvm/Support/MemoryBuffer.h" @@ -919,12 +915,10 @@ size_t ObjectFileMachO::GetModuleSpecifications( spec.SetObjectOffset(file_offset); spec.SetObjectSize(length); - if (GetArchitecture(header, data, data_offset, - spec.GetArchitecture())) { - if (spec.GetArchitecture().IsValid()) { - GetUUID(header, data, data_offset, spec.GetUUID()); - specs.Append(spec); - } + spec.GetArchitecture() = GetArchitecture(header, data, data_offset); + if (spec.GetArchitecture().IsValid()) { + GetUUID(header, data, data_offset, spec.GetUUID()); + specs.Append(spec); } } } @@ -962,6 +956,11 @@ const ConstString &ObjectFileMachO::GetSegmentNameLINKEDIT() { return g_section_name_LINKEDIT; } +const ConstString &ObjectFileMachO::GetSegmentNameDWARF() { + static ConstString g_section_name("__DWARF"); + return g_section_name; +} + const ConstString &ObjectFileMachO::GetSectionNameEHFrame() { static ConstString g_section_name_eh_frame("__eh_frame"); return g_section_name_eh_frame; @@ -1102,9 +1101,7 @@ bool ObjectFileMachO::ParseHeader() { if (can_parse) { m_data.GetU32(&offset, &m_header.cputype, 6); - ArchSpec mach_arch; - - if (GetArchitecture(mach_arch)) { + if (ArchSpec mach_arch = GetArchitecture()) { // Check if the module has a required architecture const ArchSpec &module_arch = module_sp->GetArchitecture(); if (module_arch.IsValid() && !module_arch.IsCompatibleMatch(mach_arch)) @@ -1191,21 +1188,28 @@ AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) { case eSectionTypeDebug: case eSectionTypeDWARFDebugAbbrev: + case eSectionTypeDWARFDebugAbbrevDwo: case eSectionTypeDWARFDebugAddr: case eSectionTypeDWARFDebugAranges: case eSectionTypeDWARFDebugCuIndex: case eSectionTypeDWARFDebugFrame: case eSectionTypeDWARFDebugInfo: + case eSectionTypeDWARFDebugInfoDwo: case eSectionTypeDWARFDebugLine: + case eSectionTypeDWARFDebugLineStr: case eSectionTypeDWARFDebugLoc: + case eSectionTypeDWARFDebugLocLists: case eSectionTypeDWARFDebugMacInfo: case eSectionTypeDWARFDebugMacro: case eSectionTypeDWARFDebugNames: case eSectionTypeDWARFDebugPubNames: case eSectionTypeDWARFDebugPubTypes: case eSectionTypeDWARFDebugRanges: + case eSectionTypeDWARFDebugRngLists: case eSectionTypeDWARFDebugStr: + case eSectionTypeDWARFDebugStrDwo: case eSectionTypeDWARFDebugStrOffsets: + case eSectionTypeDWARFDebugStrOffsetsDwo: case eSectionTypeDWARFDebugTypes: case eSectionTypeDWARFAppleNames: case eSectionTypeDWARFAppleTypes: @@ -1455,6 +1459,7 @@ static lldb::SectionType GetSectionType(uint32_t flags, static ConstString g_sect_name_dwarf_debug_info("__debug_info"); static ConstString g_sect_name_dwarf_debug_line("__debug_line"); static ConstString g_sect_name_dwarf_debug_loc("__debug_loc"); + static ConstString g_sect_name_dwarf_debug_loclists("__debug_loclists"); static ConstString g_sect_name_dwarf_debug_macinfo("__debug_macinfo"); static ConstString g_sect_name_dwarf_debug_names("__debug_names"); static ConstString g_sect_name_dwarf_debug_pubnames("__debug_pubnames"); @@ -1484,6 +1489,8 @@ static lldb::SectionType GetSectionType(uint32_t flags, return eSectionTypeDWARFDebugLine; if (section_name == g_sect_name_dwarf_debug_loc) return eSectionTypeDWARFDebugLoc; + if (section_name == g_sect_name_dwarf_debug_loclists) + return eSectionTypeDWARFDebugLocLists; if (section_name == g_sect_name_dwarf_debug_macinfo) return eSectionTypeDWARFDebugMacInfo; if (section_name == g_sect_name_dwarf_debug_names) @@ -1493,7 +1500,7 @@ static lldb::SectionType GetSectionType(uint32_t flags, if (section_name == g_sect_name_dwarf_debug_pubtypes) return eSectionTypeDWARFDebugPubTypes; if (section_name == g_sect_name_dwarf_debug_ranges) - return eSectionTypeDWARFDebugRanges; + return eSectionTypeDWARFDebugRanges; if (section_name == g_sect_name_dwarf_debug_str) return eSectionTypeDWARFDebugStr; if (section_name == g_sect_name_dwarf_debug_types) @@ -1668,7 +1675,7 @@ void ObjectFileMachO::ProcessSegmentCommand(const load_command &load_cmd_, } else if (unified_section_sp) { if (is_dsym && unified_section_sp->GetFileAddress() != load_cmd.vmaddr) { // Check to see if the module was read from memory? - if (module_sp->GetObjectFile()->GetHeaderAddress().IsValid()) { + if (module_sp->GetObjectFile()->GetBaseAddress().IsValid()) { // We have a module that is in memory and needs to have its file // address adjusted. We need to do this because when we load a file // from memory, its addresses will be slid already, yet the addresses @@ -2177,7 +2184,7 @@ size_t ObjectFileMachO::ParseSymtab() { uint32_t name_offset = cmd_offset + m_data.GetU32(&offset); const char *path = m_data.PeekCStr(name_offset); if (path) { - FileSpec file_spec(path, false); + FileSpec file_spec(path); // Strip the path if there is @rpath, @executable, etc so we just use // the basename if (path[0] == '@') @@ -2331,14 +2338,6 @@ size_t ObjectFileMachO::ParseSymtab() { if (nlist_data_sp) nlist_data.SetData(nlist_data_sp, 0, nlist_data_sp->GetByteSize()); - // Load strings individually from memory when loading from memory - // since shared cache string tables contain strings for all symbols - // from all shared cached libraries DataBufferSP strtab_data_sp - // (ReadMemory (process_sp, strtab_addr, - // strtab_data_byte_size)); - // if (strtab_data_sp) - // strtab_data.SetData (strtab_data_sp, 0, - // strtab_data_sp->GetByteSize()); if (m_dysymtab.nindirectsyms != 0) { const addr_t indirect_syms_addr = linkedit_load_addr + m_dysymtab.indirectsymoff - @@ -2350,8 +2349,25 @@ size_t ObjectFileMachO::ParseSymtab() { indirect_symbol_index_data.SetData( indirect_syms_data_sp, 0, indirect_syms_data_sp->GetByteSize()); + // If this binary is outside the shared cache, + // cache the string table. + // Binaries in the shared cache all share a giant string table, and + // we can't share the string tables across multiple ObjectFileMachO's, + // so we'd end up re-reading this mega-strtab for every binary + // in the shared cache - it would be a big perf problem. + // For binaries outside the shared cache, it's faster to read the + // entire strtab at once instead of piece-by-piece as we process + // the nlist records. + if ((m_header.flags & 0x80000000u) == 0) { + DataBufferSP strtab_data_sp (ReadMemory (process_sp, strtab_addr, + strtab_data_byte_size)); + if (strtab_data_sp) { + strtab_data.SetData (strtab_data_sp, 0, strtab_data_sp->GetByteSize()); + } + } } - } else if (memory_module_load_level >= + } + if (memory_module_load_level >= eMemoryModuleLoadLevelPartial) { if (function_starts_load_command.cmd) { const addr_t func_start_addr = @@ -2621,7 +2637,7 @@ size_t ObjectFileMachO::ParseSymtab() { // shared cache UUID in the development or non-development shared caches // on disk. if (process_shared_cache_uuid.IsValid()) { - if (dsc_development_filespec.Exists()) { + if (FileSystem::Instance().Exists(dsc_development_filespec)) { UUID dsc_development_uuid = GetSharedCacheUUID( dsc_development_filespec, byte_order, addr_byte_size); if (dsc_development_uuid.IsValid() && @@ -2630,7 +2646,8 @@ size_t ObjectFileMachO::ParseSymtab() { dsc_uuid = dsc_development_uuid; } } - if (!dsc_uuid.IsValid() && dsc_nondevelopment_filespec.Exists()) { + if (!dsc_uuid.IsValid() && + FileSystem::Instance().Exists(dsc_nondevelopment_filespec)) { UUID dsc_nondevelopment_uuid = GetSharedCacheUUID( dsc_nondevelopment_filespec, byte_order, addr_byte_size); if (dsc_nondevelopment_uuid.IsValid() && @@ -2643,8 +2660,8 @@ size_t ObjectFileMachO::ParseSymtab() { // Failing a UUID match, prefer the development dyld_shared cache if both // are present. - if (!dsc_filespec.Exists()) { - if (dsc_development_filespec.Exists()) { + if (!FileSystem::Instance().Exists(dsc_filespec)) { + if (FileSystem::Instance().Exists(dsc_development_filespec)) { dsc_filespec = dsc_development_filespec; } else { dsc_filespec = dsc_nondevelopment_filespec; @@ -3052,11 +3069,11 @@ size_t ObjectFileMachO::ParseSymtab() { // file so you end up with a path that looks // like "/tmp/src//tmp/src/" FileSpec so_dir(so_path, false); - if (!so_dir.Exists()) { + if (!FileSystem::Instance().Exists(so_dir)) { so_dir.SetFile( &full_so_path[double_slash_pos + 1], false); - if (so_dir.Exists()) { + if (FileSystem::Instance().Exists(so_dir)) { // Trim off the incorrect path full_so_path.erase(0, double_slash_pos + 1); @@ -4001,11 +4018,11 @@ size_t ObjectFileMachO::ParseSymtab() { // string in the DW_AT_comp_dir, and the second is the // directory for the source file so you end up with a path // that looks like "/tmp/src//tmp/src/" - FileSpec so_dir(so_path, false); - if (!so_dir.Exists()) { - so_dir.SetFile(&full_so_path[double_slash_pos + 1], false, + FileSpec so_dir(so_path); + if (!FileSystem::Instance().Exists(so_dir)) { + so_dir.SetFile(&full_so_path[double_slash_pos + 1], FileSpec::Style::native); - if (so_dir.Exists()) { + if (FileSystem::Instance().Exists(so_dir)) { // Trim off the incorrect path full_so_path.erase(0, double_slash_pos + 1); } @@ -4453,7 +4470,7 @@ size_t ObjectFileMachO::ParseSymtab() { symbol_value -= section_file_addr; } - if (is_debug == false) { + if (!is_debug) { if (type == eSymbolTypeCode) { // See if we can find a N_FUN entry for any code symbols. If we // do find a match, and the name matches, then we can merge the @@ -4600,7 +4617,7 @@ size_t ObjectFileMachO::ParseSymtab() { if (function_starts_count > 0) { uint32_t num_synthetic_function_symbols = 0; for (i = 0; i < function_starts_count; ++i) { - if (function_starts.GetEntryRef(i).data == false) + if (!function_starts.GetEntryRef(i).data) ++num_synthetic_function_symbols; } @@ -4612,7 +4629,7 @@ size_t ObjectFileMachO::ParseSymtab() { for (i = 0; i < function_starts_count; ++i) { const FunctionStarts::Entry *func_start_entry = function_starts.GetEntryAtIndex(i); - if (func_start_entry->data == false) { + if (!func_start_entry->data) { addr_t symbol_file_addr = func_start_entry->addr; uint32_t symbol_flags = 0; if (is_arm) { @@ -4817,8 +4834,7 @@ void ObjectFileMachO::Dump(Stream *s) { else s->PutCString("ObjectFileMachO32"); - ArchSpec header_arch; - GetArchitecture(header_arch); + ArchSpec header_arch = GetArchitecture(); *s << ", file = '" << m_file << "', triple = " << header_arch.GetTriple().getTriple() << "\n"; @@ -4869,25 +4885,83 @@ bool ObjectFileMachO::GetUUID(const llvm::MachO::mach_header &header, return false; } -static const char *GetOSName(uint32_t cmd) { +static llvm::StringRef GetOSName(uint32_t cmd) { switch (cmd) { case llvm::MachO::LC_VERSION_MIN_IPHONEOS: - return "ios"; + return llvm::Triple::getOSTypeName(llvm::Triple::IOS); case llvm::MachO::LC_VERSION_MIN_MACOSX: - return "macosx"; + return llvm::Triple::getOSTypeName(llvm::Triple::MacOSX); case llvm::MachO::LC_VERSION_MIN_TVOS: - return "tvos"; + return llvm::Triple::getOSTypeName(llvm::Triple::TvOS); case llvm::MachO::LC_VERSION_MIN_WATCHOS: - return "watchos"; + return llvm::Triple::getOSTypeName(llvm::Triple::WatchOS); default: llvm_unreachable("unexpected LC_VERSION load command"); } } -bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, - const lldb_private::DataExtractor &data, - lldb::offset_t lc_offset, - ArchSpec &arch) { +namespace { + struct OSEnv { + llvm::StringRef os_type; + llvm::StringRef environment; + OSEnv(uint32_t cmd) { + switch (cmd) { + case PLATFORM_MACOS: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::MacOSX); + return; + case PLATFORM_IOS: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::IOS); + return; + case PLATFORM_TVOS: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::TvOS); + return; + case PLATFORM_WATCHOS: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::WatchOS); + return; +// NEED_BRIDGEOS_TRIPLE case PLATFORM_BRIDGEOS: +// NEED_BRIDGEOS_TRIPLE os_type = llvm::Triple::getOSTypeName(llvm::Triple::BridgeOS); +// NEED_BRIDGEOS_TRIPLE return; +#if defined (PLATFORM_IOSSIMULATOR) && defined (PLATFORM_TVOSSIMULATOR) && defined (PLATFORM_WATCHOSSIMULATOR) + case PLATFORM_IOSSIMULATOR: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::IOS); + environment = + llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator); + return; + case PLATFORM_TVOSSIMULATOR: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::TvOS); + environment = + llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator); + return; + case PLATFORM_WATCHOSSIMULATOR: + os_type = llvm::Triple::getOSTypeName(llvm::Triple::WatchOS); + environment = + llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator); + return; +#endif + default: { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS | + LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("unsupported platform in LC_BUILD_VERSION"); + } + } + } + }; + + struct MinOS { + uint32_t major_version, minor_version, patch_version; + MinOS(uint32_t version) + : major_version(version >> 16), + minor_version((version >> 8) & 0xffu), + patch_version(version & 0xffu) {} + }; +} // namespace + +ArchSpec +ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, + const lldb_private::DataExtractor &data, + lldb::offset_t lc_offset) { + ArchSpec arch; arch.SetArchitecture(eArchTypeMachO, header.cputype, header.cpusubtype); if (arch.IsValid()) { @@ -4912,39 +4986,37 @@ bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, triple.setVendor(llvm::Triple::UnknownVendor); triple.setVendorName(llvm::StringRef()); } - return true; + return arch; } else { struct load_command load_cmd; + llvm::SmallString<16> os_name; + llvm::raw_svector_ostream os(os_name); + // See if there is an LC_VERSION_MIN_* load command that can give + // us the OS type. lldb::offset_t offset = lc_offset; for (uint32_t i = 0; i < header.ncmds; ++i) { const lldb::offset_t cmd_offset = offset; if (data.GetU32(&offset, &load_cmd, 2) == NULL) break; - uint32_t major, minor, patch; struct version_min_command version_min; - - llvm::SmallString<16> os_name; - llvm::raw_svector_ostream os(os_name); - switch (load_cmd.cmd) { case llvm::MachO::LC_VERSION_MIN_IPHONEOS: case llvm::MachO::LC_VERSION_MIN_MACOSX: case llvm::MachO::LC_VERSION_MIN_TVOS: - case llvm::MachO::LC_VERSION_MIN_WATCHOS: + case llvm::MachO::LC_VERSION_MIN_WATCHOS: { if (load_cmd.cmdsize != sizeof(version_min)) break; - data.ExtractBytes(cmd_offset, - sizeof(version_min), data.GetByteOrder(), - &version_min); - major = version_min.version >> 16; - minor = (version_min.version >> 8) & 0xffu; - patch = version_min.version & 0xffu; - os << GetOSName(load_cmd.cmd) << major << '.' << minor << '.' - << patch; + if (data.ExtractBytes(cmd_offset, sizeof(version_min), + data.GetByteOrder(), &version_min) == 0) + break; + MinOS min_os(version_min.version); + os << GetOSName(load_cmd.cmd) << min_os.major_version << '.' + << min_os.minor_version << '.' << min_os.patch_version; triple.setOSName(os.str()); - return true; + return arch; + } default: break; } @@ -4952,6 +5024,39 @@ bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, offset = cmd_offset + load_cmd.cmdsize; } + // See if there is an LC_BUILD_VERSION load command that can give + // us the OS type. + + offset = lc_offset; + for (uint32_t i = 0; i < header.ncmds; ++i) { + const lldb::offset_t cmd_offset = offset; + if (data.GetU32(&offset, &load_cmd, 2) == NULL) + break; + do { + if (load_cmd.cmd == llvm::MachO::LC_BUILD_VERSION) { + struct build_version_command build_version; + if (load_cmd.cmdsize < sizeof(build_version)) { + // Malformed load command. + break; + } + if (data.ExtractBytes(cmd_offset, sizeof(build_version), + data.GetByteOrder(), &build_version) == 0) + break; + MinOS min_os(build_version.minos); + OSEnv os_env(build_version.platform); + if (os_env.os_type.empty()) + break; + os << os_env.os_type << min_os.major_version << '.' + << min_os.minor_version << '.' << min_os.patch_version; + triple.setOSName(os.str()); + if (!os_env.environment.empty()) + triple.setEnvironmentName(os_env.environment); + return arch; + } + } while (0); + offset = cmd_offset + load_cmd.cmdsize; + } + if (header.filetype != MH_KEXT_BUNDLE) { // We didn't find a LC_VERSION_MIN load command and this isn't a KEXT // so lets not say our Vendor is Apple, leave it as an unspecified @@ -4961,7 +5066,7 @@ bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, } } } - return arch.IsValid(); + return arch; } bool ObjectFileMachO::GetUUID(lldb_private::UUID *uuid) { @@ -4984,9 +5089,6 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { std::vector<std::string> rpath_paths; std::vector<std::string> rpath_relative_paths; std::vector<std::string> at_exec_relative_paths; - const bool resolve_path = false; // Don't resolve the dependent file paths - // since they may not reside on this - // system uint32_t i; for (i = 0; i < m_header.ncmds; ++i) { const uint32_t cmd_offset = offset; @@ -5015,7 +5117,7 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { at_exec_relative_paths.push_back(path + strlen("@executable_path")); } else { - FileSpec file_spec(path, resolve_path); + FileSpec file_spec(path); if (files.AppendIfUnique(file_spec)) count++; } @@ -5030,8 +5132,8 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { } FileSpec this_file_spec(m_file); - this_file_spec.ResolvePath(); - + FileSystem::Instance().Resolve(this_file_spec); + if (!rpath_paths.empty()) { // Fixup all LC_RPATH values to be absolute paths std::string loader_path("@loader_path"); @@ -5052,8 +5154,10 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { path += rpath_relative_path; // It is OK to resolve this path because we must find a file on disk // for us to accept it anyway if it is rpath relative. - FileSpec file_spec(path, true); - if (file_spec.Exists() && files.AppendIfUnique(file_spec)) { + FileSpec file_spec(path); + FileSystem::Instance().Resolve(file_spec); + if (FileSystem::Instance().Exists(file_spec) && + files.AppendIfUnique(file_spec)) { count++; break; } @@ -5070,7 +5174,8 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { for (const auto &at_exec_relative_path : at_exec_relative_paths) { FileSpec file_spec = exec_dir.CopyByAppendingPathComponent(at_exec_relative_path); - if (file_spec.Exists() && files.AppendIfUnique(file_spec)) + if (FileSystem::Instance().Exists(file_spec) && + files.AppendIfUnique(file_spec)) count++; } } @@ -5235,7 +5340,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() { return m_entry_point_address; } -lldb_private::Address ObjectFileMachO::GetHeaderAddress() { +lldb_private::Address ObjectFileMachO::GetBaseAddress() { lldb_private::Address header_addr; SectionList *section_list = GetSectionList(); if (section_list) { @@ -5583,14 +5688,16 @@ llvm::VersionTuple ObjectFileMachO::GetVersion() { return llvm::VersionTuple(); } -bool ObjectFileMachO::GetArchitecture(ArchSpec &arch) { +ArchSpec ObjectFileMachO::GetArchitecture() { ModuleSP module_sp(GetModule()); + ArchSpec arch; if (module_sp) { std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + return GetArchitecture(m_header, m_data, - MachHeaderSizeFromMagic(m_header.magic), arch); + MachHeaderSizeFromMagic(m_header.magic)); } - return false; + return arch; } void ObjectFileMachO::GetProcessSharedCacheUUID(Process *process, addr_t &base_addr, UUID &uuid) { @@ -5716,8 +5823,30 @@ llvm::VersionTuple ObjectFileMachO::GetMinimumOSVersion() { m_min_os_version = llvm::VersionTuple(xxxx, yy, zz); break; } + } + } else if (lc.cmd == llvm::MachO::LC_BUILD_VERSION) { + // struct build_version_command { + // uint32_t cmd; /* LC_BUILD_VERSION */ + // uint32_t cmdsize; /* sizeof(struct build_version_command) plus */ + // /* ntools * sizeof(struct build_tool_version) */ + // uint32_t platform; /* platform */ + // uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + // uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + // uint32_t ntools; /* number of tool entries following this */ + // }; + + offset += 4; // skip platform + uint32_t minos = m_data.GetU32(&offset); + + const uint32_t xxxx = minos >> 16; + const uint32_t yy = (minos >> 8) & 0xffu; + const uint32_t zz = minos & 0xffu; + if (xxxx) { + m_min_os_version = llvm::VersionTuple(xxxx, yy, zz); + break; } } + offset = load_cmd_offset + lc.cmdsize; } @@ -5735,7 +5864,7 @@ uint32_t ObjectFileMachO::GetSDKVersion(uint32_t *versions, if (m_sdk_versions.empty()) { lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); bool success = false; - for (uint32_t i = 0; success == false && i < m_header.ncmds; ++i) { + for (uint32_t i = 0; !success && i < m_header.ncmds; ++i) { const lldb::offset_t load_cmd_offset = offset; version_min_command lc; @@ -5764,7 +5893,46 @@ uint32_t ObjectFileMachO::GetSDKVersion(uint32_t *versions, offset = load_cmd_offset + lc.cmdsize; } - if (success == false) { + if (!success) { + offset = MachHeaderSizeFromMagic(m_header.magic); + for (uint32_t i = 0; !success && i < m_header.ncmds; ++i) { + const lldb::offset_t load_cmd_offset = offset; + + version_min_command lc; + if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) + break; + if (lc.cmd == llvm::MachO::LC_BUILD_VERSION) { + // struct build_version_command { + // uint32_t cmd; /* LC_BUILD_VERSION */ + // uint32_t cmdsize; /* sizeof(struct + // build_version_command) plus */ + // /* ntools * sizeof(struct + // build_tool_version) */ + // uint32_t platform; /* platform */ + // uint32_t minos; /* X.Y.Z is encoded in nibbles + // xxxx.yy.zz */ uint32_t sdk; /* X.Y.Z is encoded + // in nibbles xxxx.yy.zz */ uint32_t ntools; /* number + // of tool entries following this */ + // }; + + offset += 4; // skip platform + uint32_t minos = m_data.GetU32(&offset); + + const uint32_t xxxx = minos >> 16; + const uint32_t yy = (minos >> 8) & 0xffu; + const uint32_t zz = minos & 0xffu; + if (xxxx) { + m_sdk_versions.push_back(xxxx); + m_sdk_versions.push_back(yy); + m_sdk_versions.push_back(zz); + success = true; + } + } + offset = load_cmd_offset + lc.cmdsize; + } + } + + if (!success) { // Push an invalid value so we don't try to find // the version # again on the next call to this // method. @@ -5814,52 +5982,52 @@ Section *ObjectFileMachO::GetMachHeaderSection() { // the mach-o file which can be subtracted from the vmaddr of the other // segments found in memory and added to the load address ModuleSP module_sp = GetModule(); - if (module_sp) { - SectionList *section_list = GetSectionList(); - if (section_list) { - lldb::addr_t mach_base_file_addr = LLDB_INVALID_ADDRESS; - const size_t num_sections = section_list->GetSize(); - - for (size_t sect_idx = 0; sect_idx < num_sections && - mach_base_file_addr == LLDB_INVALID_ADDRESS; - ++sect_idx) { - Section *section = section_list->GetSectionAtIndex(sect_idx).get(); - if (section && section->GetFileSize() > 0 && - section->GetFileOffset() == 0 && - section->IsThreadSpecific() == false && - module_sp.get() == section->GetModule().get()) { - return section; - } - } - } + if (!module_sp) + return nullptr; + SectionList *section_list = GetSectionList(); + if (!section_list) + return nullptr; + const size_t num_sections = section_list->GetSize(); + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + Section *section = section_list->GetSectionAtIndex(sect_idx).get(); + if (section->GetFileOffset() == 0 && SectionIsLoadable(section)) + return section; } return nullptr; } +bool ObjectFileMachO::SectionIsLoadable(const Section *section) { + if (!section) + return false; + const bool is_dsym = (m_header.filetype == MH_DSYM); + if (section->GetFileSize() == 0 && !is_dsym) + return false; + if (section->IsThreadSpecific()) + return false; + if (GetModule().get() != section->GetModule().get()) + return false; + // Be careful with __LINKEDIT and __DWARF segments + if (section->GetName() == GetSegmentNameLINKEDIT() || + section->GetName() == GetSegmentNameDWARF()) { + // Only map __LINKEDIT and __DWARF if we have an in memory image and + // this isn't a kernel binary like a kext or mach_kernel. + const bool is_memory_image = (bool)m_process_wp.lock(); + const Strata strata = GetStrata(); + if (is_memory_image == false || strata == eStrataKernel) + return false; + } + return true; +} + lldb::addr_t ObjectFileMachO::CalculateSectionLoadAddressForMemoryImage( - lldb::addr_t mach_header_load_address, const Section *mach_header_section, + lldb::addr_t header_load_address, const Section *header_section, const Section *section) { ModuleSP module_sp = GetModule(); - if (module_sp && mach_header_section && section && - mach_header_load_address != LLDB_INVALID_ADDRESS) { - lldb::addr_t mach_header_file_addr = mach_header_section->GetFileAddress(); - if (mach_header_file_addr != LLDB_INVALID_ADDRESS) { - if (section && section->GetFileSize() > 0 && - section->IsThreadSpecific() == false && - module_sp.get() == section->GetModule().get()) { - // Ignore __LINKEDIT and __DWARF segments - if (section->GetName() == GetSegmentNameLINKEDIT()) { - // Only map __LINKEDIT if we have an in memory image and this isn't a - // kernel binary like a kext or mach_kernel. - const bool is_memory_image = (bool)m_process_wp.lock(); - const Strata strata = GetStrata(); - if (is_memory_image == false || strata == eStrataKernel) - return LLDB_INVALID_ADDRESS; - } - return section->GetFileAddress() - mach_header_file_addr + - mach_header_load_address; - } - } + if (module_sp && header_section && section && + header_load_address != LLDB_INVALID_ADDRESS) { + lldb::addr_t file_addr = header_section->GetFileAddress(); + if (file_addr != LLDB_INVALID_ADDRESS && SectionIsLoadable(section)) + return section->GetFileAddress() - file_addr + header_load_address; } return LLDB_INVALID_ADDRESS; } @@ -5879,22 +6047,10 @@ bool ObjectFileMachO::SetLoadAddress(Target &target, lldb::addr_t value, // Iterate through the object file sections to find all of the // sections that size on disk (to avoid __PAGEZERO) and load them SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); - if (section_sp && section_sp->GetFileSize() > 0 && - section_sp->IsThreadSpecific() == false && - module_sp.get() == section_sp->GetModule().get()) { - // Ignore __LINKEDIT and __DWARF segments - if (section_sp->GetName() == GetSegmentNameLINKEDIT()) { - // Only map __LINKEDIT if we have an in memory image and this - // isn't a kernel binary like a kext or mach_kernel. - const bool is_memory_image = (bool)m_process_wp.lock(); - const Strata strata = GetStrata(); - if (is_memory_image == false || strata == eStrataKernel) - continue; - } + if (SectionIsLoadable(section_sp.get())) if (target.GetSectionLoadList().SetSectionLoadAddress( section_sp, section_sp->GetFileAddress() + value)) ++num_loaded_sections; - } } } else { // "value" is the new base address of the mach_header, adjust each @@ -5933,6 +6089,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, target_triple.getOS() == llvm::Triple::IOS || target_triple.getOS() == llvm::Triple::WatchOS || target_triple.getOS() == llvm::Triple::TvOS)) { + // NEED_BRIDGEOS_TRIPLE target_triple.getOS() == llvm::Triple::BridgeOS)) { bool make_core = false; switch (target_arch.GetMachine()) { case llvm::Triple::aarch64: @@ -6161,10 +6318,10 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, File core_file; std::string core_file_path(outfile.GetPath()); - error = core_file.Open(core_file_path.c_str(), - File::eOpenOptionWrite | - File::eOpenOptionTruncate | - File::eOpenOptionCanCreate); + error = FileSystem::Instance().Open(core_file, outfile, + File::eOpenOptionWrite | + File::eOpenOptionTruncate | + File::eOpenOptionCanCreate); if (error.Success()) { // Read 1 page at a time uint8_t bytes[0x1000]; diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index be64518064b5..196abae807e9 100644 --- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -10,16 +10,12 @@ #ifndef liblldb_ObjectFileMachO_h_ #define liblldb_ObjectFileMachO_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Address.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Core/RangeMap.h" +#include "lldb/Host/SafeMachO.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/SafeMachO.h" #include "lldb/Utility/UUID.h" //---------------------------------------------------------------------- @@ -96,7 +92,7 @@ public: void Dump(lldb_private::Stream *s) override; - bool GetArchitecture(lldb_private::ArchSpec &arch) override; + lldb_private::ArchSpec GetArchitecture() override; bool GetUUID(lldb_private::UUID *uuid) override; @@ -108,7 +104,7 @@ public: lldb_private::Address GetEntryPointAddress() override; - lldb_private::Address GetHeaderAddress() override; + lldb_private::Address GetBaseAddress() override; uint32_t GetNumThreadContexts() override; @@ -151,10 +147,10 @@ protected: lldb::offset_t lc_offset, // Offset to the first load command lldb_private::UUID &uuid); - static bool GetArchitecture(const llvm::MachO::mach_header &header, - const lldb_private::DataExtractor &data, - lldb::offset_t lc_offset, - lldb_private::ArchSpec &arch); + static lldb_private::ArchSpec + GetArchitecture(const llvm::MachO::mach_header &header, + const lldb_private::DataExtractor &data, + lldb::offset_t lc_offset); // Intended for same-host arm device debugging where lldb needs to // detect libraries in the shared cache and augment the nlist entries @@ -196,6 +192,8 @@ protected: void SanitizeSegmentCommand(llvm::MachO::segment_command_64 &seg_cmd, uint32_t cmd_idx); + bool SectionIsLoadable(const lldb_private::Section *section); + llvm::MachO::mach_header m_header; static const lldb_private::ConstString &GetSegmentNameTEXT(); static const lldb_private::ConstString &GetSegmentNameDATA(); @@ -203,6 +201,7 @@ protected: static const lldb_private::ConstString &GetSegmentNameDATA_CONST(); static const lldb_private::ConstString &GetSegmentNameOBJC(); static const lldb_private::ConstString &GetSegmentNameLINKEDIT(); + static const lldb_private::ConstString &GetSegmentNameDWARF(); static const lldb_private::ConstString &GetSectionNameEHFrame(); llvm::MachO::dysymtab_command m_dysymtab; diff --git a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index b2967f1532ab..d18ff617521f 100644 --- a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -23,11 +23,14 @@ #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" #include "lldb/Utility/UUID.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ @@ -86,6 +89,10 @@ ObjectFile *ObjectFilePECOFF::CreateInstance(const lldb::ModuleSP &module_sp, if (!objfile_ap || !objfile_ap->ParseHeader()) return nullptr; + // Cache coff binary. + if (!objfile_ap->CreateBinary()) + return nullptr; + return objfile_ap.release(); } @@ -131,9 +138,7 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( specs.Append(ModuleSpec(file, spec)); spec.SetTriple("i686-pc-windows"); specs.Append(ModuleSpec(file, spec)); - } - else if (coff_header.machine == MachineArmNt) - { + } else if (coff_header.machine == MachineArmNt) { spec.SetTriple("arm-pc-windows"); specs.Append(ModuleSpec(file, spec)); } @@ -168,6 +173,40 @@ lldb::SymbolType ObjectFilePECOFF::MapSymbolType(uint16_t coff_symbol_type) { return lldb::eSymbolTypeInvalid; } +bool ObjectFilePECOFF::CreateBinary() { + if (m_owningbin) + return true; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + + auto binary = llvm::object::createBinary(m_file.GetPath()); + if (!binary) { + if (log) + log->Printf("ObjectFilePECOFF::CreateBinary() - failed to create binary " + "for file (%s): %s", + m_file ? m_file.GetPath().c_str() : "<NULL>", + errorToErrorCode(binary.takeError()).message().c_str()); + return false; + } + + // Make sure we only handle COFF format. + if (!binary->getBinary()->isCOFF() && + !binary->getBinary()->isCOFFImportFile()) + return false; + + m_owningbin = OWNBINType(std::move(*binary)); + if (log) + log->Printf("%p ObjectFilePECOFF::CreateBinary() module = %p (%s), file = " + "%s, binary = %p (Bin = %p)", + static_cast<void *>(this), + static_cast<void *>(GetModule().get()), + GetModule()->GetSpecificationDescription().c_str(), + m_file ? m_file.GetPath().c_str() : "<NULL>", + static_cast<void *>(m_owningbin.getPointer()), + static_cast<void *>(m_owningbin->getBinary())); + return true; +} + ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, lldb::offset_t data_offset, @@ -176,7 +215,7 @@ ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp, lldb::offset_t length) : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(), - m_entry_point_address() { + m_entry_point_address(), m_deps_filespec(), m_owningbin() { ::memset(&m_dos_header, 0, sizeof(m_dos_header)); ::memset(&m_coff_header, 0, sizeof(m_coff_header)); ::memset(&m_coff_header_opt, 0, sizeof(m_coff_header_opt)); @@ -188,7 +227,7 @@ ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp, addr_t header_addr) : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(), - m_entry_point_address() { + m_entry_point_address(), m_deps_filespec(), m_owningbin() { ::memset(&m_dos_header, 0, sizeof(m_dos_header)); ::memset(&m_coff_header, 0, sizeof(m_coff_header)); ::memset(&m_coff_header_opt, 0, sizeof(m_coff_header_opt)); @@ -431,7 +470,7 @@ bool ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr) { DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) { if (m_file) { - // A bit of a hack, but we intend to write to this buffer, so we can't + // A bit of a hack, but we intend to write to this buffer, so we can't // mmap it. auto buffer_sp = MapFileData(m_file, size, offset); return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()); @@ -488,25 +527,23 @@ bool ObjectFilePECOFF::ParseSectionHeaders( } } - return m_sect_headers.empty() == false; + return !m_sect_headers.empty(); } -bool ObjectFilePECOFF::GetSectionName(std::string §_name, - const section_header_t §) { - if (sect.name[0] == '/') { - lldb::offset_t stroff = strtoul(§.name[1], NULL, 10); +llvm::StringRef ObjectFilePECOFF::GetSectionName(const section_header_t §) { + llvm::StringRef hdr_name(sect.name, llvm::array_lengthof(sect.name)); + hdr_name = hdr_name.split('\0').first; + if (hdr_name.consume_front("/")) { + lldb::offset_t stroff; + if (!to_integer(hdr_name, stroff, 10)) + return ""; lldb::offset_t string_file_offset = m_coff_header.symoff + (m_coff_header.nsyms * 18) + stroff; - const char *name = m_data.GetCStr(&string_file_offset); - if (name) { - sect_name = name; - return true; - } - - return false; + if (const char *name = m_data.GetCStr(&string_file_offset)) + return name; + return ""; } - sect_name = sect.name; - return true; + return hdr_name; } //---------------------------------------------------------------------- @@ -663,144 +700,213 @@ bool ObjectFilePECOFF::IsStripped() { } void ObjectFilePECOFF::CreateSections(SectionList &unified_section_list) { - if (!m_sections_ap.get()) { - m_sections_ap.reset(new SectionList()); + if (m_sections_ap) + return; + m_sections_ap.reset(new SectionList()); + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + const uint32_t nsects = m_sect_headers.size(); ModuleSP module_sp(GetModule()); - if (module_sp) { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - const uint32_t nsects = m_sect_headers.size(); - ModuleSP module_sp(GetModule()); - for (uint32_t idx = 0; idx < nsects; ++idx) { - std::string sect_name; - GetSectionName(sect_name, m_sect_headers[idx]); - ConstString const_sect_name(sect_name.c_str()); - static ConstString g_code_sect_name(".code"); - static ConstString g_CODE_sect_name("CODE"); - static ConstString g_data_sect_name(".data"); - static ConstString g_DATA_sect_name("DATA"); - static ConstString g_bss_sect_name(".bss"); - static ConstString g_BSS_sect_name("BSS"); - static ConstString g_debug_sect_name(".debug"); - static ConstString g_reloc_sect_name(".reloc"); - static ConstString g_stab_sect_name(".stab"); - static ConstString g_stabstr_sect_name(".stabstr"); - static ConstString g_sect_name_dwarf_debug_abbrev(".debug_abbrev"); - static ConstString g_sect_name_dwarf_debug_aranges(".debug_aranges"); - static ConstString g_sect_name_dwarf_debug_frame(".debug_frame"); - static ConstString g_sect_name_dwarf_debug_info(".debug_info"); - static ConstString g_sect_name_dwarf_debug_line(".debug_line"); - static ConstString g_sect_name_dwarf_debug_loc(".debug_loc"); - static ConstString g_sect_name_dwarf_debug_macinfo(".debug_macinfo"); - static ConstString g_sect_name_dwarf_debug_names(".debug_names"); - static ConstString g_sect_name_dwarf_debug_pubnames(".debug_pubnames"); - static ConstString g_sect_name_dwarf_debug_pubtypes(".debug_pubtypes"); - static ConstString g_sect_name_dwarf_debug_ranges(".debug_ranges"); - static ConstString g_sect_name_dwarf_debug_str(".debug_str"); - static ConstString g_sect_name_dwarf_debug_types(".debug_types"); - static ConstString g_sect_name_eh_frame(".eh_frame"); - static ConstString g_sect_name_go_symtab(".gosymtab"); - SectionType section_type = eSectionTypeOther; - if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE && - ((const_sect_name == g_code_sect_name) || - (const_sect_name == g_CODE_sect_name))) { - section_type = eSectionTypeCode; - } else if (m_sect_headers[idx].flags & - llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA && - ((const_sect_name == g_data_sect_name) || - (const_sect_name == g_DATA_sect_name))) { + for (uint32_t idx = 0; idx < nsects; ++idx) { + ConstString const_sect_name(GetSectionName(m_sect_headers[idx])); + static ConstString g_code_sect_name(".code"); + static ConstString g_CODE_sect_name("CODE"); + static ConstString g_data_sect_name(".data"); + static ConstString g_DATA_sect_name("DATA"); + static ConstString g_bss_sect_name(".bss"); + static ConstString g_BSS_sect_name("BSS"); + static ConstString g_debug_sect_name(".debug"); + static ConstString g_reloc_sect_name(".reloc"); + static ConstString g_stab_sect_name(".stab"); + static ConstString g_stabstr_sect_name(".stabstr"); + static ConstString g_sect_name_dwarf_debug_abbrev(".debug_abbrev"); + static ConstString g_sect_name_dwarf_debug_aranges(".debug_aranges"); + static ConstString g_sect_name_dwarf_debug_frame(".debug_frame"); + static ConstString g_sect_name_dwarf_debug_info(".debug_info"); + static ConstString g_sect_name_dwarf_debug_line(".debug_line"); + static ConstString g_sect_name_dwarf_debug_loc(".debug_loc"); + static ConstString g_sect_name_dwarf_debug_loclists(".debug_loclists"); + static ConstString g_sect_name_dwarf_debug_macinfo(".debug_macinfo"); + static ConstString g_sect_name_dwarf_debug_names(".debug_names"); + static ConstString g_sect_name_dwarf_debug_pubnames(".debug_pubnames"); + static ConstString g_sect_name_dwarf_debug_pubtypes(".debug_pubtypes"); + static ConstString g_sect_name_dwarf_debug_ranges(".debug_ranges"); + static ConstString g_sect_name_dwarf_debug_str(".debug_str"); + static ConstString g_sect_name_dwarf_debug_types(".debug_types"); + static ConstString g_sect_name_eh_frame(".eh_frame"); + static ConstString g_sect_name_go_symtab(".gosymtab"); + SectionType section_type = eSectionTypeOther; + if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE && + ((const_sect_name == g_code_sect_name) || + (const_sect_name == g_CODE_sect_name))) { + section_type = eSectionTypeCode; + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA && + ((const_sect_name == g_data_sect_name) || + (const_sect_name == g_DATA_sect_name))) { + if (m_sect_headers[idx].size == 0 && m_sect_headers[idx].offset == 0) + section_type = eSectionTypeZeroFill; + else section_type = eSectionTypeData; - } else if (m_sect_headers[idx].flags & - llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA && - ((const_sect_name == g_bss_sect_name) || - (const_sect_name == g_BSS_sect_name))) { - if (m_sect_headers[idx].size == 0) - section_type = eSectionTypeZeroFill; - else - section_type = eSectionTypeData; - } else if (const_sect_name == g_debug_sect_name) { - section_type = eSectionTypeDebug; - } else if (const_sect_name == g_stabstr_sect_name) { - section_type = eSectionTypeDataCString; - } else if (const_sect_name == g_reloc_sect_name) { - section_type = eSectionTypeOther; - } else if (const_sect_name == g_sect_name_dwarf_debug_abbrev) - section_type = eSectionTypeDWARFDebugAbbrev; - else if (const_sect_name == g_sect_name_dwarf_debug_aranges) - section_type = eSectionTypeDWARFDebugAranges; - else if (const_sect_name == g_sect_name_dwarf_debug_frame) - section_type = eSectionTypeDWARFDebugFrame; - else if (const_sect_name == g_sect_name_dwarf_debug_info) - section_type = eSectionTypeDWARFDebugInfo; - else if (const_sect_name == g_sect_name_dwarf_debug_line) - section_type = eSectionTypeDWARFDebugLine; - else if (const_sect_name == g_sect_name_dwarf_debug_loc) - section_type = eSectionTypeDWARFDebugLoc; - else if (const_sect_name == g_sect_name_dwarf_debug_macinfo) - section_type = eSectionTypeDWARFDebugMacInfo; - else if (const_sect_name == g_sect_name_dwarf_debug_names) - section_type = eSectionTypeDWARFDebugNames; - else if (const_sect_name == g_sect_name_dwarf_debug_pubnames) - section_type = eSectionTypeDWARFDebugPubNames; - else if (const_sect_name == g_sect_name_dwarf_debug_pubtypes) - section_type = eSectionTypeDWARFDebugPubTypes; - else if (const_sect_name == g_sect_name_dwarf_debug_ranges) - section_type = eSectionTypeDWARFDebugRanges; - else if (const_sect_name == g_sect_name_dwarf_debug_str) - section_type = eSectionTypeDWARFDebugStr; - else if (const_sect_name == g_sect_name_dwarf_debug_types) - section_type = eSectionTypeDWARFDebugTypes; - else if (const_sect_name == g_sect_name_eh_frame) - section_type = eSectionTypeEHFrame; - else if (const_sect_name == g_sect_name_go_symtab) - section_type = eSectionTypeGoSymtab; - else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE) { - section_type = eSectionTypeCode; - } else if (m_sect_headers[idx].flags & - llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) { + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA && + ((const_sect_name == g_bss_sect_name) || + (const_sect_name == g_BSS_sect_name))) { + if (m_sect_headers[idx].size == 0) + section_type = eSectionTypeZeroFill; + else + section_type = eSectionTypeData; + } else if (const_sect_name == g_debug_sect_name) { + section_type = eSectionTypeDebug; + } else if (const_sect_name == g_stabstr_sect_name) { + section_type = eSectionTypeDataCString; + } else if (const_sect_name == g_reloc_sect_name) { + section_type = eSectionTypeOther; + } else if (const_sect_name == g_sect_name_dwarf_debug_abbrev) + section_type = eSectionTypeDWARFDebugAbbrev; + else if (const_sect_name == g_sect_name_dwarf_debug_aranges) + section_type = eSectionTypeDWARFDebugAranges; + else if (const_sect_name == g_sect_name_dwarf_debug_frame) + section_type = eSectionTypeDWARFDebugFrame; + else if (const_sect_name == g_sect_name_dwarf_debug_info) + section_type = eSectionTypeDWARFDebugInfo; + else if (const_sect_name == g_sect_name_dwarf_debug_line) + section_type = eSectionTypeDWARFDebugLine; + else if (const_sect_name == g_sect_name_dwarf_debug_loc) + section_type = eSectionTypeDWARFDebugLoc; + else if (const_sect_name == g_sect_name_dwarf_debug_loclists) + section_type = eSectionTypeDWARFDebugLocLists; + else if (const_sect_name == g_sect_name_dwarf_debug_macinfo) + section_type = eSectionTypeDWARFDebugMacInfo; + else if (const_sect_name == g_sect_name_dwarf_debug_names) + section_type = eSectionTypeDWARFDebugNames; + else if (const_sect_name == g_sect_name_dwarf_debug_pubnames) + section_type = eSectionTypeDWARFDebugPubNames; + else if (const_sect_name == g_sect_name_dwarf_debug_pubtypes) + section_type = eSectionTypeDWARFDebugPubTypes; + else if (const_sect_name == g_sect_name_dwarf_debug_ranges) + section_type = eSectionTypeDWARFDebugRanges; + else if (const_sect_name == g_sect_name_dwarf_debug_str) + section_type = eSectionTypeDWARFDebugStr; + else if (const_sect_name == g_sect_name_dwarf_debug_types) + section_type = eSectionTypeDWARFDebugTypes; + else if (const_sect_name == g_sect_name_eh_frame) + section_type = eSectionTypeEHFrame; + else if (const_sect_name == g_sect_name_go_symtab) + section_type = eSectionTypeGoSymtab; + else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE) { + section_type = eSectionTypeCode; + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) { + section_type = eSectionTypeData; + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) { + if (m_sect_headers[idx].size == 0) + section_type = eSectionTypeZeroFill; + else section_type = eSectionTypeData; - } else if (m_sect_headers[idx].flags & - llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) { - if (m_sect_headers[idx].size == 0) - section_type = eSectionTypeZeroFill; - else - section_type = eSectionTypeData; - } - - // Use a segment ID of the segment index shifted left by 8 so they - // never conflict with any of the sections. - SectionSP section_sp(new Section( - module_sp, // Module to which this section belongs - this, // Object file to which this section belongs - idx + 1, // Section ID is the 1 based segment index shifted right by - // 8 bits as not to collide with any of the 256 section IDs - // that are possible - const_sect_name, // Name of this section - section_type, // This section is a container of other sections. - m_coff_header_opt.image_base + - m_sect_headers[idx].vmaddr, // File VM address == addresses as - // they are found in the object file - m_sect_headers[idx].vmsize, // VM size in bytes of this section - m_sect_headers[idx] - .offset, // Offset to the data for this section in the file - m_sect_headers[idx] - .size, // Size in bytes of this section as found in the file - m_coff_header_opt.sect_alignment, // Section alignment - m_sect_headers[idx].flags)); // Flags for this section - - // section_sp->SetIsEncrypted (segment_is_encrypted); - - unified_section_list.AddSection(section_sp); - m_sections_ap->AddSection(section_sp); } + + // Use a segment ID of the segment index shifted left by 8 so they + // never conflict with any of the sections. + SectionSP section_sp(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + idx + 1, // Section ID is the 1 based segment index shifted right by + // 8 bits as not to collide with any of the 256 section IDs + // that are possible + const_sect_name, // Name of this section + section_type, // This section is a container of other sections. + m_coff_header_opt.image_base + + m_sect_headers[idx].vmaddr, // File VM address == addresses as + // they are found in the object file + m_sect_headers[idx].vmsize, // VM size in bytes of this section + m_sect_headers[idx] + .offset, // Offset to the data for this section in the file + m_sect_headers[idx] + .size, // Size in bytes of this section as found in the file + m_coff_header_opt.sect_alignment, // Section alignment + m_sect_headers[idx].flags)); // Flags for this section + + // section_sp->SetIsEncrypted (segment_is_encrypted); + + unified_section_list.AddSection(section_sp); + m_sections_ap->AddSection(section_sp); } } } bool ObjectFilePECOFF::GetUUID(UUID *uuid) { return false; } +uint32_t ObjectFilePECOFF::ParseDependentModules() { + ModuleSP module_sp(GetModule()); + if (!module_sp) + return 0; + + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + if (m_deps_filespec) + return m_deps_filespec->GetSize(); + + // Cache coff binary if it is not done yet. + if (!CreateBinary()) + return 0; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p ObjectFilePECOFF::ParseDependentModules() module = %p " + "(%s), binary = %p (Bin = %p)", + static_cast<void *>(this), static_cast<void *>(module_sp.get()), + module_sp->GetSpecificationDescription().c_str(), + static_cast<void *>(m_owningbin.getPointer()), + m_owningbin ? static_cast<void *>(m_owningbin->getBinary()) + : nullptr); + + auto COFFObj = + llvm::dyn_cast<llvm::object::COFFObjectFile>(m_owningbin->getBinary()); + if (!COFFObj) + return 0; + + m_deps_filespec = FileSpecList(); + + for (const auto &entry : COFFObj->import_directories()) { + llvm::StringRef dll_name; + auto ec = entry.getName(dll_name); + // Report a bogus entry. + if (ec != std::error_code()) { + if (log) + log->Printf("ObjectFilePECOFF::ParseDependentModules() - failed to get " + "import directory entry name: %s", + ec.message().c_str()); + continue; + } + + // At this moment we only have the base name of the DLL. The full path can + // only be seen after the dynamic loading. Our best guess is Try to get it + // with the help of the object file's directory. + llvm::SmallString<128> dll_fullpath; + FileSpec dll_specs(dll_name); + dll_specs.GetDirectory().SetString(m_file.GetDirectory().GetCString()); + + if (!llvm::sys::fs::real_path(dll_specs.GetPath(), dll_fullpath)) + m_deps_filespec->Append(FileSpec(dll_fullpath)); + else { + // Known DLLs or DLL not found in the object file directory. + m_deps_filespec->Append(FileSpec(dll_name)); + } + } + return m_deps_filespec->GetSize(); +} + uint32_t ObjectFilePECOFF::GetDependentModules(FileSpecList &files) { - return 0; + auto num_modules = ParseDependentModules(); + auto original_size = files.GetSize(); + + for (unsigned i = 0; i < num_modules; ++i) + files.AppendIfUnique(m_deps_filespec->GetFileSpecAtIndex(i)); + + return files.GetSize() - original_size; } lldb_private::Address ObjectFilePECOFF::GetEntryPointAddress() { @@ -811,12 +917,12 @@ lldb_private::Address ObjectFilePECOFF::GetEntryPointAddress() { return m_entry_point_address; SectionList *section_list = GetSectionList(); - addr_t offset = m_coff_header_opt.entry; + addr_t file_addr = m_coff_header_opt.entry + m_coff_header_opt.image_base; if (!section_list) - m_entry_point_address.SetOffset(offset); + m_entry_point_address.SetOffset(file_addr); else - m_entry_point_address.ResolveAddressUsingFileSections(offset, section_list); + m_entry_point_address.ResolveAddressUsingFileSections(file_addr, section_list); return m_entry_point_address; } @@ -834,8 +940,7 @@ void ObjectFilePECOFF::Dump(Stream *s) { s->Indent(); s->PutCString("ObjectFilePECOFF"); - ArchSpec header_arch; - GetArchitecture(header_arch); + ArchSpec header_arch = GetArchitecture(); *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n"; @@ -857,6 +962,9 @@ void ObjectFilePECOFF::Dump(Stream *s) { s->EOL(); DumpSectionHeaders(s); s->EOL(); + + DumpDependentModules(s); + s->EOL(); } } @@ -974,8 +1082,7 @@ void ObjectFilePECOFF::DumpOptCOFFHeader(Stream *s, //---------------------------------------------------------------------- void ObjectFilePECOFF::DumpSectionHeader(Stream *s, const section_header_t &sh) { - std::string name; - GetSectionName(name, sh); + std::string name = GetSectionName(sh); s->Printf("%-16s 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%4.4x " "0x%4.4x 0x%8.8x\n", name.c_str(), sh.vmaddr, sh.vmsize, sh.offset, sh.size, sh.reloff, @@ -1004,6 +1111,22 @@ void ObjectFilePECOFF::DumpSectionHeaders(Stream *s) { } } +//---------------------------------------------------------------------- +// DumpDependentModules +// +// Dump all of the dependent modules to the specified output stream +//---------------------------------------------------------------------- +void ObjectFilePECOFF::DumpDependentModules(lldb_private::Stream *s) { + auto num_modules = ParseDependentModules(); + if (num_modules > 0) { + s->PutCString("Dependent Modules\n"); + for (unsigned i = 0; i < num_modules; ++i) { + auto spec = m_deps_filespec->GetFileSpecAtIndex(i); + s->Printf(" %s\n", spec.GetFilename().GetCString()); + } + } +} + bool ObjectFilePECOFF::IsWindowsSubsystem() { switch (m_coff_header_opt.subsystem) { case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE: @@ -1019,9 +1142,11 @@ bool ObjectFilePECOFF::IsWindowsSubsystem() { } } -bool ObjectFilePECOFF::GetArchitecture(ArchSpec &arch) { +ArchSpec ObjectFilePECOFF::GetArchitecture() { uint16_t machine = m_coff_header.machine; switch (machine) { + default: + break; case llvm::COFF::IMAGE_FILE_MACHINE_AMD64: case llvm::COFF::IMAGE_FILE_MACHINE_I386: case llvm::COFF::IMAGE_FILE_MACHINE_POWERPC: @@ -1029,14 +1154,13 @@ bool ObjectFilePECOFF::GetArchitecture(ArchSpec &arch) { case llvm::COFF::IMAGE_FILE_MACHINE_ARM: case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT: case llvm::COFF::IMAGE_FILE_MACHINE_THUMB: + ArchSpec arch; arch.SetArchitecture(eArchTypeCOFF, machine, LLDB_INVALID_CPUTYPE, IsWindowsSubsystem() ? llvm::Triple::Win32 : llvm::Triple::UnknownOS); - return true; - default: - break; + return arch; } - return false; + return ArchSpec(); } ObjectFile::Type ObjectFilePECOFF::CalculateType() { @@ -1050,6 +1174,7 @@ ObjectFile::Type ObjectFilePECOFF::CalculateType() { } ObjectFile::Strata ObjectFilePECOFF::CalculateStrata() { return eStrataUser; } + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ diff --git a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h index d8a94e19d34f..9fd313f26a0a 100644 --- a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h +++ b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h @@ -10,13 +10,10 @@ #ifndef liblldb_ObjectFilePECOFF_h_ #define liblldb_ObjectFilePECOFF_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/ObjectFile.h" +#include "llvm/Object/Binary.h" class ObjectFilePECOFF : public lldb_private::ObjectFile { public: @@ -113,7 +110,7 @@ public: void Dump(lldb_private::Stream *s) override; - bool GetArchitecture(lldb_private::ArchSpec &arch) override; + lldb_private::ArchSpec GetArchitecture() override; bool GetUUID(lldb_private::UUID *uuid) override; @@ -261,6 +258,8 @@ protected: bool ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr); bool ParseSectionHeaders(uint32_t offset); + uint32_t ParseDependentModules(); + static void DumpDOSHeader(lldb_private::Stream *s, const dos_header_t &header); static void DumpCOFFHeader(lldb_private::Stream *s, @@ -269,19 +268,27 @@ protected: const coff_opt_header_t &header); void DumpSectionHeaders(lldb_private::Stream *s); void DumpSectionHeader(lldb_private::Stream *s, const section_header_t &sh); - bool GetSectionName(std::string §_name, const section_header_t §); + void DumpDependentModules(lldb_private::Stream *s); + + llvm::StringRef GetSectionName(const section_header_t §); typedef std::vector<section_header_t> SectionHeaderColl; typedef SectionHeaderColl::iterator SectionHeaderCollIter; typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter; private: + bool CreateBinary(); + +private: dos_header_t m_dos_header; coff_header_t m_coff_header; coff_opt_header_t m_coff_header_opt; SectionHeaderColl m_sect_headers; lldb::addr_t m_image_base; lldb_private::Address m_entry_point_address; + llvm::Optional<lldb_private::FileSpecList> m_deps_filespec; + typedef llvm::object::OwningBinary<llvm::object::Binary> OWNBINType; + llvm::Optional<OWNBINType> m_owningbin; }; #endif // liblldb_ObjectFilePECOFF_h_ diff --git a/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp b/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp index d6553f6e5142..e77888c871b5 100644 --- a/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp +++ b/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp @@ -16,7 +16,7 @@ #ifdef _WIN32 #include "lldb/Host/windows/windows.h" -#include <dbghelp.h> // for MiniDumpWriteDump +#include <dbghelp.h> #endif namespace lldb_private { diff --git a/source/Plugins/OperatingSystem/CMakeLists.txt b/source/Plugins/OperatingSystem/CMakeLists.txt index 1f017adcd02b..655007a0aab9 100644 --- a/source/Plugins/OperatingSystem/CMakeLists.txt +++ b/source/Plugins/OperatingSystem/CMakeLists.txt @@ -1,2 +1 @@ -add_subdirectory(Go) add_subdirectory(Python) diff --git a/source/Plugins/OperatingSystem/Go/CMakeLists.txt b/source/Plugins/OperatingSystem/Go/CMakeLists.txt deleted file mode 100644 index 27e952a84dfc..000000000000 --- a/source/Plugins/OperatingSystem/Go/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_lldb_library(lldbPluginOSGo PLUGIN - OperatingSystemGo.cpp - - LINK_LIBS - lldbCore - lldbInterpreter - lldbSymbol - lldbTarget - lldbPluginProcessUtility - ) diff --git a/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp b/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp deleted file mode 100644 index 3f6083931513..000000000000 --- a/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp +++ /dev/null @@ -1,498 +0,0 @@ -//===-- OperatingSystemGo.cpp -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// C Includes -// C++ Includes -#include <unordered_map> - -// Other libraries and framework includes -// Project includes -#include "OperatingSystemGo.h" - -#include "Plugins/Process/Utility/DynamicRegisterInfo.h" -#include "Plugins/Process/Utility/RegisterContextMemory.h" -#include "Plugins/Process/Utility/ThreadMemory.h" -#include "lldb/Core/Debugger.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Section.h" -#include "lldb/Core/ValueObjectVariable.h" -#include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/OptionGroupBoolean.h" -#include "lldb/Interpreter/OptionGroupUInt64.h" -#include "lldb/Interpreter/OptionValueProperties.h" -#include "lldb/Interpreter/Options.h" -#include "lldb/Interpreter/Property.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/Type.h" -#include "lldb/Symbol/VariableList.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Target/ThreadList.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/StreamString.h" - -using namespace lldb; -using namespace lldb_private; - -namespace { - -static PropertyDefinition g_properties[] = { - {"enable", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, - "Specify whether goroutines should be treated as threads."}, - {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; - -enum { - ePropertyEnableGoroutines, -}; - -class PluginProperties : public Properties { -public: - PluginProperties() : Properties() { - m_collection_sp.reset(new OptionValueProperties(GetSettingName())); - m_collection_sp->Initialize(g_properties); - } - - ~PluginProperties() override = default; - - static ConstString GetSettingName() { - return OperatingSystemGo::GetPluginNameStatic(); - } - - bool GetEnableGoroutines() { - const uint32_t idx = ePropertyEnableGoroutines; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - NULL, idx, g_properties[idx].default_uint_value); - } - - bool SetEnableGoroutines(bool enable) { - const uint32_t idx = ePropertyEnableGoroutines; - return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, enable); - } -}; - -typedef std::shared_ptr<PluginProperties> OperatingSystemGoPropertiesSP; - -static const OperatingSystemGoPropertiesSP &GetGlobalPluginProperties() { - static OperatingSystemGoPropertiesSP g_settings_sp; - if (!g_settings_sp) - g_settings_sp.reset(new PluginProperties()); - return g_settings_sp; -} - -class RegisterContextGo : public RegisterContextMemory { -public: - RegisterContextGo(lldb_private::Thread &thread, uint32_t concrete_frame_idx, - DynamicRegisterInfo ®_info, lldb::addr_t reg_data_addr) - : RegisterContextMemory(thread, concrete_frame_idx, reg_info, - reg_data_addr) { - const RegisterInfo *sp = reg_info.GetRegisterInfoAtIndex( - reg_info.ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_SP)); - const RegisterInfo *pc = reg_info.GetRegisterInfoAtIndex( - reg_info.ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, - LLDB_REGNUM_GENERIC_PC)); - size_t byte_size = std::max(sp->byte_offset + sp->byte_size, - pc->byte_offset + pc->byte_size); - - DataBufferSP reg_data_sp(new DataBufferHeap(byte_size, 0)); - m_reg_data.SetData(reg_data_sp); - } - - ~RegisterContextGo() override = default; - - bool ReadRegister(const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue ®_value) override { - switch (reg_info->kinds[eRegisterKindGeneric]) { - case LLDB_REGNUM_GENERIC_SP: - case LLDB_REGNUM_GENERIC_PC: - return RegisterContextMemory::ReadRegister(reg_info, reg_value); - default: - reg_value.SetValueToInvalid(); - return true; - } - } - - bool WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue ®_value) override { - switch (reg_info->kinds[eRegisterKindGeneric]) { - case LLDB_REGNUM_GENERIC_SP: - case LLDB_REGNUM_GENERIC_PC: - return RegisterContextMemory::WriteRegister(reg_info, reg_value); - default: - return false; - } - } - -private: - DISALLOW_COPY_AND_ASSIGN(RegisterContextGo); -}; - -} // anonymous namespace - -struct OperatingSystemGo::Goroutine { - uint64_t m_lostack; - uint64_t m_histack; - uint64_t m_goid; - addr_t m_gobuf; - uint32_t m_status; -}; - -void OperatingSystemGo::Initialize() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), CreateInstance, - DebuggerInitialize); -} - -void OperatingSystemGo::DebuggerInitialize(Debugger &debugger) { - if (!PluginManager::GetSettingForOperatingSystemPlugin( - debugger, PluginProperties::GetSettingName())) { - const bool is_global_setting = true; - PluginManager::CreateSettingForOperatingSystemPlugin( - debugger, GetGlobalPluginProperties()->GetValueProperties(), - ConstString("Properties for the goroutine thread plug-in."), - is_global_setting); - } -} - -void OperatingSystemGo::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); -} - -OperatingSystem *OperatingSystemGo::CreateInstance(Process *process, - bool force) { - if (!force) { - TargetSP target_sp = process->CalculateTarget(); - if (!target_sp) - return nullptr; - ModuleList &module_list = target_sp->GetImages(); - std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); - const size_t num_modules = module_list.GetSize(); - bool found_go_runtime = false; - for (size_t i = 0; i < num_modules; ++i) { - Module *module = module_list.GetModulePointerAtIndexUnlocked(i); - const SectionList *section_list = module->GetSectionList(); - if (section_list) { - SectionSP section_sp( - section_list->FindSectionByType(eSectionTypeGoSymtab, true)); - if (section_sp) { - found_go_runtime = true; - break; - } - } - } - if (!found_go_runtime) - return nullptr; - } - return new OperatingSystemGo(process); -} - -OperatingSystemGo::OperatingSystemGo(lldb_private::Process *process) - : OperatingSystem(process), m_reginfo(new DynamicRegisterInfo) {} - -OperatingSystemGo::~OperatingSystemGo() = default; - -ConstString OperatingSystemGo::GetPluginNameStatic() { - static ConstString g_name("goroutines"); - return g_name; -} - -const char *OperatingSystemGo::GetPluginDescriptionStatic() { - return "Operating system plug-in that reads runtime data-structures for " - "goroutines."; -} - -bool OperatingSystemGo::Init(ThreadList &threads) { - if (threads.GetSize(false) < 1) - return false; - TargetSP target_sp = m_process->CalculateTarget(); - if (!target_sp) - return false; - // Go 1.6 stores goroutines in a slice called runtime.allgs - ValueObjectSP allgs_sp = FindGlobal(target_sp, "runtime.allgs"); - if (allgs_sp) { - m_allg_sp = allgs_sp->GetChildMemberWithName(ConstString("array"), true); - m_allglen_sp = allgs_sp->GetChildMemberWithName(ConstString("len"), true); - } else { - // Go 1.4 stores goroutines in the variable runtime.allg. - m_allg_sp = FindGlobal(target_sp, "runtime.allg"); - m_allglen_sp = FindGlobal(target_sp, "runtime.allglen"); - } - - if (m_allg_sp && !m_allglen_sp) { - StreamSP error_sp = target_sp->GetDebugger().GetAsyncErrorStream(); - error_sp->Printf("Unsupported Go runtime version detected."); - return false; - } - - if (!m_allg_sp) - return false; - - RegisterContextSP real_registers_sp = - threads.GetThreadAtIndex(0, false)->GetRegisterContext(); - - std::unordered_map<size_t, ConstString> register_sets; - for (size_t set_idx = 0; set_idx < real_registers_sp->GetRegisterSetCount(); - ++set_idx) { - const RegisterSet *set = real_registers_sp->GetRegisterSet(set_idx); - ConstString name(set->name); - for (size_t reg_idx = 0; reg_idx < set->num_registers; ++reg_idx) { - register_sets[reg_idx] = name; - } - } - TypeSP gobuf_sp = FindType(target_sp, "runtime.gobuf"); - if (!gobuf_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS)); - - if (log) - log->Printf("OperatingSystemGo unable to find struct Gobuf"); - return false; - } - CompilerType gobuf_type(gobuf_sp->GetLayoutCompilerType()); - for (size_t idx = 0; idx < real_registers_sp->GetRegisterCount(); ++idx) { - RegisterInfo reg = *real_registers_sp->GetRegisterInfoAtIndex(idx); - int field_index = -1; - if (reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_SP) { - field_index = 0; - } else if (reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC) { - field_index = 1; - } - if (field_index == -1) { - reg.byte_offset = ~0; - } else { - std::string field_name; - uint64_t bit_offset = 0; - CompilerType field_type = gobuf_type.GetFieldAtIndex( - field_index, field_name, &bit_offset, nullptr, nullptr); - reg.byte_size = field_type.GetByteSize(nullptr); - reg.byte_offset = bit_offset / 8; - } - ConstString name(reg.name); - ConstString alt_name(reg.alt_name); - m_reginfo->AddRegister(reg, name, alt_name, register_sets[idx]); - } - return true; -} - -//------------------------------------------------------------------ -// PluginInterface protocol -//------------------------------------------------------------------ -ConstString OperatingSystemGo::GetPluginName() { return GetPluginNameStatic(); } - -uint32_t OperatingSystemGo::GetPluginVersion() { return 1; } - -bool OperatingSystemGo::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &real_thread_list, - ThreadList &new_thread_list) { - new_thread_list = real_thread_list; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS)); - - if (!(m_allg_sp || Init(real_thread_list)) || (m_allg_sp && !m_allglen_sp) || - !GetGlobalPluginProperties()->GetEnableGoroutines()) { - return new_thread_list.GetSize(false) > 0; - } - - if (log) - log->Printf("OperatingSystemGo::UpdateThreadList(%d, %d, %d) fetching " - "thread data from Go for pid %" PRIu64, - old_thread_list.GetSize(false), real_thread_list.GetSize(false), - new_thread_list.GetSize(0), m_process->GetID()); - uint64_t allglen = m_allglen_sp->GetValueAsUnsigned(0); - if (allglen == 0) { - return new_thread_list.GetSize(false) > 0; - } - std::vector<Goroutine> goroutines; - // The threads that are in "new_thread_list" upon entry are the threads from - // the lldb_private::Process subclass, no memory threads will be in this - // list. - - Status err; - for (uint64_t i = 0; i < allglen; ++i) { - goroutines.push_back(CreateGoroutineAtIndex(i, err)); - if (err.Fail()) { - LLDB_LOG(log, "error: {0}", err); - return new_thread_list.GetSize(false) > 0; - } - } - // Make a map so we can match goroutines with backing threads. - std::map<uint64_t, ThreadSP> stack_map; - for (uint32_t i = 0; i < real_thread_list.GetSize(false); ++i) { - ThreadSP thread = real_thread_list.GetThreadAtIndex(i, false); - stack_map[thread->GetRegisterContext()->GetSP()] = thread; - } - for (const Goroutine &goroutine : goroutines) { - if (0 /* Gidle */ == goroutine.m_status || - 6 /* Gdead */ == goroutine.m_status) { - continue; - } - ThreadSP memory_thread = - old_thread_list.FindThreadByID(goroutine.m_goid, false); - if (memory_thread && IsOperatingSystemPluginThread(memory_thread) && - memory_thread->IsValid()) { - memory_thread->ClearBackingThread(); - } else { - memory_thread.reset(new ThreadMemory(*m_process, goroutine.m_goid, "", "", - goroutine.m_gobuf)); - } - // Search for the backing thread if the goroutine is running. - if (2 == (goroutine.m_status & 0xfff)) { - auto backing_it = stack_map.lower_bound(goroutine.m_lostack); - if (backing_it != stack_map.end()) { - if (goroutine.m_histack >= backing_it->first) { - if (log) - log->Printf( - "OperatingSystemGo::UpdateThreadList found backing thread " - "%" PRIx64 " (%" PRIx64 ") for thread %" PRIx64 "", - backing_it->second->GetID(), - backing_it->second->GetProtocolID(), memory_thread->GetID()); - memory_thread->SetBackingThread(backing_it->second); - new_thread_list.RemoveThreadByID(backing_it->second->GetID(), false); - } - } - } - new_thread_list.AddThread(memory_thread); - } - - return new_thread_list.GetSize(false) > 0; -} - -void OperatingSystemGo::ThreadWasSelected(Thread *thread) {} - -RegisterContextSP -OperatingSystemGo::CreateRegisterContextForThread(Thread *thread, - addr_t reg_data_addr) { - RegisterContextSP reg_ctx_sp; - if (!thread) - return reg_ctx_sp; - - if (!IsOperatingSystemPluginThread(thread->shared_from_this())) - return reg_ctx_sp; - - reg_ctx_sp.reset( - new RegisterContextGo(*thread, 0, *m_reginfo, reg_data_addr)); - return reg_ctx_sp; -} - -StopInfoSP -OperatingSystemGo::CreateThreadStopReason(lldb_private::Thread *thread) { - StopInfoSP stop_info_sp; - return stop_info_sp; -} - -lldb::ThreadSP OperatingSystemGo::CreateThread(lldb::tid_t tid, - addr_t context) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS)); - - if (log) - log->Printf("OperatingSystemGo::CreateThread (tid = 0x%" PRIx64 - ", context = 0x%" PRIx64 ") not implemented", - tid, context); - - return ThreadSP(); -} - -ValueObjectSP OperatingSystemGo::FindGlobal(TargetSP target, const char *name) { - VariableList variable_list; - - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS)); - - if (log) { - log->Printf( - "exe: %s", - target->GetExecutableModule()->GetSpecificationDescription().c_str()); - log->Printf("modules: %zu", target->GetImages().GetSize()); - } - - uint32_t match_count = target->GetImages().FindGlobalVariables( - ConstString(name), 1, variable_list); - if (match_count > 0) { - ExecutionContextScope *exe_scope = target->GetProcessSP().get(); - if (exe_scope == NULL) - exe_scope = target.get(); - return ValueObjectVariable::Create(exe_scope, - variable_list.GetVariableAtIndex(0)); - } - return ValueObjectSP(); -} - -TypeSP OperatingSystemGo::FindType(TargetSP target_sp, const char *name) { - ConstString const_typename(name); - SymbolContext sc; - const bool exact_match = false; - - const ModuleList &module_list = target_sp->GetImages(); - size_t count = module_list.GetSize(); - for (size_t idx = 0; idx < count; idx++) { - ModuleSP module_sp(module_list.GetModuleAtIndex(idx)); - if (module_sp) { - TypeSP type_sp(module_sp->FindFirstType(sc, const_typename, exact_match)); - if (type_sp) - return type_sp; - } - } - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS)); - - if (log) - log->Printf("OperatingSystemGo::FindType(%s): not found", name); - return TypeSP(); -} - -OperatingSystemGo::Goroutine -OperatingSystemGo::CreateGoroutineAtIndex(uint64_t idx, Status &err) { - err.Clear(); - Goroutine result = {}; - ValueObjectSP g = - m_allg_sp->GetSyntheticArrayMember(idx, true)->Dereference(err); - if (err.Fail()) { - return result; - } - - ConstString name("goid"); - ValueObjectSP val = g->GetChildMemberWithName(name, true); - bool success = false; - result.m_goid = val->GetValueAsUnsigned(0, &success); - if (!success) { - err.SetErrorToGenericError(); - err.SetErrorString("unable to read goid"); - return result; - } - name.SetCString("atomicstatus"); - val = g->GetChildMemberWithName(name, true); - result.m_status = (uint32_t)val->GetValueAsUnsigned(0, &success); - if (!success) { - err.SetErrorToGenericError(); - err.SetErrorString("unable to read atomicstatus"); - return result; - } - name.SetCString("sched"); - val = g->GetChildMemberWithName(name, true); - result.m_gobuf = val->GetAddressOf(false); - name.SetCString("stack"); - val = g->GetChildMemberWithName(name, true); - name.SetCString("lo"); - ValueObjectSP child = val->GetChildMemberWithName(name, true); - result.m_lostack = child->GetValueAsUnsigned(0, &success); - if (!success) { - err.SetErrorToGenericError(); - err.SetErrorString("unable to read stack.lo"); - return result; - } - name.SetCString("hi"); - child = val->GetChildMemberWithName(name, true); - result.m_histack = child->GetValueAsUnsigned(0, &success); - if (!success) { - err.SetErrorToGenericError(); - err.SetErrorString("unable to read stack.hi"); - return result; - } - return result; -} diff --git a/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h b/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h deleted file mode 100644 index 5d255a348a63..000000000000 --- a/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h +++ /dev/null @@ -1,90 +0,0 @@ -//===-- OperatingSystemGo.h -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef _liblldb_OperatingSystemGo_h_ -#define _liblldb_OperatingSystemGo_h_ - -// C Includes -// C++ Includes -#include <memory> - -// Other libraries and framework includes -// Project includes -#include "lldb/Target/OperatingSystem.h" - -class DynamicRegisterInfo; - -class OperatingSystemGo : public lldb_private::OperatingSystem { -public: - OperatingSystemGo(lldb_private::Process *process); - - ~OperatingSystemGo() override; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static lldb_private::OperatingSystem * - CreateInstance(lldb_private::Process *process, bool force); - - static void Initialize(); - - static void DebuggerInitialize(lldb_private::Debugger &debugger); - - static void Terminate(); - - static lldb_private::ConstString GetPluginNameStatic(); - - static const char *GetPluginDescriptionStatic(); - - //------------------------------------------------------------------ - // lldb_private::PluginInterface Methods - //------------------------------------------------------------------ - lldb_private::ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; - - //------------------------------------------------------------------ - // lldb_private::OperatingSystem Methods - //------------------------------------------------------------------ - bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &real_thread_list, - lldb_private::ThreadList &new_thread_list) override; - - void ThreadWasSelected(lldb_private::Thread *thread) override; - - lldb::RegisterContextSP - CreateRegisterContextForThread(lldb_private::Thread *thread, - lldb::addr_t reg_data_addr) override; - - lldb::StopInfoSP - CreateThreadStopReason(lldb_private::Thread *thread) override; - - //------------------------------------------------------------------ - // Method for lazy creation of threads on demand - //------------------------------------------------------------------ - lldb::ThreadSP CreateThread(lldb::tid_t tid, lldb::addr_t context) override; - -private: - struct Goroutine; - - static lldb::ValueObjectSP FindGlobal(lldb::TargetSP target, - const char *name); - - static lldb::TypeSP FindType(lldb::TargetSP target_sp, const char *name); - - bool Init(lldb_private::ThreadList &threads); - - Goroutine CreateGoroutineAtIndex(uint64_t idx, lldb_private::Status &err); - - std::unique_ptr<DynamicRegisterInfo> m_reginfo; - lldb::ValueObjectSP m_allg_sp; - lldb::ValueObjectSP m_allglen_sp; -}; - -#endif // liblldb_OperatingSystemGo_h_ diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index d6252c473270..89a0f2253936 100644 --- a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -10,9 +10,6 @@ #ifndef LLDB_DISABLE_PYTHON #include "OperatingSystemPython.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "Plugins/Process/Utility/DynamicRegisterInfo.h" #include "Plugins/Process/Utility/RegisterContextDummy.h" #include "Plugins/Process/Utility/RegisterContextMemory.h" @@ -20,7 +17,6 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/ScriptInterpreter.h" @@ -32,6 +28,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadList.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StructuredData.h" @@ -53,7 +50,8 @@ OperatingSystem *OperatingSystemPython::CreateInstance(Process *process, // Python OperatingSystem plug-ins must be requested by name, so force must // be true FileSpec python_os_plugin_spec(process->GetPythonOSPluginPath()); - if (python_os_plugin_spec && python_os_plugin_spec.Exists()) { + if (python_os_plugin_spec && + FileSystem::Instance().Exists(python_os_plugin_spec)) { std::unique_ptr<OperatingSystemPython> os_ap( new OperatingSystemPython(process, python_os_plugin_spec)); if (os_ap.get() && os_ap->IsValid()) @@ -215,7 +213,7 @@ bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list, // beginning of the list uint32_t insert_idx = 0; for (uint32_t core_idx = 0; core_idx < num_cores; ++core_idx) { - if (core_used_map[core_idx] == false) { + if (!core_used_map[core_idx]) { new_thread_list.InsertThread( core_thread_list.GetThreadAtIndex(core_idx, false), insert_idx); ++insert_idx; diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h index 2e1680410962..c812464fa747 100644 --- a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h +++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h @@ -12,10 +12,6 @@ #ifndef LLDB_DISABLE_PYTHON -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/OperatingSystem.h" #include "lldb/Utility/StructuredData.h" diff --git a/source/Plugins/Platform/Android/AdbClient.cpp b/source/Plugins/Platform/Android/AdbClient.cpp index 4cd8c645dd76..0ad30a528954 100644 --- a/source/Plugins/Platform/Android/AdbClient.cpp +++ b/source/Plugins/Platform/Android/AdbClient.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -// Other libraries and framework includes #include "AdbClient.h" #include "llvm/ADT/STLExtras.h" @@ -484,7 +483,7 @@ Status AdbClient::SyncService::internalPushFile(const FileSpec &local_file, return Status("Failed to send file chunk: %s", error.AsCString()); } error = SendSyncRequest( - kDONE, llvm::sys::toTimeT(FileSystem::GetModificationTime(local_file)), + kDONE, llvm::sys::toTimeT(FileSystem::Instance().GetModificationTime(local_file)), nullptr); if (error.Fail()) return error; diff --git a/source/Plugins/Platform/Android/PlatformAndroid.cpp b/source/Plugins/Platform/Android/PlatformAndroid.cpp index 4477fe371d34..a56ab0e30153 100644 --- a/source/Plugins/Platform/Android/PlatformAndroid.cpp +++ b/source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -9,15 +9,14 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/Section.h" #include "lldb/Core/ValueObject.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/UriParser.h" -// Project includes #include "AdbClient.h" #include "PlatformAndroid.h" #include "PlatformAndroidRemoteGDBServer.h" @@ -75,7 +74,7 @@ PlatformSP PlatformAndroid::CreateInstance(bool force, const ArchSpec *arch) { } bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { const llvm::Triple &triple = arch->GetTriple(); switch (triple.getVendor()) { case llvm::Triple::PC: @@ -193,7 +192,7 @@ Status PlatformAndroid::GetFile(const FileSpec &source, if (IsHost() || !m_remote_platform_sp) return PlatformLinux::GetFile(source, destination); - FileSpec source_spec(source.GetPath(false), false, FileSpec::Style::posix); + FileSpec source_spec(source.GetPath(false), FileSpec::Style::posix); if (source_spec.IsRelative()) source_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent( source_spec.GetCString(false)); @@ -237,8 +236,7 @@ Status PlatformAndroid::PutFile(const FileSpec &source, if (IsHost() || !m_remote_platform_sp) return PlatformLinux::PutFile(source, destination, uid, gid); - FileSpec destination_spec(destination.GetPath(false), false, - FileSpec::Style::posix); + FileSpec destination_spec(destination.GetPath(false), FileSpec::Style::posix); if (destination_spec.IsRelative()) destination_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent( destination_spec.GetCString(false)); @@ -343,7 +341,7 @@ Status PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp, log->Printf("Failed to remove temp directory: %s", error.AsCString()); }); - FileSpec symfile_platform_filespec(tmpdir, false); + FileSpec symfile_platform_filespec(tmpdir); symfile_platform_filespec.AppendPathComponent("symbolized.oat"); // Execute oatdump on the remote device to generate a file with symtab diff --git a/source/Plugins/Platform/Android/PlatformAndroid.h b/source/Plugins/Platform/Android/PlatformAndroid.h index 4c12eb8c016d..2e7706cc246e 100644 --- a/source/Plugins/Platform/Android/PlatformAndroid.h +++ b/source/Plugins/Platform/Android/PlatformAndroid.h @@ -10,13 +10,9 @@ #ifndef liblldb_PlatformAndroid_h_ #define liblldb_PlatformAndroid_h_ -// C Includes -// C++ Includes #include <memory> #include <string> -// Other libraries and framework includes -// Project includes #include "Plugins/Platform/Linux/PlatformLinux.h" #include "AdbClient.h" diff --git a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp index 2415da31daf0..bbb03369d63c 100644 --- a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -// Other libraries and framework includes #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/common/TCPSocket.h" #include "lldb/Utility/Log.h" diff --git a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h index 1bd13ffe89fe..40356293b589 100644 --- a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h +++ b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h @@ -10,13 +10,9 @@ #ifndef liblldb_PlatformAndroidRemoteGDBServer_h_ #define liblldb_PlatformAndroidRemoteGDBServer_h_ -// C Includes -// C++ Includes #include <map> #include <utility> -// Other libraries and framework includes -// Project includes #include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h" #include "llvm/ADT/Optional.h" diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index bc8111d1078b..59cce3a6bc2b 100644 --- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -10,25 +10,21 @@ #include "PlatformFreeBSD.h" #include "lldb/Host/Config.h" -// C Includes #include <stdio.h> #ifndef LLDB_DISABLE_POSIX #include <sys/utsname.h> #endif -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/BreakpointSite.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" #include "lldb/Host/HostInfo.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" @@ -52,7 +48,7 @@ PlatformSP PlatformFreeBSD::CreateInstance(bool force, const ArchSpec *arch) { arch ? arch->GetTriple().getTriple() : "<null>"); bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { const llvm::Triple &triple = arch->GetTriple(); switch (triple.getOS()) { case llvm::Triple::FreeBSD: @@ -274,9 +270,9 @@ lldb::ProcessSP PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info, TargetSP new_target_sp; ArchSpec emptyArchSpec; - error = debugger.GetTargetList().CreateTarget(debugger, "", emptyArchSpec, - false, m_remote_platform_sp, - new_target_sp); + error = debugger.GetTargetList().CreateTarget( + debugger, "", emptyArchSpec, eLoadDependentsNo, m_remote_platform_sp, + new_target_sp); target = new_target_sp.get(); } else error.Clear(); diff --git a/source/Plugins/Platform/Kalimba/PlatformKalimba.cpp b/source/Plugins/Platform/Kalimba/PlatformKalimba.cpp index 00327e485bf3..cc902b7f7ad5 100644 --- a/source/Plugins/Platform/Kalimba/PlatformKalimba.cpp +++ b/source/Plugins/Platform/Kalimba/PlatformKalimba.cpp @@ -11,9 +11,6 @@ #include "PlatformKalimba.h" #include "lldb/Host/Config.h" -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" @@ -33,7 +30,7 @@ static uint32_t g_initialize_count = 0; PlatformSP PlatformKalimba::CreateInstance(bool force, const ArchSpec *arch) { bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { const llvm::Triple &triple = arch->GetTriple(); switch (triple.getVendor()) { case llvm::Triple::CSR: diff --git a/source/Plugins/Platform/Kalimba/PlatformKalimba.h b/source/Plugins/Platform/Kalimba/PlatformKalimba.h index 53a8e5594aaa..efa78457d585 100644 --- a/source/Plugins/Platform/Kalimba/PlatformKalimba.h +++ b/source/Plugins/Platform/Kalimba/PlatformKalimba.h @@ -10,10 +10,6 @@ #ifndef liblldb_PlatformKalimba_h_ #define liblldb_PlatformKalimba_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/Platform.h" namespace lldb_private { diff --git a/source/Plugins/Platform/Linux/PlatformLinux.cpp b/source/Plugins/Platform/Linux/PlatformLinux.cpp index dbde91d7ab2d..7498c648d6e4 100644 --- a/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ b/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -10,23 +10,19 @@ #include "PlatformLinux.h" #include "lldb/Host/Config.h" -// C Includes #include <stdio.h> #ifndef LLDB_DISABLE_POSIX #include <sys/utsname.h> #endif -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" #include "lldb/Host/HostInfo.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" @@ -50,7 +46,7 @@ PlatformSP PlatformLinux::CreateInstance(bool force, const ArchSpec *arch) { arch ? arch->GetTriple().getTriple() : "<null>"); bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { const llvm::Triple &triple = arch->GetTriple(); switch (triple.getOS()) { case llvm::Triple::Linux: @@ -302,8 +298,8 @@ PlatformLinux::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, if (target == nullptr) { LLDB_LOG(log, "creating new target"); TargetSP new_target_sp; - error = debugger.GetTargetList().CreateTarget(debugger, "", "", false, - nullptr, new_target_sp); + error = debugger.GetTargetList().CreateTarget( + debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); if (error.Fail()) { LLDB_LOG(log, "failed to create new target: {0}", error); return process_sp; @@ -322,8 +318,8 @@ PlatformLinux::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, // Now create the gdb-remote process. LLDB_LOG(log, "having target create process with gdb-remote plugin"); - process_sp = target->CreateProcess( - launch_info.GetListenerForProcess(debugger), "gdb-remote", nullptr); + process_sp = + target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr); if (!process_sp) { error.SetErrorString("CreateProcess() failed for gdb-remote process"); diff --git a/source/Plugins/Platform/MacOSX/CMakeLists.txt b/source/Plugins/Platform/MacOSX/CMakeLists.txt index f9663559069a..6f0d952c35fb 100644 --- a/source/Plugins/Platform/MacOSX/CMakeLists.txt +++ b/source/Plugins/Platform/MacOSX/CMakeLists.txt @@ -6,6 +6,7 @@ list(APPEND PLUGIN_PLATFORM_MACOSX_SOURCES PlatformRemoteAppleTV.cpp PlatformRemoteAppleWatch.cpp PlatformRemoteDarwinDevice.cpp + PlatformRemoteAppleBridge.cpp ) list(APPEND PLUGIN_PLATFORM_MACOSX_DARWIN_ONLY_SOURCES diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp index 6852097117a1..a2f74a5fc8bc 100644 --- a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp @@ -9,16 +9,12 @@ #include "PlatformAppleSimulator.h" -// C Includes #if defined(__APPLE__) #include <dlfcn.h> #endif -// C++ Includes #include <mutex> #include <thread> -// Other libraries and framework includes -// Project includes #include "lldb/Host/PseudoTerminal.h" #include "lldb/Target/Process.h" #include "lldb/Utility/LLDBAssert.h" @@ -229,9 +225,8 @@ FileSpec PlatformAppleSimulator::GetCoreSimulatorPath() { cs_path.Printf( "%s/Library/PrivateFrameworks/CoreSimulator.framework/CoreSimulator", developer_dir); - const bool resolve_path = true; - m_core_simulator_framework_path = - FileSpec(cs_path.GetData(), resolve_path); + m_core_simulator_framework_path = FileSpec(cs_path.GetData()); + FileSystem::Instance().Resolve(*m_core_simulator_framework_path); } } diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h index 2536854e9630..daae376cc00b 100644 --- a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h +++ b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h @@ -10,12 +10,8 @@ #ifndef liblldb_PlatformAppleSimulator_h_ #define liblldb_PlatformAppleSimulator_h_ -// C Includes -// C++ Includes #include <mutex> -// Other libraries and framework includes -// Project includes #include "Plugins/Platform/MacOSX/PlatformDarwin.h" #include "Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h" #include "lldb/Utility/FileSpec.h" diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp index e55cc0f4f6a4..62bd3c3ed1f8 100644 --- a/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp @@ -9,10 +9,6 @@ #include "PlatformAppleTVSimulator.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" @@ -80,7 +76,7 @@ PlatformSP PlatformAppleTVSimulator::CreateInstance(bool force, } bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { switch (arch->GetMachine()) { case llvm::Triple::x86_64: { const llvm::Triple &triple = arch->GetTriple(); @@ -93,7 +89,7 @@ PlatformSP PlatformAppleTVSimulator::CreateInstance(bool force, // Only accept "unknown" for the vendor if the host is Apple and it // "unknown" wasn't specified (it was just returned because it was NOT // specified) - case llvm::Triple::UnknownArch: + case llvm::Triple::UnknownVendor: create = !arch->TripleVendorWasSpecified(); break; #endif @@ -190,7 +186,7 @@ Status PlatformAppleTVSimulator::ResolveExecutable( // ourselves Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); - if (resolved_module_spec.GetFileSpec().Exists()) { + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { if (resolved_module_spec.GetArchitecture().IsValid()) { error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, NULL, NULL, NULL); @@ -228,7 +224,7 @@ Status PlatformAppleTVSimulator::ResolveExecutable( } if (error.Fail() || !exe_module_sp) { - if (resolved_module_spec.GetFileSpec().Readable()) { + 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(), @@ -247,19 +243,20 @@ Status PlatformAppleTVSimulator::ResolveExecutable( return error; } -static FileSpec::EnumerateDirectoryResult +static FileSystem::EnumerateDirectoryResult EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft, - const FileSpec &file_spec) { + llvm::StringRef path) { if (ft == llvm::sys::fs::file_type::directory_file) { + FileSpec file_spec(path); const char *filename = file_spec.GetFilename().GetCString(); if (filename && strncmp(filename, "AppleTVSimulator", strlen("AppleTVSimulator")) == 0) { ::snprintf((char *)baton, PATH_MAX, "%s", filename); - return FileSpec::eEnumerateDirectoryResultQuit; + return FileSystem::eEnumerateDirectoryResultQuit; } } - return FileSpec::eEnumerateDirectoryResultNext; + return FileSystem::eEnumerateDirectoryResultNext; } const char *PlatformAppleTVSimulator::GetSDKDirectoryAsCString() { @@ -277,9 +274,9 @@ const char *PlatformAppleTVSimulator::GetSDKDirectoryAsCString() { bool find_directories = true; bool find_files = false; bool find_other = false; - FileSpec::EnumerateDirectory(sdks_directory, find_directories, find_files, - find_other, EnumerateDirectoryCallback, - sdk_dirname); + FileSystem::Instance().EnumerateDirectory( + sdks_directory, find_directories, find_files, find_other, + EnumerateDirectoryCallback, sdk_dirname); if (sdk_dirname[0]) { m_sdk_directory = sdks_directory; @@ -315,13 +312,15 @@ Status PlatformAppleTVSimulator::GetSymbolFile(const FileSpec &platform_file, platform_file_path); // First try in the SDK and see if the file is in there - local_file.SetFile(resolved_path, true, FileSpec::Style::native); - if (local_file.Exists()) + local_file.SetFile(resolved_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) return error; // Else fall back to the actual path itself - local_file.SetFile(platform_file_path, true, FileSpec::Style::native); - if (local_file.Exists()) + local_file.SetFile(platform_file_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) return error; } error.SetErrorStringWithFormat( diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h b/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h index 8cecb4d496ab..9a4da589c7ea 100644 --- a/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h +++ b/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h @@ -10,10 +10,6 @@ #ifndef liblldb_PlatformAppleTVSimulator_h_ #define liblldb_PlatformAppleTVSimulator_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "PlatformDarwin.h" class PlatformAppleTVSimulator : public PlatformDarwin { diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp index 8bbe0af0aec2..ec112cc0b9c5 100644 --- a/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp @@ -9,10 +9,6 @@ #include "PlatformAppleWatchSimulator.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" @@ -79,7 +75,7 @@ PlatformSP PlatformAppleWatchSimulator::CreateInstance(bool force, } bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { switch (arch->GetMachine()) { case llvm::Triple::x86_64: { const llvm::Triple &triple = arch->GetTriple(); @@ -92,7 +88,7 @@ PlatformSP PlatformAppleWatchSimulator::CreateInstance(bool force, // Only accept "unknown" for the vendor if the host is Apple and it // "unknown" wasn't specified (it was just returned because it was NOT // specified) - case llvm::Triple::UnknownArch: + case llvm::Triple::UnknownVendor: create = !arch->TripleVendorWasSpecified(); break; #endif @@ -190,7 +186,7 @@ Status PlatformAppleWatchSimulator::ResolveExecutable( // ourselves Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); - if (resolved_module_spec.GetFileSpec().Exists()) { + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { if (resolved_module_spec.GetArchitecture().IsValid()) { error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, NULL, NULL, NULL); @@ -228,7 +224,7 @@ Status PlatformAppleWatchSimulator::ResolveExecutable( } if (error.Fail() || !exe_module_sp) { - if (resolved_module_spec.GetFileSpec().Readable()) { + 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(), @@ -247,19 +243,20 @@ Status PlatformAppleWatchSimulator::ResolveExecutable( return error; } -static FileSpec::EnumerateDirectoryResult +static FileSystem::EnumerateDirectoryResult EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft, - const FileSpec &file_spec) { + llvm::StringRef path) { if (ft == llvm::sys::fs::file_type::directory_file) { + FileSpec file_spec(path); const char *filename = file_spec.GetFilename().GetCString(); if (filename && strncmp(filename, "AppleWatchSimulator", strlen("AppleWatchSimulator")) == 0) { ::snprintf((char *)baton, PATH_MAX, "%s", filename); - return FileSpec::eEnumerateDirectoryResultQuit; + return FileSystem::eEnumerateDirectoryResultQuit; } } - return FileSpec::eEnumerateDirectoryResultNext; + return FileSystem::eEnumerateDirectoryResultNext; } const char *PlatformAppleWatchSimulator::GetSDKDirectoryAsCString() { @@ -277,9 +274,9 @@ const char *PlatformAppleWatchSimulator::GetSDKDirectoryAsCString() { bool find_directories = true; bool find_files = false; bool find_other = false; - FileSpec::EnumerateDirectory(sdks_directory, find_directories, find_files, - find_other, EnumerateDirectoryCallback, - sdk_dirname); + FileSystem::Instance().EnumerateDirectory( + sdks_directory, find_directories, find_files, find_other, + EnumerateDirectoryCallback, sdk_dirname); if (sdk_dirname[0]) { m_sdk_directory = sdks_directory; @@ -315,13 +312,15 @@ Status PlatformAppleWatchSimulator::GetSymbolFile(const FileSpec &platform_file, platform_file_path); // First try in the SDK and see if the file is in there - local_file.SetFile(resolved_path, true, FileSpec::Style::native); - if (local_file.Exists()) + local_file.SetFile(resolved_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) return error; // Else fall back to the actual path itself - local_file.SetFile(platform_file_path, true, FileSpec::Style::native); - if (local_file.Exists()) + local_file.SetFile(platform_file_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) return error; } error.SetErrorStringWithFormat( diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h b/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h index 30aa42c964a5..c240a09e3afd 100644 --- a/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h +++ b/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h @@ -10,10 +10,6 @@ #ifndef liblldb_PlatformAppleWatchSimulator_h_ #define liblldb_PlatformAppleWatchSimulator_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "PlatformDarwin.h" class PlatformAppleWatchSimulator : public PlatformDarwin { diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 886e3b6d9a05..3868d97700e0 100644 --- a/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -9,14 +9,11 @@ #include "PlatformDarwin.h" -// C Includes #include <string.h> -// C++ Includes #include <algorithm> #include <mutex> -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/BreakpointSite.h" #include "lldb/Core/Debugger.h" @@ -33,7 +30,6 @@ #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" -#include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/Timer.h" @@ -43,7 +39,7 @@ #include "llvm/Support/VersionTuple.h" #if defined(__APPLE__) -#include <TargetConditionals.h> // for TARGET_OS_TV, TARGET_OS_WATCH +#include <TargetConditionals.h> #endif using namespace lldb; @@ -88,7 +84,7 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( ObjectFile *objfile = symfile->GetObjectFile(); if (objfile) { FileSpec symfile_spec(objfile->GetFileSpec()); - if (symfile_spec && symfile_spec.Exists()) { + if (symfile_spec && FileSystem::Instance().Exists(symfile_spec)) { while (module_spec.GetFilename()) { std::string module_basename( module_spec.GetFilename().GetCString()); @@ -130,20 +126,21 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( "%s/../Python/%s.py", symfile_spec.GetDirectory().GetCString(), original_module_basename.c_str()); - FileSpec script_fspec(path_string.GetString(), true); - FileSpec orig_script_fspec(original_path_string.GetString(), - true); + FileSpec script_fspec(path_string.GetString()); + FileSystem::Instance().Resolve(script_fspec); + FileSpec orig_script_fspec(original_path_string.GetString()); + FileSystem::Instance().Resolve(orig_script_fspec); // if we did some replacements of reserved characters, and a // file with the untampered name exists, then warn the user // that the file as-is shall not be loaded if (feedback_stream) { if (module_basename != original_module_basename && - orig_script_fspec.Exists()) { + FileSystem::Instance().Exists(orig_script_fspec)) { const char *reason_for_complaint = was_keyword ? "conflicts with a keyword" : "contains reserved characters"; - if (script_fspec.Exists()) + if (FileSystem::Instance().Exists(script_fspec)) feedback_stream->Printf( "warning: the symbol file '%s' contains a debug " "script. However, its name" @@ -167,7 +164,7 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( } } - if (script_fspec.Exists()) { + if (FileSystem::Instance().Exists(script_fspec)) { file_list.Append(script_fspec); break; } @@ -193,25 +190,12 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( Status PlatformDarwin::ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec, FileSpec &sym_file) { - Status error; sym_file = sym_spec.GetSymbolFileSpec(); - - llvm::sys::fs::file_status st; - if (status(sym_file.GetPath(), st, false)) { - error.SetErrorString("Could not stat file!"); - return error; - } - - if (exists(st)) { - if (is_directory(st)) { - sym_file = Symbols::FindSymbolFileInBundle( - sym_file, sym_spec.GetUUIDPtr(), sym_spec.GetArchitecturePtr()); - } - } else { - if (sym_spec.GetUUID().IsValid()) { - } + if (FileSystem::Instance().IsDirectory(sym_file)) { + sym_file = Symbols::FindSymbolFileInBundle(sym_file, sym_spec.GetUUIDPtr(), + sym_spec.GetArchitecturePtr()); } - return error; + return {}; } static lldb_private::Status @@ -261,7 +245,7 @@ lldb_private::Status PlatformDarwin::GetSharedModuleWithLocalCache( if (!cache_path.empty()) { std::string module_path(module_spec.GetFileSpec().GetPath()); cache_path.append(module_path); - FileSpec module_cache_spec(cache_path, false); + FileSpec module_cache_spec(cache_path); // if rsync is supported, always bring in the file - rsync will be very // efficient when files are the same on the local and remote end of the @@ -270,7 +254,7 @@ lldb_private::Status PlatformDarwin::GetSharedModuleWithLocalCache( err = BringInRemoteFile(this, module_spec, module_cache_spec); if (err.Fail()) return err; - if (module_cache_spec.Exists()) { + if (FileSystem::Instance().Exists(module_cache_spec)) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf("[%s] module %s/%s was rsynced and is now there", @@ -286,7 +270,7 @@ lldb_private::Status PlatformDarwin::GetSharedModuleWithLocalCache( } // try to find the module in the cache - if (module_cache_spec.Exists()) { + if (FileSystem::Instance().Exists(module_cache_spec)) { // get the local and remote MD5 and compare if (m_remote_platform_sp) { // when going over the *slow* GDB remote transfer mechanism we first @@ -337,7 +321,7 @@ lldb_private::Status PlatformDarwin::GetSharedModuleWithLocalCache( Status err = BringInRemoteFile(this, module_spec, module_cache_spec); if (err.Fail()) return err; - if (module_cache_spec.Exists()) { + if (FileSystem::Instance().Exists(module_cache_spec)) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf("[%s] module %s/%s is now cached and fine", @@ -412,8 +396,8 @@ Status PlatformDarwin::GetSharedModule( snprintf(new_path + search_path_len, sizeof(new_path) - search_path_len, "/%s", platform_path + bundle_directory_len); - FileSpec new_file_spec(new_path, false); - if (new_file_spec.Exists()) { + FileSpec new_file_spec(new_path); + if (FileSystem::Instance().Exists(new_file_spec)) { ModuleSpec new_module_spec(module_spec); new_module_spec.GetFileSpec() = new_file_spec; Status new_error(Platform::GetSharedModule( @@ -505,10 +489,7 @@ bool PlatformDarwin::ModuleIsExcludedForUnconstrainedSearches( return false; ObjectFile::Type obj_type = obj_file->GetType(); - if (obj_type == ObjectFile::eTypeDynamicLinker) - return true; - else - return false; + return obj_type == ObjectFile::eTypeDynamicLinker; } bool PlatformDarwin::x86GetSupportedArchitectureAtIndex(uint32_t idx, @@ -1167,9 +1148,9 @@ const char *PlatformDarwin::GetDeveloperDirectory() { if (xcode_select_prefix_dir) xcode_dir_path.append(xcode_select_prefix_dir); xcode_dir_path.append("/usr/share/xcode-select/xcode_dir_path"); - temp_file_spec.SetFile(xcode_dir_path, false, FileSpec::Style::native); + temp_file_spec.SetFile(xcode_dir_path, FileSpec::Style::native); auto dir_buffer = - DataBufferLLVM::CreateFromPath(temp_file_spec.GetPath()); + FileSystem::Instance().CreateDataBuffer(temp_file_spec.GetPath()); if (dir_buffer && dir_buffer->GetByteSize() > 0) { llvm::StringRef path_ref(dir_buffer->GetChars()); // Trim tailing newlines and make sure there is enough room for a null @@ -1183,8 +1164,8 @@ const char *PlatformDarwin::GetDeveloperDirectory() { } if (!developer_dir_path_valid) { - FileSpec xcode_select_cmd("/usr/bin/xcode-select", false); - if (xcode_select_cmd.Exists()) { + FileSpec xcode_select_cmd("/usr/bin/xcode-select"); + if (FileSystem::Instance().Exists(xcode_select_cmd)) { int exit_status = -1; int signo = -1; std::string command_output; @@ -1206,8 +1187,8 @@ const char *PlatformDarwin::GetDeveloperDirectory() { } developer_dir_path[i] = '\0'; - FileSpec devel_dir(developer_dir_path, false); - if (llvm::sys::fs::is_directory(devel_dir.GetPath())) { + FileSpec devel_dir(developer_dir_path); + if (FileSystem::Instance().IsDirectory(devel_dir)) { developer_dir_path_valid = true; } } @@ -1215,9 +1196,8 @@ const char *PlatformDarwin::GetDeveloperDirectory() { } if (developer_dir_path_valid) { - temp_file_spec.SetFile(developer_dir_path, false, - FileSpec::Style::native); - if (temp_file_spec.Exists()) { + temp_file_spec.SetFile(developer_dir_path, FileSpec::Style::native); + if (FileSystem::Instance().Exists(temp_file_spec)) { m_developer_directory.assign(developer_dir_path); return m_developer_directory.c_str(); } @@ -1247,7 +1227,7 @@ BreakpointSP PlatformDarwin::SetThreadCreationBreakpoint(Target &target) { FileSpecList bp_modules; for (size_t i = 0; i < llvm::array_lengthof(g_bp_modules); i++) { const char *bp_module = g_bp_modules[i]; - bp_modules.Append(FileSpec(bp_module, false)); + bp_modules.Append(FileSpec(bp_module)); } bool internal = true; @@ -1300,20 +1280,20 @@ static const char *const sdk_strings[] = { }; static FileSpec CheckPathForXcode(const FileSpec &fspec) { - if (fspec.Exists()) { + if (FileSystem::Instance().Exists(fspec)) { const char substr[] = ".app/Contents"; std::string path_to_shlib = fspec.GetPath(); size_t pos = path_to_shlib.rfind(substr); if (pos != std::string::npos) { path_to_shlib.erase(pos + strlen(substr)); - FileSpec ret(path_to_shlib, false); + FileSpec ret(path_to_shlib); FileSpec xcode_binary_path = ret; xcode_binary_path.AppendPathComponent("MacOS"); xcode_binary_path.AppendPathComponent("Xcode"); - if (xcode_binary_path.Exists()) { + if (FileSystem::Instance().Exists(xcode_binary_path)) { return ret; } } @@ -1348,8 +1328,9 @@ static FileSpec GetXcodeContentsPath() { if (!g_xcode_filespec) { const char *developer_dir_env_var = getenv("DEVELOPER_DIR"); if (developer_dir_env_var && developer_dir_env_var[0]) { - g_xcode_filespec = - CheckPathForXcode(FileSpec(developer_dir_env_var, true)); + FileSpec developer_dir_spec = FileSpec(developer_dir_env_var); + FileSystem::Instance().Resolve(developer_dir_spec); + g_xcode_filespec = CheckPathForXcode(developer_dir_spec); } // Fall back to using "xcrun" to find the selected Xcode @@ -1373,7 +1354,7 @@ static FileSpec GetXcodeContentsPath() { } output.append("/.."); - g_xcode_filespec = CheckPathForXcode(FileSpec(output, false)); + g_xcode_filespec = CheckPathForXcode(FileSpec(output)); } } } @@ -1402,14 +1383,11 @@ bool PlatformDarwin::SDKSupportsModules(SDKType desired_type, if (last_path_component) { const llvm::StringRef sdk_name = last_path_component.GetStringRef(); - llvm::StringRef version_part; - - if (sdk_name.startswith(sdk_strings[(int)desired_type])) { - version_part = - sdk_name.drop_front(strlen(sdk_strings[(int)desired_type])); - } else { + if (!sdk_name.startswith(sdk_strings[desired_type])) return false; - } + auto version_part = + sdk_name.drop_front(strlen(sdk_strings[desired_type])); + version_part.consume_back(".sdk"); llvm::VersionTuple version; if (version.tryParse(version_part)) @@ -1420,23 +1398,24 @@ bool PlatformDarwin::SDKSupportsModules(SDKType desired_type, return false; } -FileSpec::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( - void *baton, llvm::sys::fs::file_type file_type, const FileSpec &spec) { +FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( + void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef path) { SDKEnumeratorInfo *enumerator_info = static_cast<SDKEnumeratorInfo *>(baton); + FileSpec spec(path); if (SDKSupportsModules(enumerator_info->sdk_type, spec)) { enumerator_info->found_path = spec; - return FileSpec::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; + return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; } - return FileSpec::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; + return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; } FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, const FileSpec &sdks_spec) { // Look inside Xcode for the required installed iOS SDK version - if (!llvm::sys::fs::is_directory(sdks_spec.GetPath())) { + if (!FileSystem::Instance().IsDirectory(sdks_spec)) { return FileSpec(); } @@ -1448,11 +1427,11 @@ FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, enumerator_info.sdk_type = sdk_type; - FileSpec::EnumerateDirectory(sdks_spec.GetPath(), find_directories, - find_files, find_other, DirectoryEnumerator, - &enumerator_info); + FileSystem::Instance().EnumerateDirectory( + sdks_spec.GetPath(), find_directories, find_files, find_other, + DirectoryEnumerator, &enumerator_info); - if (llvm::sys::fs::is_directory(enumerator_info.found_path.GetPath())) + if (FileSystem::Instance().IsDirectory(enumerator_info.found_path)) return enumerator_info.found_path; else return FileSpec(); @@ -1499,7 +1478,7 @@ FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { version.getMinor().getValueOr(0)); native_sdk_spec.AppendPathComponent(native_sdk_name.GetString()); - if (native_sdk_spec.Exists()) { + if (FileSystem::Instance().Exists(native_sdk_spec)) { return native_sdk_spec; } } @@ -1597,7 +1576,7 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( sysroot_spec = GetSDKDirectoryForModules(sdk_type); } - if (llvm::sys::fs::is_directory(sysroot_spec.GetPath())) { + if (FileSystem::Instance().IsDirectory(sysroot_spec.GetPath())) { options.push_back("-isysroot"); options.push_back(sysroot_spec.GetPath()); } @@ -1661,7 +1640,7 @@ lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) { xcode_lldb_resources.AppendPathComponent("SharedFrameworks"); xcode_lldb_resources.AppendPathComponent("LLDB.framework"); xcode_lldb_resources.AppendPathComponent("Resources"); - if (xcode_lldb_resources.Exists()) { + if (FileSystem::Instance().Exists(xcode_lldb_resources)) { FileSpec dir; dir.GetDirectory().SetCString(xcode_lldb_resources.GetPath().c_str()); g_executable_dirs.push_back(dir); @@ -1675,7 +1654,7 @@ lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) { FileSpec executable_file; executable_file.GetDirectory() = executable_dir.GetDirectory(); executable_file.GetFilename().SetCString(basename); - if (executable_file.Exists()) + if (FileSystem::Instance().Exists(executable_file)) return executable_file; } @@ -1759,7 +1738,7 @@ PlatformDarwin::FindBundleBinaryInExecSearchPaths (const ModuleSpec &module_spec path_to_try.AppendPathComponent(path_parts[k]); } - if (path_to_try.Exists()) { + if (FileSystem::Instance().Exists(path_to_try)) { ModuleSpec new_module_spec(module_spec); new_module_spec.GetFileSpec() = path_to_try; Status new_error(Platform::GetSharedModule( diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/source/Plugins/Platform/MacOSX/PlatformDarwin.h index 3ad29ec1a0b9..f2dd9b1bc778 100644 --- a/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -10,12 +10,9 @@ #ifndef liblldb_PlatformDarwin_h_ #define liblldb_PlatformDarwin_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "Plugins/Platform/POSIX/PlatformPOSIX.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Utility/FileSpec.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" @@ -85,6 +82,12 @@ public: static std::tuple<llvm::VersionTuple, llvm::StringRef> ParseVersionBuildDir(llvm::StringRef str); + enum SDKType : unsigned { + MacOSX = 0, + iPhoneSimulator, + iPhoneOS, + }; + protected: void ReadLibdispatchOffsetsAddress(lldb_private::Process *process); @@ -95,12 +98,6 @@ protected: const lldb_private::FileSpecList *module_search_paths_ptr, lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); - enum class SDKType { - MacOSX = 0, - iPhoneSimulator, - iPhoneOS, - }; - static bool SDKSupportsModules(SDKType sdk_type, llvm::VersionTuple version); static bool SDKSupportsModules(SDKType desired_type, @@ -111,9 +108,9 @@ protected: SDKType sdk_type; }; - static lldb_private::FileSpec::EnumerateDirectoryResult + static lldb_private::FileSystem::EnumerateDirectoryResult DirectoryEnumerator(void *baton, llvm::sys::fs::file_type file_type, - const lldb_private::FileSpec &spec); + llvm::StringRef path); static lldb_private::FileSpec FindSDKInXcodeForModules(SDKType sdk_type, diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp index 1e3216c0af5a..4c6d9459e225 100644 --- a/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp @@ -13,10 +13,6 @@ #if defined(__APPLE__) // This Plugin uses the Mac-specific // source/Host/macosx/cfcpp utilities -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" @@ -95,7 +91,7 @@ PlatformSP PlatformDarwinKernel::CreateInstance(bool force, // ArchSpec for normal userland debugging. It is only useful in kernel debug // sessions and the DynamicLoaderDarwinPlugin (or a user doing 'platform // select') will force the creation of this Platform plugin. - if (force == false) { + if (!force) { if (log) log->Printf("PlatformDarwinKernel::%s() aborting creation of platform " "because force == false", @@ -106,7 +102,7 @@ PlatformSP PlatformDarwinKernel::CreateInstance(bool force, bool create = force; LazyBool is_ios_debug_session = eLazyBoolCalculate; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { const llvm::Triple &triple = arch->GetTriple(); switch (triple.getVendor()) { case llvm::Triple::Apple: @@ -115,7 +111,7 @@ PlatformSP PlatformDarwinKernel::CreateInstance(bool force, // Only accept "unknown" for vendor if the host is Apple and it "unknown" // wasn't specified (it was just returned because it was NOT specified) - case llvm::Triple::UnknownArch: + case llvm::Triple::UnknownVendor: create = !arch->TripleVendorWasSpecified(); break; default: @@ -129,6 +125,7 @@ PlatformSP PlatformDarwinKernel::CreateInstance(bool force, case llvm::Triple::IOS: case llvm::Triple::WatchOS: case llvm::Triple::TvOS: + // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: break; // Only accept "vendor" for vendor if the host is Apple and it "unknown" // wasn't specified (it was just returned because it was NOT specified) @@ -186,14 +183,13 @@ const char *PlatformDarwinKernel::GetDescriptionStatic() { /// Code to handle the PlatformDarwinKernel settings //------------------------------------------------------------------ -static PropertyDefinition g_properties[] = { +static constexpr PropertyDefinition g_properties[] = { {"search-locally-for-kexts", OptionValue::eTypeBoolean, true, true, NULL, - NULL, "Automatically search for kexts on the local system when doing " + {}, "Automatically search for kexts on the local system when doing " "kernel debugging."}, - {"kext-directories", OptionValue::eTypeFileSpecList, false, 0, NULL, NULL, + {"kext-directories", OptionValue::eTypeFileSpecList, false, 0, NULL, {}, "Directories/KDKs to search for kexts in when starting a kernel debug " - "session."}, - {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; + "session."}}; enum { ePropertySearchForKexts = 0, ePropertyKextDirectories }; @@ -354,6 +350,8 @@ void PlatformDarwinKernel::CollectKextAndKernelDirectories() { "/Platforms/AppleTVOS.platform/Developer/SDKs"); AddSDKSubdirsToSearchPaths(developer_dir + "/Platforms/WatchOS.platform/Developer/SDKs"); + AddSDKSubdirsToSearchPaths(developer_dir + + "/Platforms/BridgeOS.platform/Developer/SDKs"); } if (m_ios_debug_session != eLazyBoolYes) { AddSDKSubdirsToSearchPaths(developer_dir + @@ -375,12 +373,15 @@ void PlatformDarwinKernel::CollectKextAndKernelDirectories() { GetUserSpecifiedDirectoriesToSearch(); // Add simple directory /Applications/Xcode.app/Contents/Developer/../Symbols - FileSpec possible_dir(developer_dir + "/../Symbols", true); - if (llvm::sys::fs::is_directory(possible_dir.GetPath())) + FileSpec possible_dir(developer_dir + "/../Symbols"); + FileSystem::Instance().Resolve(possible_dir); + if (FileSystem::Instance().IsDirectory(possible_dir)) m_search_directories.push_back(possible_dir); // Add simple directory of the current working directory - m_search_directories_no_recursing.push_back(FileSpec(".", true)); + FileSpec cwd("."); + FileSystem::Instance().Resolve(cwd); + m_search_directories_no_recursing.push_back(cwd); } void PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch() { @@ -390,8 +391,8 @@ void PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch() { const uint32_t user_dirs_count = user_dirs.GetSize(); for (uint32_t i = 0; i < user_dirs_count; i++) { FileSpec dir = user_dirs.GetFileSpecAtIndex(i); - dir.ResolvePath(); - if (llvm::sys::fs::is_directory(dir.GetPath())) { + FileSystem::Instance().Resolve(dir); + if (FileSystem::Instance().IsDirectory(dir)) { m_search_directories.push_back(dir); } } @@ -406,14 +407,14 @@ void PlatformDarwinKernel::AddRootSubdirsToSearchPaths( // /AppleInternal/Developer/KDKs/*.kdk/... nullptr}; for (int i = 0; subdirs[i] != nullptr; i++) { - FileSpec testdir(dir + subdirs[i], true); - if (llvm::sys::fs::is_directory(testdir.GetPath())) + FileSpec testdir(dir + subdirs[i]); + FileSystem::Instance().Resolve(testdir); + if (FileSystem::Instance().IsDirectory(testdir)) thisp->m_search_directories.push_back(testdir); } // Look for kernel binaries in the top level directory, without any recursion - thisp->m_search_directories_no_recursing.push_back( - FileSpec(dir + "/", false)); + thisp->m_search_directories_no_recursing.push_back(FileSpec(dir + "/")); } // Given a directory path dir, look for any subdirs named *.kdk and *.sdk @@ -422,25 +423,26 @@ void PlatformDarwinKernel::AddSDKSubdirsToSearchPaths(const std::string &dir) { const bool find_directories = true; const bool find_files = false; const bool find_other = false; - FileSpec::EnumerateDirectory(dir.c_str(), find_directories, find_files, - find_other, FindKDKandSDKDirectoriesInDirectory, - this); + FileSystem::Instance().EnumerateDirectory( + dir.c_str(), find_directories, find_files, find_other, + FindKDKandSDKDirectoriesInDirectory, this); } // Helper function to find *.sdk and *.kdk directories in a given directory. -FileSpec::EnumerateDirectoryResult +FileSystem::EnumerateDirectoryResult PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory( - void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { + void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) { static ConstString g_sdk_suffix = ConstString(".sdk"); static ConstString g_kdk_suffix = ConstString(".kdk"); PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; + FileSpec file_spec(path); if (ft == llvm::sys::fs::file_type::directory_file && (file_spec.GetFileNameExtension() == g_sdk_suffix || file_spec.GetFileNameExtension() == g_kdk_suffix)) { AddRootSubdirsToSearchPaths(thisp, file_spec.GetPath()); } - return FileSpec::eEnumerateDirectoryResultNext; + return FileSystem::eEnumerateDirectoryResultNext; } // Recursively search trough m_search_directories looking for kext and kernel @@ -452,7 +454,7 @@ void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() { const bool find_directories = true; const bool find_files = true; const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s. - FileSpec::EnumerateDirectory( + FileSystem::Instance().EnumerateDirectory( dir.GetPath().c_str(), find_directories, find_files, find_other, GetKernelsAndKextsInDirectoryWithRecursion, this); } @@ -462,7 +464,7 @@ void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() { const bool find_directories = true; const bool find_files = true; const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s. - FileSpec::EnumerateDirectory( + FileSystem::Instance().EnumerateDirectory( dir.GetPath().c_str(), find_directories, find_files, find_other, GetKernelsAndKextsInDirectoryNoRecursion, this); } @@ -476,25 +478,27 @@ void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() { // // Recurse into any subdirectories found. -FileSpec::EnumerateDirectoryResult +FileSystem::EnumerateDirectoryResult PlatformDarwinKernel::GetKernelsAndKextsInDirectoryWithRecursion( - void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { - return GetKernelsAndKextsInDirectoryHelper(baton, ft, file_spec, true); + void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) { + return GetKernelsAndKextsInDirectoryHelper(baton, ft, path, true); } -FileSpec::EnumerateDirectoryResult +FileSystem::EnumerateDirectoryResult PlatformDarwinKernel::GetKernelsAndKextsInDirectoryNoRecursion( - void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { - return GetKernelsAndKextsInDirectoryHelper(baton, ft, file_spec, false); + void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) { + return GetKernelsAndKextsInDirectoryHelper(baton, ft, path, false); } -FileSpec::EnumerateDirectoryResult +FileSystem::EnumerateDirectoryResult PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( - void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec, + void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path, bool recurse) { static ConstString g_kext_suffix = ConstString(".kext"); static ConstString g_dsym_suffix = ConstString(".dSYM"); static ConstString g_bundle_suffix = ConstString("Bundle"); + + FileSpec file_spec(path); ConstString file_spec_extension = file_spec.GetFileNameExtension(); Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); @@ -526,19 +530,19 @@ PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( } thisp->m_kernel_binaries_without_dsyms.push_back(file_spec); } - return FileSpec::eEnumerateDirectoryResultNext; + return FileSystem::eEnumerateDirectoryResultNext; } } else if (ft == llvm::sys::fs::file_type::directory_file && file_spec_extension == g_kext_suffix) { AddKextToMap(thisp, file_spec); // Look to see if there is a PlugIns subdir with more kexts - FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns", false); + FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns"); std::string search_here_too; - if (llvm::sys::fs::is_directory(contents_plugins.GetPath())) { + if (FileSystem::Instance().IsDirectory(contents_plugins)) { search_here_too = contents_plugins.GetPath(); } else { - FileSpec plugins(file_spec.GetPath() + "/PlugIns", false); - if (llvm::sys::fs::is_directory(plugins.GetPath())) { + FileSpec plugins(file_spec.GetPath() + "/PlugIns"); + if (FileSystem::Instance().IsDirectory(plugins)) { search_here_too = plugins.GetPath(); } } @@ -547,13 +551,13 @@ PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( const bool find_directories = true; const bool find_files = false; const bool find_other = false; - FileSpec::EnumerateDirectory( + FileSystem::Instance().EnumerateDirectory( search_here_too.c_str(), find_directories, find_files, find_other, recurse ? GetKernelsAndKextsInDirectoryWithRecursion : GetKernelsAndKextsInDirectoryNoRecursion, baton); } - return FileSpec::eEnumerateDirectoryResultNext; + return FileSystem::eEnumerateDirectoryResultNext; } // Don't recurse into dSYM/kext/bundle directories if (recurse && file_spec_extension != g_dsym_suffix && @@ -561,9 +565,9 @@ PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( file_spec_extension != g_bundle_suffix) { if (log_verbose) log_verbose->Printf ("PlatformDarwinKernel descending into directory '%s'", file_spec.GetPath().c_str()); - return FileSpec::eEnumerateDirectoryResultEnter; + return FileSystem::eEnumerateDirectoryResultEnter; } else { - return FileSpec::eEnumerateDirectoryResultNext; + return FileSystem::eEnumerateDirectoryResultNext; } } @@ -610,7 +614,7 @@ bool PlatformDarwinKernel::KextHasdSYMSibling( std::string filename = dsym_fspec.GetFilename().AsCString(); filename += ".dSYM"; dsym_fspec.GetFilename() = ConstString(filename); - if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { + if (FileSystem::Instance().IsDirectory(dsym_fspec)) { return true; } // Should probably get the CFBundleExecutable here or call @@ -623,8 +627,9 @@ bool PlatformDarwinKernel::KextHasdSYMSibling( kext_bundle_filepath.GetPath() + "/Contents/MacOS/"; deep_bundle_str += executable_name.AsCString(); deep_bundle_str += ".dSYM"; - dsym_fspec.SetFile(deep_bundle_str, true, FileSpec::Style::native); - if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { + dsym_fspec.SetFile(deep_bundle_str, FileSpec::Style::native); + FileSystem::Instance().Resolve(dsym_fspec); + if (FileSystem::Instance().IsDirectory(dsym_fspec)) { return true; } @@ -633,11 +638,9 @@ bool PlatformDarwinKernel::KextHasdSYMSibling( std::string shallow_bundle_str = kext_bundle_filepath.GetPath() + "/"; shallow_bundle_str += executable_name.AsCString(); shallow_bundle_str += ".dSYM"; - dsym_fspec.SetFile(shallow_bundle_str, true, FileSpec::Style::native); - if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { - return true; - } - return false; + dsym_fspec.SetFile(shallow_bundle_str, FileSpec::Style::native); + FileSystem::Instance().Resolve(dsym_fspec); + return FileSystem::Instance().IsDirectory(dsym_fspec); } // Given a FileSpec of /dir/dir/mach.development.t7004 Return true if a dSYM @@ -648,10 +651,7 @@ bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) { std::string filename = kernel_binary.GetFilename().AsCString(); filename += ".dSYM"; kernel_dsym.GetFilename() = ConstString(filename); - if (llvm::sys::fs::is_directory(kernel_dsym.GetPath())) { - return true; - } - return false; + return FileSystem::Instance().IsDirectory(kernel_dsym); } Status PlatformDarwinKernel::GetSharedModule( @@ -710,11 +710,10 @@ Status PlatformDarwinKernel::GetSharedModule( } } - if (kext_bundle_id.compare("mach_kernel") == 0 && - module_spec.GetUUID().IsValid()) { + if (kext_bundle_id == "mach_kernel" && module_spec.GetUUID().IsValid()) { // First try all kernel binaries that have a dSYM next to them for (auto possible_kernel : m_kernel_binaries_with_dsyms) { - if (possible_kernel.Exists()) { + if (FileSystem::Instance().Exists(possible_kernel)) { ModuleSpec kern_spec(possible_kernel); kern_spec.GetUUID() = module_spec.GetUUID(); ModuleSP module_sp(new Module(kern_spec)); @@ -750,7 +749,7 @@ Status PlatformDarwinKernel::GetSharedModule( // Next try all kernel binaries that don't have a dSYM for (auto possible_kernel : m_kernel_binaries_without_dsyms) { - if (possible_kernel.Exists()) { + if (FileSystem::Instance().Exists(possible_kernel)) { ModuleSpec kern_spec(possible_kernel); kern_spec.GetUUID() = module_spec.GetUUID(); ModuleSP module_sp(new Module(kern_spec)); @@ -791,7 +790,7 @@ PlatformDarwinKernel::SearchForExecutablesRecursively(const std::string &dir) { break; if (llvm::sys::fs::is_regular_file(*status) && llvm::sys::fs::can_execute(it->path())) - executables.emplace_back(it->path(), false); + executables.emplace_back(it->path()); } return executables; } @@ -801,7 +800,7 @@ Status PlatformDarwinKernel::ExamineKextForMatchingUUID( const ArchSpec &arch, ModuleSP &exe_module_sp) { for (const auto &exe_file : SearchForExecutablesRecursively(kext_bundle_path.GetPath())) { - if (exe_file.Exists()) { + if (FileSystem::Instance().Exists(exe_file)) { ModuleSpec exe_spec(exe_file); exe_spec.GetUUID() = uuid; if (!uuid.IsValid()) { diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h index 7f603cac2bec..201c3dff1795 100644 --- a/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h +++ b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h @@ -15,14 +15,10 @@ #if defined(__APPLE__) // This Plugin uses the Mac-specific // source/Host/macosx/cfcpp utilities -// C Includes -// C++ Includes -// Other libraries and framework includes #include "lldb/Utility/FileSpec.h" #include "llvm/Support/FileSystem.h" -// Project includes #include "PlatformDarwin.h" class PlatformDarwinKernel : public PlatformDarwin { @@ -106,26 +102,25 @@ protected: void AddSDKSubdirsToSearchPaths(const std::string &dir); - static lldb_private::FileSpec::EnumerateDirectoryResult + static lldb_private::FileSystem::EnumerateDirectoryResult FindKDKandSDKDirectoriesInDirectory(void *baton, llvm::sys::fs::file_type ft, - const lldb_private::FileSpec &file_spec); + llvm::StringRef path); void SearchForKextsAndKernelsRecursively(); - static lldb_private::FileSpec::EnumerateDirectoryResult - GetKernelsAndKextsInDirectoryWithRecursion( - void *baton, llvm::sys::fs::file_type ft, - const lldb_private::FileSpec &file_spec); + static lldb_private::FileSystem::EnumerateDirectoryResult + GetKernelsAndKextsInDirectoryWithRecursion(void *baton, + llvm::sys::fs::file_type ft, + llvm::StringRef path); - static lldb_private::FileSpec::EnumerateDirectoryResult - GetKernelsAndKextsInDirectoryNoRecursion( - void *baton, llvm::sys::fs::file_type ft, - const lldb_private::FileSpec &file_spec); + static lldb_private::FileSystem::EnumerateDirectoryResult + GetKernelsAndKextsInDirectoryNoRecursion(void *baton, + llvm::sys::fs::file_type ft, + llvm::StringRef path); - static lldb_private::FileSpec::EnumerateDirectoryResult + static lldb_private::FileSystem::EnumerateDirectoryResult GetKernelsAndKextsInDirectoryHelper(void *baton, llvm::sys::fs::file_type ft, - const lldb_private::FileSpec &file_spec, - bool recurse); + llvm::StringRef path, bool recurse); static std::vector<lldb_private::FileSpec> SearchForExecutablesRecursively(const std::string &dir); @@ -148,7 +143,7 @@ protected: const lldb_private::ArchSpec &arch, lldb::ModuleSP &exe_module_sp); - // Most of the ivars are assembled under FileSpec::EnumerateDirectory calls + // Most of the ivars are assembled under FileSystem::EnumerateDirectory calls // where the // function being called for each file/directory must be static. We'll pass a // this pointer diff --git a/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp index 99f603b01f43..4117231c308a 100644 --- a/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp @@ -10,12 +10,9 @@ #include "PlatformMacOSX.h" #include "lldb/Host/Config.h" -// C++ Includes #include <sstream> -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" @@ -83,7 +80,7 @@ PlatformSP PlatformMacOSX::CreateInstance(bool force, const ArchSpec *arch) { const bool is_host = false; bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { const llvm::Triple &triple = arch->GetTriple(); switch (triple.getVendor()) { case llvm::Triple::Apple: @@ -93,7 +90,7 @@ PlatformSP PlatformMacOSX::CreateInstance(bool force, const ArchSpec *arch) { #if defined(__APPLE__) // Only accept "unknown" for vendor if the host is Apple and it "unknown" // wasn't specified (it was just returned because it was NOT specified) - case llvm::Triple::UnknownArch: + case llvm::Triple::UnknownVendor: create = !arch->TripleVendorWasSpecified(); break; #endif @@ -218,14 +215,14 @@ ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) { "SDKs/MacOSX%u.%u.sdk", xcode_contents_path.c_str(), versions[0], versions[1]); - fspec.SetFile(sdk_path.GetString(), false, FileSpec::Style::native); - if (fspec.Exists()) + fspec.SetFile(sdk_path.GetString(), FileSpec::Style::native); + if (FileSystem::Instance().Exists(fspec)) return ConstString(sdk_path.GetString()); } if (!default_xcode_sdk.empty()) { - fspec.SetFile(default_xcode_sdk, false, FileSpec::Style::native); - if (fspec.Exists()) + fspec.SetFile(default_xcode_sdk, FileSpec::Style::native); + if (FileSystem::Instance().Exists(fspec)) return ConstString(default_xcode_sdk); } } @@ -259,7 +256,7 @@ PlatformMacOSX::GetFileWithUUID(const lldb_private::FileSpec &platform_file, #endif std::string remote_os_build; m_remote_platform_sp->GetOSBuildString(remote_os_build); - if (local_os_build.compare(remote_os_build) == 0) { + if (local_os_build == remote_os_build) { // same OS version: the local file is good enough local_file = platform_file; return Status(); @@ -268,8 +265,8 @@ PlatformMacOSX::GetFileWithUUID(const lldb_private::FileSpec &platform_file, std::string cache_path(GetLocalCacheDirectory()); std::string module_path(platform_file.GetPath()); cache_path.append(module_path); - FileSpec module_cache_spec(cache_path, false); - if (module_cache_spec.Exists()) { + FileSpec module_cache_spec(cache_path); + if (FileSystem::Instance().Exists(module_cache_spec)) { local_file = module_cache_spec; return Status(); } @@ -284,7 +281,7 @@ PlatformMacOSX::GetFileWithUUID(const lldb_private::FileSpec &platform_file, err = GetFile(platform_file, module_cache_spec); if (err.Fail()) return err; - if (module_cache_spec.Exists()) { + if (FileSystem::Instance().Exists(module_cache_spec)) { local_file = module_cache_spec; return Status(); } else diff --git a/source/Plugins/Platform/MacOSX/PlatformMacOSX.h b/source/Plugins/Platform/MacOSX/PlatformMacOSX.h index d1e609258d4d..d08029a29f31 100644 --- a/source/Plugins/Platform/MacOSX/PlatformMacOSX.h +++ b/source/Plugins/Platform/MacOSX/PlatformMacOSX.h @@ -10,10 +10,6 @@ #ifndef liblldb_PlatformMacOSX_h_ #define liblldb_PlatformMacOSX_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "PlatformDarwin.h" class PlatformMacOSX : public PlatformDarwin { diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.cpp new file mode 100644 index 000000000000..fd804d0aaeed --- /dev/null +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.cpp @@ -0,0 +1,186 @@ +//===-- PlatformRemoteAppleBridge.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <string> +#include <vector> + +#include "PlatformRemoteAppleBridge.h" + +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/Host.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------ +/// Default Constructor +//------------------------------------------------------------------ +PlatformRemoteAppleBridge::PlatformRemoteAppleBridge() + : PlatformRemoteDarwinDevice () {} + +//------------------------------------------------------------------ +// Static Variables +//------------------------------------------------------------------ +static uint32_t g_initialize_count = 0; + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +void PlatformRemoteAppleBridge::Initialize() { + PlatformDarwin::Initialize(); + + if (g_initialize_count++ == 0) { + PluginManager::RegisterPlugin(PlatformRemoteAppleBridge::GetPluginNameStatic(), + PlatformRemoteAppleBridge::GetDescriptionStatic(), + PlatformRemoteAppleBridge::CreateInstance); + } +} + +void PlatformRemoteAppleBridge::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + PluginManager::UnregisterPlugin(PlatformRemoteAppleBridge::CreateInstance); + } + } + + PlatformDarwin::Terminate(); +} + +PlatformSP PlatformRemoteAppleBridge::CreateInstance(bool force, + const ArchSpec *arch) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + const char *arch_name; + if (arch && arch->GetArchitectureName()) + arch_name = arch->GetArchitectureName(); + else + arch_name = "<null>"; + + const char *triple_cstr = + arch ? arch->GetTriple().getTriple().c_str() : "<null>"; + + log->Printf("PlatformRemoteAppleBridge::%s(force=%s, arch={%s,%s})", + __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr); + } + + bool create = force; + if (!create && arch && arch->IsValid()) { + switch (arch->GetMachine()) { + case llvm::Triple::aarch64: { + const llvm::Triple &triple = arch->GetTriple(); + llvm::Triple::VendorType vendor = triple.getVendor(); + switch (vendor) { + case llvm::Triple::Apple: + create = true; + break; + +#if defined(__APPLE__) + // Only accept "unknown" for the vendor if the host is Apple and + // it "unknown" wasn't specified (it was just returned because it + // was NOT specified) + case llvm::Triple::UnknownVendor: + create = !arch->TripleVendorWasSpecified(); + break; + +#endif + default: + break; + } + if (create) { + switch (triple.getOS()) { + // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: + break; + + default: + create = false; + break; + } + } + } break; + default: + break; + } + } + + if (create) { + if (log) + log->Printf("PlatformRemoteAppleBridge::%s() creating platform", + __FUNCTION__); + + return lldb::PlatformSP(new PlatformRemoteAppleBridge()); + } + + if (log) + log->Printf("PlatformRemoteAppleBridge::%s() aborting creation of platform", + __FUNCTION__); + + return lldb::PlatformSP(); +} + +lldb_private::ConstString PlatformRemoteAppleBridge::GetPluginNameStatic() { + static ConstString g_name("remote-bridgeos"); + return g_name; +} + +const char *PlatformRemoteAppleBridge::GetDescriptionStatic() { + return "Remote BridgeOS platform plug-in."; +} + +bool PlatformRemoteAppleBridge::GetSupportedArchitectureAtIndex(uint32_t idx, + ArchSpec &arch) { + ArchSpec system_arch(GetSystemArchitecture()); + + const ArchSpec::Core system_core = system_arch.GetCore(); + switch (system_core) { + default: + switch (idx) { + case 0: + arch.SetTriple("arm64-apple-bridgeos"); + return true; + default: + break; + } + break; + + case ArchSpec::eCore_arm_arm64: + switch (idx) { + case 0: + arch.SetTriple("arm64-apple-bridgeos"); + return true; + default: + break; + } + break; + } + arch.Clear(); + return false; +} + + +void PlatformRemoteAppleBridge::GetDeviceSupportDirectoryNames (std::vector<std::string> &dirnames) +{ + dirnames.clear(); + dirnames.push_back("BridgeOS DeviceSupport"); +} + +std::string PlatformRemoteAppleBridge::GetPlatformName () +{ + return "BridgeOS.platform"; +} + diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.h b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.h new file mode 100644 index 000000000000..48f06eee3f01 --- /dev/null +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.h @@ -0,0 +1,73 @@ +//===-- PlatformRemoteAppleBridge.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_PlatformRemoteAppleBridge_h_ +#define liblldb_PlatformRemoteAppleBridge_h_ + +#include <string> + +#include "lldb/Utility/FileSpec.h" + +#include "llvm/Support/FileSystem.h" + +#include "PlatformRemoteDarwinDevice.h" + +class PlatformRemoteAppleBridge : public PlatformRemoteDarwinDevice { +public: + PlatformRemoteAppleBridge(); + + ~PlatformRemoteAppleBridge() override = default; + + //------------------------------------------------------------ + // Class Functions + //------------------------------------------------------------ + static lldb::PlatformSP CreateInstance(bool force, + const lldb_private::ArchSpec *arch); + + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static const char *GetDescriptionStatic(); + + //------------------------------------------------------------ + // lldb_private::PluginInterface functions + //------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override { + return GetPluginNameStatic(); + } + + uint32_t GetPluginVersion() override { return 1; } + + //------------------------------------------------------------ + // lldb_private::Platform functions + //------------------------------------------------------------ + + const char *GetDescription() override { return GetDescriptionStatic(); } + + bool GetSupportedArchitectureAtIndex(uint32_t idx, + lldb_private::ArchSpec &arch) override; + +protected: + + //------------------------------------------------------------ + // lldb_private::PlatformRemoteDarwinDevice functions + //------------------------------------------------------------ + + void GetDeviceSupportDirectoryNames (std::vector<std::string> &dirnames) override; + + std::string GetPlatformName () override; + +private: + DISALLOW_COPY_AND_ASSIGN(PlatformRemoteAppleBridge); +}; + +#endif // liblldb_PlatformRemoteAppleBridge_h_ diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp index be4c829a981c..593e888898c4 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp @@ -7,13 +7,9 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes #include <string> #include <vector> -// Other libraries and framework includes -// Project includes #include "PlatformRemoteAppleTV.h" #include "lldb/Breakpoint/BreakpointLocation.h" @@ -101,7 +97,7 @@ PlatformSP PlatformRemoteAppleTV::CreateInstance(bool force, // Only accept "unknown" for the vendor if the host is Apple and // "unknown" wasn't specified (it was just returned because it was NOT // specified) - case llvm::Triple::UnknownArch: + case llvm::Triple::UnknownVendor: create = !arch->TripleVendorWasSpecified(); break; diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h index 08dd231e85ee..d8860a90a460 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h @@ -10,12 +10,8 @@ #ifndef liblldb_PlatformRemoteAppleTV_h_ #define liblldb_PlatformRemoteAppleTV_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "lldb/Utility/FileSpec.h" #include "llvm/Support/FileSystem.h" diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp index 6159511d4a18..59e6e19fbffc 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp @@ -7,13 +7,9 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes #include <string> #include <vector> -// Other libraries and framework includes -// Project includes #include "PlatformRemoteAppleWatch.h" #include "lldb/Breakpoint/BreakpointLocation.h" @@ -96,7 +92,7 @@ PlatformSP PlatformRemoteAppleWatch::CreateInstance(bool force, // Only accept "unknown" for the vendor if the host is Apple and // "unknown" wasn't specified (it was just returned because it was NOT // specified) - case llvm::Triple::UnknownArch: + case llvm::Triple::UnknownVendor: create = !arch->TripleVendorWasSpecified(); break; diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h index 93be55b595f8..ed1cbea62e92 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h @@ -10,13 +10,9 @@ #ifndef liblldb_PlatformRemoteAppleWatch_h_ #define liblldb_PlatformRemoteAppleWatch_h_ -// C Includes -// C++ Includes #include <string> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Utility/FileSpec.h" #include "PlatformRemoteDarwinDevice.h" diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp index 930d062fe41e..511bfc20376b 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp @@ -9,15 +9,12 @@ #include "PlatformRemoteDarwinDevice.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -85,7 +82,7 @@ Status PlatformRemoteDarwinDevice::ResolveExecutable( // ourselves Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); - if (resolved_module_spec.GetFileSpec().Exists()) { + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid()) { error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, @@ -119,7 +116,7 @@ Status PlatformRemoteDarwinDevice::ResolveExecutable( } if (error.Fail() || !exe_module_sp) { - if (resolved_module_spec.GetFileSpec().Readable()) { + 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(), @@ -139,12 +136,12 @@ Status PlatformRemoteDarwinDevice::ResolveExecutable( return error; } -FileSpec::EnumerateDirectoryResult +FileSystem::EnumerateDirectoryResult PlatformRemoteDarwinDevice::GetContainedFilesIntoVectorOfStringsCallback( - void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { + void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) { ((PlatformRemoteDarwinDevice::SDKDirectoryInfoCollection *)baton) - ->push_back(PlatformRemoteDarwinDevice::SDKDirectoryInfo(file_spec)); - return FileSpec::eEnumerateDirectoryResultNext; + ->push_back(PlatformRemoteDarwinDevice::SDKDirectoryInfo(FileSpec(path))); + return FileSystem::eEnumerateDirectoryResultNext; } bool PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded() { @@ -153,7 +150,8 @@ bool PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded() { if (m_sdk_directory_infos.empty()) { // A --sysroot option was supplied - add it to our list of SDKs to check if (m_sdk_sysroot) { - FileSpec sdk_sysroot_fspec(m_sdk_sysroot.GetCString(), true); + FileSpec sdk_sysroot_fspec(m_sdk_sysroot.GetCString()); + FileSystem::Instance().Resolve(sdk_sysroot_fspec); const SDKDirectoryInfo sdk_sysroot_directory_info(sdk_sysroot_fspec); m_sdk_directory_infos.push_back(sdk_sysroot_directory_info); if (log) { @@ -175,10 +173,10 @@ bool PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded() { const bool find_other = false; SDKDirectoryInfoCollection builtin_sdk_directory_infos; - FileSpec::EnumerateDirectory(m_device_support_directory, find_directories, - find_files, find_other, - GetContainedFilesIntoVectorOfStringsCallback, - &builtin_sdk_directory_infos); + FileSystem::Instance().EnumerateDirectory( + m_device_support_directory, find_directories, find_files, find_other, + GetContainedFilesIntoVectorOfStringsCallback, + &builtin_sdk_directory_infos); // Only add SDK directories that have symbols in them, some SDKs only // contain developer disk images and no symbols, so they aren't useful to @@ -187,7 +185,7 @@ bool PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded() { for (const auto &sdk_directory_info : builtin_sdk_directory_infos) { sdk_symbols_symlink_fspec = sdk_directory_info.directory; sdk_symbols_symlink_fspec.AppendPathComponent("Symbols"); - if (sdk_symbols_symlink_fspec.Exists()) { + if (FileSystem::Instance().Exists(sdk_symbols_symlink_fspec)) { m_sdk_directory_infos.push_back(sdk_directory_info); if (log) { log->Printf("PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded " @@ -205,22 +203,23 @@ bool PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded() { const uint32_t num_installed = m_sdk_directory_infos.size(); std::string local_sdk_cache_str = "~/Library/Developer/Xcode/"; local_sdk_cache_str += dirname; - FileSpec local_sdk_cache(local_sdk_cache_str.c_str(), true); - if (local_sdk_cache.Exists()) { - if (log) { + FileSpec local_sdk_cache(local_sdk_cache_str.c_str()); + FileSystem::Instance().Resolve(local_sdk_cache); + if (FileSystem::Instance().Exists(local_sdk_cache)) { + if (log) { log->Printf("PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded " "searching %s for additional SDKs", local_sdk_cache.GetPath().c_str()); - } + } char path[PATH_MAX]; if (local_sdk_cache.GetPath(path, sizeof(path))) { - FileSpec::EnumerateDirectory( - path, find_directories, find_files, find_other, - GetContainedFilesIntoVectorOfStringsCallback, - &m_sdk_directory_infos); - const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); - // First try for an exact match of major, minor and update - for (uint32_t i = num_installed; i < num_sdk_infos; ++i) { + FileSystem::Instance().EnumerateDirectory( + path, find_directories, find_files, find_other, + GetContainedFilesIntoVectorOfStringsCallback, + &m_sdk_directory_infos); + const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); + // First try for an exact match of major, minor and update + for (uint32_t i = num_installed; i < num_sdk_infos; ++i) { m_sdk_directory_infos[i].user_cached = true; if (log) { log->Printf("PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded " @@ -231,6 +230,29 @@ bool PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded() { } } } + + const char *addtional_platform_dirs = getenv("PLATFORM_SDK_DIRECTORY"); + if (addtional_platform_dirs) { + SDKDirectoryInfoCollection env_var_sdk_directory_infos; + FileSystem::Instance().EnumerateDirectory( + addtional_platform_dirs, find_directories, find_files, find_other, + GetContainedFilesIntoVectorOfStringsCallback, + &env_var_sdk_directory_infos); + FileSpec sdk_symbols_symlink_fspec; + for (const auto &sdk_directory_info : env_var_sdk_directory_infos) { + sdk_symbols_symlink_fspec = sdk_directory_info.directory; + sdk_symbols_symlink_fspec.AppendPathComponent("Symbols"); + if (FileSystem::Instance().Exists(sdk_symbols_symlink_fspec)) { + m_sdk_directory_infos.push_back(sdk_directory_info); + if (log) { + log->Printf("PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded " + "added env var SDK directory %s", + sdk_symbols_symlink_fspec.GetPath().c_str()); + } + } + } + } + } } return !m_sdk_directory_infos.empty(); @@ -395,12 +417,12 @@ bool PlatformRemoteDarwinDevice::GetFileInSDK(const char *platform_file_path, const char *paths_to_try[] = {"Symbols", "", "Symbols.Internal", nullptr}; for (size_t i = 0; paths_to_try[i] != nullptr; i++) { - local_file.SetFile(sdkroot_path, false, FileSpec::Style::native); + local_file.SetFile(sdkroot_path, FileSpec::Style::native); if (paths_to_try[i][0] != '\0') local_file.AppendPathComponent(paths_to_try[i]); local_file.AppendPathComponent(platform_file_path); - local_file.ResolvePath(); - if (local_file.Exists()) { + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) { if (log) log->Printf("Found a copy of %s in the SDK dir %s/%s", platform_file_path, sdkroot_path.c_str(), @@ -428,8 +450,9 @@ Status PlatformRemoteDarwinDevice::GetSymbolFile(const FileSpec &platform_file, ::snprintf(resolved_path, sizeof(resolved_path), "%s/%s", os_version_dir, platform_file_path); - local_file.SetFile(resolved_path, true, FileSpec::Style::native); - if (local_file.Exists()) { + local_file.SetFile(resolved_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) { if (log) { log->Printf("Found a copy of %s in the DeviceSupport dir %s", platform_file_path, os_version_dir); @@ -440,8 +463,9 @@ Status PlatformRemoteDarwinDevice::GetSymbolFile(const FileSpec &platform_file, ::snprintf(resolved_path, sizeof(resolved_path), "%s/Symbols.Internal/%s", os_version_dir, platform_file_path); - local_file.SetFile(resolved_path, true, FileSpec::Style::native); - if (local_file.Exists()) { + local_file.SetFile(resolved_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) { if (log) { log->Printf( "Found a copy of %s in the DeviceSupport dir %s/Symbols.Internal", @@ -452,8 +476,9 @@ Status PlatformRemoteDarwinDevice::GetSymbolFile(const FileSpec &platform_file, ::snprintf(resolved_path, sizeof(resolved_path), "%s/Symbols/%s", os_version_dir, platform_file_path); - local_file.SetFile(resolved_path, true, FileSpec::Style::native); - if (local_file.Exists()) { + local_file.SetFile(resolved_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) { if (log) { log->Printf("Found a copy of %s in the DeviceSupport dir %s/Symbols", platform_file_path, os_version_dir); @@ -462,7 +487,7 @@ Status PlatformRemoteDarwinDevice::GetSymbolFile(const FileSpec &platform_file, } } local_file = platform_file; - if (local_file.Exists()) + if (FileSystem::Instance().Exists(local_file)) return error; error.SetErrorStringWithFormat( diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h b/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h index 8ddfd51600fd..d32179d6c98e 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h @@ -10,12 +10,8 @@ #ifndef liblldb_PlatformRemoteDarwinDevice_h_ #define liblldb_PlatformRemoteDarwinDevice_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "PlatformDarwin.h" #include "lldb/Utility/FileSpec.h" @@ -84,10 +80,10 @@ protected: const SDKDirectoryInfo *GetSDKDirectoryForCurrentOSVersion(); - static lldb_private::FileSpec::EnumerateDirectoryResult - GetContainedFilesIntoVectorOfStringsCallback( - void *baton, llvm::sys::fs::file_type ft, - const lldb_private::FileSpec &file_spec); + static lldb_private::FileSystem::EnumerateDirectoryResult + GetContainedFilesIntoVectorOfStringsCallback(void *baton, + llvm::sys::fs::file_type ft, + llvm::StringRef path); uint32_t FindFileInAllSDKs(const char *platform_file_path, lldb_private::FileSpecList &file_list); diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp index 150bfdbfc118..b69d7ea36abf 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp @@ -9,10 +9,6 @@ #include "PlatformRemoteiOS.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" @@ -75,7 +71,7 @@ PlatformSP PlatformRemoteiOS::CreateInstance(bool force, const ArchSpec *arch) { } bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { switch (arch->GetMachine()) { case llvm::Triple::arm: case llvm::Triple::aarch64: @@ -91,7 +87,7 @@ PlatformSP PlatformRemoteiOS::CreateInstance(bool force, const ArchSpec *arch) { // Only accept "unknown" for the vendor if the host is Apple and // "unknown" wasn't specified (it was just returned because it was NOT // specified) - case llvm::Triple::UnknownArch: + case llvm::Triple::UnknownVendor: create = !arch->TripleVendorWasSpecified(); break; diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h b/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h index 975f50b421f1..7e45dc3c2889 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h @@ -10,12 +10,8 @@ #ifndef liblldb_PlatformRemoteiOS_h_ #define liblldb_PlatformRemoteiOS_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "PlatformRemoteDarwinDevice.h" #include "lldb/Utility/FileSpec.h" diff --git a/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp index 26feec282322..b1d5960bb682 100644 --- a/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp @@ -10,10 +10,6 @@ #include "PlatformiOSSimulator.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" @@ -80,7 +76,7 @@ PlatformSP PlatformiOSSimulator::CreateInstance(bool force, } bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { switch (arch->GetMachine()) { case llvm::Triple::x86_64: case llvm::Triple::x86: { @@ -94,7 +90,7 @@ PlatformSP PlatformiOSSimulator::CreateInstance(bool force, // Only accept "unknown" for the vendor if the host is Apple and it // "unknown" wasn't specified (it was just returned because it was NOT // specified) - case llvm::Triple::UnknownArch: + case llvm::Triple::UnknownVendor: create = !arch->TripleVendorWasSpecified(); break; #endif @@ -196,7 +192,7 @@ Status PlatformiOSSimulator::ResolveExecutable( // ourselves Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); - if (resolved_module_spec.GetFileSpec().Exists()) { + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { if (resolved_module_spec.GetArchitecture().IsValid()) { error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, NULL, NULL, NULL); @@ -234,7 +230,7 @@ Status PlatformiOSSimulator::ResolveExecutable( } if (error.Fail() || !exe_module_sp) { - if (resolved_module_spec.GetFileSpec().Readable()) { + 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(), @@ -253,18 +249,19 @@ Status PlatformiOSSimulator::ResolveExecutable( return error; } -static FileSpec::EnumerateDirectoryResult +static FileSystem::EnumerateDirectoryResult EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft, - const FileSpec &file_spec) { + llvm::StringRef path) { if (ft == llvm::sys::fs::file_type::directory_file) { + FileSpec file_spec(path); const char *filename = file_spec.GetFilename().GetCString(); if (filename && strncmp(filename, "iPhoneSimulator", strlen("iPhoneSimulator")) == 0) { ::snprintf((char *)baton, PATH_MAX, "%s", filename); - return FileSpec::eEnumerateDirectoryResultQuit; + return FileSystem::eEnumerateDirectoryResultQuit; } } - return FileSpec::eEnumerateDirectoryResultNext; + return FileSystem::eEnumerateDirectoryResultNext; } const char *PlatformiOSSimulator::GetSDKDirectoryAsCString() { @@ -282,9 +279,9 @@ const char *PlatformiOSSimulator::GetSDKDirectoryAsCString() { bool find_directories = true; bool find_files = false; bool find_other = false; - FileSpec::EnumerateDirectory(sdks_directory, find_directories, find_files, - find_other, EnumerateDirectoryCallback, - sdk_dirname); + FileSystem::Instance().EnumerateDirectory( + sdks_directory, find_directories, find_files, find_other, + EnumerateDirectoryCallback, sdk_dirname); if (sdk_dirname[0]) { m_sdk_directory = sdks_directory; @@ -320,13 +317,15 @@ Status PlatformiOSSimulator::GetSymbolFile(const FileSpec &platform_file, platform_file_path); // First try in the SDK and see if the file is in there - local_file.SetFile(resolved_path, true, FileSpec::Style::native); - if (local_file.Exists()) + local_file.SetFile(resolved_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) return error; // Else fall back to the actual path itself - local_file.SetFile(platform_file_path, true, FileSpec::Style::native); - if (local_file.Exists()) + local_file.SetFile(platform_file_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) return error; } error.SetErrorStringWithFormat( diff --git a/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h b/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h index 2d81d6229f73..4ac43a4dde28 100644 --- a/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h +++ b/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h @@ -10,13 +10,9 @@ #ifndef liblldb_PlatformiOSSimulator_h_ #define liblldb_PlatformiOSSimulator_h_ -// C Includes -// C++ Includes #include <mutex> #include <string> -// Other libraries and framework includes -// Project includes #include "PlatformAppleSimulator.h" class PlatformiOSSimulator : public PlatformAppleSimulator { diff --git a/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h b/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h index 083e2d6c5687..bec35aaaf33b 100644 --- a/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h +++ b/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h @@ -11,19 +11,15 @@ #ifndef liblldb_PlatformiOSSimulatorCoreSimulatorSupport_h_ #define liblldb_PlatformiOSSimulatorCoreSimulatorSupport_h_ -// C Includes -// C++ Includes #include <functional> #include <ostream> #include <string> #include <vector> -// Other libraries and framework includes #ifdef __APPLE__ #include <objc/objc.h> #else typedef void *id; #endif -// Project includes #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/ConstString.h" diff --git a/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm b/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm index 4516a66ee8ca..a601e27dc8a1 100644 --- a/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm +++ b/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm @@ -409,7 +409,7 @@ static Status HandleFileAction(ProcessLaunchInfo &launch_info, // Check in case our file action open wants to open the slave const char *slave_path = launch_info.GetPTY().GetSlaveName(NULL, 0); if (slave_path) { - FileSpec slave_spec(slave_path, false); + FileSpec slave_spec(slave_path); if (file_spec == slave_spec) { int slave_fd = launch_info.GetPTY().GetSlaveFileDescriptor(); if (slave_fd == PseudoTerminal::invalid_fd) @@ -591,7 +591,7 @@ void CoreSimulatorSupport::DeviceSet::ForEach( std::function<bool(const Device &)> f) { const size_t n = GetNumDevices(); for (NSUInteger i = 0; i < n; ++i) { - if (f(GetDeviceAtIndex(i)) == false) + if (!f(GetDeviceAtIndex(i))) break; } } diff --git a/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp b/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp index 3aa8ecb4c228..aadcf961c729 100644 --- a/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp +++ b/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -10,23 +10,19 @@ #include "PlatformNetBSD.h" #include "lldb/Host/Config.h" -// C Includes #include <stdio.h> #ifndef LLDB_DISABLE_POSIX #include <sys/utsname.h> #endif -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" #include "lldb/Host/HostInfo.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" @@ -50,7 +46,7 @@ PlatformSP PlatformNetBSD::CreateInstance(bool force, const ArchSpec *arch) { arch ? arch->GetTriple().getTriple() : "<null>"); bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { const llvm::Triple &triple = arch->GetTriple(); switch (triple.getOS()) { case llvm::Triple::NetBSD: @@ -271,8 +267,8 @@ PlatformNetBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, if (target == nullptr) { LLDB_LOG(log, "creating new target"); TargetSP new_target_sp; - error = debugger.GetTargetList().CreateTarget(debugger, "", "", false, - nullptr, new_target_sp); + error = debugger.GetTargetList().CreateTarget( + debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); if (error.Fail()) { LLDB_LOG(log, "failed to create new target: {0}", error); return process_sp; @@ -291,8 +287,8 @@ PlatformNetBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, // Now create the gdb-remote process. LLDB_LOG(log, "having target create process with gdb-remote plugin"); - process_sp = target->CreateProcess( - launch_info.GetListenerForProcess(debugger), "gdb-remote", nullptr); + process_sp = + target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr); if (!process_sp) { error.SetErrorString("CreateProcess() failed for gdb-remote process"); diff --git a/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp b/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp index 10ca8fbfbdd7..7358acb61f79 100644 --- a/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp +++ b/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp @@ -10,23 +10,19 @@ #include "PlatformOpenBSD.h" #include "lldb/Host/Config.h" -// C Includes #include <stdio.h> #ifndef LLDB_DISABLE_POSIX #include <sys/utsname.h> #endif -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" #include "lldb/Host/HostInfo.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" @@ -50,7 +46,7 @@ PlatformSP PlatformOpenBSD::CreateInstance(bool force, const ArchSpec *arch) { arch ? arch->GetTriple().getTriple() : "<null>"); bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { const llvm::Triple &triple = arch->GetTriple(); switch (triple.getOS()) { case llvm::Triple::OpenBSD: diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index 5e7ffe71918e..bfa1376d3151 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -9,10 +9,6 @@ #include "PlatformPOSIX.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -128,23 +124,25 @@ PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec, if (IsHost()) { // If we have "ls" as the exe_file, resolve the executable location based // on the current path variables - if (!resolved_module_spec.GetFileSpec().Exists()) { + 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, true, + resolved_module_spec.GetFileSpec().SetFile(exe_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec()); } - if (!resolved_module_spec.GetFileSpec().Exists()) - resolved_module_spec.GetFileSpec().ResolveExecutableLocation(); + 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 (resolved_module_spec.GetFileSpec().Exists()) + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) error.Clear(); else { - const uint32_t permissions = - resolved_module_spec.GetFileSpec().GetPermissions(); + const uint32_t permissions = FileSystem::Instance().GetPermissions( + resolved_module_spec.GetFileSpec()); if (permissions && (permissions & eFilePermissionsEveryoneR) == 0) error.SetErrorStringWithFormat( "executable '%s' is not readable", @@ -166,7 +164,7 @@ PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec, // Resolve any executable within a bundle on MacOSX Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); - if (resolved_module_spec.GetFileSpec().Exists()) + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) error.Clear(); else error.SetErrorStringWithFormat("the platform is not currently " @@ -237,7 +235,8 @@ PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec, } if (error.Fail() || !exe_module_sp) { - if (resolved_module_spec.GetFileSpec().Readable()) { + 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(), @@ -455,7 +454,7 @@ lldb::user_id_t PlatformPOSIX::GetFileSize(const FileSpec &file_spec) { Status PlatformPOSIX::CreateSymlink(const FileSpec &src, const FileSpec &dst) { if (IsHost()) - return FileSystem::Symlink(src, dst); + return FileSystem::Instance().Symlink(src, dst); else if (m_remote_platform_sp) return m_remote_platform_sp->CreateSymlink(src, dst); else @@ -464,7 +463,7 @@ Status PlatformPOSIX::CreateSymlink(const FileSpec &src, const FileSpec &dst) { bool PlatformPOSIX::GetFileExists(const FileSpec &file_spec) { if (IsHost()) - return file_spec.Exists(); + return FileSystem::Instance().Exists(file_spec); else if (m_remote_platform_sp) return m_remote_platform_sp->GetFileExists(file_spec); else @@ -813,8 +812,8 @@ lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info, if (target == NULL) { TargetSP new_target_sp; - error = debugger.GetTargetList().CreateTarget(debugger, "", "", false, - NULL, new_target_sp); + error = debugger.GetTargetList().CreateTarget( + debugger, "", "", eLoadDependentsNo, NULL, new_target_sp); target = new_target_sp.get(); if (log) log->Printf("PlatformPOSIX::%s created new target", __FUNCTION__); @@ -1244,7 +1243,8 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, options.SetTrapExceptions(false); // dlopen can't throw exceptions, so // don't do the work to trap them. options.SetTimeout(std::chrono::seconds(2)); - + options.SetIsForUtilityExpr(true); + Value return_value; // Fetch the clang types we will need: ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); @@ -1281,8 +1281,7 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, std::string name_string; process->ReadCStringFromMemory(buffer_addr, name_string, utility_error); if (utility_error.Success()) - loaded_image->SetFile(name_string, false, - llvm::sys::path::Style::posix); + loaded_image->SetFile(name_string, llvm::sys::path::Style::posix); } return process->AddImageToken(token); } diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h index cc6f7299c194..97333ef1eb7c 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -10,13 +10,9 @@ #ifndef liblldb_PlatformPOSIX_h_ #define liblldb_PlatformPOSIX_h_ -// C Includes -// C++ Includes #include <map> #include <memory> -// Other libraries and framework includes -// Project includes #include "lldb/Interpreter/Options.h" #include "lldb/Target/Platform.h" diff --git a/source/Plugins/Platform/Windows/PlatformWindows.cpp b/source/Plugins/Platform/Windows/PlatformWindows.cpp index 45e906f88e00..685d49a73a77 100644 --- a/source/Plugins/Platform/Windows/PlatformWindows.cpp +++ b/source/Plugins/Platform/Windows/PlatformWindows.cpp @@ -9,16 +9,12 @@ #include "PlatformWindows.h" -// C Includes #include <stdio.h> #if defined(_WIN32) #include "lldb/Host/windows/windows.h" #include <winsock2.h> #endif -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/BreakpointSite.h" #include "lldb/Core/Debugger.h" @@ -71,7 +67,7 @@ PlatformSP PlatformWindows::CreateInstance(bool force, const bool is_host = false; bool create = force; - if (create == false && arch && arch->IsValid()) { + if (!create && arch && arch->IsValid()) { const llvm::Triple &triple = arch->GetTriple(); switch (triple.getVendor()) { case llvm::Triple::PC: @@ -192,16 +188,18 @@ Status PlatformWindows::ResolveExecutable( if (IsHost()) { // if we cant resolve the executable loation based on the current path // variables - if (!resolved_module_spec.GetFileSpec().Exists()) { + 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, true, + resolved_module_spec.GetFileSpec().SetFile(exe_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec()); } - if (!resolved_module_spec.GetFileSpec().Exists()) - resolved_module_spec.GetFileSpec().ResolveExecutableLocation(); + if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) + FileSystem::Instance().ResolveExecutableLocation( + resolved_module_spec.GetFileSpec()); - if (resolved_module_spec.GetFileSpec().Exists()) + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) error.Clear(); else { ms.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); @@ -215,7 +213,7 @@ Status PlatformWindows::ResolveExecutable( } else { // We may connect to a process and use the provided executable (Don't use // local $PATH). - if (resolved_module_spec.GetFileSpec().Exists()) + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) error.Clear(); else error.SetErrorStringWithFormat("the platform is not currently " @@ -262,7 +260,8 @@ Status PlatformWindows::ResolveExecutable( } if (error.Fail() || !exe_module_sp) { - if (resolved_module_spec.GetFileSpec().Readable()) { + 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(), @@ -438,9 +437,8 @@ ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, ProcessAttachInfo attach_info(launch_info); return Attach(attach_info, debugger, target, error); } else { - ProcessSP process_sp = - target->CreateProcess(launch_info.GetListenerForProcess(debugger), - launch_info.GetProcessPluginName(), nullptr); + ProcessSP process_sp = target->CreateProcess( + launch_info.GetListener(), launch_info.GetProcessPluginName(), nullptr); // We need to launch and attach to the process. launch_info.GetFlags().Set(eLaunchFlagDebug); @@ -470,8 +468,8 @@ lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info, FileSpec emptyFileSpec; ArchSpec emptyArchSpec; - error = debugger.GetTargetList().CreateTarget(debugger, "", "", false, - nullptr, new_target_sp); + error = debugger.GetTargetList().CreateTarget( + debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); target = new_target_sp.get(); } diff --git a/source/Plugins/Platform/Windows/PlatformWindows.h b/source/Plugins/Platform/Windows/PlatformWindows.h index 3a15271c5762..f7f55049e4e7 100644 --- a/source/Plugins/Platform/Windows/PlatformWindows.h +++ b/source/Plugins/Platform/Windows/PlatformWindows.h @@ -10,10 +10,6 @@ #ifndef liblldb_PlatformWindows_h_ #define liblldb_PlatformWindows_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/Platform.h" namespace lldb_private { diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 348bb825a5c5..f6ace706ca3f 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -10,9 +10,6 @@ #include "PlatformRemoteGDBServer.h" #include "lldb/Host/Config.h" -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -43,7 +40,7 @@ static bool g_initialized = false; void PlatformRemoteGDBServer::Initialize() { Platform::Initialize(); - if (g_initialized == false) { + if (!g_initialized) { g_initialized = true; PluginManager::RegisterPlugin( PlatformRemoteGDBServer::GetPluginNameStatic(), @@ -107,7 +104,7 @@ Status PlatformRemoteGDBServer::ResolveExecutable( // Resolve any executable within an apk on Android? // Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec()); - if (resolved_module_spec.GetFileSpec().Exists() || + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()) || module_spec.GetUUID().IsValid()) { if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid()) { @@ -142,7 +139,7 @@ Status PlatformRemoteGDBServer::ResolveExecutable( } if (error.Fail() || !exe_module_sp) { - if (resolved_module_spec.GetFileSpec().Readable()) { + 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(), @@ -488,8 +485,8 @@ lldb::ProcessSP PlatformRemoteGDBServer::DebugProcess( if (target == NULL) { TargetSP new_target_sp; - error = debugger.GetTargetList().CreateTarget(debugger, "", "", false, - NULL, new_target_sp); + error = debugger.GetTargetList().CreateTarget( + debugger, "", "", eLoadDependentsNo, NULL, new_target_sp); target = new_target_sp.get(); } else error.Clear(); @@ -499,8 +496,8 @@ lldb::ProcessSP PlatformRemoteGDBServer::DebugProcess( // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! - process_sp = target->CreateProcess( - launch_info.GetListenerForProcess(debugger), "gdb-remote", NULL); + process_sp = target->CreateProcess(launch_info.GetListener(), + "gdb-remote", NULL); if (process_sp) { error = process_sp->ConnectRemote(nullptr, connect_url.c_str()); @@ -574,8 +571,8 @@ lldb::ProcessSP PlatformRemoteGDBServer::Attach( if (target == NULL) { TargetSP new_target_sp; - error = debugger.GetTargetList().CreateTarget(debugger, "", "", false, - NULL, new_target_sp); + error = debugger.GetTargetList().CreateTarget( + debugger, "", "", eLoadDependentsNo, NULL, new_target_sp); target = new_target_sp.get(); } else error.Clear(); diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index a31933b5d9b0..7abb33423bc1 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -11,12 +11,8 @@ #ifndef liblldb_PlatformRemoteGDBServer_h_ #define liblldb_PlatformRemoteGDBServer_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" #include "lldb/Target/Platform.h" diff --git a/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp b/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp index 3505443abcb0..70d9a5248fd9 100644 --- a/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp +++ b/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp @@ -19,10 +19,10 @@ // C++ includes // LLDB includes -#include "lldb/Core/State.h" #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" @@ -63,12 +63,13 @@ Status NativeProcessProtocol::Launch( // Verify the working directory is valid if one was specified. FileSpec working_dir(launch_info.GetWorkingDirectory()); - if (working_dir && - (!working_dir.ResolvePath() || - !llvm::sys::fs::is_directory(working_dir.GetPath())) { - error.SetErrorStringWithFormat("No such file or directory: %s", + 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; + return error; + } } // Launch the inferior. diff --git a/source/Plugins/Process/Darwin/NativeProcessDarwin.h b/source/Plugins/Process/Darwin/NativeProcessDarwin.h index 0b186fd7d80c..9abdd5360eba 100644 --- a/source/Plugins/Process/Darwin/NativeProcessDarwin.h +++ b/source/Plugins/Process/Darwin/NativeProcessDarwin.h @@ -21,7 +21,6 @@ #include <mutex> #include <unordered_set> -// Other libraries and framework includes #include "lldb/Host/Debug.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/Pipe.h" diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp index 3576a7f26f86..fce0be22678e 100644 --- a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes #include <errno.h> #include <pthread.h> #include <pthread_np.h> @@ -16,12 +15,9 @@ #include <sys/types.h> #include <sys/user.h> -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/State.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/State.h" -// Project includes #include "FreeBSDThread.h" #include "POSIXStopInfo.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" @@ -42,7 +38,6 @@ #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Debugger.h" -#include "lldb/Core/State.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/HostNativeThread.h" @@ -50,6 +45,7 @@ #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadSpec.h" +#include "lldb/Utility/State.h" #include "llvm/ADT/SmallString.h" using namespace lldb; diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.h b/source/Plugins/Process/FreeBSD/FreeBSDThread.h index c93cc4fbfd73..a8559fe8b2ca 100644 --- a/source/Plugins/Process/FreeBSD/FreeBSDThread.h +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.h @@ -10,11 +10,9 @@ #ifndef liblldb_FreeBSDThread_H_ #define liblldb_FreeBSDThread_H_ -// C++ Includes #include <memory> #include <string> -// Other libraries and framework includes #include "RegisterContextPOSIX.h" #include "lldb/Target/Thread.h" diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index fa0bcea8f6bd..a13d4bcc4ecb 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -8,7 +8,6 @@ // //===----------------------------------------------------------------------===// -// C Includes #include <errno.h> #include <pthread.h> #include <pthread_np.h> @@ -18,18 +17,17 @@ #include <sys/user.h> #include <machine/elf.h> -// C++ Includes #include <mutex> #include <unordered_map> -// Other libraries and framework includes #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/State.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" #include "FreeBSDThread.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" @@ -38,13 +36,11 @@ #include "ProcessFreeBSD.h" #include "ProcessMonitor.h" -// Other libraries and framework includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/DynamicLoader.h" @@ -52,6 +48,7 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/State.h" #include "lldb/Host/posix/Fcntl.h" @@ -287,7 +284,7 @@ bool ProcessFreeBSD::CanDebug(lldb::TargetSP target_sp, // For now we are just making sure the file exists for a given module ModuleSP exe_module_sp(target_sp->GetExecutableModule()); if (exe_module_sp.get()) - return exe_module_sp->GetFileSpec().Exists(); + return FileSystem::Instance().Exists(exe_module_sp->GetFileSpec()); // If there is no executable module, we return true since we might be // preparing to attach. return true; @@ -335,7 +332,7 @@ ProcessFreeBSD::DoAttachToProcessWithID(lldb::pid_t pid, GetTarget().SetArchitecture(module_arch); // Initialize the target module list - GetTarget().SetExecutableModule(exe_module_sp, true); + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsYes); SetSTDIOFileDescriptor(m_monitor->GetTerminalFD()); @@ -373,12 +370,13 @@ Status ProcessFreeBSD::DoLaunch(Module *module, assert(m_monitor == NULL); FileSpec working_dir = launch_info.GetWorkingDirectory(); - namespace fs = llvm::sys::fs; - if (working_dir && (!working_dir.ResolvePath() || - !fs::is_directory(working_dir.GetPath()))) { - error.SetErrorStringWithFormat("No such file or directory: %s", + if (working_dir) { + FileSystem::Instance().Resolve(working_dir); + if (!FileSystem::Instance().IsDirectory(working_dir.GetPath())) { + error.SetErrorStringWithFormat("No such file or directory: %s", working_dir.GetCString()); - return error; + return error; + } } SetPrivateState(eStateLaunching); @@ -390,8 +388,7 @@ 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), - false}; + const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL, 0)}; file_action = launch_info.GetFileActionForFD(STDIN_FILENO); stdin_file_spec = @@ -519,7 +516,7 @@ void ProcessFreeBSD::DoDidExec() { executable_search_paths.GetSize() ? &executable_search_paths : NULL); if (!error.Success()) return; - target->SetExecutableModule(exe_module_sp, true); + target->SetExecutableModule(exe_module_sp, eLoadDependentsYes); } } } diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 51fdf2e5ef33..617ae3030f10 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes #include <errno.h> #include <poll.h> #include <signal.h> @@ -19,16 +18,14 @@ #include <sys/wait.h> #include <unistd.h> -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Host/Host.h" #include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" #include "llvm/Support/Errno.h" diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 1d3e2d746fa9..ca7c4e03966c 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -10,14 +10,11 @@ #ifndef liblldb_ProcessMonitor_H_ #define liblldb_ProcessMonitor_H_ -// C Includes #include <semaphore.h> #include <signal.h> -// C++ Includes #include <mutex> -// Other libraries and framework includes #include "lldb/Host/HostThread.h" #include "lldb/Utility/FileSpec.h" #include "lldb/lldb-types.h" diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h index b1b44e71de46..32973abd9207 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h @@ -10,9 +10,6 @@ #ifndef liblldb_RegisterContextPOSIX_H_ #define liblldb_RegisterContextPOSIX_H_ -// C Includes -// C++ Includes -// Other libraries and framework includes #include "Plugins/Process/Utility/RegisterInfoInterface.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/ArchSpec.h" diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp index 8ddc253aea5d..0642a30ade70 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp @@ -7,9 +7,9 @@ // //===---------------------------------------------------------------------===// -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" #include "ProcessFreeBSD.h" #include "ProcessMonitor.h" diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp index 93ffeb5ea79b..b35ee18d6a96 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp @@ -7,9 +7,9 @@ // //===---------------------------------------------------------------------===// -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" #include "ProcessFreeBSD.h" diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp index 734167e1fc98..17df44cf85ee 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" #include "ProcessFreeBSD.h" diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp index 5cc6cd290629..a8d75963ea6b 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" #include "ProcessFreeBSD.h" #include "ProcessMonitor.h" diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp index 7db7f803b371..68fd5ac13bb0 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" #include "Plugins/Process/FreeBSD/ProcessFreeBSD.h" #include "Plugins/Process/FreeBSD/ProcessMonitor.h" diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp index 3fb886e1c7a3..8c6c95380e81 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -9,29 +9,23 @@ #include "NativeProcessLinux.h" -// C Includes #include <errno.h> #include <stdint.h> #include <string.h> #include <unistd.h> -// C++ Includes #include <fstream> #include <mutex> #include <sstream> #include <string> #include <unordered_map> -// Other libraries and framework includes #include "lldb/Core/EmulateInstruction.h" #include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/State.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostProcess.h" #include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/common/NativeBreakpoint.h" #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/linux/Ptrace.h" #include "lldb/Host/linux/Uio.h" @@ -41,6 +35,8 @@ #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Target/Target.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StringExtractor.h" #include "llvm/Support/Errno.h" @@ -49,6 +45,7 @@ #include "NativeThreadLinux.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/LinuxProcMaps.h" #include "Procfs.h" #include <linux/unistd.h> @@ -759,9 +756,7 @@ void NativeProcessLinux::MonitorBreakpoint(NativeThreadLinux &thread) { // Mark the thread as stopped at breakpoint. thread.SetStoppedByBreakpoint(); - Status error = FixupBreakpointPCAsNeeded(thread); - if (error.Fail()) - LLDB_LOG(log, "pid = {0} fixup: {1}", thread.GetID(), error); + FixupBreakpointPCAsNeeded(thread); if (m_threads_stepping_with_breakpoint.find(thread.GetID()) != m_threads_stepping_with_breakpoint.end()) @@ -1238,90 +1233,6 @@ Status NativeProcessLinux::Kill() { return error; } -static Status -ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef &maps_line, - MemoryRegionInfo &memory_region_info) { - memory_region_info.Clear(); - - StringExtractor line_extractor(maps_line); - - // Format: {address_start_hex}-{address_end_hex} perms offset dev inode - // pathname perms: rwxp (letter is present if set, '-' if not, final - // character is p=private, s=shared). - - // Parse out the starting address - lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0); - - // Parse out hyphen separating start and end address from range. - if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-')) - return Status( - "malformed /proc/{pid}/maps entry, missing dash between address range"); - - // Parse out the ending address - lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address); - - // Parse out the space after the address. - if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' ')) - return Status( - "malformed /proc/{pid}/maps entry, missing space after range"); - - // Save the range. - memory_region_info.GetRange().SetRangeBase(start_address); - memory_region_info.GetRange().SetRangeEnd(end_address); - - // Any memory region in /proc/{pid}/maps is by definition mapped into the - // process. - memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); - - // Parse out each permission entry. - if (line_extractor.GetBytesLeft() < 4) - return Status("malformed /proc/{pid}/maps entry, missing some portion of " - "permissions"); - - // Handle read permission. - const char read_perm_char = line_extractor.GetChar(); - if (read_perm_char == 'r') - memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes); - else if (read_perm_char == '-') - memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); - else - return Status("unexpected /proc/{pid}/maps read permission char"); - - // Handle write permission. - const char write_perm_char = line_extractor.GetChar(); - if (write_perm_char == 'w') - memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes); - else if (write_perm_char == '-') - memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); - else - return Status("unexpected /proc/{pid}/maps write permission char"); - - // Handle execute permission. - const char exec_perm_char = line_extractor.GetChar(); - if (exec_perm_char == 'x') - memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); - else if (exec_perm_char == '-') - memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); - else - return Status("unexpected /proc/{pid}/maps exec permission char"); - - line_extractor.GetChar(); // Read the private bit - line_extractor.SkipSpaces(); // Skip the separator - line_extractor.GetHexMaxU64(false, 0); // Read the offset - line_extractor.GetHexMaxU64(false, 0); // Read the major device number - line_extractor.GetChar(); // Read the device id separator - line_extractor.GetHexMaxU64(false, 0); // Read the major device number - line_extractor.SkipSpaces(); // Skip the separator - line_extractor.GetU64(0, 10); // Read the inode number - - line_extractor.SkipSpaces(); - const char *name = line_extractor.Peek(); - if (name) - memory_region_info.SetName(name); - - return Status(); -} - Status NativeProcessLinux::GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info) { // FIXME review that the final memory region returned extends to the end of @@ -1407,22 +1318,23 @@ Status NativeProcessLinux::PopulateMemoryRegionCache() { m_supports_mem_region = LazyBool::eLazyBoolNo; return BufferOrError.getError(); } - StringRef Rest = BufferOrError.get()->getBuffer(); - while (! Rest.empty()) { - StringRef Line; - std::tie(Line, Rest) = Rest.split('\n'); - MemoryRegionInfo info; - const Status parse_error = - ParseMemoryRegionInfoFromProcMapsLine(Line, info); - if (parse_error.Fail()) { - LLDB_LOG(log, "failed to parse proc maps line '{0}': {1}", Line, - parse_error); - m_supports_mem_region = LazyBool::eLazyBoolNo; - return parse_error; - } - m_mem_region_cache.emplace_back( - info, FileSpec(info.GetName().GetCString(), true)); - } + Status Result; + ParseLinuxMapRegions(BufferOrError.get()->getBuffer(), + [&](const MemoryRegionInfo &Info, const Status &ST) { + if (ST.Success()) { + FileSpec file_spec(Info.GetName().GetCString()); + FileSystem::Instance().Resolve(file_spec); + m_mem_region_cache.emplace_back(Info, file_spec); + return true; + } else { + m_supports_mem_region = LazyBool::eLazyBoolNo; + LLDB_LOG(log, "failed to parse proc maps: {0}", ST); + Result = ST; + return false; + } + }); + if (Result.Fail()) + return Result; if (m_mem_region_cache.empty()) { // No entries after attempting to read them. This shouldn't happen if @@ -1502,40 +1414,6 @@ size_t NativeProcessLinux::UpdateThreads() { return m_threads.size(); } -Status NativeProcessLinux::GetSoftwareBreakpointPCOffset( - uint32_t &actual_opcode_size) { - // FIXME put this behind a breakpoint protocol class that can be - // set per architecture. Need ARM, MIPS support here. - static const uint8_t g_i386_opcode[] = {0xCC}; - static const uint8_t g_s390x_opcode[] = {0x00, 0x01}; - - switch (m_arch.GetMachine()) { - case llvm::Triple::x86: - case llvm::Triple::x86_64: - actual_opcode_size = static_cast<uint32_t>(sizeof(g_i386_opcode)); - return Status(); - - case llvm::Triple::systemz: - actual_opcode_size = static_cast<uint32_t>(sizeof(g_s390x_opcode)); - return Status(); - - case llvm::Triple::arm: - case llvm::Triple::aarch64: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::ppc64le: - // On these architectures the PC don't get updated for breakpoint hits - actual_opcode_size = 0; - return Status(); - - default: - assert(false && "CPU type not supported!"); - return Status("CPU type not supported"); - } -} - Status NativeProcessLinux::SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) { if (hardware) @@ -1551,74 +1429,26 @@ Status NativeProcessLinux::RemoveBreakpoint(lldb::addr_t addr, bool hardware) { return NativeProcessProtocol::RemoveBreakpoint(addr); } -Status NativeProcessLinux::GetSoftwareBreakpointTrapOpcode( - size_t trap_opcode_size_hint, size_t &actual_opcode_size, - const uint8_t *&trap_opcode_bytes) { - // FIXME put this behind a breakpoint protocol class that can be set per - // architecture. Need MIPS support here. - static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4}; +llvm::Expected<llvm::ArrayRef<uint8_t>> +NativeProcessLinux::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the // linux kernel does otherwise. - static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; - static const uint8_t g_i386_opcode[] = {0xCC}; - static const uint8_t g_mips64_opcode[] = {0x00, 0x00, 0x00, 0x0d}; - static const uint8_t g_mips64el_opcode[] = {0x0d, 0x00, 0x00, 0x00}; - static const uint8_t g_s390x_opcode[] = {0x00, 0x01}; - static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde}; - static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap - - switch (m_arch.GetMachine()) { - case llvm::Triple::aarch64: - trap_opcode_bytes = g_aarch64_opcode; - actual_opcode_size = sizeof(g_aarch64_opcode); - return Status(); + static const uint8_t g_arm_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; + static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; + switch (GetArchitecture().GetMachine()) { case llvm::Triple::arm: - switch (trap_opcode_size_hint) { + switch (size_hint) { case 2: - trap_opcode_bytes = g_thumb_breakpoint_opcode; - actual_opcode_size = sizeof(g_thumb_breakpoint_opcode); - return Status(); + return llvm::makeArrayRef(g_thumb_opcode); case 4: - trap_opcode_bytes = g_arm_breakpoint_opcode; - actual_opcode_size = sizeof(g_arm_breakpoint_opcode); - return Status(); + return llvm::makeArrayRef(g_arm_opcode); default: - assert(false && "Unrecognised trap opcode size hint!"); - return Status("Unrecognised trap opcode size hint!"); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unrecognised trap opcode size hint!"); } - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - trap_opcode_bytes = g_i386_opcode; - actual_opcode_size = sizeof(g_i386_opcode); - return Status(); - - case llvm::Triple::mips: - case llvm::Triple::mips64: - trap_opcode_bytes = g_mips64_opcode; - actual_opcode_size = sizeof(g_mips64_opcode); - return Status(); - - case llvm::Triple::mipsel: - case llvm::Triple::mips64el: - trap_opcode_bytes = g_mips64el_opcode; - actual_opcode_size = sizeof(g_mips64el_opcode); - return Status(); - - case llvm::Triple::systemz: - trap_opcode_bytes = g_s390x_opcode; - actual_opcode_size = sizeof(g_s390x_opcode); - return Status(); - - case llvm::Triple::ppc64le: - trap_opcode_bytes = g_ppc64le_opcode; - actual_opcode_size = sizeof(g_ppc64le_opcode); - return Status(); - default: - assert(false && "CPU type not supported!"); - return Status("CPU type not supported"); + return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); } } @@ -1677,15 +1507,6 @@ Status NativeProcessLinux::ReadMemory(lldb::addr_t addr, void *buf, size_t size, return Status(); } -Status NativeProcessLinux::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, - size_t size, - size_t &bytes_read) { - Status error = ReadMemory(addr, buf, size, bytes_read); - if (error.Fail()) - return error; - return m_breakpoint_list.RemoveTrapsFromBuffer(addr, buf, size); -} - Status NativeProcessLinux::WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) { const unsigned char *src = static_cast<const unsigned char *>(buf); @@ -1810,90 +1631,14 @@ NativeThreadLinux &NativeProcessLinux::AddThread(lldb::tid_t thread_id) { return static_cast<NativeThreadLinux &>(*m_threads.back()); } -Status -NativeProcessLinux::FixupBreakpointPCAsNeeded(NativeThreadLinux &thread) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - - Status error; - - // Find out the size of a breakpoint (might depend on where we are in the - // code). - NativeRegisterContext &context = thread.GetRegisterContext(); - - uint32_t breakpoint_size = 0; - error = GetSoftwareBreakpointPCOffset(breakpoint_size); - if (error.Fail()) { - LLDB_LOG(log, "GetBreakpointSize() failed: {0}", error); - return error; - } else - LLDB_LOG(log, "breakpoint size: {0}", breakpoint_size); - - // First try probing for a breakpoint at a software breakpoint location: PC - - // breakpoint size. - const lldb::addr_t initial_pc_addr = context.GetPCfromBreakpointLocation(); - lldb::addr_t breakpoint_addr = initial_pc_addr; - if (breakpoint_size > 0) { - // Do not allow breakpoint probe to wrap around. - if (breakpoint_addr >= breakpoint_size) - breakpoint_addr -= breakpoint_size; - } - - // Check if we stopped because of a breakpoint. - NativeBreakpointSP breakpoint_sp; - error = m_breakpoint_list.GetBreakpoint(breakpoint_addr, breakpoint_sp); - if (!error.Success() || !breakpoint_sp) { - // We didn't find one at a software probe location. Nothing to do. - LLDB_LOG(log, - "pid {0} no lldb breakpoint found at current pc with " - "adjustment: {1}", - GetID(), breakpoint_addr); - return Status(); - } - - // If the breakpoint is not a software breakpoint, nothing to do. - if (!breakpoint_sp->IsSoftwareBreakpoint()) { - LLDB_LOG( - log, - "pid {0} breakpoint found at {1:x}, not software, nothing to adjust", - GetID(), breakpoint_addr); - return Status(); - } - - // - // We have a software breakpoint and need to adjust the PC. - // - - // Sanity check. - if (breakpoint_size == 0) { - // Nothing to do! How did we get here? - LLDB_LOG(log, - "pid {0} breakpoint found at {1:x}, it is software, but the " - "size is zero, nothing to do (unexpected)", - GetID(), breakpoint_addr); - return Status(); - } - - // Change the program counter. - LLDB_LOG(log, "pid {0} tid {1}: changing PC from {2:x} to {3:x}", GetID(), - thread.GetID(), initial_pc_addr, breakpoint_addr); - - error = context.SetPC(breakpoint_addr); - if (error.Fail()) { - LLDB_LOG(log, "pid {0} tid {1}: failed to set PC: {2}", GetID(), - thread.GetID(), error); - return error; - } - - return error; -} - Status NativeProcessLinux::GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) { Status error = PopulateMemoryRegionCache(); if (error.Fail()) return error; - FileSpec module_file_spec(module_path, true); + FileSpec module_file_spec(module_path); + FileSystem::Instance().Resolve(module_file_spec); file_spec.Clear(); for (const auto &it : m_mem_region_cache) { @@ -1913,7 +1658,7 @@ Status NativeProcessLinux::GetFileLoadAddress(const llvm::StringRef &file_name, if (error.Fail()) return error; - FileSpec file(file_name, false); + FileSpec file(file_name); for (const auto &it : m_mem_region_cache) { if (it.second == file) { load_addr = it.first.GetRange().GetRangeBase(); diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.h b/source/Plugins/Process/Linux/NativeProcessLinux.h index 1c2f786e8d69..69f2b528d330 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -71,9 +71,6 @@ public: 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; @@ -134,13 +131,8 @@ public: 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; + llvm::Expected<llvm::ArrayRef<uint8_t>> + GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; private: MainLoop::SignalHandleUP m_sigchld_handle; @@ -190,10 +182,6 @@ private: NativeThreadLinux &AddThread(lldb::tid_t thread_id); - Status GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size); - - Status FixupBreakpointPCAsNeeded(NativeThreadLinux &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); diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp index c8a8355f9cb9..79f635c88985 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -9,10 +9,10 @@ #include "NativeRegisterContextLinux.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/common/NativeThreadProtocol.h" #include "lldb/Host/linux/Ptrace.h" +#include "lldb/Utility/RegisterValue.h" #include "Plugins/Process/Linux/NativeProcessLinux.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp index 749291684620..09d3a12942f0 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -15,9 +15,9 @@ #include "Plugins/Process/Linux/Procfs.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include <elf.h> diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index 41fe446f728c..9a392edbe9ef 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -12,14 +12,11 @@ #include "NativeRegisterContextLinux_arm.h" #include "NativeRegisterContextLinux_arm64.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "Plugins/Process/Linux/NativeProcessLinux.h" diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp index 69194b3c0663..d641056a0440 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -11,22 +11,19 @@ #include "NativeRegisterContextLinux_mips64.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "Plugins/Process/Linux/NativeProcessLinux.h" #include "Plugins/Process/Linux/Procfs.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #include "Plugins/Process/Utility/RegisterContextLinux_mips.h" #include "Plugins/Process/Utility/RegisterContextLinux_mips64.h" #include "lldb/Core/EmulateInstruction.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-private-enumerations.h" diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp index 6aa4af64ab51..da51fda1c80b 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp @@ -14,10 +14,10 @@ #include "NativeRegisterContextLinux_ppc64le.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "Plugins/Process/Linux/NativeProcessLinux.h" diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp index 36da2b001054..1bc916b69bcd 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp @@ -11,10 +11,10 @@ #include "NativeRegisterContextLinux_s390x.h" #include "Plugins/Process/Linux/NativeProcessLinux.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h" diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp index 87f4b8da053e..50bf29b094df 100755 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -11,10 +11,10 @@ #include "NativeRegisterContextLinux_x86_64.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/source/Plugins/Process/Linux/NativeThreadLinux.cpp index 4ab2a9ae6245..b64689c9d17b 100644 --- a/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ b/source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -16,12 +16,12 @@ #include "NativeRegisterContextLinux.h" #include "SingleStepCheck.h" -#include "lldb/Core/State.h" #include "lldb/Host/HostNativeThread.h" #include "lldb/Host/linux/Ptrace.h" #include "lldb/Host/linux/Support.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "lldb/lldb-enumerations.h" #include "llvm/ADT/SmallString.h" diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp index 116155d9a232..8908108eff4b 100644 --- a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp @@ -9,25 +9,21 @@ #include "CommunicationKDP.h" -// C Includes #include <errno.h> #include <limits.h> #include <string.h> -// C++ Includes -// Other libraries and framework includes #include "lldb/Core/DumpDataExtractor.h" -#include "lldb/Core/State.h" #include "lldb/Host/Host.h" #include "lldb/Target/Process.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/UUID.h" -// Project includes #include "ProcessKDPLog.h" using namespace lldb; @@ -467,19 +463,13 @@ lldb_private::UUID CommunicationKDP::GetUUID() { bool CommunicationKDP::RemoteIsEFI() { if (GetKernelVersion() == NULL) return false; - if (strncmp(m_kernel_version.c_str(), "EFI", 3) == 0) - return true; - else - return false; + return strncmp(m_kernel_version.c_str(), "EFI", 3) == 0; } bool CommunicationKDP::RemoteIsDarwinKernel() { if (GetKernelVersion() == NULL) return false; - if (m_kernel_version.find("Darwin Kernel") != std::string::npos) - return true; - else - return false; + return m_kernel_version.find("Darwin Kernel") != std::string::npos; } lldb::addr_t CommunicationKDP::GetLoadAddress() { @@ -1262,9 +1252,7 @@ bool CommunicationKDP::SendRequestResume() { request_packet.PutHex32(GetCPUMask()); DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) - return true; - return false; + return SendRequestAndGetReply(command, request_packet, reply_packet); } bool CommunicationKDP::SendRequestBreakpoint(bool set, addr_t addr) { @@ -1297,7 +1285,5 @@ bool CommunicationKDP::SendRequestSuspend() { const uint32_t command_length = 8; MakeRequestPacketHeader(command, request_packet, command_length); DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) - return true; - return false; + return SendRequestAndGetReply(command, request_packet, reply_packet); } diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h index afac6601a56b..64bfe5514735 100644 --- a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h +++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h @@ -10,18 +10,14 @@ #ifndef liblldb_CommunicationKDP_h_ #define liblldb_CommunicationKDP_h_ -// C Includes -// C++ Includes #include <list> #include <mutex> #include <string> -// Other libraries and framework includes -// Project includes #include "lldb/Core/Communication.h" -#include "lldb/Core/Listener.h" #include "lldb/Core/StreamBuffer.h" -#include "lldb/Host/Predicate.h" +#include "lldb/Utility/Listener.h" +#include "lldb/Utility/Predicate.h" #include "lldb/lldb-private.h" class CommunicationKDP : public lldb_private::Communication { diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp index 2e707ab2e363..c1c3678617c0 100644 --- a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -7,20 +7,15 @@ // //===----------------------------------------------------------------------===// -// C Includes #include <errno.h> #include <stdlib.h> -// C++ Includes #include <mutex> -// Other libraries and framework includes #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" -#include "lldb/Utility/UUID.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Host.h" #include "lldb/Host/Symbols.h" @@ -37,13 +32,14 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StringExtractor.h" +#include "lldb/Utility/UUID.h" #include "llvm/Support/Threading.h" #define USEC_PER_SEC 1000000 -// Project includes #include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h" #include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" #include "ProcessKDP.h" @@ -55,10 +51,9 @@ using namespace lldb_private; namespace { -static PropertyDefinition g_properties[] = { - {"packet-timeout", OptionValue::eTypeUInt64, true, 5, NULL, NULL, - "Specify the default packet timeout in seconds."}, - {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; +static constexpr PropertyDefinition g_properties[] = { + {"packet-timeout", OptionValue::eTypeUInt64, true, 5, NULL, {}, + "Specify the default packet timeout in seconds."}}; enum { ePropertyPacketTimeout }; @@ -301,7 +296,8 @@ Status ProcessKDP::DoConnectRemote(Stream *strm, llvm::StringRef remote_url) { if (module_spec.GetSymbolFileSpec()) { ModuleSpec executable_module_spec = Symbols::LocateExecutableObjectFile(module_spec); - if (executable_module_spec.GetFileSpec().Exists()) { + if (FileSystem::Instance().Exists( + executable_module_spec.GetFileSpec())) { module_spec.GetFileSpec() = executable_module_spec.GetFileSpec(); } @@ -310,7 +306,7 @@ Status ProcessKDP::DoConnectRemote(Stream *strm, llvm::StringRef remote_url) { !module_spec.GetSymbolFileSpec()) Symbols::DownloadObjectAndSymbolFile(module_spec, true); - if (module_spec.GetFileSpec().Exists()) { + if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { ModuleSP module_sp(new Module(module_spec)); if (module_sp.get() && module_sp->GetObjectFile()) { // Get the current target executable @@ -319,7 +315,7 @@ Status ProcessKDP::DoConnectRemote(Stream *strm, llvm::StringRef remote_url) { // Make sure you don't already have the right module loaded // and they will be uniqued if (exe_module_sp.get() != module_sp.get()) - target.SetExecutableModule(module_sp, false); + target.SetExecutableModule(module_sp, eLoadDependentsNo); } } } diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h index b4eae58af83c..f9102442de93 100644 --- a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h +++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h @@ -10,19 +10,16 @@ #ifndef liblldb_ProcessKDP_h_ #define liblldb_ProcessKDP_h_ -// C Includes -// C++ Includes #include <list> #include <vector> -// Other libraries and framework includes -#include "lldb/Core/Broadcaster.h" #include "lldb/Core/ThreadSafeValue.h" #include "lldb/Host/HostThread.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp index 159a046b617d..0f9e62ce355a 100644 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp @@ -9,10 +9,6 @@ #include "RegisterContextKDP_arm.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "ProcessKDP.h" #include "ThreadKDP.h" diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h index fe02b0648221..1532f23207f4 100644 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h @@ -10,11 +10,7 @@ #ifndef liblldb_RegisterContextKDP_arm_h_ #define liblldb_RegisterContextKDP_arm_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" class ThreadKDP; diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp index 44534a252568..e13a7f3ad907 100644 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp @@ -10,10 +10,6 @@ #include "RegisterContextKDP_arm64.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "ProcessKDP.h" #include "ThreadKDP.h" diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h index 0922654de2cc..be4038ba96ea 100644 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h @@ -11,11 +11,7 @@ #ifndef liblldb_RegisterContextKDP_arm64_h_ #define liblldb_RegisterContextKDP_arm64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" class ThreadKDP; diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp index e48232ad8dda..096aa0f95d00 100644 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContextKDP_i386.h" #include "ProcessKDP.h" #include "ThreadKDP.h" diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h index 5803670a08b4..699d5fabe157 100644 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextKDP_i386_h_ #define liblldb_RegisterContextKDP_i386_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" class ThreadKDP; diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp index 50e11f381925..9d85145f2eaf 100644 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContextKDP_x86_64.h" #include "ProcessKDP.h" #include "ThreadKDP.h" diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h index 7a40bb626385..9841ad77b004 100644 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextKDP_x86_64_h_ #define liblldb_RegisterContextKDP_x86_64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h" class ThreadKDP; diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp index 7fca0fc24fdb..6f26acd0b8aa 100644 --- a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp @@ -9,10 +9,9 @@ #include "ThreadKDP.h" -#include "lldb/Utility/SafeMachO.h" +#include "lldb/Host/SafeMachO.h" #include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Core/State.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" @@ -20,6 +19,7 @@ #include "lldb/Target/Unwind.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "Plugins/Process/Utility/StopInfoMachException.h" diff --git a/source/Plugins/Process/NetBSD/CMakeLists.txt b/source/Plugins/Process/NetBSD/CMakeLists.txt index 92a6014ced07..e131e6d70468 100644 --- a/source/Plugins/Process/NetBSD/CMakeLists.txt +++ b/source/Plugins/Process/NetBSD/CMakeLists.txt @@ -5,7 +5,6 @@ add_lldb_library(lldbPluginProcessNetBSD PLUGIN NativeThreadNetBSD.cpp LINK_LIBS - lldbCore lldbHost lldbSymbol lldbTarget diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index 1a4cb21d000e..a1b7d7df4553 100644 --- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -9,18 +9,14 @@ #include "NativeProcessNetBSD.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "lldb/Core/State.h" #include "lldb/Host/HostProcess.h" -#include "lldb/Host/common/NativeBreakpoint.h" #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/posix/ProcessLauncherPosixFork.h" #include "lldb/Target/Process.h" +#include "lldb/Utility/State.h" #include "llvm/Support/Errno.h" // System includes - They have to be included after framework includes because @@ -322,100 +318,6 @@ Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, return error; } -Status NativeProcessNetBSD::GetSoftwareBreakpointPCOffset( - uint32_t &actual_opcode_size) { - // FIXME put this behind a breakpoint protocol class that can be - // set per architecture. Need ARM, MIPS support here. - static const uint8_t g_i386_opcode[] = {0xCC}; - switch (m_arch.GetMachine()) { - case llvm::Triple::x86_64: - actual_opcode_size = static_cast<uint32_t>(sizeof(g_i386_opcode)); - return Status(); - default: - assert(false && "CPU type not supported!"); - return Status("CPU type not supported"); - } -} - -Status -NativeProcessNetBSD::FixupBreakpointPCAsNeeded(NativeThreadNetBSD &thread) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - Status error; - // Find out the size of a breakpoint (might depend on where we are in the - // code). - NativeRegisterContext& context = thread.GetRegisterContext(); - uint32_t breakpoint_size = 0; - error = GetSoftwareBreakpointPCOffset(breakpoint_size); - if (error.Fail()) { - LLDB_LOG(log, "GetBreakpointSize() failed: {0}", error); - return error; - } else - LLDB_LOG(log, "breakpoint size: {0}", breakpoint_size); - // First try probing for a breakpoint at a software breakpoint location: PC - - // breakpoint size. - const lldb::addr_t initial_pc_addr = - context.GetPCfromBreakpointLocation(); - lldb::addr_t breakpoint_addr = initial_pc_addr; - if (breakpoint_size > 0) { - // Do not allow breakpoint probe to wrap around. - if (breakpoint_addr >= breakpoint_size) - breakpoint_addr -= breakpoint_size; - } - // Check if we stopped because of a breakpoint. - NativeBreakpointSP breakpoint_sp; - error = m_breakpoint_list.GetBreakpoint(breakpoint_addr, breakpoint_sp); - if (!error.Success() || !breakpoint_sp) { - // We didn't find one at a software probe location. Nothing to do. - LLDB_LOG(log, - "pid {0} no lldb breakpoint found at current pc with " - "adjustment: {1}", - GetID(), breakpoint_addr); - return Status(); - } - // If the breakpoint is not a software breakpoint, nothing to do. - if (!breakpoint_sp->IsSoftwareBreakpoint()) { - LLDB_LOG( - log, - "pid {0} breakpoint found at {1:x}, not software, nothing to adjust", - GetID(), breakpoint_addr); - return Status(); - } - // - // We have a software breakpoint and need to adjust the PC. - // - // Sanity check. - if (breakpoint_size == 0) { - // Nothing to do! How did we get here? - LLDB_LOG(log, - "pid {0} breakpoint found at {1:x}, it is software, but the " - "size is zero, nothing to do (unexpected)", - GetID(), breakpoint_addr); - return Status(); - } - // - // We have a software breakpoint and need to adjust the PC. - // - // Sanity check. - if (breakpoint_size == 0) { - // Nothing to do! How did we get here? - LLDB_LOG(log, - "pid {0} breakpoint found at {1:x}, it is software, but the " - "size is zero, nothing to do (unexpected)", - GetID(), breakpoint_addr); - return Status(); - } - // Change the program counter. - LLDB_LOG(log, "pid {0} tid {1}: changing PC from {2:x} to {3:x}", GetID(), - thread.GetID(), initial_pc_addr, breakpoint_addr); - error = context.SetPC(breakpoint_addr); - if (error.Fail()) { - LLDB_LOG(log, "pid {0} tid {1}: failed to set PC: {2}", GetID(), - thread.GetID(), error); - return error; - } - return error; -} - Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); LLDB_LOG(log, "pid {0}", GetID()); @@ -637,7 +539,7 @@ Status NativeProcessNetBSD::PopulateMemoryRegionCache() { info.SetName(vm[i].kve_path); m_mem_region_cache.emplace_back( - info, FileSpec(info.GetName().GetCString(), true)); + info, FileSpec(info.GetName().GetCString())); } free(vm); @@ -682,23 +584,6 @@ Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size, return SetSoftwareBreakpoint(addr, size); } -Status NativeProcessNetBSD::GetSoftwareBreakpointTrapOpcode( - size_t trap_opcode_size_hint, size_t &actual_opcode_size, - const uint8_t *&trap_opcode_bytes) { - static const uint8_t g_i386_opcode[] = {0xCC}; - - switch (m_arch.GetMachine()) { - case llvm::Triple::x86: - case llvm::Triple::x86_64: - trap_opcode_bytes = g_i386_opcode; - actual_opcode_size = sizeof(g_i386_opcode); - return Status(); - default: - assert(false && "CPU type not supported!"); - return Status("CPU type not supported"); - } -} - Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) { return Status("Unimplemented"); @@ -824,15 +709,6 @@ Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf, return Status(); } -Status NativeProcessNetBSD::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, - size_t size, - size_t &bytes_read) { - Status error = ReadMemory(addr, buf, size, bytes_read); - if (error.Fail()) - return error; - return m_breakpoint_list.RemoveTrapsFromBuffer(addr, buf, size); -} - Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) { const unsigned char *src = static_cast<const unsigned char *>(buf); diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h index 142f74ecf194..a3f1c4c6a06a 100644 --- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h +++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h @@ -58,9 +58,6 @@ public: 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; @@ -93,16 +90,6 @@ public: static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, int data = 0, int *result = nullptr); -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: MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; @@ -125,8 +112,6 @@ private: void MonitorSIGTRAP(lldb::pid_t pid); void MonitorSignal(lldb::pid_t pid, int signal); - Status GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size); - Status FixupBreakpointPCAsNeeded(NativeThreadNetBSD &thread); Status PopulateMemoryRegionCache(); void SigchldHandler(); diff --git a/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp index 16b6f2c52dd5..78da3527122f 100644 --- a/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp +++ b/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp @@ -11,10 +11,10 @@ #include "NativeRegisterContextNetBSD_x86_64.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h" diff --git a/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp index 83f1da78d01d..6f5d1120e40d 100644 --- a/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ b/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -14,9 +14,9 @@ #include "Plugins/Process/POSIX/CrashReason.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/State.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" #include <sstream> diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.h b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h index 134013517a11..3ac798b3d4b3 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIXLog.h +++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h @@ -11,11 +11,7 @@ #ifndef liblldb_ProcessPOSIXLog_h_ #define liblldb_ProcessPOSIXLog_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Utility/Log.h" #define POSIX_LOG_PROCESS (1u << 1) diff --git a/source/Plugins/Process/Utility/ARMUtils.h b/source/Plugins/Process/Utility/ARMUtils.h index 2bbd519b246a..2c14dc936cbc 100644 --- a/source/Plugins/Process/Utility/ARMUtils.h +++ b/source/Plugins/Process/Utility/ARMUtils.h @@ -12,7 +12,7 @@ #include "ARMDefines.h" #include "InstructionUtils.h" -#include "llvm/Support/MathExtras.h" // for SignExtend64 template function +#include "llvm/Support/MathExtras.h" // Common utilities for the ARM/Thumb Instruction Set Architecture. diff --git a/source/Plugins/Process/Utility/CMakeLists.txt b/source/Plugins/Process/Utility/CMakeLists.txt index b43756acea63..e36ce4dec98a 100644 --- a/source/Plugins/Process/Utility/CMakeLists.txt +++ b/source/Plugins/Process/Utility/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_library(lldbPluginProcessUtility PLUGIN HistoryThread.cpp HistoryUnwind.cpp InferiorCallPOSIX.cpp + LinuxProcMaps.cpp LinuxSignals.cpp MipsLinuxSignals.cpp NativeRegisterContextRegisterInfo.cpp diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index 5f34e9915ede..dcbf474fa55a 100644 --- a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -464,7 +464,7 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { end = m_value_regs_map.end(); pos != end; ++pos) { if (pos->second.size() > 1) { - std::sort(pos->second.begin(), pos->second.end()); + llvm::sort(pos->second.begin(), pos->second.end()); reg_num_collection::iterator unique_end = std::unique(pos->second.begin(), pos->second.end()); if (unique_end != pos->second.end()) @@ -514,7 +514,7 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { end = m_invalidate_regs_map.end(); pos != end; ++pos) { if (pos->second.size() > 1) { - std::sort(pos->second.begin(), pos->second.end()); + llvm::sort(pos->second.begin(), pos->second.end()); reg_num_collection::iterator unique_end = std::unique(pos->second.begin(), pos->second.end()); if (unique_end != pos->second.end()) diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/source/Plugins/Process/Utility/DynamicRegisterInfo.h index acb3e3eb8a84..68f3902e0c96 100644 --- a/source/Plugins/Process/Utility/DynamicRegisterInfo.h +++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.h @@ -10,13 +10,9 @@ #ifndef lldb_DynamicRegisterInfo_h_ #define lldb_DynamicRegisterInfo_h_ -// C Includes -// C++ Includes #include <map> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Utility/ConstString.h" #include "lldb/Utility/StructuredData.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/FreeBSDSignals.cpp b/source/Plugins/Process/Utility/FreeBSDSignals.cpp index f695a11c9759..0b56b6093559 100644 --- a/source/Plugins/Process/Utility/FreeBSDSignals.cpp +++ b/source/Plugins/Process/Utility/FreeBSDSignals.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "FreeBSDSignals.h" using namespace lldb_private; diff --git a/source/Plugins/Process/Utility/FreeBSDSignals.h b/source/Plugins/Process/Utility/FreeBSDSignals.h index 8ec96e824f7a..174025cabb82 100644 --- a/source/Plugins/Process/Utility/FreeBSDSignals.h +++ b/source/Plugins/Process/Utility/FreeBSDSignals.h @@ -10,7 +10,6 @@ #ifndef liblldb_FreeBSDSignals_H_ #define liblldb_FreeBSDSignals_H_ -// Project includes #include "lldb/Target/UnixSignals.h" namespace lldb_private { diff --git a/source/Plugins/Process/Utility/GDBRemoteSignals.cpp b/source/Plugins/Process/Utility/GDBRemoteSignals.cpp index abcc8a38669a..cc0537c2a8b3 100644 --- a/source/Plugins/Process/Utility/GDBRemoteSignals.cpp +++ b/source/Plugins/Process/Utility/GDBRemoteSignals.cpp @@ -7,9 +7,6 @@ // //===----------------------------------------------------------------------===// -// C++ Includes -// Other libraries and framework includes -// Project includes #include "GDBRemoteSignals.h" using namespace lldb_private; diff --git a/source/Plugins/Process/Utility/GDBRemoteSignals.h b/source/Plugins/Process/Utility/GDBRemoteSignals.h index 5900fa75d6f2..79d8ec3fbbaf 100644 --- a/source/Plugins/Process/Utility/GDBRemoteSignals.h +++ b/source/Plugins/Process/Utility/GDBRemoteSignals.h @@ -10,10 +10,6 @@ #ifndef liblldb_GDBRemoteSignals_H_ #define liblldb_GDBRemoteSignals_H_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/UnixSignals.h" namespace lldb_private { diff --git a/source/Plugins/Process/Utility/HistoryThread.h b/source/Plugins/Process/Utility/HistoryThread.h index 7675a95246a7..dc24922e7c17 100644 --- a/source/Plugins/Process/Utility/HistoryThread.h +++ b/source/Plugins/Process/Utility/HistoryThread.h @@ -10,18 +10,14 @@ #ifndef liblldb_HistoryThread_h_ #define liblldb_HistoryThread_h_ -// C Includes -// C++ Includes #include <mutex> -// Other libraries and framework includes -// Project includes -#include "lldb/Core/Broadcaster.h" -#include "lldb/Core/Event.h" #include "lldb/Core/UserSettingsController.h" #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/StackFrameList.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/Broadcaster.h" +#include "lldb/Utility/Event.h" #include "lldb/Utility/UserID.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/HistoryUnwind.h b/source/Plugins/Process/Utility/HistoryUnwind.h index 3b64e38bfaa7..2cbfb680ef49 100644 --- a/source/Plugins/Process/Utility/HistoryUnwind.h +++ b/source/Plugins/Process/Utility/HistoryUnwind.h @@ -10,12 +10,8 @@ #ifndef liblldb_HistoryUnwind_h_ #define liblldb_HistoryUnwind_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Target/Unwind.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/LinuxProcMaps.cpp b/source/Plugins/Process/Utility/LinuxProcMaps.cpp new file mode 100644 index 000000000000..d45bf6dcd84f --- /dev/null +++ b/source/Plugins/Process/Utility/LinuxProcMaps.cpp @@ -0,0 +1,113 @@ +//===-- LinuxProcMaps.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LinuxProcMaps.h" +#include "llvm/ADT/StringRef.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StringExtractor.h" + +using namespace lldb_private; + +static Status +ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line, + MemoryRegionInfo &memory_region_info) { + memory_region_info.Clear(); + + StringExtractor line_extractor(maps_line); + + // Format: {address_start_hex}-{address_end_hex} perms offset dev inode + // pathname perms: rwxp (letter is present if set, '-' if not, final + // character is p=private, s=shared). + + // Parse out the starting address + lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0); + + // Parse out hyphen separating start and end address from range. + if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-')) + return Status( + "malformed /proc/{pid}/maps entry, missing dash between address range"); + + // Parse out the ending address + lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address); + + // Parse out the space after the address. + if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' ')) + return Status( + "malformed /proc/{pid}/maps entry, missing space after range"); + + // Save the range. + memory_region_info.GetRange().SetRangeBase(start_address); + memory_region_info.GetRange().SetRangeEnd(end_address); + + // Any memory region in /proc/{pid}/maps is by definition mapped into the + // process. + memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); + + // Parse out each permission entry. + if (line_extractor.GetBytesLeft() < 4) + return Status("malformed /proc/{pid}/maps entry, missing some portion of " + "permissions"); + + // Handle read permission. + const char read_perm_char = line_extractor.GetChar(); + if (read_perm_char == 'r') + memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes); + else if (read_perm_char == '-') + memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + else + return Status("unexpected /proc/{pid}/maps read permission char"); + + // Handle write permission. + const char write_perm_char = line_extractor.GetChar(); + if (write_perm_char == 'w') + memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes); + else if (write_perm_char == '-') + memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + else + return Status("unexpected /proc/{pid}/maps write permission char"); + + // Handle execute permission. + const char exec_perm_char = line_extractor.GetChar(); + if (exec_perm_char == 'x') + memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); + else if (exec_perm_char == '-') + memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + else + return Status("unexpected /proc/{pid}/maps exec permission char"); + + line_extractor.GetChar(); // Read the private bit + line_extractor.SkipSpaces(); // Skip the separator + line_extractor.GetHexMaxU64(false, 0); // Read the offset + line_extractor.GetHexMaxU64(false, 0); // Read the major device number + line_extractor.GetChar(); // Read the device id separator + line_extractor.GetHexMaxU64(false, 0); // Read the major device number + line_extractor.SkipSpaces(); // Skip the separator + line_extractor.GetU64(0, 10); // Read the inode number + + line_extractor.SkipSpaces(); + const char *name = line_extractor.Peek(); + if (name) + memory_region_info.SetName(name); + + return Status(); +} + +void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map, + LinuxMapCallback const &callback) { + llvm::StringRef lines(linux_map); + llvm::StringRef line; + while (!lines.empty()) { + std::tie(line, lines) = lines.split('\n'); + MemoryRegionInfo region; + Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region); + if (!callback(region, error)) + break; + } +} diff --git a/source/Plugins/Process/Utility/LinuxProcMaps.h b/source/Plugins/Process/Utility/LinuxProcMaps.h new file mode 100644 index 000000000000..e6eabb28fc82 --- /dev/null +++ b/source/Plugins/Process/Utility/LinuxProcMaps.h @@ -0,0 +1,28 @@ +//===-- LinuxProcMaps.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_LinuxProcMaps_H_ +#define liblldb_LinuxProcMaps_H_ + +#include "lldb/lldb-forward.h" +#include "llvm/ADT/StringRef.h" +#include <functional> + + +namespace lldb_private { + +typedef std::function<bool(const lldb_private::MemoryRegionInfo &, + const lldb_private::Status &)> LinuxMapCallback; + +void ParseLinuxMapRegions(llvm::StringRef linux_map, + LinuxMapCallback const &callback); + +} // namespace lldb_private + +#endif // liblldb_LinuxProcMaps_H_ diff --git a/source/Plugins/Process/Utility/LinuxSignals.cpp b/source/Plugins/Process/Utility/LinuxSignals.cpp index eb01075ed133..6f1f67ac3570 100644 --- a/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -7,9 +7,6 @@ // //===----------------------------------------------------------------------===// -// C++ Includes -// Other libraries and framework includes -// Project includes #include "LinuxSignals.h" using namespace lldb_private; diff --git a/source/Plugins/Process/Utility/LinuxSignals.h b/source/Plugins/Process/Utility/LinuxSignals.h index e41126225cee..f93a9d2e36d1 100644 --- a/source/Plugins/Process/Utility/LinuxSignals.h +++ b/source/Plugins/Process/Utility/LinuxSignals.h @@ -10,10 +10,6 @@ #ifndef liblldb_LinuxSignals_H_ #define liblldb_LinuxSignals_H_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/UnixSignals.h" namespace lldb_private { diff --git a/source/Plugins/Process/Utility/MipsLinuxSignals.cpp b/source/Plugins/Process/Utility/MipsLinuxSignals.cpp index 36231023aa3a..b6f3b34893bf 100644 --- a/source/Plugins/Process/Utility/MipsLinuxSignals.cpp +++ b/source/Plugins/Process/Utility/MipsLinuxSignals.cpp @@ -8,9 +8,6 @@ // //===----------------------------------------------------------------------===// -// C++ Includes -// Other libraries and framework includes -// Project includes #include "MipsLinuxSignals.h" using namespace lldb_private; diff --git a/source/Plugins/Process/Utility/MipsLinuxSignals.h b/source/Plugins/Process/Utility/MipsLinuxSignals.h index e48ea5943f2b..2796f6b8e4d7 100644 --- a/source/Plugins/Process/Utility/MipsLinuxSignals.h +++ b/source/Plugins/Process/Utility/MipsLinuxSignals.h @@ -11,10 +11,6 @@ #ifndef liblldb_MipsLinuxSignals_H_ #define liblldb_MipsLinuxSignals_H_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/UnixSignals.h" namespace lldb_private { diff --git a/source/Plugins/Process/Utility/NetBSDSignals.cpp b/source/Plugins/Process/Utility/NetBSDSignals.cpp index 7ed7189d8048..a4baab9ac85f 100644 --- a/source/Plugins/Process/Utility/NetBSDSignals.cpp +++ b/source/Plugins/Process/Utility/NetBSDSignals.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "NetBSDSignals.h" using namespace lldb_private; diff --git a/source/Plugins/Process/Utility/NetBSDSignals.h b/source/Plugins/Process/Utility/NetBSDSignals.h index 4338f881645e..7bb57fa0c0d6 100644 --- a/source/Plugins/Process/Utility/NetBSDSignals.h +++ b/source/Plugins/Process/Utility/NetBSDSignals.h @@ -10,7 +10,6 @@ #ifndef liblldb_NetBSDSignals_H_ #define liblldb_NetBSDSignals_H_ -// Project includes #include "lldb/Target/UnixSignals.h" namespace lldb_private { diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp index 5d9ff02fafdd..9ad896abd0b4 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp @@ -10,14 +10,12 @@ #include "RegisterContextDarwin_arm.h" #include "RegisterContextDarwinConstants.h" -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/Support/Compiler.h" #include "Plugins/Process/Utility/InstructionUtils.h" @@ -28,7 +26,6 @@ #define LLVM_EXTENSION #endif -// Project includes #include "Utility/ARM_DWARF_Registers.h" #include "Utility/ARM_ehframe_Registers.h" @@ -1673,7 +1670,7 @@ uint32_t RegisterContextDarwin_arm::SetHardwareWatchpoint(lldb::addr_t addr, return LLDB_INVALID_INDEX32; // We must watch for either read or write - if (read == false && write == false) + if (!read && !write) return LLDB_INVALID_INDEX32; // Can't watch more than 4 bytes per WVR/WCR pair diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h index cdf3479dff69..b46946d608bc 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextDarwin_arm_h_ #define liblldb_RegisterContextDarwin_arm_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp index 03ce7ef9f524..b478645e035d 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -11,16 +11,14 @@ #include "RegisterContextDarwin_arm64.h" #include "RegisterContextDarwinConstants.h" -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" @@ -32,7 +30,6 @@ #define LLVM_EXTENSION #endif -// Project includes #include "Utility/ARM64_DWARF_Registers.h" using namespace lldb; @@ -341,12 +338,22 @@ bool RegisterContextDarwin_arm64::ReadRegister(const RegisterInfo *reg_info, case gpr_x26: case gpr_x27: case gpr_x28: + value.SetUInt64(gpr.x[reg - gpr_x0]); + break; case gpr_fp: + value.SetUInt64(gpr.fp); + break; case gpr_sp: + value.SetUInt64(gpr.sp); + break; case gpr_lr: + value.SetUInt64(gpr.lr); + break; case gpr_pc: + value.SetUInt64(gpr.pc); + break; case gpr_cpsr: - value.SetUInt64(gpr.x[reg - gpr_x0]); + value.SetUInt64(gpr.cpsr); break; case gpr_w0: @@ -949,7 +956,7 @@ uint32_t RegisterContextDarwin_arm64::SetHardwareWatchpoint(lldb::addr_t addr, return LLDB_INVALID_INDEX32; // We must watch for either read or write - if (read == false && write == false) + if (!read && !write) return LLDB_INVALID_INDEX32; // Can't watch more than 4 bytes per WVR/WCR pair diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h index 4a0e50947ee7..9e826d85af08 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h @@ -11,10 +11,6 @@ #ifndef liblldb_RegisterContextDarwin_arm64_h_ #define liblldb_RegisterContextDarwin_arm64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp index 24414211d9aa..c9e4b37a17f3 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp @@ -7,17 +7,14 @@ // //===----------------------------------------------------------------------===// -// C Includes -#include <stddef.h> // offsetof +#include <stddef.h> -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" @@ -27,7 +24,6 @@ #define LLVM_EXTENSION #endif -// Project includes #include "RegisterContextDarwin_i386.h" using namespace lldb; diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h index aea8a2900911..ad6a1e48fc34 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextDarwin_i386_h_ #define liblldb_RegisterContextDarwin_i386_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp index ecad8240b294..95460308857a 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp @@ -7,19 +7,16 @@ // //===----------------------------------------------------------------------===// -// C Includes -#include <inttypes.h> // PRIx64 +#include <inttypes.h> #include <stdarg.h> -#include <stddef.h> // offsetof +#include <stddef.h> -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" @@ -29,7 +26,6 @@ #define LLVM_EXTENSION #endif -// Project includes #include "RegisterContextDarwin_x86_64.h" using namespace lldb; diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h index fdd5e8036dee..6d94bf75aad4 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextDarwin_x86_64_h_ #define liblldb_RegisterContextDarwin_x86_64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/source/Plugins/Process/Utility/RegisterContextDummy.cpp index dd6ca92a74ee..c51c30f45a5d 100644 --- a/source/Plugins/Process/Utility/RegisterContextDummy.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDummy.cpp @@ -11,7 +11,6 @@ #include "lldb/Core/Address.h" #include "lldb/Core/AddressRange.h" #include "lldb/Core/Module.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/FuncUnwinders.h" @@ -28,6 +27,7 @@ #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 "RegisterContextDummy.h" diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.h b/source/Plugins/Process/Utility/RegisterContextDummy.h index ea70288f3d69..d5608616c896 100644 --- a/source/Plugins/Process/Utility/RegisterContextDummy.h +++ b/source/Plugins/Process/Utility/RegisterContextDummy.h @@ -11,12 +11,8 @@ #ifndef lldb_RegisterContextDummy_h_ #define lldb_RegisterContextDummy_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h index c9a65b1cacce..b74d0ea75469 100644 --- a/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h @@ -11,10 +11,6 @@ #ifndef liblldb_RegisterContextFreeBSD_powerpc_h_ #define liblldb_RegisterContextFreeBSD_powerpc_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterInfoInterface.h" class RegisterContextFreeBSD_powerpc diff --git a/source/Plugins/Process/Utility/RegisterContextHistory.cpp b/source/Plugins/Process/Utility/RegisterContextHistory.cpp index cc0d696b338a..c9b77663a803 100644 --- a/source/Plugins/Process/Utility/RegisterContextHistory.cpp +++ b/source/Plugins/Process/Utility/RegisterContextHistory.cpp @@ -11,7 +11,6 @@ #include "lldb/Core/Address.h" #include "lldb/Core/AddressRange.h" #include "lldb/Core/Module.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/FuncUnwinders.h" @@ -28,6 +27,7 @@ #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 "RegisterContextHistory.h" diff --git a/source/Plugins/Process/Utility/RegisterContextHistory.h b/source/Plugins/Process/Utility/RegisterContextHistory.h index acaf8fe5c04a..01b3624f8c5b 100644 --- a/source/Plugins/Process/Utility/RegisterContextHistory.h +++ b/source/Plugins/Process/Utility/RegisterContextHistory.h @@ -11,12 +11,8 @@ #ifndef lldb_RegisterContextHistory_h_ #define lldb_RegisterContextHistory_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index ba9a8071bcfb..8c420a87e1b0 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -10,7 +10,6 @@ #include "lldb/Core/Address.h" #include "lldb/Core/AddressRange.h" #include "lldb/Core/Module.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/ArmUnwindInfo.h" @@ -31,6 +30,7 @@ #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" @@ -54,7 +54,8 @@ RegisterContextLLDB::RegisterContextLLDB(Thread &thread, : 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_start_pc(), + 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) { @@ -150,7 +151,8 @@ void RegisterContextLLDB::InitializeZerothFrame() { // We require either a symbol or function in the symbols context to be // successfully filled in or this context is of no use to us. - const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; + const SymbolContextItem resolve_scope = + eSymbolContextFunction | eSymbolContextSymbol; if (pc_module_sp.get() && (pc_module_sp->ResolveSymbolContextForAddress( m_current_pc, resolve_scope, m_sym_ctx) & resolve_scope)) { @@ -227,7 +229,7 @@ void RegisterContextLLDB::InitializeZerothFrame() { return; } - if (!ReadCFAValueForRow(row_register_kind, active_row, m_cfa)) { + 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; @@ -255,12 +257,14 @@ void RegisterContextLLDB::InitializeZerothFrame() { 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 - " using %s UnwindPlan", + " 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()); } @@ -320,7 +324,7 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { above_trap_handler = true; if (pc == 0 || pc == 0x1) { - if (above_trap_handler == false) { + if (!above_trap_handler) { m_frame_type = eNotAValidFrame; UnwindLogMsg("this frame has a pc of 0x0"); return; @@ -378,7 +382,7 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind(); UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0); if (row.get()) { - if (!ReadCFAValueForRow(row_register_kind, row, m_cfa)) { + if (!ReadFrameAddress(row_register_kind, row->GetCFAValue(), m_cfa)) { UnwindLogMsg("failed to get cfa value"); if (m_frame_type != eSkipFrame) // don't override eSkipFrame { @@ -387,6 +391,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { 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"); @@ -419,7 +425,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { } } - UnwindLogMsg("initialized frame cfa is 0x%" PRIx64, (uint64_t)m_cfa); + UnwindLogMsg("initialized frame cfa is 0x%" PRIx64 " afa is 0x%" PRIx64, + (uint64_t)m_cfa, (uint64_t)m_afa); return; } m_frame_type = eNotAValidFrame; @@ -436,7 +443,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { // then we might not find the correct unwind information later. Instead, let // ResolveSymbolContextForAddress fail, and handle the case via // decr_pc_and_recompute_addr_range below. - const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; + const SymbolContextItem resolve_scope = + eSymbolContextFunction | eSymbolContextSymbol; uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress( m_current_pc, resolve_scope, m_sym_ctx, resolve_tail_call_address); @@ -466,7 +474,7 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { bool decr_pc_and_recompute_addr_range = false; // If the symbol lookup failed... - if (m_sym_ctx_valid == false) + if (!m_sym_ctx_valid) decr_pc_and_recompute_addr_range = true; // Or if we're in the middle of the stack (and not "above" an asynchronous @@ -494,7 +502,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { temporary_pc.SetLoadAddress(pc - 1, &process->GetTarget()); m_sym_ctx.Clear(false); m_sym_ctx_valid = false; - uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; + SymbolContextItem resolve_scope = + eSymbolContextFunction | eSymbolContextSymbol; ModuleSP temporary_module_sp = temporary_pc.GetModule(); if (temporary_module_sp && @@ -581,13 +590,15 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { return; } - if (!ReadCFAValueForRow(row_register_kind, active_row, m_cfa)) { + if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), m_cfa)) { UnwindLogMsg("failed to get cfa"); m_frame_type = eNotAValidFrame; return; } - UnwindLogMsg("m_cfa = 0x%" PRIx64, m_cfa); + 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(); @@ -600,9 +611,10 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { } UnwindLogMsg("initialized frame current pc is 0x%" PRIx64 - " cfa 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_cfa, + (uint64_t)m_afa); } bool RegisterContextLLDB::CheckIfLoopingStack() { @@ -1238,7 +1250,7 @@ RegisterContextLLDB::SavedLocationForRegister( // 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 == false && return_address_reg.IsValid() && + if (!have_unwindplan_regloc && return_address_reg.IsValid() && IsFrameZero()) { if (return_address_reg.GetAsKind(eRegisterKindLLDB) != LLDB_INVALID_REGNUM) { @@ -1311,17 +1323,13 @@ RegisterContextLLDB::SavedLocationForRegister( unwindplan_regloc)) { can_fetch_pc_value = true; } - if (ReadCFAValueForRow(unwindplan_registerkind, active_row, - cfa_value)) { + if (ReadFrameAddress(unwindplan_registerkind, + active_row->GetCFAValue(), cfa_value)) { can_fetch_cfa = true; } } - if (can_fetch_pc_value && can_fetch_cfa) { - have_unwindplan_regloc = true; - } else { - have_unwindplan_regloc = false; - } + 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; @@ -1332,7 +1340,7 @@ RegisterContextLLDB::SavedLocationForRegister( ExecutionContext exe_ctx(m_thread.shared_from_this()); Process *process = exe_ctx.GetProcessPtr(); - if (have_unwindplan_regloc == false) { + 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, @@ -1351,7 +1359,7 @@ RegisterContextLLDB::SavedLocationForRegister( } } - if (have_unwindplan_regloc == false) { + if (!have_unwindplan_regloc) { if (IsFrameZero()) { // This is frame 0 - we should return the actual live register context // value @@ -1397,7 +1405,7 @@ RegisterContextLLDB::SavedLocationForRegister( } if (unwindplan_regloc.IsSame()) { - if (IsFrameZero() == false && + 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 " @@ -1441,6 +1449,36 @@ RegisterContextLLDB::SavedLocationForRegister( 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, @@ -1555,7 +1593,6 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() { addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS; addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS; - addr_t old_this_frame_cfa_value = m_cfa; UnwindLLDB::RegisterLocation regloc; if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB), regloc) == @@ -1585,6 +1622,7 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() { // 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(); @@ -1595,19 +1633,21 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() { if (active_row && active_row->GetCFAValue().GetValueType() != - UnwindPlan::Row::CFAValue::unspecified) { + UnwindPlan::Row::FAValue::unspecified) { addr_t new_cfa; - if (!ReadCFAValueForRow(m_fallback_unwind_plan_sp->GetRegisterKind(), - active_row, 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; - m_cfa = old_cfa; 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) { @@ -1628,19 +1668,18 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() { 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 != LLDB_INVALID_ADDRESS) { - if (old_caller_pc_value == new_caller_pc_value && - new_cfa == old_this_frame_cfa_value) { - 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; - m_cfa = old_cfa; - 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' " @@ -1674,16 +1713,19 @@ bool RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan() { if (active_row && active_row->GetCFAValue().GetValueType() != - UnwindPlan::Row::CFAValue::unspecified) { + UnwindPlan::Row::FAValue::unspecified) { addr_t new_cfa; - if (!ReadCFAValueForRow(m_fallback_unwind_plan_sp->GetRegisterKind(), - active_row, 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(); @@ -1698,18 +1740,18 @@ bool RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan() { return false; } -bool RegisterContextLLDB::ReadCFAValueForRow( - lldb::RegisterKind row_register_kind, const UnwindPlan::RowSP &row, - addr_t &cfa_value) { +bool RegisterContextLLDB::ReadFrameAddress( + lldb::RegisterKind row_register_kind, UnwindPlan::Row::FAValue &fa, + addr_t &address) { RegisterValue reg_value; - cfa_value = LLDB_INVALID_ADDRESS; + address = LLDB_INVALID_ADDRESS; addr_t cfa_reg_contents; - switch (row->GetCFAValue().GetValueType()) { - case UnwindPlan::Row::CFAValue::isRegisterDereferenced: { + switch (fa.GetValueType()) { + case UnwindPlan::Row::FAValue::isRegisterDereferenced: { RegisterNumber cfa_reg(m_thread, row_register_kind, - row->GetCFAValue().GetRegisterNumber()); + fa.GetRegisterNumber()); if (ReadGPRValue(cfa_reg, cfa_reg_contents)) { const RegisterInfo *reg_info = GetRegisterInfoAtIndex(cfa_reg.GetAsKind(eRegisterKindLLDB)); @@ -1718,12 +1760,12 @@ bool RegisterContextLLDB::ReadCFAValueForRow( Status error = ReadRegisterValueFromMemory( reg_info, cfa_reg_contents, reg_info->byte_size, reg_value); if (error.Success()) { - cfa_value = reg_value.GetAsUInt64(); + 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, cfa_value); + cfa_reg_contents, address); return true; } else { UnwindLogMsg("Tried to deref reg %s (%d) [0x%" PRIx64 @@ -1735,9 +1777,9 @@ bool RegisterContextLLDB::ReadCFAValueForRow( } break; } - case UnwindPlan::Row::CFAValue::isRegisterPlusOffset: { + case UnwindPlan::Row::FAValue::isRegisterPlusOffset: { RegisterNumber cfa_reg(m_thread, row_register_kind, - row->GetCFAValue().GetRegisterNumber()); + fa.GetRegisterNumber()); if (ReadGPRValue(cfa_reg, cfa_reg_contents)) { if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1) { @@ -1748,35 +1790,35 @@ bool RegisterContextLLDB::ReadCFAValueForRow( cfa_reg_contents = LLDB_INVALID_ADDRESS; return false; } - cfa_value = cfa_reg_contents + row->GetCFAValue().GetOffset(); + address = cfa_reg_contents + fa.GetOffset(); UnwindLogMsg( "CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64 ", offset is %d", - cfa_value, cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB), - cfa_reg_contents, row->GetCFAValue().GetOffset()); + address, cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB), + cfa_reg_contents, fa.GetOffset()); return true; } break; } - case UnwindPlan::Row::CFAValue::isDWARFExpression: { + case UnwindPlan::Row::FAValue::isDWARFExpression: { ExecutionContext exe_ctx(m_thread.shared_from_this()); Process *process = exe_ctx.GetProcessPtr(); - DataExtractor dwarfdata(row->GetCFAValue().GetDWARFExpressionBytes(), - row->GetCFAValue().GetDWARFExpressionLength(), + DataExtractor dwarfdata(fa.GetDWARFExpressionBytes(), + fa.GetDWARFExpressionLength(), process->GetByteOrder(), process->GetAddressByteSize()); ModuleSP opcode_ctx; DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr, 0, - row->GetCFAValue().GetDWARFExpressionLength()); + fa.GetDWARFExpressionLength()); dwarfexpr.SetRegisterKind(row_register_kind); Value result; Status error; if (dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr, result, &error)) { - cfa_value = result.GetScalar().ULongLong(); + address = result.GetScalar().ULongLong(); UnwindLogMsg("CFA value set by DWARF expression is 0x%" PRIx64, - cfa_value); + address); return true; } UnwindLogMsg("Failed to set CFA value via DWARF expression: %s", @@ -2005,12 +2047,8 @@ bool RegisterContextLLDB::ReadPC(addr_t &pc) { pc = abi->FixCodeAddress(pc); } - if (m_all_registers_available == false && above_trap_handler == false && - (pc == 0 || pc == 1)) { - return false; - } - - return true; + return !(m_all_registers_available == false && + above_trap_handler == false && (pc == 0 || pc == 1)); } else { return false; } diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h index 7e9e77dcf06d..50f12c6f8541 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -11,12 +11,8 @@ #ifndef lldb_RegisterContextLLDB_h_ #define lldb_RegisterContextLLDB_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "UnwindLLDB.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/UnwindPlan.h" @@ -192,9 +188,9 @@ private: bool ReadGPRValue(const RegisterNumber ®_num, lldb::addr_t &value); - // Get the CFA register for a given frame. - bool ReadCFAValueForRow(lldb::RegisterKind register_kind, - const UnwindPlan::RowSP &row, 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(); @@ -225,6 +221,7 @@ private: 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; diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp index 77c1bea34851..c0a6084cd723 100644 --- a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp @@ -9,16 +9,12 @@ #include "RegisterContextMacOSXFrameBackchain.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.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" -// Project includes #include "lldb/Utility/StringExtractorGDBRemote.h" using namespace lldb; diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h index 4f5816aa4909..69e23c2782fd 100644 --- a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h +++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h @@ -10,10 +10,6 @@ #ifndef lldb_RegisterContextMacOSXFrameBackchain_h_ #define lldb_RegisterContextMacOSXFrameBackchain_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp b/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp index 71d35bbd3938..69522ace1a68 100644 --- a/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp @@ -11,13 +11,9 @@ #include "RegisterContextMach_arm.h" -// C Includes #include <mach/mach_types.h> #include <mach/thread_act.h> -// C++ Includes -// Other libraries and framework includes -// Project includes using namespace lldb; using namespace lldb_private; diff --git a/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/source/Plugins/Process/Utility/RegisterContextMach_arm.h index a2cf6bfcbe4a..5ea47f214e25 100644 --- a/source/Plugins/Process/Utility/RegisterContextMach_arm.h +++ b/source/Plugins/Process/Utility/RegisterContextMach_arm.h @@ -10,11 +10,7 @@ #ifndef liblldb_RegisterContextMach_arm_h_ #define liblldb_RegisterContextMach_arm_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContextDarwin_arm.h" class RegisterContextMach_arm : public RegisterContextDarwin_arm { diff --git a/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp b/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp index 5a260d5de1d5..94138605239e 100644 --- a/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp @@ -9,12 +9,8 @@ #if defined(__APPLE__) -// C Includes #include <mach/thread_act.h> -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContextMach_i386.h" using namespace lldb; diff --git a/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/source/Plugins/Process/Utility/RegisterContextMach_i386.h index 8ac693a55584..a7e29e96b267 100644 --- a/source/Plugins/Process/Utility/RegisterContextMach_i386.h +++ b/source/Plugins/Process/Utility/RegisterContextMach_i386.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextMach_i386_h_ #define liblldb_RegisterContextMach_i386_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContextDarwin_i386.h" class RegisterContextMach_i386 : public RegisterContextDarwin_i386 { diff --git a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp index 0180879d51ee..e523b95ee974 100644 --- a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp @@ -9,12 +9,8 @@ #if defined(__APPLE__) -// C Includes #include <mach/thread_act.h> -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContextMach_x86_64.h" using namespace lldb; diff --git a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h index cd425046b08e..c73bdda79713 100644 --- a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h +++ b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h @@ -11,10 +11,6 @@ #ifndef liblldb_RegisterContextMach_x86_64_h_ #define liblldb_RegisterContextMach_x86_64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContextDarwin_x86_64.h" class RegisterContextMach_x86_64 : public RegisterContextDarwin_x86_64 { diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/source/Plugins/Process/Utility/RegisterContextMemory.cpp index 76189ea781de..f05c07f6c8e1 100644 --- a/source/Plugins/Process/Utility/RegisterContextMemory.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMemory.cpp @@ -9,15 +9,11 @@ #include "RegisterContextMemory.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "DynamicRegisterInfo.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" using namespace lldb; diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.h b/source/Plugins/Process/Utility/RegisterContextMemory.h index cad1592af5ba..cdf2a5446e1e 100644 --- a/source/Plugins/Process/Utility/RegisterContextMemory.h +++ b/source/Plugins/Process/Utility/RegisterContextMemory.h @@ -10,12 +10,8 @@ #ifndef lldb_RegisterContextMemory_h_ #define lldb_RegisterContextMemory_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp index 352e251e3b64..b0e53cfcc91f 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp @@ -11,14 +11,14 @@ #include <errno.h> #include <stdint.h> -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/Support/Compiler.h" #include "RegisterContextPOSIX_arm.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h index 8c5fe9d2c2de..4b5a8fe95a4f 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextPOSIX_arm_h_ #define liblldb_RegisterContextPOSIX_arm_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterInfoInterface.h" #include "lldb-arm-register-enums.h" #include "lldb/Target/RegisterContext.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp index 3ff93cde2347..8b00dfc81eab 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -11,14 +11,14 @@ #include <errno.h> #include <stdint.h> -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/Support/Compiler.h" #include "RegisterContextPOSIX_arm64.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h index 27251da2a9af..603c12d830d9 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextPOSIX_arm64_h_ #define liblldb_RegisterContextPOSIX_arm64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterInfoInterface.h" #include "lldb-arm64-register-enums.h" #include "lldb/Target/RegisterContext.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp index 98d1e6fa8817..9270d09f7293 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp @@ -11,14 +11,14 @@ #include <errno.h> #include <stdint.h> -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/Support/Compiler.h" #include "RegisterContextPOSIX_mips64.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h index 1695ec9a0bab..09cfd42b9c51 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextPOSIX_mips64_h_ #define liblldb_RegisterContextPOSIX_mips64_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContext_mips.h" #include "RegisterInfoInterface.h" #include "lldb/Target/RegisterContext.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp index 9f0552539723..47a8e2c3f9e9 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp @@ -12,14 +12,14 @@ #include <errno.h> #include <stdint.h> -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/Support/Compiler.h" #include "RegisterContextPOSIX_powerpc.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h index 50f234680ca0..3260cb1ce8bc 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextPOSIX_powerpc_h_ #define liblldb_RegisterContextPOSIX_powerpc_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContext_powerpc.h" #include "RegisterInfoInterface.h" #include "lldb/Target/RegisterContext.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp index 41ae5ec6b51a..ef221c963dc4 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp @@ -11,14 +11,14 @@ #include <errno.h> #include <stdint.h> -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/Support/Compiler.h" #include "RegisterContextPOSIX_ppc64le.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h index 1070b4dea405..9159819f17c4 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextPOSIX_ppc64le_h_ #define liblldb_RegisterContextPOSIX_ppc64le_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" #include "RegisterInfoInterface.h" #include "Utility/PPC64LE_DWARF_Registers.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp index 662ac38405ef..24f131099be4 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp @@ -11,14 +11,14 @@ #include <errno.h> #include <stdint.h> -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/Support/Compiler.h" #include "RegisterContextPOSIX_s390x.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h index d5337630c32d..7a7b6bddd6aa 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextPOSIX_s390x_h_ #define liblldb_RegisterContextPOSIX_s390x_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContext_s390x.h" #include "RegisterInfoInterface.h" #include "lldb-s390x-register-enums.h" diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp index d2a06e1b7897..78f561a0f04f 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp @@ -11,14 +11,14 @@ #include <errno.h> #include <stdint.h> -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" #include "llvm/Support/Compiler.h" #include "RegisterContextPOSIX_x86.h" @@ -376,7 +376,7 @@ RegisterContextPOSIX_x86::FPRType RegisterContextPOSIX_x86::GetFPRType() { if (m_fpr_type == eNotValid) { // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx m_fpr_type = eXSAVE; // extended floating-point registers, if available - if (false == ReadFPR()) + if (!ReadFPR()) m_fpr_type = eFXSAVE; // assume generic floating-point registers } return m_fpr_type; diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h index ca71a6f272f8..b6db45e55bbf 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h @@ -10,10 +10,6 @@ #ifndef liblldb_RegisterContextPOSIX_x86_h_ #define liblldb_RegisterContextPOSIX_x86_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "RegisterContext_x86.h" #include "RegisterInfoInterface.h" #include "lldb-x86-register-enums.h" diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h index 3b3b0856a4ca..0d50c73a31a9 100644 --- a/source/Plugins/Process/Utility/RegisterContextThreadMemory.h +++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h @@ -10,12 +10,8 @@ #ifndef lldb_RegisterContextThreadMemory_h_ #define lldb_RegisterContextThreadMemory_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterContext_x86.h b/source/Plugins/Process/Utility/RegisterContext_x86.h index 6146dcaf7e5a..e3ff492d707a 100644 --- a/source/Plugins/Process/Utility/RegisterContext_x86.h +++ b/source/Plugins/Process/Utility/RegisterContext_x86.h @@ -341,7 +341,7 @@ LLVM_PACKED_END // x86 extensions to FXSAVE (i.e. for AVX and MPX processors) LLVM_PACKED_START -struct LLVM_ALIGNAS(64) XSAVE { +struct LLVM_ALIGNAS(16) XSAVE { FXSAVE i387; // floating point registers typical in i387_fxsave_struct XSAVE_HDR header; // The xsave_hdr_struct can be used to determine if the // following extensions are usable diff --git a/source/Plugins/Process/Utility/RegisterInfos_arm.h b/source/Plugins/Process/Utility/RegisterInfos_arm.h index 74d3226c8a52..ec951ea8a391 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_arm.h +++ b/source/Plugins/Process/Utility/RegisterInfos_arm.h @@ -9,12 +9,8 @@ #ifdef DECLARE_REGISTER_INFOS_ARM_STRUCT -// C Includes #include <stddef.h> -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/source/Plugins/Process/Utility/RegisterInfos_arm64.h index b996533791ff..039d98ecdd2d 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_arm64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_arm64.h @@ -9,12 +9,8 @@ #ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT -// C Includes #include <stddef.h> -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Utility/RegisterInfos_i386.h b/source/Plugins/Process/Utility/RegisterInfos_i386.h index ffdc4d0d116b..f8947876d15f 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_i386.h +++ b/source/Plugins/Process/Utility/RegisterInfos_i386.h @@ -11,7 +11,6 @@ #include <cstddef> #include <cstdint> -// Project includes #ifdef DECLARE_REGISTER_INFOS_I386_STRUCT diff --git a/source/Plugins/Process/Utility/RegisterInfos_mips.h b/source/Plugins/Process/Utility/RegisterInfos_mips.h index b116b99b3f81..36483c068d26 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_mips.h +++ b/source/Plugins/Process/Utility/RegisterInfos_mips.h @@ -7,15 +7,11 @@ // //===---------------------------------------------------------------------===// -// C Includes #include <stddef.h> -// C++ Includes -// Other libraries and framework includes #include "lldb/Core/dwarf.h" #include "llvm/Support/Compiler.h" -// Project includes #ifdef DECLARE_REGISTER_INFOS_MIPS_STRUCT diff --git a/source/Plugins/Process/Utility/RegisterInfos_mips64.h b/source/Plugins/Process/Utility/RegisterInfos_mips64.h index 3c3912fa6978..0194074f34f2 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_mips64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_mips64.h @@ -7,15 +7,11 @@ // //===----------------------------------------------------------------------===// -// C Includes #include <stddef.h> -// C++ Includes -// Other libraries and framework includes #include "lldb/Core/dwarf.h" #include "llvm/Support/Compiler.h" -// Project includes #ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT diff --git a/source/Plugins/Process/Utility/RegisterInfos_ppc64.h b/source/Plugins/Process/Utility/RegisterInfos_ppc64.h index 69f00e4ba885..dbd87ad71a45 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_ppc64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_ppc64.h @@ -9,7 +9,6 @@ #ifdef DECLARE_REGISTER_INFOS_PPC64_STRUCT -// C Includes #include <stddef.h> // Computes the offset of the given GPR_PPC64 in the user data area. diff --git a/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h b/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h index bffa7a1d8b63..e6fa17b60758 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h +++ b/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h @@ -9,7 +9,6 @@ #ifdef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT -// C Includes #include <stddef.h> // Computes the offset of the given GPR in the user data area. diff --git a/source/Plugins/Process/Utility/RegisterInfos_s390x.h b/source/Plugins/Process/Utility/RegisterInfos_s390x.h index 0bbf422405ee..b750be4116a5 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_s390x.h +++ b/source/Plugins/Process/Utility/RegisterInfos_s390x.h @@ -7,14 +7,10 @@ // //===----------------------------------------------------------------------===// -// C Includes #include <stddef.h> -// C++ Includes -// Other libraries and framework includes #include "llvm/Support/Compiler.h" -// Project includes #ifdef DECLARE_REGISTER_INFOS_S390X_STRUCT diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp index 3dbfe611e713..de0821eb4253 100644 --- a/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -9,10 +9,12 @@ #include "StopInfoMachException.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes + +#if defined(__APPLE__) +// Needed for the EXC_RESOURCE interpretation macros +#include <kern/exc_resource.h> +#endif + #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/DynamicLoader.h" @@ -41,6 +43,12 @@ const char *StopInfoMachException::GetDescription() { const char *code_desc = NULL; const char *subcode_label = "subcode"; const char *subcode_desc = NULL; + +#if defined(__APPLE__) + char code_desc_buf[32]; + char subcode_desc_buf[32]; +#endif + switch (m_value) { case 1: // EXC_BAD_ACCESS exc_desc = "EXC_BAD_ACCESS"; @@ -275,6 +283,47 @@ const char *StopInfoMachException::GetDescription() { break; case 11: exc_desc = "EXC_RESOURCE"; +#if defined(__APPLE__) + { + int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code); + + code_label = "limit"; + code_desc = code_desc_buf; + subcode_label = "observed"; + subcode_desc = subcode_desc_buf; + + switch (resource_type) { + case RESOURCE_TYPE_CPU: + exc_desc = "EXC_RESOURCE RESOURCE_TYPE_CPU"; + snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%", + (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code)); + snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%", + (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED(m_exc_subcode)); + break; + case RESOURCE_TYPE_WAKEUPS: + exc_desc = "EXC_RESOURCE RESOURCE_TYPE_WAKEUPS"; + snprintf(code_desc_buf, sizeof(code_desc_buf), "%d w/s", + (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code)); + snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s", + (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED(m_exc_subcode)); + break; + case RESOURCE_TYPE_MEMORY: + exc_desc = "EXC_RESOURCE RESOURCE_TYPE_MEMORY"; + snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB", + (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code)); + subcode_desc = nullptr; + subcode_label = "unused"; + break; + case RESOURCE_TYPE_IO: + exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO"; + snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB", + (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code)); + snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB", + (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode));; + break; + } + } +#endif break; case 12: exc_desc = "EXC_GUARD"; diff --git a/source/Plugins/Process/Utility/StopInfoMachException.h b/source/Plugins/Process/Utility/StopInfoMachException.h index 94516454105e..027ed80e8a98 100644 --- a/source/Plugins/Process/Utility/StopInfoMachException.h +++ b/source/Plugins/Process/Utility/StopInfoMachException.h @@ -10,12 +10,8 @@ #ifndef liblldb_StopInfoMachException_h_ #define liblldb_StopInfoMachException_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "lldb/Target/StopInfo.h" namespace lldb_private { diff --git a/source/Plugins/Process/Utility/ThreadMemory.h b/source/Plugins/Process/Utility/ThreadMemory.h index 89229710da4d..c966ca03a017 100644 --- a/source/Plugins/Process/Utility/ThreadMemory.h +++ b/source/Plugins/Process/Utility/ThreadMemory.h @@ -10,12 +10,8 @@ #ifndef liblldb_ThreadMemory_h_ #define liblldb_ThreadMemory_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "lldb/Target/Thread.h" class ThreadMemory : public lldb_private::Thread { diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index 55559f07f1e5..b34c87230bd1 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -130,6 +130,8 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { 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 @@ -138,7 +140,7 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { // 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 > 300000) { + if (cur_idx >= max_stack_depth) { if (log) log->Printf("%*sFrame %d unwound too many frames, assuming unwind has " "gone astray, stopping.", @@ -210,15 +212,15 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { // 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() == false) { + 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() == false || - reg_ctx_sp->GetCFA(cursor_sp->cfa) == false || - abi->CallFrameAddressIsValid(cursor_sp->cfa) == false) { + 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 @@ -383,10 +385,8 @@ bool UnwindLLDB::AddOneMoreFrame(ABI *abi) { // 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. - if (!(m_frames[m_frames.size() - 2]->reg_ctx_lldb_sp->GetCFA( - m_frames[m_frames.size() - 2]->cfa))) - return false; - return true; + 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 @@ -468,10 +468,7 @@ bool UnwindLLDB::SearchForSavedLocationForRegister( UnwindLLDB::RegisterSearchResult result; result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister( lldb_regnum, regloc); - if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound) - return true; - else - return false; + return result == UnwindLLDB::RegisterSearchResult::eRegisterFound; } while (frame_num >= 0) { UnwindLLDB::RegisterSearchResult result; diff --git a/source/Plugins/Process/Utility/UnwindLLDB.h b/source/Plugins/Process/Utility/UnwindLLDB.h index 3d1f85a3dec3..aec7b66d9354 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.h +++ b/source/Plugins/Process/Utility/UnwindLLDB.h @@ -10,12 +10,8 @@ #ifndef lldb_UnwindLLDB_h_ #define lldb_UnwindLLDB_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/UnwindPlan.h" diff --git a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp index 2115b4e179c0..ae0b9fb0a526 100644 --- a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp +++ b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp @@ -114,7 +114,7 @@ size_t UnwindMacOSXFrameBackchain::GetStackFrameData_i386( if (!m_cursors.empty()) { lldb::addr_t first_frame_pc = m_cursors.front().pc; if (first_frame_pc != LLDB_INVALID_ADDRESS) { - const uint32_t resolve_scope = + const SymbolContextItem resolve_scope = eSymbolContextModule | eSymbolContextCompUnit | eSymbolContextFunction | eSymbolContextSymbol; @@ -205,7 +205,7 @@ size_t UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64( if (!m_cursors.empty()) { lldb::addr_t first_frame_pc = m_cursors.front().pc; if (first_frame_pc != LLDB_INVALID_ADDRESS) { - const uint32_t resolve_scope = + const SymbolContextItem resolve_scope = eSymbolContextModule | eSymbolContextCompUnit | eSymbolContextFunction | eSymbolContextSymbol; diff --git a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h index 328117a306ef..9ee0b08ca09a 100644 --- a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h +++ b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h @@ -10,12 +10,8 @@ #ifndef lldb_UnwindMacOSXFrameBackchain_h_ #define lldb_UnwindMacOSXFrameBackchain_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Target/Unwind.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/source/Plugins/Process/Windows/Common/DebuggerThread.cpp index ad43551a4c6d..81ec25871c57 100644 --- a/source/Plugins/Process/Windows/Common/DebuggerThread.cpp +++ b/source/Plugins/Process/Windows/Common/DebuggerThread.cpp @@ -12,7 +12,6 @@ #include "IDebugDelegate.h" #include "lldb/Core/ModuleSpec.h" -#include "lldb/Host/Predicate.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/windows/HostProcessWindows.h" #include "lldb/Host/windows/HostThreadWindows.h" @@ -21,6 +20,7 @@ #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Predicate.h" #include "lldb/Utility/Status.h" #include "Plugins/Process/Windows/Common/ProcessWindowsLog.h" @@ -50,7 +50,7 @@ struct DebugAttachContext { lldb::pid_t m_pid; ProcessAttachInfo m_attach_info; }; -} +} // namespace DebuggerThread::DebuggerThread(DebugDelegateSP debug_delegate) : m_debug_delegate(debug_delegate), m_pid_to_detach(0), @@ -191,7 +191,8 @@ Status DebuggerThread::StopDebugging(bool terminate) { handle, pid, terminate_suceeded); } else { LLDB_LOG(log, - "NOT calling TerminateProcess because the inferior is not valid ({0}, 0) (inferior={1})", + "NOT calling TerminateProcess because the inferior is not valid " + "({0}, 0) (inferior={1})", handle, pid); } } @@ -267,6 +268,8 @@ void DebuggerThread::DebugLoop() { if (wait_result) { DWORD continue_status = DBG_CONTINUE; switch (dbe.dwDebugEventCode) { + default: + llvm_unreachable("Unhandle debug event code!"); case EXCEPTION_DEBUG_EVENT: { ExceptionResult status = HandleExceptionEvent(dbe.u.Exception, dbe.dwThreadId); @@ -330,7 +333,7 @@ void DebuggerThread::DebugLoop() { FreeProcessHandles(); LLDB_LOG(log, "WaitForDebugEvent loop completed, exiting."); - SetEvent(m_debugging_ended_event); + ::SetEvent(m_debugging_ended_event); } ExceptionResult @@ -381,7 +384,7 @@ DebuggerThread::HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id) { Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EVENT | WINDOWS_LOG_THREAD); - LLDB_LOG(log, "Thread {0:x} spawned in process {1}", thread_id, + LLDB_LOG(log, "Thread {0} spawned in process {1}", thread_id, m_process.GetProcessId()); HostThread thread(info.hThread); thread.GetNativeThread().SetOwnsHandle(false); @@ -439,7 +442,6 @@ DebuggerThread::HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, m_debug_delegate->OnExitProcess(info.dwExitCode); - FreeProcessHandles(); return DBG_CONTINUE; } @@ -468,7 +470,7 @@ DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, if (path_str.startswith("\\\\?\\")) path += 4; - FileSpec file_spec(path, false); + FileSpec file_spec(path); ModuleSpec module_spec(file_spec); lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll); diff --git a/source/Plugins/Process/Windows/Common/DebuggerThread.h b/source/Plugins/Process/Windows/Common/DebuggerThread.h index fcf36f7dec9b..047d3ccb7296 100644 --- a/source/Plugins/Process/Windows/Common/DebuggerThread.h +++ b/source/Plugins/Process/Windows/Common/DebuggerThread.h @@ -16,8 +16,8 @@ #include "ForwardDecl.h" #include "lldb/Host/HostProcess.h" #include "lldb/Host/HostThread.h" -#include "lldb/Host/Predicate.h" #include "lldb/Host/windows/windows.h" +#include "lldb/Utility/Predicate.h" namespace lldb_private { diff --git a/source/Plugins/Process/Windows/Common/ForwardDecl.h b/source/Plugins/Process/Windows/Common/ForwardDecl.h index cfe1b79cee11..ce2af3ca4111 100644 --- a/source/Plugins/Process/Windows/Common/ForwardDecl.h +++ b/source/Plugins/Process/Windows/Common/ForwardDecl.h @@ -39,4 +39,4 @@ typedef std::shared_ptr<ExceptionRecord> ExceptionRecordSP; typedef std::unique_ptr<ExceptionRecord> ExceptionRecordUP; } -#endif
\ No newline at end of file +#endif diff --git a/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/source/Plugins/Process/Windows/Common/ProcessWindows.cpp index b14081f76617..3fe5ab7804cb 100644 --- a/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -13,12 +13,11 @@ #include "lldb/Host/windows/windows.h" #include <psapi.h> -// Other libraries and framework includes #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Core/State.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/HostNativeProcessBase.h" #include "lldb/Host/HostProcess.h" #include "lldb/Host/windows/HostThreadWindows.h" @@ -28,6 +27,7 @@ #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/State.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Format.h" @@ -72,6 +72,20 @@ std::string GetProcessExecutableName(DWORD pid) { return file_name; } +DWORD ConvertLldbToWinApiProtect(uint32_t protect) { + // We also can process a read / write permissions here, but if the debugger + // will make later a write into the allocated memory, it will fail. To get + // around it is possible inside DoWriteMemory to remember memory permissions, + // allow write, write and restore permissions, but for now we process only + // the executable permission. + // + // TODO: Process permissions other than executable + if (protect & ePermissionsExecutable) + return PAGE_EXECUTE_READWRITE; + + return PAGE_READWRITE; +} + } // anonymous namespace namespace lldb_private { @@ -237,11 +251,13 @@ Status ProcessWindows::DoLaunch(Module *exe_module, FileSpec working_dir = launch_info.GetWorkingDirectory(); namespace fs = llvm::sys::fs; - if (working_dir && (!working_dir.ResolvePath() || - !fs::is_directory(working_dir.GetPath()))) { - result.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - return result; + if (working_dir) { + FileSystem::Instance().Resolve(working_dir); + if (!FileSystem::Instance().IsDirectory(working_dir)) { + result.SetErrorStringWithFormat("No such file or directory: %s", + working_dir.GetCString()); + return result; + } } if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) { @@ -379,7 +395,7 @@ Status ProcessWindows::DoResume() { SetPrivateState(eStateRunning); } } else { - LLDB_LOG(log, "error: process %I64u is in state %u. Returning...", + LLDB_LOG(log, "error: process {0} is in state {1}. Returning...", m_session_data->m_debugger->GetProcess().GetProcessId(), GetPrivateState()); } @@ -577,7 +593,7 @@ bool ProcessWindows::CanDebug(lldb::TargetSP target_sp, // For now we are just making sure the file exists for a given module ModuleSP exe_module_sp(target_sp->GetExecutableModule()); if (exe_module_sp.get()) - return exe_module_sp->GetFileSpec().Exists(); + return FileSystem::Instance().Exists(exe_module_sp->GetFileSpec()); // However, if there is no executable module, we return true since we might // be preparing to attach. return true; @@ -695,6 +711,58 @@ size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, return bytes_written; } +lldb::addr_t ProcessWindows::DoAllocateMemory(size_t size, uint32_t permissions, + Status &error) { + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); + llvm::sys::ScopedLock lock(m_mutex); + LLDB_LOG(log, "attempting to allocate {0} bytes with permissions {1}", size, + permissions); + + if (!m_session_data) { + LLDB_LOG(log, "cannot allocate, there is no active debugger connection."); + error.SetErrorString( + "cannot allocate, there is no active debugger connection"); + return LLDB_INVALID_ADDRESS; + } + + HostProcess process = m_session_data->m_debugger->GetProcess(); + lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); + auto protect = ConvertLldbToWinApiProtect(permissions); + auto result = VirtualAllocEx(handle, nullptr, size, MEM_COMMIT, protect); + if (!result) { + error.SetError(GetLastError(), eErrorTypeWin32); + LLDB_LOG(log, "allocating failed with error: {0}", error); + return LLDB_INVALID_ADDRESS; + } + + return reinterpret_cast<addr_t>(result); +} + +Status ProcessWindows::DoDeallocateMemory(lldb::addr_t ptr) { + Status result; + + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); + llvm::sys::ScopedLock lock(m_mutex); + LLDB_LOG(log, "attempting to deallocate bytes at address {0}", ptr); + + if (!m_session_data) { + LLDB_LOG(log, "cannot deallocate, there is no active debugger connection."); + result.SetErrorString( + "cannot deallocate, there is no active debugger connection"); + return result; + } + + HostProcess process = m_session_data->m_debugger->GetProcess(); + lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); + if (!VirtualFreeEx(handle, reinterpret_cast<LPVOID>(ptr), 0, MEM_RELEASE)) { + result.SetError(GetLastError(), eErrorTypeWin32); + LLDB_LOG(log, "deallocating failed with error: {0}", result); + return result; + } + + return result; +} + Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr, MemoryRegionInfo &info) { Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); @@ -812,6 +880,14 @@ void ProcessWindows::OnExitProcess(uint32_t exit_code) { SetProcessExitStatus(GetID(), true, 0, exit_code); SetPrivateState(eStateExited); + + // If the process exits before any initial stop then notify the debugger + // of the error otherwise WaitForDebuggerConnection() will be blocked. + // An example of this issue is when a process fails to load a dependent DLL. + if (m_session_data && !m_session_data->m_initial_stop_received) { + Status error(exit_code, eErrorTypeWin32); + OnDebuggerError(error, 0); + } } void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { @@ -829,7 +905,8 @@ void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { return; } - FileSpec executable_file(file_name, true); + FileSpec executable_file(file_name); + FileSystem::Instance().Resolve(executable_file); ModuleSpec module_spec(executable_file); Status error; module = GetTarget().GetSharedModule(module_spec, &error); @@ -837,7 +914,7 @@ void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { return; } - GetTarget().SetExecutableModule(module, false); + GetTarget().SetExecutableModule(module, eLoadDependentsNo); } bool load_addr_changed; @@ -880,8 +957,9 @@ ProcessWindows::OnDebugException(bool first_chance, } if (!first_chance) { - // Any second chance exception is an application crash by definition. - SetPrivateState(eStateCrashed); + // Not any second chance exception is an application crash by definition. + // It may be an expression evaluation crash. + SetPrivateState(eStateStopped); } ExceptionResult result = ExceptionResult::SendToApplication; diff --git a/source/Plugins/Process/Windows/Common/ProcessWindows.h b/source/Plugins/Process/Windows/Common/ProcessWindows.h index ed3938beb347..00e384f58408 100644 --- a/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ b/source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -10,7 +10,6 @@ #ifndef liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_ #define liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_ -// Other libraries and framework includes #include "lldb/Target/Process.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-forward.h" @@ -84,6 +83,9 @@ public: Status &error) override; size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Status &error) override; + lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, + Status &error) override; + Status DoDeallocateMemory(lldb::addr_t ptr) override; Status GetMemoryRegionInfo(lldb::addr_t vm_addr, MemoryRegionInfo &info) override; diff --git a/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp b/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp index b3f507128f82..90d43b2cf828 100644 --- a/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp +++ b/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp @@ -40,12 +40,13 @@ void RegisterContextWindows::InvalidateAllRegisters() { bool RegisterContextWindows::ReadAllRegisterValues( lldb::DataBufferSP &data_sp) { + if (!CacheAllRegisterValues()) return false; - if (data_sp->GetByteSize() < sizeof(m_context)) { - data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0)); - } + + data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0)); memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context)); + return true; } diff --git a/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp index 3903280918cc..b121dc7bf15e 100644 --- a/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp +++ b/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Core/State.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/HostNativeThreadBase.h" #include "lldb/Host/windows/HostThreadWindows.h" @@ -15,6 +14,7 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Logging.h" +#include "lldb/Utility/State.h" #include "Plugins/Process/Utility/UnwindLLDB.h" #include "ProcessWindows.h" diff --git a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp index 4aa6c785f83c..584136a6e5bb 100644 --- a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp +++ b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Core/RegisterValue.h" #include "lldb/Host/windows/HostThreadWindows.h" #include "lldb/Host/windows/windows.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-private-types.h" @@ -74,12 +74,12 @@ RegisterInfo g_register_infos[] = { nullptr, nullptr}, {DEFINE_GPR(rcx, nullptr), - {dwarf_rcx_x86_64, dwarf_rcx_x86_64, LLDB_INVALID_REGNUM, + {dwarf_rcx_x86_64, dwarf_rcx_x86_64, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, lldb_rcx_x86_64}, nullptr, nullptr}, {DEFINE_GPR(rdx, nullptr), - {dwarf_rdx_x86_64, dwarf_rdx_x86_64, LLDB_INVALID_REGNUM, + {dwarf_rdx_x86_64, dwarf_rdx_x86_64, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, lldb_rdx_x86_64}, nullptr, nullptr}, @@ -104,22 +104,22 @@ RegisterInfo g_register_infos[] = { nullptr, nullptr}, {DEFINE_GPR(r8, nullptr), - {dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_INVALID_REGNUM, + {dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, lldb_r8_x86_64}, nullptr, nullptr}, {DEFINE_GPR(r9, nullptr), - {dwarf_r9_x86_64, dwarf_r9_x86_64, LLDB_INVALID_REGNUM, + {dwarf_r9_x86_64, dwarf_r9_x86_64, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, lldb_r9_x86_64}, nullptr, nullptr}, {DEFINE_GPR(r10, nullptr), - {dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_INVALID_REGNUM, + {dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, lldb_r10_x86_64}, nullptr, nullptr}, {DEFINE_GPR(r11, nullptr), - {dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_INVALID_REGNUM, + {dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, lldb_r11_x86_64}, nullptr, nullptr}, diff --git a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp index fd486f3d0829..e012f9105f31 100644 --- a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp +++ b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Core/RegisterValue.h" #include "lldb/Host/windows/HostThreadWindows.h" #include "lldb/Host/windows/windows.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-private-types.h" diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 7bb7b72eaac1..7d66461c15bc 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -7,25 +7,21 @@ // //===----------------------------------------------------------------------===// -// C Includes #include <stdlib.h> -// C++ Includes #include <mutex> -// Other libraries and framework includes #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Core/State.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Threading.h" @@ -61,8 +57,8 @@ lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp, // the header extension. const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr); - auto data_sp = DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), - header_size, 0); + auto data_sp = FileSystem::Instance().CreateDataBuffer( + crash_file->GetPath(), header_size, 0); if (data_sp && data_sp->GetByteSize() == header_size && elf::ELFHeader::MagicBytesMatch(data_sp->GetBytes())) { elf::ELFHeader elf_header; @@ -81,7 +77,7 @@ lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp, bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) { // For now we are just making sure the file exists for a given module - if (!m_core_module_sp && m_core_file.Exists()) { + if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) { ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture()); Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp, NULL, NULL, NULL)); @@ -122,10 +118,10 @@ ConstString ProcessElfCore::GetPluginName() { return GetPluginNameStatic(); } uint32_t ProcessElfCore::GetPluginVersion() { return 1; } lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment( - const elf::ELFProgramHeader *header) { - const lldb::addr_t addr = header->p_vaddr; - FileRange file_range(header->p_offset, header->p_filesz); - VMRangeToFileOffset::Entry range_entry(addr, header->p_memsz, file_range); + const elf::ELFProgramHeader &header) { + const lldb::addr_t addr = header.p_vaddr; + FileRange file_range(header.p_offset, header.p_filesz); + VMRangeToFileOffset::Entry range_entry(addr, header.p_memsz, file_range); VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() && @@ -140,12 +136,12 @@ lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment( // Keep a separate map of permissions that that isn't coalesced so all ranges // are maintained. const uint32_t permissions = - ((header->p_flags & llvm::ELF::PF_R) ? lldb::ePermissionsReadable : 0u) | - ((header->p_flags & llvm::ELF::PF_W) ? lldb::ePermissionsWritable : 0u) | - ((header->p_flags & llvm::ELF::PF_X) ? lldb::ePermissionsExecutable : 0u); + ((header.p_flags & llvm::ELF::PF_R) ? lldb::ePermissionsReadable : 0u) | + ((header.p_flags & llvm::ELF::PF_W) ? lldb::ePermissionsWritable : 0u) | + ((header.p_flags & llvm::ELF::PF_X) ? lldb::ePermissionsExecutable : 0u); m_core_range_infos.Append( - VMRangeToPermissions::Entry(addr, header->p_memsz, permissions)); + VMRangeToPermissions::Entry(addr, header.p_memsz, permissions)); return addr; } @@ -166,8 +162,8 @@ Status ProcessElfCore::DoLoadCore() { return error; } - const uint32_t num_segments = core->GetProgramHeaderCount(); - if (num_segments == 0) { + llvm::ArrayRef<elf::ELFProgramHeader> segments = core->ProgramHeaders(); + if (segments.size() == 0) { error.SetErrorString("core file has no segments"); return error; } @@ -181,20 +177,17 @@ Status ProcessElfCore::DoLoadCore() { /// Walk through segments and Thread and Address Map information. /// PT_NOTE - Contains Thread and Register information /// PT_LOAD - Contains a contiguous range of Process Address Space - for (uint32_t i = 1; i <= num_segments; i++) { - const elf::ELFProgramHeader *header = core->GetProgramHeaderByIndex(i); - assert(header != NULL); - - DataExtractor data = core->GetSegmentDataByIndex(i); + for (const elf::ELFProgramHeader &H : segments) { + DataExtractor data = core->GetSegmentData(H); // Parse thread contexts and auxv structure - if (header->p_type == llvm::ELF::PT_NOTE) { - if (llvm::Error error = ParseThreadContextsFromNoteSegment(header, data)) + if (H.p_type == llvm::ELF::PT_NOTE) { + if (llvm::Error error = ParseThreadContextsFromNoteSegment(H, data)) return Status(std::move(error)); } // PT_LOAD segments contains address map - if (header->p_type == llvm::ELF::PT_LOAD) { - lldb::addr_t last_addr = AddAddressRangeFromLoadSegment(header); + if (H.p_type == llvm::ELF::PT_LOAD) { + lldb::addr_t last_addr = AddAddressRangeFromLoadSegment(H); if (vm_addr > last_addr) ranges_are_sorted = false; vm_addr = last_addr; @@ -249,12 +242,11 @@ Status ProcessElfCore::DoLoadCore() { ModuleSpec exe_module_spec; exe_module_spec.GetArchitecture() = arch; exe_module_spec.GetFileSpec().SetFile( - m_nt_file_entries[0].path.GetCString(), false, - FileSpec::Style::native); + m_nt_file_entries[0].path.GetCString(), FileSpec::Style::native); if (exe_module_spec.GetFileSpec()) { exe_module_sp = GetTarget().GetSharedModule(exe_module_spec); if (exe_module_sp) - GetTarget().SetExecutableModule(exe_module_sp, false); + GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); } } } @@ -715,8 +707,8 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef<CoreNote> notes) { /// A note segment consists of one or more NOTE entries, but their types and /// meaning differ depending on the OS. llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( - const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) { - assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE); + const elf::ELFProgramHeader &segment_header, DataExtractor segment_data) { + assert(segment_header.p_type == llvm::ELF::PT_NOTE); auto notes_or_error = parseSegment(segment_data); if(!notes_or_error) @@ -744,8 +736,7 @@ uint32_t ProcessElfCore::GetNumThreadContexts() { } ArchSpec ProcessElfCore::GetArchitecture() { - ArchSpec arch; - m_core_module_sp->GetObjectFile()->GetArchitecture(arch); + ArchSpec arch = m_core_module_sp->GetObjectFile()->GetArchitecture(); ArchSpec target_arch = GetTarget().GetArchitecture(); arch.MergeFrom(target_arch); diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.h b/source/Plugins/Process/elf-core/ProcessElfCore.h index 325c0152e028..2c7268662fef 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -17,13 +17,9 @@ #ifndef liblldb_ProcessElfCore_h_ #define liblldb_ProcessElfCore_h_ -// C Includes -// C++ Includes #include <list> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Target/Process.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" @@ -140,7 +136,7 @@ private: // For ProcessElfCore only //------------------------------------------------------------------ typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange; - typedef lldb_private::RangeDataArray<lldb::addr_t, lldb::addr_t, FileRange, 1> + typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange> VMRangeToFileOffset; typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t> VMRangeToPermissions; @@ -170,7 +166,7 @@ private: // Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment llvm::Error ParseThreadContextsFromNoteSegment( - const elf::ELFProgramHeader *segment_header, + const elf::ELFProgramHeader &segment_header, lldb_private::DataExtractor segment_data); // Returns number of thread contexts stored in the core file @@ -178,7 +174,7 @@ private: // Parse a contiguous address range of the process from LOAD segment lldb::addr_t - AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *header); + AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header); llvm::Expected<std::vector<lldb_private::CoreNote>> parseSegment(const lldb_private::DataExtractor &segment); diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp index 0d683153d9ed..80c6c0207a1e 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp @@ -9,8 +9,8 @@ #include "RegisterContextPOSIXCore_arm.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/RegisterValue.h" using namespace lldb_private; diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp index 919f8901d39a..017646b44b5c 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -9,8 +9,8 @@ #include "RegisterContextPOSIXCore_arm64.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/RegisterValue.h" using namespace lldb_private; diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp index 532a1f5c0831..beeb9b666ccd 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp @@ -9,8 +9,8 @@ #include "RegisterContextPOSIXCore_mips64.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/RegisterValue.h" using namespace lldb_private; diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp index 8670e341a277..d4f86b354784 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp @@ -9,9 +9,9 @@ #include "RegisterContextPOSIXCore_powerpc.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" using namespace lldb_private; diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp index 2237e72353ac..8116a1c7ea57 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp @@ -9,9 +9,9 @@ #include "RegisterContextPOSIXCore_ppc64le.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp index f0edbf1ea854..875bb1647281 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp @@ -9,9 +9,9 @@ #include "RegisterContextPOSIXCore_s390x.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" using namespace lldb_private; diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp index a1f26d52444b..27295492f43d 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp @@ -8,9 +8,9 @@ //===----------------------------------------------------------------------===// #include "RegisterContextPOSIXCore_x86_64.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" using namespace lldb_private; diff --git a/source/Plugins/Process/gdb-remote/CMakeLists.txt b/source/Plugins/Process/gdb-remote/CMakeLists.txt index 7ae25f83c5f8..4eb5291d54d5 100644 --- a/source/Plugins/Process/gdb-remote/CMakeLists.txt +++ b/source/Plugins/Process/gdb-remote/CMakeLists.txt @@ -15,6 +15,8 @@ add_lldb_library(lldbPluginProcessGDBRemote PLUGIN GDBRemoteClientBase.cpp GDBRemoteCommunication.cpp GDBRemoteCommunicationClient.cpp + GDBRemoteCommunicationHistory.cpp + GDBRemoteCommunicationReplayServer.cpp GDBRemoteCommunicationServer.cpp GDBRemoteCommunicationServerCommon.cpp GDBRemoteCommunicationServerLLGS.cpp diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp index 4e20b56fb111..a3a4aa053261 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -379,7 +379,7 @@ void GDBRemoteClientBase::Lock::SyncWithContinueThread(bool interrupt) { log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03"); m_comm.m_interrupt_time = steady_clock::now(); } - m_comm.m_cv.wait(lock, [this] { return m_comm.m_is_running == false; }); + m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; }); m_did_interrupt = true; } m_acquired = true; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index c335b6002861..72c1314a7c94 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -9,21 +9,22 @@ #include "GDBRemoteCommunication.h" -// C Includes +#include <future> #include <limits.h> #include <string.h> #include <sys/stat.h> -// C++ Includes -// Other libraries and framework includes #include "lldb/Core/StreamFile.h" #include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/Pipe.h" #include "lldb/Host/Socket.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/common/TCPSocket.h" +#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Utility/FileSpec.h" @@ -33,7 +34,6 @@ #include "llvm/ADT/SmallString.h" #include "llvm/Support/ScopedPrinter.h" -// Project includes #include "ProcessGDBRemoteLog.h" #if defined(__APPLE__) @@ -42,7 +42,8 @@ #define DEBUGSERVER_BASENAME "lldb-server" #endif -#if defined(HAVE_LIBCOMPRESSION) +#if defined(__APPLE__) +#define HAVE_LIBCOMPRESSION #include <compression.h> #endif @@ -54,78 +55,6 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; -GDBRemoteCommunication::History::History(uint32_t size) - : m_packets(), m_curr_idx(0), m_total_packet_count(0), - m_dumped_to_log(false) { - m_packets.resize(size); -} - -GDBRemoteCommunication::History::~History() {} - -void GDBRemoteCommunication::History::AddPacket(char packet_char, - PacketType type, - uint32_t bytes_transmitted) { - const size_t size = m_packets.size(); - if (size > 0) { - const uint32_t idx = GetNextIndex(); - m_packets[idx].packet.assign(1, packet_char); - m_packets[idx].type = type; - m_packets[idx].bytes_transmitted = bytes_transmitted; - m_packets[idx].packet_idx = m_total_packet_count; - m_packets[idx].tid = llvm::get_threadid(); - } -} - -void GDBRemoteCommunication::History::AddPacket(const std::string &src, - uint32_t src_len, - PacketType type, - uint32_t bytes_transmitted) { - const size_t size = m_packets.size(); - if (size > 0) { - const uint32_t idx = GetNextIndex(); - m_packets[idx].packet.assign(src, 0, src_len); - m_packets[idx].type = type; - m_packets[idx].bytes_transmitted = bytes_transmitted; - m_packets[idx].packet_idx = m_total_packet_count; - m_packets[idx].tid = llvm::get_threadid(); - } -} - -void GDBRemoteCommunication::History::Dump(Stream &strm) const { - const uint32_t size = GetNumPacketsInHistory(); - const uint32_t first_idx = GetFirstSavedPacketIndex(); - const uint32_t stop_idx = m_curr_idx + size; - for (uint32_t i = first_idx; i < stop_idx; ++i) { - const uint32_t idx = NormalizeIndex(i); - const Entry &entry = m_packets[idx]; - if (entry.type == ePacketTypeInvalid || entry.packet.empty()) - break; - strm.Printf("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n", - entry.packet_idx, entry.tid, entry.bytes_transmitted, - (entry.type == ePacketTypeSend) ? "send" : "read", - entry.packet.c_str()); - } -} - -void GDBRemoteCommunication::History::Dump(Log *log) const { - if (log && !m_dumped_to_log) { - m_dumped_to_log = true; - const uint32_t size = GetNumPacketsInHistory(); - const uint32_t first_idx = GetFirstSavedPacketIndex(); - const uint32_t stop_idx = m_curr_idx + size; - for (uint32_t i = first_idx; i < stop_idx; ++i) { - const uint32_t idx = NormalizeIndex(i); - const Entry &entry = m_packets[idx]; - if (entry.type == ePacketTypeInvalid || entry.packet.empty()) - break; - log->Printf("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s", - entry.packet_idx, entry.tid, entry.bytes_transmitted, - (entry.type == ePacketTypeSend) ? "send" : "read", - entry.packet.c_str()); - } - } -} - //---------------------------------------------------------------------- // GDBRemoteCommunication constructor //---------------------------------------------------------------------- @@ -139,7 +68,10 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, #endif m_echo_number(0), m_supports_qEcho(eLazyBoolCalculate), m_history(512), m_send_acks(true), m_compression_type(CompressionType::None), - m_listen_url() { + m_listen_url(), m_decompression_scratch_type(CompressionType::None), + m_decompression_scratch(nullptr) { + // Unused unless HAVE_LIBCOMPRESSION is defined. + (void)m_decompression_scratch_type; } //---------------------------------------------------------------------- @@ -150,6 +82,9 @@ GDBRemoteCommunication::~GDBRemoteCommunication() { Disconnect(); } + if (m_decompression_scratch) + free (m_decompression_scratch); + // Stop the communications read thread which is used to parse all incoming // packets. This function will block until the read thread returns. if (m_read_thread_enabled) @@ -172,7 +107,8 @@ size_t GDBRemoteCommunication::SendAck() { const size_t bytes_written = Write(&ch, 1, status, NULL); if (log) log->Printf("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch); - m_history.AddPacket(ch, History::ePacketTypeSend, bytes_written); + m_history.AddPacket(ch, GDBRemoteCommunicationHistory::ePacketTypeSend, + bytes_written); return bytes_written; } @@ -183,26 +119,31 @@ size_t GDBRemoteCommunication::SendNack() { const size_t bytes_written = Write(&ch, 1, status, NULL); if (log) log->Printf("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch); - m_history.AddPacket(ch, History::ePacketTypeSend, bytes_written); + m_history.AddPacket(ch, GDBRemoteCommunicationHistory::ePacketTypeSend, + bytes_written); return bytes_written; } GDBRemoteCommunication::PacketResult GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) { - if (IsConnected()) { StreamString packet(0, 4, eByteOrderBig); - packet.PutChar('$'); packet.Write(payload.data(), payload.size()); packet.PutChar('#'); packet.PutHex8(CalculcateChecksum(payload)); + std::string packet_str = packet.GetString(); + + return SendRawPacketNoLock(packet_str); +} +GDBRemoteCommunication::PacketResult +GDBRemoteCommunication::SendRawPacketNoLock(llvm::StringRef packet, + bool skip_ack) { + if (IsConnected()) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); ConnectionStatus status = eConnectionStatusSuccess; - // TODO: Don't shimmy through a std::string, just use StringRef. - std::string packet_str = packet.GetString(); - const char *packet_data = packet_str.c_str(); - const size_t packet_length = packet.GetSize(); + const char *packet_data = packet.data(); + const size_t packet_length = packet.size(); size_t bytes_written = Write(packet_data, packet_length, status, NULL); if (log) { size_t binary_start_offset = 0; @@ -241,11 +182,12 @@ GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) { (int)packet_length, packet_data); } - m_history.AddPacket(packet.GetString(), packet_length, - History::ePacketTypeSend, bytes_written); + m_history.AddPacket(packet.str(), packet_length, + GDBRemoteCommunicationHistory::ePacketTypeSend, + bytes_written); if (bytes_written == packet_length) { - if (GetSendAcks()) + if (!skip_ack && GetSendAcks()) return GetAck(); else return PacketResult::Success; @@ -597,7 +539,7 @@ bool GDBRemoteCommunication::DecompressPacket() { size_t decompressed_bytes = 0; if (decompressed_bufsize != ULONG_MAX) { - decompressed_buffer = (uint8_t *)malloc(decompressed_bufsize + 1); + decompressed_buffer = (uint8_t *)malloc(decompressed_bufsize); if (decompressed_buffer == nullptr) { m_bytes.erase(0, size_of_first_packet); return false; @@ -605,11 +547,10 @@ bool GDBRemoteCommunication::DecompressPacket() { } #if defined(HAVE_LIBCOMPRESSION) - // libcompression is weak linked so check that compression_decode_buffer() is - // available if (m_compression_type == CompressionType::ZlibDeflate || m_compression_type == CompressionType::LZFSE || - m_compression_type == CompressionType::LZ4) { + m_compression_type == CompressionType::LZ4 || + m_compression_type == CompressionType::LZMA) { compression_algorithm compression_type; if (m_compression_type == CompressionType::LZFSE) compression_type = COMPRESSION_LZFSE; @@ -620,16 +561,33 @@ bool GDBRemoteCommunication::DecompressPacket() { else if (m_compression_type == CompressionType::LZMA) compression_type = COMPRESSION_LZMA; - // If we have the expected size of the decompressed payload, we can - // allocate the right-sized buffer and do it. If we don't have that - // information, we'll need to try decoding into a big buffer and if the - // buffer wasn't big enough, increase it and try again. + if (m_decompression_scratch_type != m_compression_type) { + if (m_decompression_scratch) { + free (m_decompression_scratch); + m_decompression_scratch = nullptr; + } + size_t scratchbuf_size = 0; + if (m_compression_type == CompressionType::LZFSE) + scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE); + else if (m_compression_type == CompressionType::LZ4) + scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZ4_RAW); + else if (m_compression_type == CompressionType::ZlibDeflate) + scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_ZLIB); + else if (m_compression_type == CompressionType::LZMA) + scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZMA); + else if (m_compression_type == CompressionType::LZFSE) + scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE); + if (scratchbuf_size > 0) { + m_decompression_scratch = (void*) malloc (scratchbuf_size); + m_decompression_scratch_type = m_compression_type; + } + } if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr) { decompressed_bytes = compression_decode_buffer( - decompressed_buffer, decompressed_bufsize + 10, - (uint8_t *)unescaped_content.data(), unescaped_content.size(), NULL, - compression_type); + decompressed_buffer, decompressed_bufsize, + (uint8_t *)unescaped_content.data(), unescaped_content.size(), + m_decompression_scratch, compression_type); } } #endif @@ -721,7 +679,7 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, // Size of packet before it is decompressed, for logging purposes size_t original_packet_size = m_bytes.size(); if (CompressionIsEnabled()) { - if (DecompressPacket() == false) { + if (!DecompressPacket()) { packet.Clear(); return GDBRemoteCommunication::PacketType::Standard; } @@ -860,7 +818,8 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, } } - m_history.AddPacket(m_bytes, total_length, History::ePacketTypeRecv, + m_history.AddPacket(m_bytes, total_length, + GDBRemoteCommunicationHistory::ePacketTypeRecv, total_length); // Clear packet_str in case there is some existing data in it. @@ -997,7 +956,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( // debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) { - debugserver_file_spec.SetFile(env_debugserver_path, false, + debugserver_file_spec.SetFile(env_debugserver_path, FileSpec::Style::native); if (log) log->Printf("GDBRemoteCommunication::%s() gdb-remote stub exe path set " @@ -1005,13 +964,14 @@ Status GDBRemoteCommunication::StartDebugserverProcess( __FUNCTION__, env_debugserver_path); } else debugserver_file_spec = g_debugserver_file_spec; - bool debugserver_exists = debugserver_file_spec.Exists(); + bool debugserver_exists = + FileSystem::Instance().Exists(debugserver_file_spec); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources directory. debugserver_file_spec = HostInfo::GetSupportExeDir(); if (debugserver_file_spec) { debugserver_file_spec.AppendPathComponent(DEBUGSERVER_BASENAME); - debugserver_exists = debugserver_file_spec.Exists(); + debugserver_exists = FileSystem::Instance().Exists(debugserver_file_spec); if (debugserver_exists) { if (log) log->Printf( @@ -1074,7 +1034,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( debugserver_args.AppendArgument(llvm::StringRef("--setsid")); } - llvm::SmallString<PATH_MAX> named_pipe_path; + llvm::SmallString<128> named_pipe_path; // socket_pipe is used by debug server to communicate back either // TCP port or domain socket name which it listens on. // The second purpose of the pipe to serve as a synchronization point - @@ -1114,9 +1074,9 @@ Status GDBRemoteCommunication::StartDebugserverProcess( __FUNCTION__, error.AsCString()); return error; } - int write_fd = socket_pipe.GetWriteFileDescriptor(); + pipe_t write = socket_pipe.GetWritePipe(); debugserver_args.AppendArgument(llvm::StringRef("--pipe")); - debugserver_args.AppendArgument(llvm::to_string(write_fd)); + debugserver_args.AppendArgument(llvm::to_string(write)); launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor()); #endif } else { @@ -1304,6 +1264,42 @@ Status GDBRemoteCommunication::StartDebugserverProcess( void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); } +void GDBRemoteCommunication::SetHistoryStream(llvm::raw_ostream *strm) { + m_history.SetStream(strm); +}; + +llvm::Error +GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client, + GDBRemoteCommunication &server) { + const bool child_processes_inherit = false; + const int backlog = 5; + TCPSocket listen_socket(true, child_processes_inherit); + if (llvm::Error error = + listen_socket.Listen("127.0.0.1:0", backlog).ToError()) + return error; + + Socket *accept_socket; + std::future<Status> accept_status = std::async( + std::launch::async, [&] { return listen_socket.Accept(accept_socket); }); + + llvm::SmallString<32> remote_addr; + llvm::raw_svector_ostream(remote_addr) + << "connect://localhost:" << listen_socket.GetLocalPortNumber(); + + std::unique_ptr<ConnectionFileDescriptor> conn_up( + new ConnectionFileDescriptor()); + if (conn_up->Connect(remote_addr, nullptr) != lldb::eConnectionStatusSuccess) + return llvm::make_error<llvm::StringError>("Unable to connect", + llvm::inconvertibleErrorCode()); + + client.SetConnection(conn_up.release()); + if (llvm::Error error = accept_status.get().ToError()) + return error; + + server.SetConnection(new ConnectionFileDescriptor(accept_socket)); + return llvm::Error::success(); +} + GDBRemoteCommunication::ScopedTimeout::ScopedTimeout( GDBRemoteCommunication &gdb_comm, std::chrono::seconds timeout) : m_gdb_comm(gdb_comm), m_timeout_modified(false) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 67796e4c61ef..369eb25b1dfa 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -10,24 +10,21 @@ #ifndef liblldb_GDBRemoteCommunication_h_ #define liblldb_GDBRemoteCommunication_h_ -// C Includes -// C++ Includes +#include "GDBRemoteCommunicationHistory.h" + #include <condition_variable> #include <mutex> #include <queue> #include <string> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Core/Communication.h" -#include "lldb/Core/Listener.h" #include "lldb/Host/HostThread.h" -#include "lldb/Host/Predicate.h" #include "lldb/Utility/Args.h" -#include "lldb/lldb-public.h" - +#include "lldb/Utility/Listener.h" +#include "lldb/Utility/Predicate.h" #include "lldb/Utility/StringExtractorGDBRemote.h" +#include "lldb/lldb-public.h" namespace lldb_private { namespace process_gdb_remote { @@ -140,86 +137,16 @@ public: // fork/exec to avoid having to connect/accept void DumpHistory(Stream &strm); + void SetHistoryStream(llvm::raw_ostream *strm); -protected: - class History { - public: - enum PacketType { - ePacketTypeInvalid = 0, - ePacketTypeSend, - ePacketTypeRecv - }; - - struct Entry { - Entry() - : packet(), type(ePacketTypeInvalid), bytes_transmitted(0), - packet_idx(0), tid(LLDB_INVALID_THREAD_ID) {} - - void Clear() { - packet.clear(); - type = ePacketTypeInvalid; - bytes_transmitted = 0; - packet_idx = 0; - tid = LLDB_INVALID_THREAD_ID; - } - std::string packet; - PacketType type; - uint32_t bytes_transmitted; - uint32_t packet_idx; - lldb::tid_t tid; - }; - - History(uint32_t size); - - ~History(); - - // For single char packets for ack, nack and /x03 - void AddPacket(char packet_char, PacketType type, - uint32_t bytes_transmitted); - - void AddPacket(const std::string &src, uint32_t src_len, PacketType type, - uint32_t bytes_transmitted); - - void Dump(Stream &strm) const; - - void Dump(Log *log) const; - - bool DidDumpToLog() const { return m_dumped_to_log; } - - protected: - uint32_t GetFirstSavedPacketIndex() const { - if (m_total_packet_count < m_packets.size()) - return 0; - else - return m_curr_idx + 1; - } - - uint32_t GetNumPacketsInHistory() const { - if (m_total_packet_count < m_packets.size()) - return m_total_packet_count; - else - return (uint32_t)m_packets.size(); - } - - uint32_t GetNextIndex() { - ++m_total_packet_count; - const uint32_t idx = m_curr_idx; - m_curr_idx = NormalizeIndex(idx + 1); - return idx; - } - - uint32_t NormalizeIndex(uint32_t i) const { return i % m_packets.size(); } - - std::vector<Entry> m_packets; - uint32_t m_curr_idx; - uint32_t m_total_packet_count; - mutable bool m_dumped_to_log; - }; + static llvm::Error ConnectLocally(GDBRemoteCommunication &client, + GDBRemoteCommunication &server); +protected: std::chrono::seconds m_packet_timeout; uint32_t m_echo_number; LazyBool m_supports_qEcho; - History m_history; + GDBRemoteCommunicationHistory m_history; bool m_send_acks; bool m_is_platform; // Set to true if this class represents a platform, // false if this class represents a debug session for @@ -228,6 +155,8 @@ protected: CompressionType m_compression_type; PacketResult SendPacketNoLock(llvm::StringRef payload); + PacketResult SendRawPacketNoLock(llvm::StringRef payload, + bool skip_ack = false); PacketResult ReadPacket(StringExtractorGDBRemote &response, Timeout<std::micro> timeout, bool sync_on_timeout); @@ -289,6 +218,9 @@ private: HostThread m_listen_thread; std::string m_listen_url; + CompressionType m_decompression_scratch_type; + void *m_decompression_scratch; + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunication); }; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index c8b59d5d236b..1e12ea6b2d56 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -9,17 +9,13 @@ #include "GDBRemoteCommunicationClient.h" -// C Includes #include <math.h> #include <sys/stat.h> -// C++ Includes #include <numeric> #include <sstream> -// Other libraries and framework includes #include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/State.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/XML.h" #include "lldb/Symbol/Symbol.h" @@ -31,9 +27,9 @@ #include "lldb/Utility/JSON.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" -// Project includes #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Host/Config.h" @@ -41,7 +37,8 @@ #include "llvm/ADT/StringSwitch.h" -#if defined(HAVE_LIBCOMPRESSION) +#if defined(__APPLE__) +#define HAVE_LIBCOMPRESSION #include <compression.h> #endif @@ -256,10 +253,7 @@ bool GDBRemoteCommunicationClient::GetVAttachOrWaitSupported() { m_attach_or_wait_reply = eLazyBoolYes; } } - if (m_attach_or_wait_reply == eLazyBoolYes) - return true; - else - return false; + return m_attach_or_wait_reply == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported() { @@ -273,14 +267,11 @@ bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported() { m_prepare_for_reg_writing_reply = eLazyBoolYes; } } - if (m_prepare_for_reg_writing_reply == eLazyBoolYes) - return true; - else - return false; + return m_prepare_for_reg_writing_reply == eLazyBoolYes; } void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { - if (did_exec == false) { + if (!did_exec) { // Hard reset everything, this is when we first connect to a GDB server m_supports_not_sending_acks = eLazyBoolCalculate; m_supports_thread_suffix = eLazyBoolCalculate; @@ -749,7 +740,7 @@ lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) { bool sequence_mutex_unavailable; size_t size; size = GetCurrentThreadIDs(thread_ids, sequence_mutex_unavailable); - if (size && sequence_mutex_unavailable == false) { + if (size && !sequence_mutex_unavailable) { m_curr_pid = thread_ids.front(); m_curr_pid_is_valid = eLazyBoolYes; return m_curr_pid; @@ -843,8 +834,8 @@ int GDBRemoteCommunicationClient::SendEnvironmentPacket( if (name_equal_value && name_equal_value[0]) { StreamString packet; bool send_hex_encoding = false; - for (const char *p = name_equal_value; - *p != '\0' && send_hex_encoding == false; ++p) { + for (const char *p = name_equal_value; *p != '\0' && !send_hex_encoding; + ++p) { if (isprint(*p)) { switch (*p) { case '$': @@ -1134,6 +1125,9 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS)); if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) { + // host info computation can require DNS traffic and shelling out to external processes. + // Increase the timeout to account for that. + ScopedTimeout timeout(*this, seconds(10)); m_qHostInfo_is_valid = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qHostInfo", response, false) == @@ -1686,12 +1680,17 @@ Status GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) { m_supports_watchpoint_support_info = eLazyBoolYes; llvm::StringRef name; llvm::StringRef value; + bool found_num_field = false; while (response.GetNameColonValue(name, value)) { if (name.equals("num")) { value.getAsInteger(0, m_num_supported_hardware_watchpoints); num = m_num_supported_hardware_watchpoints; + found_num_field = true; } } + if (!found_num_field) { + m_supports_watchpoint_support_info = eLazyBoolNo; + } } else { m_supports_watchpoint_support_info = eLazyBoolNo; } @@ -1724,12 +1723,10 @@ GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction( // On targets like MIPS and ppc64le, watchpoint exceptions are always // generated before the instruction is executed. The connected target may // not support qHostInfo or qWatchpointSupportInfo packets. - if (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel || - atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el || - atype == llvm::Triple::ppc64le) - after = false; - else - after = true; + after = + !(atype == llvm::Triple::mips || atype == llvm::Triple::mipsel || + atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el || + atype == llvm::Triple::ppc64le); } else { // For MIPS and ppc64le, set m_watchpoints_trigger_after_instruction to // eLazyBoolNo if it is not calculated before. @@ -1815,7 +1812,7 @@ bool GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) { return false; std::string cwd; response.GetHexByteString(cwd); - working_dir.SetFile(cwd, false, GetHostArchitecture().GetTriple()); + working_dir.SetFile(cwd, GetHostArchitecture().GetTriple()); return !cwd.empty(); } return false; @@ -1925,8 +1922,7 @@ bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse( // characters in a process name std::string name; extractor.GetHexByteString(name); - process_info.GetExecutableFile().SetFile(name, false, - FileSpec::Style::native); + process_info.GetExecutableFile().SetFile(name, FileSpec::Style::native); } else if (name.equals("cputype")) { value.getAsInteger(0, cpu); } else if (name.equals("cpusubtype")) { @@ -3559,7 +3555,7 @@ bool GDBRemoteCommunicationClient::GetModuleInfo( StringExtractor extractor(value); std::string path; extractor.GetHexByteString(path); - module_spec.GetFileSpec() = FileSpec(path, false, arch_spec.GetTriple()); + module_spec.GetFileSpec() = FileSpec(path, arch_spec.GetTriple()); } } @@ -3595,8 +3591,7 @@ ParseModuleSpec(StructuredData::Dictionary *dict) { if (!dict->GetValueForKeyAsString("file_path", string)) return llvm::None; - result.GetFileSpec() = - FileSpec(string, false, result.GetArchitecture().GetTriple()); + result.GetFileSpec() = FileSpec(string, result.GetArchitecture().GetTriple()); return result; } @@ -3774,7 +3769,7 @@ void GDBRemoteCommunicationClient::ServeSymbolLookups( // Is this the initial qSymbol:: packet? bool first_qsymbol_query = true; - if (m_supports_qSymbol && m_qSymbol_requests_done == false) { + if (m_supports_qSymbol && !m_qSymbol_requests_done) { Lock lock(*this, false); if (lock) { StreamString packet; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index cf1d249768d7..37d53ab425f5 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -12,8 +12,6 @@ #include "GDBRemoteClientBase.h" -// C Includes -// C++ Includes #include <chrono> #include <map> #include <mutex> diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp new file mode 100644 index 000000000000..69b13f2a3acb --- /dev/null +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp @@ -0,0 +1,143 @@ +//===-- GDBRemoteCommunicationHistory.cpp -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "GDBRemoteCommunicationHistory.h" + +// Other libraries and framework includes +#include "lldb/Core/StreamFile.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Log.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; + +void GDBRemoteCommunicationHistory::Entry::Serialize(raw_ostream &strm) const { + yaml::Output yout(strm); + yout << const_cast<GDBRemoteCommunicationHistory::Entry &>(*this); + strm.flush(); +} + +GDBRemoteCommunicationHistory::GDBRemoteCommunicationHistory(uint32_t size) + : m_packets(), m_curr_idx(0), m_total_packet_count(0), + m_dumped_to_log(false) { + if (size) + m_packets.resize(size); +} + +GDBRemoteCommunicationHistory::~GDBRemoteCommunicationHistory() {} + +void GDBRemoteCommunicationHistory::AddPacket(char packet_char, PacketType type, + uint32_t bytes_transmitted) { + const size_t size = m_packets.size(); + if (size == 0) + return; + + const uint32_t idx = GetNextIndex(); + m_packets[idx].packet.data.assign(1, packet_char); + m_packets[idx].type = type; + m_packets[idx].bytes_transmitted = bytes_transmitted; + m_packets[idx].packet_idx = m_total_packet_count; + m_packets[idx].tid = llvm::get_threadid(); + if (m_stream && type == ePacketTypeRecv) + m_packets[idx].Serialize(*m_stream); +} + +void GDBRemoteCommunicationHistory::AddPacket(const std::string &src, + uint32_t src_len, PacketType type, + uint32_t bytes_transmitted) { + const size_t size = m_packets.size(); + if (size == 0) + return; + + const uint32_t idx = GetNextIndex(); + m_packets[idx].packet.data.assign(src, 0, src_len); + m_packets[idx].type = type; + m_packets[idx].bytes_transmitted = bytes_transmitted; + m_packets[idx].packet_idx = m_total_packet_count; + m_packets[idx].tid = llvm::get_threadid(); + if (m_stream && type == ePacketTypeRecv) + m_packets[idx].Serialize(*m_stream); +} + +void GDBRemoteCommunicationHistory::Dump(Stream &strm) const { + const uint32_t size = GetNumPacketsInHistory(); + const uint32_t first_idx = GetFirstSavedPacketIndex(); + const uint32_t stop_idx = m_curr_idx + size; + for (uint32_t i = first_idx; i < stop_idx; ++i) { + const uint32_t idx = NormalizeIndex(i); + const Entry &entry = m_packets[idx]; + if (entry.type == ePacketTypeInvalid || entry.packet.data.empty()) + break; + strm.Printf("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n", + entry.packet_idx, entry.tid, entry.bytes_transmitted, + (entry.type == ePacketTypeSend) ? "send" : "read", + entry.packet.data.c_str()); + } +} + +void GDBRemoteCommunicationHistory::Dump(Log *log) const { + if (!log || m_dumped_to_log) + return; + + m_dumped_to_log = true; + const uint32_t size = GetNumPacketsInHistory(); + const uint32_t first_idx = GetFirstSavedPacketIndex(); + const uint32_t stop_idx = m_curr_idx + size; + for (uint32_t i = first_idx; i < stop_idx; ++i) { + const uint32_t idx = NormalizeIndex(i); + const Entry &entry = m_packets[idx]; + if (entry.type == ePacketTypeInvalid || entry.packet.data.empty()) + break; + log->Printf("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s", + entry.packet_idx, entry.tid, entry.bytes_transmitted, + (entry.type == ePacketTypeSend) ? "send" : "read", + entry.packet.data.c_str()); + } +} + +void yaml::ScalarEnumerationTraits<GDBRemoteCommunicationHistory::PacketType>:: + enumeration(IO &io, GDBRemoteCommunicationHistory::PacketType &value) { + io.enumCase(value, "Invalid", + GDBRemoteCommunicationHistory::ePacketTypeInvalid); + io.enumCase(value, "Send", GDBRemoteCommunicationHistory::ePacketTypeSend); + io.enumCase(value, "Recv", GDBRemoteCommunicationHistory::ePacketTypeRecv); +} + +void yaml::ScalarTraits<GDBRemoteCommunicationHistory::Entry::BinaryData>:: + output(const GDBRemoteCommunicationHistory::Entry::BinaryData &Val, void *, + raw_ostream &Out) { + Out << toHex(Val.data); +} + +StringRef +yaml::ScalarTraits<GDBRemoteCommunicationHistory::Entry::BinaryData>::input( + StringRef Scalar, void *, + GDBRemoteCommunicationHistory::Entry::BinaryData &Val) { + Val.data = fromHex(Scalar); + return {}; +} + +void yaml::MappingTraits<GDBRemoteCommunicationHistory::Entry>::mapping( + IO &io, GDBRemoteCommunicationHistory::Entry &Entry) { + io.mapRequired("packet", Entry.packet); + io.mapRequired("type", Entry.type); + io.mapRequired("bytes", Entry.bytes_transmitted); + io.mapRequired("index", Entry.packet_idx); + io.mapRequired("tid", Entry.tid); +} + +StringRef yaml::MappingTraits<GDBRemoteCommunicationHistory::Entry>::validate( + IO &io, GDBRemoteCommunicationHistory::Entry &Entry) { + if (Entry.bytes_transmitted != Entry.packet.data.size()) + return "BinaryData size doesn't match bytes transmitted"; + + return {}; +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h new file mode 100644 index 000000000000..d0ca6a0235c9 --- /dev/null +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h @@ -0,0 +1,156 @@ +//===-- GDBRemoteCommunicationHistory.h--------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GDBRemoteCommunicationHistory_h_ +#define liblldb_GDBRemoteCommunicationHistory_h_ + +#include <string> +#include <vector> + +#include "lldb/lldb-public.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" + +namespace lldb_private { +namespace process_gdb_remote { + +/// The history keeps a circular buffer of GDB remote packets. The history is +/// used for logging and replaying GDB remote packets. +class GDBRemoteCommunicationHistory { +public: + friend llvm::yaml::MappingTraits<GDBRemoteCommunicationHistory>; + + enum PacketType { ePacketTypeInvalid = 0, ePacketTypeSend, ePacketTypeRecv }; + + /// Entry in the ring buffer containing the packet data, its type, size and + /// index. Entries can be serialized to file. + struct Entry { + Entry() + : packet(), type(ePacketTypeInvalid), bytes_transmitted(0), + packet_idx(0), tid(LLDB_INVALID_THREAD_ID) {} + + void Clear() { + packet.data.clear(); + type = ePacketTypeInvalid; + bytes_transmitted = 0; + packet_idx = 0; + tid = LLDB_INVALID_THREAD_ID; + } + + struct BinaryData { + std::string data; + }; + + void Serialize(llvm::raw_ostream &strm) const; + + BinaryData packet; + PacketType type; + uint32_t bytes_transmitted; + uint32_t packet_idx; + lldb::tid_t tid; + }; + + GDBRemoteCommunicationHistory(uint32_t size = 0); + + ~GDBRemoteCommunicationHistory(); + + // For single char packets for ack, nack and /x03 + void AddPacket(char packet_char, PacketType type, uint32_t bytes_transmitted); + + void AddPacket(const std::string &src, uint32_t src_len, PacketType type, + uint32_t bytes_transmitted); + + void Dump(Stream &strm) const; + void Dump(Log *log) const; + bool DidDumpToLog() const { return m_dumped_to_log; } + + void SetStream(llvm::raw_ostream *strm) { m_stream = strm; } + +private: + uint32_t GetFirstSavedPacketIndex() const { + if (m_total_packet_count < m_packets.size()) + return 0; + else + return m_curr_idx + 1; + } + + uint32_t GetNumPacketsInHistory() const { + if (m_total_packet_count < m_packets.size()) + return m_total_packet_count; + else + return (uint32_t)m_packets.size(); + } + + uint32_t GetNextIndex() { + ++m_total_packet_count; + const uint32_t idx = m_curr_idx; + m_curr_idx = NormalizeIndex(idx + 1); + return idx; + } + + uint32_t NormalizeIndex(uint32_t i) const { + return m_packets.empty() ? 0 : i % m_packets.size(); + } + + std::vector<Entry> m_packets; + uint32_t m_curr_idx; + uint32_t m_total_packet_count; + mutable bool m_dumped_to_log; + llvm::raw_ostream *m_stream = nullptr; +}; + +} // namespace process_gdb_remote +} // namespace lldb_private + +LLVM_YAML_IS_DOCUMENT_LIST_VECTOR( + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry) + +namespace llvm { +namespace yaml { + +template <> +struct ScalarEnumerationTraits<lldb_private::process_gdb_remote:: + GDBRemoteCommunicationHistory::PacketType> { + static void enumeration(IO &io, + lldb_private::process_gdb_remote:: + GDBRemoteCommunicationHistory::PacketType &value); +}; + +template <> +struct ScalarTraits<lldb_private::process_gdb_remote:: + GDBRemoteCommunicationHistory::Entry::BinaryData> { + static void output(const lldb_private::process_gdb_remote:: + GDBRemoteCommunicationHistory::Entry::BinaryData &, + void *, raw_ostream &); + + static StringRef + input(StringRef, void *, + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry:: + BinaryData &); + + static QuotingType mustQuote(StringRef S) { return QuotingType::None; } +}; + +template <> +struct MappingTraits< + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry> { + static void + mapping(IO &io, + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry + &Entry); + + static StringRef validate( + IO &io, + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry &); +}; + +} // namespace yaml +} // namespace llvm + +#endif // liblldb_GDBRemoteCommunicationHistory_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp new file mode 100644 index 000000000000..6a78eb20992e --- /dev/null +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp @@ -0,0 +1,204 @@ +//===-- GDBRemoteCommunicationReplayServer.cpp ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <errno.h> + +#include "lldb/Host/Config.h" + +#include "GDBRemoteCommunicationReplayServer.h" +#include "ProcessGDBRemoteLog.h" + +// C Includes +// C++ Includes +#include <cstring> + +// Project includes +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Event.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; + +GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer() + : GDBRemoteCommunication("gdb-remote.server", + "gdb-remote.server.rx_packet"), + m_async_broadcaster(nullptr, "lldb.gdb-remote.server.async-broadcaster"), + m_async_listener_sp( + Listener::MakeListener("lldb.gdb-remote.server.async-listener")), + m_async_thread_state_mutex(), m_skip_acks(false) { + m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, + "async thread continue"); + m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, + "async thread should exit"); + + const uint32_t async_event_mask = + eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; + m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster, + async_event_mask); +} + +GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() { + StopAsyncThread(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( + Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) { + StringExtractorGDBRemote packet; + PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false); + + if (packet_result != PacketResult::Success) { + if (!IsConnected()) { + error.SetErrorString("lost connection"); + quit = true; + } else { + error.SetErrorString("timeout"); + } + return packet_result; + } + + m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); + + if (m_skip_acks) { + const StringExtractorGDBRemote::ServerPacketType packet_type = + packet.GetServerPacketType(); + switch (packet_type) { + case StringExtractorGDBRemote::eServerPacketType_nack: + case StringExtractorGDBRemote::eServerPacketType_ack: + return PacketResult::Success; + default: + break; + } + } else if (packet.GetStringRef() == "QStartNoAckMode") { + m_skip_acks = true; + m_send_acks = false; + } + + while (!m_packet_history.empty()) { + // Pop last packet from the history. + GDBRemoteCommunicationHistory::Entry entry = m_packet_history.back(); + m_packet_history.pop_back(); + + // We only care about what we received from the server. Skip everything + // the client sent. + if (entry.type != GDBRemoteCommunicationHistory::ePacketTypeRecv) + continue; + + return SendRawPacketNoLock(entry.packet.data, true); + } + + quit = true; + + return packet_result; +} + +LLVM_YAML_IS_DOCUMENT_LIST_VECTOR( + std::vector< + lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry>) + +llvm::Error +GDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) { + auto error_or_file = MemoryBuffer::getFile(path.GetPath()); + if (auto err = error_or_file.getError()) + return errorCodeToError(err); + + yaml::Input yin((*error_or_file)->getBuffer()); + yin >> m_packet_history; + + if (auto err = yin.error()) + return errorCodeToError(err); + + // We want to manipulate the vector like a stack so we need to reverse the + // order of the packets to have the oldest on at the back. + std::reverse(m_packet_history.begin(), m_packet_history.end()); + + return Error::success(); +} + +bool GDBRemoteCommunicationReplayServer::StartAsyncThread() { + std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); + if (!m_async_thread.IsJoinable()) { + // Create a thread that watches our internal state and controls which + // events make it to clients (into the DCProcess event queue). + m_async_thread = ThreadLauncher::LaunchThread( + "<lldb.gdb-remote.server.async>", + GDBRemoteCommunicationReplayServer::AsyncThread, this, nullptr); + } + + // Wait for handshake. + m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); + + return m_async_thread.IsJoinable(); +} + +void GDBRemoteCommunicationReplayServer::StopAsyncThread() { + std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); + + if (!m_async_thread.IsJoinable()) + return; + + // Request thread to stop. + m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit); + + // Disconnect client. + Disconnect(); + + // Stop the thread. + m_async_thread.Join(nullptr); + m_async_thread.Reset(); +} + +void GDBRemoteCommunicationReplayServer::ReceivePacket( + GDBRemoteCommunicationReplayServer &server, bool &done) { + Status error; + bool interrupt; + auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1), + error, interrupt, done); + if (packet_result != GDBRemoteCommunication::PacketResult::Success && + packet_result != + GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) { + done = true; + } else { + server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); + } +} + +thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) { + GDBRemoteCommunicationReplayServer *server = + (GDBRemoteCommunicationReplayServer *)arg; + + EventSP event_sp; + bool done = false; + + while (true) { + if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) { + const uint32_t event_type = event_sp->GetType(); + if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) { + switch (event_type) { + case eBroadcastBitAsyncContinue: + ReceivePacket(*server, done); + if (done) + return {}; + break; + case eBroadcastBitAsyncThreadShouldExit: + default: + return {}; + } + } + } + } + + return {}; +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h new file mode 100644 index 000000000000..5b840c8459b7 --- /dev/null +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h @@ -0,0 +1,83 @@ +//===-- GDBRemoteCommunicationReplayServer.h --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GDBRemoteCommunicationReplayServer_h_ +#define liblldb_GDBRemoteCommunicationReplayServer_h_ + +// Other libraries and framework includes +#include "GDBRemoteCommunication.h" +#include "GDBRemoteCommunicationHistory.h" + +// Project includes +#include "lldb/Host/HostThread.h" +#include "lldb/Utility/Broadcaster.h" +#include "lldb/lldb-private-forward.h" +#include "llvm/Support/Error.h" + +// C Includes +// C++ Includes +#include <functional> +#include <map> +#include <thread> + +class StringExtractorGDBRemote; + +namespace lldb_private { +namespace process_gdb_remote { + +class ProcessGDBRemote; + +/// Dummy GDB server that replays packets from the GDB Remote Communication +/// history. This is used to replay GDB packets. +class GDBRemoteCommunicationReplayServer : public GDBRemoteCommunication { +public: + GDBRemoteCommunicationReplayServer(); + + ~GDBRemoteCommunicationReplayServer() override; + + PacketResult GetPacketAndSendResponse(Timeout<std::micro> timeout, + Status &error, bool &interrupt, + bool &quit); + + bool HandshakeWithClient() { return GetAck() == PacketResult::Success; } + + llvm::Error LoadReplayHistory(const FileSpec &path); + + bool StartAsyncThread(); + void StopAsyncThread(); + +protected: + enum { + eBroadcastBitAsyncContinue = (1 << 0), + eBroadcastBitAsyncThreadShouldExit = (1 << 1), + }; + + static void ReceivePacket(GDBRemoteCommunicationReplayServer &server, + bool &done); + static lldb::thread_result_t AsyncThread(void *arg); + + /// Replay history with the oldest packet at the end. + std::vector<GDBRemoteCommunicationHistory::Entry> m_packet_history; + + /// Server thread. + Broadcaster m_async_broadcaster; + lldb::ListenerSP m_async_listener_sp; + HostThread m_async_thread; + std::recursive_mutex m_async_thread_state_mutex; + + bool m_skip_acks; + +private: + DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationReplayServer); +}; + +} // namespace process_gdb_remote +} // namespace lldb_private + +#endif // liblldb_GDBRemoteCommunicationReplayServer_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 4fc1fc7a1964..026f78117a0c 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -13,11 +13,8 @@ #include "GDBRemoteCommunicationServer.h" -// C Includes -// C++ Includes #include <cstring> -// Project includes #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringExtractorGDBRemote.h" diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 880caacd6414..082fb0d85424 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -10,13 +10,9 @@ #ifndef liblldb_GDBRemoteCommunicationServer_h_ #define liblldb_GDBRemoteCommunicationServer_h_ -// C Includes -// C++ Includes #include <functional> #include <map> -// Other libraries and framework includes -// Project includes #include "GDBRemoteCommunication.h" #include "lldb/lldb-private-forward.h" diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index c5b478378faa..f11ef4f1bbf8 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -11,23 +11,21 @@ #include <errno.h> -// C Includes #ifdef __APPLE__ #include <TargetConditionals.h> #endif -// C++ Includes #include <chrono> #include <cstring> -// Other libraries and framework includes #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/Config.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/SafeMachO.h" #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/FileAction.h" @@ -36,12 +34,10 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/JSON.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/SafeMachO.h" #include "lldb/Utility/StreamGDBRemote.h" #include "lldb/Utility/StreamString.h" #include "llvm/ADT/Triple.h" -// Project includes #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" @@ -353,7 +349,7 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( std::string file; extractor.GetHexByteString(file); match_info.GetProcessInfo().GetExecutableFile().SetFile( - file, false, FileSpec::Style::native); + file, FileSpec::Style::native); } else if (key.equals("name_match")) { NameMatch name_match = llvm::StringSwitch<NameMatch>(value) .Case("equals", NameMatch::Equals) @@ -520,7 +516,8 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Open( if (packet.GetChar() == ',') { mode_t mode = packet.GetHexMaxU32(false, 0600); Status error; - const FileSpec path_spec{path, true}; + FileSpec path_spec(path); + FileSystem::Instance().Resolve(path_spec); int fd = ::open(path_spec.GetCString(), flags, mode); const int save_errno = fd == -1 ? errno : 0; StreamString response; @@ -659,12 +656,14 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Mode( std::string path; packet.GetHexByteString(path); if (!path.empty()) { - Status error; - const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error); + FileSpec file_spec(path); + FileSystem::Instance().Resolve(file_spec); + std::error_code ec; + const uint32_t mode = FileSystem::Instance().GetPermissions(file_spec, ec); StreamString response; response.Printf("F%u", mode); - if (mode == 0 || error.Fail()) - response.Printf(",%i", (int)error.GetError()); + if (mode == 0 || ec) + response.Printf(",%i", (int)Status(ec).GetError()); return SendPacketNoLock(response.GetString()); } return SendErrorResponse(23); @@ -698,7 +697,11 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_symlink( packet.GetHexByteStringTerminatedBy(dst, ','); packet.GetChar(); // Skip ',' char packet.GetHexByteString(src); - Status error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false}); + + FileSpec src_spec(src); + FileSystem::Instance().Resolve(src_spec); + Status error = FileSystem::Instance().Symlink(src_spec, FileSpec(dst)); + StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetString()); @@ -731,9 +734,11 @@ GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell( packet.GetHexByteString(working_dir); int status, signo; std::string output; - Status err = Host::RunShellCommand( - path.c_str(), FileSpec{working_dir, true}, &status, &signo, &output, - std::chrono::seconds(10)); + FileSpec working_spec(working_dir); + FileSystem::Instance().Resolve(working_spec); + Status err = + Host::RunShellCommand(path.c_str(), working_spec, &status, &signo, + &output, std::chrono::seconds(10)); StreamGDBRemote response; if (err.Fail()) { response.PutCString("F,"); @@ -884,7 +889,7 @@ GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN( packet.GetHexByteString(path); const bool read = true; const bool write = false; - if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write)) { + if (file_action.Open(STDIN_FILENO, FileSpec(path), read, write)) { m_process_launch_info.AppendFileAction(file_action); return SendOKResponse(); } @@ -900,7 +905,7 @@ GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT( packet.GetHexByteString(path); const bool read = false; const bool write = true; - if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write)) { + if (file_action.Open(STDOUT_FILENO, FileSpec(path), read, write)) { m_process_launch_info.AppendFileAction(file_action); return SendOKResponse(); } @@ -916,7 +921,7 @@ GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR( packet.GetHexByteString(path); const bool read = false; const bool write = true; - if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write)) { + if (file_action.Open(STDERR_FILENO, FileSpec(path), read, write)) { m_process_launch_info.AppendFileAction(file_action); return SendOKResponse(); } @@ -1024,7 +1029,7 @@ GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { if (success) { if (arg_idx == 0) m_process_launch_info.GetExecutableFile().SetFile( - arg, false, FileSpec::Style::native); + arg, FileSpec::Style::native); m_process_launch_info.GetArguments().AppendArgument(arg); if (log) log->Printf("LLGSPacketHandler::%s added arg %d: \"%s\"", @@ -1263,7 +1268,9 @@ FileSpec GDBRemoteCommunicationServerCommon::FindModuleFile( #ifdef __ANDROID__ return HostInfoAndroid::ResolveLibraryPath(module_path, arch); #else - return FileSpec(module_path, true); + FileSpec file_spec(module_path); + FileSystem::Instance().Resolve(file_spec); + return file_spec; #endif } @@ -1272,7 +1279,9 @@ GDBRemoteCommunicationServerCommon::GetModuleInfo(llvm::StringRef module_path, llvm::StringRef triple) { ArchSpec arch(triple); - const FileSpec req_module_path_spec(module_path, true); + FileSpec req_module_path_spec(module_path); + FileSystem::Instance().Resolve(req_module_path_spec); + const FileSpec module_path_spec = FindModuleFile(req_module_path_spec.GetPath(), arch); const ModuleSpec module_spec(module_path_spec, arch); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h index e9ab8f1a11de..f3825bb36791 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h @@ -10,12 +10,8 @@ #ifndef liblldb_GDBRemoteCommunicationServerCommon_h_ #define liblldb_GDBRemoteCommunicationServerCommon_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "lldb/Target/Process.h" #include "lldb/lldb-private-forward.h" diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 50392fa38956..cdb63e72f6bd 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -14,15 +14,10 @@ #include "GDBRemoteCommunicationServerLLGS.h" #include "lldb/Utility/StreamGDBRemote.h" -// C Includes -// C++ Includes #include <chrono> #include <cstring> #include <thread> -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/State.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Debug.h" #include "lldb/Host/File.h" @@ -41,12 +36,13 @@ #include "lldb/Utility/JSON.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/UriParser.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/ScopedPrinter.h" -// Project includes #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StringExtractorGDBRemote.h" @@ -222,8 +218,10 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { m_process_launch_info.SetLaunchInSeparateProcessGroup(true); m_process_launch_info.GetFlags().Set(eLaunchFlagDebug); - const bool default_to_use_pty = true; - m_process_launch_info.FinalizeFileActions(nullptr, default_to_use_pty); + if (should_forward_stdio) { + if (llvm::Error Err = m_process_launch_info.SetUpPtyRedirection()) + return Status(std::move(Err)); + } { std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex); @@ -1333,7 +1331,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir( packet.SetFilePos(::strlen("QSetWorkingDir:")); std::string path; packet.GetHexByteString(path); - m_process_launch_info.SetWorkingDirectory(FileSpec{path, true}); + m_process_launch_info.SetWorkingDirectory(FileSpec(path)); return SendOKResponse(); } @@ -3220,7 +3218,7 @@ GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path, if (m_debugged_process_up ->GetLoadedModuleFileSpec(module_path.c_str(), file_spec) .Success()) { - if (file_spec.Exists()) + if (FileSystem::Instance().Exists(file_spec)) return file_spec; } } diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 5a74d1acaa23..a085a3cc17dd 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -10,18 +10,14 @@ #ifndef liblldb_GDBRemoteCommunicationServerLLGS_h_ #define liblldb_GDBRemoteCommunicationServerLLGS_h_ -// C Includes -// C++ Includes #include <mutex> #include <unordered_map> -// Other libraries and framework includes #include "lldb/Core/Communication.h" #include "lldb/Host/MainLoop.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/lldb-private-forward.h" -// Project includes #include "GDBRemoteCommunicationServerCommon.h" class StringExtractorGDBRemote; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index 26e28a900320..3521ddafbb16 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -11,15 +11,12 @@ #include <errno.h> -// C Includes -// C++ Includes #include <chrono> #include <csignal> #include <cstring> #include <mutex> #include <sstream> -// Other libraries and framework includes #include "llvm/Support/FileSystem.h" #include "llvm/Support/Threading.h" @@ -38,7 +35,6 @@ #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UriParser.h" -// Project includes #include "lldb/Utility/StringExtractorGDBRemote.h" using namespace lldb; @@ -168,9 +164,6 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( StringExtractorGDBRemote &packet) { -#ifdef _WIN32 - return SendErrorResponse(9); -#else // Spawn a local debugserver as a platform so we can then attach or launch a // process... @@ -221,10 +214,9 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( PacketResult packet_result = SendPacketNoLock(response.GetString()); if (packet_result != PacketResult::Success) { if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill(debugserver_pid, SIGINT); + Host::Kill(debugserver_pid, SIGINT); } return packet_result; -#endif } GDBRemoteCommunication::PacketResult @@ -532,7 +524,7 @@ const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { const char *domainsocket_dir_env = ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR"); if (domainsocket_dir_env != nullptr) - g_domainsocket_dir = FileSpec(domainsocket_dir_env, false); + g_domainsocket_dir = FileSpec(domainsocket_dir_env); else g_domainsocket_dir = HostInfo::GetProcessTempDir(); }); @@ -542,15 +534,15 @@ const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { FileSpec GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) { - llvm::SmallString<PATH_MAX> socket_path; - llvm::SmallString<PATH_MAX> socket_name( + llvm::SmallString<128> socket_path; + llvm::SmallString<128> socket_name( (llvm::StringRef(prefix) + ".%%%%%%").str()); FileSpec socket_path_spec(GetDomainSocketDir()); socket_path_spec.AppendPathComponent(socket_name.c_str()); llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path); - return FileSpec(socket_path.c_str(), false); + return FileSpec(socket_path.c_str()); } void GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index aed5106272d1..df51e0367d1d 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -10,14 +10,10 @@ #ifndef liblldb_GDBRemoteCommunicationServerPlatform_h_ #define liblldb_GDBRemoteCommunicationServerPlatform_h_ -// C Includes -// C++ Includes #include <map> #include <mutex> #include <set> -// Other libraries and framework includes -// Project includes #include "GDBRemoteCommunicationServerCommon.h" #include "lldb/Host/Socket.h" diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 07dab751f4b9..e58f47f4befe 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -9,17 +9,13 @@ #include "GDBRemoteRegisterContext.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Target.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" -// Project includes #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "ThreadGDBRemote.h" @@ -462,7 +458,7 @@ bool GDBRemoteRegisterContext::ReadAllRegisterValues( ((ProcessGDBRemote *)process)->GetGDBRemote()); const bool use_g_packet = - gdb_comm.AvoidGPackets((ProcessGDBRemote *)process) == false; + !gdb_comm.AvoidGPackets((ProcessGDBRemote *)process); GDBRemoteClientBase::Lock lock(gdb_comm, false); if (lock) { @@ -525,7 +521,7 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( ((ProcessGDBRemote *)process)->GetGDBRemote()); const bool use_g_packet = - gdb_comm.AvoidGPackets((ProcessGDBRemote *)process) == false; + !gdb_comm.AvoidGPackets((ProcessGDBRemote *)process); GDBRemoteClientBase::Lock lock(gdb_comm, false); if (lock) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 8ef91af55e0f..6e8f3306669f 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -10,12 +10,8 @@ #ifndef lldb_GDBRemoteRegisterContext_h_ #define lldb_GDBRemoteRegisterContext_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "Plugins/Process/Utility/DynamicRegisterInfo.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/ConstString.h" diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index b3d33b19bd66..797f63d537a1 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -9,12 +9,11 @@ #include "lldb/Host/Config.h" -// C Includes #include <errno.h> #include <stdlib.h> #ifndef LLDB_DISABLE_POSIX #include <netinet/in.h> -#include <sys/mman.h> // for mmap +#include <sys/mman.h> #include <sys/socket.h> #include <unistd.h> #endif @@ -22,7 +21,6 @@ #include <sys/types.h> #include <time.h> -// C++ Includes #include <algorithm> #include <csignal> #include <map> @@ -34,7 +32,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/Value.h" #include "lldb/DataFormatters/FormatManager.h" @@ -68,10 +65,11 @@ #include "lldb/Utility/Args.h" #include "lldb/Utility/CleanUp.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" -// Project includes #include "GDBRemoteRegisterContext.h" #include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" @@ -88,6 +86,7 @@ #include "llvm/Support/raw_ostream.h" #define DEBUGSERVER_BASENAME "debugserver" +using namespace llvm; using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; @@ -101,21 +100,21 @@ namespace lldb { // and get the packet history dumped to a file. void DumpProcessGDBRemotePacketHistory(void *p, const char *path) { StreamFile strm; - Status error(strm.GetFile().Open(path, File::eOpenOptionWrite | - File::eOpenOptionCanCreate)); + Status error = FileSystem::Instance().Open(strm.GetFile(), FileSpec(path), + File::eOpenOptionWrite | + File::eOpenOptionCanCreate); if (error.Success()) ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory(strm); } -} +} // namespace lldb namespace { -static PropertyDefinition g_properties[] = { - {"packet-timeout", OptionValue::eTypeUInt64, true, 1, NULL, NULL, +static constexpr PropertyDefinition g_properties[] = { + {"packet-timeout", OptionValue::eTypeUInt64, true, 1, NULL, {}, "Specify the default packet timeout in seconds."}, - {"target-definition-file", OptionValue::eTypeFileSpec, true, 0, NULL, NULL, - "The file that provides the description for remote target registers."}, - {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; + {"target-definition-file", OptionValue::eTypeFileSpec, true, 0, NULL, {}, + "The file that provides the description for remote target registers."}}; enum { ePropertyPacketTimeout, ePropertyTargetDefinitionFile }; @@ -158,7 +157,42 @@ static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() { return g_settings_sp; } -} // anonymous namespace end +class ProcessGDBRemoteProvider + : public repro::Provider<ProcessGDBRemoteProvider> { +public: + ProcessGDBRemoteProvider(const FileSpec &directory) : Provider(directory) { + m_info.name = "gdb-remote"; + m_info.files.push_back("gdb-remote.yaml"); + } + + raw_ostream *GetHistoryStream() { + FileSpec history_file = + GetRoot().CopyByAppendingPathComponent("gdb-remote.yaml"); + + std::error_code EC; + m_stream_up = llvm::make_unique<raw_fd_ostream>(history_file.GetPath(), EC, + sys::fs::OpenFlags::F_None); + return m_stream_up.get(); + } + + void SetCallback(std::function<void()> callback) { + m_callback = std::move(callback); + } + + void Keep() override { m_callback(); } + + void Discard() override { m_callback(); } + + static char ID; + +private: + std::function<void()> m_callback; + std::unique_ptr<raw_fd_ostream> m_stream_up; +}; + +char ProcessGDBRemoteProvider::ID = 0; + +} // namespace // TODO Randomly assigning a port is unsafe. We should get an unused // ephemeral port from the kernel and make sure we reserve it before passing it @@ -234,7 +268,7 @@ bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp, case ObjectFile::eTypeUnknown: break; } - return exe_module->GetFileSpec().Exists(); + return FileSystem::Instance().Exists(exe_module->GetFileSpec()); } // However, if there is no executable module, we return true since we might // be preparing to attach. @@ -259,8 +293,8 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, m_addr_to_mmap_size(), m_thread_create_bp_sp(), m_waiting_for_attach(false), m_destroy_tried_resuming(false), m_command_sp(), m_breakpoint_pc_offset(0), - m_initial_tid(LLDB_INVALID_THREAD_ID), m_allow_flash_writes(false), - m_erased_flash_ranges() { + m_initial_tid(LLDB_INVALID_THREAD_ID), m_replay_mode(false), + m_allow_flash_writes(false), m_erased_flash_ranges() { m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, @@ -268,6 +302,15 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit, "async thread did exit"); + if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { + ProcessGDBRemoteProvider &provider = + g->GetOrCreate<ProcessGDBRemoteProvider>(); + // Set the history stream to the stream owned by the provider. + m_gdb_comm.SetHistoryStream(provider.GetHistoryStream()); + // Make sure to clear the stream again when we're finished. + provider.SetCallback([&]() { m_gdb_comm.SetHistoryStream(nullptr); }); + } + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_ASYNC)); const uint32_t async_event_mask = @@ -440,10 +483,10 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile(); - if (!target_definition_fspec.Exists()) { + if (!FileSystem::Instance().Exists(target_definition_fspec)) { // If the filename doesn't exist, it may be a ~ not having been expanded - // try to resolve it. - target_definition_fspec.ResolvePath(); + FileSystem::Instance().Resolve(target_definition_fspec); } if (target_definition_fspec) { // See if we can get register definitions from a python file @@ -640,7 +683,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { m_register_info.Finalize(GetTarget().GetArchitecture()); } -Status ProcessGDBRemote::WillLaunch(Module *module) { +Status ProcessGDBRemote::WillLaunch(lldb_private::Module *module) { return WillLaunchOrAttach(); } @@ -689,7 +732,9 @@ Status ProcessGDBRemote::DoConnectRemote(Stream *strm, if (m_gdb_comm.GetProcessArchitecture().IsValid()) { target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); } else { - target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); + if (m_gdb_comm.GetHostArchitecture().IsValid()) { + target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); + } } } @@ -754,7 +799,7 @@ Status ProcessGDBRemote::WillLaunchOrAttach() { //---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- -Status ProcessGDBRemote::DoLaunch(Module *exe_module, +Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, ProcessLaunchInfo &launch_info) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); Status error; @@ -824,13 +869,13 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module, if (disable_stdio) { // set to /dev/null unless redirected to a file above if (!stdin_file_spec) - stdin_file_spec.SetFile(FileSystem::DEV_NULL, false, + stdin_file_spec.SetFile(FileSystem::DEV_NULL, FileSpec::Style::native); if (!stdout_file_spec) - stdout_file_spec.SetFile(FileSystem::DEV_NULL, false, + stdout_file_spec.SetFile(FileSystem::DEV_NULL, FileSpec::Style::native); if (!stderr_file_spec) - stderr_file_spec.SetFile(FileSystem::DEV_NULL, false, + stderr_file_spec.SetFile(FileSystem::DEV_NULL, FileSpec::Style::native); } else if (platform_sp && platform_sp->IsHost()) { // If the debugserver is local and we aren't disabling STDIO, lets use @@ -839,7 +884,7 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module, // does a lot of output. if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) && pty.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, NULL, 0)) { - FileSpec slave_name{pty.GetSlaveName(NULL, 0), false}; + FileSpec slave_name{pty.GetSlaveName(NULL, 0)}; if (!stdin_file_spec) stdin_file_spec = slave_name; @@ -1058,9 +1103,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { if (log) log->Printf("ProcessGDBRemote::%s gdb-remote had process architecture, " "using %s %s", - __FUNCTION__, process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "<null>", + __FUNCTION__, + process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "<null>", process_arch.GetTriple().getTriple().c_str() ? process_arch.GetTriple().getTriple().c_str() : "<null>"); @@ -1069,9 +1115,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { if (log) log->Printf("ProcessGDBRemote::%s gdb-remote did not have process " "architecture, using gdb-remote host architecture %s %s", - __FUNCTION__, process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "<null>", + __FUNCTION__, + process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "<null>", process_arch.GetTriple().getTriple().c_str() ? process_arch.GetTriple().getTriple().c_str() : "<null>"); @@ -1083,9 +1130,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { if (log) log->Printf( "ProcessGDBRemote::%s analyzing target arch, currently %s %s", - __FUNCTION__, target_arch.GetArchitectureName() - ? target_arch.GetArchitectureName() - : "<null>", + __FUNCTION__, + target_arch.GetArchitectureName() + ? target_arch.GetArchitectureName() + : "<null>", target_arch.GetTriple().getTriple().c_str() ? target_arch.GetTriple().getTriple().c_str() : "<null>"); @@ -1105,9 +1153,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { if (log) log->Printf("ProcessGDBRemote::%s remote process is ARM/Apple, " "setting target arch to %s %s", - __FUNCTION__, process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "<null>", + __FUNCTION__, + process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "<null>", process_arch.GetTriple().getTriple().c_str() ? process_arch.GetTriple().getTriple().c_str() : "<null>"); @@ -1135,9 +1184,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { if (log) log->Printf("ProcessGDBRemote::%s final target arch after " "adjustments for remote architecture: %s %s", - __FUNCTION__, target_arch.GetArchitectureName() - ? target_arch.GetArchitectureName() - : "<null>", + __FUNCTION__, + target_arch.GetArchitectureName() + ? target_arch.GetArchitectureName() + : "<null>", target_arch.GetTriple().getTriple().c_str() ? target_arch.GetTriple().getTriple().c_str() : "<null>"); @@ -1478,7 +1528,7 @@ Status ProcessGDBRemote::DoResume() { new EventDataBytes(continue_packet.GetString().data(), continue_packet.GetSize())); - if (listener_sp->GetEvent(event_sp, std::chrono::seconds(5)) == false) { + if (!listener_sp->GetEvent(event_sp, std::chrono::seconds(5))) { error.SetErrorString("Resume timed out."); if (log) log->Printf("ProcessGDBRemote::DoResume: Resume timed out."); @@ -1832,7 +1882,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( bool handled = false; bool did_exec = false; if (!reason.empty()) { - if (reason.compare("trace") == 0) { + if (reason == "trace") { addr_t pc = thread_sp->GetRegisterContext()->GetPC(); lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() ->GetBreakpointSiteList() @@ -1850,7 +1900,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( thread_sp->SetStopInfo( StopInfo::CreateStopReasonToTrace(*thread_sp)); handled = true; - } else if (reason.compare("breakpoint") == 0) { + } else if (reason == "breakpoint") { addr_t pc = thread_sp->GetRegisterContext()->GetPC(); lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess() ->GetBreakpointSiteList() @@ -1871,9 +1921,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( thread_sp->SetStopInfo(invalid_stop_info_sp); } } - } else if (reason.compare("trap") == 0) { + } else if (reason == "trap") { // Let the trap just use the standard signal stop reason below... - } else if (reason.compare("watchpoint") == 0) { + } else if (reason == "watchpoint") { StringExtractor desc_extractor(description.c_str()); addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32); @@ -1905,11 +1955,11 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID( *thread_sp, watch_id, wp_hit_addr)); handled = true; - } else if (reason.compare("exception") == 0) { + } else if (reason == "exception") { thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException( *thread_sp, description.c_str())); handled = true; - } else if (reason.compare("exec") == 0) { + } else if (reason == "exec") { did_exec = true; thread_sp->SetStopInfo( StopInfo::CreateStopReasonWithExec(*thread_sp)); @@ -1934,7 +1984,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( } } - if (!handled && signo && did_exec == false) { + if (!handled && signo && !did_exec) { if (signo == SIGTRAP) { // Currently we are going to assume SIGTRAP means we are either // hitting a breakpoint or hardware single stepping. @@ -2648,7 +2698,7 @@ void ProcessGDBRemote::SetLastStopPacket( // We are are not using non-stop mode, there can only be one last stop // reply packet, so clear the list. - if (GetTarget().GetNonStopModeEnabled() == false) + if (!GetTarget().GetNonStopModeEnabled()) m_stop_packet_stack.clear(); // Add this stop packet to the stop packet stack This stack will get popped @@ -3378,6 +3428,43 @@ Status ProcessGDBRemote::DoSignal(int signo) { return error; } +Status ProcessGDBRemote::ConnectToReplayServer(repro::Loader *loader) { + if (!loader) + return Status("No loader provided."); + + auto provider_info = loader->GetProviderInfo("gdb-remote"); + if (!provider_info) + return Status("No provider for gdb-remote."); + + if (provider_info->files.empty()) + return Status("Provider for gdb-remote contains no files."); + + // Construct replay history path. + FileSpec history_file = loader->GetRoot().CopyByAppendingPathComponent( + provider_info->files.front()); + + // Enable replay mode. + m_replay_mode = true; + + // Load replay history. + if (auto error = m_gdb_replay_server.LoadReplayHistory(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"); + + // Start server thread. + m_gdb_replay_server.StartAsyncThread(); + + // Start client thread. + StartAsyncThread(); + + // Do the usual setup. + return ConnectToDebugserver(""); +} + Status ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) { // Make sure we aren't already connected? @@ -3388,6 +3475,9 @@ 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); + auto error = LaunchAndConnectToDebugserver(process_info); if (error.Fail()) { const char *error_string = error.AsCString(); @@ -3497,7 +3587,7 @@ bool ProcessGDBRemote::MonitorDebugserverProcess( bool exited, // True if the process did exit int signo, // Zero for no signal int exit_status // Exit value of process if signal is zero - ) { +) { // "debugserver_pid" argument passed in is the process ID for debugserver // that we are tracking... Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); @@ -4269,8 +4359,9 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, return false; feature_node.ForEachChildElementWithName( - "reg", [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, - &abi_sp](const XMLNode ®_node) -> bool { + "reg", + [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, + &abi_sp](const XMLNode ®_node) -> bool { std::string gdb_group; std::string gdb_type; ConstString reg_name; @@ -4432,7 +4523,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, return true; } -} // namespace {} +} // namespace // query the target of gdb-remote for extended target information return: // 'true' on success @@ -4509,12 +4600,19 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { // <architecture>arm</architecture> (seen from Segger JLink on unspecified arm board) // use that if we don't have anything better. if (!arch_to_use.IsValid() && !target_info.arch.empty()) { - if (target_info.arch == "i386:x86-64") - { + if (target_info.arch == "i386:x86-64") { // We don't have any information about vendor or OS. arch_to_use.SetTriple("x86_64--"); GetTarget().MergeArchitecture(arch_to_use); } + + // SEGGER J-Link jtag boards send this very-generic arch name, + // we'll need to use this if we have absolutely nothing better + // to work with or the register definitions won't be accepted. + if (target_info.arch == "arm") { + arch_to_use.SetTriple("arm--"); + GetTarget().MergeArchitecture(arch_to_use); + } } // Initialize these outside of ParseRegisters, since they should not be @@ -4760,7 +4858,8 @@ size_t ProcessGDBRemote::LoadModules(LoadedModuleInfoList &module_list) { if (!modInfo.get_link_map(link_map)) link_map = LLDB_INVALID_ADDRESS; - FileSpec file(mod_name, true); + FileSpec file(mod_name); + FileSystem::Instance().Resolve(file); lldb::ModuleSP module_sp = LoadModuleAtAddress(file, link_map, mod_base, mod_base_is_offset); @@ -4802,7 +4901,7 @@ size_t ProcessGDBRemote::LoadModules(LoadedModuleInfoList &module_list) { return true; lldb::ModuleSP module_copy_sp = module_sp; - target.SetExecutableModule(module_copy_sp, false); + target.SetExecutableModule(module_copy_sp, eLoadDependentsNo); return false; }); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 45bb2d4c28e7..14a5237e4345 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -10,15 +10,12 @@ #ifndef liblldb_ProcessGDBRemote_h_ #define liblldb_ProcessGDBRemote_h_ -// C Includes -// C++ Includes #include <atomic> #include <map> #include <mutex> #include <string> #include <vector> -#include "lldb/Core/Broadcaster.h" #include "lldb/Core/LoadedModuleInfoList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ThreadSafeValue.h" @@ -26,6 +23,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamGDBRemote.h" @@ -36,11 +34,15 @@ #include "lldb/lldb-private-forward.h" #include "GDBRemoteCommunicationClient.h" +#include "GDBRemoteCommunicationReplayServer.h" #include "GDBRemoteRegisterContext.h" #include "llvm/ADT/DenseMap.h" namespace lldb_private { +namespace repro { +class Loader; +} namespace process_gdb_remote { class ThreadGDBRemote; @@ -264,6 +266,7 @@ protected: }; GDBRemoteCommunicationClient m_gdb_comm; + GDBRemoteCommunicationReplayServer m_gdb_replay_server; std::atomic<lldb::pid_t> m_debugserver_pid; std::vector<StringExtractorGDBRemote> m_stop_packet_stack; // The stop packet // stack replaces @@ -304,6 +307,7 @@ protected: int64_t m_breakpoint_pc_offset; lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach + bool m_replay_mode; bool m_allow_flash_writes; using FlashRangeVector = lldb_private::RangeVector<lldb::addr_t, size_t>; using FlashRange = FlashRangeVector::Entry; @@ -331,6 +335,8 @@ protected: bool UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) override; + Status ConnectToReplayServer(repro::Loader *loader); + Status EstablishConnectionIfNeeded(const ProcessInfo &process_info); Status LaunchAndConnectToDebugserver(const ProcessInfo &process_info); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h index 3c5801176690..d4981df88d8d 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h @@ -10,11 +10,7 @@ #ifndef liblldb_ProcessGDBRemoteLog_h_ #define liblldb_ProcessGDBRemoteLog_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Utility/Log.h" #define GDBR_LOG_PROCESS (1u << 1) diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index a525c16b9f13..db7dc3eae0ba 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -10,7 +10,6 @@ #include "ThreadGDBRemote.h" #include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Core/State.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -20,6 +19,7 @@ #include "lldb/Target/UnixSignals.h" #include "lldb/Target/Unwind.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "ProcessGDBRemote.h" @@ -197,13 +197,10 @@ void ThreadGDBRemote::SetQueueLibdispatchQueueAddress( } bool ThreadGDBRemote::ThreadHasQueueInformation() const { - if (m_thread_dispatch_qaddr != 0 && - m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS && - m_dispatch_queue_t != LLDB_INVALID_ADDRESS && - m_queue_kind != eQueueKindUnknown && m_queue_serial_number != 0) { - return true; - } - return false; + return m_thread_dispatch_qaddr != 0 && + m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS && + m_dispatch_queue_t != LLDB_INVALID_ADDRESS && + m_queue_kind != eQueueKindUnknown && m_queue_serial_number != 0; } LazyBool ThreadGDBRemote::GetAssociatedWithLibdispatchQueue() { diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index 1a5b60aea288..4485a9cdc4c3 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -10,12 +10,8 @@ #ifndef liblldb_ThreadGDBRemote_h_ #define liblldb_ThreadGDBRemote_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/StructuredData.h" diff --git a/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/source/Plugins/Process/mach-core/ProcessMachCore.cpp index bfa35ed506a9..08b9f08a47f6 100644 --- a/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ b/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -8,38 +8,33 @@ // //===----------------------------------------------------------------------===// -// C Includes #include <errno.h> #include <stdlib.h> -// C++ Includes #include "llvm/Support/MathExtras.h" #include "llvm/Support/Threading.h" #include <mutex> -// Other libraries and framework includes #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Core/State.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBuffer.h" -#include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" -// Project includes #include "ProcessMachCore.h" #include "Plugins/Process/Utility/StopInfoMachException.h" #include "ThreadMachCore.h" // Needed for the plug-in names for the dynamic loaders. -#include "lldb/Utility/SafeMachO.h" +#include "lldb/Host/SafeMachO.h" #include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h" #include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h" @@ -67,8 +62,8 @@ lldb::ProcessSP ProcessMachCore::CreateInstance(lldb::TargetSP target_sp, lldb::ProcessSP process_sp; if (crash_file) { const size_t header_size = sizeof(llvm::MachO::mach_header); - auto data_sp = - DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), header_size, 0); + auto data_sp = FileSystem::Instance().CreateDataBuffer( + crash_file->GetPath(), header_size, 0); if (data_sp && data_sp->GetByteSize() == header_size) { DataExtractor data(data_sp, lldb::eByteOrderLittle, 4); @@ -90,7 +85,7 @@ bool ProcessMachCore::CanDebug(lldb::TargetSP target_sp, return true; // For now we are just making sure the file exists for a given module - if (!m_core_module_sp && m_core_file.Exists()) { + if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) { // Don't add the Target's architecture to the ModuleSpec - we may be // working with a core file that doesn't have the correct cpusubtype in the // header but we should still try to use it - @@ -307,36 +302,38 @@ Status ProcessMachCore::DoLoadCore() { // LC_IDENT is very obsolete and should not be used in new code, but if the // load command is present, let's use the contents. std::string corefile_identifier = core_objfile->GetIdentifierString(); - if (found_main_binary_definitively == false - && corefile_identifier.find("Darwin Kernel") != std::string::npos) { - UUID uuid; - addr_t addr = LLDB_INVALID_ADDRESS; - if (corefile_identifier.find("UUID=") != std::string::npos) { - size_t p = corefile_identifier.find("UUID=") + strlen("UUID="); - std::string uuid_str = corefile_identifier.substr(p, 36); - uuid.SetFromStringRef(uuid_str); - } - if (corefile_identifier.find("stext=") != std::string::npos) { - size_t p = corefile_identifier.find("stext=") + strlen("stext="); - if (corefile_identifier[p] == '0' && corefile_identifier[p + 1] == 'x') { - errno = 0; - addr = ::strtoul(corefile_identifier.c_str() + p, NULL, 16); - if (errno != 0 || addr == 0) - addr = LLDB_INVALID_ADDRESS; - } - } - if (uuid.IsValid() && addr != LLDB_INVALID_ADDRESS) { - m_mach_kernel_addr = addr; - found_main_binary_definitively = true; - if (log) - log->Printf("ProcessMachCore::DoLoadCore: Using the kernel address 0x%" PRIx64 - " from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'", addr, corefile_identifier.c_str()); + if (!found_main_binary_definitively && + corefile_identifier.find("Darwin Kernel") != std::string::npos) { + UUID uuid; + addr_t addr = LLDB_INVALID_ADDRESS; + if (corefile_identifier.find("UUID=") != std::string::npos) { + size_t p = corefile_identifier.find("UUID=") + strlen("UUID="); + std::string uuid_str = corefile_identifier.substr(p, 36); + uuid.SetFromStringRef(uuid_str); + } + if (corefile_identifier.find("stext=") != std::string::npos) { + size_t p = corefile_identifier.find("stext=") + strlen("stext="); + if (corefile_identifier[p] == '0' && corefile_identifier[p + 1] == 'x') { + errno = 0; + addr = ::strtoul(corefile_identifier.c_str() + p, NULL, 16); + if (errno != 0 || addr == 0) + addr = LLDB_INVALID_ADDRESS; } + } + if (uuid.IsValid() && addr != LLDB_INVALID_ADDRESS) { + m_mach_kernel_addr = addr; + found_main_binary_definitively = true; + if (log) + log->Printf( + "ProcessMachCore::DoLoadCore: Using the kernel address 0x%" PRIx64 + " from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'", + addr, corefile_identifier.c_str()); + } } - if (found_main_binary_definitively == false - && (m_dyld_addr == LLDB_INVALID_ADDRESS - || m_mach_kernel_addr == LLDB_INVALID_ADDRESS)) { + if (!found_main_binary_definitively && + (m_dyld_addr == LLDB_INVALID_ADDRESS || + m_mach_kernel_addr == LLDB_INVALID_ADDRESS)) { // We need to locate the main executable in the memory ranges we have in // the core file. We need to search for both a user-process dyld binary // and a kernel binary in memory; we must look at all the pages in the @@ -357,16 +354,15 @@ Status ProcessMachCore::DoLoadCore() { } } - if (found_main_binary_definitively == false - && m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { + if (!found_main_binary_definitively && + m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { // In the case of multiple kernel images found in the core file via // exhaustive search, we may not pick the correct one. See if the // DynamicLoaderDarwinKernel's search heuristics might identify the correct // one. Most of the time, I expect the address from SearchForDarwinKernel() // will be the same as the address we found via exhaustive search. - if (GetTarget().GetArchitecture().IsValid() == false && - m_core_module_sp.get()) { + if (!GetTarget().GetArchitecture().IsValid() && m_core_module_sp.get()) { GetTarget().SetArchitecture(m_core_module_sp->GetArchitecture()); } diff --git a/source/Plugins/Process/mach-core/ProcessMachCore.h b/source/Plugins/Process/mach-core/ProcessMachCore.h index 101df6b79115..0c6fc693a50c 100644 --- a/source/Plugins/Process/mach-core/ProcessMachCore.h +++ b/source/Plugins/Process/mach-core/ProcessMachCore.h @@ -10,13 +10,9 @@ #ifndef liblldb_ProcessMachCore_h_ #define liblldb_ProcessMachCore_h_ -// C Includes -// C++ Includes #include <list> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Target/Process.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" diff --git a/source/Plugins/Process/mach-core/ThreadMachCore.cpp b/source/Plugins/Process/mach-core/ThreadMachCore.cpp index c262dd47f978..16edd28f1a13 100644 --- a/source/Plugins/Process/mach-core/ThreadMachCore.cpp +++ b/source/Plugins/Process/mach-core/ThreadMachCore.cpp @@ -9,10 +9,7 @@ #include "ThreadMachCore.h" -#include "lldb/Utility/SafeMachO.h" - #include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Core/State.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -21,6 +18,7 @@ #include "lldb/Target/Unwind.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "ProcessMachCore.h" diff --git a/source/Plugins/Process/mach-core/ThreadMachCore.h b/source/Plugins/Process/mach-core/ThreadMachCore.h index a4db484e850f..696ba7294e4a 100644 --- a/source/Plugins/Process/mach-core/ThreadMachCore.h +++ b/source/Plugins/Process/mach-core/ThreadMachCore.h @@ -10,12 +10,8 @@ #ifndef liblldb_ThreadMachCore_h_ #define liblldb_ThreadMachCore_h_ -// C Includes -// C++ Includes #include <string> -// Other libraries and framework includes -// Project includes #include "lldb/Target/Thread.h" class ProcessMachCore; diff --git a/source/Plugins/Process/minidump/CMakeLists.txt b/source/Plugins/Process/minidump/CMakeLists.txt index b898ee1aa144..4126a7ea991c 100644 --- a/source/Plugins/Process/minidump/CMakeLists.txt +++ b/source/Plugins/Process/minidump/CMakeLists.txt @@ -1,6 +1,8 @@ add_lldb_library(lldbPluginProcessMinidump PLUGIN MinidumpTypes.cpp MinidumpParser.cpp + RegisterContextMinidump_ARM.cpp + RegisterContextMinidump_ARM64.cpp RegisterContextMinidump_x86_32.cpp RegisterContextMinidump_x86_64.cpp ProcessMinidump.cpp diff --git a/source/Plugins/Process/minidump/MinidumpParser.cpp b/source/Plugins/Process/minidump/MinidumpParser.cpp index 9a979335e99e..d4053ca70b94 100644 --- a/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -7,20 +7,19 @@ // //===----------------------------------------------------------------------===// -// Project includes #include "MinidumpParser.h" #include "NtStructures.h" #include "RegisterContextMinidump_x86_32.h" -// Other libraries and framework includes -#include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Utility/LLDBAssert.h" +#include "Plugins/Process/Utility/LinuxProcMaps.h" // C includes // C++ includes #include <algorithm> #include <map> #include <vector> +#include <utility> using namespace lldb_private; using namespace minidump; @@ -80,8 +79,18 @@ UUID MinidumpParser::GetModuleUUID(const MinidumpModule *module) { // PDB70 record const CvRecordPdb70 *pdb70_uuid = nullptr; Status error = consumeObject(cv_record, pdb70_uuid); - if (!error.Fail()) - return UUID::fromData(pdb70_uuid, sizeof(*pdb70_uuid)); + if (!error.Fail()) { + auto arch = GetArchitecture(); + // For Apple targets we only need a 16 byte UUID so that we can match + // the UUID in the Module to actual UUIDs from the built binaries. The + // "Age" field is zero in breakpad minidump files for Apple targets, so + // we restrict the UUID to the "Uuid" field so we have a UUID we can use + // to match. + if (arch.GetTriple().getVendor() == llvm::Triple::Apple) + return UUID::fromData(pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid)); + else + return UUID::fromData(pdb70_uuid, sizeof(*pdb70_uuid)); + } } else if (cv_signature == CvSignature::ElfBuildId) return UUID::fromData(cv_record); @@ -98,11 +107,15 @@ llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() { } llvm::ArrayRef<uint8_t> -MinidumpParser::GetThreadContext(const MinidumpThread &td) { - if (td.thread_context.rva + td.thread_context.data_size > GetData().size()) +MinidumpParser::GetThreadContext(const MinidumpLocationDescriptor &location) { + if (location.rva + location.data_size > GetData().size()) return {}; + return GetData().slice(location.rva, location.data_size); +} - return GetData().slice(td.thread_context.rva, td.thread_context.data_size); +llvm::ArrayRef<uint8_t> +MinidumpParser::GetThreadContext(const MinidumpThread &td) { + return GetThreadContext(td.thread_context); } llvm::ArrayRef<uint8_t> @@ -146,11 +159,14 @@ const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() { } ArchSpec MinidumpParser::GetArchitecture() { - ArchSpec arch_spec; + if (m_arch.IsValid()) + return m_arch; + + // Set the architecture in m_arch const MinidumpSystemInfo *system_info = GetSystemInfo(); if (!system_info) - return arch_spec; + return m_arch; // TODO what to do about big endiand flavors of arm ? // TODO set the arm subarch stuff if the minidump has info about it @@ -196,19 +212,28 @@ ArchSpec MinidumpParser::GetArchitecture() { break; case MinidumpOSPlatform::MacOSX: triple.setOS(llvm::Triple::OSType::MacOSX); + triple.setVendor(llvm::Triple::Apple); + break; + case MinidumpOSPlatform::IOS: + triple.setOS(llvm::Triple::OSType::IOS); + triple.setVendor(llvm::Triple::Apple); break; case MinidumpOSPlatform::Android: triple.setOS(llvm::Triple::OSType::Linux); triple.setEnvironment(llvm::Triple::EnvironmentType::Android); break; - default: + default: { triple.setOS(llvm::Triple::OSType::UnknownOS); + std::string csd_version; + if (auto s = GetMinidumpString(system_info->csd_version_rva)) + csd_version = *s; + if (csd_version.find("Linux") != std::string::npos) + triple.setOS(llvm::Triple::OSType::Linux); break; + } } - - arch_spec.SetTriple(triple); - - return arch_spec; + m_arch.SetTriple(triple); + return m_arch; } const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() { @@ -254,36 +279,45 @@ llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() { std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() { llvm::ArrayRef<MinidumpModule> modules = GetModuleList(); - // map module_name -> pair(load_address, pointer to module struct in memory) - llvm::StringMap<std::pair<uint64_t, const MinidumpModule *>> lowest_addr; + // map module_name -> filtered_modules index + typedef llvm::StringMap<size_t> MapType; + MapType module_name_to_filtered_index; std::vector<const MinidumpModule *> filtered_modules; - + llvm::Optional<std::string> name; std::string module_name; for (const auto &module : modules) { name = GetMinidumpString(module.module_name_rva); - + if (!name) continue; - + module_name = name.getValue(); - - auto iter = lowest_addr.end(); - bool exists; - std::tie(iter, exists) = lowest_addr.try_emplace( - module_name, std::make_pair(module.base_of_image, &module)); - - if (exists && module.base_of_image < iter->second.first) - iter->second = std::make_pair(module.base_of_image, &module); - } - - filtered_modules.reserve(lowest_addr.size()); - for (const auto &module : lowest_addr) { - filtered_modules.push_back(module.second.second); + + MapType::iterator iter; + bool inserted; + // See if we have inserted this module aready into filtered_modules. If we + // haven't insert an entry into module_name_to_filtered_index with the + // index where we will insert it if it isn't in the vector already. + std::tie(iter, inserted) = module_name_to_filtered_index.try_emplace( + module_name, filtered_modules.size()); + + if (inserted) { + // This module has not been seen yet, insert it into filtered_modules at + // the index that was inserted into module_name_to_filtered_index using + // "filtered_modules.size()" above. + filtered_modules.push_back(&module); + } else { + // This module has been seen. Modules are sometimes mentioned multiple + // times when they are mapped discontiguously, so find the module with + // the lowest "base_of_image" and use that as the filtered module. + auto dup_module = filtered_modules[iter->second]; + if (module.base_of_image < dup_module->base_of_image) + filtered_modules[iter->second] = &module; + } } - return filtered_modules; } @@ -381,72 +415,153 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr, return range->range_ref.slice(offset, overlap); } -llvm::Optional<MemoryRegionInfo> -MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) { - MemoryRegionInfo info; - llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList); +static bool +CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser, + std::vector<MemoryRegionInfo> ®ions) { + auto data = parser.GetStream(MinidumpStreamType::LinuxMaps); if (data.empty()) - return llvm::None; + return false; + ParseLinuxMapRegions(llvm::toStringRef(data), + [&](const lldb_private::MemoryRegionInfo ®ion, + const lldb_private::Status &status) -> bool { + if (status.Success()) + regions.push_back(region); + return true; + }); + return !regions.empty(); +} - std::vector<const MinidumpMemoryInfo *> mem_info_list = - MinidumpMemoryInfo::ParseMemoryInfoList(data); +static bool +CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser, + std::vector<MemoryRegionInfo> ®ions) { + auto data = parser.GetStream(MinidumpStreamType::MemoryInfoList); + if (data.empty()) + return false; + auto mem_info_list = MinidumpMemoryInfo::ParseMemoryInfoList(data); if (mem_info_list.empty()) - return llvm::None; + return false; + constexpr auto yes = MemoryRegionInfo::eYes; + constexpr auto no = MemoryRegionInfo::eNo; + regions.reserve(mem_info_list.size()); + for (const auto &entry : mem_info_list) { + MemoryRegionInfo region; + region.GetRange().SetRangeBase(entry->base_address); + region.GetRange().SetByteSize(entry->region_size); + region.SetReadable(entry->isReadable() ? yes : no); + region.SetWritable(entry->isWritable() ? yes : no); + region.SetExecutable(entry->isExecutable() ? yes : no); + region.SetMapped(entry->isMapped() ? yes : no); + regions.push_back(region); + } + return !regions.empty(); +} - const auto yes = MemoryRegionInfo::eYes; - const auto no = MemoryRegionInfo::eNo; +static bool +CreateRegionsCacheFromMemoryList(MinidumpParser &parser, + std::vector<MemoryRegionInfo> ®ions) { + auto data = parser.GetStream(MinidumpStreamType::MemoryList); + if (data.empty()) + return false; + auto memory_list = MinidumpMemoryDescriptor::ParseMemoryList(data); + if (memory_list.empty()) + return false; + regions.reserve(memory_list.size()); + for (const auto &memory_desc : memory_list) { + if (memory_desc.memory.data_size == 0) + continue; + MemoryRegionInfo region; + region.GetRange().SetRangeBase(memory_desc.start_of_memory_range); + region.GetRange().SetByteSize(memory_desc.memory.data_size); + region.SetReadable(MemoryRegionInfo::eYes); + region.SetMapped(MemoryRegionInfo::eYes); + regions.push_back(region); + } + regions.shrink_to_fit(); + return !regions.empty(); +} - const MinidumpMemoryInfo *next_entry = nullptr; - for (const auto &entry : mem_info_list) { - const auto head = entry->base_address; - const auto tail = head + entry->region_size; - - if (head <= load_addr && load_addr < tail) { - info.GetRange().SetRangeBase( - (entry->state != uint32_t(MinidumpMemoryInfoState::MemFree)) - ? head - : load_addr); - info.GetRange().SetRangeEnd(tail); - - const uint32_t PageNoAccess = - static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageNoAccess); - info.SetReadable((entry->protect & PageNoAccess) == 0 ? yes : no); - - const uint32_t PageWritable = - static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable); - info.SetWritable((entry->protect & PageWritable) != 0 ? yes : no); - - const uint32_t PageExecutable = static_cast<uint32_t>( - MinidumpMemoryProtectionContants::PageExecutable); - info.SetExecutable((entry->protect & PageExecutable) != 0 ? yes : no); - - const uint32_t MemFree = - static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree); - info.SetMapped((entry->state != MemFree) ? yes : no); - - return info; - } else if (head > load_addr && - (next_entry == nullptr || head < next_entry->base_address)) { - // In case there is no region containing load_addr keep track of the - // nearest region after load_addr so we can return the distance to it. - next_entry = entry; - } +static bool +CreateRegionsCacheFromMemory64List(MinidumpParser &parser, + std::vector<MemoryRegionInfo> ®ions) { + llvm::ArrayRef<uint8_t> data = + parser.GetStream(MinidumpStreamType::Memory64List); + if (data.empty()) + return false; + llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list; + uint64_t base_rva; + std::tie(memory64_list, base_rva) = + MinidumpMemoryDescriptor64::ParseMemory64List(data); + + if (memory64_list.empty()) + return false; + + regions.reserve(memory64_list.size()); + for (const auto &memory_desc : memory64_list) { + if (memory_desc.data_size == 0) + continue; + MemoryRegionInfo region; + region.GetRange().SetRangeBase(memory_desc.start_of_memory_range); + region.GetRange().SetByteSize(memory_desc.data_size); + region.SetReadable(MemoryRegionInfo::eYes); + region.SetMapped(MemoryRegionInfo::eYes); + regions.push_back(region); } + regions.shrink_to_fit(); + return !regions.empty(); +} + +MemoryRegionInfo +MinidumpParser::FindMemoryRegion(lldb::addr_t load_addr) const { + auto begin = m_regions.begin(); + auto end = m_regions.end(); + auto pos = std::lower_bound(begin, end, load_addr); + if (pos != end && pos->GetRange().Contains(load_addr)) + return *pos; + + MemoryRegionInfo region; + if (pos == begin) + region.GetRange().SetRangeBase(0); + else { + auto prev = pos - 1; + if (prev->GetRange().Contains(load_addr)) + return *prev; + region.GetRange().SetRangeBase(prev->GetRange().GetRangeEnd()); + } + if (pos == end) + region.GetRange().SetRangeEnd(UINT64_MAX); + else + region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase()); + region.SetReadable(MemoryRegionInfo::eNo); + region.SetWritable(MemoryRegionInfo::eNo); + region.SetExecutable(MemoryRegionInfo::eNo); + region.SetMapped(MemoryRegionInfo::eNo); + return region; +} - // No containing region found. Create an unmapped region that extends to the - // next region or LLDB_INVALID_ADDRESS - info.GetRange().SetRangeBase(load_addr); - info.GetRange().SetRangeEnd((next_entry != nullptr) ? next_entry->base_address - : LLDB_INVALID_ADDRESS); - info.SetReadable(no); - info.SetWritable(no); - info.SetExecutable(no); - info.SetMapped(no); - - // Note that the memory info list doesn't seem to contain ranges in kernel - // space, so if you're walking a stack that has kernel frames, the stack may - // appear truncated. - return info; +MemoryRegionInfo +MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) { + if (!m_parsed_regions) + GetMemoryRegions(); + return FindMemoryRegion(load_addr); +} + +const MemoryRegionInfos &MinidumpParser::GetMemoryRegions() { + if (!m_parsed_regions) { + m_parsed_regions = true; + // We haven't cached our memory regions yet we will create the region cache + // once. We create the region cache using the best source. We start with + // the linux maps since they are the most complete and have names for the + // regions. Next we try the MemoryInfoList since it has + // read/write/execute/map data, and then fall back to the MemoryList and + // Memory64List to just get a list of the memory that is mapped in this + // core file + if (!CreateRegionsCacheFromLinuxMaps(*this, m_regions)) + if (!CreateRegionsCacheFromMemoryInfoList(*this, m_regions)) + if (!CreateRegionsCacheFromMemoryList(*this, m_regions)) + CreateRegionsCacheFromMemory64List(*this, m_regions); + llvm::sort(m_regions.begin(), m_regions.end()); + } + return m_regions; } Status MinidumpParser::Initialize() { @@ -531,10 +646,10 @@ Status MinidumpParser::Initialize() { } // Sort the file map ranges by start offset - std::sort(minidump_map.begin(), minidump_map.end(), - [](const FileRange &a, const FileRange &b) { - return a.offset < b.offset; - }); + llvm::sort(minidump_map.begin(), minidump_map.end(), + [](const FileRange &a, const FileRange &b) { + return a.offset < b.offset; + }); // Check for overlapping streams/data structures for (size_t i = 1; i < minidump_map.size(); ++i) { @@ -554,3 +669,48 @@ Status MinidumpParser::Initialize() { return error; } + +#define ENUM_TO_CSTR(ST) case (uint32_t)MinidumpStreamType::ST: return #ST + +llvm::StringRef +MinidumpParser::GetStreamTypeAsString(uint32_t stream_type) { + switch (stream_type) { + ENUM_TO_CSTR(Unused); + ENUM_TO_CSTR(Reserved0); + ENUM_TO_CSTR(Reserved1); + ENUM_TO_CSTR(ThreadList); + ENUM_TO_CSTR(ModuleList); + ENUM_TO_CSTR(MemoryList); + ENUM_TO_CSTR(Exception); + ENUM_TO_CSTR(SystemInfo); + ENUM_TO_CSTR(ThreadExList); + ENUM_TO_CSTR(Memory64List); + ENUM_TO_CSTR(CommentA); + ENUM_TO_CSTR(CommentW); + ENUM_TO_CSTR(HandleData); + ENUM_TO_CSTR(FunctionTable); + ENUM_TO_CSTR(UnloadedModuleList); + ENUM_TO_CSTR(MiscInfo); + ENUM_TO_CSTR(MemoryInfoList); + ENUM_TO_CSTR(ThreadInfoList); + ENUM_TO_CSTR(HandleOperationList); + ENUM_TO_CSTR(Token); + ENUM_TO_CSTR(JavascriptData); + ENUM_TO_CSTR(SystemMemoryInfo); + ENUM_TO_CSTR(ProcessVMCounters); + ENUM_TO_CSTR(BreakpadInfo); + ENUM_TO_CSTR(AssertionInfo); + ENUM_TO_CSTR(LinuxCPUInfo); + ENUM_TO_CSTR(LinuxProcStatus); + ENUM_TO_CSTR(LinuxLSBRelease); + ENUM_TO_CSTR(LinuxCMDLine); + ENUM_TO_CSTR(LinuxEnviron); + ENUM_TO_CSTR(LinuxAuxv); + ENUM_TO_CSTR(LinuxMaps); + ENUM_TO_CSTR(LinuxDSODebug); + ENUM_TO_CSTR(LinuxProcStat); + ENUM_TO_CSTR(LinuxProcUptime); + ENUM_TO_CSTR(LinuxProcFD); + } + return "unknown stream type"; +} diff --git a/source/Plugins/Process/minidump/MinidumpParser.h b/source/Plugins/Process/minidump/MinidumpParser.h index 49b1eef14de5..07ea6aa908ff 100644 --- a/source/Plugins/Process/minidump/MinidumpParser.h +++ b/source/Plugins/Process/minidump/MinidumpParser.h @@ -1,5 +1,4 @@ -//===-- MinidumpParser.h -----------------------------------------*- C++ -//-*-===// +//===-- MinidumpParser.h -----------------------------------------*- C++-*-===// // // The LLVM Compiler Infrastructure // @@ -11,9 +10,9 @@ #ifndef liblldb_MinidumpParser_h_ #define liblldb_MinidumpParser_h_ -// Project includes #include "MinidumpTypes.h" +#include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/Status.h" @@ -59,6 +58,9 @@ public: llvm::ArrayRef<MinidumpThread> GetThreads(); + llvm::ArrayRef<uint8_t> + GetThreadContext(const MinidumpLocationDescriptor &location); + llvm::ArrayRef<uint8_t> GetThreadContext(const MinidumpThread &td); llvm::ArrayRef<uint8_t> GetThreadContextWow64(const MinidumpThread &td); @@ -87,17 +89,31 @@ public: llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size); - llvm::Optional<MemoryRegionInfo> GetMemoryRegionInfo(lldb::addr_t); + MemoryRegionInfo GetMemoryRegionInfo(lldb::addr_t load_addr); + + const MemoryRegionInfos &GetMemoryRegions(); // Perform consistency checks and initialize internal data structures Status Initialize(); + static llvm::StringRef GetStreamTypeAsString(uint32_t stream_type); + + const llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> & + GetDirectoryMap() const { + return m_directory_map; + } + private: MinidumpParser(const lldb::DataBufferSP &data_buf_sp); + MemoryRegionInfo FindMemoryRegion(lldb::addr_t load_addr) const; + private: lldb::DataBufferSP m_data_sp; llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> m_directory_map; + ArchSpec m_arch; + MemoryRegionInfos m_regions; + bool m_parsed_regions = false; }; } // end namespace minidump diff --git a/source/Plugins/Process/minidump/MinidumpTypes.cpp b/source/Plugins/Process/minidump/MinidumpTypes.cpp index 049704ba80ca..7b1900e34ef1 100644 --- a/source/Plugins/Process/minidump/MinidumpTypes.cpp +++ b/source/Plugins/Process/minidump/MinidumpTypes.cpp @@ -7,10 +7,8 @@ // //===----------------------------------------------------------------------===// -// Project includes #include "MinidumpTypes.h" -// Other libraries and framework includes // C includes // C++ includes @@ -244,6 +242,8 @@ MinidumpMemoryInfo::ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data) { return {}; std::vector<const MinidumpMemoryInfo *> result; + result.reserve(header->num_of_entries); + for (uint64_t i = 0; i < header->num_of_entries; ++i) { result.push_back(reinterpret_cast<const MinidumpMemoryInfo *>( data.data() + i * header->size_of_entry)); diff --git a/source/Plugins/Process/minidump/MinidumpTypes.h b/source/Plugins/Process/minidump/MinidumpTypes.h index e83089865b9e..a5ea215d2548 100644 --- a/source/Plugins/Process/minidump/MinidumpTypes.h +++ b/source/Plugins/Process/minidump/MinidumpTypes.h @@ -10,9 +10,7 @@ #ifndef liblldb_MinidumpTypes_h_ #define liblldb_MinidumpTypes_h_ -// Project includes -// Other libraries and framework includes #include "lldb/Utility/Status.h" #include "llvm/ADT/ArrayRef.h" @@ -98,7 +96,10 @@ enum class MinidumpStreamType : uint32_t { LinuxEnviron = 0x47670007, /* /proc/$x/environ */ LinuxAuxv = 0x47670008, /* /proc/$x/auxv */ LinuxMaps = 0x47670009, /* /proc/$x/maps */ - LinuxDSODebug = 0x4767000A + LinuxDSODebug = 0x4767000A, + LinuxProcStat = 0x4767000B, /* /proc/$x/stat */ + LinuxProcUptime = 0x4767000C, /* uptime */ + LinuxProcFD = 0x4767000D, /* /proc/$x/fb */ }; // for MinidumpSystemInfo.processor_arch @@ -258,25 +259,6 @@ struct MinidumpMemoryInfoListHeader { static_assert(sizeof(MinidumpMemoryInfoListHeader) == 16, "sizeof MinidumpMemoryInfoListHeader is not correct!"); -// Reference: -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680386(v=vs.85).aspx -struct MinidumpMemoryInfo { - llvm::support::ulittle64_t base_address; - llvm::support::ulittle64_t allocation_base; - llvm::support::ulittle32_t allocation_protect; - llvm::support::ulittle32_t alignment1; - llvm::support::ulittle64_t region_size; - llvm::support::ulittle32_t state; - llvm::support::ulittle32_t protect; - llvm::support::ulittle32_t type; - llvm::support::ulittle32_t alignment2; - - static std::vector<const MinidumpMemoryInfo *> - ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data); -}; -static_assert(sizeof(MinidumpMemoryInfo) == 48, - "sizeof MinidumpMemoryInfo is not correct!"); - enum class MinidumpMemoryInfoState : uint32_t { MemCommit = 0x1000, MemFree = 0x10000, @@ -313,6 +295,45 @@ enum class MinidumpMemoryProtectionContants : uint32_t { }; // Reference: +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680386(v=vs.85).aspx +struct MinidumpMemoryInfo { + llvm::support::ulittle64_t base_address; + llvm::support::ulittle64_t allocation_base; + llvm::support::ulittle32_t allocation_protect; + llvm::support::ulittle32_t alignment1; + llvm::support::ulittle64_t region_size; + llvm::support::ulittle32_t state; + llvm::support::ulittle32_t protect; + llvm::support::ulittle32_t type; + llvm::support::ulittle32_t alignment2; + + static std::vector<const MinidumpMemoryInfo *> + ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data); + + bool isReadable() const { + const auto mask = MinidumpMemoryProtectionContants::PageNoAccess; + return (static_cast<uint32_t>(mask) & protect) == 0; + } + + bool isWritable() const { + const auto mask = MinidumpMemoryProtectionContants::PageWritable; + return (static_cast<uint32_t>(mask) & protect) != 0; + } + + bool isExecutable() const { + const auto mask = MinidumpMemoryProtectionContants::PageExecutable; + return (static_cast<uint32_t>(mask) & protect) != 0; + } + + bool isMapped() const { + return state != static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree); + } +}; + +static_assert(sizeof(MinidumpMemoryInfo) == 48, + "sizeof MinidumpMemoryInfo is not correct!"); + +// Reference: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx struct MinidumpThread { llvm::support::ulittle32_t thread_id; diff --git a/source/Plugins/Process/minidump/ProcessMinidump.cpp b/source/Plugins/Process/minidump/ProcessMinidump.cpp index b43f22382eac..c5cca7ea62c6 100644 --- a/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -7,28 +7,34 @@ // //===----------------------------------------------------------------------===// -// Project includes #include "ProcessMinidump.h" #include "ThreadMinidump.h" -// Other libraries and framework includes +#include "lldb/Core/DumpDataExtractor.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Core/State.h" -#include "lldb/Target/DynamicLoader.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionGroupBoolean.h" +#include "lldb/Target/JITLoaderList.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" -#include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Threading.h" +#include "Plugins/Process/Utility/StopInfoMachException.h" + // C includes // C++ includes @@ -75,7 +81,7 @@ public: section_sp, module->base_of_image); } - ObjectFile *GetObjectFile() override { return nullptr; } +ObjectFile *GetObjectFile() override { return nullptr; } SectionList *GetSectionList() override { return Module::GetUnifiedSectionList(); @@ -100,8 +106,8 @@ lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, lldb::ProcessSP process_sp; // Read enough data for the Minidump header constexpr size_t header_size = sizeof(MinidumpHeader); - auto DataPtr = - DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), header_size, 0); + auto DataPtr = FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), + header_size, 0); if (!DataPtr) return nullptr; @@ -113,7 +119,8 @@ lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, if (header == nullptr) return nullptr; - auto AllData = DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), -1, 0); + auto AllData = + FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), -1, 0); if (!AllData) return nullptr; @@ -174,19 +181,21 @@ Status ProcessMinidump::DoLoadCore() { switch (arch.GetMachine()) { case llvm::Triple::x86: case llvm::Triple::x86_64: - // supported + case llvm::Triple::arm: + case llvm::Triple::aarch64: + // Any supported architectures must be listed here and also supported in + // ThreadMinidump::CreateRegisterContextForFrame(). break; - default: error.SetErrorStringWithFormat("unsupported minidump architecture: %s", arch.GetArchitectureName()); return error; } + GetTarget().SetArchitecture(arch, true /*set_platform*/); m_thread_list = m_minidump_parser.GetThreads(); m_active_exception = m_minidump_parser.GetExceptionStream(); ReadModuleList(); - GetTarget().SetArchitecture(arch); llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid(); if (!pid) { @@ -198,12 +207,6 @@ Status ProcessMinidump::DoLoadCore() { return error; } -DynamicLoader *ProcessMinidump::GetDynamicLoader() { - if (m_dyld_ap.get() == nullptr) - m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr)); - return m_dyld_ap.get(); -} - ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); } uint32_t ProcessMinidump::GetPluginVersion() { return 1; } @@ -229,6 +232,11 @@ void ProcessMinidump::RefreshStateAfterStop() { if (arch.GetTriple().getOS() == llvm::Triple::Linux) { stop_info = StopInfo::CreateStopReasonWithSignal( *stop_thread, m_active_exception->exception_record.exception_code); + } else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) { + stop_info = StopInfoMachException::CreateStopReasonWithMachException( + *stop_thread, m_active_exception->exception_record.exception_code, 2, + m_active_exception->exception_record.exception_flags, + m_active_exception->exception_record.exception_address, 0); } else { std::string desc; llvm::raw_string_ostream desc_stream(desc); @@ -284,33 +292,36 @@ ArchSpec ProcessMinidump::GetArchitecture() { Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info) { - Status error; - auto info = m_minidump_parser.GetMemoryRegionInfo(load_addr); - if (!info) { - error.SetErrorString("No valid MemoryRegionInfo found!"); - return error; - } - range_info = info.getValue(); - return error; + range_info = m_minidump_parser.GetMemoryRegionInfo(load_addr); + return Status(); +} + +Status ProcessMinidump::GetMemoryRegions( + lldb_private::MemoryRegionInfos ®ion_list) { + region_list = m_minidump_parser.GetMemoryRegions(); + return Status(); } void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); } bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) { - uint32_t num_threads = 0; - if (m_thread_list.size() > 0) - num_threads = m_thread_list.size(); + for (const MinidumpThread& thread : m_thread_list) { + MinidumpLocationDescriptor context_location = thread.thread_context; + + // If the minidump contains an exception context, use it + if (m_active_exception != nullptr && + m_active_exception->thread_id == thread.thread_id) { + context_location = m_active_exception->thread_context; + } - for (lldb::tid_t tid = 0; tid < num_threads; ++tid) { llvm::ArrayRef<uint8_t> context; if (!m_is_wow64) - context = m_minidump_parser.GetThreadContext(m_thread_list[tid]); + context = m_minidump_parser.GetThreadContext(context_location); else - context = m_minidump_parser.GetThreadContextWow64(m_thread_list[tid]); + context = m_minidump_parser.GetThreadContextWow64(thread); - lldb::ThreadSP thread_sp( - new ThreadMinidump(*this, m_thread_list[tid], context)); + lldb::ThreadSP thread_sp(new ThreadMinidump(*this, thread, context)); new_thread_list.AddThread(thread_sp); } return new_thread_list.GetSize(false) > 0; @@ -344,8 +355,8 @@ void ProcessMinidump::ReadModuleList() { } const auto uuid = m_minidump_parser.GetModuleUUID(module); - const auto file_spec = - FileSpec(name.getValue(), true, GetArchitecture().GetTriple()); + auto file_spec = FileSpec(name.getValue(), GetArchitecture().GetTriple()); + FileSystem::Instance().Resolve(file_spec); ModuleSpec module_spec(file_spec, uuid); Status error; lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error); @@ -357,6 +368,12 @@ void ProcessMinidump::ReadModuleList() { // This enables most LLDB functionality involving address-to-module // translations (ex. identifing the module for a stack frame PC) and // modules/sections commands (ex. target modules list, ...) + if (log) { + log->Printf("Unable to locate the matching object file, creating a " + "placeholder module for: %s", + name.getValue().c_str()); + } + auto placeholder_module = std::make_shared<PlaceholderModule>(module_spec); placeholder_module->CreateImageSection(module, GetTarget()); @@ -387,3 +404,248 @@ bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) { } return true; } + +// For minidumps there's no runtime generated code so we don't need JITLoader(s) +// Avoiding them will also speed up minidump loading since JITLoaders normally +// try to set up symbolic breakpoints, which in turn may force loading more +// debug information than needed. +JITLoaderList &ProcessMinidump::GetJITLoaders() { + if (!m_jit_loaders_ap) { + m_jit_loaders_ap = llvm::make_unique<JITLoaderList>(); + } + return *m_jit_loaders_ap; +} + +#define INIT_BOOL(VAR, LONG, SHORT, DESC) \ + VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true) +#define APPEND_OPT(VAR) \ + m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1) + +class CommandObjectProcessMinidumpDump : public CommandObjectParsed { +private: + OptionGroupOptions m_option_group; + OptionGroupBoolean m_dump_all; + OptionGroupBoolean m_dump_directory; + OptionGroupBoolean m_dump_linux_cpuinfo; + OptionGroupBoolean m_dump_linux_proc_status; + OptionGroupBoolean m_dump_linux_lsb_release; + OptionGroupBoolean m_dump_linux_cmdline; + OptionGroupBoolean m_dump_linux_environ; + OptionGroupBoolean m_dump_linux_auxv; + OptionGroupBoolean m_dump_linux_maps; + OptionGroupBoolean m_dump_linux_proc_stat; + OptionGroupBoolean m_dump_linux_proc_uptime; + OptionGroupBoolean m_dump_linux_proc_fd; + OptionGroupBoolean m_dump_linux_all; + + void SetDefaultOptionsIfNoneAreSet() { + if (m_dump_all.GetOptionValue().GetCurrentValue() || + m_dump_linux_all.GetOptionValue().GetCurrentValue() || + m_dump_directory.GetOptionValue().GetCurrentValue() || + m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() || + m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() || + m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() || + m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() || + m_dump_linux_environ.GetOptionValue().GetCurrentValue() || + m_dump_linux_auxv.GetOptionValue().GetCurrentValue() || + m_dump_linux_maps.GetOptionValue().GetCurrentValue() || + m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() || + m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() || + m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue()) + return; + // If no options were set, then dump everything + m_dump_all.GetOptionValue().SetCurrentValue(true); + } + bool DumpAll() const { + return m_dump_all.GetOptionValue().GetCurrentValue(); + } + bool DumpDirectory() const { + return DumpAll() || + m_dump_directory.GetOptionValue().GetCurrentValue(); + } + bool DumpLinux() const { + return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxCPUInfo() const { + return DumpLinux() || + m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxProcStatus() const { + return DumpLinux() || + m_dump_linux_proc_status.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxProcStat() const { + return DumpLinux() || + m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxLSBRelease() const { + return DumpLinux() || + m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxCMDLine() const { + return DumpLinux() || + m_dump_linux_cmdline.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxEnviron() const { + return DumpLinux() || + m_dump_linux_environ.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxAuxv() const { + return DumpLinux() || + m_dump_linux_auxv.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxMaps() const { + return DumpLinux() || + m_dump_linux_maps.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxProcUptime() const { + return DumpLinux() || + m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue(); + } + bool DumpLinuxProcFD() const { + return DumpLinux() || + m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue(); + } +public: + + CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process plugin dump", + "Dump information from the minidump file.", NULL), + m_option_group(), + INIT_BOOL(m_dump_all, "all", 'a', + "Dump the everything in the minidump."), + INIT_BOOL(m_dump_directory, "directory", 'd', + "Dump the minidump directory map."), + INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C', + "Dump linux /proc/cpuinfo."), + INIT_BOOL(m_dump_linux_proc_status, "status", 's', + "Dump linux /proc/<pid>/status."), + INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r', + "Dump linux /etc/lsb-release."), + INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c', + "Dump linux /proc/<pid>/cmdline."), + INIT_BOOL(m_dump_linux_environ, "environ", 'e', + "Dump linux /proc/<pid>/environ."), + INIT_BOOL(m_dump_linux_auxv, "auxv", 'x', + "Dump linux /proc/<pid>/auxv."), + INIT_BOOL(m_dump_linux_maps, "maps", 'm', + "Dump linux /proc/<pid>/maps."), + INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S', + "Dump linux /proc/<pid>/stat."), + INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u', + "Dump linux process uptime."), + INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f', + "Dump linux /proc/<pid>/fd."), + INIT_BOOL(m_dump_linux_all, "linux", 'l', + "Dump all linux streams.") { + APPEND_OPT(m_dump_all); + APPEND_OPT(m_dump_directory); + APPEND_OPT(m_dump_linux_cpuinfo); + APPEND_OPT(m_dump_linux_proc_status); + APPEND_OPT(m_dump_linux_lsb_release); + APPEND_OPT(m_dump_linux_cmdline); + APPEND_OPT(m_dump_linux_environ); + APPEND_OPT(m_dump_linux_auxv); + APPEND_OPT(m_dump_linux_maps); + APPEND_OPT(m_dump_linux_proc_stat); + APPEND_OPT(m_dump_linux_proc_uptime); + APPEND_OPT(m_dump_linux_proc_fd); + APPEND_OPT(m_dump_linux_all); + m_option_group.Finalize(); + } + + ~CommandObjectProcessMinidumpDump() {} + + Options *GetOptions() override { return &m_option_group; } + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc > 0) { + result.AppendErrorWithFormat("'%s' take no arguments, only options", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + SetDefaultOptionsIfNoneAreSet(); + + ProcessMinidump *process = static_cast<ProcessMinidump *>( + m_interpreter.GetExecutionContext().GetProcessPtr()); + result.SetStatus(eReturnStatusSuccessFinishResult); + Stream &s = result.GetOutputStream(); + MinidumpParser &minidump = process->m_minidump_parser; + if (DumpDirectory()) { + s.Printf("RVA SIZE TYPE MinidumpStreamType\n"); + s.Printf("---------- ---------- ---------- --------------------------\n"); + for (const auto &pair: minidump.GetDirectoryMap()) + s.Printf("0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)pair.second.rva, + (uint32_t)pair.second.data_size, pair.first, + MinidumpParser::GetStreamTypeAsString(pair.first).data()); + s.Printf("\n"); + } + auto DumpTextStream = [&](MinidumpStreamType stream_type, + llvm::StringRef label) -> void { + auto bytes = minidump.GetStream(stream_type); + if (!bytes.empty()) { + if (label.empty()) + label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type); + s.Printf("%s:\n%s\n\n", label.data(), bytes.data()); + } + }; + auto DumpBinaryStream = [&](MinidumpStreamType stream_type, + llvm::StringRef label) -> void { + auto bytes = minidump.GetStream(stream_type); + if (!bytes.empty()) { + if (label.empty()) + label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type); + s.Printf("%s:\n", label.data()); + DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle, + process->GetAddressByteSize()); + DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1, + bytes.size(), 16, 0, 0, 0); + s.Printf("\n\n"); + } + }; + + if (DumpLinuxCPUInfo()) + DumpTextStream(MinidumpStreamType::LinuxCPUInfo, "/proc/cpuinfo"); + if (DumpLinuxProcStatus()) + DumpTextStream(MinidumpStreamType::LinuxProcStatus, "/proc/PID/status"); + if (DumpLinuxLSBRelease()) + DumpTextStream(MinidumpStreamType::LinuxLSBRelease, "/etc/lsb-release"); + if (DumpLinuxCMDLine()) + DumpTextStream(MinidumpStreamType::LinuxCMDLine, "/proc/PID/cmdline"); + if (DumpLinuxEnviron()) + DumpTextStream(MinidumpStreamType::LinuxEnviron, "/proc/PID/environ"); + if (DumpLinuxAuxv()) + DumpBinaryStream(MinidumpStreamType::LinuxAuxv, "/proc/PID/auxv"); + if (DumpLinuxMaps()) + DumpTextStream(MinidumpStreamType::LinuxMaps, "/proc/PID/maps"); + if (DumpLinuxProcStat()) + DumpTextStream(MinidumpStreamType::LinuxProcStat, "/proc/PID/stat"); + if (DumpLinuxProcUptime()) + DumpTextStream(MinidumpStreamType::LinuxProcUptime, "uptime"); + if (DumpLinuxProcFD()) + DumpTextStream(MinidumpStreamType::LinuxProcFD, "/proc/PID/fd"); + return true; + } +}; + +class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword { +public: + CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "process plugin", + "Commands for operating on a ProcessMinidump process.", + "process plugin <subcommand> [<subcommand-options>]") { + LoadSubCommand("dump", + CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter))); + } + + ~CommandObjectMultiwordProcessMinidump() {} +}; + +CommandObject *ProcessMinidump::GetPluginCommandObject() { + if (!m_command_sp) + m_command_sp.reset(new CommandObjectMultiwordProcessMinidump( + GetTarget().GetDebugger().GetCommandInterpreter())); + return m_command_sp.get(); +} diff --git a/source/Plugins/Process/minidump/ProcessMinidump.h b/source/Plugins/Process/minidump/ProcessMinidump.h index d65ada9009a7..30347b79e1c1 100644 --- a/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/source/Plugins/Process/minidump/ProcessMinidump.h @@ -10,11 +10,9 @@ #ifndef liblldb_ProcessMinidump_h_ #define liblldb_ProcessMinidump_h_ -// Project includes #include "MinidumpParser.h" #include "MinidumpTypes.h" -// Other libraries and framework includes #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" @@ -24,8 +22,6 @@ #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" -// C Includes -// C++ Includes namespace lldb_private { @@ -53,9 +49,11 @@ public: bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override; + CommandObject *GetPluginCommandObject() override; + Status DoLoadCore() override; - DynamicLoader *GetDynamicLoader() override; + DynamicLoader *GetDynamicLoader() override { return nullptr; } ConstString GetPluginName() override; @@ -82,6 +80,9 @@ public: Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info) override; + Status GetMemoryRegions( + lldb_private::MemoryRegionInfos ®ion_list) override; + bool GetProcessInfo(ProcessInstanceInfo &info) override; Status WillResume() override { @@ -102,10 +103,13 @@ protected: void ReadModuleList(); + JITLoaderList &GetJITLoaders() override; + private: FileSpec m_core_file; llvm::ArrayRef<MinidumpThread> m_thread_list; const MinidumpExceptionStream *m_active_exception; + lldb::CommandObjectSP m_command_sp; bool m_is_wow64; }; diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp b/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp new file mode 100644 index 000000000000..93c3ba70b9e7 --- /dev/null +++ b/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp @@ -0,0 +1,532 @@ +//===-- RegisterContextMinidump_ARM.cpp -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RegisterContextMinidump_ARM.h" + +#include "Utility/ARM_DWARF_Registers.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/lldb-enumerations.h" + +// C includes +#include <assert.h> + +// C++ includes + +using namespace lldb; +using namespace lldb_private; +using namespace minidump; + +#define INV LLDB_INVALID_REGNUM +#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM::Context, r)) + +#define DEF_R(i) \ + { \ + "r" #i, nullptr, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \ + {INV, dwarf_r##i, INV, INV, reg_r##i}, nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_R_ARG(i, n) \ + { \ + "r" #i, "arg" #n, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \ + {INV, dwarf_r##i, LLDB_REGNUM_GENERIC_ARG1 + i, INV, reg_r##i}, \ + nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_D(i) \ + { \ + "d" #i, nullptr, 8, OFFSET(d) + i * 8, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, dwarf_d##i, INV, INV, reg_d##i}, \ + nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_S(i) \ + { \ + "s" #i, nullptr, 4, OFFSET(s) + i * 4, eEncodingIEEE754, eFormatFloat, \ + {INV, dwarf_s##i, INV, INV, reg_s##i}, nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_Q(i) \ + { \ + "q" #i, nullptr, 16, OFFSET(q) + i * 16, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, dwarf_q##i, INV, INV, reg_q##i}, \ + nullptr, nullptr, nullptr, 0 \ + } + +// Zero based LLDB register numbers for this register context +enum { + // General Purpose Registers + reg_r0, + reg_r1, + reg_r2, + reg_r3, + reg_r4, + reg_r5, + reg_r6, + reg_r7, + reg_r8, + reg_r9, + reg_r10, + reg_r11, + reg_r12, + reg_sp, + reg_lr, + reg_pc, + reg_cpsr, + // Floating Point Registers + reg_fpscr, + reg_d0, + reg_d1, + reg_d2, + reg_d3, + reg_d4, + reg_d5, + reg_d6, + reg_d7, + reg_d8, + reg_d9, + reg_d10, + reg_d11, + reg_d12, + reg_d13, + reg_d14, + reg_d15, + reg_d16, + reg_d17, + reg_d18, + reg_d19, + reg_d20, + reg_d21, + reg_d22, + reg_d23, + reg_d24, + reg_d25, + reg_d26, + reg_d27, + reg_d28, + reg_d29, + reg_d30, + reg_d31, + reg_s0, + reg_s1, + reg_s2, + reg_s3, + reg_s4, + reg_s5, + reg_s6, + reg_s7, + reg_s8, + reg_s9, + reg_s10, + reg_s11, + reg_s12, + reg_s13, + reg_s14, + reg_s15, + reg_s16, + reg_s17, + reg_s18, + reg_s19, + reg_s20, + reg_s21, + reg_s22, + reg_s23, + reg_s24, + reg_s25, + reg_s26, + reg_s27, + reg_s28, + reg_s29, + reg_s30, + reg_s31, + reg_q0, + reg_q1, + reg_q2, + reg_q3, + reg_q4, + reg_q5, + reg_q6, + reg_q7, + reg_q8, + reg_q9, + reg_q10, + reg_q11, + reg_q12, + reg_q13, + reg_q14, + reg_q15, + k_num_regs +}; + +static RegisterInfo g_reg_info_apple_fp = { + "fp", + "r7", + 4, + OFFSET(r) + 7 * 4, + eEncodingUint, + eFormatHex, + {INV, dwarf_r7, LLDB_REGNUM_GENERIC_FP, INV, reg_r7}, + nullptr, + nullptr, + nullptr, + 0}; + +static RegisterInfo g_reg_info_fp = { + "fp", + "r11", + 4, + OFFSET(r) + 11 * 4, + eEncodingUint, + eFormatHex, + {INV, dwarf_r11, LLDB_REGNUM_GENERIC_FP, INV, reg_r11}, + nullptr, + nullptr, + nullptr, + 0}; + +// Register info definitions for this register context +static RegisterInfo g_reg_infos[] = { + DEF_R_ARG(0, 1), + DEF_R_ARG(1, 2), + DEF_R_ARG(2, 3), + DEF_R_ARG(3, 4), + DEF_R(4), + DEF_R(5), + DEF_R(6), + DEF_R(7), + DEF_R(8), + DEF_R(9), + DEF_R(10), + DEF_R(11), + DEF_R(12), + {"sp", + "r13", + 4, + OFFSET(r) + 13 * 4, + eEncodingUint, + eFormatHex, + {INV, dwarf_sp, LLDB_REGNUM_GENERIC_SP, INV, reg_sp}, + nullptr, + nullptr, + nullptr, + 0}, + {"lr", + "r14", + 4, + OFFSET(r) + 14 * 4, + eEncodingUint, + eFormatHex, + {INV, dwarf_lr, LLDB_REGNUM_GENERIC_RA, INV, reg_lr}, + nullptr, + nullptr, + nullptr, + 0}, + {"pc", + "r15", + 4, + OFFSET(r) + 15 * 4, + eEncodingUint, + eFormatHex, + {INV, dwarf_pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc}, + nullptr, + nullptr, + nullptr, + 0}, + {"cpsr", + "psr", + 4, + OFFSET(cpsr), + eEncodingUint, + eFormatHex, + {INV, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr}, + nullptr, + nullptr, + nullptr, + 0}, + {"fpscr", + nullptr, + 8, + OFFSET(fpscr), + eEncodingUint, + eFormatHex, + {INV, INV, INV, INV, reg_fpscr}, + nullptr, + nullptr, + nullptr, + 0}, + DEF_D(0), + DEF_D(1), + DEF_D(2), + DEF_D(3), + DEF_D(4), + DEF_D(5), + DEF_D(6), + DEF_D(7), + DEF_D(8), + DEF_D(9), + DEF_D(10), + DEF_D(11), + DEF_D(12), + DEF_D(13), + DEF_D(14), + DEF_D(15), + DEF_D(16), + DEF_D(17), + DEF_D(18), + DEF_D(19), + DEF_D(20), + DEF_D(21), + DEF_D(22), + DEF_D(23), + DEF_D(24), + DEF_D(25), + DEF_D(26), + DEF_D(27), + DEF_D(28), + DEF_D(29), + DEF_D(30), + DEF_D(31), + DEF_S(0), + DEF_S(1), + DEF_S(2), + DEF_S(3), + DEF_S(4), + DEF_S(5), + DEF_S(6), + DEF_S(7), + DEF_S(8), + DEF_S(9), + DEF_S(10), + DEF_S(11), + DEF_S(12), + DEF_S(13), + DEF_S(14), + DEF_S(15), + DEF_S(16), + DEF_S(17), + DEF_S(18), + DEF_S(19), + DEF_S(20), + DEF_S(21), + DEF_S(22), + DEF_S(23), + DEF_S(24), + DEF_S(25), + DEF_S(26), + DEF_S(27), + DEF_S(28), + DEF_S(29), + DEF_S(30), + DEF_S(31), + DEF_Q(0), + DEF_Q(1), + DEF_Q(2), + DEF_Q(3), + DEF_Q(4), + DEF_Q(5), + DEF_Q(6), + DEF_Q(7), + DEF_Q(8), + DEF_Q(9), + DEF_Q(10), + DEF_Q(11), + DEF_Q(12), + DEF_Q(13), + DEF_Q(14), + DEF_Q(15)}; + +constexpr size_t k_num_reg_infos = llvm::array_lengthof(g_reg_infos); + +// ARM general purpose registers. +const uint32_t g_gpr_regnums[] = { + reg_r0, + reg_r1, + reg_r2, + reg_r3, + reg_r4, + reg_r5, + reg_r6, + reg_r7, + reg_r8, + reg_r9, + reg_r10, + reg_r11, + reg_r12, + reg_sp, + reg_lr, + reg_pc, + reg_cpsr, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +const uint32_t g_fpu_regnums[] = { + reg_fpscr, + reg_d0, + reg_d1, + reg_d2, + reg_d3, + reg_d4, + reg_d5, + reg_d6, + reg_d7, + reg_d8, + reg_d9, + reg_d10, + reg_d11, + reg_d12, + reg_d13, + reg_d14, + reg_d15, + reg_d16, + reg_d17, + reg_d18, + reg_d19, + reg_d20, + reg_d21, + reg_d22, + reg_d23, + reg_d24, + reg_d25, + reg_d26, + reg_d27, + reg_d28, + reg_d29, + reg_d30, + reg_d31, + reg_s0, + reg_s1, + reg_s2, + reg_s3, + reg_s4, + reg_s5, + reg_s6, + reg_s7, + reg_s8, + reg_s9, + reg_s10, + reg_s11, + reg_s12, + reg_s13, + reg_s14, + reg_s15, + reg_s16, + reg_s17, + reg_s18, + reg_s19, + reg_s20, + reg_s21, + reg_s22, + reg_s23, + reg_s24, + reg_s25, + reg_s26, + reg_s27, + reg_s28, + reg_s29, + reg_s30, + reg_s31, + reg_q0, + reg_q1, + reg_q2, + reg_q3, + reg_q4, + reg_q5, + reg_q6, + reg_q7, + reg_q8, + reg_q9, + reg_q10, + reg_q11, + reg_q12, + reg_q13, + reg_q14, + reg_q15, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +// Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1 +constexpr size_t k_num_gpr_regs = llvm::array_lengthof(g_gpr_regnums) - 1; +constexpr size_t k_num_fpu_regs = llvm::array_lengthof(g_fpu_regnums) - 1; + +static RegisterSet g_reg_sets[] = { + {"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums}, + {"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums}, +}; + +constexpr size_t k_num_reg_sets = llvm::array_lengthof(g_reg_sets); + +RegisterContextMinidump_ARM::RegisterContextMinidump_ARM( + Thread &thread, const DataExtractor &data, bool apple) + : RegisterContext(thread, 0), m_apple(apple) { + lldb::offset_t offset = 0; + m_regs.context_flags = data.GetU32(&offset); + for (unsigned i = 0; i < llvm::array_lengthof(m_regs.r); ++i) + m_regs.r[i] = data.GetU32(&offset); + m_regs.cpsr = data.GetU32(&offset); + m_regs.fpscr = data.GetU64(&offset); + for (unsigned i = 0; i < llvm::array_lengthof(m_regs.d); ++i) + m_regs.d[i] = data.GetU64(&offset); + lldbassert(k_num_regs == k_num_reg_infos); +} + +size_t RegisterContextMinidump_ARM::GetRegisterCount() { return k_num_regs; } + +const RegisterInfo * +RegisterContextMinidump_ARM::GetRegisterInfoAtIndex(size_t reg) { + if (reg < k_num_reg_infos) { + if (m_apple) { + if (reg == reg_r7) + return &g_reg_info_apple_fp; + } else { + if (reg == reg_r11) + return &g_reg_info_fp; + } + return &g_reg_infos[reg]; + } + return nullptr; +} + +size_t RegisterContextMinidump_ARM::GetRegisterSetCount() { + return k_num_reg_sets; +} + +const RegisterSet *RegisterContextMinidump_ARM::GetRegisterSet(size_t set) { + if (set < k_num_reg_sets) + return &g_reg_sets[set]; + return nullptr; +} + +const char *RegisterContextMinidump_ARM::GetRegisterName(unsigned reg) { + if (reg < k_num_reg_infos) + return g_reg_infos[reg].name; + return nullptr; +} + +bool RegisterContextMinidump_ARM::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + reg_value.SetFromMemoryData( + reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset, + reg_info->byte_size, lldb::eByteOrderLittle, error); + return error.Success(); +} + +bool RegisterContextMinidump_ARM::WriteRegister(const RegisterInfo *, + const RegisterValue &) { + return false; +} + +uint32_t RegisterContextMinidump_ARM::ConvertRegisterKindToRegisterNumber( + lldb::RegisterKind kind, uint32_t num) { + for (size_t i = 0; i < k_num_regs; ++i) { + if (g_reg_infos[i].kinds[kind] == num) + return i; + } + return LLDB_INVALID_REGNUM; +} diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h b/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h new file mode 100644 index 000000000000..959611a1491d --- /dev/null +++ b/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h @@ -0,0 +1,93 @@ +//===-- RegisterContextMinidump_ARM.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextMinidump_ARM_h_ +#define liblldb_RegisterContextMinidump_ARM_h_ + +#include "MinidumpTypes.h" + +#include "Plugins/Process/Utility/RegisterInfoInterface.h" + +#include "lldb/Target/RegisterContext.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitmaskEnum.h" + +// C includes +// C++ includes + +namespace lldb_private { + +namespace minidump { + +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +class RegisterContextMinidump_ARM : public lldb_private::RegisterContext { +public: + RegisterContextMinidump_ARM(lldb_private::Thread &thread, + const DataExtractor &data, bool apple); + + ~RegisterContextMinidump_ARM() override = default; + + void InvalidateAllRegisters() override { + // Do nothing... registers are always valid... + } + + size_t GetRegisterCount() override; + + const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; + + size_t GetRegisterSetCount() override; + + const lldb_private::RegisterSet *GetRegisterSet(size_t set) override; + + const char *GetRegisterName(unsigned reg); + + bool ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + bool WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) override; + + // Reference: see breakpad/crashpad source + struct QRegValue { + uint64_t lo; + uint64_t hi; + }; + + struct Context { + uint32_t context_flags; + uint32_t r[16]; + uint32_t cpsr; + uint64_t fpscr; + union { + uint64_t d[32]; + uint32_t s[32]; + QRegValue q[16]; + }; + uint32_t extra[8]; + }; + +protected: + enum class Flags : uint32_t { + ARM_Flag = 0x40000000, + Integer = ARM_Flag | 0x00000002, + FloatingPoint = ARM_Flag | 0x00000004, + LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint) + }; + Context m_regs; + const bool m_apple; // True if this is an Apple ARM where FP is R7 +}; + +} // end namespace minidump +} // end namespace lldb_private +#endif // liblldb_RegisterContextMinidump_ARM_h_ diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp b/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp new file mode 100644 index 000000000000..3582e7d01867 --- /dev/null +++ b/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp @@ -0,0 +1,834 @@ +//===-- RegisterContextMinidump_ARM64.cpp -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RegisterContextMinidump_ARM64.h" + +#include "Utility/ARM64_DWARF_Registers.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/lldb-enumerations.h" + +// C includes +#include <assert.h> + +// C++ includes + +using namespace lldb; +using namespace lldb_private; +using namespace minidump; + +#define INV LLDB_INVALID_REGNUM +#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM64::Context, r)) + +#define DEF_X(i) \ + { \ + "x" #i, nullptr, 8, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \ + {INV, arm64_dwarf::x##i, INV, INV, reg_x##i}, nullptr, nullptr, \ + nullptr, 0 \ + } + +#define DEF_W(i) \ + { \ + "w" #i, nullptr, 4, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \ + {INV, INV, INV, INV, reg_w##i}, nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_X_ARG(i, n) \ + { \ + "x" #i, "arg" #n, 8, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \ + {INV, arm64_dwarf::x##i, LLDB_REGNUM_GENERIC_ARG1 + i, INV, reg_x##i}, \ + nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_V(i) \ + { \ + "v" #i, nullptr, 16, OFFSET(v) + i * 16, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, arm64_dwarf::v##i, INV, INV, reg_v##i}, \ + nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_D(i) \ + { \ + "d" #i, nullptr, 8, OFFSET(v) + i * 16, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_d##i}, nullptr, \ + nullptr, nullptr, 0 \ + } + +#define DEF_S(i) \ + { \ + "s" #i, nullptr, 4, OFFSET(v) + i * 16, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_s##i}, nullptr, \ + nullptr, nullptr, 0 \ + } + +#define DEF_H(i) \ + { \ + "h" #i, nullptr, 2, OFFSET(v) + i * 16, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_h##i}, nullptr, \ + nullptr, nullptr, 0 \ + } + +// Zero based LLDB register numbers for this register context +enum { + // General Purpose Registers + reg_x0 = 0, + reg_x1, + reg_x2, + reg_x3, + reg_x4, + reg_x5, + reg_x6, + reg_x7, + reg_x8, + reg_x9, + reg_x10, + reg_x11, + reg_x12, + reg_x13, + reg_x14, + reg_x15, + reg_x16, + reg_x17, + reg_x18, + reg_x19, + reg_x20, + reg_x21, + reg_x22, + reg_x23, + reg_x24, + reg_x25, + reg_x26, + reg_x27, + reg_x28, + reg_fp, + reg_lr, + reg_sp, + reg_pc, + reg_w0, + reg_w1, + reg_w2, + reg_w3, + reg_w4, + reg_w5, + reg_w6, + reg_w7, + reg_w8, + reg_w9, + reg_w10, + reg_w11, + reg_w12, + reg_w13, + reg_w14, + reg_w15, + reg_w16, + reg_w17, + reg_w18, + reg_w19, + reg_w20, + reg_w21, + reg_w22, + reg_w23, + reg_w24, + reg_w25, + reg_w26, + reg_w27, + reg_w28, + reg_w29, + reg_w30, + reg_w31, + reg_cpsr, + // Floating Point Registers + reg_fpsr, + reg_fpcr, + reg_v0, + reg_v1, + reg_v2, + reg_v3, + reg_v4, + reg_v5, + reg_v6, + reg_v7, + reg_v8, + reg_v9, + reg_v10, + reg_v11, + reg_v12, + reg_v13, + reg_v14, + reg_v15, + reg_v16, + reg_v17, + reg_v18, + reg_v19, + reg_v20, + reg_v21, + reg_v22, + reg_v23, + reg_v24, + reg_v25, + reg_v26, + reg_v27, + reg_v28, + reg_v29, + reg_v30, + reg_v31, + reg_d0, + reg_d1, + reg_d2, + reg_d3, + reg_d4, + reg_d5, + reg_d6, + reg_d7, + reg_d8, + reg_d9, + reg_d10, + reg_d11, + reg_d12, + reg_d13, + reg_d14, + reg_d15, + reg_d16, + reg_d17, + reg_d18, + reg_d19, + reg_d20, + reg_d21, + reg_d22, + reg_d23, + reg_d24, + reg_d25, + reg_d26, + reg_d27, + reg_d28, + reg_d29, + reg_d30, + reg_d31, + reg_s0, + reg_s1, + reg_s2, + reg_s3, + reg_s4, + reg_s5, + reg_s6, + reg_s7, + reg_s8, + reg_s9, + reg_s10, + reg_s11, + reg_s12, + reg_s13, + reg_s14, + reg_s15, + reg_s16, + reg_s17, + reg_s18, + reg_s19, + reg_s20, + reg_s21, + reg_s22, + reg_s23, + reg_s24, + reg_s25, + reg_s26, + reg_s27, + reg_s28, + reg_s29, + reg_s30, + reg_s31, + reg_h0, + reg_h1, + reg_h2, + reg_h3, + reg_h4, + reg_h5, + reg_h6, + reg_h7, + reg_h8, + reg_h9, + reg_h10, + reg_h11, + reg_h12, + reg_h13, + reg_h14, + reg_h15, + reg_h16, + reg_h17, + reg_h18, + reg_h19, + reg_h20, + reg_h21, + reg_h22, + reg_h23, + reg_h24, + reg_h25, + reg_h26, + reg_h27, + reg_h28, + reg_h29, + reg_h30, + reg_h31, + k_num_regs +}; + +// Register info definitions for this register context +static RegisterInfo g_reg_infos[] = { + DEF_X_ARG(0, 1), + DEF_X_ARG(1, 2), + DEF_X_ARG(2, 3), + DEF_X_ARG(3, 4), + DEF_X_ARG(4, 5), + DEF_X_ARG(5, 6), + DEF_X_ARG(6, 7), + DEF_X_ARG(7, 8), + DEF_X(8), + DEF_X(9), + DEF_X(10), + DEF_X(11), + DEF_X(12), + DEF_X(13), + DEF_X(14), + DEF_X(15), + DEF_X(16), + DEF_X(17), + DEF_X(18), + DEF_X(19), + DEF_X(20), + DEF_X(21), + DEF_X(22), + DEF_X(23), + DEF_X(24), + DEF_X(25), + DEF_X(26), + DEF_X(27), + DEF_X(28), + {"fp", + "x29", + 8, + OFFSET(x) + 29 * 8, + eEncodingUint, + eFormatHex, + {INV, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, INV, reg_fp}, + nullptr, + nullptr, + nullptr, + 0}, + {"lr", + "x30", + 8, + OFFSET(x) + 30 * 8, + eEncodingUint, + eFormatHex, + {INV, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, INV, reg_lr}, + nullptr, + nullptr, + nullptr, + 0}, + {"sp", + "x31", + 8, + OFFSET(x) + 31 * 8, + eEncodingUint, + eFormatHex, + {INV, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, INV, reg_sp}, + nullptr, + nullptr, + nullptr, + 0}, + {"pc", + nullptr, + 8, + OFFSET(pc), + eEncodingUint, + eFormatHex, + {INV, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc}, + nullptr, + nullptr, + nullptr, + 0}, + // w0 - w31 + DEF_W(0), + DEF_W(1), + DEF_W(2), + DEF_W(3), + DEF_W(4), + DEF_W(5), + DEF_W(6), + DEF_W(7), + DEF_W(8), + DEF_W(9), + DEF_W(10), + DEF_W(11), + DEF_W(12), + DEF_W(13), + DEF_W(14), + DEF_W(15), + DEF_W(16), + DEF_W(17), + DEF_W(18), + DEF_W(19), + DEF_W(20), + DEF_W(21), + DEF_W(22), + DEF_W(23), + DEF_W(24), + DEF_W(25), + DEF_W(26), + DEF_W(27), + DEF_W(28), + DEF_W(29), + DEF_W(30), + DEF_W(31), + {"cpsr", + "psr", + 4, + OFFSET(cpsr), + eEncodingUint, + eFormatHex, + {INV, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr}, + nullptr, + nullptr, + nullptr, + 0}, + {"fpsr", + nullptr, + 4, + OFFSET(fpsr), + eEncodingUint, + eFormatHex, + {INV, INV, INV, INV, reg_fpsr}, + nullptr, + nullptr, + nullptr, + 0}, + {"fpcr", + nullptr, + 4, + OFFSET(fpcr), + eEncodingUint, + eFormatHex, + {INV, INV, INV, INV, reg_fpcr}, + nullptr, + nullptr, + nullptr, + 0}, + // v0 - v31 + DEF_V(0), + DEF_V(1), + DEF_V(2), + DEF_V(3), + DEF_V(4), + DEF_V(5), + DEF_V(6), + DEF_V(7), + DEF_V(8), + DEF_V(9), + DEF_V(10), + DEF_V(11), + DEF_V(12), + DEF_V(13), + DEF_V(14), + DEF_V(15), + DEF_V(16), + DEF_V(17), + DEF_V(18), + DEF_V(19), + DEF_V(20), + DEF_V(21), + DEF_V(22), + DEF_V(23), + DEF_V(24), + DEF_V(25), + DEF_V(26), + DEF_V(27), + DEF_V(28), + DEF_V(29), + DEF_V(30), + DEF_V(31), + // d0 - d31 + DEF_D(0), + DEF_D(1), + DEF_D(2), + DEF_D(3), + DEF_D(4), + DEF_D(5), + DEF_D(6), + DEF_D(7), + DEF_D(8), + DEF_D(9), + DEF_D(10), + DEF_D(11), + DEF_D(12), + DEF_D(13), + DEF_D(14), + DEF_D(15), + DEF_D(16), + DEF_D(17), + DEF_D(18), + DEF_D(19), + DEF_D(20), + DEF_D(21), + DEF_D(22), + DEF_D(23), + DEF_D(24), + DEF_D(25), + DEF_D(26), + DEF_D(27), + DEF_D(28), + DEF_D(29), + DEF_D(30), + DEF_D(31), + // s0 - s31 + DEF_S(0), + DEF_S(1), + DEF_S(2), + DEF_S(3), + DEF_S(4), + DEF_S(5), + DEF_S(6), + DEF_S(7), + DEF_S(8), + DEF_S(9), + DEF_S(10), + DEF_S(11), + DEF_S(12), + DEF_S(13), + DEF_S(14), + DEF_S(15), + DEF_S(16), + DEF_S(17), + DEF_S(18), + DEF_S(19), + DEF_S(20), + DEF_S(21), + DEF_S(22), + DEF_S(23), + DEF_S(24), + DEF_S(25), + DEF_S(26), + DEF_S(27), + DEF_S(28), + DEF_S(29), + DEF_S(30), + DEF_S(31), + // h0 - h31 + DEF_H(0), + DEF_H(1), + DEF_H(2), + DEF_H(3), + DEF_H(4), + DEF_H(5), + DEF_H(6), + DEF_H(7), + DEF_H(8), + DEF_H(9), + DEF_H(10), + DEF_H(11), + DEF_H(12), + DEF_H(13), + DEF_H(14), + DEF_H(15), + DEF_H(16), + DEF_H(17), + DEF_H(18), + DEF_H(19), + DEF_H(20), + DEF_H(21), + DEF_H(22), + DEF_H(23), + DEF_H(24), + DEF_H(25), + DEF_H(26), + DEF_H(27), + DEF_H(28), + DEF_H(29), + DEF_H(30), + DEF_H(31), +}; + +constexpr size_t k_num_reg_infos = llvm::array_lengthof(g_reg_infos); + +// ARM64 general purpose registers. +const uint32_t g_gpr_regnums[] = { + reg_x0, + reg_x1, + reg_x2, + reg_x3, + reg_x4, + reg_x5, + reg_x6, + reg_x7, + reg_x8, + reg_x9, + reg_x10, + reg_x11, + reg_x12, + reg_x13, + reg_x14, + reg_x15, + reg_x16, + reg_x17, + reg_x18, + reg_x19, + reg_x20, + reg_x21, + reg_x22, + reg_x23, + reg_x24, + reg_x25, + reg_x26, + reg_x27, + reg_x28, + reg_fp, + reg_lr, + reg_sp, + reg_w0, + reg_w1, + reg_w2, + reg_w3, + reg_w4, + reg_w5, + reg_w6, + reg_w7, + reg_w8, + reg_w9, + reg_w10, + reg_w11, + reg_w12, + reg_w13, + reg_w14, + reg_w15, + reg_w16, + reg_w17, + reg_w18, + reg_w19, + reg_w20, + reg_w21, + reg_w22, + reg_w23, + reg_w24, + reg_w25, + reg_w26, + reg_w27, + reg_w28, + reg_w29, + reg_w30, + reg_w31, + reg_pc, + reg_cpsr, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +const uint32_t g_fpu_regnums[] = { + reg_v0, + reg_v1, + reg_v2, + reg_v3, + reg_v4, + reg_v5, + reg_v6, + reg_v7, + reg_v8, + reg_v9, + reg_v10, + reg_v11, + reg_v12, + reg_v13, + reg_v14, + reg_v15, + reg_v16, + reg_v17, + reg_v18, + reg_v19, + reg_v20, + reg_v21, + reg_v22, + reg_v23, + reg_v24, + reg_v25, + reg_v26, + reg_v27, + reg_v28, + reg_v29, + reg_v30, + reg_v31, + reg_d0, + reg_d1, + reg_d2, + reg_d3, + reg_d4, + reg_d5, + reg_d6, + reg_d7, + reg_d8, + reg_d9, + reg_d10, + reg_d11, + reg_d12, + reg_d13, + reg_d14, + reg_d15, + reg_d16, + reg_d17, + reg_d18, + reg_d19, + reg_d20, + reg_d21, + reg_d22, + reg_d23, + reg_d24, + reg_d25, + reg_d26, + reg_d27, + reg_d28, + reg_d29, + reg_d30, + reg_d31, + reg_s0, + reg_s1, + reg_s2, + reg_s3, + reg_s4, + reg_s5, + reg_s6, + reg_s7, + reg_s8, + reg_s9, + reg_s10, + reg_s11, + reg_s12, + reg_s13, + reg_s14, + reg_s15, + reg_s16, + reg_s17, + reg_s18, + reg_s19, + reg_s20, + reg_s21, + reg_s22, + reg_s23, + reg_s24, + reg_s25, + reg_s26, + reg_s27, + reg_s28, + reg_s29, + reg_s30, + reg_s31, + reg_h0, + reg_h1, + reg_h2, + reg_h3, + reg_h4, + reg_h5, + reg_h6, + reg_h7, + reg_h8, + reg_h9, + reg_h10, + reg_h11, + reg_h12, + reg_h13, + reg_h14, + reg_h15, + reg_h16, + reg_h17, + reg_h18, + reg_h19, + reg_h20, + reg_h21, + reg_h22, + reg_h23, + reg_h24, + reg_h25, + reg_h26, + reg_h27, + reg_h28, + reg_h29, + reg_h30, + reg_h31, + reg_fpsr, + reg_fpcr, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +// Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1 +constexpr size_t k_num_gpr_regs = llvm::array_lengthof(g_gpr_regnums) - 1; +constexpr size_t k_num_fpu_regs = llvm::array_lengthof(g_fpu_regnums) - 1; + +static RegisterSet g_reg_sets[] = { + {"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums}, + {"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums}, +}; + +constexpr size_t k_num_reg_sets = llvm::array_lengthof(g_reg_sets); + +RegisterContextMinidump_ARM64::RegisterContextMinidump_ARM64( + Thread &thread, const DataExtractor &data) + : RegisterContext(thread, 0) { + lldb::offset_t offset = 0; + m_regs.context_flags = data.GetU64(&offset); + for (unsigned i = 0; i < 32; ++i) + m_regs.x[i] = data.GetU64(&offset); + m_regs.pc = data.GetU64(&offset); + m_regs.cpsr = data.GetU32(&offset); + m_regs.fpsr = data.GetU32(&offset); + m_regs.fpcr = data.GetU32(&offset); + auto regs_data = data.GetData(&offset, sizeof(m_regs.v)); + if (regs_data) + memcpy(m_regs.v, regs_data, sizeof(m_regs.v)); + assert(k_num_regs == k_num_reg_infos); +} +size_t RegisterContextMinidump_ARM64::GetRegisterCount() { return k_num_regs; } + +const RegisterInfo * +RegisterContextMinidump_ARM64::GetRegisterInfoAtIndex(size_t reg) { + if (reg < k_num_reg_infos) + return &g_reg_infos[reg]; + return nullptr; +} + +size_t RegisterContextMinidump_ARM64::GetRegisterSetCount() { + return k_num_reg_sets; +} + +const RegisterSet *RegisterContextMinidump_ARM64::GetRegisterSet(size_t set) { + if (set < k_num_reg_sets) + return &g_reg_sets[set]; + return nullptr; +} + +const char *RegisterContextMinidump_ARM64::GetRegisterName(unsigned reg) { + if (reg < k_num_reg_infos) + return g_reg_infos[reg].name; + return nullptr; +} + +bool RegisterContextMinidump_ARM64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + reg_value.SetFromMemoryData( + reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset, + reg_info->byte_size, lldb::eByteOrderLittle, error); + return error.Success(); +} + +bool RegisterContextMinidump_ARM64::WriteRegister(const RegisterInfo *, + const RegisterValue &) { + return false; +} + +uint32_t RegisterContextMinidump_ARM64::ConvertRegisterKindToRegisterNumber( + lldb::RegisterKind kind, uint32_t num) { + for (size_t i = 0; i < k_num_regs; ++i) { + if (g_reg_infos[i].kinds[kind] == num) + return i; + } + return LLDB_INVALID_REGNUM; +} diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h b/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h new file mode 100644 index 000000000000..ee47b1577e52 --- /dev/null +++ b/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h @@ -0,0 +1,83 @@ +//===-- RegisterContextMinidump_ARM64.h -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextMinidump_ARM64_h_ +#define liblldb_RegisterContextMinidump_ARM64_h_ + +#include "MinidumpTypes.h" + +#include "Plugins/Process/Utility/RegisterInfoInterface.h" +#include "lldb/Target/RegisterContext.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitmaskEnum.h" + +// C includes +// C++ includes + +namespace lldb_private { + +namespace minidump { + +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +class RegisterContextMinidump_ARM64 : public lldb_private::RegisterContext { +public: + RegisterContextMinidump_ARM64(lldb_private::Thread &thread, + const DataExtractor &data); + + ~RegisterContextMinidump_ARM64() override = default; + + void InvalidateAllRegisters() override { + // Do nothing... registers are always valid... + } + + size_t GetRegisterCount() override; + + const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; + + size_t GetRegisterSetCount() override; + + const lldb_private::RegisterSet *GetRegisterSet(size_t set) override; + + const char *GetRegisterName(unsigned reg); + + bool ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + bool WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) override; + + // Reference: see breakpad/crashpad source + struct Context { + uint64_t context_flags; + uint64_t x[32]; + uint64_t pc; + uint32_t cpsr; + uint32_t fpsr; + uint32_t fpcr; + uint8_t v[32 * 16]; // 32 128-bit floating point registers + }; + +protected: + enum class Flags : uint32_t { + ARM64_Flag = 0x80000000, + Integer = ARM64_Flag | 0x00000002, + FloatingPoint = ARM64_Flag | 0x00000004, + LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint) + }; + Context m_regs; +}; + +} // end namespace minidump +} // end namespace lldb_private +#endif // liblldb_RegisterContextMinidump_ARM64_h_ diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp index 7605f8b143af..1fdbb5e3f1e5 100644 --- a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp +++ b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp @@ -7,10 +7,8 @@ // //===----------------------------------------------------------------------===// -// Project includes #include "RegisterContextMinidump_x86_32.h" -// Other libraries and framework includes #include "lldb/Utility/DataBufferHeap.h" // C includes diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h index e18bb3b4f5d9..38c2ffca4938 100644 --- a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h +++ b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h @@ -10,10 +10,8 @@ #ifndef liblldb_RegisterContextMinidump_x86_32_h_ #define liblldb_RegisterContextMinidump_x86_32_h_ -// Project includes #include "MinidumpTypes.h" -// Other libraries and framework includes #include "Plugins/Process/Utility/RegisterInfoInterface.h" #include "Plugins/Process/Utility/lldb-x86-register-enums.h" diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp index ba1cb6dbf3ef..eaa155de8eb9 100644 --- a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp +++ b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp @@ -7,10 +7,8 @@ // //===----------------------------------------------------------------------===// -// Project includes #include "RegisterContextMinidump_x86_64.h" -// Other libraries and framework includes #include "lldb/Utility/DataBufferHeap.h" // C includes diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h index 9ba2ee9f29ad..30ce9065e141 100644 --- a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h +++ b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h @@ -10,10 +10,8 @@ #ifndef liblldb_RegisterContextMinidump_h_ #define liblldb_RegisterContextMinidump_h_ -// Project includes #include "MinidumpTypes.h" -// Other libraries and framework includes #include "Plugins/Process/Utility/RegisterInfoInterface.h" #include "Plugins/Process/Utility/lldb-x86-register-enums.h" diff --git a/source/Plugins/Process/minidump/ThreadMinidump.cpp b/source/Plugins/Process/minidump/ThreadMinidump.cpp index 3fafb6134e7f..f4c136577719 100644 --- a/source/Plugins/Process/minidump/ThreadMinidump.cpp +++ b/source/Plugins/Process/minidump/ThreadMinidump.cpp @@ -7,14 +7,14 @@ // //===----------------------------------------------------------------------===// -// Project includes #include "ThreadMinidump.h" #include "ProcessMinidump.h" +#include "RegisterContextMinidump_ARM.h" +#include "RegisterContextMinidump_ARM64.h" #include "RegisterContextMinidump_x86_32.h" #include "RegisterContextMinidump_x86_64.h" -// Other libraries and framework includes #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h" @@ -27,8 +27,6 @@ #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" -// C Includes -// C++ Includes using namespace lldb; using namespace lldb_private; @@ -54,7 +52,6 @@ RegisterContextSP ThreadMinidump::CreateRegisterContextForFrame(StackFrame *frame) { RegisterContextSP reg_ctx_sp; uint32_t concrete_frame_idx = 0; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (frame) concrete_frame_idx = frame->GetConcreteFrameIndex(); @@ -88,15 +85,22 @@ ThreadMinidump::CreateRegisterContextForFrame(StackFrame *frame) { *this, reg_interface, gpregset, {})); break; } - default: + case llvm::Triple::aarch64: { + DataExtractor data(m_gpregset_data.data(), m_gpregset_data.size(), + lldb::eByteOrderLittle, 8); + m_thread_reg_ctx_sp.reset(new RegisterContextMinidump_ARM64(*this, data)); break; } - - if (!reg_interface) { - if (log) - log->Printf("elf-core::%s:: Architecture(%d) not supported", - __FUNCTION__, arch.GetMachine()); - assert(false && "Architecture not supported"); + case llvm::Triple::arm: { + DataExtractor data(m_gpregset_data.data(), m_gpregset_data.size(), + lldb::eByteOrderLittle, 8); + const bool apple = arch.GetTriple().getVendor() == llvm::Triple::Apple; + m_thread_reg_ctx_sp.reset( + new RegisterContextMinidump_ARM(*this, data, apple)); + break; + } + default: + break; } reg_ctx_sp = m_thread_reg_ctx_sp; diff --git a/source/Plugins/Process/minidump/ThreadMinidump.h b/source/Plugins/Process/minidump/ThreadMinidump.h index 74ac44f74dcf..45364facaa56 100644 --- a/source/Plugins/Process/minidump/ThreadMinidump.h +++ b/source/Plugins/Process/minidump/ThreadMinidump.h @@ -10,14 +10,10 @@ #ifndef liblldb_ThreadMinidump_h_ #define liblldb_ThreadMinidump_h_ -// Project includes #include "MinidumpTypes.h" -// Other libraries and framework includes #include "lldb/Target/Thread.h" -// C Includes -// C++ Includes namespace lldb_private { diff --git a/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h b/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h index 824579472b5e..8937d9843f87 100644 --- a/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h +++ b/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h @@ -10,10 +10,6 @@ #ifndef liblldb_ScriptInterpreterNone_h_ #define liblldb_ScriptInterpreterNone_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Interpreter/ScriptInterpreter.h" namespace lldb_private { diff --git a/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index 90d8ab97fb73..7e96dd9893c8 100644 --- a/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -222,9 +222,7 @@ PythonBytes::~PythonBytes() {} bool PythonBytes::Check(PyObject *py_obj) { if (!py_obj) return false; - if (PyBytes_Check(py_obj)) - return true; - return false; + return PyBytes_Check(py_obj); } void PythonBytes::Reset(PyRefType type, PyObject *py_obj) { @@ -294,9 +292,7 @@ PythonByteArray::~PythonByteArray() {} bool PythonByteArray::Check(PyObject *py_obj) { if (!py_obj) return false; - if (PyByteArray_Check(py_obj)) - return true; - return false; + return PyByteArray_Check(py_obj); } void PythonByteArray::Reset(PyRefType type, PyObject *py_obj) { @@ -939,7 +935,8 @@ PythonFile::PythonFile() : PythonObject() {} PythonFile::PythonFile(File &file, const char *mode) { Reset(file, mode); } PythonFile::PythonFile(const char *path, const char *mode) { - lldb_private::File file(path, GetOptionsFromMode(mode)); + lldb_private::File file; + FileSystem::Instance().Open(file, FileSpec(path), GetOptionsFromMode(mode)); Reset(file, mode); } diff --git a/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index beeb64782367..7cd98df28ee0 100644 --- a/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -15,10 +15,6 @@ // LLDB Python header must be included first #include "lldb-python.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Utility/Flags.h" #include "lldb/Host/File.h" diff --git a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index b8eb36a2baf6..41cb443d4f1e 100644 --- a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -27,6 +27,7 @@ #include <string> #include "lldb/API/SBValue.h" +#include "lldb/API/SBFrame.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Breakpoint/WatchpointOptions.h" @@ -91,6 +92,10 @@ static ScriptInterpreterPython::SWIGPythonCallModuleInit g_swig_call_module_init = nullptr; static ScriptInterpreterPython::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = nullptr; +static ScriptInterpreterPython::SWIGPythonCreateFrameRecognizer + g_swig_create_frame_recognizer = nullptr; +static ScriptInterpreterPython::SWIGPythonGetRecognizedArguments + g_swig_get_recognized_arguments = nullptr; static ScriptInterpreterPython::SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = nullptr; static ScriptInterpreterPython::SWIGPythonScriptKeyword_Thread @@ -107,6 +112,10 @@ static ScriptInterpreterPython::SWIGPythonCreateScriptedThreadPlan g_swig_thread_plan_script = nullptr; static ScriptInterpreterPython::SWIGPythonCallThreadPlan g_swig_call_thread_plan = nullptr; +static ScriptInterpreterPython::SWIGPythonCreateScriptedBreakpointResolver + g_swig_bkpt_resolver_script = nullptr; +static ScriptInterpreterPython::SWIGPythonCallBreakpointResolver + g_swig_call_bkpt_resolver = nullptr; static bool g_initialized = false; @@ -128,6 +137,9 @@ public: InitializePythonHome(); + // Register _lldb as a built-in module. + PyImport_AppendInittab("_lldb", g_swig_init_callback); + // Python < 3.2 and Python >= 3.2 reversed the ordering requirements for // calling `Py_Initialize` and `PyEval_InitThreads`. < 3.2 requires that you // call `PyEval_InitThreads` first, and >= 3.2 requires that you call it last. @@ -196,7 +208,7 @@ ScriptInterpreterPython::Locker::Locker(ScriptInterpreterPython *py_interpreter, m_python_interpreter(py_interpreter) { DoAcquireLock(); if ((on_entry & InitSession) == InitSession) { - if (DoInitSession(on_entry, in, out, err) == false) { + if (!DoInitSession(on_entry, in, out, err)) { // Don't teardown the session if we didn't init it. m_teardown_session = false; } @@ -817,11 +829,15 @@ bool ScriptInterpreterPython::ExecuteOneLine( error_file_sp); } else { input_file_sp.reset(new StreamFile()); - input_file_sp->GetFile().Open(FileSystem::DEV_NULL, - File::eOpenOptionRead); + FileSystem::Instance().Open(input_file_sp->GetFile(), + FileSpec(FileSystem::DEV_NULL), + File::eOpenOptionRead); + output_file_sp.reset(new StreamFile()); - output_file_sp->GetFile().Open(FileSystem::DEV_NULL, - File::eOpenOptionWrite); + FileSystem::Instance().Open(output_file_sp->GetFile(), + FileSpec(FileSystem::DEV_NULL), + File::eOpenOptionWrite); + error_file_sp = output_file_sp; } @@ -1491,6 +1507,62 @@ bool ScriptInterpreterPython::GenerateTypeSynthClass(StringList &user_input, return true; } +StructuredData::GenericSP ScriptInterpreterPython::CreateFrameRecognizer( + const char *class_name) { + if (class_name == nullptr || class_name[0] == '\0') + return StructuredData::GenericSP(); + + void *ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + ret_val = + g_swig_create_frame_recognizer(class_name, m_dictionary_name.c_str()); + } + + return StructuredData::GenericSP(new StructuredPythonObject(ret_val)); +} + +lldb::ValueObjectListSP ScriptInterpreterPython::GetRecognizedArguments( + const StructuredData::ObjectSP &os_plugin_object_sp, + lldb::StackFrameSP frame_sp) { + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + if (!os_plugin_object_sp) return ValueObjectListSP(); + + StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); + if (!generic) return nullptr; + + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)generic->GetValue()); + + if (!implementor.IsAllocated()) return ValueObjectListSP(); + + PythonObject py_return( + PyRefType::Owned, + (PyObject *)g_swig_get_recognized_arguments(implementor.get(), frame_sp)); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + if (py_return.get()) { + PythonList result_list(PyRefType::Borrowed, py_return.get()); + ValueObjectListSP result = ValueObjectListSP(new ValueObjectList()); + for (size_t i = 0; i < result_list.GetSize(); i++) { + PyObject *item = result_list.GetItemAtIndex(i).get(); + lldb::SBValue *sb_value_ptr = + (lldb::SBValue *)g_swig_cast_to_sbvalue(item); + auto valobj_sp = g_swig_get_valobj_sp_from_sbvalue(sb_value_ptr); + if (valobj_sp) result->Append(valobj_sp); + } + return result; + } + return ValueObjectListSP(); +} + StructuredData::GenericSP ScriptInterpreterPython::OSPlugin_CreatePluginObject( const char *class_name, lldb::ProcessSP process_sp) { if (class_name == nullptr || class_name[0] == '\0') @@ -1868,10 +1940,88 @@ lldb::StateType ScriptInterpreterPython::ScriptedThreadPlanGetRunState( return lldb::eStateRunning; } +StructuredData::GenericSP +ScriptInterpreterPython::CreateScriptedBreakpointResolver( + const char *class_name, + StructuredDataImpl *args_data, + lldb::BreakpointSP &bkpt_sp) { + + if (class_name == nullptr || class_name[0] == '\0') + return StructuredData::GenericSP(); + + if (!bkpt_sp.get()) + return StructuredData::GenericSP(); + + Debugger &debugger = bkpt_sp->GetTarget().GetDebugger(); + ScriptInterpreter *script_interpreter = + debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = + static_cast<ScriptInterpreterPython *>(script_interpreter); + + if (!script_interpreter) + return StructuredData::GenericSP(); + + void *ret_val; + + { + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + + ret_val = g_swig_bkpt_resolver_script( + class_name, python_interpreter->m_dictionary_name.c_str(), + args_data, bkpt_sp); + } + + return StructuredData::GenericSP(new StructuredPythonObject(ret_val)); +} + +bool +ScriptInterpreterPython::ScriptedBreakpointResolverSearchCallback( + StructuredData::GenericSP implementor_sp, + SymbolContext *sym_ctx) { + bool should_continue = false; + + if (implementor_sp) { + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + should_continue + = g_swig_call_bkpt_resolver(implementor_sp->GetValue(), "__callback__", + sym_ctx); + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + } + return should_continue; +} + +lldb::SearchDepth +ScriptInterpreterPython::ScriptedBreakpointResolverSearchDepth( + StructuredData::GenericSP implementor_sp) { + int depth_as_int = lldb::eSearchDepthModule; + if (implementor_sp) { + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + depth_as_int + = g_swig_call_bkpt_resolver(implementor_sp->GetValue(), "__get_depth__", nullptr); + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + } + if (depth_as_int == lldb::eSearchDepthInvalid) + return lldb::eSearchDepthModule; + + if (depth_as_int <= lldb::kLastSearchDepthKind) + return (lldb::SearchDepth) depth_as_int; + else + return lldb::eSearchDepthModule; +} + StructuredData::ObjectSP ScriptInterpreterPython::LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { - if (!file_spec.Exists()) { + if (!FileSystem::Instance().Exists(file_spec)) { error.SetErrorString("no such file"); return StructuredData::ObjectSP(); } @@ -2603,7 +2753,8 @@ bool ScriptInterpreterPython::LoadScriptingModule( lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this(); { - FileSpec target_file(pathname, true); + FileSpec target_file(pathname); + FileSystem::Instance().Resolve(target_file); std::string basename(target_file.GetFilename().GetCString()); StreamString command_stream; @@ -2687,7 +2838,7 @@ bool ScriptInterpreterPython::LoadScriptingModule( bool was_imported = (was_imported_globally || was_imported_locally); - if (was_imported == true && can_reload == false) { + if (was_imported && !can_reload) { error.SetErrorString("module already imported"); return false; } @@ -3100,6 +3251,8 @@ void ScriptInterpreterPython::InitializeInterpreter( SWIGPythonCallCommandObject swig_call_command_object, SWIGPythonCallModuleInit swig_call_module_init, SWIGPythonCreateOSPlugin swig_create_os_plugin, + SWIGPythonCreateFrameRecognizer swig_create_frame_recognizer, + SWIGPythonGetRecognizedArguments swig_get_recognized_arguments, SWIGPythonScriptKeyword_Process swig_run_script_keyword_process, SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, @@ -3107,7 +3260,9 @@ void ScriptInterpreterPython::InitializeInterpreter( SWIGPythonScriptKeyword_Value swig_run_script_keyword_value, SWIGPython_GetDynamicSetting swig_plugin_get, SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, - SWIGPythonCallThreadPlan swig_call_thread_plan) { + SWIGPythonCallThreadPlan swig_call_thread_plan, + SWIGPythonCreateScriptedBreakpointResolver swig_bkpt_resolver_script, + SWIGPythonCallBreakpointResolver swig_call_bkpt_resolver) { g_swig_init_callback = swig_init_callback; g_swig_breakpoint_callback = swig_breakpoint_callback; g_swig_watchpoint_callback = swig_watchpoint_callback; @@ -3126,6 +3281,8 @@ void ScriptInterpreterPython::InitializeInterpreter( g_swig_call_command_object = swig_call_command_object; g_swig_call_module_init = swig_call_module_init; g_swig_create_os_plugin = swig_create_os_plugin; + g_swig_create_frame_recognizer = swig_create_frame_recognizer; + g_swig_get_recognized_arguments = swig_get_recognized_arguments; g_swig_run_script_keyword_process = swig_run_script_keyword_process; g_swig_run_script_keyword_thread = swig_run_script_keyword_thread; g_swig_run_script_keyword_target = swig_run_script_keyword_target; @@ -3134,6 +3291,8 @@ void ScriptInterpreterPython::InitializeInterpreter( g_swig_plugin_get = swig_plugin_get; g_swig_thread_plan_script = swig_thread_plan_script; g_swig_call_thread_plan = swig_call_thread_plan; + g_swig_bkpt_resolver_script = swig_bkpt_resolver_script; + g_swig_call_bkpt_resolver = swig_call_bkpt_resolver; } void ScriptInterpreterPython::InitializePrivate() { diff --git a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h index b13979dc069b..a047359883ce 100644 --- a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -16,14 +16,10 @@ #else -// C Includes -// C++ Includes #include <memory> #include <string> #include <vector> -// Other libraries and framework includes -// Project includes #include "PythonDataObjects.h" #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Core/IOHandler.h" @@ -81,10 +77,25 @@ public: const char *method_name, Event *event_sp, bool &got_error); + typedef void *(*SWIGPythonCreateScriptedBreakpointResolver)( + const char *python_class_name, const char *session_dictionary_name, + lldb_private::StructuredDataImpl *args_impl, + lldb::BreakpointSP &bkpt_sp); + + typedef unsigned int (*SWIGPythonCallBreakpointResolver)(void *implementor, + const char *method_name, + lldb_private::SymbolContext *sym_ctx); + typedef void *(*SWIGPythonCreateOSPlugin)(const char *python_class_name, const char *session_dictionary_name, const lldb::ProcessSP &process_sp); + typedef void *(*SWIGPythonCreateFrameRecognizer)( + const char *python_class_name, const char *session_dictionary_name); + + typedef void *(*SWIGPythonGetRecognizedArguments)( + void *implementor, const lldb::StackFrameSP &frame_sp); + typedef size_t (*SWIGPythonCalculateNumChildren)(void *implementor, uint32_t max); @@ -208,6 +219,26 @@ public: lldb::StateType ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, bool &script_error) override; + + StructuredData::GenericSP + CreateScriptedBreakpointResolver(const char *class_name, + StructuredDataImpl *args_data, + lldb::BreakpointSP &bkpt_sp) override; + bool + ScriptedBreakpointResolverSearchCallback(StructuredData::GenericSP + implementor_sp, + SymbolContext *sym_ctx) override; + + lldb::SearchDepth + ScriptedBreakpointResolverSearchDepth(StructuredData::GenericSP + implementor_sp) override; + + StructuredData::GenericSP + CreateFrameRecognizer(const char *class_name) override; + + lldb::ValueObjectListSP + GetRecognizedArguments(const StructuredData::ObjectSP &implementor, + lldb::StackFrameSP frame_sp) override; StructuredData::GenericSP OSPlugin_CreatePluginObject(const char *class_name, @@ -404,6 +435,8 @@ public: SWIGPythonCallCommandObject swig_call_command_object, SWIGPythonCallModuleInit swig_call_module_init, SWIGPythonCreateOSPlugin swig_create_os_plugin, + SWIGPythonCreateFrameRecognizer swig_create_frame_recognizer, + SWIGPythonGetRecognizedArguments swig_get_recognized_arguments, SWIGPythonScriptKeyword_Process swig_run_script_keyword_process, SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, @@ -411,7 +444,9 @@ public: SWIGPythonScriptKeyword_Value swig_run_script_keyword_value, SWIGPython_GetDynamicSetting swig_plugin_get, SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, - SWIGPythonCallThreadPlan swig_call_thread_plan); + SWIGPythonCallThreadPlan swig_call_thread_plan, + SWIGPythonCreateScriptedBreakpointResolver swig_bkpt_resolver_script, + SWIGPythonCallBreakpointResolver swig_call_breakpoint_resolver); const char *GetDictionaryName() { return m_dictionary_name.c_str(); } diff --git a/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp b/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp index e33e26507fb1..6e3792bff9c4 100644 --- a/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp +++ b/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp @@ -112,14 +112,14 @@ void SetGlobalEnableOptions(const DebuggerSP &debugger_sp, /// Code to handle the StructuredDataDarwinLog settings //------------------------------------------------------------------ -static PropertyDefinition g_properties[] = { +static constexpr PropertyDefinition g_properties[] = { { "enable-on-startup", // name OptionValue::eTypeBoolean, // type true, // global false, // default uint value nullptr, // default cstring value - nullptr, // enum values + {}, // enum values "Enable Darwin os_log collection when debugged process is launched " "or attached." // description }, @@ -129,13 +129,11 @@ static PropertyDefinition g_properties[] = { true, // global 0, // default uint value "", // default cstring value - nullptr, // enum values + {}, // enum values "Specify the options to 'plugin structured-data darwin-log enable' " "that should be applied when automatically enabling logging on " "startup/attach." // description - }, - // Last entry sentinel. - {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}}; + }}; enum { ePropertyEnableOnStartup = 0, ePropertyAutoEnableOptions = 1 }; @@ -402,23 +400,23 @@ static void RegisterFilterOperations() { /// This resets the logging with whatever settings are currently set. // ------------------------------------------------------------------------- -static OptionDefinition g_enable_option_table[] = { +static constexpr OptionDefinition g_enable_option_table[] = { // Source stream include/exclude options (the first-level filter). This one // should be made as small as possible as everything that goes through here // must be processed by the process monitor. {LLDB_OPT_SET_ALL, false, "any-process", 'a', OptionParser::eNoArgument, - nullptr, nullptr, 0, eArgTypeNone, + nullptr, {}, 0, eArgTypeNone, "Specifies log messages from other related processes should be " "included."}, {LLDB_OPT_SET_ALL, false, "debug", 'd', OptionParser::eNoArgument, nullptr, - nullptr, 0, eArgTypeNone, + {}, 0, eArgTypeNone, "Specifies debug-level log messages should be included. Specifying" " --debug implies --info."}, {LLDB_OPT_SET_ALL, false, "info", 'i', OptionParser::eNoArgument, nullptr, - nullptr, 0, eArgTypeNone, + {}, 0, eArgTypeNone, "Specifies info-level log messages should be included."}, {LLDB_OPT_SET_ALL, false, "filter", 'f', OptionParser::eRequiredArgument, - nullptr, nullptr, 0, eArgRawInput, + nullptr, {}, 0, eArgRawInput, // There doesn't appear to be a great way for me to have these multi-line, // formatted tables in help. This looks mostly right but there are extra // linefeeds added at seemingly random spots, and indentation isn't @@ -452,52 +450,52 @@ static OptionDefinition g_enable_option_table[] = { "Prefer character classes like [[:digit:]] to \\d and the like, as " "getting the backslashes escaped through properly is error-prone."}, {LLDB_OPT_SET_ALL, false, "live-stream", 'l', - OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, + OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "Specify whether logging events are live-streamed or buffered. " "True indicates live streaming, false indicates buffered. The " "default is true (live streaming). Live streaming will deliver " "log messages with less delay, but buffered capture mode has less " "of an observer effect."}, {LLDB_OPT_SET_ALL, false, "no-match-accepts", 'n', - OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, + OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "Specify whether a log message that doesn't match any filter rule " "is accepted or rejected, where true indicates accept. The " "default is true."}, {LLDB_OPT_SET_ALL, false, "echo-to-stderr", 'e', - OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, + OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "Specify whether os_log()/NSLog() messages are echoed to the " "target program's stderr. When DarwinLog is enabled, we shut off " "the mirroring of os_log()/NSLog() to the program's stderr. " "Setting this flag to true will restore the stderr mirroring." "The default is false."}, {LLDB_OPT_SET_ALL, false, "broadcast-events", 'b', - OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, + OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "Specify if the plugin should broadcast events. Broadcasting " "log events is a requirement for displaying the log entries in " "LLDB command-line. It is also required if LLDB clients want to " "process log events. The default is true."}, // Message formatting options {LLDB_OPT_SET_ALL, false, "timestamp-relative", 'r', - OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, + OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Include timestamp in the message header when printing a log " "message. The timestamp is relative to the first displayed " "message."}, {LLDB_OPT_SET_ALL, false, "subsystem", 's', OptionParser::eNoArgument, - nullptr, nullptr, 0, eArgTypeNone, - "Include the subsystem in the the message header when displaying " + nullptr, {}, 0, eArgTypeNone, + "Include the subsystem in the message header when displaying " "a log message."}, {LLDB_OPT_SET_ALL, false, "category", 'c', OptionParser::eNoArgument, - nullptr, nullptr, 0, eArgTypeNone, + nullptr, {}, 0, eArgTypeNone, "Include the category in the message header when displaying " "a log message."}, {LLDB_OPT_SET_ALL, false, "activity-chain", 'C', OptionParser::eNoArgument, - nullptr, nullptr, 0, eArgTypeNone, + nullptr, {}, 0, eArgTypeNone, "Include the activity parent-child chain in the message header " "when displaying a log message. The activity hierarchy is " "displayed as {grandparent-activity}:" "{parent-activity}:{activity}[:...]."}, {LLDB_OPT_SET_ALL, false, "all-fields", 'A', OptionParser::eNoArgument, - nullptr, nullptr, 0, eArgTypeNone, + nullptr, {}, 0, eArgTypeNone, "Shortcut to specify that all header fields should be displayed."}}; class EnableOptions : public Options { @@ -1679,7 +1677,7 @@ void StructuredDataDarwinLog::AddInitCompletionHook(Process &process) { // Build up the module list. FileSpecList module_spec_list; auto module_file_spec = - FileSpec(GetGlobalProperties()->GetLoggingModuleName(), false); + FileSpec(GetGlobalProperties()->GetLoggingModuleName()); module_spec_list.Append(module_file_spec); // We aren't specifying a source file set. diff --git a/source/Plugins/SymbolFile/Breakpad/CMakeLists.txt b/source/Plugins/SymbolFile/Breakpad/CMakeLists.txt new file mode 100644 index 000000000000..e93d0618a0e4 --- /dev/null +++ b/source/Plugins/SymbolFile/Breakpad/CMakeLists.txt @@ -0,0 +1,12 @@ +add_lldb_library(lldbPluginSymbolFileBreakpad PLUGIN + SymbolFileBreakpad.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbUtility + lldbPluginObjectFileBreakpad + LINK_COMPONENTS + Support + ) diff --git a/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp new file mode 100644 index 000000000000..2cca7a66b014 --- /dev/null +++ b/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -0,0 +1,223 @@ +//===-- SymbolFileBreakpad.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h" +#include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/TypeMap.h" +#include "lldb/Utility/Log.h" +#include "llvm/ADT/StringExtras.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::breakpad; + +namespace { +class LineIterator { +public: + // begin iterator for sections of given type + LineIterator(ObjectFile &obj, ConstString section_type) + : m_obj(&obj), m_section_type(section_type), m_next_section_idx(0) { + ++*this; + } + + // end iterator + explicit LineIterator(ObjectFile &obj) + : m_obj(&obj), + m_next_section_idx(m_obj->GetSectionList()->GetNumSections(0)) {} + + friend bool operator!=(const LineIterator &lhs, const LineIterator &rhs) { + assert(lhs.m_obj == rhs.m_obj); + if (lhs.m_next_section_idx != rhs.m_next_section_idx) + return true; + if (lhs.m_next_text.data() != rhs.m_next_text.data()) + return true; + assert(lhs.m_current_text == rhs.m_current_text); + assert(rhs.m_next_text == rhs.m_next_text); + return false; + } + + const LineIterator &operator++(); + llvm::StringRef operator*() const { return m_current_text; } + +private: + ObjectFile *m_obj; + ConstString m_section_type; + uint32_t m_next_section_idx; + llvm::StringRef m_current_text; + llvm::StringRef m_next_text; +}; +} // namespace + +const LineIterator &LineIterator::operator++() { + const SectionList &list = *m_obj->GetSectionList(); + size_t num_sections = list.GetNumSections(0); + while (m_next_text.empty() && m_next_section_idx < num_sections) { + Section § = *list.GetSectionAtIndex(m_next_section_idx++); + if (sect.GetName() != m_section_type) + continue; + DataExtractor data; + m_obj->ReadSectionData(§, data); + m_next_text = + llvm::StringRef(reinterpret_cast<const char *>(data.GetDataStart()), + data.GetByteSize()); + } + std::tie(m_current_text, m_next_text) = m_next_text.split('\n'); + return *this; +} + +static llvm::iterator_range<LineIterator> lines(ObjectFile &obj, + ConstString section_type) { + return llvm::make_range(LineIterator(obj, section_type), LineIterator(obj)); +} + +void SymbolFileBreakpad::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); +} + +void SymbolFileBreakpad::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString SymbolFileBreakpad::GetPluginNameStatic() { + static ConstString g_name("breakpad"); + return g_name; +} + +uint32_t SymbolFileBreakpad::CalculateAbilities() { + if (!m_obj_file) + return 0; + if (m_obj_file->GetPluginName() != ObjectFileBreakpad::GetPluginNameStatic()) + return 0; + + return CompileUnits | Functions; +} + +uint32_t SymbolFileBreakpad::GetNumCompileUnits() { + // TODO + return 0; +} + +CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) { + // TODO + return nullptr; +} + +size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) { + // TODO + return 0; +} + +bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) { + // TODO + return 0; +} + +uint32_t +SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr, + SymbolContextItem resolve_scope, + SymbolContext &sc) { + // TODO + return 0; +} + +uint32_t SymbolFileBreakpad::FindFunctions( + const ConstString &name, const CompilerDeclContext *parent_decl_ctx, + FunctionNameType name_type_mask, bool include_inlines, bool append, + SymbolContextList &sc_list) { + // TODO + if (!append) + sc_list.Clear(); + return sc_list.GetSize(); +} + +uint32_t SymbolFileBreakpad::FindFunctions(const RegularExpression ®ex, + bool include_inlines, bool append, + SymbolContextList &sc_list) { + // TODO + if (!append) + sc_list.Clear(); + return sc_list.GetSize(); +} + +uint32_t SymbolFileBreakpad::FindTypes( + const ConstString &name, const CompilerDeclContext *parent_decl_ctx, + bool append, uint32_t max_matches, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) { + if (!append) + types.Clear(); + return types.GetSize(); +} + +size_t +SymbolFileBreakpad::FindTypes(const std::vector<CompilerContext> &context, + bool append, TypeMap &types) { + if (!append) + types.Clear(); + return types.GetSize(); +} + +void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); + Module &module = *m_obj_file->GetModule(); + addr_t base = module.GetObjectFile()->GetBaseAddress().GetFileAddress(); + if (base == LLDB_INVALID_ADDRESS) { + LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping " + "symtab population."); + return; + } + + const SectionList &list = *module.GetSectionList(); + for (llvm::StringRef line : lines(*m_obj_file, ConstString("PUBLIC"))) { + // PUBLIC [m] address param_size name + // skip PUBLIC keyword + line = getToken(line).second; + llvm::StringRef token; + std::tie(token, line) = getToken(line); + if (token == "m") + std::tie(token, line) = getToken(line); + + addr_t address; + if (!to_integer(token, address, 16)) + continue; + address += base; + + // skip param_size + line = getToken(line).second; + + llvm::StringRef name = line.trim(); + + SectionSP section_sp = list.FindSectionContainingFileAddress(address); + if (!section_sp) { + LLDB_LOG(log, + "Ignoring symbol {0}, whose address ({1}) is outside of the " + "object file. Mismatched symbol file?", + name, address); + continue; + } + + symtab.AddSymbol(Symbol( + /*symID*/ 0, Mangled(name, /*is_mangled*/ false), eSymbolTypeCode, + /*is_global*/ true, /*is_debug*/ false, /*is_trampoline*/ false, + /*is_artificial*/ false, + AddressRange(section_sp, address - section_sp->GetFileAddress(), 0), + /*size_is_valid*/ 0, /*contains_linker_annotations*/ false, + /*flags*/ 0)); + } + + // TODO: Process FUNC records as well. + + symtab.CalculateSymbolSizes(); +} diff --git a/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h new file mode 100644 index 000000000000..68e8d11c7dd7 --- /dev/null +++ b/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -0,0 +1,146 @@ +//===-- SymbolFileBreakpad.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILE_BREAKPAD_SYMBOLFILEBREAKPAD_H +#define LLDB_PLUGINS_SYMBOLFILE_BREAKPAD_SYMBOLFILEBREAKPAD_H + +#include "lldb/Symbol/SymbolFile.h" + +namespace lldb_private { + +namespace breakpad { + +class SymbolFileBreakpad : public SymbolFile { +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + static void Terminate(); + static void DebuggerInitialize(Debugger &debugger) {} + static ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic() { + return "Breakpad debug symbol file reader."; + } + + static SymbolFile *CreateInstance(ObjectFile *obj_file) { + return new SymbolFileBreakpad(obj_file); + } + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + SymbolFileBreakpad(ObjectFile *object_file) : SymbolFile(object_file) {} + + ~SymbolFileBreakpad() override {} + + uint32_t CalculateAbilities() override; + + void InitializeObject() override {} + + //------------------------------------------------------------------ + // Compile Unit function calls + //------------------------------------------------------------------ + + uint32_t GetNumCompileUnits() override; + + lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; + + lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) override { + return lldb::eLanguageTypeUnknown; + } + + size_t ParseFunctions(CompileUnit &comp_unit) override; + + bool ParseLineTable(CompileUnit &comp_unit) override; + + bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; } + + bool ParseSupportFiles(CompileUnit &comp_unit, + FileSpecList &support_files) override { + return false; + } + size_t ParseTypes(CompileUnit &cu) override { return 0; } + + bool + ParseImportedModules(const SymbolContext &sc, + std::vector<ConstString> &imported_modules) override { + return false; + } + + size_t ParseBlocksRecursive(Function &func) override { return 0; } + + uint32_t FindGlobalVariables(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, + uint32_t max_matches, + VariableList &variables) override { + return 0; + } + + size_t ParseVariablesForContext(const SymbolContext &sc) override { + return 0; + } + Type *ResolveTypeUID(lldb::user_id_t type_uid) override { return nullptr; } + llvm::Optional<ArrayInfo> GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, + const lldb_private::ExecutionContext *exe_ctx) override { + return llvm::None; + } + + bool CompleteType(CompilerType &compiler_type) override { return false; } + uint32_t ResolveSymbolContext(const Address &so_addr, + lldb::SymbolContextItem resolve_scope, + SymbolContext &sc) override; + + size_t GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask, + TypeList &type_list) override { + return 0; + } + + uint32_t FindFunctions(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, + lldb::FunctionNameType name_type_mask, + bool include_inlines, bool append, + SymbolContextList &sc_list) override; + + uint32_t FindFunctions(const RegularExpression ®ex, bool include_inlines, + bool append, SymbolContextList &sc_list) override; + + uint32_t FindTypes(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, bool append, + uint32_t max_matches, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, + TypeMap &types) override; + + size_t FindTypes(const std::vector<CompilerContext> &context, bool append, + TypeMap &types) override; + + TypeSystem *GetTypeSystemForLanguage(lldb::LanguageType language) override { + return nullptr; + } + + CompilerDeclContext + FindNamespace(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx) override { + return CompilerDeclContext(); + } + + void AddSymbols(Symtab &symtab) override; + + ConstString GetPluginName() override { return GetPluginNameStatic(); } + uint32_t GetPluginVersion() override { return 1; } + +private: +}; + +} // namespace breakpad +} // namespace lldb_private + +#endif diff --git a/source/Plugins/SymbolFile/CMakeLists.txt b/source/Plugins/SymbolFile/CMakeLists.txt index 98510704ce73..ad1c92bd8469 100644 --- a/source/Plugins/SymbolFile/CMakeLists.txt +++ b/source/Plugins/SymbolFile/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(Breakpad) add_subdirectory(DWARF) add_subdirectory(Symtab) +add_subdirectory(NativePDB) add_subdirectory(PDB) diff --git a/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/source/Plugins/SymbolFile/DWARF/CMakeLists.txt index f62a496f808a..0e47ee34fe51 100644 --- a/source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ b/source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -4,9 +4,6 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN DIERef.cpp DWARFAbbreviationDeclaration.cpp DWARFASTParserClang.cpp - DWARFASTParserGo.cpp - DWARFASTParserJava.cpp - DWARFASTParserOCaml.cpp DWARFAttribute.cpp DWARFBaseDIE.cpp DWARFCompileUnit.cpp diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h index ae7c770d6ef7..24d5f26745dc 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h @@ -12,10 +12,16 @@ #include "DWARFDefines.h" #include "lldb/Core/PluginInterface.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" class DWARFDIE; +namespace lldb_private { +class CompileUnit; +class ExecutionContext; +} +class SymbolFileDWARF; class DWARFASTParser { public: @@ -27,7 +33,7 @@ public: bool *type_is_new_ptr) = 0; virtual lldb_private::Function * - ParseFunctionFromDWARF(const lldb_private::SymbolContext &sc, + ParseFunctionFromDWARF(lldb_private::CompileUnit &comp_unit, const DWARFDIE &die) = 0; virtual bool @@ -45,6 +51,10 @@ public: virtual std::vector<DWARFDIE> GetDIEForDeclContext(lldb_private::CompilerDeclContext decl_context) = 0; + + static llvm::Optional<lldb_private::SymbolFile::ArrayInfo> + ParseChildArrayInfo(const DWARFDIE &parent_die, + const lldb_private::ExecutionContext *exe_ctx = nullptr); }; #endif // SymbolFileDWARF_DWARFASTParser_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index fe6f1be3ca48..70d48e5f1dfa 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -125,7 +125,7 @@ ClangASTImporter &DWARFASTParserClang::GetClangASTImporter() { } /// Detect a forward declaration that is nested in a DW_TAG_module. -static bool isClangModuleFwdDecl(const DWARFDIE &Die) { +static bool IsClangModuleFwdDecl(const DWARFDIE &Die) { if (!Die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0)) return false; auto Parent = Die.GetParent(); @@ -142,30 +142,31 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWO(const DWARFDIE &die, Log *log) { if (!dwo_module_sp) return TypeSP(); - // This type comes from an external DWO module. - std::vector<CompilerContext> dwo_context; - die.GetDWOContext(dwo_context); + // If this type comes from a Clang module, look in the DWARF section + // of the pcm file in the module cache. Clang generates DWO skeleton + // units as breadcrumbs to find them. + std::vector<CompilerContext> decl_context; + die.GetDeclContext(decl_context); TypeMap dwo_types; - if (!dwo_module_sp->GetSymbolVendor()->FindTypes(dwo_context, true, + if (!dwo_module_sp->GetSymbolVendor()->FindTypes(decl_context, true, dwo_types)) { - if (!isClangModuleFwdDecl(die)) + if (!IsClangModuleFwdDecl(die)) return TypeSP(); // Since this this type is defined in one of the Clang modules imported by // this symbol file, search all of them. - auto *SymFile = die.GetCU()->GetSymbolFileDWARF(); - for (const auto &NameModule : SymFile->getExternalTypeModules()) { - if (!NameModule.second) + auto *sym_file = die.GetCU()->GetSymbolFileDWARF(); + for (const auto &name_module : sym_file->getExternalTypeModules()) { + if (!name_module.second) continue; - SymbolVendor *SymVendor = NameModule.second->GetSymbolVendor(); - if (SymVendor->FindTypes(dwo_context, true, dwo_types)) + SymbolVendor *sym_vendor = name_module.second->GetSymbolVendor(); + if (sym_vendor->FindTypes(decl_context, true, dwo_types)) break; } } - const size_t num_dwo_types = dwo_types.GetSize(); - if (num_dwo_types != 1) + if (dwo_types.GetSize() != 1) return TypeSP(); // We found a real definition for this type in the Clang module, so lets use @@ -307,14 +308,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, decl.SetColumn(form_value.Unsigned()); break; case DW_AT_name: - type_name_cstr = form_value.AsCString(); - // Work around a bug in llvm-gcc where they give a name to a - // reference type which doesn't include the "&"... - if (tag == DW_TAG_reference_type) { - if (strchr(type_name_cstr, '&') == NULL) - type_name_cstr = NULL; - } if (type_name_cstr) type_name_const_str.SetCString(type_name_cstr); break; @@ -421,8 +415,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || - encoding_data_type == Type::eEncodingIsTypedefUID) && - sc.comp_unit != NULL) { + encoding_data_type == Type::eEncodingIsTypedefUID)) { if (tag == DW_TAG_pointer_type) { DWARFDIE target_die = die.GetReferencedDIE(DW_AT_type); @@ -558,16 +551,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (attributes.ExtractFormValueAtIndex(i, form_value)) { switch (attr) { case DW_AT_decl_file: - if (die.GetCU()->DW_AT_decl_file_attributes_are_invalid()) { - // llvm-gcc outputs invalid DW_AT_decl_file attributes that - // always point to the compile unit file, so we clear this - // invalid value so that we can still unique types - // efficiently. - decl.SetFile(FileSpec("<invalid>", false)); - } else - decl.SetFile( - sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex( - form_value.Unsigned())); + decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex( + form_value.Unsigned())); break; case DW_AT_decl_line: @@ -671,7 +656,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } if (byte_size_valid && byte_size == 0 && type_name_cstr && - die.HasChildren() == false && + !die.HasChildren() && sc.comp_unit->GetLanguage() == eLanguageTypeObjC) { // Work around an issue with clang at the moment where forward // declarations for objective C classes are emitted as: @@ -909,7 +894,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, // has child classes or types that require the class to be created // for use as their decl contexts the class will be ready to accept // these child definitions. - if (die.HasChildren() == false) { + if (!die.HasChildren()) { // No children for this struct/union/class, lets finish it if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { ClangASTContext::CompleteTagDeclarationDefinition(clang_type); @@ -1308,10 +1293,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (die.HasChildren()) { bool skip_artificial = true; - ParseChildParameters(sc, containing_decl_ctx, die, skip_artificial, - is_static, is_variadic, has_template_params, - function_param_types, function_param_decls, - type_quals); + ParseChildParameters(*sc.comp_unit, containing_decl_ctx, die, + skip_artificial, is_static, is_variadic, + has_template_params, function_param_types, + function_param_decls, type_quals); } bool ignore_containing_context = false; @@ -1748,16 +1733,19 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, Type *element_type = dwarf->ResolveTypeUID(type_die_ref); if (element_type) { - std::vector<uint64_t> element_orders; - ParseChildArrayInfo(sc, die, first_index, element_orders, - byte_stride, bit_stride); + auto array_info = ParseChildArrayInfo(die); + if (array_info) { + first_index = array_info->first_index; + byte_stride = array_info->byte_stride; + bit_stride = array_info->bit_stride; + } if (byte_stride == 0 && bit_stride == 0) byte_stride = element_type->GetByteSize(); CompilerType array_element_type = element_type->GetForwardCompilerType(); if (ClangASTContext::IsCXXClassType(array_element_type) && - array_element_type.GetCompleteType() == false) { + !array_element_type.GetCompleteType()) { ModuleSP module_sp = die.GetModule(); if (module_sp) { if (die.GetCU()->GetProducer() == eProducerClang) @@ -1800,12 +1788,11 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } uint64_t array_element_bit_stride = byte_stride * 8 + bit_stride; - if (element_orders.size() > 0) { + if (array_info && array_info->element_orders.size() > 0) { uint64_t num_elements = 0; - std::vector<uint64_t>::const_reverse_iterator pos; - std::vector<uint64_t>::const_reverse_iterator end = - element_orders.rend(); - for (pos = element_orders.rbegin(); pos != end; ++pos) { + auto end = array_info->element_orders.rend(); + for (auto pos = array_info->element_orders.rbegin(); pos != end; + ++pos) { num_elements = *pos; clang_type = m_ast.CreateArrayType(array_element_type, num_elements, is_vector); @@ -1824,6 +1811,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, NULL, DIERef(type_die_form).GetUID(dwarf), Type::eEncodingIsUID, &decl, clang_type, Type::eResolveStateFull)); type_sp->SetEncodingType(element_type); + m_ast.SetMetadataAsUserID(clang_type.GetOpaqueQualType(), + die.GetID()); } } } break; @@ -1861,12 +1850,14 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, clang_type = ClangASTContext::CreateMemberPointerType( class_clang_type, pointee_clang_type); - byte_size = clang_type.GetByteSize(nullptr); - - type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, - byte_size, NULL, LLDB_INVALID_UID, - Type::eEncodingIsUID, NULL, clang_type, - Type::eResolveStateForward)); + if (llvm::Optional<uint64_t> clang_type_size = + clang_type.GetByteSize(nullptr)) { + byte_size = *clang_type_size; + type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, + byte_size, NULL, LLDB_INVALID_UID, + Type::eEncodingIsUID, NULL, clang_type, + Type::eResolveStateForward)); + } } break; @@ -2056,7 +2047,10 @@ bool DWARFASTParserClang::ParseTemplateDIE( clang_type.IsIntegerOrEnumerationType(is_signed); if (tag == DW_TAG_template_value_parameter && uval64_valid) { - llvm::APInt apint(clang_type.GetBitSize(nullptr), uval64, is_signed); + llvm::Optional<uint64_t> size = clang_type.GetBitSize(nullptr); + if (!size) + return false; + llvm::APInt apint(*size, uval64, is_signed); template_param_infos.args.push_back( clang::TemplateArgument(*ast, llvm::APSInt(apint, !is_signed), ClangUtil::GetQualType(clang_type))); @@ -2108,95 +2102,6 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( return template_param_infos.args.size() == template_param_infos.names.size(); } -// 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). -static 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. -static 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)); - } -} - -// If clang_type is a CXXRecordDecl, builds the method override list for each -// of its virtual methods. -static void addMethodOverrides(ClangASTContext &ast, CompilerType &clang_type) { - if (auto *record = - ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType())) - for (auto *method : record->methods()) - addOverridesForMethod(method); -} - bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, CompilerType &clang_type) { @@ -2287,14 +2192,14 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, } SymbolContext sc(die.GetLLDBCompileUnit()); - std::vector<clang::CXXBaseSpecifier *> base_classes; + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; std::vector<int> member_accessibilities; bool is_a_class = false; // Parse members and base classes first DWARFDIECollection member_function_dies; DelayedPropertyList delayed_properties; - ParseChildMembers(sc, die, clang_type, class_language, base_classes, + ParseChildMembers(sc, die, clang_type, class_language, bases, member_accessibilities, member_function_dies, delayed_properties, default_accessibility, is_a_class, layout_info); @@ -2358,17 +2263,17 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, &member_accessibilities.front(), member_accessibilities.size()); } - if (!base_classes.empty()) { + 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.SetBaseClassesForClassType() - for (auto &base_class : base_classes) { + // 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, type_source_info->getType().getAsOpaquePtr()); - if (base_class_type.GetCompleteType() == false) { + 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.", @@ -2381,7 +2286,7 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, // 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.SetBaseClassesForClassType()" below. Since we + // "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. @@ -2393,19 +2298,14 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, } } } - m_ast.SetBaseClassesForClassType(clang_type.GetOpaqueQualType(), - &base_classes.front(), - base_classes.size()); - - // Clang will copy each CXXBaseSpecifier in "base_classes" so we have - // to free them all. - ClangASTContext::DeleteBaseClassSpecifiers(&base_classes.front(), - base_classes.size()); + + m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), + std::move(bases)); } } } - addMethodOverrides(m_ast, clang_type); + m_ast.AddMethodOverridesForCXXRecordType(clang_type.GetOpaqueQualType()); ClangASTContext::BuildIndirectFields(clang_type); ClangASTContext::CompleteTagDeclarationDefinition(clang_type); @@ -2604,9 +2504,7 @@ size_t DWARFASTParserClang::ParseChildEnumerators( if (name && name[0] && got_value) { m_ast.AddEnumerationValueToEnumerationType( - clang_type.GetOpaqueQualType(), - m_ast.GetEnumerationIntegerType(clang_type.GetOpaqueQualType()), - decl, name, enum_value, enumerator_byte_size * 8); + clang_type, decl, name, enum_value, enumerator_byte_size * 8); ++enumerators_added; } } @@ -2663,7 +2561,7 @@ protected: }; #endif -Function *DWARFASTParserClang::ParseFunctionFromDWARF(const SymbolContext &sc, +Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, const DWARFDIE &die) { DWARFRangeList func_ranges; const char *name = NULL; @@ -2724,9 +2622,9 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(const SymbolContext &sc, clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); - ParseChildParameters(sc, containing_decl_ctx, die, true, is_static, - is_variadic, has_template_params, param_types, - param_decls, type_quals); + ParseChildParameters(comp_unit, containing_decl_ctx, die, true, + is_static, is_variadic, has_template_params, + param_types, param_decls, type_quals); sstr << "("; for (size_t i = 0; i < param_types.size(); i++) { if (i > 0) @@ -2747,7 +2645,7 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(const SymbolContext &sc, std::unique_ptr<Declaration> decl_ap; if (decl_file != 0 || decl_line != 0 || decl_column != 0) decl_ap.reset(new Declaration( - sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), + comp_unit.GetSupportFiles().GetFileSpecAtIndex(decl_file), decl_line, decl_column)); SymbolFileDWARF *dwarf = die.GetDWARF(); @@ -2758,7 +2656,7 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(const SymbolContext &sc, if (dwarf->FixupAddress(func_range.GetBaseAddress())) { const user_id_t func_user_id = die.GetID(); - func_sp.reset(new Function(sc.comp_unit, + func_sp.reset(new Function(&comp_unit, func_user_id, // UserID is the DIE offset func_user_id, func_name, func_type, func_range)); // first address range @@ -2766,7 +2664,7 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(const SymbolContext &sc, if (func_sp.get() != NULL) { if (frame_base.IsValid()) func_sp->GetFrameBaseExpression() = frame_base; - sc.comp_unit->AddFunction(func_sp); + comp_unit.AddFunction(func_sp); return func_sp.get(); } } @@ -2778,7 +2676,7 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(const SymbolContext &sc, bool DWARFASTParserClang::ParseChildMembers( const SymbolContext &sc, const DWARFDIE &parent_die, CompilerType &class_clang_type, const LanguageType class_language, - std::vector<clang::CXXBaseSpecifier *> &base_classes, + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes, std::vector<int> &member_accessibilities, DWARFDIECollection &member_function_dies, DelayedPropertyList &delayed_properties, AccessType &default_accessibility, @@ -2977,15 +2875,6 @@ bool DWARFASTParserClang::ParseChildMembers( class_language == eLanguageTypeObjC_plus_plus) accessibility = eAccessNone; - if (member_idx == 0 && !is_artificial && name && - (strstr(name, "_vptr$") == name)) { - // Not all compilers will mark the vtable pointer member as - // artificial (llvm-gcc). We can't have the virtual members in our - // classes otherwise it throws off all child offsets since we end up - // having and extra pointer sized member in our class layouts. - is_artificial = true; - } - // Handle static members if (is_external && member_byte_offset == UINT32_MAX) { Type *var_type = die.ResolveTypeUID(DIERef(encoding_form)); @@ -3000,7 +2889,7 @@ bool DWARFASTParserClang::ParseChildMembers( break; } - if (is_artificial == false) { + if (!is_artificial) { Type *member_type = die.ResolveTypeUID(DIERef(encoding_form)); clang::FieldDecl *field_decl = NULL; @@ -3141,7 +3030,7 @@ bool DWARFASTParserClang::ParseChildMembers( if (anon_field_info.IsValid()) { clang::FieldDecl *unnamed_bitfield_decl = ClangASTContext::AddFieldToRecordType( - class_clang_type, NULL, + class_clang_type, llvm::StringRef(), m_ast.GetBuiltinTypeForEncodingAndBitSize( eEncodingSint, word_width), accessibility, anon_field_info.bit_size); @@ -3198,7 +3087,7 @@ bool DWARFASTParserClang::ParseChildMembers( } if (ClangASTContext::IsCXXClassType(member_clang_type) && - member_clang_type.GetCompleteType() == false) { + !member_clang_type.GetCompleteType()) { if (die.GetCU()->GetProducer() == eProducerClang) module_sp->ReportError( "DWARF DIE at 0x%8.8x (class %s) has a member variable " @@ -3383,9 +3272,14 @@ bool DWARFASTParserClang::ParseChildMembers( if (class_language == eLanguageTypeObjC) { ast->SetObjCSuperClass(class_clang_type, base_class_clang_type); } else { - base_classes.push_back(ast->CreateBaseClassSpecifier( - base_class_clang_type.GetOpaqueQualType(), accessibility, - is_virtual, is_base_of_class)); + std::unique_ptr<clang::CXXBaseSpecifier> result = + ast->CreateBaseClassSpecifier( + base_class_clang_type.GetOpaqueQualType(), accessibility, + is_virtual, is_base_of_class); + if (!result) + break; + + base_classes.push_back(std::move(result)); if (is_virtual) { // Do not specify any offset for virtual inheritance. The DWARF @@ -3419,7 +3313,7 @@ bool DWARFASTParserClang::ParseChildMembers( } size_t DWARFASTParserClang::ParseChildParameters( - const SymbolContext &sc, clang::DeclContext *containing_decl_ctx, + CompileUnit &comp_unit, clang::DeclContext *containing_decl_ctx, const DWARFDIE &parent_die, bool skip_artificial, bool &is_static, bool &is_variadic, bool &has_template_params, std::vector<CompilerType> &function_param_types, @@ -3451,7 +3345,7 @@ size_t DWARFASTParserClang::ParseChildParameters( if (attributes.ExtractFormValueAtIndex(i, form_value)) { switch (attr) { case DW_AT_decl_file: - decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex( + decl.SetFile(comp_unit.GetSupportFiles().GetFileSpecAtIndex( form_value.Unsigned())); break; case DW_AT_decl_line: @@ -3517,8 +3411,9 @@ size_t DWARFASTParserClang::ParseChildParameters( function_param_types.push_back(type->GetForwardCompilerType()); clang::ParmVarDecl *param_var_decl = - m_ast.CreateParameterDeclaration( - name, type->GetForwardCompilerType(), storage); + m_ast.CreateParameterDeclaration(containing_decl_ctx, name, + type->GetForwardCompilerType(), + storage); assert(param_var_decl); function_param_decls.push_back(param_var_decl); @@ -3551,12 +3446,12 @@ size_t DWARFASTParserClang::ParseChildParameters( return arg_idx; } -void DWARFASTParserClang::ParseChildArrayInfo( - const SymbolContext &sc, const DWARFDIE &parent_die, int64_t &first_index, - std::vector<uint64_t> &element_orders, uint32_t &byte_stride, - uint32_t &bit_stride) { +llvm::Optional<SymbolFile::ArrayInfo> +DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die, + const ExecutionContext *exe_ctx) { + SymbolFile::ArrayInfo array_info; if (!parent_die) - return; + return llvm::None; for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) { @@ -3580,15 +3475,31 @@ void DWARFASTParserClang::ParseChildArrayInfo( break; case DW_AT_count: - num_elements = form_value.Unsigned(); + if (DWARFDIE var_die = die.GetReferencedDIE(DW_AT_count)) { + if (var_die.Tag() == DW_TAG_variable) + if (exe_ctx) { + if (auto frame = exe_ctx->GetFrameSP()) { + Status error; + lldb::VariableSP var_sp; + auto valobj_sp = frame->GetValueForVariableExpressionPath( + var_die.GetName(), eNoDynamicValues, 0, var_sp, + error); + if (valobj_sp) { + num_elements = valobj_sp->GetValueAsUnsigned(0); + break; + } + } + } + } else + num_elements = form_value.Unsigned(); break; case DW_AT_bit_stride: - bit_stride = form_value.Unsigned(); + array_info.bit_stride = form_value.Unsigned(); break; case DW_AT_byte_stride: - byte_stride = form_value.Unsigned(); + array_info.byte_stride = form_value.Unsigned(); break; case DW_AT_lower_bound: @@ -3622,11 +3533,12 @@ void DWARFASTParserClang::ParseChildArrayInfo( num_elements = upper_bound - lower_bound + 1; } - element_orders.push_back(num_elements); + array_info.element_orders.push_back(num_elements); } } break; } } + return array_info; } Type *DWARFASTParserClang::GetTypeForDIE(const DWARFDIE &die) { diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 57c1fc07b2b6..63e058d7bf21 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -10,15 +10,11 @@ #ifndef SymbolFileDWARF_DWARFASTParserClang_h_ #define SymbolFileDWARF_DWARFASTParserClang_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes #include "clang/AST/CharUnits.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -// Project includes #include "DWARFASTParser.h" #include "DWARFDefines.h" #include "lldb/Core/ClangForward.h" @@ -26,8 +22,12 @@ #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangASTImporter.h" +namespace lldb_private { +class CompileUnit; +} class DWARFDebugInfoEntry; class DWARFDIECollection; +class SymbolFileDWARF; class DWARFASTParserClang : public DWARFASTParser { public: @@ -41,7 +41,7 @@ public: bool *type_is_new_ptr) override; lldb_private::Function * - ParseFunctionFromDWARF(const lldb_private::SymbolContext &sc, + ParseFunctionFromDWARF(lldb_private::CompileUnit &comp_unit, const DWARFDIE &die) override; bool @@ -80,19 +80,19 @@ protected: lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); - bool - ParseChildMembers(const lldb_private::SymbolContext &sc, const DWARFDIE &die, - lldb_private::CompilerType &class_compiler_type, - const lldb::LanguageType class_language, - std::vector<clang::CXXBaseSpecifier *> &base_classes, - std::vector<int> &member_accessibilities, - DWARFDIECollection &member_function_dies, - DelayedPropertyList &delayed_properties, - lldb::AccessType &default_accessibility, bool &is_a_class, - lldb_private::ClangASTImporter::LayoutInfo &layout_info); + bool ParseChildMembers( + const lldb_private::SymbolContext &sc, 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, + DWARFDIECollection &member_function_dies, + DelayedPropertyList &delayed_properties, + lldb::AccessType &default_accessibility, bool &is_a_class, + lldb_private::ClangASTImporter::LayoutInfo &layout_info); size_t - ParseChildParameters(const lldb_private::SymbolContext &sc, + ParseChildParameters(lldb_private::CompileUnit &comp_unit, clang::DeclContext *containing_decl_ctx, const DWARFDIE &parent_die, bool skip_artificial, bool &is_static, bool &is_variadic, @@ -101,11 +101,6 @@ protected: std::vector<clang::ParmVarDecl *> &function_param_decls, unsigned &type_quals); - void ParseChildArrayInfo(const lldb_private::SymbolContext &sc, - const DWARFDIE &parent_die, int64_t &first_index, - std::vector<uint64_t> &element_orders, - uint32_t &byte_stride, uint32_t &bit_stride); - size_t ParseChildEnumerators(const lldb_private::SymbolContext &sc, lldb_private::CompilerType &compiler_type, bool is_signed, uint32_t enumerator_byte_size, diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp deleted file mode 100644 index 328212e4b684..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp +++ /dev/null @@ -1,772 +0,0 @@ -//===-- DWARFASTParserGo.cpp ---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DWARFASTParserGo.h" - -#include "DWARFASTParserGo.h" -#include "DWARFDIE.h" -#include "DWARFDIECollection.h" -#include "DWARFDebugInfo.h" -#include "DWARFDeclContext.h" -#include "DWARFDefines.h" -#include "SymbolFileDWARF.h" -#include "SymbolFileDWARFDebugMap.h" -#include "UniqueDWARFASTType.h" - -#include "clang/Basic/Specifiers.h" - -#include "lldb/Core/Module.h" -#include "lldb/Core/Value.h" -#include "lldb/Symbol/CompileUnit.h" -#include "lldb/Symbol/Function.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/TypeList.h" - -//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN - -#ifdef ENABLE_DEBUG_PRINTF -#include <stdio.h> -#define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__) -#else -#define DEBUG_PRINTF(fmt, ...) -#endif - -#define DW_AT_go_kind 0x2900 -#define DW_AT_go_key 0x2901 -#define DW_AT_go_elem 0x2902 - -using namespace lldb; -using namespace lldb_private; -DWARFASTParserGo::DWARFASTParserGo(GoASTContext &ast) : m_ast(ast) {} - -DWARFASTParserGo::~DWARFASTParserGo() {} - -TypeSP DWARFASTParserGo::ParseTypeFromDWARF( - const lldb_private::SymbolContext &sc, const DWARFDIE &die, - lldb_private::Log *log, bool *type_is_new_ptr) { - TypeSP type_sp; - - if (type_is_new_ptr) - *type_is_new_ptr = false; - - if (die) { - SymbolFileDWARF *dwarf = die.GetDWARF(); - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, "DWARFASTParserGo::ParseTypeFromDWARF (die = 0x%8.8x) %s name = " - "'%s')", - die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.GetName()); - } - - Type *type_ptr = dwarf->m_die_to_type.lookup(die.GetDIE()); - TypeList *type_list = dwarf->GetTypeList(); - if (type_ptr == NULL) { - if (type_is_new_ptr) - *type_is_new_ptr = true; - - const dw_tag_t tag = die.Tag(); - - bool is_forward_declaration = false; - DWARFAttributes attributes; - const char *type_name_cstr = NULL; - ConstString type_name_const_str; - Type::ResolveState resolve_state = Type::eResolveStateUnresolved; - uint64_t byte_size = 0; - uint64_t go_kind = 0; - Declaration decl; - - Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; - CompilerType compiler_type; - DWARFFormValue form_value; - - dw_attr_t attr; - - switch (tag) { - case DW_TAG_base_type: - case DW_TAG_pointer_type: - case DW_TAG_typedef: - case DW_TAG_unspecified_type: { - // Set a bit that lets us know that we are currently parsing this - dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; - - const size_t num_attributes = die.GetAttributes(attributes); - lldb::user_id_t encoding_uid = LLDB_INVALID_UID; - - if (num_attributes > 0) { - uint32_t i; - for (i = 0; i < num_attributes; ++i) { - attr = attributes.AttributeAtIndex(i); - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - type_name_cstr = form_value.AsCString(); - if (type_name_cstr) - type_name_const_str.SetCString(type_name_cstr); - break; - case DW_AT_byte_size: - byte_size = form_value.Unsigned(); - break; - case DW_AT_encoding: - // = form_value.Unsigned(); - break; - case DW_AT_type: - encoding_uid = form_value.Reference(); - break; - case DW_AT_go_kind: - go_kind = form_value.Unsigned(); - break; - default: - // Do we care about DW_AT_go_key or DW_AT_go_elem? - break; - } - } - } - } - - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", - die.GetID(), DW_TAG_value_to_name(tag), type_name_cstr, - encoding_uid); - - switch (tag) { - default: - break; - - case DW_TAG_unspecified_type: - resolve_state = Type::eResolveStateFull; - compiler_type = m_ast.CreateVoidType(type_name_const_str); - break; - - case DW_TAG_base_type: - resolve_state = Type::eResolveStateFull; - compiler_type = - m_ast.CreateBaseType(go_kind, type_name_const_str, byte_size); - break; - - case DW_TAG_pointer_type: - encoding_data_type = Type::eEncodingIsPointerUID; - break; - case DW_TAG_typedef: - encoding_data_type = Type::eEncodingIsTypedefUID; - CompilerType impl; - Type *type = dwarf->ResolveTypeUID(encoding_uid); - if (type) { - if (go_kind == 0 && type->GetName() == type_name_const_str) { - // Go emits extra typedefs as a forward declaration. Ignore - // these. - dwarf->m_die_to_type[die.GetDIE()] = type; - return type->shared_from_this(); - } - impl = type->GetForwardCompilerType(); - compiler_type = - m_ast.CreateTypedefType(go_kind, type_name_const_str, impl); - } - break; - } - - type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, - byte_size, NULL, encoding_uid, - encoding_data_type, &decl, compiler_type, - resolve_state)); - - dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); - } break; - - case DW_TAG_structure_type: { - // Set a bit that lets us know that we are currently parsing this - dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; - bool byte_size_valid = false; - - const size_t num_attributes = die.GetAttributes(attributes); - if (num_attributes > 0) { - uint32_t i; - for (i = 0; i < num_attributes; ++i) { - attr = attributes.AttributeAtIndex(i); - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - type_name_cstr = form_value.AsCString(); - type_name_const_str.SetCString(type_name_cstr); - break; - - case DW_AT_byte_size: - byte_size = form_value.Unsigned(); - byte_size_valid = true; - break; - - case DW_AT_go_kind: - go_kind = form_value.Unsigned(); - break; - - // TODO: Should we use SLICETYPE's DW_AT_go_elem? - default: - break; - } - } - } - } - - // TODO(ribrdb): Do we need this? - - // UniqueDWARFASTType is large, so don't create a local variables on - // the stack, put it on the heap. This function is often called - // recursively and clang isn't good and sharing the stack space for - // variables in different blocks. - std::unique_ptr<UniqueDWARFASTType> unique_ast_entry_ap( - new UniqueDWARFASTType()); - - // Only try and unique the type if it has a name. - if (type_name_const_str && - dwarf->GetUniqueDWARFASTTypeMap().Find( - type_name_const_str, die, decl, - byte_size_valid ? byte_size : -1, *unique_ast_entry_ap)) { - // We have already parsed this type or from another compile unit. GCC - // loves to use the "one definition rule" which can result in - // multiple definitions of the same class over and over in each - // compile unit. - type_sp = unique_ast_entry_ap->m_type_sp; - if (type_sp) { - dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); - return type_sp; - } - } - - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); - - bool compiler_type_was_created = false; - compiler_type.SetCompilerType( - &m_ast, - dwarf->m_forward_decl_die_to_clang_type.lookup(die.GetDIE())); - if (!compiler_type) { - compiler_type_was_created = true; - compiler_type = - m_ast.CreateStructType(go_kind, type_name_const_str, byte_size); - } - - type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, - byte_size, NULL, LLDB_INVALID_UID, - Type::eEncodingIsUID, &decl, compiler_type, - Type::eResolveStateForward)); - - // Add our type to the unique type map so we don't end up creating many - // copies of the same type over and over in the ASTContext for our - // module - unique_ast_entry_ap->m_type_sp = type_sp; - unique_ast_entry_ap->m_die = die; - unique_ast_entry_ap->m_declaration = decl; - unique_ast_entry_ap->m_byte_size = byte_size; - dwarf->GetUniqueDWARFASTTypeMap().Insert(type_name_const_str, - *unique_ast_entry_ap); - - if (!is_forward_declaration) { - // Always start the definition for a class type so that if the class - // has child classes or types that require the class to be created - // for use as their decl contexts the class will be ready to accept - // these child definitions. - if (die.HasChildren() == false) { - // No children for this struct/union/class, lets finish it - m_ast.CompleteStructType(compiler_type); - } else if (compiler_type_was_created) { - // Leave this as a forward declaration until we need to know the - // details of the type. lldb_private::Type will automatically call - // the SymbolFile virtual function - // "SymbolFileDWARF::CompleteType(Type *)" When the definition - // needs to be defined. - dwarf->m_forward_decl_die_to_clang_type[die.GetDIE()] = - compiler_type.GetOpaqueQualType(); - dwarf->m_forward_decl_clang_type_to_die[compiler_type - .GetOpaqueQualType()] = - die.GetDIERef(); - // SetHasExternalStorage (compiler_type.GetOpaqueQualType(), true); - } - } - } break; - - case DW_TAG_subprogram: - case DW_TAG_subroutine_type: { - // Set a bit that lets us know that we are currently parsing this - dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; - - bool is_variadic = false; - clang::StorageClass storage = - clang::SC_None; //, Extern, Static, PrivateExtern - - const size_t num_attributes = die.GetAttributes(attributes); - if (num_attributes > 0) { - uint32_t i; - for (i = 0; i < num_attributes; ++i) { - attr = attributes.AttributeAtIndex(i); - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - type_name_cstr = form_value.AsCString(); - type_name_const_str.SetCString(type_name_cstr); - break; - - case DW_AT_external: - if (form_value.Unsigned()) { - if (storage == clang::SC_None) - storage = clang::SC_Extern; - else - storage = clang::SC_PrivateExtern; - } - break; - - case DW_AT_high_pc: - case DW_AT_low_pc: - break; - } - } - } - } - - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); - - std::vector<CompilerType> function_param_types; - - // Parse the function children for the parameters - - if (die.HasChildren()) { - ParseChildParameters(sc, die, is_variadic, function_param_types); - } - - // compiler_type will get the function prototype clang type after this - // call - compiler_type = m_ast.CreateFunctionType( - type_name_const_str, function_param_types.data(), - function_param_types.size(), is_variadic); - - type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, 0, NULL, - LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, - compiler_type, Type::eResolveStateFull)); - assert(type_sp.get()); - } break; - - case DW_TAG_array_type: { - // Set a bit that lets us know that we are currently parsing this - dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; - - lldb::user_id_t type_die_offset = DW_INVALID_OFFSET; - int64_t first_index = 0; - uint32_t byte_stride = 0; - uint32_t bit_stride = 0; - const size_t num_attributes = die.GetAttributes(attributes); - - if (num_attributes > 0) { - uint32_t i; - for (i = 0; i < num_attributes; ++i) { - attr = attributes.AttributeAtIndex(i); - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - type_name_cstr = form_value.AsCString(); - type_name_const_str.SetCString(type_name_cstr); - break; - - case DW_AT_type: - type_die_offset = form_value.Reference(); - break; - case DW_AT_byte_size: - break; // byte_size = form_value.Unsigned(); break; - case DW_AT_go_kind: - go_kind = form_value.Unsigned(); - break; - default: - break; - } - } - } - - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); - - Type *element_type = dwarf->ResolveTypeUID(type_die_offset); - - if (element_type) { - std::vector<uint64_t> element_orders; - ParseChildArrayInfo(sc, die, first_index, element_orders, - byte_stride, bit_stride); - if (byte_stride == 0) - byte_stride = element_type->GetByteSize(); - CompilerType array_element_type = - element_type->GetForwardCompilerType(); - if (element_orders.size() > 0) { - if (element_orders.size() > 1) - printf("golang: unsupported multi-dimensional array %s\n", - type_name_cstr); - compiler_type = m_ast.CreateArrayType( - type_name_const_str, array_element_type, element_orders[0]); - } else { - compiler_type = m_ast.CreateArrayType(type_name_const_str, - array_element_type, 0); - } - type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, - byte_stride, NULL, type_die_offset, - Type::eEncodingIsUID, &decl, compiler_type, - Type::eResolveStateFull)); - type_sp->SetEncodingType(element_type); - } - } - } break; - - default: - dwarf->GetObjectFile()->GetModule()->ReportError( - "{0x%8.8x}: unhandled type tag 0x%4.4x (%s), " - "please file a bug and attach the file at the " - "start of this error message", - die.GetOffset(), tag, DW_TAG_value_to_name(tag)); - break; - } - - if (type_sp.get()) { - DWARFDIE sc_parent_die = - SymbolFileDWARF::GetParentSymbolContextDIE(die); - dw_tag_t sc_parent_tag = sc_parent_die.Tag(); - - SymbolContextScope *symbol_context_scope = NULL; - if (sc_parent_tag == DW_TAG_compile_unit || - sc_parent_tag == DW_TAG_partial_unit) { - symbol_context_scope = sc.comp_unit; - } else if (sc.function != NULL && sc_parent_die) { - symbol_context_scope = - sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); - if (symbol_context_scope == NULL) - symbol_context_scope = sc.function; - } - - if (symbol_context_scope != NULL) { - type_sp->SetSymbolContextScope(symbol_context_scope); - } - - // We are ready to put this type into the uniqued list up at the module - // level - type_list->Insert(type_sp); - - dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); - } - } else if (type_ptr != DIE_IS_BEING_PARSED) { - type_sp = type_ptr->shared_from_this(); - } - } - return type_sp; -} - -size_t DWARFASTParserGo::ParseChildParameters( - const SymbolContext &sc, - - const DWARFDIE &parent_die, bool &is_variadic, - std::vector<CompilerType> &function_param_types) { - if (!parent_die) - return 0; - - size_t arg_idx = 0; - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { - - dw_tag_t tag = die.Tag(); - switch (tag) { - case DW_TAG_formal_parameter: { - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - if (num_attributes > 0) { - Declaration decl; - DWARFFormValue param_type_die_offset; - - uint32_t i; - for (i = 0; i < num_attributes; ++i) { - const dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - // = form_value.AsCString(); - break; - case DW_AT_type: - param_type_die_offset = form_value; - break; - case DW_AT_location: - // if (form_value.BlockData()) - // { - // const DWARFDataExtractor& - // debug_info_data = - // debug_info(); - // uint32_t block_length = - // form_value.Unsigned(); - // DWARFDataExtractor - // location(debug_info_data, - // form_value.BlockData() - - // debug_info_data.GetDataStart(), - // block_length); - // } - // else - // { - // } - // break; - default: - break; - } - } - } - - Type *type = parent_die.ResolveTypeUID(DIERef(param_type_die_offset)); - if (type) { - function_param_types.push_back(type->GetForwardCompilerType()); - } - } - arg_idx++; - } break; - - case DW_TAG_unspecified_parameters: - is_variadic = true; - break; - - default: - break; - } - } - return arg_idx; -} - -void DWARFASTParserGo::ParseChildArrayInfo( - const SymbolContext &sc, const DWARFDIE &parent_die, int64_t &first_index, - std::vector<uint64_t> &element_orders, uint32_t &byte_stride, - uint32_t &bit_stride) { - if (!parent_die) - return; - - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { - const dw_tag_t tag = die.Tag(); - switch (tag) { - case DW_TAG_subrange_type: { - DWARFAttributes attributes; - const size_t num_child_attributes = die.GetAttributes(attributes); - if (num_child_attributes > 0) { - uint64_t num_elements = 0; - uint32_t i; - for (i = 0; i < num_child_attributes; ++i) { - const dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_count: - num_elements = form_value.Unsigned(); - break; - - default: - case DW_AT_type: - break; - } - } - } - - element_orders.push_back(num_elements); - } - } break; - } - } -} - -bool DWARFASTParserGo::CompleteTypeFromDWARF(const DWARFDIE &die, - lldb_private::Type *type, - CompilerType &compiler_type) { - if (!die) - return false; - - const dw_tag_t tag = die.Tag(); - - SymbolFileDWARF *dwarf = die.GetDWARF(); - Log *log = - nullptr; // (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION)); - if (log) - dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( - log, "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", - die.GetID(), DW_TAG_value_to_name(tag), type->GetName().AsCString()); - assert(compiler_type); - DWARFAttributes attributes; - - switch (tag) { - case DW_TAG_structure_type: { - { - if (die.HasChildren()) { - SymbolContext sc(die.GetLLDBCompileUnit()); - - ParseChildMembers(sc, die, compiler_type); - } - } - m_ast.CompleteStructType(compiler_type); - return (bool)compiler_type; - } - - default: - assert(false && "not a forward go type decl!"); - break; - } - - return false; -} - -size_t DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, - const DWARFDIE &parent_die, - CompilerType &class_compiler_type) { - size_t count = 0; - uint32_t member_idx = 0; - - ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); - GoASTContext *ast = - llvm::dyn_cast_or_null<GoASTContext>(class_compiler_type.GetTypeSystem()); - if (ast == nullptr) - return 0; - - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { - dw_tag_t tag = die.Tag(); - - switch (tag) { - case DW_TAG_member: { - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - if (num_attributes > 0) { - Declaration decl; - const char *name = NULL; - - DWARFFormValue encoding_uid; - uint32_t member_byte_offset = UINT32_MAX; - uint32_t i; - for (i = 0; i < num_attributes; ++i) { - const dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - name = form_value.AsCString(); - break; - case DW_AT_type: - encoding_uid = form_value; - break; - case DW_AT_data_member_location: - if (form_value.BlockData()) { - Value initialValue(0); - Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = die.GetData(); - uint32_t block_length = form_value.Unsigned(); - uint32_t block_offset = - form_value.BlockData() - debug_info_data.GetDataStart(); - if (DWARFExpression::Evaluate( - NULL, // ExecutionContext * - NULL, // RegisterContext * - module_sp, debug_info_data, die.GetCU(), block_offset, - block_length, eRegisterKindDWARF, &initialValue, NULL, - memberOffset, NULL)) { - member_byte_offset = memberOffset.ResolveValue(NULL).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(); - } - break; - - default: - break; - } - } - } - - Type *member_type = die.ResolveTypeUID(DIERef(encoding_uid)); - if (member_type) { - CompilerType member_go_type = member_type->GetFullCompilerType(); - ConstString name_const_str(name); - m_ast.AddFieldToStruct(class_compiler_type, name_const_str, - member_go_type, member_byte_offset); - } - } - ++member_idx; - } break; - - default: - break; - } - } - - return count; -} - -Function *DWARFASTParserGo::ParseFunctionFromDWARF(const SymbolContext &sc, - const DWARFDIE &die) { - DWARFRangeList func_ranges; - const char *name = NULL; - const char *mangled = NULL; - int decl_file = 0; - int decl_line = 0; - int decl_column = 0; - int call_file = 0; - int call_line = 0; - int call_column = 0; - DWARFExpression frame_base(die.GetCU()); - - assert(die.Tag() == DW_TAG_subprogram); - - if (die.Tag() != DW_TAG_subprogram) - return NULL; - - if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line, - decl_column, call_file, call_line, call_column, - &frame_base)) { - // Union of all ranges in the function DIE (if the function is - // discontiguous) - AddressRange func_range; - lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase(0); - lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd(0); - if (lowest_func_addr != LLDB_INVALID_ADDRESS && - lowest_func_addr <= highest_func_addr) { - ModuleSP module_sp(die.GetModule()); - func_range.GetBaseAddress().ResolveAddressUsingFileSections( - lowest_func_addr, module_sp->GetSectionList()); - if (func_range.GetBaseAddress().IsValid()) - func_range.SetByteSize(highest_func_addr - lowest_func_addr); - } - - if (func_range.GetBaseAddress().IsValid()) { - Mangled func_name; - func_name.SetValue(ConstString(name), false); - - FunctionSP func_sp; - std::unique_ptr<Declaration> decl_ap; - if (decl_file != 0 || decl_line != 0 || decl_column != 0) - decl_ap.reset(new Declaration( - sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), - decl_line, decl_column)); - - SymbolFileDWARF *dwarf = die.GetDWARF(); - // Supply the type _only_ if it has already been parsed - Type *func_type = dwarf->m_die_to_type.lookup(die.GetDIE()); - - assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED); - - if (dwarf->FixupAddress(func_range.GetBaseAddress())) { - const user_id_t func_user_id = die.GetID(); - func_sp.reset(new Function(sc.comp_unit, - func_user_id, // UserID is the DIE offset - func_user_id, func_name, func_type, - func_range)); // first address range - - if (func_sp.get() != NULL) { - if (frame_base.IsValid()) - func_sp->GetFrameBaseExpression() = frame_base; - sc.comp_unit->AddFunction(func_sp); - return func_sp.get(); - } - } - } - } - return NULL; -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h b/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h deleted file mode 100644 index 2a7c3871a309..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h +++ /dev/null @@ -1,84 +0,0 @@ -//===-- DWARFASTParserGo.h --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef SymbolFileDWARF_DWARFASTParserGo_h_ -#define SymbolFileDWARF_DWARFASTParserGo_h_ - -// C Includes -// C++ Includes -// Other libraries and framework includes -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" - -// Project includes -#include "DWARFASTParser.h" -#include "DWARFDIE.h" -#include "DWARFDefines.h" -#include "lldb/Core/PluginInterface.h" -#include "lldb/Symbol/GoASTContext.h" - -class DWARFDebugInfoEntry; -class DWARFDIECollection; - -class DWARFASTParserGo : public DWARFASTParser { -public: - DWARFASTParserGo(lldb_private::GoASTContext &ast); - - ~DWARFASTParserGo() override; - - lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, lldb_private::Log *log, - bool *type_is_new_ptr) override; - - lldb_private::Function * - ParseFunctionFromDWARF(const lldb_private::SymbolContext &sc, - const DWARFDIE &die) override; - - bool CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, - lldb_private::CompilerType &go_type) override; - - lldb_private::CompilerDeclContext - GetDeclContextForUIDFromDWARF(const DWARFDIE &die) override { - return lldb_private::CompilerDeclContext(); - } - - lldb_private::CompilerDeclContext - GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) override { - return lldb_private::CompilerDeclContext(); - } - - lldb_private::CompilerDecl - GetDeclForUIDFromDWARF(const DWARFDIE &die) override { - return lldb_private::CompilerDecl(); - } - - std::vector<DWARFDIE> GetDIEForDeclContext( - lldb_private::CompilerDeclContext decl_context) override { - return std::vector<DWARFDIE>(); - } - -private: - size_t ParseChildParameters( - const lldb_private::SymbolContext &sc, const DWARFDIE &parent_die, - bool &is_variadic, - std::vector<lldb_private::CompilerType> &function_param_types); - void ParseChildArrayInfo(const lldb_private::SymbolContext &sc, - const DWARFDIE &parent_die, int64_t &first_index, - std::vector<uint64_t> &element_orders, - uint32_t &byte_stride, uint32_t &bit_stride); - - size_t ParseChildMembers(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, - lldb_private::CompilerType &class_compiler_type); - - lldb_private::GoASTContext &m_ast; -}; - -#endif // SymbolFileDWARF_DWARFASTParserGo_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp deleted file mode 100644 index 476394487985..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp +++ /dev/null @@ -1,510 +0,0 @@ -//===-- DWARFASTParserJava.cpp ----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DWARFASTParserJava.h" -#include "DWARFAttribute.h" -#include "DWARFUnit.h" -#include "DWARFDebugInfoEntry.h" -#include "DWARFDebugInfoEntry.h" -#include "DWARFDeclContext.h" -#include "SymbolFileDWARF.h" - -#include "lldb/Core/Module.h" -#include "lldb/Symbol/CompileUnit.h" -#include "lldb/Symbol/SymbolContextScope.h" -#include "lldb/Symbol/TypeList.h" - -using namespace lldb; -using namespace lldb_private; - -DWARFASTParserJava::DWARFASTParserJava(JavaASTContext &ast) : m_ast(ast) {} - -DWARFASTParserJava::~DWARFASTParserJava() {} - -TypeSP DWARFASTParserJava::ParseBaseTypeFromDIE(const DWARFDIE &die) { - SymbolFileDWARF *dwarf = die.GetDWARF(); - dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; - - ConstString type_name; - uint64_t byte_size = 0; - - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - for (uint32_t i = 0; i < num_attributes; ++i) { - DWARFFormValue form_value; - dw_attr_t attr = attributes.AttributeAtIndex(i); - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - type_name.SetCString(form_value.AsCString()); - break; - case DW_AT_byte_size: - byte_size = form_value.Unsigned(); - break; - case DW_AT_encoding: - break; - default: - assert(false && "Unsupported attribute for DW_TAG_base_type"); - } - } - } - - Declaration decl; - CompilerType compiler_type = m_ast.CreateBaseType(type_name); - return std::make_shared<Type>(die.GetID(), dwarf, type_name, byte_size, - nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, - decl, compiler_type, Type::eResolveStateFull); -} - -TypeSP DWARFASTParserJava::ParseArrayTypeFromDIE(const DWARFDIE &die) { - SymbolFileDWARF *dwarf = die.GetDWARF(); - dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; - - ConstString linkage_name; - DWARFFormValue type_attr_value; - lldb::addr_t data_offset = LLDB_INVALID_ADDRESS; - DWARFExpression length_expression(die.GetCU()); - - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - for (uint32_t i = 0; i < num_attributes; ++i) { - DWARFFormValue form_value; - dw_attr_t attr = attributes.AttributeAtIndex(i); - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_linkage_name: - linkage_name.SetCString(form_value.AsCString()); - break; - case DW_AT_type: - type_attr_value = form_value; - break; - case DW_AT_data_member_location: - data_offset = form_value.Unsigned(); - break; - case DW_AT_declaration: - break; - default: - assert(false && "Unsupported attribute for DW_TAG_array_type"); - } - } - } - - for (DWARFDIE child_die = die.GetFirstChild(); child_die.IsValid(); - child_die = child_die.GetSibling()) { - if (child_die.Tag() == DW_TAG_subrange_type) { - DWARFAttributes attributes; - const size_t num_attributes = child_die.GetAttributes(attributes); - for (uint32_t i = 0; i < num_attributes; ++i) { - DWARFFormValue form_value; - dw_attr_t attr = attributes.AttributeAtIndex(i); - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_count: - if (form_value.BlockData()) - length_expression.CopyOpcodeData( - form_value.BlockData(), form_value.Unsigned(), - child_die.GetCU()->GetByteOrder(), - child_die.GetCU()->GetAddressByteSize()); - break; - default: - assert(false && "Unsupported attribute for DW_TAG_subrange_type"); - } - } - } - } else { - assert(false && "Unsupported child for DW_TAG_array_type"); - } - } - - DIERef type_die_ref(type_attr_value); - Type *element_type = dwarf->ResolveTypeUID(type_die_ref); - if (!element_type) - return nullptr; - - CompilerType element_compiler_type = element_type->GetForwardCompilerType(); - CompilerType array_compiler_type = m_ast.CreateArrayType( - linkage_name, element_compiler_type, length_expression, data_offset); - - Declaration decl; - TypeSP type_sp(new Type(die.GetID(), dwarf, array_compiler_type.GetTypeName(), - -1, nullptr, type_die_ref.GetUID(dwarf), - Type::eEncodingIsUID, &decl, array_compiler_type, - Type::eResolveStateFull)); - type_sp->SetEncodingType(element_type); - return type_sp; -} - -TypeSP DWARFASTParserJava::ParseReferenceTypeFromDIE(const DWARFDIE &die) { - SymbolFileDWARF *dwarf = die.GetDWARF(); - dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; - - Declaration decl; - DWARFFormValue type_attr_value; - - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - for (uint32_t i = 0; i < num_attributes; ++i) { - DWARFFormValue form_value; - dw_attr_t attr = attributes.AttributeAtIndex(i); - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_type: - type_attr_value = form_value; - break; - default: - assert(false && "Unsupported attribute for DW_TAG_array_type"); - } - } - } - - DIERef type_die_ref(type_attr_value); - Type *pointee_type = dwarf->ResolveTypeUID(type_die_ref); - if (!pointee_type) - return nullptr; - - CompilerType pointee_compiler_type = pointee_type->GetForwardCompilerType(); - CompilerType reference_compiler_type = - m_ast.CreateReferenceType(pointee_compiler_type); - TypeSP type_sp( - new Type(die.GetID(), dwarf, reference_compiler_type.GetTypeName(), -1, - nullptr, type_die_ref.GetUID(dwarf), Type::eEncodingIsUID, &decl, - reference_compiler_type, Type::eResolveStateFull)); - type_sp->SetEncodingType(pointee_type); - return type_sp; -} - -lldb::TypeSP DWARFASTParserJava::ParseClassTypeFromDIE(const DWARFDIE &die, - bool &is_new_type) { - SymbolFileDWARF *dwarf = die.GetDWARF(); - dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; - - Declaration decl; - ConstString name; - ConstString linkage_name; - bool is_forward_declaration = false; - uint32_t byte_size = 0; - - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - for (uint32_t i = 0; i < num_attributes; ++i) { - DWARFFormValue form_value; - dw_attr_t attr = attributes.AttributeAtIndex(i); - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - name.SetCString(form_value.AsCString()); - break; - case DW_AT_declaration: - is_forward_declaration = form_value.Boolean(); - break; - case DW_AT_byte_size: - byte_size = form_value.Unsigned(); - break; - case DW_AT_linkage_name: - linkage_name.SetCString(form_value.AsCString()); - break; - default: - assert(false && "Unsupported attribute for DW_TAG_class_type"); - } - } - } - - UniqueDWARFASTType unique_ast_entry; - if (name) { - std::string qualified_name; - if (die.GetQualifiedName(qualified_name)) { - name.SetCString(qualified_name.c_str()); - if (dwarf->GetUniqueDWARFASTTypeMap().Find(name, die, Declaration(), -1, - unique_ast_entry)) { - if (unique_ast_entry.m_type_sp) { - dwarf->GetDIEToType()[die.GetDIE()] = - unique_ast_entry.m_type_sp.get(); - is_new_type = false; - return unique_ast_entry.m_type_sp; - } - } - } - } - - if (is_forward_declaration) { - DWARFDeclContext die_decl_ctx; - die.GetDWARFDeclContext(die_decl_ctx); - - TypeSP type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die_decl_ctx); - if (type_sp) { - // We found a real definition for this type elsewhere so lets use it - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - is_new_type = false; - return type_sp; - } - } - - CompilerType compiler_type( - &m_ast, dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE())); - if (!compiler_type) - compiler_type = m_ast.CreateObjectType(name, linkage_name, byte_size); - - is_new_type = true; - TypeSP type_sp(new Type(die.GetID(), dwarf, name, - -1, // byte size isn't specified - nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, - &decl, compiler_type, Type::eResolveStateForward)); - - // Add our type to the unique type map - unique_ast_entry.m_type_sp = type_sp; - unique_ast_entry.m_die = die; - unique_ast_entry.m_declaration = decl; - unique_ast_entry.m_byte_size = -1; - dwarf->GetUniqueDWARFASTTypeMap().Insert(name, unique_ast_entry); - - if (!is_forward_declaration) { - // Leave this as a forward declaration until we need to know the details of - // the type - dwarf->GetForwardDeclDieToClangType()[die.GetDIE()] = - compiler_type.GetOpaqueQualType(); - dwarf->GetForwardDeclClangTypeToDie()[compiler_type.GetOpaqueQualType()] = - die.GetDIERef(); - } - return type_sp; -} - -lldb::TypeSP DWARFASTParserJava::ParseTypeFromDWARF( - const lldb_private::SymbolContext &sc, const DWARFDIE &die, - lldb_private::Log *log, bool *type_is_new_ptr) { - if (type_is_new_ptr) - *type_is_new_ptr = false; - - if (!die) - return nullptr; - - SymbolFileDWARF *dwarf = die.GetDWARF(); - - Type *type_ptr = dwarf->m_die_to_type.lookup(die.GetDIE()); - if (type_ptr == DIE_IS_BEING_PARSED) - return nullptr; - if (type_ptr != nullptr) - return type_ptr->shared_from_this(); - - TypeSP type_sp; - if (type_is_new_ptr) - *type_is_new_ptr = true; - - switch (die.Tag()) { - case DW_TAG_base_type: { - type_sp = ParseBaseTypeFromDIE(die); - break; - } - case DW_TAG_array_type: { - type_sp = ParseArrayTypeFromDIE(die); - break; - } - case DW_TAG_class_type: { - bool is_new_type = false; - type_sp = ParseClassTypeFromDIE(die, is_new_type); - if (!is_new_type) - return type_sp; - break; - } - case DW_TAG_reference_type: { - type_sp = ParseReferenceTypeFromDIE(die); - break; - } - } - - if (!type_sp) - return nullptr; - - DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die); - dw_tag_t sc_parent_tag = sc_parent_die.Tag(); - - SymbolContextScope *symbol_context_scope = nullptr; - if (sc_parent_tag == DW_TAG_compile_unit || - sc_parent_tag == DW_TAG_partial_unit) { - symbol_context_scope = sc.comp_unit; - } else if (sc.function != nullptr && sc_parent_die) { - symbol_context_scope = - sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); - if (symbol_context_scope == nullptr) - symbol_context_scope = sc.function; - } - - if (symbol_context_scope != nullptr) - type_sp->SetSymbolContextScope(symbol_context_scope); - - dwarf->GetTypeList()->Insert(type_sp); - dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); - - return type_sp; -} - -lldb_private::Function *DWARFASTParserJava::ParseFunctionFromDWARF( - const lldb_private::SymbolContext &sc, const DWARFDIE &die) { - assert(die.Tag() == DW_TAG_subprogram); - - const char *name = nullptr; - const char *mangled = nullptr; - int decl_file = 0; - int decl_line = 0; - int decl_column = 0; - int call_file = 0; - int call_line = 0; - int call_column = 0; - DWARFRangeList func_ranges; - DWARFExpression frame_base(die.GetCU()); - - if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line, - decl_column, call_file, call_line, call_column, - &frame_base)) { - // Union of all ranges in the function DIE (if the function is - // discontiguous) - AddressRange func_range; - lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase(0); - lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd(0); - if (lowest_func_addr != LLDB_INVALID_ADDRESS && - lowest_func_addr <= highest_func_addr) { - ModuleSP module_sp(die.GetModule()); - func_range.GetBaseAddress().ResolveAddressUsingFileSections( - lowest_func_addr, module_sp->GetSectionList()); - if (func_range.GetBaseAddress().IsValid()) - func_range.SetByteSize(highest_func_addr - lowest_func_addr); - } - - if (func_range.GetBaseAddress().IsValid()) { - std::unique_ptr<Declaration> decl_ap; - if (decl_file != 0 || decl_line != 0 || decl_column != 0) - decl_ap.reset(new Declaration( - sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), - decl_line, decl_column)); - - if (die.GetDWARF()->FixupAddress(func_range.GetBaseAddress())) { - FunctionSP func_sp(new Function(sc.comp_unit, die.GetID(), die.GetID(), - Mangled(ConstString(name), false), - nullptr, // No function types in java - func_range)); - if (frame_base.IsValid()) - func_sp->GetFrameBaseExpression() = frame_base; - sc.comp_unit->AddFunction(func_sp); - - return func_sp.get(); - } - } - } - return nullptr; -} - -bool DWARFASTParserJava::CompleteTypeFromDWARF( - const DWARFDIE &die, lldb_private::Type *type, - lldb_private::CompilerType &java_type) { - switch (die.Tag()) { - case DW_TAG_class_type: { - if (die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 0) { - if (die.HasChildren()) - ParseChildMembers(die, java_type); - m_ast.CompleteObjectType(java_type); - return java_type.IsValid(); - } - } break; - default: - assert(false && "Not a forward java type declaration!"); - break; - } - return false; -} - -void DWARFASTParserJava::ParseChildMembers(const DWARFDIE &parent_die, - CompilerType &compiler_type) { - DWARFUnit *dwarf_cu = parent_die.GetCU(); - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { - switch (die.Tag()) { - case DW_TAG_member: { - const char *name = nullptr; - DWARFFormValue encoding_uid; - uint32_t member_byte_offset = UINT32_MAX; - DWARFExpression member_location_expression(dwarf_cu); - - DWARFAttributes attributes; - size_t num_attributes = die.GetAttributes(attributes); - for (size_t i = 0; i < num_attributes; ++i) { - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attributes.AttributeAtIndex(i)) { - case DW_AT_name: - name = form_value.AsCString(); - break; - case DW_AT_type: - encoding_uid = form_value; - break; - case DW_AT_data_member_location: - if (form_value.BlockData()) - member_location_expression.CopyOpcodeData( - form_value.BlockData(), form_value.Unsigned(), - dwarf_cu->GetByteOrder(), dwarf_cu->GetAddressByteSize()); - else - member_byte_offset = form_value.Unsigned(); - break; - case DW_AT_artificial: - static_cast<void>(form_value.Boolean()); - break; - case DW_AT_accessibility: - // TODO: Handle when needed - break; - default: - assert(false && "Unhandled attribute for DW_TAG_member"); - break; - } - } - } - - if (strcmp(name, ".dynamic_type") == 0) - m_ast.SetDynamicTypeId(compiler_type, member_location_expression); - else { - if (Type *member_type = die.ResolveTypeUID(DIERef(encoding_uid))) - m_ast.AddMemberToObject(compiler_type, ConstString(name), - member_type->GetFullCompilerType(), - member_byte_offset); - } - break; - } - case DW_TAG_inheritance: { - DWARFFormValue encoding_uid; - uint32_t member_byte_offset = UINT32_MAX; - - DWARFAttributes attributes; - size_t num_attributes = die.GetAttributes(attributes); - for (size_t i = 0; i < num_attributes; ++i) { - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attributes.AttributeAtIndex(i)) { - case DW_AT_type: - encoding_uid = form_value; - break; - case DW_AT_data_member_location: - member_byte_offset = form_value.Unsigned(); - break; - case DW_AT_accessibility: - // In java all base class is public so we can ignore this attribute - break; - default: - assert(false && "Unhandled attribute for DW_TAG_member"); - break; - } - } - } - if (Type *base_type = die.ResolveTypeUID(DIERef(encoding_uid))) - m_ast.AddBaseClassToObject(compiler_type, - base_type->GetFullCompilerType(), - member_byte_offset); - break; - } - default: - break; - } - } -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.h b/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.h deleted file mode 100644 index 01d81833d517..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.h +++ /dev/null @@ -1,81 +0,0 @@ -//===-- DWARFASTParserJava.h ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef SymbolFileDWARF_DWARFASTParserJava_h_ -#define SymbolFileDWARF_DWARFASTParserJava_h_ - -// C Includes -// C++ Includes -// Other libraries and framework includes -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" - -// Project includes -#include "DWARFASTParser.h" -#include "DWARFDIE.h" -#include "DWARFDefines.h" -#include "lldb/Core/PluginInterface.h" -#include "lldb/Symbol/JavaASTContext.h" - -class DWARFDebugInfoEntry; -class DWARFDIECollection; - -class DWARFASTParserJava : public DWARFASTParser { -public: - DWARFASTParserJava(lldb_private::JavaASTContext &ast); - ~DWARFASTParserJava() override; - - lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, lldb_private::Log *log, - bool *type_is_new_ptr) override; - - lldb_private::Function * - ParseFunctionFromDWARF(const lldb_private::SymbolContext &sc, - const DWARFDIE &die) override; - - bool CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, - lldb_private::CompilerType &java_type) override; - - lldb_private::CompilerDeclContext - GetDeclContextForUIDFromDWARF(const DWARFDIE &die) override { - return lldb_private::CompilerDeclContext(); - } - - lldb_private::CompilerDeclContext - GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) override { - return lldb_private::CompilerDeclContext(); - } - - lldb_private::CompilerDecl - GetDeclForUIDFromDWARF(const DWARFDIE &die) override { - return lldb_private::CompilerDecl(); - } - - std::vector<DWARFDIE> GetDIEForDeclContext( - lldb_private::CompilerDeclContext decl_context) override { - return std::vector<DWARFDIE>(); - } - - void ParseChildMembers(const DWARFDIE &parent_die, - lldb_private::CompilerType &class_compiler_type); - -private: - lldb_private::JavaASTContext &m_ast; - - lldb::TypeSP ParseBaseTypeFromDIE(const DWARFDIE &die); - - lldb::TypeSP ParseArrayTypeFromDIE(const DWARFDIE &die); - - lldb::TypeSP ParseReferenceTypeFromDIE(const DWARFDIE &die); - - lldb::TypeSP ParseClassTypeFromDIE(const DWARFDIE &die, bool &is_new_type); -}; - -#endif // SymbolFileDWARF_DWARFASTParserJava_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp deleted file mode 100644 index 3ef5c2eb8626..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp +++ /dev/null @@ -1,210 +0,0 @@ -//===-- DWARFASTParserOCaml.cpp ---------------------------------*- C++ -*-===// - -#include "DWARFASTParserOCaml.h" - -#include "lldb/Core/Module.h" -#include "lldb/Symbol/CompileUnit.h" -#include "lldb/Symbol/Function.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/Type.h" -#include "lldb/Symbol/TypeList.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.h" - -using namespace lldb; -using namespace lldb_private; - -DWARFASTParserOCaml::DWARFASTParserOCaml(OCamlASTContext &ast) : m_ast(ast) {} - -DWARFASTParserOCaml::~DWARFASTParserOCaml() {} - -TypeSP DWARFASTParserOCaml::ParseBaseTypeFromDIE(const DWARFDIE &die) { - SymbolFileDWARF *dwarf = die.GetDWARF(); - dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; - - ConstString type_name; - uint64_t byte_size = 0; - - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - for (uint32_t i = 0; i < num_attributes; ++i) { - DWARFFormValue form_value; - dw_attr_t attr = attributes.AttributeAtIndex(i); - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - type_name.SetCString(form_value.AsCString()); - break; - case DW_AT_byte_size: - byte_size = form_value.Unsigned(); - break; - case DW_AT_encoding: - break; - default: - assert(false && "Unsupported attribute for DW_TAG_base_type"); - } - } - } - - Declaration decl; - CompilerType compiler_type = m_ast.CreateBaseType(type_name, byte_size); - return std::make_shared<Type>(die.GetID(), dwarf, type_name, byte_size, - nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, - decl, compiler_type, Type::eResolveStateFull); -} - -lldb::TypeSP DWARFASTParserOCaml::ParseTypeFromDWARF(const SymbolContext &sc, - const DWARFDIE &die, - Log *log, - bool *type_is_new_ptr) { - if (type_is_new_ptr) - *type_is_new_ptr = false; - - if (!die) - return nullptr; - - SymbolFileDWARF *dwarf = die.GetDWARF(); - - Type *type_ptr = dwarf->m_die_to_type.lookup(die.GetDIE()); - if (type_ptr == DIE_IS_BEING_PARSED) - return nullptr; - if (type_ptr != nullptr) - return type_ptr->shared_from_this(); - - TypeSP type_sp; - if (type_is_new_ptr) - *type_is_new_ptr = true; - - switch (die.Tag()) { - case DW_TAG_base_type: { - type_sp = ParseBaseTypeFromDIE(die); - break; - } - case DW_TAG_array_type: { - break; - } - case DW_TAG_class_type: { - break; - } - case DW_TAG_reference_type: { - break; - } - } - - if (!type_sp) - return nullptr; - - DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die); - dw_tag_t sc_parent_tag = sc_parent_die.Tag(); - - SymbolContextScope *symbol_context_scope = nullptr; - if (sc_parent_tag == DW_TAG_compile_unit || - sc_parent_tag == DW_TAG_partial_unit) { - symbol_context_scope = sc.comp_unit; - } else if (sc.function != nullptr && sc_parent_die) { - symbol_context_scope = - sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); - if (symbol_context_scope == nullptr) - symbol_context_scope = sc.function; - } - - if (symbol_context_scope != nullptr) - type_sp->SetSymbolContextScope(symbol_context_scope); - - dwarf->GetTypeList()->Insert(type_sp); - dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); - - return type_sp; -} - -Function *DWARFASTParserOCaml::ParseFunctionFromDWARF(const SymbolContext &sc, - const DWARFDIE &die) { - DWARFRangeList func_ranges; - const char *name = NULL; - const char *mangled = NULL; - int decl_file = 0; - int decl_line = 0; - int decl_column = 0; - int call_file = 0; - int call_line = 0; - int call_column = 0; - DWARFExpression frame_base(die.GetCU()); - - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - - if (die) { - SymbolFileDWARF *dwarf = die.GetDWARF(); - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, "DWARFASTParserOCaml::ParseFunctionFromDWARF (die = 0x%8.8x) %s " - "name = '%s')", - die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.GetName()); - } - } - - assert(die.Tag() == DW_TAG_subprogram); - - if (die.Tag() != DW_TAG_subprogram) - return NULL; - - if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line, - decl_column, call_file, call_line, call_column, - &frame_base)) { - AddressRange func_range; - lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase(0); - lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd(0); - if (lowest_func_addr != LLDB_INVALID_ADDRESS && - lowest_func_addr <= highest_func_addr) { - ModuleSP module_sp(die.GetModule()); - func_range.GetBaseAddress().ResolveAddressUsingFileSections( - lowest_func_addr, module_sp->GetSectionList()); - if (func_range.GetBaseAddress().IsValid()) - func_range.SetByteSize(highest_func_addr - lowest_func_addr); - } - - if (func_range.GetBaseAddress().IsValid()) { - Mangled func_name; - - func_name.SetValue(ConstString(name), true); - - FunctionSP func_sp; - std::unique_ptr<Declaration> decl_ap; - if (decl_file != 0 || decl_line != 0 || decl_column != 0) - decl_ap.reset(new Declaration( - sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), - decl_line, decl_column)); - - SymbolFileDWARF *dwarf = die.GetDWARF(); - Type *func_type = dwarf->m_die_to_type.lookup(die.GetDIE()); - - assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED); - - if (dwarf->FixupAddress(func_range.GetBaseAddress())) { - const user_id_t func_user_id = die.GetID(); - func_sp.reset(new Function(sc.comp_unit, - func_user_id, // UserID is the DIE offset - func_user_id, func_name, func_type, - func_range)); // first address range - - if (func_sp.get() != NULL) { - if (frame_base.IsValid()) - func_sp->GetFrameBaseExpression() = frame_base; - sc.comp_unit->AddFunction(func_sp); - return func_sp.get(); - } - } - } - } - - return NULL; -} - -lldb_private::CompilerDeclContext -DWARFASTParserOCaml::GetDeclContextForUIDFromDWARF(const DWARFDIE &die) { - return CompilerDeclContext(); -} - -lldb_private::CompilerDeclContext -DWARFASTParserOCaml::GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) { - return CompilerDeclContext(); -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h b/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h deleted file mode 100644 index 09cb5e14934f..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h +++ /dev/null @@ -1,59 +0,0 @@ -//===-- DWARFASTParserOCaml.h -----------------------------------*- C++ -*-===// - -#ifndef SymbolFileDWARF_DWARFASTParserOCaml_h_ -#define SymbolFileDWARF_DWARFASTParserOCaml_h_ - -#include "DWARFASTParser.h" -#include "DWARFDIE.h" -#include "DWARFDebugInfo.h" -#include "DWARFDefines.h" -#include "SymbolFileDWARF.h" - -#include "lldb/Symbol/OCamlASTContext.h" - -class DWARFDebugInfoEntry; -class DWARFDIECollection; - -class DWARFASTParserOCaml : public DWARFASTParser { -public: - DWARFASTParserOCaml(lldb_private::OCamlASTContext &ast); - - virtual ~DWARFASTParserOCaml(); - - lldb::TypeSP ParseBaseTypeFromDIE(const DWARFDIE &die); - - lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, lldb_private::Log *log, - bool *type_is_new_ptr) override; - - lldb_private::Function * - ParseFunctionFromDWARF(const lldb_private::SymbolContext &sc, - const DWARFDIE &die) override; - - bool - CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, - lldb_private::CompilerType &compiler_type) override { - return false; - } - - lldb_private::CompilerDecl - GetDeclForUIDFromDWARF(const DWARFDIE &die) override { - return lldb_private::CompilerDecl(); - } - - lldb_private::CompilerDeclContext - GetDeclContextForUIDFromDWARF(const DWARFDIE &die) override; - - lldb_private::CompilerDeclContext - GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) override; - - std::vector<DWARFDIE> GetDIEForDeclContext( - lldb_private::CompilerDeclContext decl_context) override { - return {}; - } - -protected: - lldb_private::OCamlASTContext &m_ast; -}; - -#endif // SymbolFileDWARF_DWARFASTParserOCaml_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp index a765be0b46d0..d78b9ab10f5a 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp @@ -41,9 +41,13 @@ bool DWARFAbbreviationDeclaration::Extract(const DWARFDataExtractor &data, while (data.ValidOffset(*offset_ptr)) { dw_attr_t attr = data.GetULEB128(offset_ptr); dw_form_t form = data.GetULEB128(offset_ptr); + DWARFFormValue::ValueType val; + + if (form == DW_FORM_implicit_const) + val.value.sval = data.GetULEB128(offset_ptr); if (attr && form) - m_attributes.push_back(DWARFAttribute(attr, form)); + m_attributes.push_back(DWARFAttribute(attr, form, val)); else break; } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h index b2296c455d6a..afce52558f45 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h @@ -35,20 +35,11 @@ public: dw_form_t GetFormByIndex(uint32_t idx) const { return m_attributes.size() > idx ? m_attributes[idx].get_form() : 0; } - bool GetAttrAndFormByIndex(uint32_t idx, dw_attr_t &attr, - dw_form_t &form) const { - if (m_attributes.size() > idx) { - m_attributes[idx].get(attr, form); - return true; - } - attr = form = 0; - return false; - } - // idx is assumed to be valid when calling GetAttrAndFormByIndexUnchecked() - void GetAttrAndFormByIndexUnchecked(uint32_t idx, dw_attr_t &attr, - dw_form_t &form) const { - m_attributes[idx].get(attr, form); + // idx is assumed to be valid when calling GetAttrAndFormByIndex() + void GetAttrAndFormValueByIndex(uint32_t idx, dw_attr_t &attr, + DWARFFormValue &form_value) const { + m_attributes[idx].get(attr, form_value.FormRef(), form_value.ValueRef()); } dw_form_t GetFormByIndexUnchecked(uint32_t idx) const { return m_attributes[idx].get_form(); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp index 2586d1f18530..dd830eb7b9dd 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp @@ -26,10 +26,10 @@ uint32_t DWARFAttributes::FindAttributeIndex(dw_attr_t attr) const { return UINT32_MAX; } -void DWARFAttributes::Append(const DWARFUnit *cu, - dw_offset_t attr_die_offset, dw_attr_t attr, - dw_form_t form) { - AttributeValue attr_value = {cu, attr_die_offset, {attr, form}}; +void DWARFAttributes::Append(const DWARFUnit *cu, dw_offset_t attr_die_offset, + dw_attr_t attr, dw_form_t form) { + AttributeValue attr_value = { + cu, attr_die_offset, {attr, form, DWARFFormValue::ValueType()}}; m_infos.push_back(attr_value); } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h index db4324cf7725..2399861d7fc3 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h @@ -11,15 +11,17 @@ #define SymbolFileDWARF_DWARFAttribute_h_ #include "DWARFDefines.h" +#include "DWARFFormValue.h" #include "llvm/ADT/SmallVector.h" #include <vector> class DWARFUnit; -class DWARFFormValue; class DWARFAttribute { public: - DWARFAttribute(dw_attr_t attr, dw_form_t form) : m_attr(attr), m_form(form) {} + DWARFAttribute(dw_attr_t attr, dw_form_t form, + DWARFFormValue::ValueType value) + : m_attr(attr), m_form(form), m_value(value) {} void set(dw_attr_t attr, dw_form_t form) { m_attr = attr; @@ -29,9 +31,11 @@ public: void set_form(dw_form_t form) { m_form = form; } dw_attr_t get_attr() const { return m_attr; } dw_form_t get_form() const { return m_form; } - void get(dw_attr_t &attr, dw_form_t &form) const { + void get(dw_attr_t &attr, dw_form_t &form, + DWARFFormValue::ValueType &val) const { attr = m_attr; form = m_form; + val = m_value; } bool operator==(const DWARFAttribute &rhs) const { return m_attr == rhs.m_attr && m_form == rhs.m_form; @@ -43,6 +47,7 @@ public: protected: dw_attr_t m_attr; dw_form_t m_form; + DWARFFormValue::ValueType m_value; }; class DWARFAttributes { diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index 8541f1cfe1f6..b9a7231286e3 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -34,8 +34,18 @@ DWARFUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, cu_sp->m_length = debug_info.GetDWARFInitialLength(offset_ptr); cu_sp->m_is_dwarf64 = debug_info.IsDWARF64(); cu_sp->m_version = debug_info.GetU16(offset_ptr); - abbr_offset = debug_info.GetDWARFOffset(offset_ptr); - cu_sp->m_addr_size = debug_info.GetU8(offset_ptr); + + if (cu_sp->m_version == 5) { + cu_sp->m_unit_type = debug_info.GetU8(offset_ptr); + cu_sp->m_addr_size = debug_info.GetU8(offset_ptr); + abbr_offset = debug_info.GetDWARFOffset(offset_ptr); + + if (cu_sp->m_unit_type == llvm::dwarf::DW_UT_skeleton) + cu_sp->m_dwo_id = debug_info.GetU64(offset_ptr); + } else { + abbr_offset = debug_info.GetDWARFOffset(offset_ptr); + cu_sp->m_addr_size = debug_info.GetU8(offset_ptr); + } bool length_OK = debug_info.ValidOffset(cu_sp->GetNextCompileUnitOffset() - 1); @@ -65,6 +75,23 @@ void DWARFCompileUnit::Dump(Stream *s) const { GetNextCompileUnitOffset()); } +uint32_t DWARFCompileUnit::GetHeaderByteSize() const { + if (m_version < 5) + return m_is_dwarf64 ? 23 : 11; + + switch (m_unit_type) { + case llvm::dwarf::DW_UT_compile: + case llvm::dwarf::DW_UT_partial: + return 12; + case llvm::dwarf::DW_UT_skeleton: + case llvm::dwarf::DW_UT_split_compile: + return 20; + case llvm::dwarf::DW_UT_type: + case llvm::dwarf::DW_UT_split_type: + return 24; + } + llvm_unreachable("invalid UnitType."); +} const lldb_private::DWARFDataExtractor &DWARFCompileUnit::GetData() const { return m_dwarf->get_debug_info_data(); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index d20f31505ed4..b92a155e0335 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -35,9 +35,7 @@ public: /// @return /// Byte size of the compile unit header //------------------------------------------------------------------ - uint32_t GetHeaderByteSize() const override { - return m_is_dwarf64 ? 23 : 11; - } + uint32_t GetHeaderByteSize() const override; private: DWARFCompileUnit(SymbolFileDWARF *dwarf2Data); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index d9754e911017..22b70b2d6852 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -166,13 +166,13 @@ void DWARFDIE::GetDWARFDeclContext(DWARFDeclContext &dwarf_decl_ctx) const { } } -void DWARFDIE::GetDWOContext(std::vector<CompilerContext> &context) const { +void DWARFDIE::GetDeclContext(std::vector<CompilerContext> &context) const { const dw_tag_t tag = Tag(); if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) return; DWARFDIE parent = GetParent(); if (parent) - parent.GetDWOContext(context); + parent.GetDeclContext(context); switch (tag) { case DW_TAG_module: context.push_back( diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index ecbf4912634e..b0d06a886ac1 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -90,7 +90,10 @@ public: void GetDWARFDeclContext(DWARFDeclContext &dwarf_decl_ctx) const; - void GetDWOContext(std::vector<lldb_private::CompilerContext> &context) const; + /// Return this DIE's decl context as it is needed to look up types + /// in Clang's -gmodules debug info format. + void + GetDeclContext(std::vector<lldb_private::CompilerContext> &context) const; //---------------------------------------------------------------------- // Getting attribute values from the DIE. diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h index ce0bfb3931d5..1f342035f135 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h @@ -10,7 +10,6 @@ #ifndef liblldb_DWARFDataExtractor_h_ #define liblldb_DWARFDataExtractor_h_ -// Other libraries and framework includes. #include "lldb/Core/dwarf.h" #include "lldb/Utility/DataExtractor.h" diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h index 6524cb3ce483..e7a8635f0532 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h @@ -19,7 +19,7 @@ class SymbolFileDWARF; class DWARFDebugAranges { protected: - typedef lldb_private::RangeDataArray<dw_addr_t, uint32_t, dw_offset_t, 1> + typedef lldb_private::RangeDataVector<dw_addr_t, uint32_t, dw_offset_t> RangeToDIE; public: diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index d32aef6e162c..7531aeac709a 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -40,9 +40,8 @@ bool DWARFDebugInfoEntry::FastExtract( m_offset = *offset_ptr; m_parent_idx = 0; m_sibling_idx = 0; - m_empty_children = false; const uint64_t abbr_idx = debug_info_data.GetULEB128(offset_ptr); - assert(abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE)); + lldbassert(abbr_idx <= UINT16_MAX); m_abbr_idx = abbr_idx; // assert (fixed_form_sizes); // For best performance this should be @@ -119,21 +118,33 @@ bool DWARFDebugInfoEntry::FastExtract( break; // 1 byte values + case DW_FORM_addrx1: case DW_FORM_data1: case DW_FORM_flag: case DW_FORM_ref1: + case DW_FORM_strx1: form_size = 1; break; // 2 byte values + case DW_FORM_addrx2: case DW_FORM_data2: case DW_FORM_ref2: + case DW_FORM_strx2: form_size = 2; break; + // 3 byte values + case DW_FORM_addrx3: + case DW_FORM_strx3: + form_size = 3; + break; + // 4 byte values + case DW_FORM_addrx4: case DW_FORM_data4: case DW_FORM_ref4: + case DW_FORM_strx4: form_size = 4; break; @@ -145,11 +156,14 @@ bool DWARFDebugInfoEntry::FastExtract( break; // signed or unsigned LEB 128 values + case DW_FORM_addrx: + case DW_FORM_rnglistx: case DW_FORM_sdata: case DW_FORM_udata: case DW_FORM_ref_udata: case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: + case DW_FORM_strx: debug_info_data.Skip_LEB128(&offset); break; @@ -166,6 +180,10 @@ bool DWARFDebugInfoEntry::FastExtract( debug_info_data.GetU32(&offset); break; + case DW_FORM_implicit_const: + form_size = 0; + break; + default: *offset_ptr = m_offset; return false; @@ -208,7 +226,7 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, m_offset = offset; const uint64_t abbr_idx = debug_info_data.GetULEB128(&offset); - assert(abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE)); + lldbassert(abbr_idx <= UINT16_MAX); m_abbr_idx = abbr_idx; if (abbr_idx) { const DWARFAbbreviationDeclaration *abbrevDecl = @@ -225,15 +243,14 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, // Skip all data in the .debug_info for the attributes const uint32_t numAttributes = abbrevDecl->NumAttributes(); - uint32_t i; - dw_attr_t attr; - dw_form_t form; - for (i = 0; i < numAttributes; ++i) { - abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); + for (uint32_t i = 0; i < numAttributes; ++i) { + DWARFFormValue form_value(cu); + dw_attr_t attr; + abbrevDecl->GetAttrAndFormValueByIndex(i, attr, form_value); + dw_form_t form = form_value.Form(); if (isCompileUnitTag && ((attr == DW_AT_entry_pc) || (attr == DW_AT_low_pc))) { - DWARFFormValue form_value(cu, form); if (form_value.ExtractValue(debug_info_data, &offset)) { if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc) const_cast<DWARFUnit *>(cu)->SetBaseAddress( @@ -279,6 +296,7 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, // 0 sized form case DW_FORM_flag_present: + case DW_FORM_implicit_const: form_size = 0; break; @@ -370,6 +388,13 @@ void DWARFDebugInfoEntry::DumpAncestry(SymbolFileDWARF *dwarf2Data, Dump(dwarf2Data, cu, s, recurse_depth); } +static dw_offset_t GetRangesOffset(const DWARFDebugRangesBase *debug_ranges, + DWARFFormValue &form_value) { + if (form_value.Form() == DW_FORM_rnglistx) + return debug_ranges->GetOffset(form_value.Unsigned()); + return form_value.Unsigned(); +} + //---------------------------------------------------------------------- // GetDIENamesAndRanges // @@ -409,14 +434,13 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( return false; const uint32_t numAttributes = abbrevDecl->NumAttributes(); - uint32_t i; - dw_attr_t attr; - dw_form_t form; bool do_offset = false; - for (i = 0; i < numAttributes; ++i) { - abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); - DWARFFormValue form_value(cu, form); + for (uint32_t i = 0; i < numAttributes; ++i) { + DWARFFormValue form_value(cu); + dw_attr_t attr; + abbrevDecl->GetAttrAndFormValueByIndex(i, attr, form_value); + if (form_value.ExtractValue(debug_info_data, &offset)) { switch (attr) { case DW_AT_low_pc: @@ -446,20 +470,15 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( break; case DW_AT_ranges: { - const DWARFDebugRanges *debug_ranges = dwarf2Data->DebugRanges(); - if (debug_ranges) { - debug_ranges->FindRanges(cu->GetRangesBase(), form_value.Unsigned(), ranges); - // All DW_AT_ranges are relative to the base address of the compile - // unit. We add the compile unit base address to make sure all the - // addresses are properly fixed up. - ranges.Slide(cu->GetBaseAddress()); - } else { + const DWARFDebugRangesBase *debug_ranges = dwarf2Data->DebugRanges(); + if (debug_ranges) + debug_ranges->FindRanges(cu, GetRangesOffset(debug_ranges, form_value), ranges); + else cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()->ReportError( "{0x%8.8x}: DIE has DW_AT_ranges(0x%" PRIx64 ") attribute yet DWARF has no .debug_ranges, please file a bug " "and attach the file at the start of this error message", m_offset, form_value.Unsigned()); - } } break; case DW_AT_name: @@ -521,7 +540,7 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( block_length); } else { const DWARFDataExtractor &debug_loc_data = - dwarf2Data->get_debug_loc_data(); + dwarf2Data->DebugLocData(); const dw_offset_t debug_loc_offset = form_value.Unsigned(); size_t loc_list_length = DWARFExpression::LocationListSize( @@ -606,14 +625,13 @@ void DWARFDebugInfoEntry::Dump(SymbolFileDWARF *dwarf2Data, // Dump all data in the .debug_info for the attributes const uint32_t numAttributes = abbrevDecl->NumAttributes(); - uint32_t i; - dw_attr_t attr; - dw_form_t form; - for (i = 0; i < numAttributes; ++i) { - abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); + for (uint32_t i = 0; i < numAttributes; ++i) { + DWARFFormValue form_value(cu); + dw_attr_t attr; + abbrevDecl->GetAttrAndFormValueByIndex(i, attr, form_value); DumpAttribute(dwarf2Data, cu, debug_info_data, &offset, s, attr, - form); + form_value); } const DWARFDebugInfoEntry *child = GetFirstChild(); @@ -663,23 +681,21 @@ void DWARFDebugInfoEntry::DumpLocation(SymbolFileDWARF *dwarf2Data, void DWARFDebugInfoEntry::DumpAttribute( SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const DWARFDataExtractor &debug_info_data, lldb::offset_t *offset_ptr, - Stream &s, dw_attr_t attr, dw_form_t form) { + 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)); + s.Printf("[%s", DW_FORM_value_to_name(form_value.Form())); } - DWARFFormValue form_value(cu, form); - if (!form_value.ExtractValue(debug_info_data, offset_ptr)) return; if (show_form) { - if (form == DW_FORM_indirect) { + if (form_value.Form() == DW_FORM_indirect) { s.Printf(" [%s]", DW_FORM_value_to_name(form_value.Form())); } @@ -719,7 +735,7 @@ void DWARFDebugInfoEntry::DumpAttribute( uint64_t debug_loc_offset = form_value.Unsigned(); if (dwarf2Data) { DWARFExpression::PrintDWARFLocationList( - s, cu, dwarf2Data->get_debug_loc_data(), debug_loc_offset); + s, cu, dwarf2Data->DebugLocData(), debug_loc_offset); } } } break; @@ -740,11 +756,13 @@ void DWARFDebugInfoEntry::DumpAttribute( } break; case DW_AT_ranges: { - lldb::offset_t ranges_offset = form_value.Unsigned(); + if (!dwarf2Data) + break; + lldb::offset_t ranges_offset = + GetRangesOffset(dwarf2Data->DebugRanges(), form_value); dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0; - if (dwarf2Data) - DWARFDebugRanges::Dump(s, dwarf2Data->get_debug_ranges_data(), - &ranges_offset, base_addr); + DWARFDebugRanges::Dump(s, dwarf2Data->get_debug_ranges_data(), + &ranges_offset, base_addr); } break; default: @@ -786,11 +804,11 @@ size_t DWARFDebugInfoEntry::GetAttributes( cu->GetAddressByteSize(), cu->IsDWARF64()); const uint32_t num_attributes = abbrevDecl->NumAttributes(); - uint32_t i; - dw_attr_t attr; - dw_form_t form; - for (i = 0; i < num_attributes; ++i) { - abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); + for (uint32_t i = 0; i < num_attributes; ++i) { + DWARFFormValue form_value(cu); + dw_attr_t attr; + abbrevDecl->GetAttrAndFormValueByIndex(i, attr, form_value); + const dw_form_t form = form_value.Form(); // If we are tracking down DW_AT_specification or DW_AT_abstract_origin // attributes, the depth will be non-zero. We need to omit certain @@ -811,7 +829,6 @@ size_t DWARFDebugInfoEntry::GetAttributes( } if ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin)) { - DWARFFormValue form_value(cu, form); if (form_value.ExtractValue(debug_info_data, &offset)) { dw_offset_t die_offset = form_value.Reference(); DWARFDIE spec_die = @@ -1055,14 +1072,11 @@ size_t DWARFDebugInfoEntry::GetAttributeAddressRanges( bool check_specification_or_abstract_origin) const { ranges.Clear(); - dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned( - dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET, - check_specification_or_abstract_origin); - if (debug_ranges_offset != DW_INVALID_OFFSET) { - DWARFDebugRanges *debug_ranges = dwarf2Data->DebugRanges(); - - debug_ranges->FindRanges(cu->GetRangesBase(), debug_ranges_offset, ranges); - ranges.Slide(cu->GetBaseAddress()); + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, DW_AT_ranges, form_value)) { + if (DWARFDebugRangesBase *debug_ranges = dwarf2Data->DebugRanges()) + debug_ranges->FindRanges(cu, GetRangesOffset(debug_ranges, form_value), + ranges); } else if (check_hi_lo_pc) { dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; @@ -1713,16 +1727,13 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, ((function_die != NULL) || (block_die != NULL)); } } else { - dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned( - dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET); - if (debug_ranges_offset != DW_INVALID_OFFSET) { + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, DW_AT_ranges, form_value)) { DWARFRangeList ranges; - DWARFDebugRanges *debug_ranges = dwarf2Data->DebugRanges(); - debug_ranges->FindRanges(cu->GetRangesBase(), debug_ranges_offset, ranges); - // All DW_AT_ranges are relative to the base address of the compile - // unit. We add the compile unit base address to make sure all the - // addresses are properly fixed up. - ranges.Slide(cu->GetBaseAddress()); + DWARFDebugRangesBase *debug_ranges = dwarf2Data->DebugRanges(); + debug_ranges->FindRanges( + cu, GetRangesOffset(debug_ranges, form_value), ranges); + if (ranges.FindEntryThatContains(address)) { found_address = true; // puts("***MATCH***"); @@ -1829,7 +1840,6 @@ void DWARFDebugInfoEntry::DumpDIECollection( 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 && - m_empty_children == rhs.m_empty_children && m_abbr_idx == rhs.m_abbr_idx && m_has_children == rhs.m_has_children && m_tag == rhs.m_tag; } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 97cb3046eb3e..ec19fc814fba 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -43,7 +43,6 @@ typedef UInt32ToDIEMMap::const_iterator UInt32ToDIEMMapConstIter; class DWARFDeclContext; #define DIE_SIBLING_IDX_BITSIZE 31 -#define DIE_ABBR_IDX_BITSIZE 15 class DWARFDebugInfoEntry { public: @@ -57,8 +56,7 @@ public: DWARFDebugInfoEntry() : m_offset(DW_INVALID_OFFSET), m_parent_idx(0), m_sibling_idx(0), - m_empty_children(false), m_abbr_idx(0), m_has_children(false), - m_tag(0) {} + m_has_children(false), m_abbr_idx(0), m_tag(0) {} explicit operator bool() const { return m_offset != DW_INVALID_OFFSET; } bool operator==(const DWARFDebugInfoEntry &rhs) const; @@ -178,7 +176,7 @@ public: DumpAttribute(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const lldb_private::DWARFDataExtractor &debug_info_data, lldb::offset_t *offset_ptr, lldb_private::Stream &s, - dw_attr_t attr, dw_form_t form); + dw_attr_t attr, DWARFFormValue &form_value); // This one dumps the comp unit name, objfile name and die offset for this die // so the stream S. void DumpLocation(SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, @@ -227,10 +225,10 @@ public: // we don't need to store our child pointer, if we have a child it will // be the next entry in the list... DWARFDebugInfoEntry *GetFirstChild() { - return (HasChildren() && !m_empty_children) ? this + 1 : NULL; + return HasChildren() ? this + 1 : NULL; } const DWARFDebugInfoEntry *GetFirstChild() const { - return (HasChildren() && !m_empty_children) ? this + 1 : NULL; + return HasChildren() ? this + 1 : NULL; } void GetDeclContextDIEs(DWARFUnit *cu, @@ -271,10 +269,6 @@ public: void SetParentIndex(uint32_t idx) { m_parent_idx = idx; } - bool GetEmptyChildren() const { return m_empty_children; } - - void SetEmptyChildren(bool b) { m_empty_children = b; } - static void DumpDIECollection(lldb_private::Stream &strm, DWARFDebugInfoEntry::collection &die_collection); @@ -285,13 +279,13 @@ protected: uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. // If zero this die has no parent uint32_t m_sibling_idx : 31, // How many to add to "this" to get the sibling. - m_empty_children : 1; // If a DIE says it had children, yet it just - // contained a NULL tag, this will be set. - uint32_t m_abbr_idx : DIE_ABBR_IDX_BITSIZE, - m_has_children : 1, // Set to 1 if this DIE has children - m_tag : 16; // A copy of the DW_TAG value so we don't - // have to go through the compile unit - // abbrev table + // If it is zero, then the DIE doesn't have children, or the + // DWARF claimed it had children but the DIE only contained + // a single NULL terminating child. + m_has_children : 1; + uint16_t m_abbr_idx; + uint16_t m_tag; // A copy of the DW_TAG value so we don't have to go through + // the compile unit abbrev table }; #endif // SymbolFileDWARF_DWARFDebugInfoEntry_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp index 317ea4c22c66..d9f50122bd6f 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp @@ -41,7 +41,7 @@ void DWARFDebugLine::Parse(const DWARFDataExtractor &debug_line_data) { if (line_table_sp.get() == NULL) break; - if (ParseStatementTable(debug_line_data, &offset, line_table_sp.get())) { + if (ParseStatementTable(debug_line_data, &offset, line_table_sp.get(), nullptr)) { // Make sure we don't don't loop infinitely if (offset <= debug_line_offset) break; @@ -127,7 +127,7 @@ DWARFDebugLine::DumpStatementTable(Log *log, "--------\n", debug_line_offset); - if (ParseStatementTable(debug_line_data, &offset, DumpStateToFile, log)) + if (ParseStatementTable(debug_line_data, &offset, DumpStateToFile, log, nullptr)) return offset; else return debug_line_offset + 1; // Skip to next byte in .debug_line section @@ -366,17 +366,38 @@ void DWARFDebugLine::Parse(const DWARFDataExtractor &debug_line_data, void *userData) { lldb::offset_t offset = 0; if (debug_line_data.ValidOffset(offset)) { - if (!ParseStatementTable(debug_line_data, &offset, callback, userData)) + if (!ParseStatementTable(debug_line_data, &offset, callback, userData, nullptr)) ++offset; // Skip to next byte in .debug_line section } } +namespace { +struct EntryDescriptor { + dw_sleb128_t code; + dw_sleb128_t form; +}; + +static std::vector<EntryDescriptor> +ReadDescriptors(const DWARFDataExtractor &debug_line_data, + lldb::offset_t *offset_ptr) { + std::vector<EntryDescriptor> ret; + uint8_t n = debug_line_data.GetU8(offset_ptr); + for (uint8_t i = 0; i < n; ++i) { + EntryDescriptor ent; + ent.code = debug_line_data.GetULEB128(offset_ptr); + ent.form = debug_line_data.GetULEB128(offset_ptr); + ret.push_back(ent); + } + return ret; +} +} // namespace + //---------------------------------------------------------------------- // DWARFDebugLine::ParsePrologue //---------------------------------------------------------------------- bool DWARFDebugLine::ParsePrologue(const DWARFDataExtractor &debug_line_data, lldb::offset_t *offset_ptr, - Prologue *prologue) { + Prologue *prologue, DWARFUnit *dwarf_cu) { const lldb::offset_t prologue_offset = *offset_ptr; // DEBUG_PRINTF("0x%8.8x: ParsePrologue()\n", *offset_ptr); @@ -386,9 +407,14 @@ bool DWARFDebugLine::ParsePrologue(const DWARFDataExtractor &debug_line_data, const char *s; prologue->total_length = debug_line_data.GetDWARFInitialLength(offset_ptr); prologue->version = debug_line_data.GetU16(offset_ptr); - if (prologue->version < 2 || prologue->version > 4) + if (prologue->version < 2 || prologue->version > 5) return false; + if (prologue->version >= 5) { + prologue->address_size = debug_line_data.GetU8(offset_ptr); + prologue->segment_selector_size = debug_line_data.GetU8(offset_ptr); + } + prologue->prologue_length = debug_line_data.GetDWARFOffset(offset_ptr); const lldb::offset_t end_prologue_offset = prologue->prologue_length + *offset_ptr; @@ -410,25 +436,83 @@ bool DWARFDebugLine::ParsePrologue(const DWARFDataExtractor &debug_line_data, prologue->standard_opcode_lengths.push_back(op_len); } - while (*offset_ptr < end_prologue_offset) { - s = debug_line_data.GetCStr(offset_ptr); - if (s && s[0]) - prologue->include_directories.push_back(s); - else - break; - } + if (prologue->version >= 5) { + std::vector<EntryDescriptor> dirEntryFormatV = + ReadDescriptors(debug_line_data, offset_ptr); + uint8_t dirCount = debug_line_data.GetULEB128(offset_ptr); + for (int i = 0; i < dirCount; ++i) { + for (EntryDescriptor &ent : dirEntryFormatV) { + DWARFFormValue value(dwarf_cu, ent.form); + if (ent.code != DW_LNCT_path) { + if (!value.SkipValue(debug_line_data, offset_ptr)) + return false; + continue; + } - while (*offset_ptr < end_prologue_offset) { - const char *name = debug_line_data.GetCStr(offset_ptr); - if (name && name[0]) { - FileNameEntry fileEntry; - fileEntry.name = name; - fileEntry.dir_idx = debug_line_data.GetULEB128(offset_ptr); - fileEntry.mod_time = debug_line_data.GetULEB128(offset_ptr); - fileEntry.length = debug_line_data.GetULEB128(offset_ptr); - prologue->file_names.push_back(fileEntry); - } else - break; + if (!value.ExtractValue(debug_line_data, offset_ptr)) + return false; + prologue->include_directories.push_back(value.AsCString()); + } + } + + std::vector<EntryDescriptor> filesEntryFormatV = + ReadDescriptors(debug_line_data, offset_ptr); + llvm::DenseSet<std::pair<uint64_t, uint64_t>> seen; + uint8_t n = debug_line_data.GetULEB128(offset_ptr); + for (int i = 0; i < n; ++i) { + FileNameEntry entry; + for (EntryDescriptor &ent : filesEntryFormatV) { + DWARFFormValue value(dwarf_cu, ent.form); + if (!value.ExtractValue(debug_line_data, offset_ptr)) + return false; + + switch (ent.code) { + case DW_LNCT_path: + entry.name = value.AsCString(); + break; + case DW_LNCT_directory_index: + entry.dir_idx = value.Unsigned(); + break; + case DW_LNCT_timestamp: + entry.mod_time = value.Unsigned(); + break; + case DW_LNCT_size: + entry.length = value.Unsigned(); + break; + case DW_LNCT_MD5: + assert(value.Unsigned() == 16); + std::uninitialized_copy_n(value.BlockData(), 16, + entry.checksum.Bytes.begin()); + break; + default: + break; + } + } + + if (seen.insert(entry.checksum.words()).second) + prologue->file_names.push_back(entry); + } + } else { + while (*offset_ptr < end_prologue_offset) { + s = debug_line_data.GetCStr(offset_ptr); + if (s && s[0]) + prologue->include_directories.push_back(s); + else + break; + } + + while (*offset_ptr < end_prologue_offset) { + const char *name = debug_line_data.GetCStr(offset_ptr); + if (name && name[0]) { + FileNameEntry fileEntry; + fileEntry.name = name; + fileEntry.dir_idx = debug_line_data.GetULEB128(offset_ptr); + fileEntry.mod_time = debug_line_data.GetULEB128(offset_ptr); + fileEntry.length = debug_line_data.GetULEB128(offset_ptr); + prologue->file_names.push_back(fileEntry); + } else + break; + } } // XXX GNU as is broken for 64-Bit DWARF @@ -445,11 +529,11 @@ bool DWARFDebugLine::ParsePrologue(const DWARFDataExtractor &debug_line_data, bool DWARFDebugLine::ParseSupportFiles( const lldb::ModuleSP &module_sp, const DWARFDataExtractor &debug_line_data, const lldb_private::FileSpec &cu_comp_dir, dw_offset_t stmt_list, - FileSpecList &support_files) { + FileSpecList &support_files, DWARFUnit *dwarf_cu) { lldb::offset_t offset = stmt_list; Prologue prologue; - if (!ParsePrologue(debug_line_data, &offset, &prologue)) { + if (!ParsePrologue(debug_line_data, &offset, &prologue, dwarf_cu)) { Host::SystemLog(Host::eSystemLogError, "error: parsing line table prologue " "at 0x%8.8x (parsing ended around " "0x%8.8" PRIx64 "\n", @@ -463,7 +547,7 @@ bool DWARFDebugLine::ParseSupportFiles( for (uint32_t file_idx = 1; prologue.GetFile(file_idx, cu_comp_dir, file_spec); ++file_idx) { if (module_sp->RemapSourceFile(file_spec.GetPath(), remapped_file)) - file_spec.SetFile(remapped_file, false, FileSpec::Style::native); + file_spec.SetFile(remapped_file, FileSpec::Style::native); support_files.Append(file_spec); } return true; @@ -478,7 +562,7 @@ bool DWARFDebugLine::ParseSupportFiles( //---------------------------------------------------------------------- bool DWARFDebugLine::ParseStatementTable( const DWARFDataExtractor &debug_line_data, lldb::offset_t *offset_ptr, - DWARFDebugLine::State::Callback callback, void *userData) { + DWARFDebugLine::State::Callback callback, void *userData, DWARFUnit *dwarf_cu) { Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_LINE)); Prologue::shared_ptr prologue(new Prologue()); @@ -489,7 +573,7 @@ bool DWARFDebugLine::ParseStatementTable( func_cat, "DWARFDebugLine::ParseStatementTable (.debug_line[0x%8.8x])", debug_line_offset); - if (!ParsePrologue(debug_line_data, offset_ptr, prologue.get())) { + if (!ParsePrologue(debug_line_data, offset_ptr, prologue.get(), dwarf_cu)) { if (log) log->Error("failed to parse DWARF line table prologue"); // Restore our offset and return false to indicate failure! @@ -775,9 +859,9 @@ static void ParseStatementTableCallback(dw_offset_t offset, //---------------------------------------------------------------------- bool DWARFDebugLine::ParseStatementTable( const DWARFDataExtractor &debug_line_data, lldb::offset_t *offset_ptr, - LineTable *line_table) { + LineTable *line_table, DWARFUnit *dwarf_cu) { return ParseStatementTable(debug_line_data, offset_ptr, - ParseStatementTableCallback, line_table); + ParseStatementTableCallback, line_table, dwarf_cu); } inline bool DWARFDebugLine::Prologue::IsValid() const { @@ -866,7 +950,7 @@ bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, const lldb_private::FileSpec &comp_dir, FileSpec &file) const { uint32_t idx = file_idx - 1; // File indexes are 1 based... if (idx < file_names.size()) { - file.SetFile(file_names[idx].name, false, FileSpec::Style::native); + file.SetFile(file_names[idx].name, FileSpec::Style::native); if (file.IsRelative()) { if (file_names[idx].dir_idx > 0) { const uint32_t dir_idx = file_names[idx].dir_idx - 1; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h index 3ab15ac59028..04f72e03a2db 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h @@ -19,6 +19,9 @@ #include "DWARFDataExtractor.h" #include "DWARFDefines.h" +#include "llvm/Support/MD5.h" + +class DWARFUnit; class SymbolFileDWARF; //---------------------------------------------------------------------- @@ -36,6 +39,7 @@ public: dw_sleb128_t dir_idx; dw_sleb128_t mod_time; dw_sleb128_t length; + llvm::MD5::MD5Result checksum; }; //------------------------------------------------------------------ @@ -55,6 +59,10 @@ public: // total_length field itself). uint16_t version; // Version identifier for the statement information format. + + uint8_t address_size; + uint8_t segment_selector_size; + uint32_t prologue_length; // The number of bytes following the // prologue_length field to the beginning of the // first byte of the statement program itself. @@ -201,14 +209,15 @@ public: const lldb_private::DWARFDataExtractor &debug_line_data, const lldb_private::FileSpec &cu_comp_dir, dw_offset_t stmt_list, - lldb_private::FileSpecList &support_files); + lldb_private::FileSpecList &support_files, DWARFUnit *dwarf_cu); static bool ParsePrologue(const lldb_private::DWARFDataExtractor &debug_line_data, - lldb::offset_t *offset_ptr, Prologue *prologue); + lldb::offset_t *offset_ptr, Prologue *prologue, + DWARFUnit *dwarf_cu = nullptr); static bool ParseStatementTable(const lldb_private::DWARFDataExtractor &debug_line_data, lldb::offset_t *offset_ptr, State::Callback callback, - void *userData); + void *userData, DWARFUnit *dwarf_cu); static dw_offset_t DumpStatementTable(lldb_private::Log *log, const lldb_private::DWARFDataExtractor &debug_line_data, @@ -219,7 +228,8 @@ public: const dw_offset_t line_offset, uint32_t flags); static bool ParseStatementTable(const lldb_private::DWARFDataExtractor &debug_line_data, - lldb::offset_t *offset_ptr, LineTable *line_table); + lldb::offset_t *offset_ptr, LineTable *line_table, + DWARFUnit *dwarf_cu); static void Parse(const lldb_private::DWARFDataExtractor &debug_line_data, DWARFDebugLine::State::Callback callback, void *userData); // static void AppendLineTableData(const DWARFDebugLine::Prologue* prologue, diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp index 1c31d1c42598..d79acdc5cfc4 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp @@ -25,7 +25,7 @@ DWARFDebugMacroHeader::ParseHeader(const DWARFDataExtractor &debug_macro_data, header.m_version = debug_macro_data.GetU16(offset); uint8_t flags = debug_macro_data.GetU8(offset); - header.m_offset_is_64_bit = flags & OFFSET_SIZE_MASK ? true : false; + header.m_offset_is_64_bit = (flags & OFFSET_SIZE_MASK) != 0; if (flags & DEBUG_LINE_OFFSET_MASK) { if (header.m_offset_is_64_bit) diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp index 89e27efb3cc2..a0436dd7ffad 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "DWARFDebugRanges.h" +#include "DWARFUnit.h" #include "SymbolFileDWARF.h" #include "lldb/Utility/Stream.h" #include <assert.h> @@ -29,8 +30,6 @@ static dw_addr_t GetBaseAddressMarker(uint32_t addr_size) { DWARFDebugRanges::DWARFDebugRanges() : m_range_map() {} -DWARFDebugRanges::~DWARFDebugRanges() {} - void DWARFDebugRanges::Extract(SymbolFileDWARF *dwarf2Data) { DWARFRangeList range_list; lldb::offset_t offset = 0; @@ -112,14 +111,185 @@ void DWARFDebugRanges::Dump(Stream &s, } } -bool DWARFDebugRanges::FindRanges(dw_addr_t debug_ranges_base, +bool DWARFDebugRanges::FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, DWARFRangeList &range_list) const { - dw_addr_t debug_ranges_address = debug_ranges_base + debug_ranges_offset; + dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset; range_map_const_iterator pos = m_range_map.find(debug_ranges_address); if (pos != m_range_map.end()) { range_list = pos->second; + + // All DW_AT_ranges are relative to the base address of the compile + // unit. We add the compile unit base address to make sure all the + // addresses are properly fixed up. + range_list.Slide(cu->GetBaseAddress()); + return true; + } + return false; +} + +uint64_t DWARFDebugRanges::GetOffset(size_t Index) const { + lldbassert(false && "DW_FORM_rnglistx is not present before DWARF5"); + return 0; +} + +bool DWARFDebugRngLists::ExtractRangeList( + const DWARFDataExtractor &data, uint8_t addrSize, + lldb::offset_t *offset_ptr, std::vector<RngListEntry> &rangeList) { + rangeList.clear(); + + bool error = false; + while (!error) { + switch (data.GetU8(offset_ptr)) { + case DW_RLE_end_of_list: + return true; + + case DW_RLE_start_length: { + dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); + dw_addr_t len = data.GetULEB128(offset_ptr); + rangeList.push_back({DW_RLE_start_length, begin, len}); + break; + } + + case DW_RLE_start_end: { + dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); + dw_addr_t end = data.GetMaxU64(offset_ptr, addrSize); + rangeList.push_back({DW_RLE_start_end, begin, end}); + break; + } + + case DW_RLE_base_address: { + dw_addr_t base = data.GetMaxU64(offset_ptr, addrSize); + rangeList.push_back({DW_RLE_base_address, base, 0}); + break; + } + + case DW_RLE_offset_pair: { + dw_addr_t begin = data.GetULEB128(offset_ptr); + dw_addr_t end = data.GetULEB128(offset_ptr); + rangeList.push_back({DW_RLE_offset_pair, begin, end}); + break; + } + + case DW_RLE_base_addressx: { + dw_addr_t base = data.GetULEB128(offset_ptr); + rangeList.push_back({DW_RLE_base_addressx, base, 0}); + break; + } + + case DW_RLE_startx_endx: { + dw_addr_t start = data.GetULEB128(offset_ptr); + dw_addr_t end = data.GetULEB128(offset_ptr); + rangeList.push_back({DW_RLE_startx_endx, start, end}); + break; + } + + case DW_RLE_startx_length: { + dw_addr_t start = data.GetULEB128(offset_ptr); + dw_addr_t length = data.GetULEB128(offset_ptr); + rangeList.push_back({DW_RLE_startx_length, start, length}); + break; + } + + default: + lldbassert(0 && "unknown range list entry encoding"); + error = true; + } + } + + return false; +} + +static uint64_t ReadAddressFromDebugAddrSection(const DWARFUnit *cu, + uint32_t index) { + uint32_t index_size = cu->GetAddressByteSize(); + dw_offset_t addr_base = cu->GetAddrBase(); + lldb::offset_t offset = addr_base + index * index_size; + return cu->GetSymbolFileDWARF()->get_debug_addr_data().GetMaxU64(&offset, + index_size); +} + +bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu, + dw_offset_t debug_ranges_offset, + DWARFRangeList &range_list) const { + range_list.Clear(); + dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset; + auto pos = m_range_map.find(debug_ranges_address); + if (pos != m_range_map.end()) { + dw_addr_t BaseAddr = cu->GetBaseAddress(); + for (const RngListEntry &E : pos->second) { + switch (E.encoding) { + case DW_RLE_start_length: + range_list.Append(DWARFRangeList::Entry(E.value0, E.value1)); + break; + case DW_RLE_base_address: + BaseAddr = E.value0; + break; + case DW_RLE_start_end: + range_list.Append(DWARFRangeList::Entry(E.value0, E.value1 - E.value0)); + break; + case DW_RLE_offset_pair: + range_list.Append( + DWARFRangeList::Entry(BaseAddr + E.value0, E.value1 - E.value0)); + break; + case DW_RLE_base_addressx: { + BaseAddr = ReadAddressFromDebugAddrSection(cu, E.value0); + break; + } + case DW_RLE_startx_endx: { + dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); + dw_addr_t end = ReadAddressFromDebugAddrSection(cu, E.value1); + range_list.Append(DWARFRangeList::Entry(start, end - start)); + break; + } + case DW_RLE_startx_length: { + dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); + range_list.Append(DWARFRangeList::Entry(start, E.value1)); + break; + } + default: + llvm_unreachable("unexpected encoding"); + } + } return true; } return false; } + +void DWARFDebugRngLists::Extract(SymbolFileDWARF *dwarf2Data) { + const DWARFDataExtractor &data = dwarf2Data->get_debug_rnglists_data(); + lldb::offset_t offset = 0; + + uint64_t length = data.GetU32(&offset); + bool isDwarf64 = (length == 0xffffffff); + if (isDwarf64) + length = data.GetU64(&offset); + lldb::offset_t end = offset + length; + + // Check version. + if (data.GetU16(&offset) < 5) + return; + + uint8_t addrSize = data.GetU8(&offset); + + // We do not support non-zero segment selector size. + if (data.GetU8(&offset) != 0) { + lldbassert(0 && "not implemented"); + return; + } + + uint32_t offsetsAmount = data.GetU32(&offset); + for (uint32_t i = 0; i < offsetsAmount; ++i) + Offsets.push_back(data.GetMaxU64(&offset, isDwarf64 ? 8 : 4)); + + lldb::offset_t listOffset = offset; + std::vector<RngListEntry> rangeList; + while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) { + m_range_map[listOffset] = rangeList; + listOffset = offset; + } +} + +uint64_t DWARFDebugRngLists::GetOffset(size_t Index) const { + return Offsets[Index]; +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h index f514359e00a4..5790f448ba85 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h @@ -15,17 +15,28 @@ #include <map> -class DWARFDebugRanges { +class DWARFDebugRangesBase { +public: + virtual ~DWARFDebugRangesBase(){}; + + virtual void Extract(SymbolFileDWARF *dwarf2Data) = 0; + virtual bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, + DWARFRangeList &range_list) const = 0; + virtual uint64_t GetOffset(size_t Index) const = 0; +}; + +class DWARFDebugRanges final : public DWARFDebugRangesBase { public: DWARFDebugRanges(); - ~DWARFDebugRanges(); - void Extract(SymbolFileDWARF *dwarf2Data); + + void Extract(SymbolFileDWARF *dwarf2Data) override; + bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, + DWARFRangeList &range_list) const override; + uint64_t GetOffset(size_t Index) const override; + static void Dump(lldb_private::Stream &s, const lldb_private::DWARFDataExtractor &debug_ranges_data, lldb::offset_t *offset_ptr, dw_addr_t cu_base_addr); - bool FindRanges(dw_addr_t debug_ranges_base, - dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const; protected: bool Extract(SymbolFileDWARF *dwarf2Data, lldb::offset_t *offset_ptr, @@ -37,4 +48,27 @@ protected: range_map m_range_map; }; +// DWARF v5 .debug_rnglists section. +class DWARFDebugRngLists final : public DWARFDebugRangesBase { + struct RngListEntry { + uint8_t encoding; + uint64_t value0; + uint64_t value1; + }; + +public: + void Extract(SymbolFileDWARF *dwarf2Data) override; + bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, + DWARFRangeList &range_list) const override; + uint64_t GetOffset(size_t Index) const override; + +protected: + bool ExtractRangeList(const lldb_private::DWARFDataExtractor &data, + uint8_t addrSize, lldb::offset_t *offset_ptr, + std::vector<RngListEntry> &list); + + std::vector<uint64_t> Offsets; + std::map<dw_offset_t, std::vector<RngListEntry>> m_range_map; +}; + #endif // SymbolFileDWARF_DWARFDebugRanges_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h index 1f3c59768fdf..aff5ea64e9ce 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h @@ -10,13 +10,9 @@ #ifndef SymbolFileDWARF_DWARFDeclContext_h_ #define SymbolFileDWARF_DWARFDeclContext_h_ -// C Includes -// C++ Includes #include <string> #include <vector> -// Other libraries and framework includes #include "lldb/Utility/ConstString.h" -// Project includes #include "DWARFDefines.h" //---------------------------------------------------------------------- diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp index 1d927ba3bca3..99becdbb2bc1 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp @@ -504,9 +504,9 @@ const char *DW_MACINFO_value_to_name(uint32_t val) { return llvmstr.data(); } -const char *DW_CFA_value_to_name(uint32_t val) { +const char *DW_CFA_value_to_name(uint32_t val, llvm::Triple::ArchType Arch) { static char invalid[100]; - llvm::StringRef llvmstr = llvm::dwarf::CallFrameString(val); + llvm::StringRef llvmstr = llvm::dwarf::CallFrameString(val, Arch); if (llvmstr.empty()) { snprintf(invalid, sizeof(invalid), "Unknown DW_CFA constant: 0x%x", val); return invalid; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h index 926f83b3564a..0f5a885efb86 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDefines.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h @@ -64,7 +64,7 @@ const char *DW_LNE_value_to_name(uint32_t val); const char *DW_MACINFO_value_to_name(uint32_t val); -const char *DW_CFA_value_to_name(uint32_t val); +const char *DW_CFA_value_to_name(uint32_t val, llvm::Triple::ArchType Arch); const char *DW_GNU_EH_PE_value_to_name(uint32_t val); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index 4fde5748d3f3..5d2a8ffdb85b 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -154,6 +154,9 @@ DWARFFormValue::GetFixedFormSizesForAddressSize(uint8_t addr_size, DWARFFormValue::DWARFFormValue() : m_cu(NULL), m_form(0), m_value() {} +DWARFFormValue::DWARFFormValue(const DWARFUnit *cu) + : m_cu(cu), m_form(0), m_value() {} + DWARFFormValue::DWARFFormValue(const DWARFUnit *cu, dw_form_t form) : m_cu(cu), m_form(form), m_value() {} @@ -165,6 +168,9 @@ void DWARFFormValue::Clear() { bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, lldb::offset_t *offset_ptr) { + if (m_form == DW_FORM_implicit_const) + return true; + bool indirect = false; bool is_block = false; m_value.data = NULL; @@ -176,8 +182,12 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, switch (m_form) { case DW_FORM_addr: assert(m_cu); - m_value.value.uval = data.GetMaxU64( - offset_ptr, DWARFUnit::GetAddressByteSize(m_cu)); + m_value.value.uval = + data.GetMaxU64(offset_ptr, DWARFUnit::GetAddressByteSize(m_cu)); + break; + case DW_FORM_block1: + m_value.value.uval = data.GetU8(offset_ptr); + is_block = true; break; case DW_FORM_block2: m_value.value.uval = data.GetU16(offset_ptr); @@ -187,94 +197,82 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, m_value.value.uval = data.GetU32(offset_ptr); is_block = true; break; - case DW_FORM_data2: - m_value.value.uval = data.GetU16(offset_ptr); - break; - case DW_FORM_data4: - m_value.value.uval = data.GetU32(offset_ptr); - break; - case DW_FORM_data8: - m_value.value.uval = data.GetU64(offset_ptr); - break; - case DW_FORM_string: - m_value.value.cstr = data.GetCStr(offset_ptr); + case DW_FORM_data16: + m_value.value.uval = 16; + is_block = true; break; case DW_FORM_exprloc: case DW_FORM_block: m_value.value.uval = data.GetULEB128(offset_ptr); is_block = true; break; - case DW_FORM_block1: - m_value.value.uval = data.GetU8(offset_ptr); - is_block = true; - break; - case DW_FORM_data1: - m_value.value.uval = data.GetU8(offset_ptr); - break; - case DW_FORM_flag: - m_value.value.uval = data.GetU8(offset_ptr); + case DW_FORM_string: + m_value.value.cstr = data.GetCStr(offset_ptr); break; case DW_FORM_sdata: m_value.value.sval = data.GetSLEB128(offset_ptr); break; case DW_FORM_strp: + case DW_FORM_line_strp: + case DW_FORM_sec_offset: assert(m_cu); m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFUnit::IsDWARF64(m_cu) ? 8 : 4); break; - // case DW_FORM_APPLE_db_str: - case DW_FORM_udata: - m_value.value.uval = data.GetULEB128(offset_ptr); - break; - case DW_FORM_ref_addr: - assert(m_cu); - ref_addr_size = 4; - if (m_cu->GetVersion() <= 2) - ref_addr_size = m_cu->GetAddressByteSize(); - else - ref_addr_size = m_cu->IsDWARF64() ? 8 : 4; - m_value.value.uval = data.GetMaxU64(offset_ptr, ref_addr_size); - break; + case DW_FORM_addrx1: + case DW_FORM_strx1: case DW_FORM_ref1: + case DW_FORM_data1: + case DW_FORM_flag: m_value.value.uval = data.GetU8(offset_ptr); break; + case DW_FORM_addrx2: + case DW_FORM_strx2: case DW_FORM_ref2: + case DW_FORM_data2: m_value.value.uval = data.GetU16(offset_ptr); break; + case DW_FORM_addrx3: + case DW_FORM_strx3: + m_value.value.uval = data.GetMaxU64(offset_ptr, 3); + break; + case DW_FORM_addrx4: + case DW_FORM_strx4: case DW_FORM_ref4: + case DW_FORM_data4: m_value.value.uval = data.GetU32(offset_ptr); break; + case DW_FORM_data8: case DW_FORM_ref8: + case DW_FORM_ref_sig8: m_value.value.uval = data.GetU64(offset_ptr); break; + case DW_FORM_addrx: + case DW_FORM_rnglistx: + case DW_FORM_strx: + case DW_FORM_udata: case DW_FORM_ref_udata: + case DW_FORM_GNU_str_index: + case DW_FORM_GNU_addr_index: m_value.value.uval = data.GetULEB128(offset_ptr); break; + case DW_FORM_ref_addr: + assert(m_cu); + if (m_cu->GetVersion() <= 2) + ref_addr_size = m_cu->GetAddressByteSize(); + else + ref_addr_size = m_cu->IsDWARF64() ? 8 : 4; + m_value.value.uval = data.GetMaxU64(offset_ptr, ref_addr_size); + break; case DW_FORM_indirect: m_form = data.GetULEB128(offset_ptr); indirect = true; break; - - case DW_FORM_sec_offset: - assert(m_cu); - m_value.value.uval = - data.GetMaxU64(offset_ptr, DWARFUnit::IsDWARF64(m_cu) ? 8 : 4); - break; case DW_FORM_flag_present: m_value.value.uval = 1; break; - case DW_FORM_ref_sig8: - m_value.value.uval = data.GetU64(offset_ptr); - break; - case DW_FORM_GNU_str_index: - m_value.value.uval = data.GetULEB128(offset_ptr); - break; - case DW_FORM_GNU_addr_index: - m_value.value.uval = data.GetULEB128(offset_ptr); - break; default: return false; - break; } } while (indirect); @@ -346,49 +344,65 @@ bool DWARFFormValue::SkipValue(dw_form_t form, // 0 bytes values (implied from DW_FORM) case DW_FORM_flag_present: + case DW_FORM_implicit_const: return true; - // 1 byte values - case DW_FORM_data1: - case DW_FORM_flag: - case DW_FORM_ref1: - *offset_ptr += 1; - return true; + // 1 byte values + case DW_FORM_addrx1: + case DW_FORM_data1: + case DW_FORM_flag: + case DW_FORM_ref1: + case DW_FORM_strx1: + *offset_ptr += 1; + return true; - // 2 byte values - case DW_FORM_data2: - case DW_FORM_ref2: - *offset_ptr += 2; - return true; + // 2 byte values + case DW_FORM_addrx2: + case DW_FORM_data2: + case DW_FORM_ref2: + case DW_FORM_strx2: + *offset_ptr += 2; + return true; - // 32 bit for DWARF 32, 64 for DWARF 64 - case DW_FORM_sec_offset: - case DW_FORM_strp: - assert(cu); - *offset_ptr += (cu->IsDWARF64() ? 8 : 4); - return true; + // 3 byte values + case DW_FORM_addrx3: + case DW_FORM_strx3: + *offset_ptr += 3; + return true; - // 4 byte values - case DW_FORM_data4: - case DW_FORM_ref4: - *offset_ptr += 4; - return true; + // 32 bit for DWARF 32, 64 for DWARF 64 + case DW_FORM_sec_offset: + case DW_FORM_strp: + assert(cu); + *offset_ptr += (cu->IsDWARF64() ? 8 : 4); + return true; - // 8 byte values - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_ref_sig8: - *offset_ptr += 8; - return true; + // 4 byte values + case DW_FORM_addrx4: + case DW_FORM_data4: + case DW_FORM_ref4: + case DW_FORM_strx4: + *offset_ptr += 4; + return true; - // signed or unsigned LEB 128 values - case DW_FORM_sdata: - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_GNU_addr_index: - case DW_FORM_GNU_str_index: - debug_info_data.Skip_LEB128(offset_ptr); - return true; + // 8 byte values + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + *offset_ptr += 8; + return true; + + // signed or unsigned LEB 128 values + case DW_FORM_addrx: + case DW_FORM_rnglistx: + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_GNU_addr_index: + case DW_FORM_GNU_str_index: + case DW_FORM_strx: + debug_info_data.Skip_LEB128(offset_ptr); + return true; case DW_FORM_indirect: { dw_form_t indirect_form = debug_info_data.GetULEB128(offset_ptr); @@ -546,6 +560,26 @@ const char *DWARFFormValue::AsCString() const { index_size); return symbol_file->get_debug_str_data().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. + if (!symbol_file) + return nullptr; + + uint32_t indexSize = m_cu->IsDWARF64() ? 8 : 4; + lldb::offset_t offset = + m_cu->GetStrOffsetsBase() + m_value.value.uval * indexSize; + dw_offset_t strOffset = + symbol_file->get_debug_str_offsets_data().GetMaxU64(&offset, indexSize); + return symbol_file->get_debug_str_data().PeekCStr(strOffset); + } + + if (m_form == DW_FORM_line_strp) + return symbol_file->get_debug_line_str_data().PeekCStr(m_value.value.uval); + return nullptr; } @@ -556,7 +590,9 @@ dw_addr_t DWARFFormValue::Address() const { return Unsigned(); assert(m_cu); - assert(m_form == DW_FORM_GNU_addr_index); + assert(m_form == DW_FORM_GNU_addr_index || m_form == DW_FORM_addrx || + m_form == DW_FORM_addrx1 || m_form == DW_FORM_addrx2 || + m_form == DW_FORM_addrx3 || m_form == DW_FORM_addrx4); if (!symbol_file) return 0; @@ -568,7 +604,7 @@ dw_addr_t DWARFFormValue::Address() const { } uint64_t DWARFFormValue::Reference() const { - uint64_t die_offset = m_value.value.uval; + uint64_t value = m_value.value.uval; switch (m_form) { case DW_FORM_ref1: case DW_FORM_ref2: @@ -577,32 +613,36 @@ uint64_t DWARFFormValue::Reference() const { case DW_FORM_ref_udata: assert(m_cu); // CU must be valid for DW_FORM_ref forms that are compile // unit relative or we will get this wrong - die_offset += m_cu->GetOffset(); - break; + return value + m_cu->GetOffset(); + + case DW_FORM_ref_addr: + case DW_FORM_ref_sig8: + case DW_FORM_GNU_ref_alt: + return value; default: - break; + return DW_INVALID_OFFSET; } - - return die_offset; } uint64_t DWARFFormValue::Reference(dw_offset_t base_offset) const { - uint64_t die_offset = m_value.value.uval; + uint64_t value = m_value.value.uval; switch (m_form) { case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: - die_offset += base_offset; - break; + return value + base_offset; + + case DW_FORM_ref_addr: + case DW_FORM_ref_sig8: + case DW_FORM_GNU_ref_alt: + return value; default: - break; + return DW_INVALID_OFFSET; } - - return die_offset; } const uint8_t *DWARFFormValue::BlockData() const { return m_value.data; } @@ -729,6 +769,8 @@ int DWARFFormValue::Compare(const DWARFFormValue &a_value, bool DWARFFormValue::FormIsSupported(dw_form_t form) { switch (form) { case DW_FORM_addr: + case DW_FORM_addrx: + case DW_FORM_rnglistx: case DW_FORM_block2: case DW_FORM_block4: case DW_FORM_data2: @@ -741,6 +783,11 @@ bool DWARFFormValue::FormIsSupported(dw_form_t form) { case DW_FORM_flag: case DW_FORM_sdata: case DW_FORM_strp: + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: case DW_FORM_udata: case DW_FORM_ref_addr: case DW_FORM_ref1: @@ -755,6 +802,7 @@ bool DWARFFormValue::FormIsSupported(dw_form_t form) { case DW_FORM_ref_sig8: case DW_FORM_GNU_str_index: case DW_FORM_GNU_addr_index: + case DW_FORM_implicit_const: return true; default: break; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index ef1a693b37c9..0890f0c1bfc5 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -11,9 +11,10 @@ #define SymbolFileDWARF_DWARFFormValue_h_ #include "DWARFDataExtractor.h" -#include <stddef.h> // for NULL +#include <stddef.h> class DWARFUnit; +class SymbolFileDWARF; class DWARFFormValue { public: @@ -55,12 +56,17 @@ public: }; DWARFFormValue(); + DWARFFormValue(const DWARFUnit *cu); DWARFFormValue(const DWARFUnit *cu, dw_form_t form); const DWARFUnit *GetCompileUnit() const { return m_cu; } void SetCompileUnit(const DWARFUnit *cu) { m_cu = cu; } dw_form_t Form() const { return m_form; } + dw_form_t& FormRef() { return m_form; } void SetForm(dw_form_t form) { m_form = form; } const ValueType &Value() const { return m_value; } + ValueType &ValueRef() { return m_value; } + void SetValue(const ValueType &val) { m_value = val; } + void Dump(lldb_private::Stream &s) const; bool ExtractValue(const lldb_private::DWARFDataExtractor &data, lldb::offset_t *offset_ptr); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index f44b2bb97b2b..7afc71bc24f0 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -191,13 +191,6 @@ void DWARFUnit::ExtractDIEsRWLocked() { IsDWARF64()); while (offset < next_cu_offset && die.FastExtract(data, this, fixed_form_sizes, &offset)) { - // if (log) - // log->Printf("0x%8.8x: %*.*s%s%s", - // die.GetOffset(), - // depth * 2, depth * 2, "", - // DW_TAG_value_to_name (die.Tag()), - // die.HasChildren() ? " *" : ""); - const bool null_die = die.IsNULL(); if (depth == 0) { assert(m_die_array.empty() && "Compile unit DIE already added"); @@ -223,7 +216,7 @@ void DWARFUnit::ExtractDIEsRWLocked() { // the list (saves up to 25% in C++ code), we need a way to let the // DIE know that it actually doesn't have children. if (!m_die_array.empty()) - m_die_array.back().SetEmptyChildren(true); + m_die_array.back().SetHasChildren(false); } } else { die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]); @@ -244,9 +237,6 @@ void DWARFUnit::ExtractDIEsRWLocked() { if (depth > 0) --depth; - if (depth == 0) - break; // We are done with this compile unit! - prev_die_had_children = false; } else { die_index_stack.back() = m_die_array.size() - 1; @@ -258,10 +248,17 @@ void DWARFUnit::ExtractDIEsRWLocked() { } prev_die_had_children = die_has_children; } + + if (depth == 0) + break; // We are done with this compile unit! } if (!m_die_array.empty()) { - lldbassert(!m_first_die || m_first_die == m_die_array.front()); + if (m_first_die) { + // Only needed for the assertion. + m_first_die.SetHasChildren(m_die_array.front().HasChildren()); + lldbassert(m_first_die == m_die_array.front()); + } m_first_die = m_die_array.front(); } @@ -301,8 +298,46 @@ void DWARFUnit::ExtractDIEsEndCheck(lldb::offset_t offset) const { } } +// This is used when a split dwarf is enabled. +// A skeleton compilation unit may contain the DW_AT_str_offsets_base attribute +// that points to the first string offset of the CU contribution to the +// .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) { + lldb::offset_t baseOffset = 0; + + const DWARFDataExtractor &strOffsets = + dwo_cu->GetSymbolFileDWARF()->get_debug_str_offsets_data(); + uint64_t length = strOffsets.GetU32(&baseOffset); + if (length == 0xffffffff) + length = strOffsets.GetU64(&baseOffset); + + // Check version. + if (strOffsets.GetU16(&baseOffset) < 5) + return; + + // Skip padding. + baseOffset += 2; + + dwo_cu->SetStrOffsetsBase(baseOffset); +} + // m_die_array_mutex must be already held as read/write. void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { + dw_addr_t addr_base = cu_die.GetAttributeValueAsUnsigned( + m_dwarf, this, DW_AT_addr_base, LLDB_INVALID_ADDRESS); + if (addr_base != LLDB_INVALID_ADDRESS) + SetAddrBase(addr_base); + + dw_addr_t ranges_base = cu_die.GetAttributeValueAsUnsigned( + m_dwarf, this, DW_AT_rnglists_base, LLDB_INVALID_ADDRESS); + if (ranges_base != LLDB_INVALID_ADDRESS) + SetRangesBase(ranges_base); + + SetStrOffsetsBase(cu_die.GetAttributeValueAsUnsigned( + m_dwarf, this, DW_AT_str_offsets_base, 0)); + uint64_t base_addr = cu_die.GetAttributeValueAsAddress( m_dwarf, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); if (base_addr == LLDB_INVALID_ADDRESS) @@ -333,11 +368,25 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { m_dwo_symbol_file = std::move(dwo_symbol_file); - dw_addr_t addr_base = - cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_GNU_addr_base, 0); - dw_addr_t ranges_base = cu_die.GetAttributeValueAsUnsigned( - m_dwarf, this, DW_AT_GNU_ranges_base, 0); - dwo_cu->SetAddrBase(addr_base, ranges_base, m_offset); + // 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_* + // attributes which were applicable to the DWO units. The corresponding + // DW_AT_* attributes standardized in DWARF v5 are also applicable to the main + // unit in contrast. + if (addr_base == LLDB_INVALID_ADDRESS) + addr_base = cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, + DW_AT_GNU_addr_base, 0); + dwo_cu->SetAddrBase(addr_base); + + if (ranges_base == LLDB_INVALID_ADDRESS) + ranges_base = cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, + DW_AT_GNU_ranges_base, 0); + dwo_cu->SetRangesBase(ranges_base); + + dwo_cu->SetBaseObjOffset(m_offset); + + SetDwoStrOffsetsBase(dwo_cu); } DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) { @@ -395,14 +444,20 @@ dw_offset_t DWARFUnit::GetAbbrevOffset() const { return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET; } -void DWARFUnit::SetAddrBase(dw_addr_t addr_base, - dw_addr_t ranges_base, - dw_offset_t base_obj_offset) { - m_addr_base = addr_base; +void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; } + +void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) { m_ranges_base = ranges_base; +} + +void DWARFUnit::SetBaseObjOffset(dw_offset_t base_obj_offset) { m_base_obj_offset = base_obj_offset; } +void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) { + m_str_offsets_base = str_offsets_base; +} + // It may be called only with m_die_array_mutex held R/W. void DWARFUnit::ClearDIEsRWLocked() { m_die_array.clear(); @@ -586,9 +641,7 @@ void DWARFUnit::SetUserData(void *d) { } bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() { - if (GetProducer() == eProducerLLVMGCC) - return false; - return true; + return GetProducer() != eProducerLLVMGCC; } bool DWARFUnit::DW_AT_decl_file_attributes_are_invalid() { @@ -600,11 +653,8 @@ bool DWARFUnit::DW_AT_decl_file_attributes_are_invalid() { bool DWARFUnit::Supports_unnamed_objc_bitfields() { if (GetProducer() == eProducerClang) { const uint32_t major_version = GetProducerVersionMajor(); - if (major_version > 425 || - (major_version == 425 && GetProducerVersionUpdate() >= 13)) - return true; - else - return false; + return major_version > 425 || + (major_version == 425 && GetProducerVersionUpdate() >= 13); } return true; // Assume all other compilers didn't have incorrect ObjC bitfield // info diff --git a/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 3cc24d4202b8..178c894686ee 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -111,8 +111,11 @@ public: dw_addr_t GetBaseAddress() const { return m_base_addr; } dw_addr_t GetAddrBase() const { return m_addr_base; } dw_addr_t GetRangesBase() const { return m_ranges_base; } - void SetAddrBase(dw_addr_t addr_base, dw_addr_t ranges_base, - dw_offset_t base_obj_offset); + dw_addr_t GetStrOffsetsBase() const { return m_str_offsets_base; } + void SetAddrBase(dw_addr_t addr_base); + void SetRangesBase(dw_addr_t ranges_base); + void SetBaseObjOffset(dw_offset_t base_obj_offset); + void SetStrOffsetsBase(dw_offset_t str_offsets_base); void BuildAddressRangeTable(SymbolFileDWARF *dwarf, DWARFDebugAranges *debug_aranges); @@ -202,6 +205,8 @@ protected: dw_offset_t m_length = 0; uint16_t m_version = 0; uint8_t m_addr_size = 0; + uint8_t m_unit_type = 0; + uint64_t m_dwo_id = 0; DWARFProducer m_producer = eProducerInvalid; uint32_t m_producer_version_major = 0; uint32_t m_producer_version_minor = 0; @@ -214,7 +219,7 @@ protected: // If this is a dwo compile unit this is the offset of the base compile unit // in the main object file dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET; - + dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base. // Offset of the initial length field. dw_offset_t m_offset; diff --git a/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index 614ff470d161..c043272f8a3e 100644 --- a/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -225,7 +225,8 @@ void DebugNamesDWARFIndex::GetFunctions( const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, std::vector<DWARFDIE> &dies) { - m_fallback.GetFunctions(name, info, parent_decl_ctx, name_type_mask, dies); + std::vector<DWARFDIE> v; + m_fallback.GetFunctions(name, info, parent_decl_ctx, name_type_mask, v); for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name.GetStringRef())) { @@ -235,8 +236,13 @@ void DebugNamesDWARFIndex::GetFunctions( if (DIERef ref = ToDIERef(entry)) ProcessFunctionDIE(name.GetStringRef(), ref, info, parent_decl_ctx, - name_type_mask, dies); + name_type_mask, v); } + + std::set<DWARFDebugInfoEntry *> seen; + for (DWARFDIE die : v) + if (seen.insert(die.GetDIE()).second) + dies.push_back(die); } void DebugNamesDWARFIndex::GetFunctions(const RegularExpression ®ex, diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp index 36211a08557e..f83ba6663dfc 100644 --- a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp +++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp @@ -279,7 +279,9 @@ bool DWARFMappedHash::Header::Read(const lldb_private::DWARFDataExtractor &data, switch (header_data.atoms[i].type) { case eAtomTypeDIEOffset: // DIE offset, check form for encoding hash_data.offset = - (dw_offset_t)form_value.Reference(header_data.die_base_offset); + DWARFFormValue::IsDataForm(form_value.Form()) + ? form_value.Unsigned() + : form_value.Reference(header_data.die_base_offset); break; case eAtomTypeTag: // DW_TAG value for the DIE diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h index 0293fbd7c495..038e9b8c2b08 100644 --- a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h +++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h @@ -10,10 +10,6 @@ #ifndef SymbolFileDWARF_LogChannelDWARF_h_ #define SymbolFileDWARF_LogChannelDWARF_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Utility/Log.h" #define DWARF_LOG_DEBUG_INFO (1u << 1) diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index ac320ac52b08..2a0a89f0b25a 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -9,7 +9,6 @@ #include "SymbolFileDWARF.h" -// Other libraries and framework includes #include "llvm/Support/Casting.h" #include "llvm/Support/Threading.h" @@ -17,12 +16,12 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/Value.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" @@ -111,17 +110,14 @@ using namespace lldb_private; namespace { -PropertyDefinition g_properties[] = { +static constexpr PropertyDefinition g_properties[] = { {"comp-dir-symlink-paths", OptionValue::eTypeFileSpecList, true, 0, nullptr, - nullptr, + {}, "If the DW_AT_comp_dir matches any of these paths the symbolic " "links will be resolved at DWARF parse time."}, - {"ignore-file-indexes", OptionValue::eTypeBoolean, true, 0, nullptr, - nullptr, + {"ignore-file-indexes", OptionValue::eTypeBoolean, true, 0, nullptr, {}, "Ignore indexes present in the object files and always index DWARF " - "manually."}, - {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}, -}; + "manually."}}; enum { ePropertySymLinkPaths, @@ -200,7 +196,7 @@ static FileSpec resolveCompDir(const char *path_from_dwarf) { bool is_symlink = false; // Always normalize our compile unit directory to get rid of redundant // slashes and other path anomalies before we use it for path prepending - FileSpec local_spec(local_path, false); + FileSpec local_spec(local_path); const auto &file_specs = GetGlobalPluginProperties()->GetSymLinkPaths(); for (size_t i = 0; i < file_specs.GetSize() && !is_symlink; ++i) is_symlink = FileSpec::Equal(file_specs.GetFileSpecAtIndex(i), @@ -215,7 +211,7 @@ static FileSpec resolveCompDir(const char *path_from_dwarf) { return local_spec; FileSpec resolved_symlink; - const auto error = FileSystem::Readlink(local_spec, resolved_symlink); + const auto error = FileSystem::Instance().Readlink(local_spec, resolved_symlink); if (error.Success()) return resolved_symlink; @@ -263,6 +259,9 @@ SymbolFile *SymbolFileDWARF::CreateInstance(ObjectFile *obj_file) { } TypeList *SymbolFileDWARF::GetTypeList() { + // This method can be called without going through the symbol vendor so we + // need to lock the module. + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); if (debug_map_symfile) return debug_map_symfile->GetTypeList(); @@ -341,9 +340,10 @@ void SymbolFileDWARF::GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset, } size_t SymbolFileDWARF::GetTypes(SymbolContextScope *sc_scope, - uint32_t type_mask, TypeList &type_list) + TypeClass type_mask, TypeList &type_list) { + ASSERT_MODULE_LOCK(this); TypeSet type_set; CompileUnit *comp_unit = NULL; @@ -413,9 +413,9 @@ SymbolFileDWARF::SymbolFileDWARF(ObjectFile *objfile) m_debug_map_module_wp(), m_debug_map_symfile(NULL), m_data_debug_abbrev(), m_data_debug_aranges(), m_data_debug_frame(), m_data_debug_info(), m_data_debug_line(), m_data_debug_macro(), m_data_debug_loc(), - m_data_debug_ranges(), m_data_debug_str(), m_data_apple_names(), - m_data_apple_types(), m_data_apple_namespaces(), m_abbr(), m_info(), - m_line(), m_fetched_external_modules(false), + m_data_debug_ranges(), m_data_debug_rnglists(), m_data_debug_str(), + m_data_apple_names(), m_data_apple_types(), m_data_apple_namespaces(), + m_abbr(), m_info(), m_line(), m_fetched_external_modules(false), m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate), m_ranges(), m_unique_ast_type_map() {} @@ -494,7 +494,7 @@ void SymbolFileDWARF::InitializeObject() { } bool SymbolFileDWARF::SupportedVersion(uint16_t version) { - return version == 2 || version == 3 || version == 4; + return version >= 2 && version <= 5; } uint32_t SymbolFileDWARF::CalculateAbilities() { @@ -645,19 +645,40 @@ const DWARFDataExtractor &SymbolFileDWARF::get_debug_line_data() { return GetCachedSectionData(eSectionTypeDWARFDebugLine, m_data_debug_line); } +const DWARFDataExtractor &SymbolFileDWARF::get_debug_line_str_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugLineStr, m_data_debug_line_str); +} + const DWARFDataExtractor &SymbolFileDWARF::get_debug_macro_data() { return GetCachedSectionData(eSectionTypeDWARFDebugMacro, m_data_debug_macro); } +const DWARFDataExtractor &SymbolFileDWARF::DebugLocData() { + const DWARFDataExtractor &debugLocData = get_debug_loc_data(); + if (debugLocData.GetByteSize() > 0) + return debugLocData; + return get_debug_loclists_data(); +} + const DWARFDataExtractor &SymbolFileDWARF::get_debug_loc_data() { return GetCachedSectionData(eSectionTypeDWARFDebugLoc, m_data_debug_loc); } +const DWARFDataExtractor &SymbolFileDWARF::get_debug_loclists_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugLocLists, + m_data_debug_loclists); +} + const DWARFDataExtractor &SymbolFileDWARF::get_debug_ranges_data() { return GetCachedSectionData(eSectionTypeDWARFDebugRanges, m_data_debug_ranges); } +const DWARFDataExtractor &SymbolFileDWARF::get_debug_rnglists_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugRngLists, + m_data_debug_rnglists); +} + const DWARFDataExtractor &SymbolFileDWARF::get_debug_str_data() { return GetCachedSectionData(eSectionTypeDWARFDebugStr, m_data_debug_str); } @@ -747,21 +768,24 @@ SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { return NULL; } -DWARFDebugRanges *SymbolFileDWARF::DebugRanges() { +DWARFDebugRangesBase *SymbolFileDWARF::DebugRanges() { if (m_ranges.get() == NULL) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, static_cast<void *>(this)); - if (get_debug_ranges_data().GetByteSize() > 0) { + + if (get_debug_ranges_data().GetByteSize() > 0) m_ranges.reset(new DWARFDebugRanges()); - if (m_ranges.get()) - m_ranges->Extract(this); - } + else if (get_debug_rnglists_data().GetByteSize() > 0) + m_ranges.reset(new DWARFDebugRngLists()); + + if (m_ranges.get()) + m_ranges->Extract(this); } return m_ranges.get(); } -const DWARFDebugRanges *SymbolFileDWARF::DebugRanges() const { +const DWARFDebugRangesBase *SymbolFileDWARF::DebugRanges() const { return m_ranges.get(); } @@ -786,7 +810,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFUnit *dwarf_cu, if (module_sp) { const DWARFDIE cu_die = dwarf_cu->DIE(); if (cu_die) { - FileSpec cu_file_spec{cu_die.GetName(), false}; + FileSpec cu_file_spec(cu_die.GetName()); 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 @@ -801,8 +825,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFUnit *dwarf_cu, std::string remapped_file; if (module_sp->RemapSourceFile(cu_file_spec.GetPath(), remapped_file)) - cu_file_spec.SetFile(remapped_file, false, - FileSpec::Style::native); + cu_file_spec.SetFile(remapped_file, FileSpec::Style::native); } LanguageType cu_language = DWARFUnit::LanguageTypeFromDWARF( @@ -851,6 +874,7 @@ uint32_t SymbolFileDWARF::GetNumCompileUnits() { } CompUnitSP SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) { + ASSERT_MODULE_LOCK(this); CompUnitSP cu_sp; DWARFDebugInfo *info = DebugInfo(); if (info) { @@ -861,8 +885,9 @@ CompUnitSP SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) { return cu_sp; } -Function *SymbolFileDWARF::ParseCompileUnitFunction(const SymbolContext &sc, - const DWARFDIE &die) { +Function *SymbolFileDWARF::ParseFunction(CompileUnit &comp_unit, + const DWARFDIE &die) { + ASSERT_MODULE_LOCK(this); if (die.IsValid()) { TypeSystem *type_system = GetTypeSystemForLanguage(die.GetCU()->GetLanguageType()); @@ -870,7 +895,7 @@ Function *SymbolFileDWARF::ParseCompileUnitFunction(const SymbolContext &sc, if (type_system) { DWARFASTParser *dwarf_ast = type_system->GetDWARFParser(); if (dwarf_ast) - return dwarf_ast->ParseFunctionFromDWARF(sc, die); + return dwarf_ast->ParseFunctionFromDWARF(comp_unit, die); } } return nullptr; @@ -884,20 +909,19 @@ bool SymbolFileDWARF::FixupAddress(Address &addr) { // This is a normal DWARF file, no address fixups need to happen return true; } -lldb::LanguageType -SymbolFileDWARF::ParseCompileUnitLanguage(const SymbolContext &sc) { - assert(sc.comp_unit); - DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); +lldb::LanguageType SymbolFileDWARF::ParseLanguage(CompileUnit &comp_unit) { + ASSERT_MODULE_LOCK(this); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (dwarf_cu) return dwarf_cu->GetLanguageType(); else return eLanguageTypeUnknown; } -size_t SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) { - assert(sc.comp_unit); +size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) { + ASSERT_MODULE_LOCK(this); size_t functions_added = 0; - DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (dwarf_cu) { DWARFDIECollection function_dies; const size_t num_functions = @@ -905,8 +929,8 @@ size_t SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) { size_t func_idx; for (func_idx = 0; func_idx < num_functions; ++func_idx) { DWARFDIE die = function_dies.GetDIEAtIndex(func_idx); - if (sc.comp_unit->FindFunctionByUID(die.GetID()).get() == NULL) { - if (ParseCompileUnitFunction(sc, die)) + if (comp_unit.FindFunctionByUID(die.GetID()).get() == NULL) { + if (ParseFunction(comp_unit, die)) ++functions_added; } } @@ -915,10 +939,10 @@ size_t SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) { return functions_added; } -bool SymbolFileDWARF::ParseCompileUnitSupportFiles( - const SymbolContext &sc, FileSpecList &support_files) { - assert(sc.comp_unit); - DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); +bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit, + FileSpecList &support_files) { + ASSERT_MODULE_LOCK(this); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (dwarf_cu) { const DWARFBaseDIE cu_die = dwarf_cu->GetUnitDIEOnly(); @@ -930,19 +954,19 @@ bool SymbolFileDWARF::ParseCompileUnitSupportFiles( if (stmt_list != DW_INVALID_OFFSET) { // All file indexes in DWARF are one based and a file of index zero is // supposed to be the compile unit itself. - support_files.Append(*sc.comp_unit); + support_files.Append(comp_unit); return DWARFDebugLine::ParseSupportFiles( - sc.comp_unit->GetModule(), get_debug_line_data(), cu_comp_dir, - stmt_list, support_files); + comp_unit.GetModule(), get_debug_line_data(), cu_comp_dir, + stmt_list, support_files, dwarf_cu); } } } return false; } -bool SymbolFileDWARF::ParseCompileUnitIsOptimized( - const lldb_private::SymbolContext &sc) { - DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); +bool SymbolFileDWARF::ParseIsOptimized(CompileUnit &comp_unit) { + ASSERT_MODULE_LOCK(this); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (dwarf_cu) return dwarf_cu->GetIsOptimized(); return false; @@ -951,6 +975,7 @@ bool SymbolFileDWARF::ParseCompileUnitIsOptimized( bool SymbolFileDWARF::ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules) { + ASSERT_MODULE_LOCK(this); assert(sc.comp_unit); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { @@ -1027,12 +1052,12 @@ static void ParseDWARFLineTableCallback(dw_offset_t offset, } } -bool SymbolFileDWARF::ParseCompileUnitLineTable(const SymbolContext &sc) { - assert(sc.comp_unit); - if (sc.comp_unit->GetLineTable() != NULL) +bool SymbolFileDWARF::ParseLineTable(CompileUnit &comp_unit) { + ASSERT_MODULE_LOCK(this); + if (comp_unit.GetLineTable() != NULL) return true; - DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (dwarf_cu) { const DWARFBaseDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly(); if (dwarf_cu_die) { @@ -1040,7 +1065,7 @@ bool SymbolFileDWARF::ParseCompileUnitLineTable(const SymbolContext &sc) { dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_stmt_list, DW_INVALID_OFFSET); if (cu_line_offset != DW_INVALID_OFFSET) { - std::unique_ptr<LineTable> line_table_ap(new LineTable(sc.comp_unit)); + std::unique_ptr<LineTable> line_table_ap(new LineTable(&comp_unit)); if (line_table_ap.get()) { ParseDWARFLineTableCallbackInfo info; info.line_table = line_table_ap.get(); @@ -1053,9 +1078,7 @@ bool SymbolFileDWARF::ParseCompileUnitLineTable(const SymbolContext &sc) { * #0 * for MIPS. Use ArchSpec to clear the bit #0. */ - ArchSpec arch; - GetObjectFile()->GetArchitecture(arch); - switch (arch.GetMachine()) { + switch (GetObjectFile()->GetArchitecture().GetMachine()) { case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -1070,17 +1093,17 @@ bool SymbolFileDWARF::ParseCompileUnitLineTable(const SymbolContext &sc) { lldb::offset_t offset = cu_line_offset; DWARFDebugLine::ParseStatementTable(get_debug_line_data(), &offset, ParseDWARFLineTableCallback, - &info); + &info, dwarf_cu); SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); if (debug_map_symfile) { // 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 are relative to the .o file into addresses for // the main executable. - sc.comp_unit->SetLineTable( + comp_unit.SetLineTable( debug_map_symfile->LinkOSOLineTable(this, line_table_ap.get())); } else { - sc.comp_unit->SetLineTable(line_table_ap.release()); + comp_unit.SetLineTable(line_table_ap.release()); return true; } } @@ -1112,10 +1135,10 @@ SymbolFileDWARF::ParseDebugMacros(lldb::offset_t *offset) { return debug_macros_sp; } -bool SymbolFileDWARF::ParseCompileUnitDebugMacros(const SymbolContext &sc) { - assert(sc.comp_unit); +bool SymbolFileDWARF::ParseDebugMacros(CompileUnit &comp_unit) { + ASSERT_MODULE_LOCK(this); - DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (dwarf_cu == nullptr) return false; @@ -1131,16 +1154,14 @@ bool SymbolFileDWARF::ParseCompileUnitDebugMacros(const SymbolContext &sc) { if (sect_offset == DW_INVALID_OFFSET) return false; - sc.comp_unit->SetDebugMacros(ParseDebugMacros(§_offset)); + comp_unit.SetDebugMacros(ParseDebugMacros(§_offset)); return true; } -size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc, - Block *parent_block, - const DWARFDIE &orig_die, - addr_t subprogram_low_pc, - uint32_t depth) { +size_t SymbolFileDWARF::ParseBlocksRecursive( + lldb_private::CompileUnit &comp_unit, Block *parent_block, + const DWARFDIE &orig_die, addr_t subprogram_low_pc, uint32_t depth) { size_t blocks_added = 0; DWARFDIE die = orig_die; while (die) { @@ -1219,13 +1240,13 @@ size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc, std::unique_ptr<Declaration> decl_ap; if (decl_file != 0 || decl_line != 0 || decl_column != 0) decl_ap.reset(new Declaration( - sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), + comp_unit.GetSupportFiles().GetFileSpecAtIndex(decl_file), decl_line, decl_column)); std::unique_ptr<Declaration> call_ap; if (call_file != 0 || call_line != 0 || call_column != 0) call_ap.reset(new Declaration( - sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(call_file), + comp_unit.GetSupportFiles().GetFileSpecAtIndex(call_file), call_line, call_column)); block->SetInlinedFunctionInfo(name, mangled_name, decl_ap.get(), @@ -1235,8 +1256,9 @@ size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc, ++blocks_added; if (die.HasChildren()) { - blocks_added += ParseFunctionBlocks(sc, block, die.GetFirstChild(), - subprogram_low_pc, depth + 1); + blocks_added += + ParseBlocksRecursive(comp_unit, block, die.GetFirstChild(), + subprogram_low_pc, depth + 1); } } } break; @@ -1292,6 +1314,9 @@ void SymbolFileDWARF::ParseDeclsForContext(CompilerDeclContext decl_ctx) { } SymbolFileDWARF *SymbolFileDWARF::GetDWARFForUID(lldb::user_id_t uid) { + // This method can be called without going through the symbol vendor so we + // need to lock the module. + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API we // must make sure we use the correct DWARF file when resolving things. On // MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple @@ -1308,6 +1333,9 @@ SymbolFileDWARF *SymbolFileDWARF::GetDWARFForUID(lldb::user_id_t uid) { DWARFDIE SymbolFileDWARF::GetDIEFromUID(lldb::user_id_t uid) { + // This method can be called without going through the symbol vendor so we + // need to lock the module. + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API we // must make sure we use the correct DWARF file when resolving things. On // MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple @@ -1322,6 +1350,9 @@ SymbolFileDWARF::GetDIEFromUID(lldb::user_id_t uid) { } CompilerDecl SymbolFileDWARF::GetDeclForUID(lldb::user_id_t type_uid) { + // This method can be called without going through the symbol vendor so we + // need to lock the module. + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); // Anytime we have a lldb::user_id_t, we must get the DIE by calling // SymbolFileDWARF::GetDIEFromUID(). See comments inside the // SymbolFileDWARF::GetDIEFromUID() for details. @@ -1333,6 +1364,9 @@ CompilerDecl SymbolFileDWARF::GetDeclForUID(lldb::user_id_t type_uid) { CompilerDeclContext SymbolFileDWARF::GetDeclContextForUID(lldb::user_id_t type_uid) { + // This method can be called without going through the symbol vendor so we + // need to lock the module. + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); // Anytime we have a lldb::user_id_t, we must get the DIE by calling // SymbolFileDWARF::GetDIEFromUID(). See comments inside the // SymbolFileDWARF::GetDIEFromUID() for details. @@ -1344,6 +1378,9 @@ SymbolFileDWARF::GetDeclContextForUID(lldb::user_id_t type_uid) { CompilerDeclContext SymbolFileDWARF::GetDeclContextContainingUID(lldb::user_id_t type_uid) { + // This method can be called without going through the symbol vendor so we + // need to lock the module. + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); // Anytime we have a lldb::user_id_t, we must get the DIE by calling // SymbolFileDWARF::GetDIEFromUID(). See comments inside the // SymbolFileDWARF::GetDIEFromUID() for details. @@ -1354,6 +1391,9 @@ SymbolFileDWARF::GetDeclContextContainingUID(lldb::user_id_t type_uid) { } Type *SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid) { + // This method can be called without going through the symbol vendor so we + // need to lock the module. + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); // Anytime we have a lldb::user_id_t, we must get the DIE by calling // SymbolFileDWARF::GetDIEFromUID(). See comments inside the // SymbolFileDWARF::GetDIEFromUID() for details. @@ -1364,6 +1404,17 @@ Type *SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid) { return nullptr; } +llvm::Optional<SymbolFile::ArrayInfo> +SymbolFileDWARF::GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + DWARFDIE type_die = GetDIEFromUID(type_uid); + if (type_die) + return DWARFASTParser::ParseChildArrayInfo(type_die, exe_ctx); + else + return llvm::None; +} + Type *SymbolFileDWARF::ResolveTypeUID(const DIERef &die_ref) { return ResolveType(GetDIE(die_ref), true); } @@ -1429,8 +1480,7 @@ bool SymbolFileDWARF::HasForwardDeclForClangType( } bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) { - std::lock_guard<std::recursive_mutex> guard( - GetObjectFile()->GetModule()->GetMutex()); + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(compiler_type.GetTypeSystem()); @@ -1525,7 +1575,7 @@ bool SymbolFileDWARF::GetFunction(const DWARFDIE &die, SymbolContext &sc) { sc.function = sc.comp_unit->FindFunctionByUID(die.GetID()).get(); if (sc.function == NULL) - sc.function = ParseCompileUnitFunction(sc, die); + sc.function = ParseFunction(*sc.comp_unit, die); if (sc.function) { sc.module_sp = sc.function->CalculateSymbolContextModule(); @@ -1578,18 +1628,20 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( return dwo_symfile; } - FileSpec dwo_file(dwo_name, true); + FileSpec dwo_file(dwo_name); + FileSystem::Instance().Resolve(dwo_file); if (dwo_file.IsRelative()) { const char *comp_dir = cu_die.GetAttributeValueAsString( this, &dwarf_cu, DW_AT_comp_dir, nullptr); if (!comp_dir) return nullptr; - dwo_file.SetFile(comp_dir, true, FileSpec::Style::native); + dwo_file.SetFile(comp_dir, FileSpec::Style::native); + FileSystem::Instance().Resolve(dwo_file); dwo_file.AppendPathComponent(dwo_name); } - if (!dwo_file.Exists()) + if (!FileSystem::Instance().Exists(dwo_file)) return nullptr; const lldb::offset_t file_offset = 0; @@ -1597,7 +1649,8 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( lldb::offset_t dwo_file_data_offset = 0; ObjectFileSP dwo_obj_file = ObjectFile::FindPlugin( GetObjectFile()->GetModule(), &dwo_file, file_offset, - dwo_file.GetByteSize(), dwo_file_data_sp, dwo_file_data_offset); + FileSystem::Instance().GetByteSize(dwo_file), dwo_file_data_sp, + dwo_file_data_offset); if (dwo_obj_file == nullptr) return nullptr; @@ -1616,7 +1669,7 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { DWARFUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly(); - if (die && die.HasChildren() == false) { + if (die && !die.HasChildren()) { const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr); if (name) { @@ -1628,14 +1681,15 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { die.GetAttributeValueAsString(DW_AT_GNU_dwo_name, nullptr); if (dwo_path) { ModuleSpec dwo_module_spec; - dwo_module_spec.GetFileSpec().SetFile(dwo_path, false, + dwo_module_spec.GetFileSpec().SetFile(dwo_path, FileSpec::Style::native); if (dwo_module_spec.GetFileSpec().IsRelative()) { const char *comp_dir = die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr); if (comp_dir) { - dwo_module_spec.GetFileSpec().SetFile(comp_dir, true, + dwo_module_spec.GetFileSpec().SetFile(comp_dir, FileSpec::Style::native); + FileSystem::Instance().Resolve(dwo_module_spec.GetFileSpec()); dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path); } } @@ -1726,7 +1780,7 @@ SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() { } uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, - uint32_t resolve_scope, + SymbolContextItem resolve_scope, SymbolContext &sc) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, @@ -1784,7 +1838,7 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, sc.function = sc.comp_unit->FindFunctionByUID(function_die.GetID()).get(); if (sc.function == NULL) - sc.function = ParseCompileUnitFunction(sc, function_die); + sc.function = ParseFunction(*sc.comp_unit, function_die); if (sc.function && (resolve_scope & eSymbolContextBlock)) block_die = function_die.LookupDeepestBlock(file_vm_addr); @@ -1860,7 +1914,7 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, uint32_t line, bool check_inlines, - uint32_t resolve_scope, + SymbolContextItem resolve_scope, SymbolContextList &sc_list) { const uint32_t prev_size = sc_list.GetSize(); if (resolve_scope & eSymbolContextCompUnit) { @@ -1925,7 +1979,7 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, .get(); if (sc.function == NULL) sc.function = - ParseCompileUnitFunction(sc, function_die); + ParseFunction(*sc.comp_unit, function_die); if (sc.function && (resolve_scope & eSymbolContextBlock)) @@ -1975,11 +2029,17 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, } void SymbolFileDWARF::PreloadSymbols() { - std::lock_guard<std::recursive_mutex> guard( - GetObjectFile()->GetModule()->GetMutex()); + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); m_index->Preload(); } +std::recursive_mutex &SymbolFileDWARF::GetModuleMutex() const { + lldb::ModuleSP module_sp(m_debug_map_module_wp.lock()); + if (module_sp) + return module_sp->GetMutex(); + return GetObjectFile()->GetModule()->GetMutex(); +} + bool SymbolFileDWARF::DeclContextMatchesThisSymbolFile( const lldb_private::CompilerDeclContext *decl_ctx) { if (decl_ctx == nullptr || !decl_ctx->IsValid()) { @@ -2195,7 +2255,7 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, sc.block = function_block.FindBlockByID(inlined_die.GetID()); if (sc.block == NULL) sc.block = function_block.FindBlockByID(inlined_die.GetOffset()); - if (sc.block == NULL || sc.block->GetStartAddress(addr) == false) + if (sc.block == NULL || !sc.block->GetStartAddress(addr)) addr.Clear(); } else { sc.block = NULL; @@ -2231,11 +2291,10 @@ bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext *decl_ctx, return false; } -uint32_t -SymbolFileDWARF::FindFunctions(const ConstString &name, - const CompilerDeclContext *parent_decl_ctx, - uint32_t name_type_mask, bool include_inlines, - bool append, SymbolContextList &sc_list) { +uint32_t SymbolFileDWARF::FindFunctions( + const ConstString &name, const CompilerDeclContext *parent_decl_ctx, + FunctionNameType name_type_mask, bool include_inlines, bool append, + SymbolContextList &sc_list) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "SymbolFileDWARF::FindFunctions (name = '%s')", name.AsCString()); @@ -2378,9 +2437,8 @@ void SymbolFileDWARF::GetMangledNamesForFunction( } uint32_t SymbolFileDWARF::FindTypes( - const SymbolContext &sc, const ConstString &name, - const CompilerDeclContext *parent_decl_ctx, bool append, - uint32_t max_matches, + const ConstString &name, const CompilerDeclContext *parent_decl_ctx, + bool append, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types) { // If we aren't appending the results to this list, then clear the list @@ -2469,8 +2527,8 @@ uint32_t SymbolFileDWARF::FindTypes( SymbolVendor *sym_vendor = external_module_sp->GetSymbolVendor(); if (sym_vendor) { const uint32_t num_external_matches = - sym_vendor->FindTypes(sc, name, parent_decl_ctx, append, - max_matches, searched_symbol_files, types); + sym_vendor->FindTypes(name, parent_decl_ctx, append, max_matches, + searched_symbol_files, types); if (num_external_matches) return num_external_matches; } @@ -2506,7 +2564,7 @@ size_t SymbolFileDWARF::FindTypes(const std::vector<CompilerContext> &context, if (die) { std::vector<CompilerContext> die_context; - die.GetDWOContext(die_context); + die.GetDeclContext(die_context); if (die_context != context) continue; @@ -2528,7 +2586,7 @@ size_t SymbolFileDWARF::FindTypes(const std::vector<CompilerContext> &context, } CompilerDeclContext -SymbolFileDWARF::FindNamespace(const SymbolContext &sc, const ConstString &name, +SymbolFileDWARF::FindNamespace(const ConstString &name, const CompilerDeclContext *parent_decl_ctx) { Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); @@ -3065,39 +3123,36 @@ size_t SymbolFileDWARF::ParseTypes(const SymbolContext &sc, return types_added; } -size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc) { - assert(sc.comp_unit && sc.function); +size_t SymbolFileDWARF::ParseBlocksRecursive(Function &func) { + ASSERT_MODULE_LOCK(this); + CompileUnit *comp_unit = func.GetCompileUnit(); + lldbassert(comp_unit); + + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(comp_unit); + if (!dwarf_cu) + return 0; + size_t functions_added = 0; - DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); - if (dwarf_cu) { - const dw_offset_t function_die_offset = sc.function->GetID(); - DWARFDIE function_die = dwarf_cu->GetDIE(function_die_offset); - if (function_die) { - ParseFunctionBlocks(sc, &sc.function->GetBlock(false), function_die, - LLDB_INVALID_ADDRESS, 0); - } + const dw_offset_t function_die_offset = func.GetID(); + DWARFDIE function_die = dwarf_cu->GetDIE(function_die_offset); + if (function_die) { + ParseBlocksRecursive(*comp_unit, &func.GetBlock(false), function_die, + LLDB_INVALID_ADDRESS, 0); } return functions_added; } -size_t SymbolFileDWARF::ParseTypes(const SymbolContext &sc) { - // At least a compile unit must be valid - assert(sc.comp_unit); +size_t SymbolFileDWARF::ParseTypes(CompileUnit &comp_unit) { + ASSERT_MODULE_LOCK(this); size_t types_added = 0; - DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (dwarf_cu) { - if (sc.function) { - dw_offset_t function_die_offset = sc.function->GetID(); - DWARFDIE func_die = dwarf_cu->GetDIE(function_die_offset); - if (func_die && func_die.HasChildren()) { - types_added = ParseTypes(sc, func_die.GetFirstChild(), true, true); - } - } else { - DWARFDIE dwarf_cu_die = dwarf_cu->DIE(); - if (dwarf_cu_die && dwarf_cu_die.HasChildren()) { - types_added = ParseTypes(sc, dwarf_cu_die.GetFirstChild(), true, true); - } + DWARFDIE dwarf_cu_die = dwarf_cu->DIE(); + if (dwarf_cu_die && dwarf_cu_die.HasChildren()) { + SymbolContext sc; + sc.comp_unit = &comp_unit; + types_added = ParseTypes(sc, dwarf_cu_die.GetFirstChild(), true, true); } } @@ -3105,6 +3160,7 @@ size_t SymbolFileDWARF::ParseTypes(const SymbolContext &sc) { } size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { + ASSERT_MODULE_LOCK(this); if (sc.comp_unit != NULL) { DWARFDebugInfo *info = DebugInfo(); if (info == NULL) @@ -3298,7 +3354,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, uint32_t block_length = form_value.Unsigned(); location.CopyOpcodeData(module, data, block_offset, block_length); } else { - const DWARFDataExtractor &debug_loc_data = get_debug_loc_data(); + const DWARFDataExtractor &debug_loc_data = DebugLocData(); const dw_offset_t debug_loc_offset = form_value.Unsigned(); size_t loc_list_length = DWARFExpression::LocationListSize( @@ -3319,22 +3375,10 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, case DW_AT_start_scope: { if (form_value.Form() == DW_FORM_sec_offset) { DWARFRangeList dwarf_scope_ranges; - const DWARFDebugRanges *debug_ranges = DebugRanges(); - debug_ranges->FindRanges(die.GetCU()->GetRangesBase(), + const DWARFDebugRangesBase *debug_ranges = DebugRanges(); + debug_ranges->FindRanges(die.GetCU(), form_value.Unsigned(), dwarf_scope_ranges); - - // All DW_AT_start_scope are relative to the base address of the - // compile unit. We add the compile unit base address to make - // sure all the addresses are properly fixed up. - for (size_t i = 0, count = dwarf_scope_ranges.GetSize(); - i < count; ++i) { - const DWARFRangeList::Entry &range = - dwarf_scope_ranges.GetEntryRef(i); - scope_ranges.Append(range.GetRangeBase() + - die.GetCU()->GetBaseAddress(), - range.GetByteSize()); - } } else { // TODO: Handle the case when DW_AT_start_scope have form // constant. The @@ -3436,6 +3480,11 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, is_static_lifetime = true; } SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); + if (debug_map_symfile) + // Set the module of the expression to the linked module + // instead of the oject file so the relocated address can be + // found there. + location.SetModule(debug_map_symfile->GetObjectFile()->GetModule()); if (is_static_lifetime) { if (is_external) @@ -3736,6 +3785,60 @@ size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc, return vars_added; } +/// Collect call graph edges present in a function DIE. +static std::vector<lldb_private::CallEdge> +CollectCallEdges(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); + if (!has_call_edges) + return {}; + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + LLDB_LOG(log, "CollectCallEdges: Found call site info in {0}", + function_die.GetPubname()); + + // Scan the DIE for TAG_call_site entries. + // TODO: A recursive scan of all blocks in the subprogram is needed in order + // to be DWARF5-compliant. This may need to be done lazily to be performant. + // For now, assume that all entries are nested directly under the subprogram + // (this is the kind of DWARF LLVM produces) and parse them eagerly. + std::vector<CallEdge> call_edges; + for (DWARFDIE child = function_die.GetFirstChild(); child.IsValid(); + child = child.GetSibling()) { + if (child.Tag() != DW_TAG_call_site) + continue; + + // Extract DW_AT_call_origin (the call target's DIE). + DWARFDIE call_origin = child.GetReferencedDIE(DW_AT_call_origin); + if (!call_origin.IsValid()) { + LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", + function_die.GetPubname()); + continue; + } + + // 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. + addr_t return_pc = child.GetAttributeValueAsAddress(DW_AT_call_return_pc, + LLDB_INVALID_ADDRESS); + + LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", + call_origin.GetPubname(), return_pc); + call_edges.emplace_back(call_origin.GetMangledName(), return_pc); + } + return call_edges; +} + +std::vector<lldb_private::CallEdge> +SymbolFileDWARF::ParseCallEdgesInFunction(UserID func_id) { + DWARFDIE func_die = GetDIEFromUID(func_id.GetID()); + if (func_die.IsValid()) + return CollectCallEdges(func_die); + return {}; +} + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -3745,6 +3848,14 @@ uint32_t SymbolFileDWARF::GetPluginVersion() { return 1; } void SymbolFileDWARF::Dump(lldb_private::Stream &s) { m_index->Dump(s); } +void SymbolFileDWARF::DumpClangAST(Stream &s) { + TypeSystem *ts = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus); + ClangASTContext *clang = llvm::dyn_cast_or_null<ClangASTContext>(ts); + if (!clang) + return; + clang->Dump(s); +} + SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { if (m_debug_map_symfile == NULL && !m_debug_map_module_wp.expired()) { lldb::ModuleSP module_sp(m_debug_map_module_wp.lock()); @@ -3760,6 +3871,8 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { DWARFExpression::LocationListFormat SymbolFileDWARF::GetLocationListFormat() const { + if (m_data_debug_loclists.m_data.GetByteSize() > 0) + return DWARFExpression::LocLists; return DWARFExpression::RegularLocationList; } @@ -3768,9 +3881,9 @@ SymbolFileDWARFDwp *SymbolFileDWARF::GetDwpSymbolFile() { ModuleSpec module_spec; module_spec.GetFileSpec() = m_obj_file->GetFileSpec(); module_spec.GetSymbolFileSpec() = - FileSpec(m_obj_file->GetFileSpec().GetPath() + ".dwp", false); + FileSpec(m_obj_file->GetFileSpec().GetPath() + ".dwp"); FileSpec dwp_filespec = Symbols::LocateExecutableSymbolFile(module_spec); - if (dwp_filespec.Exists()) { + if (FileSystem::Instance().Exists(dwp_filespec)) { m_dwp_symfile = SymbolFileDWARFDwp::Create(GetObjectFile()->GetModule(), dwp_filespec); } diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index a5f2ac8f3e7d..d351289f8b51 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -10,8 +10,6 @@ #ifndef SymbolFileDWARF_SymbolFileDWARF_h_ #define SymbolFileDWARF_SymbolFileDWARF_h_ -// C Includes -// C++ Includes #include <list> #include <map> #include <mutex> @@ -19,7 +17,6 @@ #include <unordered_map> #include <vector> -// Other libraries and framework includes #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Threading.h" @@ -35,7 +32,6 @@ #include "lldb/Utility/ConstString.h" #include "lldb/lldb-private.h" -// Project includes #include "DWARFDataExtractor.h" #include "DWARFDefines.h" #include "DWARFIndex.h" @@ -53,7 +49,7 @@ class DWARFDebugAranges; class DWARFDebugInfo; class DWARFDebugInfoEntry; class DWARFDebugLine; -class DWARFDebugRanges; +class DWARFDebugRangesBase; class DWARFDeclContext; class DWARFDIECollection; class DWARFFormValue; @@ -73,9 +69,6 @@ public: friend class DWARFUnit; friend class DWARFDIE; friend class DWARFASTParserClang; - friend class DWARFASTParserGo; - friend class DWARFASTParserJava; - friend class DWARFASTParserOCaml; //------------------------------------------------------------------ // Static Functions @@ -114,36 +107,34 @@ public: lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; lldb::LanguageType - ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) override; + ParseLanguage(lldb_private::CompileUnit &comp_unit) override; - size_t - ParseCompileUnitFunctions(const lldb_private::SymbolContext &sc) override; + size_t ParseFunctions(lldb_private::CompileUnit &comp_unit) override; - bool - ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc) override; + bool ParseLineTable(lldb_private::CompileUnit &comp_unit) override; - bool - ParseCompileUnitDebugMacros(const lldb_private::SymbolContext &sc) override; + bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; - bool ParseCompileUnitSupportFiles( - const lldb_private::SymbolContext &sc, - lldb_private::FileSpecList &support_files) override; + bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, + lldb_private::FileSpecList &support_files) override; - bool - ParseCompileUnitIsOptimized(const lldb_private::SymbolContext &sc) override; + bool ParseIsOptimized(lldb_private::CompileUnit &comp_unit) override; + + size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override; bool ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules) override; - size_t ParseFunctionBlocks(const lldb_private::SymbolContext &sc) override; - - size_t ParseTypes(const lldb_private::SymbolContext &sc) override; + size_t ParseBlocksRecursive(lldb_private::Function &func) override; size_t ParseVariablesForContext(const lldb_private::SymbolContext &sc) override; lldb_private::Type *ResolveTypeUID(lldb::user_id_t type_uid) override; + llvm::Optional<ArrayInfo> GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, + const lldb_private::ExecutionContext *exe_ctx) override; bool CompleteType(lldb_private::CompilerType &compiler_type) override; @@ -168,12 +159,13 @@ public: ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override; uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr, - uint32_t resolve_scope, + lldb::SymbolContextItem resolve_scope, lldb_private::SymbolContext &sc) override; uint32_t ResolveSymbolContext(const lldb_private::FileSpec &file_spec, uint32_t line, - bool check_inlines, uint32_t resolve_scope, + bool check_inlines, + lldb::SymbolContextItem resolve_scope, lldb_private::SymbolContextList &sc_list) override; uint32_t @@ -189,8 +181,8 @@ public: uint32_t FindFunctions(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, - uint32_t name_type_mask, bool include_inlines, bool append, - lldb_private::SymbolContextList &sc_list) override; + lldb::FunctionNameType name_type_mask, bool include_inlines, + bool append, lldb_private::SymbolContextList &sc_list) override; uint32_t FindFunctions(const lldb_private::RegularExpression ®ex, bool include_inlines, bool append, @@ -201,8 +193,7 @@ public: std::vector<lldb_private::ConstString> &mangled_names) override; uint32_t - FindTypes(const lldb_private::SymbolContext &sc, - const lldb_private::ConstString &name, + FindTypes(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, @@ -214,19 +205,20 @@ public: lldb_private::TypeList *GetTypeList() override; size_t GetTypes(lldb_private::SymbolContextScope *sc_scope, - uint32_t type_mask, + lldb::TypeClass type_mask, lldb_private::TypeList &type_list) override; lldb_private::TypeSystem * GetTypeSystemForLanguage(lldb::LanguageType language) override; lldb_private::CompilerDeclContext FindNamespace( - const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx) override; void PreloadSymbols() override; + std::recursive_mutex &GetModuleMutex() const override; + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -234,17 +226,20 @@ public: uint32_t GetPluginVersion() override; - const lldb_private::DWARFDataExtractor &get_debug_abbrev_data(); - const lldb_private::DWARFDataExtractor &get_debug_addr_data(); + virtual const lldb_private::DWARFDataExtractor &get_debug_abbrev_data(); + virtual const lldb_private::DWARFDataExtractor &get_debug_addr_data(); const lldb_private::DWARFDataExtractor &get_debug_aranges_data(); const lldb_private::DWARFDataExtractor &get_debug_frame_data(); - const lldb_private::DWARFDataExtractor &get_debug_info_data(); + virtual const lldb_private::DWARFDataExtractor &get_debug_info_data(); const lldb_private::DWARFDataExtractor &get_debug_line_data(); + const lldb_private::DWARFDataExtractor &get_debug_line_str_data(); const lldb_private::DWARFDataExtractor &get_debug_macro_data(); const lldb_private::DWARFDataExtractor &get_debug_loc_data(); + const lldb_private::DWARFDataExtractor &get_debug_loclists_data(); const lldb_private::DWARFDataExtractor &get_debug_ranges_data(); - const lldb_private::DWARFDataExtractor &get_debug_str_data(); - const lldb_private::DWARFDataExtractor &get_debug_str_offsets_data(); + const lldb_private::DWARFDataExtractor &get_debug_rnglists_data(); + virtual const lldb_private::DWARFDataExtractor &get_debug_str_data(); + virtual const lldb_private::DWARFDataExtractor &get_debug_str_offsets_data(); const lldb_private::DWARFDataExtractor &get_debug_types_data(); const lldb_private::DWARFDataExtractor &get_apple_names_data(); const lldb_private::DWARFDataExtractor &get_apple_types_data(); @@ -260,9 +255,11 @@ public: const DWARFDebugInfo *DebugInfo() const; - DWARFDebugRanges *DebugRanges(); + DWARFDebugRangesBase *DebugRanges(); - const DWARFDebugRanges *DebugRanges() const; + const DWARFDebugRangesBase *DebugRanges() const; + + const lldb_private::DWARFDataExtractor &DebugLocData(); static bool SupportedVersion(uint16_t version); @@ -316,8 +313,13 @@ public: DIEInDeclContext(const lldb_private::CompilerDeclContext *parent_decl_ctx, const DWARFDIE &die); + std::vector<lldb_private::CallEdge> + ParseCallEdgesInFunction(UserID func_id) override; + void Dump(lldb_private::Stream &s) override; + void DumpClangAST(lldb_private::Stream &s) override; + protected: typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *> DIEToTypePtr; @@ -352,14 +354,13 @@ protected: bool GetFunction(const DWARFDIE &die, lldb_private::SymbolContext &sc); - lldb_private::Function * - ParseCompileUnitFunction(const lldb_private::SymbolContext &sc, - const DWARFDIE &die); + lldb_private::Function *ParseFunction(lldb_private::CompileUnit &comp_unit, + const DWARFDIE &die); - size_t ParseFunctionBlocks(const lldb_private::SymbolContext &sc, - lldb_private::Block *parent_block, - const DWARFDIE &die, - lldb::addr_t subprogram_low_pc, uint32_t depth); + size_t ParseBlocksRecursive(lldb_private::CompileUnit &comp_unit, + lldb_private::Block *parent_block, + const DWARFDIE &die, + lldb::addr_t subprogram_low_pc, uint32_t depth); size_t ParseTypes(const lldb_private::SymbolContext &sc, const DWARFDIE &die, bool parse_siblings, bool parse_children); @@ -466,9 +467,12 @@ protected: DWARFDataSegment m_data_debug_frame; DWARFDataSegment m_data_debug_info; DWARFDataSegment m_data_debug_line; + DWARFDataSegment m_data_debug_line_str; DWARFDataSegment m_data_debug_macro; DWARFDataSegment m_data_debug_loc; + DWARFDataSegment m_data_debug_loclists; DWARFDataSegment m_data_debug_ranges; + DWARFDataSegment m_data_debug_rnglists; DWARFDataSegment m_data_debug_str; DWARFDataSegment m_data_debug_str_offsets; DWARFDataSegment m_data_debug_types; @@ -498,7 +502,7 @@ protected: typedef std::shared_ptr<std::set<DIERef>> DIERefSetSP; typedef std::unordered_map<std::string, DIERefSetSP> NameToOffsetMap; NameToOffsetMap m_function_scope_qualified_name_map; - std::unique_ptr<DWARFDebugRanges> m_ranges; + std::unique_ptr<DWARFDebugRangesBase> m_ranges; UniqueDWARFASTTypeMap m_unique_ast_type_map; DIEToTypePtr m_die_to_type; DIEToVariableSP m_die_to_variable_sp; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 39c70d146524..2c1e6416a935 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -7,10 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "SymbolFileDWARFDebugMap.h" #include "DWARFDebugAranges.h" @@ -90,11 +86,10 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( const uint32_t oso_end_idx = comp_unit_info->last_symbol_index + 1; for (uint32_t idx = comp_unit_info->first_symbol_index + 2; // Skip the N_SO and N_OSO - idx < oso_end_idx; - ++idx) { + idx < oso_end_idx; ++idx) { Symbol *exe_symbol = exe_symtab->SymbolAtIndex(idx); if (exe_symbol) { - if (exe_symbol->IsDebug() == false) + if (!exe_symbol->IsDebug()) continue; switch (exe_symbol->GetType()) { @@ -184,7 +179,7 @@ public: GetSymbolVendor(bool can_create = true, lldb_private::Stream *feedback_strm = NULL) override { // Scope for locker - if (m_symfile_ap.get() || can_create == false) + if (m_symfile_ap.get() || !can_create) return m_symfile_ap.get(); ModuleSP exe_module_sp(m_exe_module_wp.lock()); @@ -351,7 +346,7 @@ void SymbolFileDWARFDebugMap::InitOSO() { so_symbol->GetType() == eSymbolTypeSourceFile && oso_symbol->GetType() == eSymbolTypeObjectFile) { m_compile_unit_infos[i].so_file.SetFile( - so_symbol->GetName().AsCString(), false, FileSpec::Style::native); + so_symbol->GetName().AsCString(), FileSpec::Style::native); m_compile_unit_infos[i].oso_path = oso_symbol->GetName(); m_compile_unit_infos[i].oso_mod_time = llvm::sys::toTimePoint(oso_symbol->GetIntegerValue(0)); @@ -421,10 +416,13 @@ Module *SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo( m_oso_map[{comp_unit_info->oso_path, comp_unit_info->oso_mod_time}] = comp_unit_info->oso_sp; const char *oso_path = comp_unit_info->oso_path.GetCString(); - FileSpec oso_file(oso_path, false); + FileSpec oso_file(oso_path); ConstString oso_object; - if (oso_file.Exists()) { - auto oso_mod_time = FileSystem::GetModificationTime(oso_file); + if (FileSystem::Instance().Exists(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>( + FileSystem::Instance().GetModificationTime(oso_file)); if (oso_mod_time != comp_unit_info->oso_mod_time) { obj_file->GetModule()->ReportError( "debug map object file '%s' has changed (actual time is " @@ -490,7 +488,12 @@ ObjectFile *SymbolFileDWARFDebugMap::GetObjectFileByOSOIndex(uint32_t oso_idx) { SymbolFileDWARF * SymbolFileDWARFDebugMap::GetSymbolFile(const SymbolContext &sc) { - CompileUnitInfo *comp_unit_info = GetCompUnitInfo(sc); + return GetSymbolFile(*sc.comp_unit); +} + +SymbolFileDWARF * +SymbolFileDWARFDebugMap::GetSymbolFile(const CompileUnit &comp_unit) { + CompileUnitInfo *comp_unit_info = GetCompUnitInfo(comp_unit); if (comp_unit_info) return GetSymbolFileByCompUnitInfo(comp_unit_info); return NULL; @@ -518,7 +521,8 @@ uint32_t SymbolFileDWARFDebugMap::GetCompUnitInfoIndex( SymbolFileDWARF * SymbolFileDWARFDebugMap::GetSymbolFileByOSOIndex(uint32_t oso_idx) { - if (oso_idx < m_compile_unit_infos.size()) + unsigned size = m_compile_unit_infos.size(); + if (oso_idx < size) return GetSymbolFileByCompUnitInfo(&m_compile_unit_infos[oso_idx]); return NULL; } @@ -597,9 +601,14 @@ CompUnitSP SymbolFileDWARFDebugMap::ParseCompileUnitAtIndex(uint32_t cu_idx) { SymbolFileDWARFDebugMap::CompileUnitInfo * SymbolFileDWARFDebugMap::GetCompUnitInfo(const SymbolContext &sc) { + return GetCompUnitInfo(*sc.comp_unit); +} + +SymbolFileDWARFDebugMap::CompileUnitInfo * +SymbolFileDWARFDebugMap::GetCompUnitInfo(const CompileUnit &comp_unit) { const uint32_t cu_count = GetNumCompileUnits(); for (uint32_t i = 0; i < cu_count; ++i) { - if (sc.comp_unit == m_compile_unit_infos[i].compile_unit_sp.get()) + if (comp_unit == m_compile_unit_infos[i].compile_unit_sp.get()) return &m_compile_unit_infos[i]; } return NULL; @@ -617,50 +626,46 @@ size_t SymbolFileDWARFDebugMap::GetCompUnitInfosForModule( } lldb::LanguageType -SymbolFileDWARFDebugMap::ParseCompileUnitLanguage(const SymbolContext &sc) { - SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); +SymbolFileDWARFDebugMap::ParseLanguage(CompileUnit &comp_unit) { + SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); if (oso_dwarf) - return oso_dwarf->ParseCompileUnitLanguage(sc); + return oso_dwarf->ParseLanguage(comp_unit); return eLanguageTypeUnknown; } -size_t -SymbolFileDWARFDebugMap::ParseCompileUnitFunctions(const SymbolContext &sc) { - SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); +size_t SymbolFileDWARFDebugMap::ParseFunctions(CompileUnit &comp_unit) { + SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); if (oso_dwarf) - return oso_dwarf->ParseCompileUnitFunctions(sc); + return oso_dwarf->ParseFunctions(comp_unit); return 0; } -bool SymbolFileDWARFDebugMap::ParseCompileUnitLineTable( - const SymbolContext &sc) { - SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); +bool SymbolFileDWARFDebugMap::ParseLineTable(CompileUnit &comp_unit) { + SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); if (oso_dwarf) - return oso_dwarf->ParseCompileUnitLineTable(sc); + return oso_dwarf->ParseLineTable(comp_unit); return false; } -bool SymbolFileDWARFDebugMap::ParseCompileUnitDebugMacros( - const SymbolContext &sc) { - SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); +bool SymbolFileDWARFDebugMap::ParseDebugMacros(CompileUnit &comp_unit) { + SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); if (oso_dwarf) - return oso_dwarf->ParseCompileUnitDebugMacros(sc); + return oso_dwarf->ParseDebugMacros(comp_unit); return false; } -bool SymbolFileDWARFDebugMap::ParseCompileUnitSupportFiles( - const SymbolContext &sc, FileSpecList &support_files) { - SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); +bool SymbolFileDWARFDebugMap::ParseSupportFiles(CompileUnit &comp_unit, + FileSpecList &support_files) { + SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); if (oso_dwarf) - return oso_dwarf->ParseCompileUnitSupportFiles(sc, support_files); + return oso_dwarf->ParseSupportFiles(comp_unit, support_files); return false; } -bool SymbolFileDWARFDebugMap::ParseCompileUnitIsOptimized( - const lldb_private::SymbolContext &sc) { - SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); +bool SymbolFileDWARFDebugMap::ParseIsOptimized(CompileUnit &comp_unit) { + SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); if (oso_dwarf) - return oso_dwarf->ParseCompileUnitIsOptimized(sc); + return oso_dwarf->ParseIsOptimized(comp_unit); return false; } @@ -672,17 +677,21 @@ bool SymbolFileDWARFDebugMap::ParseImportedModules( return false; } -size_t SymbolFileDWARFDebugMap::ParseFunctionBlocks(const SymbolContext &sc) { - SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); +size_t SymbolFileDWARFDebugMap::ParseBlocksRecursive(Function &func) { + CompileUnit *comp_unit = func.GetCompileUnit(); + if (!comp_unit) + return 0; + + SymbolFileDWARF *oso_dwarf = GetSymbolFile(*comp_unit); if (oso_dwarf) - return oso_dwarf->ParseFunctionBlocks(sc); + return oso_dwarf->ParseBlocksRecursive(func); return 0; } -size_t SymbolFileDWARFDebugMap::ParseTypes(const SymbolContext &sc) { - SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); +size_t SymbolFileDWARFDebugMap::ParseTypes(CompileUnit &comp_unit) { + SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); if (oso_dwarf) - return oso_dwarf->ParseTypes(sc); + return oso_dwarf->ParseTypes(comp_unit); return 0; } @@ -702,6 +711,16 @@ Type *SymbolFileDWARFDebugMap::ResolveTypeUID(lldb::user_id_t type_uid) { return NULL; } +llvm::Optional<SymbolFile::ArrayInfo> +SymbolFileDWARFDebugMap::GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) { + const uint64_t oso_idx = GetOSOIndexFromUserID(type_uid); + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx); + if (oso_dwarf) + return oso_dwarf->GetDynamicArrayInfoForUID(type_uid, exe_ctx); + return llvm::None; +} + bool SymbolFileDWARFDebugMap::CompleteType(CompilerType &compiler_type) { bool success = false; if (compiler_type) { @@ -717,8 +736,10 @@ bool SymbolFileDWARFDebugMap::CompleteType(CompilerType &compiler_type) { return success; } -uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext( - const Address &exe_so_addr, uint32_t resolve_scope, SymbolContext &sc) { +uint32_t +SymbolFileDWARFDebugMap::ResolveSymbolContext(const Address &exe_so_addr, + SymbolContextItem resolve_scope, + SymbolContext &sc) { uint32_t resolved_flags = 0; Symtab *symtab = m_obj_file->GetSymtab(); if (symtab) { @@ -760,7 +781,7 @@ uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext( uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext( const FileSpec &file_spec, uint32_t line, bool check_inlines, - uint32_t resolve_scope, SymbolContextList &sc_list) { + SymbolContextItem resolve_scope, SymbolContextList &sc_list) { const uint32_t initial = sc_list.GetSize(); const uint32_t cu_count = GetNumCompileUnits(); @@ -792,8 +813,7 @@ uint32_t SymbolFileDWARFDebugMap::PrivateFindGlobalVariables( const 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) { + uint32_t max_matches, VariableList &variables) { const uint32_t original_size = variables.GetSize(); const size_t match_count = indexes.size(); for (size_t i = 0; i < match_count; ++i) { @@ -977,7 +997,7 @@ static void RemoveFunctionsWithModuleNotEqualTo(const ModuleSP &module_sp, uint32_t SymbolFileDWARFDebugMap::FindFunctions( const ConstString &name, const CompilerDeclContext *parent_decl_ctx, - uint32_t name_type_mask, bool include_inlines, bool append, + FunctionNameType name_type_mask, bool include_inlines, bool append, SymbolContextList &sc_list) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, @@ -1032,7 +1052,7 @@ uint32_t SymbolFileDWARFDebugMap::FindFunctions(const RegularExpression ®ex, } size_t SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope, - uint32_t type_mask, + lldb::TypeClass type_mask, TypeList &type_list) { static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, @@ -1060,6 +1080,15 @@ size_t SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope, return type_list.GetSize() - initial_size; } +std::vector<lldb_private::CallEdge> +SymbolFileDWARFDebugMap::ParseCallEdgesInFunction(UserID func_id) { + uint32_t oso_idx = GetOSOIndexFromUserID(func_id.GetID()); + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx); + if (oso_dwarf) + return oso_dwarf->ParseCallEdgesInFunction(func_id); + return {}; +} + TypeSP SymbolFileDWARFDebugMap::FindDefinitionTypeForDWARFDeclContext( const DWARFDeclContext &die_decl_ctx) { TypeSP type_sp; @@ -1136,7 +1165,7 @@ TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( // Only search all .o files for the definition if we don't need the // implementation because otherwise, with a valid debug map we should have // the ObjC class symbol and the code above should have found it. - if (must_be_implementation == false) { + if (!must_be_implementation) { TypeSP type_sp; ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { @@ -1151,32 +1180,20 @@ TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( } uint32_t SymbolFileDWARFDebugMap::FindTypes( - const SymbolContext &sc, const ConstString &name, - const CompilerDeclContext *parent_decl_ctx, bool append, - uint32_t max_matches, + const ConstString &name, const CompilerDeclContext *parent_decl_ctx, + bool append, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types) { if (!append) types.Clear(); const uint32_t initial_types_size = types.GetSize(); - SymbolFileDWARF *oso_dwarf; - if (sc.comp_unit) { - oso_dwarf = GetSymbolFile(sc); - if (oso_dwarf) - return oso_dwarf->FindTypes(sc, name, parent_decl_ctx, append, - max_matches, searched_symbol_files, types); - } else { - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { - oso_dwarf->FindTypes(sc, name, parent_decl_ctx, append, max_matches, - searched_symbol_files, types); - if (types.GetSize() >= max_matches) - return true; - else - return false; - }); - } + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + oso_dwarf->FindTypes(name, parent_decl_ctx, append, max_matches, + searched_symbol_files, types); + return types.GetSize() >= max_matches; + }); return types.GetSize() - initial_types_size; } @@ -1195,27 +1212,26 @@ uint32_t SymbolFileDWARFDebugMap::FindTypes( //} CompilerDeclContext SymbolFileDWARFDebugMap::FindNamespace( - const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, const CompilerDeclContext *parent_decl_ctx) { CompilerDeclContext matching_namespace; - SymbolFileDWARF *oso_dwarf; - if (sc.comp_unit) { - oso_dwarf = GetSymbolFile(sc); - if (oso_dwarf) - matching_namespace = oso_dwarf->FindNamespace(sc, name, parent_decl_ctx); - } else { - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { - matching_namespace = oso_dwarf->FindNamespace(sc, name, parent_decl_ctx); + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + matching_namespace = oso_dwarf->FindNamespace(name, parent_decl_ctx); - return (bool)matching_namespace; - }); - } + return (bool)matching_namespace; + }); return matching_namespace; } +void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s) { + ForEachSymbolFile([&s](SymbolFileDWARF *oso_dwarf) -> bool { + oso_dwarf->DumpClangAST(s); + return true; + }); +} + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 550f74a203ea..176eadeeca71 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -56,27 +56,33 @@ public: lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; lldb::LanguageType - ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) override; - size_t - ParseCompileUnitFunctions(const lldb_private::SymbolContext &sc) override; - bool - ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc) override; - bool - ParseCompileUnitDebugMacros(const lldb_private::SymbolContext &sc) override; - bool ParseCompileUnitSupportFiles( - const lldb_private::SymbolContext &sc, - lldb_private::FileSpecList &support_files) override; - bool - ParseCompileUnitIsOptimized(const lldb_private::SymbolContext &sc) override; + ParseLanguage(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 ParseSupportFiles(lldb_private::CompileUnit &comp_unit, + lldb_private::FileSpecList &support_files) override; + + bool ParseIsOptimized(lldb_private::CompileUnit &comp_unit) override; + + size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override; + bool ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules) override; - size_t ParseFunctionBlocks(const lldb_private::SymbolContext &sc) override; - size_t ParseTypes(const lldb_private::SymbolContext &sc) override; + size_t ParseBlocksRecursive(lldb_private::Function &func) override; size_t ParseVariablesForContext(const lldb_private::SymbolContext &sc) override; lldb_private::Type *ResolveTypeUID(lldb::user_id_t type_uid) override; + llvm::Optional<ArrayInfo> GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, + const lldb_private::ExecutionContext *exe_ctx) override; + lldb_private::CompilerDeclContext GetDeclContextForUID(lldb::user_id_t uid) override; lldb_private::CompilerDeclContext @@ -86,11 +92,12 @@ public: bool CompleteType(lldb_private::CompilerType &compiler_type) override; uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr, - uint32_t resolve_scope, + lldb::SymbolContextItem resolve_scope, lldb_private::SymbolContext &sc) override; uint32_t ResolveSymbolContext(const lldb_private::FileSpec &file_spec, uint32_t line, - bool check_inlines, uint32_t resolve_scope, + bool check_inlines, + lldb::SymbolContextItem resolve_scope, lldb_private::SymbolContextList &sc_list) override; uint32_t FindGlobalVariables(const lldb_private::ConstString &name, @@ -103,25 +110,27 @@ public: uint32_t FindFunctions(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, - uint32_t name_type_mask, bool include_inlines, bool append, - lldb_private::SymbolContextList &sc_list) override; + lldb::FunctionNameType name_type_mask, bool include_inlines, + bool append, lldb_private::SymbolContextList &sc_list) override; uint32_t FindFunctions(const lldb_private::RegularExpression ®ex, bool include_inlines, bool append, lldb_private::SymbolContextList &sc_list) override; uint32_t - FindTypes(const lldb_private::SymbolContext &sc, - const lldb_private::ConstString &name, + FindTypes(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) override; lldb_private::CompilerDeclContext FindNamespace( - const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx) override; size_t GetTypes(lldb_private::SymbolContextScope *sc_scope, - uint32_t type_mask, + lldb::TypeClass type_mask, lldb_private::TypeList &type_list) override; + std::vector<lldb_private::CallEdge> + ParseCallEdgesInFunction(lldb_private::UserID func_id) override; + + void DumpClangAST(lldb_private::Stream &s) override; //------------------------------------------------------------------ // PluginInterface protocol @@ -189,6 +198,7 @@ protected: bool GetFileSpecForSO(uint32_t oso_idx, lldb_private::FileSpec &file_spec); CompileUnitInfo *GetCompUnitInfo(const lldb_private::SymbolContext &sc); + CompileUnitInfo *GetCompUnitInfo(const lldb_private::CompileUnit &comp_unit); size_t GetCompUnitInfosForModule(const lldb_private::Module *oso_module, std::vector<CompileUnitInfo *> &cu_infos); @@ -206,6 +216,7 @@ protected: uint32_t GetCompUnitInfoIndex(const CompileUnitInfo *comp_unit_info); SymbolFileDWARF *GetSymbolFile(const lldb_private::SymbolContext &sc); + SymbolFileDWARF *GetSymbolFile(const lldb_private::CompileUnit &comp_unit); SymbolFileDWARF *GetSymbolFileByCompUnitInfo(CompileUnitInfo *comp_unit_info); diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index 15fe362fa117..7881448535b8 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -61,14 +61,6 @@ SymbolFileDWARFDwo::ParseCompileUnit(DWARFUnit *dwarf_cu, } DWARFUnit *SymbolFileDWARFDwo::GetCompileUnit() { - // A clang module is found via a skeleton CU, but is not a proper DWO. - // Clang modules have a .debug_info section instead of the *_dwo variant. - if (auto *section_list = m_obj_file->GetSectionList(false)) - if (auto section_sp = - section_list->FindSectionByType(eSectionTypeDWARFDebugInfo, true)) - if (!section_sp->GetName().GetStringRef().endswith("dwo")) - return nullptr; - // Only dwo files with 1 compile unit is supported if (GetNumCompileUnits() == 1) return DebugInfo()->GetCompileUnitAtIndex(0); @@ -126,6 +118,37 @@ DWARFUnit *SymbolFileDWARFDwo::GetBaseCompileUnit() { return m_base_dwarf_cu; } +const DWARFDataExtractor &SymbolFileDWARFDwo::get_debug_abbrev_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugAbbrevDwo, + m_data_debug_abbrev); +} + +const DWARFDataExtractor &SymbolFileDWARFDwo::get_debug_addr_data() { + // For single file split dwarf case (when we have .dwo sections in a .o), + // we do not want to use the .debug_addr section from .o file, + // but want to get one from the final executable. + // For regular split debug case, .dwo file does not contain the + // .debug_addr, so we would always fall back to such lookup anyways. + llvm::call_once(m_data_debug_addr.m_flag, [this] { + SymbolFileDWARF::LoadSectionData(eSectionTypeDWARFDebugAddr, + std::ref(m_data_debug_addr.m_data)); + }); + return m_data_debug_addr.m_data; +} + +const DWARFDataExtractor &SymbolFileDWARFDwo::get_debug_info_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugInfoDwo, m_data_debug_info); +} + +const DWARFDataExtractor &SymbolFileDWARFDwo::get_debug_str_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugStrDwo, m_data_debug_str); +} + +const DWARFDataExtractor &SymbolFileDWARFDwo::get_debug_str_offsets_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugStrOffsetsDwo, + m_data_debug_str_offsets); +} + SymbolFileDWARF *SymbolFileDWARFDwo::GetBaseSymbolFile() { return m_base_dwarf_cu->GetSymbolFileDWARF(); } diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index 483a19512a36..b9ed37547aca 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -10,10 +10,6 @@ #ifndef SymbolFileDWARFDwo_SymbolFileDWARFDwo_h_ #define SymbolFileDWARFDwo_SymbolFileDWARFDwo_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "SymbolFileDWARF.h" class SymbolFileDWARFDwo : public SymbolFileDWARF { @@ -50,6 +46,12 @@ public: DWARFUnit *GetBaseCompileUnit() override; + const lldb_private::DWARFDataExtractor &get_debug_abbrev_data() override; + const lldb_private::DWARFDataExtractor &get_debug_addr_data() override; + const lldb_private::DWARFDataExtractor &get_debug_info_data() override; + const lldb_private::DWARFDataExtractor &get_debug_str_data() override; + const lldb_private::DWARFDataExtractor &get_debug_str_offsets_data() override; + protected: void LoadSectionData(lldb::SectionType sect_type, lldb_private::DWARFDataExtractor &data) override; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h index b1b505b5899f..905ba0a5c7b8 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h @@ -10,10 +10,6 @@ #ifndef SymbolFileDWARFDwoDwp_SymbolFileDWARFDwoDwp_h_ #define SymbolFileDWARFDwoDwp_SymbolFileDWARFDwoDwp_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "SymbolFileDWARFDwo.h" #include "SymbolFileDWARFDwp.h" diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp index ae10e7179e33..73226dfc130f 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp @@ -9,10 +9,6 @@ #include "SymbolFileDWARFDwp.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Section.h" #include "lldb/Symbol/ObjectFile.h" @@ -30,7 +26,7 @@ lldbSectTypeToLlvmSectionKind(lldb::SectionType type) { case lldb::eSectionTypeDWARFDebugLine: return llvm::DW_SECT_LINE; case lldb::eSectionTypeDWARFDebugLoc: - return llvm::DW_SECT_LOC; + return llvm::DW_SECT_LOC; case lldb::eSectionTypeDWARFDebugStrOffsets: return llvm::DW_SECT_STR_OFFSETS; // case lldb::eSectionTypeDWARFDebugMacinfo: @@ -50,7 +46,8 @@ SymbolFileDWARFDwp::Create(lldb::ModuleSP module_sp, 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, file_spec.GetByteSize(), file_data_sp, + 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; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h index 470d1c5b1c48..87f4d9402335 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h @@ -10,14 +10,10 @@ #ifndef SymbolFileDWARFDwp_SymbolFileDWARFDwp_h_ #define SymbolFileDWARFDwp_SymbolFileDWARFDwp_h_ -// C Includes -// C++ Includes #include <memory> -// Other libraries and framework includes #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" -// Project includes #include "lldb/Core/Module.h" #include "DWARFDataExtractor.h" diff --git a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp index 8273d975e57d..dd912aecf0d8 100644 --- a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp +++ b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp @@ -9,10 +9,6 @@ #include "UniqueDWARFASTType.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/Declaration.h" bool UniqueDWARFASTTypeList::Find(const DWARFDIE &die, diff --git a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h index 5d51044cbe1a..1e6b164e9457 100644 --- a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h +++ b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h @@ -10,14 +10,10 @@ #ifndef lldb_UniqueDWARFASTType_h_ #define lldb_UniqueDWARFASTType_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes #include "llvm/ADT/DenseMap.h" -// Project includes #include "DWARFDIE.h" #include "lldb/Symbol/Declaration.h" diff --git a/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt b/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt new file mode 100644 index 000000000000..da2d7fe8108a --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt @@ -0,0 +1,21 @@ +add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN + CompileUnitIndex.cpp + DWARFLocationExpression.cpp + PdbAstBuilder.cpp + PdbIndex.cpp + PdbSymUid.cpp + PdbUtil.cpp + SymbolFileNativePDB.cpp + UdtRecordCompleter.cpp + + LINK_LIBS + clangAST + clangLex + lldbCore + lldbSymbol + lldbUtility + LINK_COMPONENTS + DebugInfoCodeView + DebugInfoPDB + Support + ) diff --git a/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp b/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp new file mode 100644 index 000000000000..67ea05767fde --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp @@ -0,0 +1,217 @@ +//===-- CompileUnitIndex.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CompileUnitIndex.h" + +#include "PdbIndex.h" +#include "PdbUtil.h" + +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Support/Path.h" + +#include "lldb/Utility/LLDBAssert.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::npdb; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static bool IsMainFile(llvm::StringRef main, llvm::StringRef other) { + if (main == other) + return true; + + // If the files refer to the local file system, we can just ask the file + // system if they're equivalent. But if the source isn't present on disk + // then we still want to try. + if (llvm::sys::fs::equivalent(main, other)) + return true; + + llvm::SmallString<64> normalized(other); + llvm::sys::path::native(normalized); + return main.equals_lower(normalized); +} + +static void ParseCompile3(const CVSymbol &sym, CompilandIndexItem &cci) { + cci.m_compile_opts.emplace(); + llvm::cantFail( + SymbolDeserializer::deserializeAs<Compile3Sym>(sym, *cci.m_compile_opts)); +} + +static void ParseObjname(const CVSymbol &sym, CompilandIndexItem &cci) { + cci.m_obj_name.emplace(); + llvm::cantFail( + SymbolDeserializer::deserializeAs<ObjNameSym>(sym, *cci.m_obj_name)); +} + +static void ParseBuildInfo(PdbIndex &index, const CVSymbol &sym, + CompilandIndexItem &cci) { + BuildInfoSym bis(SymbolRecordKind::BuildInfoSym); + llvm::cantFail(SymbolDeserializer::deserializeAs<BuildInfoSym>(sym, bis)); + + // S_BUILDINFO just points to an LF_BUILDINFO in the IPI stream. Let's do + // a little extra work to pull out the LF_BUILDINFO. + LazyRandomTypeCollection &types = index.ipi().typeCollection(); + llvm::Optional<CVType> cvt = types.tryGetType(bis.BuildId); + + if (!cvt || cvt->kind() != LF_BUILDINFO) + return; + + BuildInfoRecord bir; + llvm::cantFail(TypeDeserializer::deserializeAs<BuildInfoRecord>(*cvt, bir)); + cci.m_build_info.assign(bir.ArgIndices.begin(), bir.ArgIndices.end()); +} + +static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item) { + const CVSymbolArray &syms = item.m_debug_stream.getSymbolArray(); + + // This is a private function, it shouldn't be called if the information + // has already been parsed. + lldbassert(!item.m_obj_name); + lldbassert(!item.m_compile_opts); + lldbassert(item.m_build_info.empty()); + + // We're looking for 3 things. S_COMPILE3, S_OBJNAME, and S_BUILDINFO. + int found = 0; + for (const CVSymbol &sym : syms) { + switch (sym.kind()) { + case S_COMPILE3: + ParseCompile3(sym, item); + break; + case S_OBJNAME: + ParseObjname(sym, item); + break; + case S_BUILDINFO: + ParseBuildInfo(index, sym, item); + break; + default: + continue; + } + if (++found >= 3) + break; + } +} + +CompilandIndexItem::CompilandIndexItem( + PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream, + llvm::pdb::DbiModuleDescriptor descriptor) + : m_id(id), m_debug_stream(std::move(debug_stream)), + m_module_descriptor(std::move(descriptor)) {} + +CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) { + auto result = m_comp_units.try_emplace(modi, nullptr); + if (!result.second) + return *result.first->second; + + // Find the module list and load its debug information stream and cache it + // since we need to use it for almost all interesting operations. + const DbiModuleList &modules = m_index.dbi().modules(); + llvm::pdb::DbiModuleDescriptor descriptor = modules.getModuleDescriptor(modi); + uint16_t stream = descriptor.getModuleStreamIndex(); + std::unique_ptr<llvm::msf::MappedBlockStream> stream_data = + m_index.pdb().createIndexedStream(stream); + llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor, + std::move(stream_data)); + cantFail(debug_stream.reload()); + + std::unique_ptr<CompilandIndexItem> &cci = result.first->second; + + cci = llvm::make_unique<CompilandIndexItem>( + PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor)); + ParseExtendedInfo(m_index, *cci); + + cci->m_strings.initialize(debug_stream.getSubsectionsArray()); + PDBStringTable &strings = cantFail(m_index.pdb().getStringTable()); + cci->m_strings.setStrings(strings.getStringTable()); + + // We want the main source file to always comes first. Note that we can't + // just push_back the main file onto the front because `GetMainSourceFile` + // computes it in such a way that it doesn't own the resulting memory. So we + // have to iterate the module file list comparing each one to the main file + // 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(); + llvm::sys::path::native(main_file); + + uint32_t file_count = modules.getSourceFileCount(modi); + cci->m_file_list.reserve(file_count); + bool found_main_file = false; + for (llvm::StringRef file : modules.source_files(modi)) { + if (!found_main_file && IsMainFile(main_file, file)) { + cci->m_file_list.insert(cci->m_file_list.begin(), file); + found_main_file = true; + continue; + } + cci->m_file_list.push_back(file); + } + + return *cci; +} + +const CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) const { + auto iter = m_comp_units.find(modi); + if (iter == m_comp_units.end()) + return nullptr; + return iter->second.get(); +} + +CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) { + auto iter = m_comp_units.find(modi); + if (iter == m_comp_units.end()) + return nullptr; + return iter->second.get(); +} + +llvm::SmallString<64> +CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const { + // LF_BUILDINFO contains a list of arg indices which point to LF_STRING_ID + // records in the IPI stream. The order of the arg indices is as follows: + // [0] - working directory where compiler was invoked. + // [1] - absolute path to compiler binary + // [2] - source file name + // [3] - path to compiler generated PDB (the /Zi PDB, although this entry gets + // added even when using /Z7) + // [4] - full command line invocation. + // + // We need to form the path [0]\[2] to generate the full path to the main + // file.source + if (item.m_build_info.size() < 3) + return {""}; + + LazyRandomTypeCollection &types = m_index.ipi().typeCollection(); + + StringIdRecord working_dir; + StringIdRecord file_name; + CVType dir_cvt = types.getType(item.m_build_info[0]); + CVType file_cvt = types.getType(item.m_build_info[2]); + llvm::cantFail( + TypeDeserializer::deserializeAs<StringIdRecord>(dir_cvt, working_dir)); + llvm::cantFail( + TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name)); + + llvm::sys::path::Style style = working_dir.String.startswith("/") + ? llvm::sys::path::Style::posix + : llvm::sys::path::Style::windows; + if (llvm::sys::path::is_absolute(file_name.String, style)) + return file_name.String; + + llvm::SmallString<64> absolute_path = working_dir.String; + llvm::sys::path::append(absolute_path, file_name.String); + return absolute_path; +} diff --git a/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h b/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h new file mode 100644 index 000000000000..c965870da44b --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h @@ -0,0 +1,95 @@ +//===-- CompileUnitIndex.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_COMPILEUNITINDEX_H +#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_COMPILEUNITINDEX_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +#include "PdbSymUid.h" + +#include <map> +#include <memory> + +namespace lldb_private { + +namespace npdb { +class PdbIndex; + +/// Represents a single compile unit. This class is useful for collecting the +/// important accessors and information about a compile unit from disparate +/// parts of the PDB into a single place, simplifying acess to compile unit +/// information for the callers. +struct CompilandIndexItem { + CompilandIndexItem(PdbCompilandId m_id, + llvm::pdb::ModuleDebugStreamRef debug_stream, + llvm::pdb::DbiModuleDescriptor descriptor); + + // index of this compile unit. + PdbCompilandId m_id; + + // debug stream. + llvm::pdb::ModuleDebugStreamRef m_debug_stream; + + // dbi module descriptor. + llvm::pdb::DbiModuleDescriptor m_module_descriptor; + + llvm::codeview::StringsAndChecksumsRef m_strings; + + // List of files which contribute to this compiland. + std::vector<llvm::StringRef> m_file_list; + + // Maps virtual address to global symbol id, which can then be used to + // locate the exact compile unit and offset of the symbol. Note that this + // is intentionally an ordered map so that we can find all symbols up to a + // given starting address. + std::map<lldb::addr_t, PdbSymUid> m_symbols_by_va; + + // S_COMPILE3 sym describing compilation settings for the module. + llvm::Optional<llvm::codeview::Compile3Sym> m_compile_opts; + + // S_OBJNAME sym describing object name. + llvm::Optional<llvm::codeview::ObjNameSym> m_obj_name; + + // LF_BUILDINFO sym describing source file name, working directory, + // command line, etc. This usually contains exactly 5 items which + // are references to other strings. + llvm::SmallVector<llvm::codeview::TypeIndex, 5> m_build_info; +}; + +/// Indexes information about all compile units. This is really just a map of +/// global compile unit index to |CompilandIndexItem| structures. +class CompileUnitIndex { + PdbIndex &m_index; + llvm::DenseMap<uint16_t, std::unique_ptr<CompilandIndexItem>> m_comp_units; + +public: + explicit CompileUnitIndex(PdbIndex &index) : m_index(index) {} + + CompilandIndexItem &GetOrCreateCompiland(uint16_t modi); + + const CompilandIndexItem *GetCompiland(uint16_t modi) const; + + CompilandIndexItem *GetCompiland(uint16_t modi); + + llvm::SmallString<64> GetMainSourceFile(const CompilandIndexItem &item) const; +}; +} // namespace npdb +} // namespace lldb_private + +#endif diff --git a/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp b/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp new file mode 100644 index 000000000000..7b62530e4680 --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp @@ -0,0 +1,673 @@ +//===-- DWARFLocationExpression.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFLocationExpression.h" + +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/StreamBuffer.h" +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" + +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Support/Endian.h" + +#include "PdbUtil.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::npdb; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static const uint32_t g_code_view_to_lldb_registers_x86[] = { + LLDB_INVALID_REGNUM, // NONE + lldb_al_i386, // AL + lldb_cl_i386, // CL + lldb_dl_i386, // DL + lldb_bl_i386, // BL + lldb_ah_i386, // AH + lldb_ch_i386, // CH + lldb_dh_i386, // DH + lldb_bh_i386, // BH + lldb_ax_i386, // AX + lldb_cx_i386, // CX + lldb_dx_i386, // DX + lldb_bx_i386, // BX + lldb_sp_i386, // SP + lldb_bp_i386, // BP + lldb_si_i386, // SI + lldb_di_i386, // DI + lldb_eax_i386, // EAX + lldb_ecx_i386, // ECX + lldb_edx_i386, // EDX + lldb_ebx_i386, // EBX + lldb_esp_i386, // ESP + lldb_ebp_i386, // EBP + lldb_esi_i386, // ESI + lldb_edi_i386, // EDI + lldb_es_i386, // ES + lldb_cs_i386, // CS + lldb_ss_i386, // SS + lldb_ds_i386, // DS + lldb_fs_i386, // FS + lldb_gs_i386, // GS + LLDB_INVALID_REGNUM, // IP + LLDB_INVALID_REGNUM, // FLAGS + lldb_eip_i386, // EIP + lldb_eflags_i386, // EFLAGS + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // TEMP + LLDB_INVALID_REGNUM, // TEMPH + LLDB_INVALID_REGNUM, // QUOTE + LLDB_INVALID_REGNUM, // PCDR3 + LLDB_INVALID_REGNUM, // PCDR4 + LLDB_INVALID_REGNUM, // PCDR5 + LLDB_INVALID_REGNUM, // PCDR6 + LLDB_INVALID_REGNUM, // PCDR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CR0 + LLDB_INVALID_REGNUM, // CR1 + LLDB_INVALID_REGNUM, // CR2 + LLDB_INVALID_REGNUM, // CR3 + LLDB_INVALID_REGNUM, // CR4 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_dr0_i386, // DR0 + lldb_dr1_i386, // DR1 + lldb_dr2_i386, // DR2 + lldb_dr3_i386, // DR3 + lldb_dr4_i386, // DR4 + lldb_dr5_i386, // DR5 + lldb_dr6_i386, // DR6 + lldb_dr7_i386, // DR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // GDTR + LLDB_INVALID_REGNUM, // GDTL + LLDB_INVALID_REGNUM, // IDTR + LLDB_INVALID_REGNUM, // IDTL + LLDB_INVALID_REGNUM, // LDTR + LLDB_INVALID_REGNUM, // TR + LLDB_INVALID_REGNUM, // PSEUDO1 + LLDB_INVALID_REGNUM, // PSEUDO2 + LLDB_INVALID_REGNUM, // PSEUDO3 + LLDB_INVALID_REGNUM, // PSEUDO4 + LLDB_INVALID_REGNUM, // PSEUDO5 + LLDB_INVALID_REGNUM, // PSEUDO6 + LLDB_INVALID_REGNUM, // PSEUDO7 + LLDB_INVALID_REGNUM, // PSEUDO8 + LLDB_INVALID_REGNUM, // PSEUDO9 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_st0_i386, // ST0 + lldb_st1_i386, // ST1 + lldb_st2_i386, // ST2 + lldb_st3_i386, // ST3 + lldb_st4_i386, // ST4 + lldb_st5_i386, // ST5 + lldb_st6_i386, // ST6 + lldb_st7_i386, // ST7 + LLDB_INVALID_REGNUM, // CTRL + LLDB_INVALID_REGNUM, // STAT + LLDB_INVALID_REGNUM, // TAG + LLDB_INVALID_REGNUM, // FPIP + LLDB_INVALID_REGNUM, // FPCS + LLDB_INVALID_REGNUM, // FPDO + LLDB_INVALID_REGNUM, // FPDS + LLDB_INVALID_REGNUM, // ISEM + LLDB_INVALID_REGNUM, // FPEIP + LLDB_INVALID_REGNUM, // FPEDO + lldb_mm0_i386, // MM0 + lldb_mm1_i386, // MM1 + lldb_mm2_i386, // MM2 + lldb_mm3_i386, // MM3 + lldb_mm4_i386, // MM4 + lldb_mm5_i386, // MM5 + lldb_mm6_i386, // MM6 + lldb_mm7_i386, // MM7 + lldb_xmm0_i386, // XMM0 + lldb_xmm1_i386, // XMM1 + lldb_xmm2_i386, // XMM2 + lldb_xmm3_i386, // XMM3 + lldb_xmm4_i386, // XMM4 + lldb_xmm5_i386, // XMM5 + lldb_xmm6_i386, // XMM6 + lldb_xmm7_i386 // XMM7 +}; + +static const uint32_t g_code_view_to_lldb_registers_x86_64[] = { + LLDB_INVALID_REGNUM, // NONE + lldb_al_x86_64, // AL + lldb_cl_x86_64, // CL + lldb_dl_x86_64, // DL + lldb_bl_x86_64, // BL + lldb_ah_x86_64, // AH + lldb_ch_x86_64, // CH + lldb_dh_x86_64, // DH + lldb_bh_x86_64, // BH + lldb_ax_x86_64, // AX + lldb_cx_x86_64, // CX + lldb_dx_x86_64, // DX + lldb_bx_x86_64, // BX + lldb_sp_x86_64, // SP + lldb_bp_x86_64, // BP + lldb_si_x86_64, // SI + lldb_di_x86_64, // DI + lldb_eax_x86_64, // EAX + lldb_ecx_x86_64, // ECX + lldb_edx_x86_64, // EDX + lldb_ebx_x86_64, // EBX + lldb_esp_x86_64, // ESP + lldb_ebp_x86_64, // EBP + lldb_esi_x86_64, // ESI + lldb_edi_x86_64, // EDI + lldb_es_x86_64, // ES + lldb_cs_x86_64, // CS + lldb_ss_x86_64, // SS + lldb_ds_x86_64, // DS + lldb_fs_x86_64, // FS + lldb_gs_x86_64, // GS + LLDB_INVALID_REGNUM, // IP + LLDB_INVALID_REGNUM, // FLAGS + LLDB_INVALID_REGNUM, // EIP + LLDB_INVALID_REGNUM, // EFLAGS + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // TEMP + LLDB_INVALID_REGNUM, // TEMPH + LLDB_INVALID_REGNUM, // QUOTE + LLDB_INVALID_REGNUM, // PCDR3 + LLDB_INVALID_REGNUM, // PCDR4 + LLDB_INVALID_REGNUM, // PCDR5 + LLDB_INVALID_REGNUM, // PCDR6 + LLDB_INVALID_REGNUM, // PCDR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CR0 + LLDB_INVALID_REGNUM, // CR1 + LLDB_INVALID_REGNUM, // CR2 + LLDB_INVALID_REGNUM, // CR3 + LLDB_INVALID_REGNUM, // CR4 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_dr0_x86_64, // DR0 + lldb_dr1_x86_64, // DR1 + lldb_dr2_x86_64, // DR2 + lldb_dr3_x86_64, // DR3 + lldb_dr4_x86_64, // DR4 + lldb_dr5_x86_64, // DR5 + lldb_dr6_x86_64, // DR6 + lldb_dr7_x86_64, // DR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // GDTR + LLDB_INVALID_REGNUM, // GDTL + LLDB_INVALID_REGNUM, // IDTR + LLDB_INVALID_REGNUM, // IDTL + LLDB_INVALID_REGNUM, // LDTR + LLDB_INVALID_REGNUM, // TR + LLDB_INVALID_REGNUM, // PSEUDO1 + LLDB_INVALID_REGNUM, // PSEUDO2 + LLDB_INVALID_REGNUM, // PSEUDO3 + LLDB_INVALID_REGNUM, // PSEUDO4 + LLDB_INVALID_REGNUM, // PSEUDO5 + LLDB_INVALID_REGNUM, // PSEUDO6 + LLDB_INVALID_REGNUM, // PSEUDO7 + LLDB_INVALID_REGNUM, // PSEUDO8 + LLDB_INVALID_REGNUM, // PSEUDO9 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_st0_x86_64, // ST0 + lldb_st1_x86_64, // ST1 + lldb_st2_x86_64, // ST2 + lldb_st3_x86_64, // ST3 + lldb_st4_x86_64, // ST4 + lldb_st5_x86_64, // ST5 + lldb_st6_x86_64, // ST6 + lldb_st7_x86_64, // ST7 + LLDB_INVALID_REGNUM, // CTRL + LLDB_INVALID_REGNUM, // STAT + LLDB_INVALID_REGNUM, // TAG + LLDB_INVALID_REGNUM, // FPIP + LLDB_INVALID_REGNUM, // FPCS + LLDB_INVALID_REGNUM, // FPDO + LLDB_INVALID_REGNUM, // FPDS + LLDB_INVALID_REGNUM, // ISEM + LLDB_INVALID_REGNUM, // FPEIP + LLDB_INVALID_REGNUM, // FPEDO + lldb_mm0_x86_64, // MM0 + lldb_mm1_x86_64, // MM1 + lldb_mm2_x86_64, // MM2 + lldb_mm3_x86_64, // MM3 + lldb_mm4_x86_64, // MM4 + lldb_mm5_x86_64, // MM5 + lldb_mm6_x86_64, // MM6 + lldb_mm7_x86_64, // MM7 + lldb_xmm0_x86_64, // XMM0 + lldb_xmm1_x86_64, // XMM1 + lldb_xmm2_x86_64, // XMM2 + lldb_xmm3_x86_64, // XMM3 + lldb_xmm4_x86_64, // XMM4 + lldb_xmm5_x86_64, // XMM5 + lldb_xmm6_x86_64, // XMM6 + lldb_xmm7_x86_64, // XMM7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + lldb_mxcsr_x86_64, // MXCSR + LLDB_INVALID_REGNUM, // EDXEAX + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // EMM0L + LLDB_INVALID_REGNUM, // EMM1L + LLDB_INVALID_REGNUM, // EMM2L + LLDB_INVALID_REGNUM, // EMM3L + LLDB_INVALID_REGNUM, // EMM4L + LLDB_INVALID_REGNUM, // EMM5L + LLDB_INVALID_REGNUM, // EMM6L + LLDB_INVALID_REGNUM, // EMM7L + LLDB_INVALID_REGNUM, // EMM0H + LLDB_INVALID_REGNUM, // EMM1H + LLDB_INVALID_REGNUM, // EMM2H + LLDB_INVALID_REGNUM, // EMM3H + LLDB_INVALID_REGNUM, // EMM4H + LLDB_INVALID_REGNUM, // EMM5H + LLDB_INVALID_REGNUM, // EMM6H + LLDB_INVALID_REGNUM, // EMM7H + LLDB_INVALID_REGNUM, // MM00 + LLDB_INVALID_REGNUM, // MM01 + LLDB_INVALID_REGNUM, // MM10 + LLDB_INVALID_REGNUM, // MM11 + LLDB_INVALID_REGNUM, // MM20 + LLDB_INVALID_REGNUM, // MM21 + LLDB_INVALID_REGNUM, // MM30 + LLDB_INVALID_REGNUM, // MM31 + LLDB_INVALID_REGNUM, // MM40 + LLDB_INVALID_REGNUM, // MM41 + LLDB_INVALID_REGNUM, // MM50 + LLDB_INVALID_REGNUM, // MM51 + LLDB_INVALID_REGNUM, // MM60 + LLDB_INVALID_REGNUM, // MM61 + LLDB_INVALID_REGNUM, // MM70 + LLDB_INVALID_REGNUM, // MM71 + lldb_xmm8_x86_64, // XMM8 + lldb_xmm9_x86_64, // XMM9 + lldb_xmm10_x86_64, // XMM10 + lldb_xmm11_x86_64, // XMM11 + lldb_xmm12_x86_64, // XMM12 + lldb_xmm13_x86_64, // XMM13 + lldb_xmm14_x86_64, // XMM14 + lldb_xmm15_x86_64, // XMM15 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + lldb_sil_x86_64, // SIL + lldb_dil_x86_64, // DIL + lldb_bpl_x86_64, // BPL + lldb_spl_x86_64, // SPL + lldb_rax_x86_64, // RAX + lldb_rbx_x86_64, // RBX + lldb_rcx_x86_64, // RCX + lldb_rdx_x86_64, // RDX + lldb_rsi_x86_64, // RSI + lldb_rdi_x86_64, // RDI + lldb_rbp_x86_64, // RBP + lldb_rsp_x86_64, // RSP + lldb_r8_x86_64, // R8 + lldb_r9_x86_64, // R9 + lldb_r10_x86_64, // R10 + lldb_r11_x86_64, // R11 + lldb_r12_x86_64, // R12 + lldb_r13_x86_64, // R13 + lldb_r14_x86_64, // R14 + lldb_r15_x86_64, // R15 + lldb_r8l_x86_64, // R8B + lldb_r9l_x86_64, // R9B + lldb_r10l_x86_64, // R10B + lldb_r11l_x86_64, // R11B + lldb_r12l_x86_64, // R12B + lldb_r13l_x86_64, // R13B + lldb_r14l_x86_64, // R14B + lldb_r15l_x86_64, // R15B + lldb_r8w_x86_64, // R8W + lldb_r9w_x86_64, // R9W + lldb_r10w_x86_64, // R10W + lldb_r11w_x86_64, // R11W + lldb_r12w_x86_64, // R12W + lldb_r13w_x86_64, // R13W + lldb_r14w_x86_64, // R14W + lldb_r15w_x86_64, // R15W + lldb_r8d_x86_64, // R8D + lldb_r9d_x86_64, // R9D + lldb_r10d_x86_64, // R10D + lldb_r11d_x86_64, // R11D + lldb_r12d_x86_64, // R12D + lldb_r13d_x86_64, // R13D + lldb_r14d_x86_64, // R14D + lldb_r15d_x86_64, // R15D + lldb_ymm0_x86_64, // AMD64_YMM0 + lldb_ymm1_x86_64, // AMD64_YMM1 + lldb_ymm2_x86_64, // AMD64_YMM2 + lldb_ymm3_x86_64, // AMD64_YMM3 + lldb_ymm4_x86_64, // AMD64_YMM4 + lldb_ymm5_x86_64, // AMD64_YMM5 + lldb_ymm6_x86_64, // AMD64_YMM6 + lldb_ymm7_x86_64, // AMD64_YMM7 + lldb_ymm8_x86_64, // AMD64_YMM8 + lldb_ymm9_x86_64, // AMD64_YMM9 + lldb_ymm10_x86_64, // AMD64_YMM10 + lldb_ymm11_x86_64, // AMD64_YMM11 + lldb_ymm12_x86_64, // AMD64_YMM12 + lldb_ymm13_x86_64, // AMD64_YMM13 + lldb_ymm14_x86_64, // AMD64_YMM14 + lldb_ymm15_x86_64, // AMD64_YMM15 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_bnd0_x86_64, // BND0 + lldb_bnd1_x86_64, // BND1 + lldb_bnd2_x86_64 // BND2 +}; + +uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type, + llvm::codeview::RegisterId register_id) { + switch (arch_type) { + case llvm::Triple::x86: + if (static_cast<uint16_t>(register_id) < + sizeof(g_code_view_to_lldb_registers_x86) / + sizeof(g_code_view_to_lldb_registers_x86[0])) + return g_code_view_to_lldb_registers_x86[static_cast<uint16_t>( + register_id)]; + + switch (register_id) { + case llvm::codeview::RegisterId::MXCSR: + return lldb_mxcsr_i386; + case llvm::codeview::RegisterId::BND0: + return lldb_bnd0_i386; + case llvm::codeview::RegisterId::BND1: + return lldb_bnd1_i386; + case llvm::codeview::RegisterId::BND2: + return lldb_bnd2_i386; + default: + return LLDB_INVALID_REGNUM; + } + case llvm::Triple::x86_64: + if (static_cast<uint16_t>(register_id) < + sizeof(g_code_view_to_lldb_registers_x86_64) / + sizeof(g_code_view_to_lldb_registers_x86_64[0])) + return g_code_view_to_lldb_registers_x86_64[static_cast<uint16_t>( + register_id)]; + + return LLDB_INVALID_REGNUM; + default: + return LLDB_INVALID_REGNUM; + } +} + +uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) { + if (register_id == llvm::codeview::RegisterId::VFRAME) + return LLDB_REGNUM_GENERIC_FP; + + return LLDB_INVALID_REGNUM; +} + +static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type, + llvm::codeview::RegisterId register_id, + RegisterKind ®ister_kind) { + register_kind = eRegisterKindLLDB; + uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id); + if (reg_num != LLDB_INVALID_REGNUM) + return reg_num; + + register_kind = eRegisterKindGeneric; + return GetGenericRegisterNumber(register_id); +} + +static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) { + switch (kind) { + case SimpleTypeKind::Int128: + case SimpleTypeKind::Int64: + case SimpleTypeKind::Int64Quad: + case SimpleTypeKind::Int32: + case SimpleTypeKind::Int32Long: + case SimpleTypeKind::Int16: + case SimpleTypeKind::Int16Short: + case SimpleTypeKind::Float128: + case SimpleTypeKind::Float80: + case SimpleTypeKind::Float64: + case SimpleTypeKind::Float32: + case SimpleTypeKind::Float16: + case SimpleTypeKind::NarrowCharacter: + case SimpleTypeKind::SignedCharacter: + case SimpleTypeKind::SByte: + return true; + default: + return false; + } +} + +static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti, + TpiStream &tpi) { + if (ti.isSimple()) { + SimpleTypeKind stk = ti.getSimpleKind(); + return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)}; + } + + CVType cvt = tpi.getType(ti); + switch (cvt.kind()) { + case LF_MODIFIER: { + ModifierRecord mfr; + llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr)); + return GetIntegralTypeInfo(mfr.ModifiedType, tpi); + } + case LF_POINTER: { + PointerRecord pr; + llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr)); + return GetIntegralTypeInfo(pr.ReferentType, tpi); + } + case LF_ENUM: { + EnumRecord er; + llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er)); + return GetIntegralTypeInfo(er.UnderlyingType, tpi); + } + default: + assert(false && "Type is not integral!"); + return {0, false}; + } +} + +template <typename StreamWriter> +static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module, + StreamWriter &&writer) { + const ArchSpec &architecture = module->GetArchitecture(); + ByteOrder byte_order = architecture.GetByteOrder(); + uint32_t address_size = architecture.GetAddressByteSize(); + uint32_t byte_size = architecture.GetDataByteSize(); + if (byte_order == eByteOrderInvalid || address_size == 0) + return DWARFExpression(nullptr); + + RegisterKind register_kind = eRegisterKindDWARF; + StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order); + + if (!writer(stream, register_kind)) + return DWARFExpression(nullptr); + + DataBufferSP buffer = + std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize()); + DataExtractor extractor(buffer, byte_order, address_size, byte_size); + DWARFExpression result(module, extractor, nullptr, 0, buffer->GetByteSize()); + result.SetRegisterKind(register_kind); + + return result; +} + +static DWARFExpression MakeRegisterBasedLocationExpressionInternal( + llvm::codeview::RegisterId reg, llvm::Optional<int32_t> relative_offset, + lldb::ModuleSP module) { + return MakeLocationExpressionInternal( + module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { + uint32_t reg_num = GetRegisterNumber( + module->GetArchitecture().GetMachine(), reg, register_kind); + if (reg_num == LLDB_INVALID_REGNUM) + return false; + + if (reg_num > 31) { + llvm::dwarf::LocationAtom base = relative_offset + ? llvm::dwarf::DW_OP_bregx + : llvm::dwarf::DW_OP_regx; + stream.PutHex8(base); + stream.PutULEB128(reg_num); + } else { + llvm::dwarf::LocationAtom base = relative_offset + ? llvm::dwarf::DW_OP_breg0 + : llvm::dwarf::DW_OP_reg0; + stream.PutHex8(base + reg_num); + } + + if (relative_offset) + stream.PutSLEB128(*relative_offset); + + return true; + }); +} + +DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression( + llvm::codeview::RegisterId reg, lldb::ModuleSP module) { + return MakeRegisterBasedLocationExpressionInternal(reg, llvm::None, module); +} + +DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression( + llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) { + return MakeRegisterBasedLocationExpressionInternal(reg, offset, module); +} + +DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression( + uint16_t section, uint32_t offset, ModuleSP module) { + assert(section > 0); + assert(module); + + return MakeLocationExpressionInternal( + module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { + stream.PutHex8(llvm::dwarf::DW_OP_addr); + + SectionList *section_list = module->GetSectionList(); + assert(section_list); + + // Section indices in PDB are 1-based, but in DWARF they are 0-based, so + // we need to subtract 1. + uint32_t section_idx = section - 1; + if (section_idx >= section_list->GetSize()) + return false; + + auto section_ptr = section_list->GetSectionAtIndex(section_idx); + if (!section_ptr) + return false; + + stream.PutMaxHex64(section_ptr->GetFileAddress() + offset, + stream.GetAddressByteSize(), stream.GetByteOrder()); + + return true; + }); +} + +DWARFExpression lldb_private::npdb::MakeConstantLocationExpression( + TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant, + ModuleSP module) { + const ArchSpec &architecture = module->GetArchitecture(); + uint32_t address_size = architecture.GetAddressByteSize(); + + size_t size = 0; + bool is_signed = false; + std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi); + + union { + llvm::support::little64_t I; + llvm::support::ulittle64_t U; + } Value; + + std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>(); + buffer->SetByteSize(size); + + llvm::ArrayRef<uint8_t> bytes; + if (is_signed) { + Value.I = constant.getSExtValue(); + } else { + Value.U = constant.getZExtValue(); + } + + bytes = llvm::makeArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8) + .take_front(size); + buffer->CopyData(bytes.data(), size); + DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size); + DWARFExpression result(nullptr, extractor, nullptr, 0, size); + return result; +} diff --git a/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h b/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h new file mode 100644 index 000000000000..670e95ee8e3c --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h @@ -0,0 +1,42 @@ +//===-- DWARFLocationExpression.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H +#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H + +#include "lldb/lldb-forward.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" + +namespace llvm { +class APSInt; +namespace codeview { +class TypeIndex; +} +namespace pdb { +class TpiStream; +} +} // namespace llvm +namespace lldb_private { +namespace npdb { +DWARFExpression +MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg, + lldb::ModuleSP module); + +DWARFExpression MakeRegRelLocationExpression(llvm::codeview::RegisterId reg, + int32_t offset, + lldb::ModuleSP module); +DWARFExpression MakeGlobalLocationExpression(uint16_t section, uint32_t offset, + lldb::ModuleSP module); +DWARFExpression MakeConstantLocationExpression( + llvm::codeview::TypeIndex underlying_ti, llvm::pdb::TpiStream &tpi, + const llvm::APSInt &constant, lldb::ModuleSP module); +} // namespace npdb +} // namespace lldb_private + +#endif diff --git a/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp new file mode 100644 index 000000000000..8917fd092385 --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -0,0 +1,1348 @@ +#include "PdbAstBuilder.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/RecordName.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Demangle/MicrosoftDemangle.h" + +#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "lldb/Core/Module.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangUtil.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/LLDBAssert.h" + +#include "PdbUtil.h" +#include "UdtRecordCompleter.h" + +using namespace lldb_private; +using namespace lldb_private::npdb; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static llvm::Optional<PdbCompilandSymId> FindSymbolScope(PdbIndex &index, + PdbCompilandSymId id) { + CVSymbol sym = index.ReadSymbolRecord(id); + if (symbolOpensScope(sym.kind())) { + // If this exact symbol opens a scope, we can just directly access its + // parent. + id.offset = getScopeParentOffset(sym); + // Global symbols have parent offset of 0. Return llvm::None to indicate + // this. + if (id.offset == 0) + return llvm::None; + return id; + } + + // Otherwise we need to start at the beginning and iterate forward until we + // reach (or pass) this particular symbol + CompilandIndexItem &cii = index.compilands().GetOrCreateCompiland(id.modi); + const CVSymbolArray &syms = cii.m_debug_stream.getSymbolArray(); + + auto begin = syms.begin(); + auto end = syms.at(id.offset); + std::vector<PdbCompilandSymId> scope_stack; + + while (begin != end) { + if (id.offset == begin.offset()) { + // We have a match! Return the top of the stack + if (scope_stack.empty()) + return llvm::None; + return scope_stack.back(); + } + if (begin.offset() > id.offset) { + // We passed it. We couldn't even find this symbol record. + lldbassert(false && "Invalid compiland symbol id!"); + return llvm::None; + } + + // We haven't found the symbol yet. Check if we need to open or close the + // scope stack. + if (symbolOpensScope(begin->kind())) { + // We can use the end offset of the scope to determine whether or not + // we can just outright skip this entire scope. + uint32_t scope_end = getScopeEndOffset(*begin); + if (scope_end < id.modi) { + begin = syms.at(scope_end); + } else { + // The symbol we're looking for is somewhere in this scope. + scope_stack.emplace_back(id.modi, begin.offset()); + } + } else if (symbolEndsScope(begin->kind())) { + scope_stack.pop_back(); + } + ++begin; + } + + return llvm::None; +} + +static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) { + switch (cr.Kind) { + case TypeRecordKind::Class: + return clang::TTK_Class; + case TypeRecordKind::Struct: + return clang::TTK_Struct; + case TypeRecordKind::Union: + return clang::TTK_Union; + case TypeRecordKind::Interface: + return clang::TTK_Interface; + case TypeRecordKind::Enum: + return clang::TTK_Enum; + default: + lldbassert(false && "Invalid tag record kind!"); + return clang::TTK_Struct; + } +} + +static bool IsCVarArgsFunction(llvm::ArrayRef<TypeIndex> args) { + if (args.empty()) + return false; + return args.back() == TypeIndex::None(); +} + +static bool +AnyScopesHaveTemplateParams(llvm::ArrayRef<llvm::ms_demangle::Node *> scopes) { + for (llvm::ms_demangle::Node *n : scopes) { + auto *idn = static_cast<llvm::ms_demangle::IdentifierNode *>(n); + if (idn->TemplateParams) + return true; + } + return false; +} + +static ClangASTContext &GetClangASTContext(ObjectFile &obj) { + TypeSystem *ts = + obj.GetModule()->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + lldbassert(ts); + return static_cast<ClangASTContext &>(*ts); +} + +static llvm::Optional<clang::CallingConv> +TranslateCallingConvention(llvm::codeview::CallingConvention conv) { + using CC = llvm::codeview::CallingConvention; + switch (conv) { + + case CC::NearC: + case CC::FarC: + return clang::CallingConv::CC_C; + case CC::NearPascal: + case CC::FarPascal: + return clang::CallingConv::CC_X86Pascal; + case CC::NearFast: + case CC::FarFast: + return clang::CallingConv::CC_X86FastCall; + case CC::NearStdCall: + case CC::FarStdCall: + return clang::CallingConv::CC_X86StdCall; + case CC::ThisCall: + return clang::CallingConv::CC_X86ThisCall; + case CC::NearVector: + return clang::CallingConv::CC_X86VectorCall; + default: + return llvm::None; + } +} + +static llvm::Optional<CVTagRecord> +GetNestedTagDefinition(const NestedTypeRecord &Record, + const CVTagRecord &parent, TpiStream &tpi) { + // An LF_NESTTYPE is essentially a nested typedef / using declaration, but it + // is also used to indicate the primary definition of a nested class. That is + // to say, if you have: + // struct A { + // struct B {}; + // using C = B; + // }; + // Then in the debug info, this will appear as: + // LF_STRUCTURE `A::B` [type index = N] + // LF_STRUCTURE `A` + // LF_NESTTYPE [name = `B`, index = N] + // LF_NESTTYPE [name = `C`, index = N] + // In order to accurately reconstruct the decl context hierarchy, we need to + // know which ones are actual definitions and which ones are just aliases. + + // If it's a simple type, then this is something like `using foo = int`. + if (Record.Type.isSimple()) + return llvm::None; + + CVType cvt = tpi.getType(Record.Type); + + if (!IsTagRecord(cvt)) + return llvm::None; + + // If it's an inner definition, then treat whatever name we have here as a + // 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(); + if (qname.size() < 4 || child.asTag().getUniqueName().size() < 4) + return llvm::None; + + // qname[3] is the tag type identifier (struct, class, union, etc). Since the + // inner tag type is not necessarily the same as the outer tag type, re-write + // it to match the inner tag type. + qname[3] = child.asTag().getUniqueName()[3]; + std::string piece; + if (qname[3] == 'W') + piece = "4"; + piece += Record.Name; + piece.push_back('@'); + qname.insert(4, std::move(piece)); + if (qname != child.asTag().UniqueName) + return llvm::None; + + return std::move(child); +} + +PdbAstBuilder::PdbAstBuilder(ObjectFile &obj, PdbIndex &index) + : m_index(index), m_clang(GetClangASTContext(obj)) { + BuildParentMap(); +} + +clang::DeclContext &PdbAstBuilder::GetTranslationUnitDecl() { + return *m_clang.GetTranslationUnitDecl(); +} + +std::pair<clang::DeclContext *, std::string> +PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) { + // FIXME: Move this to GetDeclContextContainingUID. + if (!record.hasUniqueName()) + return CreateDeclInfoForUndecoratedName(record.Name); + + 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 {m_clang.GetTranslationUnitDecl(), record.UniqueName}; + + llvm::ms_demangle::IdentifierNode *idn = + ttn->QualifiedName->getUnqualifiedIdentifier(); + std::string uname = idn->toString(llvm::ms_demangle::OF_NoTagSpecifier); + + llvm::ms_demangle::NodeArrayNode *name_components = + ttn->QualifiedName->Components; + llvm::ArrayRef<llvm::ms_demangle::Node *> scopes(name_components->Nodes, + name_components->Count - 1); + + clang::DeclContext *context = m_clang.GetTranslationUnitDecl(); + + // If this type doesn't have a parent type in the debug info, then the best we + // can do is to say that it's either a series of namespaces (if the scope is + // non-empty), or the translation unit (if the scope is empty). + auto parent_iter = m_parent_types.find(ti); + if (parent_iter == m_parent_types.end()) { + if (scopes.empty()) + return {context, uname}; + + // If there is no parent in the debug info, but some of the scopes have + // template params, then this is a case of bad debug info. See, for + // example, llvm.org/pr39607. We don't want to create an ambiguity between + // 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}; + + for (llvm::ms_demangle::Node *scope : scopes) { + auto *nii = static_cast<llvm::ms_demangle::NamedIdentifierNode *>(scope); + std::string str = nii->toString(); + context = m_clang.GetUniqueNamespaceDeclaration(str.c_str(), context); + } + return {context, uname}; + } + + // Otherwise, all we need to do is get the parent type of this type and + // recurse into our lazy type creation / AST reconstruction logic to get an + // LLDB TypeSP for the parent. This will cause the AST to automatically get + // the right DeclContext created for any parent. + clang::QualType parent_qt = GetOrCreateType(parent_iter->second); + + context = clang::TagDecl::castToDeclContext(parent_qt->getAsTagDecl()); + return {context, uname}; +} + +void PdbAstBuilder::BuildParentMap() { + LazyRandomTypeCollection &types = m_index.tpi().typeCollection(); + + llvm::DenseMap<TypeIndex, TypeIndex> forward_to_full; + llvm::DenseMap<TypeIndex, TypeIndex> full_to_forward; + + struct RecordIndices { + TypeIndex forward; + TypeIndex full; + }; + + llvm::StringMap<RecordIndices> record_indices; + + for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) { + CVType type = types.getType(*ti); + if (!IsTagRecord(type)) + continue; + + CVTagRecord tag = CVTagRecord::create(type); + + RecordIndices &indices = record_indices[tag.asTag().getUniqueName()]; + if (tag.asTag().isForwardRef()) + indices.forward = *ti; + else + indices.full = *ti; + + if (indices.full != TypeIndex::None() && + indices.forward != TypeIndex::None()) { + forward_to_full[indices.forward] = indices.full; + full_to_forward[indices.full] = indices.forward; + } + + // We're looking for LF_NESTTYPE records in the field list, so ignore + // forward references (no field list), and anything without a nested class + // (since there won't be any LF_NESTTYPE records). + if (tag.asTag().isForwardRef() || !tag.asTag().containsNestedClass()) + continue; + + struct ProcessTpiStream : public TypeVisitorCallbacks { + ProcessTpiStream(PdbIndex &index, TypeIndex parent, + const CVTagRecord &parent_cvt, + llvm::DenseMap<TypeIndex, TypeIndex> &parents) + : index(index), parents(parents), parent(parent), + parent_cvt(parent_cvt) {} + + PdbIndex &index; + llvm::DenseMap<TypeIndex, TypeIndex> &parents; + + unsigned unnamed_type_index = 1; + TypeIndex parent; + const CVTagRecord &parent_cvt; + + llvm::Error visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Record) override { + std::string unnamed_type_name; + if (Record.Name.empty()) { + unnamed_type_name = + llvm::formatv("<unnamed-type-$S{0}>", unnamed_type_index).str(); + Record.Name = unnamed_type_name; + ++unnamed_type_index; + } + llvm::Optional<CVTagRecord> tag = + GetNestedTagDefinition(Record, parent_cvt, index.tpi()); + if (!tag) + return llvm::ErrorSuccess(); + + parents[Record.Type] = parent; + return llvm::ErrorSuccess(); + } + }; + + CVType field_list = m_index.tpi().getType(tag.asTag().FieldList); + ProcessTpiStream process(m_index, *ti, tag, m_parent_types); + llvm::Error error = visitMemberRecordStream(field_list.data(), process); + if (error) + llvm::consumeError(std::move(error)); + } + + // Now that we know the forward -> full mapping of all type indices, we can + // re-write all the indices. At the end of this process, we want a mapping + // consisting of fwd -> full and full -> full for all child -> parent indices. + // We can re-write the values in place, but for the keys, we must save them + // off so that we don't modify the map in place while also iterating it. + std::vector<TypeIndex> full_keys; + std::vector<TypeIndex> fwd_keys; + for (auto &entry : m_parent_types) { + TypeIndex key = entry.first; + TypeIndex value = entry.second; + + auto iter = forward_to_full.find(value); + if (iter != forward_to_full.end()) + entry.second = iter->second; + + iter = forward_to_full.find(key); + if (iter != forward_to_full.end()) + fwd_keys.push_back(key); + else + full_keys.push_back(key); + } + for (TypeIndex fwd : fwd_keys) { + TypeIndex full = forward_to_full[fwd]; + m_parent_types[full] = m_parent_types[fwd]; + } + for (TypeIndex full : full_keys) { + TypeIndex fwd = full_to_forward[full]; + m_parent_types[fwd] = m_parent_types[full]; + } + + // Now that +} + +static bool isLocalVariableType(SymbolKind K) { + switch (K) { + case S_REGISTER: + case S_REGREL32: + case S_LOCAL: + return true; + default: + break; + } + return false; +} + +static std::string +RenderScopeList(llvm::ArrayRef<llvm::ms_demangle::Node *> nodes) { + lldbassert(!nodes.empty()); + + std::string result = nodes.front()->toString(); + nodes = nodes.drop_front(); + while (!nodes.empty()) { + result += "::"; + result += nodes.front()->toString(llvm::ms_demangle::OF_NoTagSpecifier); + nodes = nodes.drop_front(); + } + return result; +} + +static llvm::Optional<PublicSym32> FindPublicSym(const SegmentOffset &addr, + SymbolStream &syms, + PublicsStream &publics) { + llvm::FixedStreamArray<ulittle32_t> addr_map = publics.getAddressMap(); + auto iter = std::lower_bound( + addr_map.begin(), addr_map.end(), addr, + [&](const ulittle32_t &x, const SegmentOffset &y) { + CVSymbol s1 = syms.readRecord(x); + lldbassert(s1.kind() == S_PUB32); + PublicSym32 p1; + llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(s1, p1)); + if (p1.Segment < y.segment) + return true; + return p1.Offset < y.offset; + }); + if (iter == addr_map.end()) + return llvm::None; + CVSymbol sym = syms.readRecord(*iter); + lldbassert(sym.kind() == S_PUB32); + PublicSym32 p; + llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym, p)); + if (p.Segment == addr.segment && p.Offset == addr.offset) + return p; + return llvm::None; +} + +clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) { + CVSymbol cvs = m_index.ReadSymbolRecord(id); + + if (isLocalVariableType(cvs.kind())) { + clang::DeclContext *scope = GetParentDeclContext(id); + clang::Decl *scope_decl = clang::Decl::castFromDeclContext(scope); + PdbCompilandSymId scope_id(id.modi, m_decl_to_status[scope_decl].uid); + return GetOrCreateVariableDecl(scope_id, id); + } + + switch (cvs.kind()) { + case S_GPROC32: + case S_LPROC32: + return GetOrCreateFunctionDecl(id); + case S_GDATA32: + case S_LDATA32: + case S_GTHREAD32: + case S_CONSTANT: + // global variable + return nullptr; + case S_BLOCK32: + return GetOrCreateBlockDecl(id); + default: + return nullptr; + } +} + +clang::Decl *PdbAstBuilder::GetOrCreateDeclForUid(PdbSymUid uid) { + if (clang::Decl *result = TryGetDecl(uid)) + return result; + + clang::Decl *result = nullptr; + switch (uid.kind()) { + case PdbSymUidKind::CompilandSym: + result = GetOrCreateSymbolForId(uid.asCompilandSym()); + break; + case PdbSymUidKind::Type: { + clang::QualType qt = GetOrCreateType(uid.asTypeSym()); + if (auto *tag = qt->getAsTagDecl()) { + result = tag; + break; + } + return nullptr; + } + default: + return nullptr; + } + m_uid_to_decl[toOpaqueUid(uid)] = result; + return result; +} + +clang::DeclContext *PdbAstBuilder::GetOrCreateDeclContextForUid(PdbSymUid uid) { + if (uid.kind() == PdbSymUidKind::CompilandSym) { + if (uid.asCompilandSym().offset == 0) + return &GetTranslationUnitDecl(); + } + + clang::Decl *decl = GetOrCreateDeclForUid(uid); + if (!decl) + return nullptr; + + return clang::Decl::castToDeclContext(decl); +} + +std::pair<clang::DeclContext *, std::string> +PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) { + MSVCUndecoratedNameParser parser(name); + llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers(); + + clang::DeclContext *context = &GetTranslationUnitDecl(); + + llvm::StringRef uname = specs.back().GetBaseName(); + specs = specs.drop_back(); + if (specs.empty()) + return {context, name}; + + llvm::StringRef scope_name = specs.back().GetFullName(); + + // It might be a class name, try that first. + std::vector<TypeIndex> types = m_index.tpi().findRecordsByName(scope_name); + while (!types.empty()) { + clang::QualType qt = GetOrCreateType(types.back()); + clang::TagDecl *tag = qt->getAsTagDecl(); + if (tag) + return {clang::TagDecl::castToDeclContext(tag), uname}; + types.pop_back(); + } + + // If that fails, treat it as a series of namespaces. + for (const MSVCUndecoratedNameSpecifier &spec : specs) { + std::string ns_name = spec.GetBaseName().str(); + context = m_clang.GetUniqueNamespaceDeclaration(ns_name.c_str(), context); + } + return {context, uname}; +} + +clang::DeclContext * +PdbAstBuilder::GetParentDeclContextForSymbol(const CVSymbol &sym) { + if (!SymbolHasAddress(sym)) + return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first; + SegmentOffset addr = GetSegmentAndOffset(sym); + llvm::Optional<PublicSym32> pub = + FindPublicSym(addr, m_index.symrecords(), m_index.publics()); + if (!pub) + return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first; + + llvm::ms_demangle::Demangler demangler; + StringView name{pub->Name.begin(), pub->Name.size()}; + llvm::ms_demangle::SymbolNode *node = demangler.parse(name); + if (!node) + return &GetTranslationUnitDecl(); + llvm::ArrayRef<llvm::ms_demangle::Node *> name_components{ + node->Name->Components->Nodes, node->Name->Components->Count - 1}; + + if (!name_components.empty()) { + // Render the current list of scope nodes as a fully qualified name, and + // look it up in the debug info as a type name. If we find something, + // this is a type (which may itself be prefixed by a namespace). If we + // don't, this is a list of namespaces. + std::string qname = RenderScopeList(name_components); + std::vector<TypeIndex> matches = m_index.tpi().findRecordsByName(qname); + while (!matches.empty()) { + clang::QualType qt = GetOrCreateType(matches.back()); + clang::TagDecl *tag = qt->getAsTagDecl(); + if (tag) + return clang::TagDecl::castToDeclContext(tag); + matches.pop_back(); + } + } + + // It's not a type. It must be a series of namespaces. + clang::DeclContext *context = &GetTranslationUnitDecl(); + while (!name_components.empty()) { + std::string ns = name_components.front()->toString(); + context = m_clang.GetUniqueNamespaceDeclaration(ns.c_str(), context); + name_components = name_components.drop_front(); + } + return context; +} + +clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) { + // We must do this *without* calling GetOrCreate on the current uid, as + // that would be an infinite recursion. + switch (uid.kind()) { + case PdbSymUidKind::CompilandSym: { + llvm::Optional<PdbCompilandSymId> scope = + FindSymbolScope(m_index, uid.asCompilandSym()); + if (scope) + return GetOrCreateDeclContextForUid(*scope); + + CVSymbol sym = m_index.ReadSymbolRecord(uid.asCompilandSym()); + return GetParentDeclContextForSymbol(sym); + } + case PdbSymUidKind::Type: { + // It could be a namespace, class, or global. We don't support nested + // functions yet. Anyway, we just need to consult the parent type map. + PdbTypeSymId type_id = uid.asTypeSym(); + auto iter = m_parent_types.find(type_id.index); + if (iter == m_parent_types.end()) + return &GetTranslationUnitDecl(); + return GetOrCreateDeclContextForUid(PdbTypeSymId(iter->second)); + } + case PdbSymUidKind::FieldListMember: + // In this case the parent DeclContext is the one for the class that this + // member is inside of. + break; + case PdbSymUidKind::GlobalSym: { + // If this refers to a compiland symbol, just recurse in with that symbol. + // The only other possibilities are S_CONSTANT and S_UDT, in which case we + // need to parse the undecorated name to figure out the scope, then look + // that up in the TPI stream. If it's found, it's a type, othewrise it's + // a series of namespaces. + // FIXME: do this. + CVSymbol global = m_index.ReadSymbolRecord(uid.asGlobalSym()); + switch (global.kind()) { + case SymbolKind::S_GDATA32: + case SymbolKind::S_LDATA32: + return GetParentDeclContextForSymbol(global); + case SymbolKind::S_PROCREF: + case SymbolKind::S_LPROCREF: { + ProcRefSym ref{global.kind()}; + llvm::cantFail( + SymbolDeserializer::deserializeAs<ProcRefSym>(global, ref)); + PdbCompilandSymId cu_sym_id{ref.modi(), ref.SymOffset}; + return GetParentDeclContext(cu_sym_id); + } + case SymbolKind::S_CONSTANT: + case SymbolKind::S_UDT: + return CreateDeclInfoForUndecoratedName(getSymbolName(global)).first; + default: + break; + } + break; + } + default: + break; + } + return &GetTranslationUnitDecl(); +} + +bool PdbAstBuilder::CompleteType(clang::QualType qt) { + clang::TagDecl *tag = qt->getAsTagDecl(); + if (!tag) + return false; + + return CompleteTagDecl(*tag); +} + +bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) { + // If this is not in our map, it's an error. + auto status_iter = m_decl_to_status.find(&tag); + lldbassert(status_iter != m_decl_to_status.end()); + + // If it's already complete, just return. + DeclStatus &status = status_iter->second; + if (status.resolved) + return true; + + PdbTypeSymId type_id = PdbSymUid(status.uid).asTypeSym(); + + lldbassert(IsTagRecord(type_id, m_index.tpi())); + + clang::QualType tag_qt = m_clang.getASTContext()->getTypeDeclType(&tag); + ClangASTContext::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false); + + TypeIndex tag_ti = type_id.index; + CVType cvt = m_index.tpi().getType(tag_ti); + if (cvt.kind() == LF_MODIFIER) + tag_ti = LookThroughModifierRecord(cvt); + + PdbTypeSymId best_ti = GetBestPossibleDecl(tag_ti, m_index.tpi()); + cvt = m_index.tpi().getType(best_ti.index); + lldbassert(IsTagRecord(cvt)); + + if (IsForwardRefUdt(cvt)) { + // If we can't find a full decl for this forward ref anywhere in the debug + // info, then we have no way to complete it. + return false; + } + + TypeIndex field_list_ti = GetFieldListIndex(cvt); + CVType field_list_cvt = m_index.tpi().getType(field_list_ti); + if (field_list_cvt.kind() != LF_FIELDLIST) + return false; + + // 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()); + auto error = + llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer); + completer.complete(); + + status.resolved = true; + if (!error) + return true; + + llvm::consumeError(std::move(error)); + return false; +} + +clang::QualType PdbAstBuilder::CreateSimpleType(TypeIndex ti) { + if (ti == TypeIndex::NullptrT()) + return GetBasicType(lldb::eBasicTypeNullPtr); + + if (ti.getSimpleMode() != SimpleTypeMode::Direct) { + clang::QualType direct_type = GetOrCreateType(ti.makeDirect()); + return m_clang.getASTContext()->getPointerType(direct_type); + } + + if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated) + return {}; + + lldb::BasicType bt = GetCompilerTypeForSimpleKind(ti.getSimpleKind()); + if (bt == lldb::eBasicTypeInvalid) + return {}; + + return GetBasicType(bt); +} + +clang::QualType PdbAstBuilder::CreatePointerType(const PointerRecord &pointer) { + clang::QualType pointee_type = GetOrCreateType(pointer.ReferentType); + + // This can happen for pointers to LF_VTSHAPE records, which we shouldn't + // create in the AST. + if (pointee_type.isNull()) + return {}; + + if (pointer.isPointerToMember()) { + MemberPointerInfo mpi = pointer.getMemberInfo(); + clang::QualType class_type = GetOrCreateType(mpi.ContainingType); + + return m_clang.getASTContext()->getMemberPointerType( + pointee_type, class_type.getTypePtr()); + } + + clang::QualType pointer_type; + if (pointer.getMode() == PointerMode::LValueReference) + pointer_type = + m_clang.getASTContext()->getLValueReferenceType(pointee_type); + else if (pointer.getMode() == PointerMode::RValueReference) + pointer_type = + m_clang.getASTContext()->getRValueReferenceType(pointee_type); + else + pointer_type = m_clang.getASTContext()->getPointerType(pointee_type); + + if ((pointer.getOptions() & PointerOptions::Const) != PointerOptions::None) + pointer_type.addConst(); + + if ((pointer.getOptions() & PointerOptions::Volatile) != PointerOptions::None) + pointer_type.addVolatile(); + + if ((pointer.getOptions() & PointerOptions::Restrict) != PointerOptions::None) + pointer_type.addRestrict(); + + return pointer_type; +} + +clang::QualType +PdbAstBuilder::CreateModifierType(const ModifierRecord &modifier) { + clang::QualType unmodified_type = GetOrCreateType(modifier.ModifiedType); + if (unmodified_type.isNull()) + return {}; + + if ((modifier.Modifiers & ModifierOptions::Const) != ModifierOptions::None) + unmodified_type.addConst(); + if ((modifier.Modifiers & ModifierOptions::Volatile) != ModifierOptions::None) + unmodified_type.addVolatile(); + + return unmodified_type; +} + +clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id, + const TagRecord &record) { + clang::DeclContext *context = nullptr; + std::string uname; + std::tie(context, uname) = CreateDeclInfoForType(record, id.index); + clang::TagTypeKind ttk = TranslateUdtKind(record); + lldb::AccessType access = + (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; + + ClangASTMetadata metadata; + metadata.SetUserID(toOpaqueUid(id)); + metadata.SetIsDynamicCXXType(false); + + CompilerType ct = + m_clang.CreateRecordType(context, access, uname.c_str(), ttk, + lldb::eLanguageTypeC_plus_plus, &metadata); + + lldbassert(ct.IsValid()); + + ClangASTContext::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 + // ask us. + clang::QualType result = + clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); + + ClangASTContext::SetHasExternalStorage(result.getAsOpaquePtr(), true); + return result; +} + +clang::Decl *PdbAstBuilder::TryGetDecl(PdbSymUid uid) const { + auto iter = m_uid_to_decl.find(toOpaqueUid(uid)); + if (iter != m_uid_to_decl.end()) + return iter->second; + return nullptr; +} + +clang::NamespaceDecl * +PdbAstBuilder::GetOrCreateNamespaceDecl(llvm::StringRef name, + clang::DeclContext &context) { + return m_clang.GetUniqueNamespaceDeclaration(name.str().c_str(), &context); +} + +clang::BlockDecl * +PdbAstBuilder::GetOrCreateBlockDecl(PdbCompilandSymId block_id) { + if (clang::Decl *decl = TryGetDecl(block_id)) + return llvm::dyn_cast<clang::BlockDecl>(decl); + + clang::DeclContext *scope = GetParentDeclContext(block_id); + + clang::BlockDecl *block_decl = m_clang.CreateBlockDeclaration(scope); + m_uid_to_decl.insert({toOpaqueUid(block_id), block_decl}); + + DeclStatus status; + status.resolved = true; + status.uid = toOpaqueUid(block_id); + m_decl_to_status.insert({block_decl, status}); + + return block_decl; +} + +clang::VarDecl *PdbAstBuilder::CreateVariableDecl(PdbSymUid uid, CVSymbol sym, + clang::DeclContext &scope) { + VariableInfo var_info = GetVariableNameInfo(sym); + clang::QualType qt = GetOrCreateType(var_info.type); + + clang::VarDecl *var_decl = m_clang.CreateVariableDeclaration( + &scope, var_info.name.str().c_str(), qt); + + m_uid_to_decl[toOpaqueUid(uid)] = var_decl; + DeclStatus status; + status.resolved = true; + status.uid = toOpaqueUid(uid); + m_decl_to_status.insert({var_decl, status}); + return var_decl; +} + +clang::VarDecl * +PdbAstBuilder::GetOrCreateVariableDecl(PdbCompilandSymId scope_id, + PdbCompilandSymId var_id) { + if (clang::Decl *decl = TryGetDecl(var_id)) + return llvm::dyn_cast<clang::VarDecl>(decl); + + clang::DeclContext *scope = GetOrCreateDeclContextForUid(scope_id); + + CVSymbol sym = m_index.ReadSymbolRecord(var_id); + return CreateVariableDecl(PdbSymUid(var_id), sym, *scope); +} + +clang::VarDecl *PdbAstBuilder::GetOrCreateVariableDecl(PdbGlobalSymId var_id) { + if (clang::Decl *decl = TryGetDecl(var_id)) + return llvm::dyn_cast<clang::VarDecl>(decl); + + CVSymbol sym = m_index.ReadSymbolRecord(var_id); + return CreateVariableDecl(PdbSymUid(var_id), sym, GetTranslationUnitDecl()); +} + +clang::TypedefNameDecl * +PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) { + if (clang::Decl *decl = TryGetDecl(id)) + return llvm::dyn_cast<clang::TypedefNameDecl>(decl); + + CVSymbol sym = m_index.ReadSymbolRecord(id); + lldbassert(sym.kind() == S_UDT); + UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym)); + + clang::DeclContext *scope = GetParentDeclContext(id); + + PdbTypeSymId real_type_id{udt.Type, false}; + clang::QualType qt = GetOrCreateType(real_type_id); + + std::string uname = DropNameScope(udt.Name); + + CompilerType ct = m_clang.CreateTypedefType(ToCompilerType(qt), uname.c_str(), + ToCompilerDeclContext(*scope)); + clang::TypedefNameDecl *tnd = m_clang.GetAsTypedefDecl(ct); + DeclStatus status; + status.resolved = true; + status.uid = toOpaqueUid(id); + m_decl_to_status.insert({tnd, status}); + return tnd; +} + +clang::QualType PdbAstBuilder::GetBasicType(lldb::BasicType type) { + CompilerType ct = m_clang.GetBasicType(type); + return clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); +} + +clang::QualType PdbAstBuilder::CreateType(PdbTypeSymId type) { + if (type.index.isSimple()) + return CreateSimpleType(type.index); + + CVType cvt = m_index.tpi().getType(type.index); + + if (cvt.kind() == LF_MODIFIER) { + ModifierRecord modifier; + llvm::cantFail( + TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier)); + return CreateModifierType(modifier); + } + + if (cvt.kind() == LF_POINTER) { + PointerRecord pointer; + llvm::cantFail( + TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer)); + return CreatePointerType(pointer); + } + + if (IsTagRecord(cvt)) { + CVTagRecord tag = CVTagRecord::create(cvt); + if (tag.kind() == CVTagRecord::Union) + return CreateRecordType(type.index, tag.asUnion()); + if (tag.kind() == CVTagRecord::Enum) + return CreateEnumType(type.index, tag.asEnum()); + return CreateRecordType(type.index, tag.asClass()); + } + + if (cvt.kind() == LF_ARRAY) { + ArrayRecord ar; + llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar)); + return CreateArrayType(ar); + } + + if (cvt.kind() == LF_PROCEDURE) { + ProcedureRecord pr; + llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr)); + return CreateProcedureType(pr); + } + + return {}; +} + +clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) { + lldb::user_id_t uid = toOpaqueUid(type); + auto iter = m_uid_to_type.find(uid); + if (iter != m_uid_to_type.end()) + return iter->second; + + PdbTypeSymId best_type = GetBestPossibleDecl(type, m_index.tpi()); + + clang::QualType qt; + if (best_type.index != type.index) { + // This is a forward decl. Call GetOrCreate on the full decl, then map the + // forward decl id to the full decl QualType. + clang::QualType qt = GetOrCreateType(best_type); + m_uid_to_type[toOpaqueUid(type)] = qt; + return qt; + } + + // This is either a full decl, or a forward decl with no matching full decl + // in the debug info. + qt = CreateType(type); + m_uid_to_type[toOpaqueUid(type)] = qt; + if (IsTagRecord(type, m_index.tpi())) { + clang::TagDecl *tag = qt->getAsTagDecl(); + lldbassert(m_decl_to_status.count(tag) == 0); + + DeclStatus &status = m_decl_to_status[tag]; + status.uid = uid; + status.resolved = false; + } + return qt; +} + +clang::FunctionDecl * +PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { + if (clang::Decl *decl = TryGetDecl(func_id)) + return llvm::dyn_cast<clang::FunctionDecl>(decl); + + clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id)); + std::string context_name; + if (clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(parent)) { + context_name = ns->getQualifiedNameAsString(); + } else if (clang::TagDecl *tag = llvm::dyn_cast<clang::TagDecl>(parent)) { + context_name = tag->getQualifiedNameAsString(); + } + + CVSymbol cvs = m_index.ReadSymbolRecord(func_id); + ProcSym proc(static_cast<SymbolRecordKind>(cvs.kind())); + llvm::cantFail(SymbolDeserializer::deserializeAs<ProcSym>(cvs, proc)); + + PdbTypeSymId type_id(proc.FunctionType); + clang::QualType qt = GetOrCreateType(type_id); + if (qt.isNull()) + return nullptr; + + clang::StorageClass storage = clang::SC_None; + if (proc.Kind == SymbolRecordKind::ProcSym) + storage = clang::SC_Static; + + const clang::FunctionProtoType *func_type = + llvm::dyn_cast<clang::FunctionProtoType>(qt); + + CompilerType func_ct = ToCompilerType(qt); + + llvm::StringRef proc_name = proc.Name; + proc_name.consume_front(context_name); + proc_name.consume_front("::"); + + clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( + parent, 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; + DeclStatus status; + status.resolved = true; + status.uid = toOpaqueUid(func_id); + m_decl_to_status.insert({function_decl, status}); + + CreateFunctionParameters(func_id, *function_decl, func_type->getNumParams()); + + return function_decl; +} + +void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id, + clang::FunctionDecl &function_decl, + uint32_t param_count) { + CompilandIndexItem *cii = m_index.compilands().GetCompiland(func_id.modi); + CVSymbolArray scope = + cii->m_debug_stream.getSymbolArrayForScope(func_id.offset); + + auto begin = scope.begin(); + auto end = scope.end(); + std::vector<clang::ParmVarDecl *> params; + while (begin != end && param_count > 0) { + uint32_t record_offset = begin.offset(); + CVSymbol sym = *begin++; + + TypeIndex param_type; + llvm::StringRef param_name; + switch (sym.kind()) { + case S_REGREL32: { + RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); + cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg)); + param_type = reg.Type; + param_name = reg.Name; + break; + } + case S_REGISTER: { + RegisterSym reg(SymbolRecordKind::RegisterSym); + cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg)); + param_type = reg.Index; + param_name = reg.Name; + break; + } + case S_LOCAL: { + LocalSym local(SymbolRecordKind::LocalSym); + cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local)); + if ((local.Flags & LocalSymFlags::IsParameter) == LocalSymFlags::None) + continue; + param_type = local.Type; + param_name = local.Name; + break; + } + case S_BLOCK32: + // All parameters should come before the first block. If that isn't the + // case, then perhaps this is bad debug info that doesn't contain + // information about all parameters. + return; + default: + continue; + } + + PdbCompilandSymId param_uid(func_id.modi, record_offset); + clang::QualType qt = GetOrCreateType(param_type); + + CompilerType param_type_ct(&m_clang, qt.getAsOpaquePtr()); + clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration( + &function_decl, param_name.str().c_str(), param_type_ct, + clang::SC_None); + lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0); + + m_uid_to_decl[toOpaqueUid(param_uid)] = param; + params.push_back(param); + --param_count; + } + + if (!params.empty()) + m_clang.SetFunctionParameters(&function_decl, params.data(), params.size()); +} + +clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id, + const EnumRecord &er) { + clang::DeclContext *decl_context = nullptr; + std::string uname; + std::tie(decl_context, uname) = CreateDeclInfoForType(er, id.index); + clang::QualType underlying_type = GetOrCreateType(er.UnderlyingType); + + Declaration declaration; + CompilerType enum_ct = m_clang.CreateEnumerationType( + uname.c_str(), decl_context, declaration, ToCompilerType(underlying_type), + er.isScoped()); + + ClangASTContext::StartTagDeclarationDefinition(enum_ct); + ClangASTContext::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true); + + return clang::QualType::getFromOpaquePtr(enum_ct.GetOpaqueQualType()); +} + +clang::QualType PdbAstBuilder::CreateArrayType(const ArrayRecord &ar) { + clang::QualType element_type = GetOrCreateType(ar.ElementType); + + uint64_t element_count = + ar.Size / GetSizeOfType({ar.ElementType}, m_index.tpi()); + + CompilerType array_ct = m_clang.CreateArrayType(ToCompilerType(element_type), + element_count, false); + return clang::QualType::getFromOpaquePtr(array_ct.GetOpaqueQualType()); +} + +clang::QualType +PdbAstBuilder::CreateProcedureType(const ProcedureRecord &proc) { + TpiStream &stream = m_index.tpi(); + CVType args_cvt = stream.getType(proc.ArgumentList); + ArgListRecord args; + llvm::cantFail( + TypeDeserializer::deserializeAs<ArgListRecord>(args_cvt, args)); + + llvm::ArrayRef<TypeIndex> arg_indices = llvm::makeArrayRef(args.ArgIndices); + bool is_variadic = IsCVarArgsFunction(arg_indices); + if (is_variadic) + arg_indices = arg_indices.drop_back(); + + std::vector<CompilerType> arg_types; + arg_types.reserve(arg_indices.size()); + + for (TypeIndex arg_index : arg_indices) { + clang::QualType arg_type = GetOrCreateType(arg_index); + arg_types.push_back(ToCompilerType(arg_type)); + } + + clang::QualType return_type = GetOrCreateType(proc.ReturnType); + + llvm::Optional<clang::CallingConv> cc = + TranslateCallingConvention(proc.CallConv); + if (!cc) + return {}; + + CompilerType return_ct = ToCompilerType(return_type); + CompilerType func_sig_ast_type = m_clang.CreateFunctionType( + return_ct, arg_types.data(), arg_types.size(), is_variadic, 0, *cc); + + return clang::QualType::getFromOpaquePtr( + func_sig_ast_type.GetOpaqueQualType()); +} + +static bool isTagDecl(clang::DeclContext &context) { + return !!llvm::dyn_cast<clang::TagDecl>(&context); +} + +static bool isFunctionDecl(clang::DeclContext &context) { + return !!llvm::dyn_cast<clang::FunctionDecl>(&context); +} + +static bool isBlockDecl(clang::DeclContext &context) { + return !!llvm::dyn_cast<clang::BlockDecl>(&context); +} + +void PdbAstBuilder::ParseAllNamespacesPlusChildrenOf( + llvm::Optional<llvm::StringRef> parent) { + TypeIndex ti{m_index.tpi().TypeIndexBegin()}; + for (const CVType &cvt : m_index.tpi().typeArray()) { + PdbTypeSymId tid{ti}; + ++ti; + + if (!IsTagRecord(cvt)) + continue; + + CVTagRecord tag = CVTagRecord::create(cvt); + + if (!parent.hasValue()) { + clang::QualType qt = GetOrCreateType(tid); + CompleteType(qt); + continue; + } + + // Call CreateDeclInfoForType unconditionally so that the namespace info + // gets created. But only call CreateRecordType if the namespace name + // matches. + clang::DeclContext *context = nullptr; + std::string uname; + std::tie(context, uname) = CreateDeclInfoForType(tag.asTag(), tid.index); + if (!context->isNamespace()) + continue; + + clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(context); + std::string actual_ns = ns->getQualifiedNameAsString(); + if (llvm::StringRef(actual_ns).startswith(*parent)) { + clang::QualType qt = GetOrCreateType(tid); + CompleteType(qt); + continue; + } + } + + uint32_t module_count = m_index.dbi().modules().getModuleCount(); + for (uint16_t modi = 0; modi < module_count; ++modi) { + CompilandIndexItem &cii = m_index.compilands().GetOrCreateCompiland(modi); + const CVSymbolArray &symbols = cii.m_debug_stream.getSymbolArray(); + auto iter = symbols.begin(); + while (iter != symbols.end()) { + PdbCompilandSymId sym_id{modi, iter.offset()}; + + switch (iter->kind()) { + case S_GPROC32: + case S_LPROC32: + GetOrCreateFunctionDecl(sym_id); + iter = symbols.at(getScopeEndOffset(*iter)); + break; + case S_GDATA32: + case S_GTHREAD32: + case S_LDATA32: + case S_LTHREAD32: + GetOrCreateVariableDecl(PdbCompilandSymId(modi, 0), sym_id); + ++iter; + break; + default: + ++iter; + continue; + } + } + } +} + +static CVSymbolArray skipFunctionParameters(clang::Decl &decl, + const CVSymbolArray &symbols) { + clang::FunctionDecl *func_decl = llvm::dyn_cast<clang::FunctionDecl>(&decl); + if (!func_decl) + return symbols; + unsigned int params = func_decl->getNumParams(); + if (params == 0) + return symbols; + + CVSymbolArray result = symbols; + + while (!result.empty()) { + if (params == 0) + return result; + + CVSymbol sym = *result.begin(); + result.drop_front(); + + if (!isLocalVariableType(sym.kind())) + continue; + + --params; + } + return result; +} + +void PdbAstBuilder::ParseBlockChildren(PdbCompilandSymId block_id) { + CVSymbol sym = m_index.ReadSymbolRecord(block_id); + lldbassert(sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32 || + sym.kind() == S_BLOCK32); + CompilandIndexItem &cii = + m_index.compilands().GetOrCreateCompiland(block_id.modi); + CVSymbolArray symbols = + cii.m_debug_stream.getSymbolArrayForScope(block_id.offset); + + // Function parameters should already have been created when the function was + // parsed. + if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32) + symbols = + skipFunctionParameters(*m_uid_to_decl[toOpaqueUid(block_id)], symbols); + + auto begin = symbols.begin(); + while (begin != symbols.end()) { + PdbCompilandSymId child_sym_id(block_id.modi, begin.offset()); + GetOrCreateSymbolForId(child_sym_id); + if (begin->kind() == S_BLOCK32) { + ParseBlockChildren(child_sym_id); + begin = symbols.at(getScopeEndOffset(*begin)); + } + ++begin; + } +} + +void PdbAstBuilder::ParseDeclsForSimpleContext(clang::DeclContext &context) { + + clang::Decl *decl = clang::Decl::castFromDeclContext(&context); + lldbassert(decl); + + auto iter = m_decl_to_status.find(decl); + lldbassert(iter != m_decl_to_status.end()); + + if (auto *tag = llvm::dyn_cast<clang::TagDecl>(&context)) { + CompleteTagDecl(*tag); + return; + } + + if (isFunctionDecl(context) || isBlockDecl(context)) { + PdbCompilandSymId block_id = PdbSymUid(iter->second.uid).asCompilandSym(); + ParseBlockChildren(block_id); + } +} + +void PdbAstBuilder::ParseDeclsForContext(clang::DeclContext &context) { + // Namespaces aren't explicitly represented in the debug info, and the only + // way to parse them is to parse all type info, demangling every single type + // and trying to reconstruct the DeclContext hierarchy this way. Since this + // is an expensive operation, we have to special case it so that we do other + // work (such as parsing the items that appear within the namespaces) at the + // same time. + if (context.isTranslationUnit()) { + ParseAllNamespacesPlusChildrenOf(llvm::None); + return; + } + + if (context.isNamespace()) { + clang::NamespaceDecl &ns = *llvm::dyn_cast<clang::NamespaceDecl>(&context); + std::string qname = ns.getQualifiedNameAsString(); + ParseAllNamespacesPlusChildrenOf(llvm::StringRef{qname}); + return; + } + + if (isTagDecl(context) || isFunctionDecl(context) || isBlockDecl(context)) { + ParseDeclsForSimpleContext(context); + return; + } +} + +CompilerDecl PdbAstBuilder::ToCompilerDecl(clang::Decl &decl) { + return {&m_clang, &decl}; +} + +CompilerType PdbAstBuilder::ToCompilerType(clang::QualType qt) { + return {&m_clang, qt.getAsOpaquePtr()}; +} + +CompilerDeclContext +PdbAstBuilder::ToCompilerDeclContext(clang::DeclContext &context) { + return {&m_clang, &context}; +} + +clang::DeclContext * +PdbAstBuilder::FromCompilerDeclContext(CompilerDeclContext context) { + return static_cast<clang::DeclContext *>(context.GetOpaqueDeclContext()); +} + +void PdbAstBuilder::Dump(Stream &stream) { m_clang.Dump(stream); } diff --git a/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h new file mode 100644 index 000000000000..e3c0346f935e --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h @@ -0,0 +1,144 @@ +//===-- PdbAstBuilder.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H +#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" + +#include "lldb/Symbol/ClangASTImporter.h" + +#include "PdbIndex.h" +#include "PdbSymUid.h" + +namespace clang { +class TagDecl; +class DeclContext; +class Decl; +class QualType; +class FunctionDecl; +class NamespaceDecl; +} // namespace clang + +namespace llvm { +namespace codeview { +class ProcSym; +} +} // namespace llvm + +namespace lldb_private { +class ClangASTImporter; +class ObjectFile; + +namespace npdb { +class PdbIndex; +struct VariableInfo; + +struct DeclStatus { + DeclStatus() = default; + DeclStatus(lldb::user_id_t uid, bool resolved) + : uid(uid), resolved(resolved) {} + lldb::user_id_t uid = 0; + bool resolved = false; +}; + +class PdbAstBuilder { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + PdbAstBuilder(ObjectFile &obj, PdbIndex &index); + + clang::DeclContext &GetTranslationUnitDecl(); + + clang::Decl *GetOrCreateDeclForUid(PdbSymUid uid); + clang::DeclContext *GetOrCreateDeclContextForUid(PdbSymUid uid); + clang::DeclContext *GetParentDeclContext(PdbSymUid uid); + + clang::NamespaceDecl *GetOrCreateNamespaceDecl(llvm::StringRef name, + clang::DeclContext &context); + clang::FunctionDecl *GetOrCreateFunctionDecl(PdbCompilandSymId func_id); + clang::BlockDecl *GetOrCreateBlockDecl(PdbCompilandSymId block_id); + clang::VarDecl *GetOrCreateVariableDecl(PdbCompilandSymId scope_id, + PdbCompilandSymId var_id); + clang::VarDecl *GetOrCreateVariableDecl(PdbGlobalSymId var_id); + clang::TypedefNameDecl *GetOrCreateTypedefDecl(PdbGlobalSymId id); + void ParseDeclsForContext(clang::DeclContext &context); + + clang::QualType GetBasicType(lldb::BasicType type); + clang::QualType GetOrCreateType(PdbTypeSymId type); + + bool CompleteTagDecl(clang::TagDecl &tag); + bool CompleteType(clang::QualType qt); + + CompilerDecl ToCompilerDecl(clang::Decl &decl); + CompilerType ToCompilerType(clang::QualType qt); + CompilerDeclContext ToCompilerDeclContext(clang::DeclContext &context); + clang::DeclContext *FromCompilerDeclContext(CompilerDeclContext context); + + ClangASTContext &clang() { return m_clang; } + ClangASTImporter &importer() { return m_importer; } + + void Dump(Stream &stream); + +private: + clang::Decl *TryGetDecl(PdbSymUid uid) const; + + using TypeIndex = llvm::codeview::TypeIndex; + + clang::QualType + CreatePointerType(const llvm::codeview::PointerRecord &pointer); + clang::QualType + CreateModifierType(const llvm::codeview::ModifierRecord &modifier); + clang::QualType CreateArrayType(const llvm::codeview::ArrayRecord &array); + clang::QualType CreateRecordType(PdbTypeSymId id, + const llvm::codeview::TagRecord &record); + clang::QualType CreateEnumType(PdbTypeSymId id, + const llvm::codeview::EnumRecord &record); + clang::QualType + CreateProcedureType(const llvm::codeview::ProcedureRecord &proc); + clang::QualType CreateType(PdbTypeSymId type); + + void CreateFunctionParameters(PdbCompilandSymId func_id, + clang::FunctionDecl &function_decl, + uint32_t param_count); + clang::Decl *GetOrCreateSymbolForId(PdbCompilandSymId id); + clang::VarDecl *CreateVariableDecl(PdbSymUid uid, + llvm::codeview::CVSymbol sym, + clang::DeclContext &scope); + clang::DeclContext * + GetParentDeclContextForSymbol(const llvm::codeview::CVSymbol &sym); + + void ParseAllNamespacesPlusChildrenOf(llvm::Optional<llvm::StringRef> parent); + void ParseDeclsForSimpleContext(clang::DeclContext &context); + void ParseBlockChildren(PdbCompilandSymId block_id); + + void BuildParentMap(); + std::pair<clang::DeclContext *, std::string> + CreateDeclInfoForType(const llvm::codeview::TagRecord &record, TypeIndex ti); + std::pair<clang::DeclContext *, std::string> + CreateDeclInfoForUndecoratedName(llvm::StringRef uname); + clang::QualType CreateSimpleType(TypeIndex ti); + + PdbIndex &m_index; + ClangASTContext &m_clang; + + ClangASTImporter m_importer; + + llvm::DenseMap<TypeIndex, TypeIndex> m_parent_types; + llvm::DenseMap<clang::Decl *, DeclStatus> m_decl_to_status; + llvm::DenseMap<lldb::user_id_t, clang::Decl *> m_uid_to_decl; + llvm::DenseMap<lldb::user_id_t, clang::QualType> m_uid_to_type; +}; + +} // namespace npdb +} // namespace lldb_private + +#endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ diff --git a/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp b/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp new file mode 100644 index 000000000000..9f5dab6c2e84 --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp @@ -0,0 +1,200 @@ +//===-- PdbIndex.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PdbIndex.h" +#include "PdbUtil.h" + +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Error.h" + +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/lldb-defines.h" + +using namespace lldb_private; +using namespace lldb_private::npdb; +using namespace llvm::codeview; +using namespace llvm::pdb; + +PdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {} + +#define ASSIGN_PTR_OR_RETURN(result_ptr, expr) \ + { \ + auto expected_result = expr; \ + if (!expected_result) \ + return expected_result.takeError(); \ + result_ptr = &expected_result.get(); \ + } + +llvm::Expected<std::unique_ptr<PdbIndex>> +PdbIndex::create(std::unique_ptr<llvm::pdb::PDBFile> file) { + lldbassert(file); + + std::unique_ptr<PdbIndex> result(new PdbIndex()); + ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream()); + ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream()); + ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream()); + ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream()); + ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream()); + ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream()); + ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream()); + + result->m_tpi->buildHashMap(); + + result->m_file = std::move(file); + + return std::move(result); +} + +lldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment, + uint32_t offset) const { + // Segment indices are 1-based. + lldbassert(segment > 0); + + uint32_t max_section = dbi().getSectionHeaders().size(); + lldbassert(segment <= max_section + 1); + + // If this is an absolute symbol, it's indicated by the magic section index + // |max_section+1|. In this case, the offset is meaningless, so just return. + if (segment == max_section + 1) + return LLDB_INVALID_ADDRESS; + + const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1]; + return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) + + static_cast<lldb::addr_t>(offset); +} + +lldb::addr_t PdbIndex::MakeVirtualAddress(const SegmentOffset &so) const { + return MakeVirtualAddress(so.segment, so.offset); +} + +llvm::Optional<uint16_t> +PdbIndex::GetModuleIndexForAddr(uint16_t segment, uint32_t offset) const { + return GetModuleIndexForVa(MakeVirtualAddress(segment, offset)); +} + +llvm::Optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const { + auto iter = m_va_to_modi.find(va); + if (iter == m_va_to_modi.end()) + return llvm::None; + + return iter.value(); +} + +void PdbIndex::ParseSectionContribs() { + class Visitor : public ISectionContribVisitor { + PdbIndex &m_ctx; + llvm::IntervalMap<uint64_t, uint16_t> &m_imap; + + public: + Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap) + : m_ctx(ctx), m_imap(imap) {} + + void visit(const SectionContrib &C) override { + if (C.Size == 0) + return; + + uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off); + uint64_t end = va + C.Size; + // IntervalMap's start and end represent a closed range, not a half-open + // range, so we have to subtract 1. + m_imap.insert(va, end - 1, C.Imod); + } + void visit(const SectionContrib2 &C) override { visit(C.Base); } + }; + Visitor v(*this, m_va_to_modi); + dbi().visitSectionContributions(v); +} + +void PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) { + lldbassert(cci.m_symbols_by_va.empty() && + "Addr to symbol map is already built!"); + uint16_t modi = cci.m_id.modi; + const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray(); + for (auto iter = syms.begin(); iter != syms.end(); ++iter) { + if (!SymbolHasAddress(*iter)) + continue; + + SegmentOffset so = GetSegmentAndOffset(*iter); + lldb::addr_t va = MakeVirtualAddress(so); + + PdbCompilandSymId cu_sym_id(modi, iter.offset()); + + // If the debug info is incorrect, we could have multiple symbols with the + // same address. So use try_emplace instead of insert, and the first one + // will win. + cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id))); + } +} + +std::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) { + std::vector<SymbolAndUid> result; + + llvm::Optional<uint16_t> modi = GetModuleIndexForVa(va); + if (!modi) + return result; + + CompilandIndexItem &cci = compilands().GetOrCreateCompiland(*modi); + if (cci.m_symbols_by_va.empty()) + BuildAddrToSymbolMap(cci); + + // The map is sorted by starting address of the symbol. So for example + // we could (in theory) have this situation + // + // [------------------] + // [----------] + // [-----------] + // [-------------] + // [----] + // [-----] + // ^ Address we're searching for + // In order to find this, we use the upper_bound of the key value which would + // be the first symbol whose starting address is higher than the element we're + // searching for. + + auto ub = cci.m_symbols_by_va.upper_bound(va); + + for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) { + PdbCompilandSymId cu_sym_id = iter->second.asCompilandSym(); + CVSymbol sym = ReadSymbolRecord(cu_sym_id); + + SegmentOffsetLength sol; + if (SymbolIsCode(sym)) + sol = GetSegmentOffsetAndLength(sym); + else + sol.so = GetSegmentAndOffset(sym); + + lldb::addr_t start = MakeVirtualAddress(sol.so); + lldb::addr_t end = start + sol.length; + if (va >= start && va < end) + result.push_back({std::move(sym), iter->second}); + } + + return result; +} + +CVSymbol PdbIndex::ReadSymbolRecord(PdbCompilandSymId cu_sym) const { + // We need to subtract 4 here to adjust for the codeview debug magic + // at the beginning of the debug info stream. + const CompilandIndexItem *cci = compilands().GetCompiland(cu_sym.modi); + auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset); + lldbassert(iter != cci->m_debug_stream.getSymbolArray().end()); + return *iter; +} + +CVSymbol PdbIndex::ReadSymbolRecord(PdbGlobalSymId global) const { + return symrecords().readRecord(global.offset); +} diff --git a/source/Plugins/SymbolFile/NativePDB/PdbIndex.h b/source/Plugins/SymbolFile/NativePDB/PdbIndex.h new file mode 100644 index 000000000000..839d4e6606e4 --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/PdbIndex.h @@ -0,0 +1,162 @@ +//===-- PdbIndex.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBINDEX_H +#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBINDEX_H + +#include "lldb/lldb-types.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +#include "CompileUnitIndex.h" +#include "PdbSymUid.h" + +#include <map> +#include <memory> + +namespace llvm { +namespace pdb { +class DbiStream; +class TpiStream; +class TpiStream; +class InfoStream; +class PublicsStream; +class GlobalsStream; +class SymbolStream; +} // namespace pdb +} // namespace llvm + +namespace lldb_private { +namespace npdb { +struct SegmentOffset; + +/// PdbIndex - Lazy access to the important parts of a PDB file. +/// +/// This is a layer on top of LLVM's native PDB support libraries which cache +/// certain data when it is accessed the first time. The entire PDB file is +/// mapped into memory, and the underlying support libraries vend out memory +/// that is always backed by the file, so it is safe to hold StringRefs and +/// ArrayRefs into the backing memory as long as the PdbIndex instance is +/// alive. +class PdbIndex { + + /// The underlying PDB file. + std::unique_ptr<llvm::pdb::PDBFile> m_file; + + /// The DBI stream. This contains general high level information about the + /// features present in the PDB file, compile units (such as the information + /// necessary to locate full symbol information for each compile unit), + /// section contributions, and other data which is not specifically symbol or + /// type records. + llvm::pdb::DbiStream *m_dbi = nullptr; + + /// TPI (types) and IPI (indices) streams. These are both in the exact same + /// format with different data. Most type records are stored in the TPI + /// stream but certain specific types of records are stored in the IPI stream. + /// The IPI stream records can refer to the records in the TPI stream, but not + /// the other way around. + llvm::pdb::TpiStream *m_tpi = nullptr; + llvm::pdb::TpiStream *m_ipi = nullptr; + + /// This is called the "PDB Stream" in the Microsoft reference implementation. + /// It contains information about the structure of the file, as well as fields + /// used to match EXE and PDB. + llvm::pdb::InfoStream *m_info = nullptr; + + /// Publics stream. Is actually a serialized hash table where the keys are + /// addresses of symbols in the executable, and values are a record containing + /// mangled names and an index which can be used to locate more detailed info + /// about the symbol in the Symbol Records stream. The publics stream only + /// contains info about externally visible symbols. + llvm::pdb::PublicsStream *m_publics = nullptr; + + /// Globals stream. Contrary to its name, this does not contain information + /// about all "global variables" or "global functions". Rather, it is the + /// "global symbol table", i.e. it contains information about *every* symbol + /// in the executable. It is a hash table keyed on name, whose values are + /// indices into the symbol records stream to find the full record. + llvm::pdb::GlobalsStream *m_globals = nullptr; + + /// Symbol records stream. The publics and globals stream refer to records + /// in this stream. For some records, like constants and typedefs, the + /// complete record lives in this stream. For other symbol types, such as + /// functions, data, and other things that have been materialied into a + /// specific compile unit, the records here simply provide a reference + /// necessary to locate the full information. + llvm::pdb::SymbolStream *m_symrecords = nullptr; + + /// Index of all compile units, mapping identifier to |CompilandIndexItem| + /// instance. + CompileUnitIndex m_cus; + + /// An allocator for the interval maps + llvm::IntervalMap<lldb::addr_t, uint32_t>::Allocator m_allocator; + + /// Maps virtual address to module index + llvm::IntervalMap<lldb::addr_t, uint16_t> m_va_to_modi; + + /// The address at which the program has been loaded into memory. + lldb::addr_t m_load_address = 0; + + PdbIndex(); + + void BuildAddrToSymbolMap(CompilandIndexItem &cci); + +public: + static llvm::Expected<std::unique_ptr<PdbIndex>> + create(std::unique_ptr<llvm::pdb::PDBFile>); + + void SetLoadAddress(lldb::addr_t addr) { m_load_address = addr; } + void ParseSectionContribs(); + + llvm::pdb::PDBFile &pdb() { return *m_file; } + const llvm::pdb::PDBFile &pdb() const { return *m_file; } + + llvm::pdb::DbiStream &dbi() { return *m_dbi; } + const llvm::pdb::DbiStream &dbi() const { return *m_dbi; } + + llvm::pdb::TpiStream &tpi() { return *m_tpi; } + const llvm::pdb::TpiStream &tpi() const { return *m_tpi; } + + llvm::pdb::TpiStream &ipi() { return *m_ipi; } + const llvm::pdb::TpiStream &ipi() const { return *m_ipi; } + + llvm::pdb::InfoStream &info() { return *m_info; } + const llvm::pdb::InfoStream &info() const { return *m_info; } + + llvm::pdb::PublicsStream &publics() { return *m_publics; } + const llvm::pdb::PublicsStream &publics() const { return *m_publics; } + + llvm::pdb::GlobalsStream &globals() { return *m_globals; } + const llvm::pdb::GlobalsStream &globals() const { return *m_globals; } + + llvm::pdb::SymbolStream &symrecords() { return *m_symrecords; } + const llvm::pdb::SymbolStream &symrecords() const { return *m_symrecords; } + + CompileUnitIndex &compilands() { return m_cus; } + const CompileUnitIndex &compilands() const { return m_cus; } + + lldb::addr_t MakeVirtualAddress(uint16_t segment, uint32_t offset) const; + lldb::addr_t MakeVirtualAddress(const SegmentOffset &so) const; + + std::vector<SymbolAndUid> FindSymbolsByVa(lldb::addr_t va); + + llvm::codeview::CVSymbol ReadSymbolRecord(PdbCompilandSymId cu_sym) const; + llvm::codeview::CVSymbol ReadSymbolRecord(PdbGlobalSymId global) const; + + llvm::Optional<uint16_t> GetModuleIndexForAddr(uint16_t segment, + uint32_t offset) const; + llvm::Optional<uint16_t> GetModuleIndexForVa(lldb::addr_t va) const; +}; +} // namespace npdb +} // namespace lldb_private + +#endif diff --git a/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp b/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp new file mode 100644 index 000000000000..e5424568da47 --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp @@ -0,0 +1,161 @@ +//===-- PdbSymUid.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PdbSymUid.h" + +using namespace lldb_private; +using namespace lldb_private::npdb; +using namespace llvm::codeview; + +namespace { +struct GenericIdRepr { + uint64_t tag : 4; + uint64_t data : 60; +}; + +struct CompilandIdRepr { + uint64_t tag : 4; + uint64_t modi : 16; + uint64_t unused : 44; +}; + +struct CompilandSymIdRepr { + uint64_t tag : 4; + uint64_t modi : 16; + uint64_t offset : 32; + uint64_t unused : 12; +}; + +struct GlobalSymIdRepr { + uint64_t tag : 4; + uint64_t offset : 32; + uint64_t pub : 1; + uint64_t unused : 27; +}; + +struct TypeSymIdRepr { + uint64_t tag : 4; + uint64_t index : 32; + uint64_t ipi : 1; + uint64_t unused : 27; +}; + +struct FieldListMemberIdRepr { + uint64_t tag : 4; + uint64_t index : 32; + uint64_t offset : 16; + uint64_t unused : 12; +}; + +static_assert(sizeof(CompilandIdRepr) == 8, "Invalid structure size!"); +static_assert(sizeof(CompilandSymIdRepr) == 8, "Invalid structure size!"); +static_assert(sizeof(GlobalSymIdRepr) == 8, "Invalid structure size!"); +static_assert(sizeof(TypeSymIdRepr) == 8, "Invalid structure size!"); +static_assert(sizeof(FieldListMemberIdRepr) == 8, "Invalid structure size!"); +} // namespace + +template <typename OutT, typename InT> static OutT repr_cast(const InT &value) { + OutT result; + ::memcpy(&result, &value, sizeof(value)); + return result; +} + +PdbSymUid::PdbSymUid(const PdbCompilandId &cid) { + CompilandIdRepr repr; + ::memset(&repr, 0, sizeof(repr)); + repr.modi = cid.modi; + repr.tag = static_cast<uint64_t>(PdbSymUidKind::Compiland); + m_repr = repr_cast<uint64_t>(repr); +} + +PdbSymUid::PdbSymUid(const PdbCompilandSymId &csid) { + CompilandSymIdRepr repr; + ::memset(&repr, 0, sizeof(repr)); + repr.modi = csid.modi; + repr.offset = csid.offset; + repr.tag = static_cast<uint64_t>(PdbSymUidKind::CompilandSym); + m_repr = repr_cast<uint64_t>(repr); +} + +PdbSymUid::PdbSymUid(const PdbGlobalSymId &gsid) { + GlobalSymIdRepr repr; + ::memset(&repr, 0, sizeof(repr)); + repr.pub = gsid.is_public; + repr.offset = gsid.offset; + repr.tag = static_cast<uint64_t>(PdbSymUidKind::GlobalSym); + m_repr = repr_cast<uint64_t>(repr); +} + +PdbSymUid::PdbSymUid(const PdbTypeSymId &tsid) { + TypeSymIdRepr repr; + ::memset(&repr, 0, sizeof(repr)); + repr.index = tsid.index.getIndex(); + repr.ipi = tsid.is_ipi; + repr.tag = static_cast<uint64_t>(PdbSymUidKind::Type); + m_repr = repr_cast<uint64_t>(repr); +} + +PdbSymUid::PdbSymUid(const PdbFieldListMemberId &flmid) { + FieldListMemberIdRepr repr; + ::memset(&repr, 0, sizeof(repr)); + repr.index = flmid.index.getIndex(); + repr.offset = flmid.offset; + repr.tag = static_cast<uint64_t>(PdbSymUidKind::FieldListMember); + m_repr = repr_cast<uint64_t>(repr); +} + +PdbSymUidKind PdbSymUid::kind() const { + GenericIdRepr generic = repr_cast<GenericIdRepr>(m_repr); + return static_cast<PdbSymUidKind>(generic.tag); +} + +PdbCompilandId PdbSymUid::asCompiland() const { + assert(kind() == PdbSymUidKind::Compiland); + auto repr = repr_cast<CompilandIdRepr>(m_repr); + PdbCompilandId result; + result.modi = repr.modi; + return result; +} + +PdbCompilandSymId PdbSymUid::asCompilandSym() const { + assert(kind() == PdbSymUidKind::CompilandSym); + auto repr = repr_cast<CompilandSymIdRepr>(m_repr); + PdbCompilandSymId result; + result.modi = repr.modi; + result.offset = repr.offset; + return result; +} + +PdbGlobalSymId PdbSymUid::asGlobalSym() const { + assert(kind() == PdbSymUidKind::GlobalSym || + kind() == PdbSymUidKind::PublicSym); + auto repr = repr_cast<GlobalSymIdRepr>(m_repr); + PdbGlobalSymId result; + result.is_public = repr.pub; + result.offset = repr.offset; + return result; +} + +PdbTypeSymId PdbSymUid::asTypeSym() const { + assert(kind() == PdbSymUidKind::Type); + auto repr = repr_cast<TypeSymIdRepr>(m_repr); + PdbTypeSymId result; + result.index.setIndex(repr.index); + result.is_ipi = repr.ipi; + return result; +} + +PdbFieldListMemberId PdbSymUid::asFieldListMember() const { + assert(kind() == PdbSymUidKind::FieldListMember); + auto repr = repr_cast<FieldListMemberIdRepr>(m_repr); + PdbFieldListMemberId result; + result.index.setIndex(repr.index); + result.offset = repr.offset; + return result; +} diff --git a/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h b/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h new file mode 100644 index 000000000000..1166bee4e327 --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h @@ -0,0 +1,126 @@ +//===-- PdbSymUid.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// A unique identification scheme for Pdb records. +// The scheme is to partition a 64-bit integer into an 8-bit tag field, which +// will contain some value from the PDB_SymType enumeration. The format of the +// other 48-bits depend on the tag, but must be sufficient to locate the +// corresponding entry in the underlying PDB file quickly. For example, for +// a compile unit, we use 2 bytes to represent the index, which allows fast +// access to the compile unit's information. +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBSYMUID_H +#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBSYMUID_H + +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Support/Compiler.h" + +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { +namespace npdb { + +enum class PdbSymUidKind : uint8_t { + Compiland, + CompilandSym, + PublicSym, + GlobalSym, + Type, + FieldListMember +}; + +struct PdbCompilandId { + // 0-based index of module in PDB + uint16_t modi; +}; + +struct PdbCompilandSymId { + PdbCompilandSymId() = default; + PdbCompilandSymId(uint16_t modi, uint32_t offset) + : modi(modi), offset(offset) {} + // 0-based index of module in PDB + uint16_t modi = 0; + + // Offset of symbol's record in module stream. This is + // offset by 4 from the CVSymbolArray's notion of offset + // due to the debug magic at the beginning of the stream. + uint32_t offset = 0; +}; + +struct PdbGlobalSymId { + PdbGlobalSymId() = default; + PdbGlobalSymId(uint32_t offset, bool is_public) + : offset(offset), is_public(is_public) {} + + // Offset of symbol's record in globals or publics stream. + uint32_t offset = 0; + + // True if this symbol is in the public stream, false if it's in the globals + // stream. + bool is_public = false; +}; + +struct PdbTypeSymId { + PdbTypeSymId() = default; + PdbTypeSymId(llvm::codeview::TypeIndex index, bool is_ipi = false) + : index(index), is_ipi(is_ipi) {} + + // The index of the of the type in the TPI or IPI stream. + llvm::codeview::TypeIndex index; + + // True if this symbol comes from the IPI stream, false if it's from the TPI + // stream. + bool is_ipi = false; +}; + +struct PdbFieldListMemberId { + // The TypeIndex of the LF_FIELDLIST record. + llvm::codeview::TypeIndex index; + + // The offset from the beginning of the LF_FIELDLIST record to this record. + uint16_t offset = 0; +}; + +class PdbSymUid { + uint64_t m_repr = 0; + +public: + PdbSymUid() = default; + PdbSymUid(uint64_t repr) : m_repr(repr) {} + PdbSymUid(const PdbCompilandId &cid); + PdbSymUid(const PdbCompilandSymId &csid); + PdbSymUid(const PdbGlobalSymId &gsid); + PdbSymUid(const PdbTypeSymId &tsid); + PdbSymUid(const PdbFieldListMemberId &flmid); + + uint64_t toOpaqueId() const { return m_repr; } + + PdbSymUidKind kind() const; + + PdbCompilandId asCompiland() const; + PdbCompilandSymId asCompilandSym() const; + PdbGlobalSymId asGlobalSym() const; + PdbTypeSymId asTypeSym() const; + PdbFieldListMemberId asFieldListMember() const; +}; + +template <typename T> uint64_t toOpaqueUid(const T &cid) { + return PdbSymUid(cid).toOpaqueId(); +} + +struct SymbolAndUid { + llvm::codeview::CVSymbol sym; + PdbSymUid uid; +}; +} // namespace npdb +} // namespace lldb_private + +#endif diff --git a/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp new file mode 100644 index 000000000000..317725dd250e --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp @@ -0,0 +1,750 @@ +//===-- PdbUtil.cpp ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PdbUtil.h" + +#include "DWARFLocationExpression.h" +#include "PdbIndex.h" +#include "PdbSymUid.h" + +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/lldb-enumerations.h" + +using namespace lldb_private; +using namespace lldb_private::npdb; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static Variable::RangeList +MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range, + llvm::ArrayRef<LocalVariableAddrGap> gaps) { + lldb::addr_t start = + index.MakeVirtualAddress(range.ISectStart, range.OffsetStart); + lldb::addr_t end = start + range.Range; + + Variable::RangeList result; + while (!gaps.empty()) { + const LocalVariableAddrGap &gap = gaps.front(); + + lldb::addr_t size = gap.GapStartOffset - start; + result.Append(start, size); + start += gap.Range; + gaps = gaps.drop_front(); + } + + result.Append(start, end); + return result; +} + +CVTagRecord CVTagRecord::create(CVType type) { + assert(IsTagRecord(type) && "type is not a tag record!"); + switch (type.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: { + ClassRecord cr; + llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(type, cr)); + return CVTagRecord(std::move(cr)); + } + case LF_UNION: { + UnionRecord ur; + llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(type, ur)); + return CVTagRecord(std::move(ur)); + } + case LF_ENUM: { + EnumRecord er; + llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(type, er)); + return CVTagRecord(std::move(er)); + } + default: + llvm_unreachable("Unreachable!"); + } +} + +CVTagRecord::CVTagRecord(ClassRecord &&c) + : cvclass(std::move(c)), + m_kind(cvclass.Kind == TypeRecordKind::Struct ? Struct : Class) {} +CVTagRecord::CVTagRecord(UnionRecord &&u) + : cvunion(std::move(u)), m_kind(Union) {} +CVTagRecord::CVTagRecord(EnumRecord &&e) : cvenum(std::move(e)), m_kind(Enum) {} + +PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) { + switch (kind) { + case S_COMPILE3: + case S_OBJNAME: + return PDB_SymType::CompilandDetails; + case S_ENVBLOCK: + return PDB_SymType::CompilandEnv; + case S_THUNK32: + case S_TRAMPOLINE: + return PDB_SymType::Thunk; + case S_COFFGROUP: + return PDB_SymType::CoffGroup; + case S_EXPORT: + return PDB_SymType::Export; + case S_LPROC32: + case S_GPROC32: + case S_LPROC32_DPC: + return PDB_SymType::Function; + case S_PUB32: + return PDB_SymType::PublicSymbol; + case S_INLINESITE: + return PDB_SymType::InlineSite; + case S_LOCAL: + case S_BPREL32: + case S_REGREL32: + case S_MANCONSTANT: + case S_CONSTANT: + case S_LDATA32: + case S_GDATA32: + case S_LMANDATA: + case S_GMANDATA: + case S_LTHREAD32: + case S_GTHREAD32: + return PDB_SymType::Data; + case S_BLOCK32: + return PDB_SymType::Block; + case S_LABEL32: + return PDB_SymType::Label; + case S_CALLSITEINFO: + return PDB_SymType::CallSite; + case S_HEAPALLOCSITE: + return PDB_SymType::HeapAllocationSite; + case S_CALLEES: + return PDB_SymType::Callee; + case S_CALLERS: + return PDB_SymType::Caller; + default: + lldbassert(false && "Invalid symbol record kind!"); + } + return PDB_SymType::None; +} + +PDB_SymType lldb_private::npdb::CVTypeToPDBType(TypeLeafKind kind) { + switch (kind) { + case LF_ARRAY: + return PDB_SymType::ArrayType; + case LF_ARGLIST: + return PDB_SymType::FunctionSig; + case LF_BCLASS: + return PDB_SymType::BaseClass; + case LF_BINTERFACE: + return PDB_SymType::BaseInterface; + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: + case LF_UNION: + return PDB_SymType::UDT; + case LF_POINTER: + return PDB_SymType::PointerType; + case LF_ENUM: + return PDB_SymType::Enum; + case LF_PROCEDURE: + return PDB_SymType::FunctionSig; + case LF_BITFIELD: + return PDB_SymType::BuiltinType; + default: + lldbassert(false && "Invalid type record kind!"); + } + return PDB_SymType::None; +} + +bool lldb_private::npdb::SymbolHasAddress(const CVSymbol &sym) { + switch (sym.kind()) { + case S_GPROC32: + case S_LPROC32: + case S_GPROC32_ID: + case S_LPROC32_ID: + case S_LPROC32_DPC: + case S_LPROC32_DPC_ID: + case S_THUNK32: + case S_TRAMPOLINE: + case S_COFFGROUP: + case S_BLOCK32: + case S_LABEL32: + case S_CALLSITEINFO: + case S_HEAPALLOCSITE: + case S_LDATA32: + case S_GDATA32: + case S_LMANDATA: + case S_GMANDATA: + case S_LTHREAD32: + case S_GTHREAD32: + return true; + default: + return false; + } +} + +bool lldb_private::npdb::SymbolIsCode(const CVSymbol &sym) { + switch (sym.kind()) { + case S_GPROC32: + case S_LPROC32: + case S_GPROC32_ID: + case S_LPROC32_ID: + case S_LPROC32_DPC: + case S_LPROC32_DPC_ID: + case S_THUNK32: + case S_TRAMPOLINE: + case S_COFFGROUP: + case S_BLOCK32: + return true; + default: + return false; + } +} + +template <typename RecordT> RecordT createRecord(const CVSymbol &sym) { + RecordT record(static_cast<SymbolRecordKind>(sym.kind())); + cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record)); + return record; +} + +template <typename RecordT> +static SegmentOffset GetSegmentAndOffset(const CVSymbol &sym) { + RecordT record = createRecord<RecordT>(sym); + return {record.Segment, record.CodeOffset}; +} + +template <> +SegmentOffset GetSegmentAndOffset<TrampolineSym>(const CVSymbol &sym) { + TrampolineSym record = createRecord<TrampolineSym>(sym); + return {record.ThunkSection, record.ThunkOffset}; +} + +template <> SegmentOffset GetSegmentAndOffset<Thunk32Sym>(const CVSymbol &sym) { + Thunk32Sym record = createRecord<Thunk32Sym>(sym); + return {record.Segment, record.Offset}; +} + +template <> +SegmentOffset GetSegmentAndOffset<CoffGroupSym>(const CVSymbol &sym) { + CoffGroupSym record = createRecord<CoffGroupSym>(sym); + return {record.Segment, record.Offset}; +} + +template <> SegmentOffset GetSegmentAndOffset<DataSym>(const CVSymbol &sym) { + DataSym record = createRecord<DataSym>(sym); + return {record.Segment, record.DataOffset}; +} + +template <> +SegmentOffset GetSegmentAndOffset<ThreadLocalDataSym>(const CVSymbol &sym) { + ThreadLocalDataSym record = createRecord<ThreadLocalDataSym>(sym); + return {record.Segment, record.DataOffset}; +} + +SegmentOffset lldb_private::npdb::GetSegmentAndOffset(const CVSymbol &sym) { + switch (sym.kind()) { + case S_GPROC32: + case S_LPROC32: + case S_GPROC32_ID: + case S_LPROC32_ID: + case S_LPROC32_DPC: + case S_LPROC32_DPC_ID: + return ::GetSegmentAndOffset<ProcSym>(sym); + case S_THUNK32: + return ::GetSegmentAndOffset<Thunk32Sym>(sym); + break; + case S_TRAMPOLINE: + return ::GetSegmentAndOffset<TrampolineSym>(sym); + break; + case S_COFFGROUP: + return ::GetSegmentAndOffset<CoffGroupSym>(sym); + break; + case S_BLOCK32: + return ::GetSegmentAndOffset<BlockSym>(sym); + break; + case S_LABEL32: + return ::GetSegmentAndOffset<LabelSym>(sym); + break; + case S_CALLSITEINFO: + return ::GetSegmentAndOffset<CallSiteInfoSym>(sym); + break; + case S_HEAPALLOCSITE: + return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym); + break; + case S_LDATA32: + case S_GDATA32: + case S_LMANDATA: + case S_GMANDATA: + return ::GetSegmentAndOffset<DataSym>(sym); + break; + case S_LTHREAD32: + case S_GTHREAD32: + return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym); + break; + default: + lldbassert(false && "Record does not have a segment/offset!"); + } + return {0, 0}; +} + +template <typename RecordT> +SegmentOffsetLength GetSegmentOffsetAndLength(const CVSymbol &sym) { + RecordT record = createRecord<RecordT>(sym); + return {record.Segment, record.CodeOffset, record.CodeSize}; +} + +template <> +SegmentOffsetLength +GetSegmentOffsetAndLength<TrampolineSym>(const CVSymbol &sym) { + TrampolineSym record = createRecord<TrampolineSym>(sym); + return {record.ThunkSection, record.ThunkOffset, record.Size}; +} + +template <> +SegmentOffsetLength GetSegmentOffsetAndLength<Thunk32Sym>(const CVSymbol &sym) { + Thunk32Sym record = createRecord<Thunk32Sym>(sym); + return SegmentOffsetLength{record.Segment, record.Offset, record.Length}; +} + +template <> +SegmentOffsetLength +GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) { + CoffGroupSym record = createRecord<CoffGroupSym>(sym); + return SegmentOffsetLength{record.Segment, record.Offset, record.Size}; +} + +SegmentOffsetLength +lldb_private::npdb::GetSegmentOffsetAndLength(const CVSymbol &sym) { + switch (sym.kind()) { + case S_GPROC32: + case S_LPROC32: + case S_GPROC32_ID: + case S_LPROC32_ID: + case S_LPROC32_DPC: + case S_LPROC32_DPC_ID: + return ::GetSegmentOffsetAndLength<ProcSym>(sym); + case S_THUNK32: + return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym); + break; + case S_TRAMPOLINE: + return ::GetSegmentOffsetAndLength<TrampolineSym>(sym); + break; + case S_COFFGROUP: + return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym); + break; + case S_BLOCK32: + return ::GetSegmentOffsetAndLength<BlockSym>(sym); + break; + default: + lldbassert(false && "Record does not have a segment/offset/length triple!"); + } + return {0, 0, 0}; +} + +bool lldb_private::npdb::IsForwardRefUdt(CVType cvt) { + ClassRecord cr; + UnionRecord ur; + EnumRecord er; + switch (cvt.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: + llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr)); + return cr.isForwardRef(); + case LF_UNION: + llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur)); + return ur.isForwardRef(); + case LF_ENUM: + llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er)); + return er.isForwardRef(); + default: + return false; + } +} + +bool lldb_private::npdb::IsTagRecord(llvm::codeview::CVType cvt) { + switch (cvt.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_UNION: + case LF_ENUM: + return true; + default: + return false; + } +} + +bool lldb_private::npdb::IsClassStructUnion(llvm::codeview::CVType cvt) { + switch (cvt.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_UNION: + return true; + default: + return false; + } +} + +bool lldb_private::npdb::IsForwardRefUdt(const PdbTypeSymId &id, + TpiStream &tpi) { + if (id.is_ipi || id.index.isSimple()) + return false; + return IsForwardRefUdt(tpi.getType(id.index)); +} + +bool lldb_private::npdb::IsTagRecord(const PdbTypeSymId &id, TpiStream &tpi) { + if (id.is_ipi || id.index.isSimple()) + return false; + return IsTagRecord(tpi.getType(id.index)); +} + +lldb::AccessType +lldb_private::npdb::TranslateMemberAccess(MemberAccess access) { + switch (access) { + case MemberAccess::Private: + return lldb::eAccessPrivate; + case MemberAccess::Protected: + return lldb::eAccessProtected; + case MemberAccess::Public: + return lldb::eAccessPublic; + case MemberAccess::None: + return lldb::eAccessNone; + } + llvm_unreachable("unreachable"); +} + +TypeIndex lldb_private::npdb::GetFieldListIndex(CVType cvt) { + switch (cvt.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: { + ClassRecord cr; + cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr)); + return cr.FieldList; + } + case LF_UNION: { + UnionRecord ur; + cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur)); + return ur.FieldList; + } + case LF_ENUM: { + EnumRecord er; + cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er)); + return er.FieldList; + } + default: + llvm_unreachable("Unreachable!"); + } +} + +TypeIndex lldb_private::npdb::LookThroughModifierRecord(CVType modifier) { + lldbassert(modifier.kind() == LF_MODIFIER); + ModifierRecord mr; + llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(modifier, mr)); + return mr.ModifiedType; +} + +llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) { + return MSVCUndecoratedNameParser::DropScope(name); +} + +VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) { + VariableInfo result; + + if (sym.kind() == S_REGREL32) { + RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); + cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg)); + result.type = reg.Type; + result.name = reg.Name; + return result; + } + + if (sym.kind() == S_REGISTER) { + RegisterSym reg(SymbolRecordKind::RegisterSym); + cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg)); + result.type = reg.Index; + result.name = reg.Name; + return result; + } + + if (sym.kind() == S_LOCAL) { + LocalSym local(SymbolRecordKind::LocalSym); + cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local)); + result.type = local.Type; + result.name = local.Name; + return result; + } + + if (sym.kind() == S_GDATA32 || sym.kind() == S_LDATA32) { + DataSym data(SymbolRecordKind::DataSym); + cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, data)); + result.type = data.Type; + result.name = data.Name; + return result; + } + + if (sym.kind() == S_GTHREAD32 || sym.kind() == S_LTHREAD32) { + ThreadLocalDataSym data(SymbolRecordKind::ThreadLocalDataSym); + cantFail(SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, data)); + result.type = data.Type; + result.name = data.Name; + return result; + } + + if (sym.kind() == S_CONSTANT) { + ConstantSym constant(SymbolRecordKind::ConstantSym); + cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(sym, constant)); + result.type = constant.Type; + result.name = constant.Name; + return result; + } + + lldbassert(false && "Invalid variable record kind!"); + return {}; +} + +VariableInfo lldb_private::npdb::GetVariableLocationInfo( + PdbIndex &index, PdbCompilandSymId var_id, lldb::ModuleSP module) { + + CVSymbol sym = index.ReadSymbolRecord(var_id); + + VariableInfo result = GetVariableNameInfo(sym); + + if (sym.kind() == S_REGREL32) { + RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); + cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg)); + result.location = + MakeRegRelLocationExpression(reg.Register, reg.Offset, module); + result.ranges.emplace(); + return result; + } + + if (sym.kind() == S_REGISTER) { + RegisterSym reg(SymbolRecordKind::RegisterSym); + cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg)); + result.location = MakeEnregisteredLocationExpression(reg.Register, module); + result.ranges.emplace(); + return result; + } + + if (sym.kind() == S_LOCAL) { + LocalSym local(SymbolRecordKind::LocalSym); + cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local)); + + PdbCompilandSymId loc_specifier_id(var_id.modi, + var_id.offset + sym.RecordData.size()); + CVSymbol loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id); + if (loc_specifier_cvs.kind() == S_DEFRANGE_FRAMEPOINTER_REL) { + DefRangeFramePointerRelSym loc( + SymbolRecordKind::DefRangeFramePointerRelSym); + cantFail(SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>( + loc_specifier_cvs, loc)); + // FIXME: The register needs to come from the S_FRAMEPROC symbol. + result.location = + MakeRegRelLocationExpression(RegisterId::RSP, loc.Offset, module); + result.ranges = MakeRangeList(index, loc.Range, loc.Gaps); + } else { + // FIXME: Handle other kinds + } + return result; + } + llvm_unreachable("Symbol is not a local variable!"); + return result; +} + +lldb::BasicType +lldb_private::npdb::GetCompilerTypeForSimpleKind(SimpleTypeKind kind) { + switch (kind) { + case SimpleTypeKind::Boolean128: + case SimpleTypeKind::Boolean16: + case SimpleTypeKind::Boolean32: + case SimpleTypeKind::Boolean64: + case SimpleTypeKind::Boolean8: + return lldb::eBasicTypeBool; + case SimpleTypeKind::Byte: + case SimpleTypeKind::UnsignedCharacter: + return lldb::eBasicTypeUnsignedChar; + case SimpleTypeKind::NarrowCharacter: + return lldb::eBasicTypeChar; + case SimpleTypeKind::SignedCharacter: + case SimpleTypeKind::SByte: + return lldb::eBasicTypeSignedChar; + case SimpleTypeKind::Character16: + return lldb::eBasicTypeChar16; + case SimpleTypeKind::Character32: + return lldb::eBasicTypeChar32; + case SimpleTypeKind::Complex80: + return lldb::eBasicTypeLongDoubleComplex; + case SimpleTypeKind::Complex64: + return lldb::eBasicTypeDoubleComplex; + case SimpleTypeKind::Complex32: + return lldb::eBasicTypeFloatComplex; + case SimpleTypeKind::Float128: + case SimpleTypeKind::Float80: + return lldb::eBasicTypeLongDouble; + case SimpleTypeKind::Float64: + return lldb::eBasicTypeDouble; + case SimpleTypeKind::Float32: + return lldb::eBasicTypeFloat; + case SimpleTypeKind::Float16: + return lldb::eBasicTypeHalf; + case SimpleTypeKind::Int128: + return lldb::eBasicTypeInt128; + case SimpleTypeKind::Int64: + case SimpleTypeKind::Int64Quad: + return lldb::eBasicTypeLongLong; + case SimpleTypeKind::Int32: + return lldb::eBasicTypeInt; + case SimpleTypeKind::Int16: + case SimpleTypeKind::Int16Short: + return lldb::eBasicTypeShort; + case SimpleTypeKind::UInt128: + return lldb::eBasicTypeUnsignedInt128; + case SimpleTypeKind::UInt64: + case SimpleTypeKind::UInt64Quad: + return lldb::eBasicTypeUnsignedLongLong; + case SimpleTypeKind::HResult: + case SimpleTypeKind::UInt32: + return lldb::eBasicTypeUnsignedInt; + case SimpleTypeKind::UInt16: + case SimpleTypeKind::UInt16Short: + return lldb::eBasicTypeUnsignedShort; + case SimpleTypeKind::Int32Long: + return lldb::eBasicTypeLong; + case SimpleTypeKind::UInt32Long: + return lldb::eBasicTypeUnsignedLong; + case SimpleTypeKind::Void: + return lldb::eBasicTypeVoid; + case SimpleTypeKind::WideCharacter: + return lldb::eBasicTypeWChar; + default: + return lldb::eBasicTypeInvalid; + } +} + +size_t lldb_private::npdb::GetTypeSizeForSimpleKind(SimpleTypeKind kind) { + switch (kind) { + case SimpleTypeKind::Boolean128: + case SimpleTypeKind::Int128: + case SimpleTypeKind::UInt128: + case SimpleTypeKind::Float128: + return 16; + case SimpleTypeKind::Complex80: + case SimpleTypeKind::Float80: + return 10; + case SimpleTypeKind::Boolean64: + case SimpleTypeKind::Complex64: + case SimpleTypeKind::UInt64: + case SimpleTypeKind::UInt64Quad: + case SimpleTypeKind::Float64: + case SimpleTypeKind::Int64: + case SimpleTypeKind::Int64Quad: + return 8; + case SimpleTypeKind::Boolean32: + case SimpleTypeKind::Character32: + case SimpleTypeKind::Complex32: + case SimpleTypeKind::Float32: + case SimpleTypeKind::Int32: + case SimpleTypeKind::Int32Long: + case SimpleTypeKind::UInt32Long: + case SimpleTypeKind::HResult: + case SimpleTypeKind::UInt32: + return 4; + case SimpleTypeKind::Boolean16: + case SimpleTypeKind::Character16: + case SimpleTypeKind::Float16: + case SimpleTypeKind::Int16: + case SimpleTypeKind::Int16Short: + case SimpleTypeKind::UInt16: + case SimpleTypeKind::UInt16Short: + case SimpleTypeKind::WideCharacter: + return 2; + case SimpleTypeKind::Boolean8: + case SimpleTypeKind::Byte: + case SimpleTypeKind::UnsignedCharacter: + case SimpleTypeKind::NarrowCharacter: + case SimpleTypeKind::SignedCharacter: + case SimpleTypeKind::SByte: + return 1; + case SimpleTypeKind::Void: + default: + return 0; + } +} + +PdbTypeSymId lldb_private::npdb::GetBestPossibleDecl(PdbTypeSymId id, + TpiStream &tpi) { + if (id.index.isSimple()) + return id; + + CVType cvt = tpi.getType(id.index); + + // Only tag records have a best and a worst record. + if (!IsTagRecord(cvt)) + return id; + + // Tag records that are not forward decls are full decls, hence they are the + // best. + if (!IsForwardRefUdt(cvt)) + return id; + + return llvm::cantFail(tpi.findFullDeclForForwardRef(id.index)); +} + +template <typename RecordType> static size_t GetSizeOfTypeInternal(CVType cvt) { + RecordType record; + llvm::cantFail(TypeDeserializer::deserializeAs<RecordType>(cvt, record)); + return record.getSize(); +} + +size_t lldb_private::npdb::GetSizeOfType(PdbTypeSymId id, + llvm::pdb::TpiStream &tpi) { + if (id.index.isSimple()) { + switch (id.index.getSimpleMode()) { + case SimpleTypeMode::Direct: + return GetTypeSizeForSimpleKind(id.index.getSimpleKind()); + case SimpleTypeMode::NearPointer32: + case SimpleTypeMode::FarPointer32: + return 4; + case SimpleTypeMode::NearPointer64: + return 8; + case SimpleTypeMode::NearPointer128: + return 16; + default: + break; + } + return 0; + } + + TypeIndex index = id.index; + if (IsForwardRefUdt(index, tpi)) + index = llvm::cantFail(tpi.findFullDeclForForwardRef(index)); + + CVType cvt = tpi.getType(index); + switch (cvt.kind()) { + case LF_MODIFIER: + return GetSizeOfType({LookThroughModifierRecord(cvt)}, tpi); + case LF_ENUM: { + EnumRecord record; + llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, record)); + return GetSizeOfType({record.UnderlyingType}, tpi); + } + case LF_POINTER: + return GetSizeOfTypeInternal<PointerRecord>(cvt); + case LF_ARRAY: + return GetSizeOfTypeInternal<ArrayRecord>(cvt); + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: + return GetSizeOfTypeInternal<ClassRecord>(cvt); + case LF_UNION: + return GetSizeOfTypeInternal<UnionRecord>(cvt); + default: + break; + } + return 0; +} diff --git a/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/source/Plugins/SymbolFile/NativePDB/PdbUtil.h new file mode 100644 index 000000000000..570c300b6a2b --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/PdbUtil.h @@ -0,0 +1,159 @@ +//===-- PdbUtil.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBUTIL_H +#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBUTIL_H + +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/lldb-enumerations.h" + +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +#include "PdbSymUid.h" + +#include <tuple> +#include <utility> + +namespace llvm { +namespace pdb { +class TpiStream; +} +} // namespace llvm + +namespace lldb_private { +namespace npdb { + +class PdbIndex; + +struct CVTagRecord { + enum Kind { Class, Struct, Union, Enum }; + + static CVTagRecord create(llvm::codeview::CVType type); + + Kind kind() const { return m_kind; } + + const llvm::codeview::TagRecord &asTag() const { + if (m_kind == Struct || m_kind == Class) + return cvclass; + if (m_kind == Enum) + return cvenum; + return cvunion; + } + + const llvm::codeview::ClassRecord &asClass() const { + assert(m_kind == Struct || m_kind == Class); + return cvclass; + } + + const llvm::codeview::EnumRecord &asEnum() const { + assert(m_kind == Enum); + return cvenum; + } + + const llvm::codeview::UnionRecord &asUnion() const { + assert(m_kind == Union); + return cvunion; + } + + llvm::StringRef name() const { + if (m_kind == Struct || m_kind == Union) + return cvclass.Name; + if (m_kind == Enum) + return cvenum.Name; + return cvunion.Name; + } + +private: + CVTagRecord(llvm::codeview::ClassRecord &&c); + CVTagRecord(llvm::codeview::UnionRecord &&u); + CVTagRecord(llvm::codeview::EnumRecord &&e); + union { + llvm::codeview::ClassRecord cvclass; + llvm::codeview::EnumRecord cvenum; + llvm::codeview::UnionRecord cvunion; + }; + Kind m_kind; +}; + +struct SegmentOffset { + SegmentOffset() = default; + SegmentOffset(uint16_t s, uint32_t o) : segment(s), offset(o) {} + uint16_t segment = 0; + uint32_t offset = 0; +}; + +struct SegmentOffsetLength { + SegmentOffsetLength() = default; + SegmentOffsetLength(uint16_t s, uint32_t o, uint32_t l) + : so(s, o), length(l) {} + SegmentOffset so; + uint32_t length = 0; +}; + +struct VariableInfo { + llvm::StringRef name; + llvm::codeview::TypeIndex type; + llvm::Optional<DWARFExpression> location; + llvm::Optional<Variable::RangeList> ranges; +}; + +llvm::pdb::PDB_SymType CVSymToPDBSym(llvm::codeview::SymbolKind kind); +llvm::pdb::PDB_SymType CVTypeToPDBType(llvm::codeview::TypeLeafKind kind); + +bool SymbolHasAddress(const llvm::codeview::CVSymbol &sym); +bool SymbolIsCode(const llvm::codeview::CVSymbol &sym); + +SegmentOffset GetSegmentAndOffset(const llvm::codeview::CVSymbol &sym); +SegmentOffsetLength +GetSegmentOffsetAndLength(const llvm::codeview::CVSymbol &sym); + +template <typename RecordT> bool IsValidRecord(const RecordT &sym) { + return true; +} + +inline bool IsValidRecord(const llvm::codeview::ProcRefSym &sym) { + // S_PROCREF symbols have 1-based module indices. + return sym.Module > 0; +} + +bool IsForwardRefUdt(llvm::codeview::CVType cvt); +bool IsTagRecord(llvm::codeview::CVType cvt); +bool IsClassStructUnion(llvm::codeview::CVType cvt); + +bool IsForwardRefUdt(const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi); +bool IsTagRecord(const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi); + +lldb::AccessType TranslateMemberAccess(llvm::codeview::MemberAccess access); +llvm::codeview::TypeIndex GetFieldListIndex(llvm::codeview::CVType cvt); +llvm::codeview::TypeIndex +LookThroughModifierRecord(llvm::codeview::CVType modifier); + +llvm::StringRef DropNameScope(llvm::StringRef name); + +VariableInfo GetVariableNameInfo(llvm::codeview::CVSymbol symbol); +VariableInfo GetVariableLocationInfo(PdbIndex &index, PdbCompilandSymId var_id, + lldb::ModuleSP module); + +size_t GetTypeSizeForSimpleKind(llvm::codeview::SimpleTypeKind kind); +lldb::BasicType +GetCompilerTypeForSimpleKind(llvm::codeview::SimpleTypeKind kind); + +PdbTypeSymId GetBestPossibleDecl(PdbTypeSymId id, llvm::pdb::TpiStream &tpi); + +size_t GetSizeOfType(PdbTypeSymId id, llvm::pdb::TpiStream &tpi); + +} // namespace npdb +} // namespace lldb_private + +#endif diff --git a/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp new file mode 100644 index 000000000000..7e97e2b37724 --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -0,0 +1,1571 @@ +//===-- SymbolFileNativePDB.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SymbolFileNativePDB.h" + +#include "clang/AST/Attr.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" + +#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.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/ClangASTImporter.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangUtil.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Symbol/VariableList.h" + +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/RecordName.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Demangle/MicrosoftDemangle.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" + +#include "DWARFLocationExpression.h" +#include "PdbAstBuilder.h" +#include "PdbSymUid.h" +#include "PdbUtil.h" +#include "UdtRecordCompleter.h" + +using namespace lldb; +using namespace lldb_private; +using namespace npdb; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static lldb::LanguageType TranslateLanguage(PDB_Lang lang) { + switch (lang) { + case PDB_Lang::Cpp: + return lldb::LanguageType::eLanguageTypeC_plus_plus; + case PDB_Lang::C: + return lldb::LanguageType::eLanguageTypeC; + default: + return lldb::LanguageType::eLanguageTypeUnknown; + } +} + +static std::unique_ptr<PDBFile> loadPDBFile(std::string PdbPath, + llvm::BumpPtrAllocator &Allocator) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer = + llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); + if (!ErrorOrBuffer) + return nullptr; + std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); + + llvm::StringRef Path = Buffer->getBufferIdentifier(); + auto Stream = llvm::make_unique<llvm::MemoryBufferByteStream>( + std::move(Buffer), llvm::support::little); + + auto File = llvm::make_unique<PDBFile>(Path, std::move(Stream), Allocator); + if (auto EC = File->parseFileHeaders()) { + llvm::consumeError(std::move(EC)); + return nullptr; + } + if (auto EC = File->parseStreamData()) { + llvm::consumeError(std::move(EC)); + return nullptr; + } + + return File; +} + +static std::unique_ptr<PDBFile> +loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { + // Try to find a matching PDB for an EXE. + using namespace llvm::object; + auto expected_binary = createBinary(exe_path); + + // If the file isn't a PE/COFF executable, fail. + if (!expected_binary) { + llvm::consumeError(expected_binary.takeError()); + return nullptr; + } + OwningBinary<Binary> binary = std::move(*expected_binary); + + auto *obj = llvm::dyn_cast<llvm::object::COFFObjectFile>(binary.getBinary()); + if (!obj) + return nullptr; + const llvm::codeview::DebugInfo *pdb_info = nullptr; + + // If it doesn't have a debug directory, fail. + llvm::StringRef pdb_file; + auto ec = obj->getDebugPDBInfo(pdb_info, pdb_file); + if (ec) + 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); + if (ec || magic != llvm::file_magic::pdb) + return nullptr; + std::unique_ptr<PDBFile> pdb = loadPDBFile(pdb_file, allocator); + if (!pdb) + return nullptr; + + auto expected_info = pdb->getPDBInfoStream(); + if (!expected_info) { + llvm::consumeError(expected_info.takeError()); + return nullptr; + } + llvm::codeview::GUID guid; + memcpy(&guid, pdb_info->PDB70.Signature, 16); + + if (expected_info->getGuid() != guid) + return nullptr; + return pdb; +} + +static bool IsFunctionPrologue(const CompilandIndexItem &cci, + lldb::addr_t addr) { + // FIXME: Implement this. + return false; +} + +static bool IsFunctionEpilogue(const CompilandIndexItem &cci, + lldb::addr_t addr) { + // FIXME: Implement this. + return false; +} + +static llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) { + switch (kind) { + case SimpleTypeKind::Boolean128: + case SimpleTypeKind::Boolean16: + case SimpleTypeKind::Boolean32: + case SimpleTypeKind::Boolean64: + case SimpleTypeKind::Boolean8: + return "bool"; + case SimpleTypeKind::Byte: + case SimpleTypeKind::UnsignedCharacter: + return "unsigned char"; + case SimpleTypeKind::NarrowCharacter: + return "char"; + case SimpleTypeKind::SignedCharacter: + case SimpleTypeKind::SByte: + return "signed char"; + case SimpleTypeKind::Character16: + return "char16_t"; + case SimpleTypeKind::Character32: + return "char32_t"; + case SimpleTypeKind::Complex80: + case SimpleTypeKind::Complex64: + case SimpleTypeKind::Complex32: + return "complex"; + case SimpleTypeKind::Float128: + case SimpleTypeKind::Float80: + return "long double"; + case SimpleTypeKind::Float64: + return "double"; + case SimpleTypeKind::Float32: + return "float"; + case SimpleTypeKind::Float16: + return "single"; + case SimpleTypeKind::Int128: + return "__int128"; + case SimpleTypeKind::Int64: + case SimpleTypeKind::Int64Quad: + return "int64_t"; + case SimpleTypeKind::Int32: + return "int"; + case SimpleTypeKind::Int16: + return "short"; + case SimpleTypeKind::UInt128: + return "unsigned __int128"; + case SimpleTypeKind::UInt64: + case SimpleTypeKind::UInt64Quad: + return "uint64_t"; + case SimpleTypeKind::HResult: + return "HRESULT"; + case SimpleTypeKind::UInt32: + return "unsigned"; + case SimpleTypeKind::UInt16: + case SimpleTypeKind::UInt16Short: + return "unsigned short"; + case SimpleTypeKind::Int32Long: + return "long"; + case SimpleTypeKind::UInt32Long: + return "unsigned long"; + case SimpleTypeKind::Void: + return "void"; + case SimpleTypeKind::WideCharacter: + return "wchar_t"; + default: + return ""; + } +} + +static bool IsClassRecord(TypeLeafKind kind) { + switch (kind) { + case LF_STRUCTURE: + case LF_CLASS: + case LF_INTERFACE: + return true; + default: + return false; + } +} + +void SymbolFileNativePDB::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); +} + +void SymbolFileNativePDB::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +void SymbolFileNativePDB::DebuggerInitialize(Debugger &debugger) {} + +ConstString SymbolFileNativePDB::GetPluginNameStatic() { + static ConstString g_name("native-pdb"); + return g_name; +} + +const char *SymbolFileNativePDB::GetPluginDescriptionStatic() { + return "Microsoft PDB debug symbol cross-platform file reader."; +} + +SymbolFile *SymbolFileNativePDB::CreateInstance(ObjectFile *obj_file) { + return new SymbolFileNativePDB(obj_file); +} + +SymbolFileNativePDB::SymbolFileNativePDB(ObjectFile *object_file) + : SymbolFile(object_file) {} + +SymbolFileNativePDB::~SymbolFileNativePDB() {} + +uint32_t SymbolFileNativePDB::CalculateAbilities() { + uint32_t abilities = 0; + if (!m_obj_file) + return 0; + + if (!m_index) { + // Lazily load and match the PDB file, but only do this once. + std::unique_ptr<PDBFile> file_up = + loadMatchingPDBFile(m_obj_file->GetFileSpec().GetPath(), m_allocator); + + if (!file_up) { + auto module_sp = m_obj_file->GetModule(); + if (!module_sp) + return 0; + // See if any symbol file is specified through `--symfile` option. + FileSpec symfile = module_sp->GetSymbolFileFileSpec(); + if (!symfile) + return 0; + file_up = loadPDBFile(symfile.GetPath(), m_allocator); + } + + if (!file_up) + return 0; + + auto expected_index = PdbIndex::create(std::move(file_up)); + if (!expected_index) { + llvm::consumeError(expected_index.takeError()); + return 0; + } + m_index = std::move(*expected_index); + } + if (!m_index) + return 0; + + // We don't especially have to be precise here. We only distinguish between + // stripped and not stripped. + abilities = kAllAbilities; + + if (m_index->dbi().isStripped()) + abilities &= ~(Blocks | LocalVariables); + return abilities; +} + +void SymbolFileNativePDB::InitializeObject() { + m_obj_load_address = m_obj_file->GetFileOffset(); + m_index->SetLoadAddress(m_obj_load_address); + m_index->ParseSectionContribs(); + + TypeSystem *ts = m_obj_file->GetModule()->GetTypeSystemForLanguage( + lldb::eLanguageTypeC_plus_plus); + if (ts) + ts->SetSymbolFile(this); + + m_ast = llvm::make_unique<PdbAstBuilder>(*m_obj_file, *m_index); +} + +uint32_t SymbolFileNativePDB::GetNumCompileUnits() { + const DbiModuleList &modules = m_index->dbi().modules(); + uint32_t count = modules.getModuleCount(); + if (count == 0) + return count; + + // The linker can inject an additional "dummy" compilation unit into the + // PDB. Ignore this special compile unit for our purposes, if it is there. + // It is always the last one. + DbiModuleDescriptor last = modules.getModuleDescriptor(count - 1); + if (last.getModuleName() == "* Linker *") + --count; + return count; +} + +Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) { + CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi); + CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset); + + if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32) { + // This is a function. It must be global. Creating the Function entry for + // it automatically creates a block for it. + CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii); + return GetOrCreateFunction(block_id, *comp_unit)->GetBlock(false); + } + + lldbassert(sym.kind() == S_BLOCK32); + + // This is a block. Its parent is either a function or another block. In + // either case, its parent can be viewed as a block (e.g. a function contains + // 1 big block. So just get the parent block and add this block to it. + BlockSym block(static_cast<SymbolRecordKind>(sym.kind())); + cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block)); + lldbassert(block.Parent != 0); + PdbCompilandSymId parent_id(block_id.modi, block.Parent); + Block &parent_block = GetOrCreateBlock(parent_id); + lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id); + BlockSP child_block = std::make_shared<Block>(opaque_block_uid); + parent_block.AddChild(child_block); + + m_ast->GetOrCreateBlockDecl(block_id); + + m_blocks.insert({opaque_block_uid, child_block}); + return *child_block; +} + +lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id, + CompileUnit &comp_unit) { + const CompilandIndexItem *cci = + m_index->compilands().GetCompiland(func_id.modi); + lldbassert(cci); + CVSymbol sym_record = cci->m_debug_stream.readSymbolAtOffset(func_id.offset); + + lldbassert(sym_record.kind() == S_LPROC32 || sym_record.kind() == S_GPROC32); + SegmentOffsetLength sol = GetSegmentOffsetAndLength(sym_record); + + auto file_vm_addr = m_index->MakeVirtualAddress(sol.so); + if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0) + return nullptr; + + AddressRange func_range(file_vm_addr, sol.length, + comp_unit.GetModule()->GetSectionList()); + if (!func_range.GetBaseAddress().IsValid()) + return nullptr; + + ProcSym proc(static_cast<SymbolRecordKind>(sym_record.kind())); + cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym_record, proc)); + if (proc.FunctionType == TypeIndex::None()) + return nullptr; + TypeSP func_type = GetOrCreateType(proc.FunctionType); + if (!func_type) + return nullptr; + + PdbTypeSymId sig_id(proc.FunctionType, false); + Mangled mangled(proc.Name); + FunctionSP func_sp = std::make_shared<Function>( + &comp_unit, toOpaqueUid(func_id), toOpaqueUid(sig_id), mangled, + func_type.get(), func_range); + + comp_unit.AddFunction(func_sp); + + m_ast->GetOrCreateFunctionDecl(func_id); + + return func_sp; +} + +CompUnitSP +SymbolFileNativePDB::CreateCompileUnit(const CompilandIndexItem &cci) { + lldb::LanguageType lang = + cci.m_compile_opts ? TranslateLanguage(cci.m_compile_opts->getLanguage()) + : lldb::eLanguageTypeUnknown; + + LazyBool optimized = eLazyBoolNo; + if (cci.m_compile_opts && cci.m_compile_opts->hasOptimizations()) + optimized = eLazyBoolYes; + + llvm::SmallString<64> source_file_name = + m_index->compilands().GetMainSourceFile(cci); + FileSpec fs(source_file_name); + + CompUnitSP cu_sp = + std::make_shared<CompileUnit>(m_obj_file->GetModule(), nullptr, fs, + toOpaqueUid(cci.m_id), lang, optimized); + + m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex( + cci.m_id.modi, cu_sp); + return cu_sp; +} + +lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id, + const ModifierRecord &mr, + CompilerType ct) { + TpiStream &stream = m_index->tpi(); + + std::string name; + if (mr.ModifiedType.isSimple()) + name = GetSimpleTypeName(mr.ModifiedType.getSimpleKind()); + else + name = computeTypeName(stream.typeCollection(), mr.ModifiedType); + Declaration decl; + lldb::TypeSP modified_type = GetOrCreateType(mr.ModifiedType); + + return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(name), + modified_type->GetByteSize(), nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, + ct, Type::eResolveStateFull); +} + +lldb::TypeSP +SymbolFileNativePDB::CreatePointerType(PdbTypeSymId type_id, + const llvm::codeview::PointerRecord &pr, + CompilerType ct) { + TypeSP pointee = GetOrCreateType(pr.ReferentType); + if (!pointee) + return nullptr; + + if (pr.isPointerToMember()) { + MemberPointerInfo mpi = pr.getMemberInfo(); + GetOrCreateType(mpi.ContainingType); + } + + Declaration decl; + return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(), + pr.getSize(), nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, decl, ct, + Type::eResolveStateFull); +} + +lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti, + CompilerType ct) { + uint64_t uid = toOpaqueUid(PdbTypeSymId(ti, false)); + if (ti == TypeIndex::NullptrT()) { + Declaration decl; + return std::make_shared<Type>( + uid, this, ConstString("std::nullptr_t"), 0, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, decl, ct, Type::eResolveStateFull); + } + + if (ti.getSimpleMode() != SimpleTypeMode::Direct) { + TypeSP direct_sp = GetOrCreateType(ti.makeDirect()); + uint32_t pointer_size = 0; + switch (ti.getSimpleMode()) { + case SimpleTypeMode::FarPointer32: + case SimpleTypeMode::NearPointer32: + pointer_size = 4; + break; + case SimpleTypeMode::NearPointer64: + pointer_size = 8; + break; + default: + // 128-bit and 16-bit pointers unsupported. + return nullptr; + } + Declaration decl; + return std::make_shared<Type>( + uid, this, ConstString(), pointer_size, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, decl, ct, Type::eResolveStateFull); + } + + if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated) + return nullptr; + + size_t size = GetTypeSizeForSimpleKind(ti.getSimpleKind()); + llvm::StringRef type_name = GetSimpleTypeName(ti.getSimpleKind()); + + Declaration decl; + return std::make_shared<Type>(uid, this, ConstString(type_name), size, + nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, + decl, ct, Type::eResolveStateFull); +} + +static std::string GetUnqualifiedTypeName(const TagRecord &record) { + if (!record.hasUniqueName()) { + MSVCUndecoratedNameParser parser(record.Name); + llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers(); + + return 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; + + llvm::ms_demangle::IdentifierNode *idn = + ttn->QualifiedName->getUnqualifiedIdentifier(); + return idn->toString(); +} + +lldb::TypeSP +SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id, + const TagRecord &record, + size_t size, CompilerType ct) { + + std::string uname = GetUnqualifiedTypeName(record); + + // FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE. + Declaration decl; + return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(uname), + size, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, decl, ct, + Type::eResolveStateForward); +} + +lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, + const ClassRecord &cr, + CompilerType ct) { + return CreateClassStructUnion(type_id, cr, cr.getSize(), ct); +} + +lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, + const UnionRecord &ur, + CompilerType ct) { + return CreateClassStructUnion(type_id, ur, ur.getSize(), ct); +} + +lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, + const EnumRecord &er, + CompilerType ct) { + std::string uname = GetUnqualifiedTypeName(er); + + Declaration decl; + TypeSP underlying_type = GetOrCreateType(er.UnderlyingType); + + return std::make_shared<lldb_private::Type>( + toOpaqueUid(type_id), this, ConstString(uname), + underlying_type->GetByteSize(), nullptr, LLDB_INVALID_UID, + lldb_private::Type::eEncodingIsUID, decl, ct, + lldb_private::Type::eResolveStateForward); +} + +TypeSP SymbolFileNativePDB::CreateArrayType(PdbTypeSymId type_id, + const ArrayRecord &ar, + CompilerType ct) { + TypeSP element_type = GetOrCreateType(ar.ElementType); + + Declaration decl; + TypeSP array_sp = std::make_shared<lldb_private::Type>( + toOpaqueUid(type_id), this, ConstString(), ar.Size, nullptr, + LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct, + lldb_private::Type::eResolveStateFull); + array_sp->SetEncodingType(element_type.get()); + return array_sp; +} + +TypeSP SymbolFileNativePDB::CreateProcedureType(PdbTypeSymId type_id, + const ProcedureRecord &pr, + CompilerType ct) { + Declaration decl; + return std::make_shared<lldb_private::Type>( + toOpaqueUid(type_id), this, ConstString(), 0, nullptr, LLDB_INVALID_UID, + lldb_private::Type::eEncodingIsUID, decl, ct, + lldb_private::Type::eResolveStateFull); +} + +TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id, CompilerType ct) { + if (type_id.index.isSimple()) + return CreateSimpleType(type_id.index, ct); + + TpiStream &stream = type_id.is_ipi ? m_index->ipi() : m_index->tpi(); + CVType cvt = stream.getType(type_id.index); + + if (cvt.kind() == LF_MODIFIER) { + ModifierRecord modifier; + llvm::cantFail( + TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier)); + return CreateModifierType(type_id, modifier, ct); + } + + if (cvt.kind() == LF_POINTER) { + PointerRecord pointer; + llvm::cantFail( + TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer)); + return CreatePointerType(type_id, pointer, ct); + } + + if (IsClassRecord(cvt.kind())) { + ClassRecord cr; + llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr)); + return CreateTagType(type_id, cr, ct); + } + + if (cvt.kind() == LF_ENUM) { + EnumRecord er; + llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er)); + return CreateTagType(type_id, er, ct); + } + + if (cvt.kind() == LF_UNION) { + UnionRecord ur; + llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur)); + return CreateTagType(type_id, ur, ct); + } + + if (cvt.kind() == LF_ARRAY) { + ArrayRecord ar; + llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar)); + return CreateArrayType(type_id, ar, ct); + } + + if (cvt.kind() == LF_PROCEDURE) { + ProcedureRecord pr; + llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr)); + return CreateProcedureType(type_id, pr, ct); + } + + return nullptr; +} + +TypeSP SymbolFileNativePDB::CreateAndCacheType(PdbTypeSymId type_id) { + // If they search for a UDT which is a forward ref, try and resolve the full + // decl and just map the forward ref uid to the full decl record. + llvm::Optional<PdbTypeSymId> full_decl_uid; + if (IsForwardRefUdt(type_id, m_index->tpi())) { + auto expected_full_ti = + m_index->tpi().findFullDeclForForwardRef(type_id.index); + if (!expected_full_ti) + llvm::consumeError(expected_full_ti.takeError()); + else if (*expected_full_ti != type_id.index) { + full_decl_uid = PdbTypeSymId(*expected_full_ti, false); + + // It's possible that a lookup would occur for the full decl causing it + // to be cached, then a second lookup would occur for the forward decl. + // We don't want to create a second full decl, so make sure the full + // decl hasn't already been cached. + auto full_iter = m_types.find(toOpaqueUid(*full_decl_uid)); + if (full_iter != m_types.end()) { + TypeSP result = full_iter->second; + // Map the forward decl to the TypeSP for the full decl so we can take + // the fast path next time. + m_types[toOpaqueUid(type_id)] = result; + return result; + } + } + } + + PdbTypeSymId best_decl_id = full_decl_uid ? *full_decl_uid : type_id; + + clang::QualType qt = m_ast->GetOrCreateType(best_decl_id); + + TypeSP result = CreateType(best_decl_id, m_ast->ToCompilerType(qt)); + if (!result) + return nullptr; + + uint64_t best_uid = toOpaqueUid(best_decl_id); + m_types[best_uid] = result; + // If we had both a forward decl and a full decl, make both point to the new + // type. + if (full_decl_uid) + m_types[toOpaqueUid(type_id)] = result; + + return result; +} + +TypeSP SymbolFileNativePDB::GetOrCreateType(PdbTypeSymId type_id) { + // We can't use try_emplace / overwrite here because the process of creating + // a type could create nested types, which could invalidate iterators. So + // we have to do a 2-phase lookup / insert. + auto iter = m_types.find(toOpaqueUid(type_id)); + if (iter != m_types.end()) + return iter->second; + + TypeSP type = CreateAndCacheType(type_id); + if (type) + m_obj_file->GetModule()->GetTypeList()->Insert(type); + return type; +} + +VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) { + CVSymbol sym = m_index->symrecords().readRecord(var_id.offset); + if (sym.kind() == S_CONSTANT) + return CreateConstantSymbol(var_id, sym); + + lldb::ValueType scope = eValueTypeInvalid; + TypeIndex ti; + llvm::StringRef name; + lldb::addr_t addr = 0; + uint16_t section = 0; + uint32_t offset = 0; + bool is_external = false; + switch (sym.kind()) { + case S_GDATA32: + is_external = true; + LLVM_FALLTHROUGH; + case S_LDATA32: { + DataSym ds(sym.kind()); + llvm::cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, ds)); + ti = ds.Type; + scope = (sym.kind() == S_GDATA32) ? eValueTypeVariableGlobal + : eValueTypeVariableStatic; + name = ds.Name; + section = ds.Segment; + offset = ds.DataOffset; + addr = m_index->MakeVirtualAddress(ds.Segment, ds.DataOffset); + break; + } + case S_GTHREAD32: + is_external = true; + LLVM_FALLTHROUGH; + case S_LTHREAD32: { + ThreadLocalDataSym tlds(sym.kind()); + llvm::cantFail( + SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, tlds)); + ti = tlds.Type; + name = tlds.Name; + section = tlds.Segment; + offset = tlds.DataOffset; + addr = m_index->MakeVirtualAddress(tlds.Segment, tlds.DataOffset); + scope = eValueTypeVariableThreadLocal; + break; + } + default: + llvm_unreachable("unreachable!"); + } + + CompUnitSP comp_unit; + llvm::Optional<uint16_t> modi = m_index->GetModuleIndexForVa(addr); + if (modi) { + CompilandIndexItem &cci = m_index->compilands().GetOrCreateCompiland(*modi); + comp_unit = GetOrCreateCompileUnit(cci); + } + + Declaration decl; + PdbTypeSymId tid(ti, false); + SymbolFileTypeSP type_sp = + std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid)); + Variable::RangeList ranges; + + m_ast->GetOrCreateVariableDecl(var_id); + + DWARFExpression location = MakeGlobalLocationExpression( + section, offset, GetObjectFile()->GetModule()); + + std::string global_name("::"); + global_name += name; + VariableSP var_sp = std::make_shared<Variable>( + toOpaqueUid(var_id), name.str().c_str(), global_name.c_str(), type_sp, + scope, comp_unit.get(), ranges, &decl, location, is_external, false, + false); + var_sp->SetLocationIsConstantValueData(false); + + return var_sp; +} + +lldb::VariableSP +SymbolFileNativePDB::CreateConstantSymbol(PdbGlobalSymId var_id, + const CVSymbol &cvs) { + TpiStream &tpi = m_index->tpi(); + ConstantSym constant(cvs.kind()); + + llvm::cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(cvs, constant)); + std::string global_name("::"); + global_name += constant.Name; + PdbTypeSymId tid(constant.Type, false); + SymbolFileTypeSP type_sp = + std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid)); + + Declaration decl; + Variable::RangeList ranges; + ModuleSP module = GetObjectFile()->GetModule(); + DWARFExpression location = MakeConstantLocationExpression( + constant.Type, tpi, constant.Value, module); + + VariableSP var_sp = std::make_shared<Variable>( + toOpaqueUid(var_id), constant.Name.str().c_str(), global_name.c_str(), + type_sp, eValueTypeVariableGlobal, module.get(), ranges, &decl, location, + false, false, false); + var_sp->SetLocationIsConstantValueData(true); + return var_sp; +} + +VariableSP +SymbolFileNativePDB::GetOrCreateGlobalVariable(PdbGlobalSymId var_id) { + auto emplace_result = m_global_vars.try_emplace(toOpaqueUid(var_id), nullptr); + if (emplace_result.second) + emplace_result.first->second = CreateGlobalVariable(var_id); + + return emplace_result.first->second; +} + +lldb::TypeSP SymbolFileNativePDB::GetOrCreateType(TypeIndex ti) { + return GetOrCreateType(PdbTypeSymId(ti, false)); +} + +FunctionSP SymbolFileNativePDB::GetOrCreateFunction(PdbCompilandSymId func_id, + CompileUnit &comp_unit) { + auto emplace_result = m_functions.try_emplace(toOpaqueUid(func_id), nullptr); + if (emplace_result.second) + emplace_result.first->second = CreateFunction(func_id, comp_unit); + + return emplace_result.first->second; +} + +CompUnitSP +SymbolFileNativePDB::GetOrCreateCompileUnit(const CompilandIndexItem &cci) { + + auto emplace_result = + m_compilands.try_emplace(toOpaqueUid(cci.m_id), nullptr); + if (emplace_result.second) + emplace_result.first->second = CreateCompileUnit(cci); + + lldbassert(emplace_result.first->second); + return emplace_result.first->second; +} + +Block &SymbolFileNativePDB::GetOrCreateBlock(PdbCompilandSymId block_id) { + auto iter = m_blocks.find(toOpaqueUid(block_id)); + if (iter != m_blocks.end()) + return *iter->second; + + return CreateBlock(block_id); +} + +void SymbolFileNativePDB::ParseDeclsForContext( + lldb_private::CompilerDeclContext decl_ctx) { + clang::DeclContext *context = m_ast->FromCompilerDeclContext(decl_ctx); + if (!context) + return; + m_ast->ParseDeclsForContext(*context); +} + +lldb::CompUnitSP SymbolFileNativePDB::ParseCompileUnitAtIndex(uint32_t index) { + if (index >= GetNumCompileUnits()) + return CompUnitSP(); + lldbassert(index < UINT16_MAX); + if (index >= UINT16_MAX) + return nullptr; + + CompilandIndexItem &item = m_index->compilands().GetOrCreateCompiland(index); + + return GetOrCreateCompileUnit(item); +} + +lldb::LanguageType SymbolFileNativePDB::ParseLanguage(CompileUnit &comp_unit) { + PdbSymUid uid(comp_unit.GetID()); + lldbassert(uid.kind() == PdbSymUidKind::Compiland); + + CompilandIndexItem *item = + m_index->compilands().GetCompiland(uid.asCompiland().modi); + lldbassert(item); + if (!item->m_compile_opts) + return lldb::eLanguageTypeUnknown; + + return TranslateLanguage(item->m_compile_opts->getLanguage()); +} + +void SymbolFileNativePDB::AddSymbols(Symtab &symtab) { return; } + +size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) { + PdbSymUid uid{comp_unit.GetID()}; + lldbassert(uid.kind() == PdbSymUidKind::Compiland); + uint16_t modi = uid.asCompiland().modi; + CompilandIndexItem &cii = m_index->compilands().GetOrCreateCompiland(modi); + + size_t count = comp_unit.GetNumFunctions(); + const CVSymbolArray &syms = cii.m_debug_stream.getSymbolArray(); + for (auto iter = syms.begin(); iter != syms.end(); ++iter) { + if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32) + continue; + + PdbCompilandSymId sym_id{modi, iter.offset()}; + + FunctionSP func = GetOrCreateFunction(sym_id, comp_unit); + } + + size_t new_count = comp_unit.GetNumFunctions(); + lldbassert(new_count >= count); + return new_count - count; +} + +static bool NeedsResolvedCompileUnit(uint32_t resolve_scope) { + // If any of these flags are set, we need to resolve the compile unit. + uint32_t flags = eSymbolContextCompUnit; + flags |= eSymbolContextVariable; + flags |= eSymbolContextFunction; + flags |= eSymbolContextBlock; + flags |= eSymbolContextLineEntry; + return (resolve_scope & flags) != 0; +} + +uint32_t SymbolFileNativePDB::ResolveSymbolContext( + const Address &addr, SymbolContextItem resolve_scope, SymbolContext &sc) { + uint32_t resolved_flags = 0; + lldb::addr_t file_addr = addr.GetFileAddress(); + + if (NeedsResolvedCompileUnit(resolve_scope)) { + llvm::Optional<uint16_t> modi = m_index->GetModuleIndexForVa(file_addr); + if (!modi) + return 0; + CompilandIndexItem *cci = m_index->compilands().GetCompiland(*modi); + if (!cci) + return 0; + + sc.comp_unit = GetOrCreateCompileUnit(*cci).get(); + resolved_flags |= eSymbolContextCompUnit; + } + + if (resolve_scope & eSymbolContextFunction || + resolve_scope & eSymbolContextBlock) { + lldbassert(sc.comp_unit); + std::vector<SymbolAndUid> matches = m_index->FindSymbolsByVa(file_addr); + // Search the matches in reverse. This way if there are multiple matches + // (for example we are 3 levels deep in a nested scope) it will find the + // innermost one first. + for (const auto &match : llvm::reverse(matches)) { + if (match.uid.kind() != PdbSymUidKind::CompilandSym) + continue; + + PdbCompilandSymId csid = match.uid.asCompilandSym(); + CVSymbol cvs = m_index->ReadSymbolRecord(csid); + PDB_SymType type = CVSymToPDBSym(cvs.kind()); + if (type != PDB_SymType::Function && type != PDB_SymType::Block) + continue; + if (type == PDB_SymType::Function) { + sc.function = GetOrCreateFunction(csid, *sc.comp_unit).get(); + sc.block = sc.GetFunctionBlock(); + } + + if (type == PDB_SymType::Block) { + sc.block = &GetOrCreateBlock(csid); + sc.function = sc.block->CalculateSymbolContextFunction(); + } + resolved_flags |= eSymbolContextFunction; + resolved_flags |= eSymbolContextBlock; + break; + } + } + + if (resolve_scope & eSymbolContextLineEntry) { + lldbassert(sc.comp_unit); + if (auto *line_table = sc.comp_unit->GetLineTable()) { + if (line_table->FindLineEntryByAddress(addr, sc.line_entry)) + resolved_flags |= eSymbolContextLineEntry; + } + } + + return resolved_flags; +} + +uint32_t SymbolFileNativePDB::ResolveSymbolContext( + const FileSpec &file_spec, uint32_t line, bool check_inlines, + lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) { + return 0; +} + +static void AppendLineEntryToSequence(LineTable &table, LineSequence &sequence, + const CompilandIndexItem &cci, + lldb::addr_t base_addr, + uint32_t file_number, + const LineFragmentHeader &block, + const LineNumberEntry &cur) { + LineInfo cur_info(cur.Flags); + + if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto()) + return; + + uint64_t addr = base_addr + cur.Offset; + + bool is_statement = cur_info.isStatement(); + bool is_prologue = IsFunctionPrologue(cci, addr); + bool is_epilogue = IsFunctionEpilogue(cci, addr); + + uint32_t lno = cur_info.getStartLine(); + + table.AppendLineEntryToSequence(&sequence, addr, lno, 0, file_number, + is_statement, false, is_prologue, is_epilogue, + false); +} + +static void TerminateLineSequence(LineTable &table, + const LineFragmentHeader &block, + lldb::addr_t base_addr, uint32_t file_number, + uint32_t last_line, + std::unique_ptr<LineSequence> seq) { + // The end is always a terminal entry, so insert it regardless. + table.AppendLineEntryToSequence(seq.get(), base_addr + block.CodeSize, + last_line, 0, file_number, false, false, + false, false, true); + table.InsertSequence(seq.release()); +} + +bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) { + // Unfortunately LLDB is set up to parse the entire compile unit line table + // all at once, even if all it really needs is line info for a specific + // function. In the future it would be nice if it could set the sc.m_function + // member, and we could only get the line info for the function in question. + PdbSymUid cu_id(comp_unit.GetID()); + lldbassert(cu_id.kind() == PdbSymUidKind::Compiland); + CompilandIndexItem *cci = + m_index->compilands().GetCompiland(cu_id.asCompiland().modi); + lldbassert(cci); + auto line_table = llvm::make_unique<LineTable>(&comp_unit); + + // This is basically a copy of the .debug$S subsections from all original COFF + // object files merged together with address relocations applied. We are + // looking for all DEBUG_S_LINES subsections. + for (const DebugSubsectionRecord &dssr : + cci->m_debug_stream.getSubsectionsArray()) { + if (dssr.kind() != DebugSubsectionKind::Lines) + continue; + + DebugLinesSubsectionRef lines; + llvm::BinaryStreamReader reader(dssr.getRecordData()); + if (auto EC = lines.initialize(reader)) { + llvm::consumeError(std::move(EC)); + return false; + } + + const LineFragmentHeader *lfh = lines.header(); + uint64_t virtual_addr = + m_index->MakeVirtualAddress(lfh->RelocSegment, lfh->RelocOffset); + + const auto &checksums = cci->m_strings.checksums().getArray(); + const auto &strings = cci->m_strings.strings(); + for (const LineColumnEntry &group : lines) { + // Indices in this structure are actually offsets of records in the + // DEBUG_S_FILECHECKSUMS subsection. Those entries then have an index + // into the global PDB string table. + auto iter = checksums.at(group.NameIndex); + if (iter == checksums.end()) + continue; + + llvm::Expected<llvm::StringRef> efn = + strings.getString(iter->FileNameOffset); + if (!efn) { + llvm::consumeError(efn.takeError()); + continue; + } + + // LLDB wants the index of the file in the list of support files. + auto fn_iter = llvm::find(cci->m_file_list, *efn); + lldbassert(fn_iter != cci->m_file_list.end()); + // LLDB support file indices are 1-based. + uint32_t file_index = + 1 + std::distance(cci->m_file_list.begin(), fn_iter); + + std::unique_ptr<LineSequence> sequence( + line_table->CreateLineSequenceContainer()); + lldbassert(!group.LineNumbers.empty()); + + for (const LineNumberEntry &entry : group.LineNumbers) { + AppendLineEntryToSequence(*line_table, *sequence, *cci, virtual_addr, + file_index, *lfh, entry); + } + LineInfo last_line(group.LineNumbers.back().Flags); + TerminateLineSequence(*line_table, *lfh, virtual_addr, file_index, + last_line.getEndLine(), std::move(sequence)); + } + } + + if (line_table->GetSize() == 0) + return false; + + comp_unit.SetLineTable(line_table.release()); + return true; +} + +bool SymbolFileNativePDB::ParseDebugMacros(CompileUnit &comp_unit) { + // PDB doesn't contain information about macros + return false; +} + +bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit, + FileSpecList &support_files) { + PdbSymUid cu_id(comp_unit.GetID()); + lldbassert(cu_id.kind() == PdbSymUidKind::Compiland); + CompilandIndexItem *cci = + m_index->compilands().GetCompiland(cu_id.asCompiland().modi); + lldbassert(cci); + + for (llvm::StringRef f : cci->m_file_list) { + FileSpec::Style style = + f.startswith("/") ? FileSpec::Style::posix : FileSpec::Style::windows; + FileSpec spec(f, style); + support_files.Append(spec); + } + + llvm::SmallString<64> main_source_file = + m_index->compilands().GetMainSourceFile(*cci); + FileSpec::Style style = main_source_file.startswith("/") + ? FileSpec::Style::posix + : FileSpec::Style::windows; + FileSpec spec(main_source_file, style); + support_files.Insert(0, spec); + return true; +} + +bool SymbolFileNativePDB::ParseImportedModules( + const SymbolContext &sc, std::vector<ConstString> &imported_modules) { + // PDB does not yet support module debug info + return false; +} + +size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) { + GetOrCreateBlock(PdbSymUid(func.GetID()).asCompilandSym()); + // FIXME: Parse child blocks + return 1; +} + +void SymbolFileNativePDB::DumpClangAST(Stream &s) { m_ast->Dump(s); } + +uint32_t SymbolFileNativePDB::FindGlobalVariables( + const ConstString &name, const CompilerDeclContext *parent_decl_ctx, + uint32_t max_matches, VariableList &variables) { + using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>; + + std::vector<SymbolAndOffset> results = m_index->globals().findRecordsByName( + name.GetStringRef(), m_index->symrecords()); + for (const SymbolAndOffset &result : results) { + VariableSP var; + switch (result.second.kind()) { + case SymbolKind::S_GDATA32: + case SymbolKind::S_LDATA32: + case SymbolKind::S_GTHREAD32: + case SymbolKind::S_LTHREAD32: + case SymbolKind::S_CONSTANT: { + PdbGlobalSymId global(result.first, false); + var = GetOrCreateGlobalVariable(global); + variables.AddVariable(var); + break; + } + default: + continue; + } + } + return variables.GetSize(); +} + +uint32_t SymbolFileNativePDB::FindFunctions( + const ConstString &name, const CompilerDeclContext *parent_decl_ctx, + FunctionNameType name_type_mask, bool include_inlines, bool append, + SymbolContextList &sc_list) { + // For now we only support lookup by method name. + if (!(name_type_mask & eFunctionNameTypeMethod)) + return 0; + + using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>; + + std::vector<SymbolAndOffset> matches = m_index->globals().findRecordsByName( + name.GetStringRef(), m_index->symrecords()); + for (const SymbolAndOffset &match : matches) { + if (match.second.kind() != S_PROCREF && match.second.kind() != S_LPROCREF) + continue; + ProcRefSym proc(match.second.kind()); + cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(match.second, proc)); + + if (!IsValidRecord(proc)) + continue; + + CompilandIndexItem &cci = + m_index->compilands().GetOrCreateCompiland(proc.modi()); + SymbolContext sc; + + sc.comp_unit = GetOrCreateCompileUnit(cci).get(); + PdbCompilandSymId func_id(proc.modi(), proc.SymOffset); + sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get(); + + sc_list.Append(sc); + } + + return sc_list.GetSize(); +} + +uint32_t SymbolFileNativePDB::FindFunctions(const RegularExpression ®ex, + bool include_inlines, bool append, + SymbolContextList &sc_list) { + return 0; +} + +uint32_t SymbolFileNativePDB::FindTypes( + const ConstString &name, const CompilerDeclContext *parent_decl_ctx, + bool append, uint32_t max_matches, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) { + if (!append) + types.Clear(); + if (!name) + return 0; + + searched_symbol_files.clear(); + searched_symbol_files.insert(this); + + // There is an assumption 'name' is not a regex + size_t match_count = FindTypesByName(name.GetStringRef(), max_matches, types); + + return match_count; +} + +size_t +SymbolFileNativePDB::FindTypes(const std::vector<CompilerContext> &context, + bool append, TypeMap &types) { + return 0; +} + +size_t SymbolFileNativePDB::FindTypesByName(llvm::StringRef name, + uint32_t max_matches, + TypeMap &types) { + + size_t match_count = 0; + std::vector<TypeIndex> matches = m_index->tpi().findRecordsByName(name); + if (max_matches > 0 && max_matches < matches.size()) + matches.resize(max_matches); + + for (TypeIndex ti : matches) { + TypeSP type = GetOrCreateType(ti); + if (!type) + continue; + + types.Insert(type); + ++match_count; + } + return match_count; +} + +size_t SymbolFileNativePDB::ParseTypes(CompileUnit &comp_unit) { + // Only do the full type scan the first time. + if (m_done_full_type_scan) + return 0; + + size_t old_count = m_obj_file->GetModule()->GetTypeList()->GetSize(); + LazyRandomTypeCollection &types = m_index->tpi().typeCollection(); + + // First process the entire TPI stream. + for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) { + TypeSP type = GetOrCreateType(*ti); + if (type) + (void)type->GetFullCompilerType(); + } + + // Next look for S_UDT records in the globals stream. + for (const uint32_t gid : m_index->globals().getGlobalsTable()) { + PdbGlobalSymId global{gid, false}; + CVSymbol sym = m_index->ReadSymbolRecord(global); + if (sym.kind() != S_UDT) + continue; + + UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym)); + bool is_typedef = true; + if (IsTagRecord(PdbTypeSymId{udt.Type, false}, m_index->tpi())) { + CVType cvt = m_index->tpi().getType(udt.Type); + llvm::StringRef name = CVTagRecord::create(cvt).name(); + if (name == udt.Name) + is_typedef = false; + } + + if (is_typedef) + GetOrCreateTypedef(global); + } + + size_t new_count = m_obj_file->GetModule()->GetTypeList()->GetSize(); + + m_done_full_type_scan = true; + + return new_count - old_count; +} + +size_t +SymbolFileNativePDB::ParseVariablesForCompileUnit(CompileUnit &comp_unit, + VariableList &variables) { + PdbSymUid sym_uid(comp_unit.GetID()); + lldbassert(sym_uid.kind() == PdbSymUidKind::Compiland); + return 0; +} + +VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id, + PdbCompilandSymId var_id, + bool is_param) { + ModuleSP module = GetObjectFile()->GetModule(); + VariableInfo var_info = GetVariableLocationInfo(*m_index, var_id, module); + if (!var_info.location || !var_info.ranges) + return nullptr; + + CompilandIndexItem *cii = m_index->compilands().GetCompiland(var_id.modi); + CompUnitSP comp_unit_sp = GetOrCreateCompileUnit(*cii); + TypeSP type_sp = GetOrCreateType(var_info.type); + std::string name = var_info.name.str(); + Declaration decl; + SymbolFileTypeSP sftype = + std::make_shared<SymbolFileType>(*this, type_sp->GetID()); + + ValueType var_scope = + is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal; + VariableSP var_sp = std::make_shared<Variable>( + toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope, + comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, false, + false, false); + + if (!is_param) + m_ast->GetOrCreateVariableDecl(scope_id, var_id); + + m_local_variables[toOpaqueUid(var_id)] = var_sp; + return var_sp; +} + +VariableSP SymbolFileNativePDB::GetOrCreateLocalVariable( + PdbCompilandSymId scope_id, PdbCompilandSymId var_id, bool is_param) { + auto iter = m_local_variables.find(toOpaqueUid(var_id)); + if (iter != m_local_variables.end()) + return iter->second; + + return CreateLocalVariable(scope_id, var_id, is_param); +} + +TypeSP SymbolFileNativePDB::CreateTypedef(PdbGlobalSymId id) { + CVSymbol sym = m_index->ReadSymbolRecord(id); + lldbassert(sym.kind() == SymbolKind::S_UDT); + + UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym)); + + TypeSP target_type = GetOrCreateType(udt.Type); + + (void)m_ast->GetOrCreateTypedefDecl(id); + + Declaration decl; + return std::make_shared<lldb_private::Type>( + toOpaqueUid(id), this, ConstString(udt.Name), target_type->GetByteSize(), + nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID, + decl, target_type->GetForwardCompilerType(), + lldb_private::Type::eResolveStateForward); +} + +TypeSP SymbolFileNativePDB::GetOrCreateTypedef(PdbGlobalSymId id) { + auto iter = m_types.find(toOpaqueUid(id)); + if (iter != m_types.end()) + return iter->second; + + return CreateTypedef(id); +} + +size_t SymbolFileNativePDB::ParseVariablesForBlock(PdbCompilandSymId block_id) { + Block &block = GetOrCreateBlock(block_id); + + size_t count = 0; + + CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi); + CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset); + uint32_t params_remaining = 0; + switch (sym.kind()) { + case S_GPROC32: + case S_LPROC32: { + ProcSym proc(static_cast<SymbolRecordKind>(sym.kind())); + cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym, proc)); + CVType signature = m_index->tpi().getType(proc.FunctionType); + ProcedureRecord sig; + cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(signature, sig)); + params_remaining = sig.getParameterCount(); + break; + } + case S_BLOCK32: + break; + default: + lldbassert(false && "Symbol is not a block!"); + return 0; + } + + VariableListSP variables = block.GetBlockVariableList(false); + if (!variables) { + variables = std::make_shared<VariableList>(); + block.SetVariableList(variables); + } + + CVSymbolArray syms = limitSymbolArrayToScope( + cii->m_debug_stream.getSymbolArray(), block_id.offset); + + // Skip the first record since it's a PROC32 or BLOCK32, and there's + // no point examining it since we know it's not a local variable. + syms.drop_front(); + auto iter = syms.begin(); + auto end = syms.end(); + + while (iter != end) { + uint32_t record_offset = iter.offset(); + CVSymbol variable_cvs = *iter; + PdbCompilandSymId child_sym_id(block_id.modi, record_offset); + ++iter; + + // If this is a block, recurse into its children and then skip it. + if (variable_cvs.kind() == S_BLOCK32) { + uint32_t block_end = getScopeEndOffset(variable_cvs); + count += ParseVariablesForBlock(child_sym_id); + iter = syms.at(block_end); + continue; + } + + bool is_param = params_remaining > 0; + VariableSP variable; + switch (variable_cvs.kind()) { + case S_REGREL32: + case S_REGISTER: + case S_LOCAL: + variable = GetOrCreateLocalVariable(block_id, child_sym_id, is_param); + if (is_param) + --params_remaining; + if (variable) + variables->AddVariableIfUnique(variable); + break; + default: + break; + } + } + + // Pass false for set_children, since we call this recursively so that the + // children will call this for themselves. + block.SetDidParseVariables(true, false); + + return count; +} + +size_t SymbolFileNativePDB::ParseVariablesForContext(const SymbolContext &sc) { + lldbassert(sc.function || sc.comp_unit); + + VariableListSP variables; + if (sc.block) { + PdbSymUid block_id(sc.block->GetID()); + + size_t count = ParseVariablesForBlock(block_id.asCompilandSym()); + return count; + } + + if (sc.function) { + PdbSymUid block_id(sc.function->GetID()); + + size_t count = ParseVariablesForBlock(block_id.asCompilandSym()); + return count; + } + + if (sc.comp_unit) { + variables = sc.comp_unit->GetVariableList(false); + if (!variables) { + variables = std::make_shared<VariableList>(); + sc.comp_unit->SetVariableList(variables); + } + return ParseVariablesForCompileUnit(*sc.comp_unit, *variables); + } + + llvm_unreachable("Unreachable!"); +} + +CompilerDecl SymbolFileNativePDB::GetDeclForUID(lldb::user_id_t uid) { + clang::Decl *decl = m_ast->GetOrCreateDeclForUid(PdbSymUid(uid)); + + return m_ast->ToCompilerDecl(*decl); +} + +CompilerDeclContext +SymbolFileNativePDB::GetDeclContextForUID(lldb::user_id_t uid) { + clang::DeclContext *context = + m_ast->GetOrCreateDeclContextForUid(PdbSymUid(uid)); + if (!context) + return {}; + + return m_ast->ToCompilerDeclContext(*context); +} + +CompilerDeclContext +SymbolFileNativePDB::GetDeclContextContainingUID(lldb::user_id_t uid) { + clang::DeclContext *context = m_ast->GetParentDeclContext(PdbSymUid(uid)); + return m_ast->ToCompilerDeclContext(*context); +} + +Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) { + auto iter = m_types.find(type_uid); + // lldb should not be passing us non-sensical type uids. the only way it + // could have a type uid in the first place is if we handed it out, in which + // case we should know about the type. However, that doesn't mean we've + // instantiated it yet. We can vend out a UID for a future type. So if the + // type doesn't exist, let's instantiate it now. + if (iter != m_types.end()) + return &*iter->second; + + PdbSymUid uid(type_uid); + lldbassert(uid.kind() == PdbSymUidKind::Type); + PdbTypeSymId type_id = uid.asTypeSym(); + if (type_id.index.isNoneType()) + return nullptr; + + TypeSP type_sp = CreateAndCacheType(type_id); + return &*type_sp; +} + +llvm::Optional<SymbolFile::ArrayInfo> +SymbolFileNativePDB::GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) { + return llvm::None; +} + + +bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) { + clang::QualType qt = + clang::QualType::getFromOpaquePtr(compiler_type.GetOpaqueQualType()); + + return m_ast->CompleteType(qt); +} + +size_t SymbolFileNativePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope, + TypeClass type_mask, + lldb_private::TypeList &type_list) { + return 0; +} + +CompilerDeclContext +SymbolFileNativePDB::FindNamespace(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx) { + return {}; +} + +TypeSystem * +SymbolFileNativePDB::GetTypeSystemForLanguage(lldb::LanguageType language) { + auto type_system = + m_obj_file->GetModule()->GetTypeSystemForLanguage(language); + if (type_system) + type_system->SetSymbolFile(this); + return type_system; +} + +ConstString SymbolFileNativePDB::GetPluginName() { + static ConstString g_name("pdb"); + return g_name; +} + +uint32_t SymbolFileNativePDB::GetPluginVersion() { return 1; } diff --git a/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h new file mode 100644 index 000000000000..dcf3fe365ef1 --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -0,0 +1,245 @@ +//===-- SymbolFileNativePDB.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H +#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H + +#include "lldb/Symbol/ClangASTImporter.h" +#include "lldb/Symbol/SymbolFile.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +#include "CompileUnitIndex.h" +#include "PdbIndex.h" + +namespace clang { +class TagDecl; +} + +namespace llvm { +namespace codeview { +class ClassRecord; +class EnumRecord; +class ModifierRecord; +class PointerRecord; +struct UnionRecord; +} // namespace codeview +} // namespace llvm + +namespace lldb_private { +class ClangASTImporter; + +namespace npdb { +class PdbAstBuilder; + +class SymbolFileNativePDB : public SymbolFile { + friend class UdtRecordCompleter; + +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static void DebuggerInitialize(Debugger &debugger); + + static ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + static SymbolFile *CreateInstance(ObjectFile *obj_file); + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + SymbolFileNativePDB(ObjectFile *ofile); + + ~SymbolFileNativePDB() override; + + uint32_t CalculateAbilities() override; + + void InitializeObject() override; + + //------------------------------------------------------------------ + // Compile Unit function calls + //------------------------------------------------------------------ + + uint32_t GetNumCompileUnits() override; + + void + ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override; + + lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; + + lldb::LanguageType + ParseLanguage(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 ParseSupportFiles(lldb_private::CompileUnit &comp_unit, + FileSpecList &support_files) override; + size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override; + + bool + ParseImportedModules(const SymbolContext &sc, + std::vector<ConstString> &imported_modules) override; + + size_t ParseBlocksRecursive(Function &func) override; + + uint32_t FindGlobalVariables(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, + uint32_t max_matches, + VariableList &variables) override; + + size_t ParseVariablesForContext(const SymbolContext &sc) override; + + void AddSymbols(Symtab &symtab) override; + + CompilerDecl GetDeclForUID(lldb::user_id_t uid) override; + CompilerDeclContext GetDeclContextForUID(lldb::user_id_t uid) override; + CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) override; + Type *ResolveTypeUID(lldb::user_id_t type_uid) override; + llvm::Optional<ArrayInfo> GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, + const lldb_private::ExecutionContext *exe_ctx) override; + + bool CompleteType(CompilerType &compiler_type) override; + uint32_t ResolveSymbolContext(const Address &so_addr, + lldb::SymbolContextItem resolve_scope, + SymbolContext &sc) override; + uint32_t ResolveSymbolContext(const FileSpec &file_spec, uint32_t line, + bool check_inlines, + lldb::SymbolContextItem resolve_scope, + SymbolContextList &sc_list) override; + + size_t GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask, + TypeList &type_list) override; + + uint32_t FindFunctions(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, + lldb::FunctionNameType name_type_mask, + bool include_inlines, bool append, + SymbolContextList &sc_list) override; + + uint32_t FindFunctions(const RegularExpression ®ex, bool include_inlines, + bool append, SymbolContextList &sc_list) override; + + uint32_t FindTypes(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, bool append, + uint32_t max_matches, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, + TypeMap &types) override; + + size_t FindTypes(const std::vector<CompilerContext> &context, bool append, + TypeMap &types) override; + + TypeSystem *GetTypeSystemForLanguage(lldb::LanguageType language) override; + + CompilerDeclContext + FindNamespace(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx) override; + + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + llvm::pdb::PDBFile &GetPDBFile() { return m_index->pdb(); } + const llvm::pdb::PDBFile &GetPDBFile() const { return m_index->pdb(); } + + void DumpClangAST(Stream &s) override; + +private: + + size_t FindTypesByName(llvm::StringRef name, uint32_t max_matches, + TypeMap &types); + + lldb::TypeSP CreateModifierType(PdbTypeSymId type_id, + const llvm::codeview::ModifierRecord &mr, + CompilerType ct); + lldb::TypeSP CreatePointerType(PdbTypeSymId type_id, + const llvm::codeview::PointerRecord &pr, + CompilerType ct); + lldb::TypeSP CreateSimpleType(llvm::codeview::TypeIndex ti, CompilerType ct); + lldb::TypeSP CreateTagType(PdbTypeSymId type_id, + const llvm::codeview::ClassRecord &cr, + CompilerType ct); + lldb::TypeSP CreateTagType(PdbTypeSymId type_id, + const llvm::codeview::EnumRecord &er, + CompilerType ct); + lldb::TypeSP CreateTagType(PdbTypeSymId type_id, + const llvm::codeview::UnionRecord &ur, + CompilerType ct); + lldb::TypeSP CreateArrayType(PdbTypeSymId type_id, + const llvm::codeview::ArrayRecord &ar, + CompilerType ct); + lldb::TypeSP CreateProcedureType(PdbTypeSymId type_id, + const llvm::codeview::ProcedureRecord &pr, + CompilerType ct); + lldb::TypeSP CreateClassStructUnion(PdbTypeSymId type_id, + const llvm::codeview::TagRecord &record, + size_t size, CompilerType ct); + + lldb::FunctionSP GetOrCreateFunction(PdbCompilandSymId func_id, + CompileUnit &comp_unit); + lldb::CompUnitSP GetOrCreateCompileUnit(const CompilandIndexItem &cci); + lldb::TypeSP GetOrCreateType(PdbTypeSymId type_id); + lldb::TypeSP GetOrCreateType(llvm::codeview::TypeIndex ti); + lldb::VariableSP GetOrCreateGlobalVariable(PdbGlobalSymId var_id); + Block &GetOrCreateBlock(PdbCompilandSymId block_id); + lldb::VariableSP GetOrCreateLocalVariable(PdbCompilandSymId scope_id, + PdbCompilandSymId var_id, + bool is_param); + lldb::TypeSP GetOrCreateTypedef(PdbGlobalSymId id); + + lldb::FunctionSP CreateFunction(PdbCompilandSymId func_id, + CompileUnit &comp_unit); + Block &CreateBlock(PdbCompilandSymId block_id); + lldb::VariableSP CreateLocalVariable(PdbCompilandSymId scope_id, + PdbCompilandSymId var_id, bool is_param); + lldb::TypeSP CreateTypedef(PdbGlobalSymId id); + lldb::CompUnitSP CreateCompileUnit(const CompilandIndexItem &cci); + lldb::TypeSP CreateType(PdbTypeSymId type_id, CompilerType ct); + lldb::TypeSP CreateAndCacheType(PdbTypeSymId type_id); + lldb::VariableSP CreateGlobalVariable(PdbGlobalSymId var_id); + lldb::VariableSP CreateConstantSymbol(PdbGlobalSymId var_id, + const llvm::codeview::CVSymbol &cvs); + size_t ParseVariablesForCompileUnit(CompileUnit &comp_unit, + VariableList &variables); + size_t ParseVariablesForBlock(PdbCompilandSymId block_id); + + llvm::BumpPtrAllocator m_allocator; + + lldb::addr_t m_obj_load_address = 0; + bool m_done_full_type_scan = false; + + std::unique_ptr<PdbIndex> m_index; + + std::unique_ptr<PdbAstBuilder> m_ast; + + llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_global_vars; + llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_local_variables; + llvm::DenseMap<lldb::user_id_t, lldb::BlockSP> m_blocks; + llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions; + llvm::DenseMap<lldb::user_id_t, lldb::CompUnitSP> m_compilands; + llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types; +}; + +} // namespace npdb +} // namespace lldb_private + +#endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ diff --git a/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp new file mode 100644 index 000000000000..239dfbee625d --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -0,0 +1,191 @@ +#include "UdtRecordCompleter.h" + +#include "PdbAstBuilder.h" +#include "PdbIndex.h" +#include "PdbSymUid.h" +#include "PdbUtil.h" + +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangASTImporter.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/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +using namespace llvm::codeview; +using namespace llvm::pdb; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::npdb; + +using Error = llvm::Error; + +UdtRecordCompleter::UdtRecordCompleter(PdbTypeSymId id, + CompilerType &derived_ct, + clang::TagDecl &tag_decl, + PdbAstBuilder &ast_builder, + TpiStream &tpi) + : 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); + switch (cvt.kind()) { + case LF_ENUM: + llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er)); + break; + case LF_UNION: + llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur)); + break; + case LF_CLASS: + case LF_STRUCTURE: + llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr)); + break; + default: + llvm_unreachable("unreachable!"); + } +} + +clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex( + llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access) { + PdbTypeSymId type_id(ti); + clang::QualType qt = m_ast_builder.GetOrCreateType(type_id); + + CVType udt_cvt = m_tpi.getType(ti); + + std::unique_ptr<clang::CXXBaseSpecifier> base_spec = + m_ast_builder.clang().CreateBaseClassSpecifier( + qt.getAsOpaquePtr(), TranslateMemberAccess(access), false, + udt_cvt.kind() == LF_CLASS); + lldbassert(base_spec); + m_bases.push_back(std::move(base_spec)); + return qt; +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + BaseClassRecord &base) { + clang::QualType base_qt = + AddBaseClassForTypeIndex(base.Type, base.getAccess()); + + auto decl = + m_ast_builder.clang().GetAsCXXRecordDecl(base_qt.getAsOpaquePtr()); + lldbassert(decl); + + auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset()); + m_layout.base_offsets.insert(std::make_pair(decl, offset)); + + return llvm::Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + VirtualBaseClassRecord &base) { + AddBaseClassForTypeIndex(base.BaseType, base.getAccess()); + + // FIXME: Handle virtual base offsets. + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + ListContinuationRecord &cont) { + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + VFPtrRecord &vfptr) { + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember( + CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) { + clang::QualType member_type = + m_ast_builder.GetOrCreateType(PdbTypeSymId(static_data_member.Type)); + + m_ast_builder.CompleteType(member_type); + + CompilerType member_ct = m_ast_builder.ToCompilerType(member_type); + + lldb::AccessType access = + TranslateMemberAccess(static_data_member.getAccess()); + ClangASTContext::AddVariableToRecordType( + m_derived_ct, static_data_member.Name, member_ct, access); + + // FIXME: Add a PdbSymUid namespace for field list members and update + // the m_uid_to_decl map with this decl. + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + NestedTypeRecord &nested) { + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + DataMemberRecord &data_member) { + + uint64_t offset = data_member.FieldOffset * 8; + uint32_t bitfield_width = 0; + + TypeIndex ti(data_member.Type); + if (!ti.isSimple()) { + CVType cvt = m_tpi.getType(ti); + if (cvt.kind() == LF_BITFIELD) { + BitFieldRecord bfr; + llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr)); + offset += bfr.BitOffset; + bitfield_width = bfr.BitSize; + ti = bfr.Type; + } + } + + clang::QualType member_qt = m_ast_builder.GetOrCreateType(PdbTypeSymId(ti)); + m_ast_builder.CompleteType(member_qt); + + lldb::AccessType access = TranslateMemberAccess(data_member.getAccess()); + + clang::FieldDecl *decl = ClangASTContext::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 + // the m_uid_to_decl map with this decl. + + m_layout.field_offsets.insert(std::make_pair(decl, offset)); + + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + OneMethodRecord &one_method) { + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + OverloadedMethodRecord &overloaded) { + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + EnumeratorRecord &enumerator) { + Declaration decl; + llvm::StringRef name = DropNameScope(enumerator.getName()); + + m_ast_builder.clang().AddEnumerationValueToEnumerationType( + m_derived_ct, decl, name.str().c_str(), enumerator.Value); + return Error::success(); +} + +void UdtRecordCompleter::complete() { + ClangASTContext &clang = m_ast_builder.clang(); + clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(), + std::move(m_bases)); + + clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType()); + ClangASTContext::BuildIndirectFields(m_derived_ct); + ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct); + + if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) { + m_ast_builder.importer().InsertRecordDecl(record_decl, m_layout); + } +} diff --git a/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h new file mode 100644 index 000000000000..469685126e59 --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h @@ -0,0 +1,75 @@ +//===-- SymbolFileNativePDB.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H +#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H + +#include "lldb/Symbol/ClangASTImporter.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" + +#include "PdbSymUid.h" + +namespace clang { +class CXXBaseSpecifier; +class QualType; +class TagDecl; +} // namespace clang + +namespace llvm { +namespace pdb { +class TpiStream; +} +} // namespace llvm + +namespace lldb_private { +class Type; +class CompilerType; +namespace npdb { +class PdbAstBuilder; + +class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks { + union UdtTagRecord { + UdtTagRecord() {} + llvm::codeview::UnionRecord ur; + llvm::codeview::ClassRecord cr; + llvm::codeview::EnumRecord er; + } m_cvr; + + PdbTypeSymId m_id; + CompilerType &m_derived_ct; + clang::TagDecl &m_tag_decl; + PdbAstBuilder &m_ast_builder; + llvm::pdb::TpiStream &m_tpi; + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> m_bases; + ClangASTImporter::LayoutInfo m_layout; + +public: + UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct, + clang::TagDecl &tag_decl, PdbAstBuilder &ast_builder, + llvm::pdb::TpiStream &tpi); + +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR, \ + llvm::codeview::Name##Record &Record) override; +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" + + void complete(); + +private: + clang::QualType AddBaseClassForTypeIndex(llvm::codeview::TypeIndex ti, + llvm::codeview::MemberAccess access); +}; + +} // namespace npdb +} // namespace lldb_private + +#endif // LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H diff --git a/source/Plugins/SymbolFile/PDB/CMakeLists.txt b/source/Plugins/SymbolFile/PDB/CMakeLists.txt index 1c176c32224d..19698a7187f7 100644 --- a/source/Plugins/SymbolFile/PDB/CMakeLists.txt +++ b/source/Plugins/SymbolFile/PDB/CMakeLists.txt @@ -9,6 +9,7 @@ add_lldb_library(lldbPluginSymbolFilePDB PLUGIN lldbCore lldbSymbol lldbUtility + lldbPluginSymbolFileNativePDB LINK_COMPONENTS DebugInfoPDB Support diff --git a/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index 8bea994aae5d..65e718bedaf1 100644 --- a/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -9,14 +9,19 @@ #include "PDBASTParser.h" +#include "SymbolFilePDB.h" + #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "lldb/Core/Module.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" #include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/TypeMap.h" #include "lldb/Symbol/TypeSystem.h" #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" @@ -33,12 +38,13 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" + using namespace lldb; using namespace lldb_private; using namespace llvm::pdb; -namespace { -int TranslateUdtKind(PDB_UdtType pdb_kind) { +static int TranslateUdtKind(PDB_UdtType pdb_kind) { switch (pdb_kind) { case PDB_UdtType::Class: return clang::TTK_Class; @@ -49,10 +55,10 @@ int TranslateUdtKind(PDB_UdtType pdb_kind) { case PDB_UdtType::Interface: return clang::TTK_Interface; } - return -1; + llvm_unreachable("unsuported PDB UDT type"); } -lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) { +static lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) { switch (type) { case PDB_BuiltinType::Float: return lldb::eEncodingIEEE754; @@ -73,7 +79,7 @@ lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) { } } -lldb::Encoding TranslateEnumEncoding(PDB_VariantType type) { +static lldb::Encoding TranslateEnumEncoding(PDB_VariantType type) { switch (type) { case PDB_VariantType::Int8: case PDB_VariantType::Int16: @@ -94,7 +100,7 @@ lldb::Encoding TranslateEnumEncoding(PDB_VariantType type) { return lldb::eEncodingSint; } -CompilerType +static CompilerType GetBuiltinTypeForPDBEncodingAndBitSize(ClangASTContext &clang_ast, const PDBSymbolTypeBuiltin &pdb_type, Encoding encoding, uint32_t width) { @@ -109,6 +115,8 @@ GetBuiltinTypeForPDBEncodingAndBitSize(ClangASTContext &clang_ast, return CompilerType(); case PDB_BuiltinType::Void: return clang_ast.GetBasicType(eBasicTypeVoid); + case PDB_BuiltinType::Char: + return clang_ast.GetBasicType(eBasicTypeChar); case PDB_BuiltinType::Bool: return clang_ast.GetBasicType(eBasicTypeBool); case PDB_BuiltinType::Long: @@ -143,8 +151,8 @@ GetBuiltinTypeForPDBEncodingAndBitSize(ClangASTContext &clang_ast, return clang_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, width); } -ConstString GetPDBBuiltinTypeName(const PDBSymbolTypeBuiltin &pdb_type, - CompilerType &compiler_type) { +static ConstString GetPDBBuiltinTypeName(const PDBSymbolTypeBuiltin &pdb_type, + CompilerType &compiler_type) { PDB_BuiltinType kind = pdb_type.getBuiltinType(); switch (kind) { default: @@ -175,7 +183,8 @@ ConstString GetPDBBuiltinTypeName(const PDBSymbolTypeBuiltin &pdb_type, return compiler_type.GetTypeName(); } -bool GetDeclarationForSymbol(const PDBSymbol &symbol, Declaration &decl) { +static bool GetDeclarationForSymbol(const PDBSymbol &symbol, + Declaration &decl) { auto &raw_sym = symbol.getRawSymbol(); auto first_line_up = raw_sym.getSrcLineOnTypeDefn(); @@ -193,13 +202,159 @@ bool GetDeclarationForSymbol(const PDBSymbol &symbol, Declaration &decl) { if (!src_file_up) return false; - FileSpec spec(src_file_up->getFileName(), /*resolve_path*/ false); + FileSpec spec(src_file_up->getFileName()); decl.SetFile(spec); decl.SetColumn(first_line_up->getColumnNumber()); decl.SetLine(first_line_up->getLineNumber()); return true; } -} // namespace + +static AccessType TranslateMemberAccess(PDB_MemberAccess access) { + switch (access) { + case PDB_MemberAccess::Private: + return eAccessPrivate; + case PDB_MemberAccess::Protected: + return eAccessProtected; + case PDB_MemberAccess::Public: + return eAccessPublic; + } + return eAccessNone; +} + +static AccessType GetDefaultAccessibilityForUdtKind(PDB_UdtType udt_kind) { + switch (udt_kind) { + case PDB_UdtType::Struct: + case PDB_UdtType::Union: + return eAccessPublic; + case PDB_UdtType::Class: + case PDB_UdtType::Interface: + return eAccessPrivate; + } + llvm_unreachable("unsupported PDB UDT type"); +} + +static AccessType GetAccessibilityForUdt(const PDBSymbolTypeUDT &udt) { + AccessType access = TranslateMemberAccess(udt.getAccess()); + if (access != lldb::eAccessNone || !udt.isNested()) + return access; + + auto parent = udt.getClassParent(); + if (!parent) + return lldb::eAccessNone; + + auto parent_udt = llvm::dyn_cast<PDBSymbolTypeUDT>(parent.get()); + if (!parent_udt) + return lldb::eAccessNone; + + return GetDefaultAccessibilityForUdtKind(parent_udt->getUdtKind()); +} + +static clang::MSInheritanceAttr::Spelling +GetMSInheritance(const PDBSymbolTypeUDT &udt) { + int base_count = 0; + bool has_virtual = false; + + auto bases_enum = udt.findAllChildren<PDBSymbolTypeBaseClass>(); + if (bases_enum) { + while (auto base = bases_enum->getNext()) { + base_count++; + has_virtual |= base->isVirtualBaseClass(); + } + } + + if (has_virtual) + return clang::MSInheritanceAttr::Keyword_virtual_inheritance; + if (base_count > 1) + return clang::MSInheritanceAttr::Keyword_multiple_inheritance; + return clang::MSInheritanceAttr::Keyword_single_inheritance; +} + +static std::unique_ptr<llvm::pdb::PDBSymbol> +GetClassOrFunctionParent(const llvm::pdb::PDBSymbol &symbol) { + const IPDBSession &session = symbol.getSession(); + const IPDBRawSymbol &raw = symbol.getRawSymbol(); + auto tag = symbol.getSymTag(); + + // For items that are nested inside of a class, return the class that it is + // nested inside of. + // Note that only certain items can be nested inside of classes. + switch (tag) { + case PDB_SymType::Function: + case PDB_SymType::Data: + case PDB_SymType::UDT: + case PDB_SymType::Enum: + case PDB_SymType::FunctionSig: + case PDB_SymType::Typedef: + case PDB_SymType::BaseClass: + case PDB_SymType::VTable: { + auto class_parent_id = raw.getClassParentId(); + if (auto class_parent = session.getSymbolById(class_parent_id)) + return class_parent; + break; + } + default: + break; + } + + // Otherwise, if it is nested inside of a function, return the function. + // Note that only certain items can be nested inside of functions. + switch (tag) { + case PDB_SymType::Block: + case PDB_SymType::Data: { + auto lexical_parent_id = raw.getLexicalParentId(); + auto lexical_parent = session.getSymbolById(lexical_parent_id); + if (!lexical_parent) + return nullptr; + + auto lexical_parent_tag = lexical_parent->getSymTag(); + if (lexical_parent_tag == PDB_SymType::Function) + return lexical_parent; + if (lexical_parent_tag == PDB_SymType::Exe) + return nullptr; + + return GetClassOrFunctionParent(*lexical_parent); + } + default: + return nullptr; + } +} + +static clang::NamedDecl * +GetDeclFromContextByName(const clang::ASTContext &ast, + const clang::DeclContext &decl_context, + llvm::StringRef name) { + clang::IdentifierInfo &ident = ast.Idents.get(name); + clang::DeclarationName decl_name = ast.DeclarationNames.getIdentifier(&ident); + clang::DeclContext::lookup_result result = decl_context.lookup(decl_name); + if (result.empty()) + return nullptr; + + return result[0]; +} + +static bool IsAnonymousNamespaceName(llvm::StringRef name) { + return name == "`anonymous namespace'" || name == "`anonymous-namespace'"; +} + +static clang::CallingConv TranslateCallingConvention(PDB_CallingConv pdb_cc) { + switch (pdb_cc) { + case llvm::codeview::CallingConvention::NearC: + return clang::CC_C; + case llvm::codeview::CallingConvention::NearStdCall: + return clang::CC_X86StdCall; + case llvm::codeview::CallingConvention::NearFast: + return clang::CC_X86FastCall; + case llvm::codeview::CallingConvention::ThisCall: + return clang::CC_X86ThisCall; + case llvm::codeview::CallingConvention::NearVector: + return clang::CC_X86VectorCall; + case llvm::codeview::CallingConvention::NearPascal: + return clang::CC_X86Pascal; + default: + assert(false && "Unknown calling convention"); + return clang::CC_C; + } +} PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) {} @@ -208,76 +363,167 @@ PDBASTParser::~PDBASTParser() {} // DebugInfoASTParser interface lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { - // PDB doesn't maintain enough information to robustly rebuild the entire - // tree, and this is most problematic when it comes to figure out the right - // DeclContext to put a type in. So for now, everything goes in the - // translation unit decl as a fully qualified type. - clang::DeclContext *tu_decl_ctx = m_ast.GetTranslationUnitDecl(); Declaration decl; - switch (type.getSymTag()) { + case PDB_SymType::BaseClass: { + auto symbol_file = m_ast.GetSymbolFile(); + if (!symbol_file) + return nullptr; + + auto ty = symbol_file->ResolveTypeUID(type.getRawSymbol().getTypeId()); + return ty ? ty->shared_from_this() : nullptr; + } break; case PDB_SymType::UDT: { auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&type); assert(udt); - AccessType access = lldb::eAccessPublic; - PDB_UdtType udt_kind = udt->getUdtKind(); - auto tag_type_kind = TranslateUdtKind(udt_kind); - if (tag_type_kind == -1) + + // Note that, unnamed UDT being typedef-ed is generated as a UDT symbol + // other than a Typedef symbol in PDB. For example, + // typedef union { short Row; short Col; } Union; + // is generated as a named UDT in PDB: + // union Union { short Row; short Col; } + // Such symbols will be handled here. + + // Some UDT with trival ctor has zero length. Just ignore. + if (udt->getLength() == 0) + return nullptr; + + // Ignore unnamed-tag UDTs. + std::string name = MSVCUndecoratedNameParser::DropScope(udt->getName()); + if (name.empty()) return nullptr; - if (udt_kind == PDB_UdtType::Class) - access = lldb::eAccessPrivate; + auto decl_context = GetDeclContextContainingSymbol(type); - CompilerType clang_type = m_ast.CreateRecordType( - tu_decl_ctx, access, udt->getName().c_str(), tag_type_kind, - lldb::eLanguageTypeC_plus_plus, nullptr); + // Check if such an UDT already exists in the current context. + // This may occur with const or volatile types. There are separate type + // symbols in PDB for types with const or volatile modifiers, but we need + // to create only one declaration for them all. + Type::ResolveStateTag type_resolve_state_tag; + CompilerType clang_type = m_ast.GetTypeForIdentifier<clang::CXXRecordDecl>( + ConstString(name), decl_context); + if (!clang_type.IsValid()) { + auto access = GetAccessibilityForUdt(*udt); - m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); + auto tag_type_kind = TranslateUdtKind(udt->getUdtKind()); + ClangASTMetadata metadata; + metadata.SetUserID(type.getSymIndexId()); + metadata.SetIsDynamicCXXType(false); + + clang_type = m_ast.CreateRecordType( + decl_context, access, name.c_str(), tag_type_kind, + lldb::eLanguageTypeC_plus_plus, &metadata); + assert(clang_type.IsValid()); + + auto record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + assert(record_decl); + m_uid_to_decl[type.getSymIndexId()] = record_decl; + + auto inheritance_attr = clang::MSInheritanceAttr::CreateImplicit( + *m_ast.getASTContext(), GetMSInheritance(*udt)); + record_decl->addAttr(inheritance_attr); + + ClangASTContext::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); + + ClangASTContext::SetHasExternalStorage(clang_type.GetOpaqueQualType(), + false); + + type_resolve_state_tag = Type::eResolveStateFull; + } else { + // Add the type to the forward declarations. It will help us to avoid + // an endless recursion in CompleteTypeFromUdt function. + m_forward_decl_to_uid[record_decl] = type.getSymIndexId(); + + ClangASTContext::SetHasExternalStorage(clang_type.GetOpaqueQualType(), + true); + + type_resolve_state_tag = Type::eResolveStateForward; + } + } else + type_resolve_state_tag = Type::eResolveStateForward; + + if (udt->isConstType()) + clang_type = clang_type.AddConstModifier(); + + if (udt->isVolatileType()) + clang_type = clang_type.AddVolatileModifier(); + + GetDeclarationForSymbol(type, decl); return std::make_shared<lldb_private::Type>( - type.getSymIndexId(), m_ast.GetSymbolFile(), - ConstString(udt->getName()), udt->getLength(), nullptr, - LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type, - lldb_private::Type::eResolveStateForward); + type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), + udt->getLength(), nullptr, LLDB_INVALID_UID, + lldb_private::Type::eEncodingIsUID, decl, clang_type, + type_resolve_state_tag); } break; case PDB_SymType::Enum: { auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type); assert(enum_type); - auto underlying_type_up = enum_type->getUnderlyingType(); - if (!underlying_type_up) - return nullptr; - lldb::Encoding encoding = - TranslateBuiltinEncoding(underlying_type_up->getBuiltinType()); - // FIXME: Type of underlying builtin is always `Int`. We correct it with - // the very first enumerator's encoding if any. - auto first_child = enum_type->findOneChild<PDBSymbolData>(); - if (first_child) { - encoding = TranslateEnumEncoding(first_child->getValue().Type); - } - std::string name = enum_type->getName(); + + std::string name = + MSVCUndecoratedNameParser::DropScope(enum_type->getName()); + auto decl_context = GetDeclContextContainingSymbol(type); uint64_t bytes = enum_type->getLength(); - CompilerType builtin_type; - if (bytes > 0) - builtin_type = GetBuiltinTypeForPDBEncodingAndBitSize( - m_ast, *underlying_type_up, encoding, bytes * 8); - else - builtin_type = m_ast.GetBasicType(eBasicTypeInt); - // FIXME: PDB does not have information about scoped enumeration (Enum - // Class). Set it false for now. - bool isScoped = false; - - CompilerType ast_enum = m_ast.CreateEnumerationType( - name.c_str(), tu_decl_ctx, decl, builtin_type, isScoped); - auto enum_values = enum_type->findAllChildren<PDBSymbolData>(); - if (enum_values) { - while (auto enum_value = enum_values->getNext()) { - if (enum_value->getDataKind() != PDB_DataKind::Constant) - continue; - AddEnumValue(ast_enum, *enum_value); + + // Check if such an enum already exists in the current context + CompilerType ast_enum = m_ast.GetTypeForIdentifier<clang::EnumDecl>( + ConstString(name), decl_context); + if (!ast_enum.IsValid()) { + auto underlying_type_up = enum_type->getUnderlyingType(); + if (!underlying_type_up) + return nullptr; + + lldb::Encoding encoding = + TranslateBuiltinEncoding(underlying_type_up->getBuiltinType()); + // FIXME: Type of underlying builtin is always `Int`. We correct it with + // the very first enumerator's encoding if any. + auto first_child = enum_type->findOneChild<PDBSymbolData>(); + if (first_child) + encoding = TranslateEnumEncoding(first_child->getValue().Type); + + CompilerType builtin_type; + if (bytes > 0) + builtin_type = GetBuiltinTypeForPDBEncodingAndBitSize( + m_ast, *underlying_type_up, encoding, bytes * 8); + else + builtin_type = m_ast.GetBasicType(eBasicTypeInt); + + // FIXME: PDB does not have information about scoped enumeration (Enum + // Class). Set it false for now. + bool isScoped = false; + + ast_enum = m_ast.CreateEnumerationType(name.c_str(), decl_context, decl, + builtin_type, isScoped); + + auto enum_decl = ClangASTContext::GetAsEnumDecl(ast_enum); + assert(enum_decl); + m_uid_to_decl[type.getSymIndexId()] = enum_decl; + + auto enum_values = enum_type->findAllChildren<PDBSymbolData>(); + if (enum_values) { + while (auto enum_value = enum_values->getNext()) { + if (enum_value->getDataKind() != PDB_DataKind::Constant) + continue; + AddEnumValue(ast_enum, *enum_value); + } } + + if (ClangASTContext::StartTagDeclarationDefinition(ast_enum)) + ClangASTContext::CompleteTagDeclarationDefinition(ast_enum); } - if (ClangASTContext::StartTagDeclarationDefinition(ast_enum)) - ClangASTContext::CompleteTagDeclarationDefinition(ast_enum); + + if (enum_type->isConstType()) + ast_enum = ast_enum.AddConstModifier(); + + if (enum_type->isVolatileType()) + ast_enum = ast_enum.AddVolatileModifier(); GetDeclarationForSymbol(type, decl); return std::make_shared<lldb_private::Type>( @@ -288,23 +534,43 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { case PDB_SymType::Typedef: { auto type_def = llvm::dyn_cast<PDBSymbolTypeTypedef>(&type); assert(type_def); + lldb_private::Type *target_type = m_ast.GetSymbolFile()->ResolveTypeUID(type_def->getTypeId()); if (!target_type) return nullptr; - std::string name = type_def->getName(); - uint64_t bytes = type_def->getLength(); - CompilerType target_ast_type = target_type->GetFullCompilerType(); - CompilerDeclContext target_decl_ctx = - m_ast.GetSymbolFile()->GetDeclContextForUID(target_type->GetID()); + + std::string name = + MSVCUndecoratedNameParser::DropScope(type_def->getName()); + auto decl_ctx = GetDeclContextContainingSymbol(type); + + // Check if such a typedef already exists in the current context CompilerType ast_typedef = - m_ast.CreateTypedefType(target_ast_type, name.c_str(), target_decl_ctx); - if (!ast_typedef) - return nullptr; + m_ast.GetTypeForIdentifier<clang::TypedefNameDecl>(ConstString(name), + decl_ctx); + if (!ast_typedef.IsValid()) { + CompilerType target_ast_type = target_type->GetFullCompilerType(); + + ast_typedef = m_ast.CreateTypedefType( + target_ast_type, name.c_str(), CompilerDeclContext(&m_ast, decl_ctx)); + if (!ast_typedef) + return nullptr; + + auto typedef_decl = ClangASTContext::GetAsTypedefDecl(ast_typedef); + assert(typedef_decl); + m_uid_to_decl[type.getSymIndexId()] = typedef_decl; + } + + if (type_def->isConstType()) + ast_typedef = ast_typedef.AddConstModifier(); + + if (type_def->isVolatileType()) + ast_typedef = ast_typedef.AddVolatileModifier(); + GetDeclarationForSymbol(type, decl); return std::make_shared<lldb_private::Type>( type_def->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), - bytes, nullptr, target_type->GetID(), + type_def->getLength(), nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID, decl, ast_typedef, lldb_private::Type::eResolveStateFull); } break; @@ -321,7 +587,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { return nullptr; func_sig = sig.release(); // Function type is named. - name = pdb_func->getName(); + name = MSVCUndecoratedNameParser::DropScope(pdb_func->getName()); } else if (auto pdb_func_sig = llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) { func_sig = const_cast<PDBSymbolTypeFunctionSig *>(pdb_func_sig); @@ -364,9 +630,10 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { type_quals |= clang::Qualifiers::Const; if (func_sig->isVolatileType()) type_quals |= clang::Qualifiers::Volatile; + auto cc = TranslateCallingConvention(func_sig->getCallingConvention()); CompilerType func_sig_ast_type = m_ast.CreateFunctionType(return_ast_type, arg_list.data(), - arg_list.size(), is_variadic, type_quals); + arg_list.size(), is_variadic, type_quals, cc); GetDeclarationForSymbol(type, decl); return std::make_shared<lldb_private::Type>( @@ -391,7 +658,7 @@ 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) && - element_ast_type.GetCompleteType() == false) { + !element_ast_type.GetCompleteType()) { if (ClangASTContext::StartTagDeclarationDefinition(element_ast_type)) { ClangASTContext::CompleteTagDeclarationDefinition(element_ast_type); } else { @@ -441,6 +708,26 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { if (!pointee_type) return nullptr; + if (pointer_type->isPointerToDataMember() || + pointer_type->isPointerToMemberFunction()) { + auto class_parent_uid = pointer_type->getRawSymbol().getClassParentId(); + auto class_parent_type = + m_ast.GetSymbolFile()->ResolveTypeUID(class_parent_uid); + assert(class_parent_type); + + CompilerType pointer_ast_type; + pointer_ast_type = ClangASTContext::CreateMemberPointerType( + class_parent_type->GetLayoutCompilerType(), + pointee_type->GetForwardCompilerType()); + assert(pointer_ast_type); + + return std::make_shared<lldb_private::Type>( + pointer_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), + pointer_type->getLength(), nullptr, LLDB_INVALID_UID, + lldb_private::Type::eEncodingIsUID, decl, pointer_ast_type, + lldb_private::Type::eResolveStateForward); + } + CompilerType pointer_ast_type; pointer_ast_type = pointee_type->GetFullCompilerType(); if (pointer_type->isReference()) @@ -471,11 +758,363 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { return nullptr; } +bool PDBASTParser::CompleteTypeFromPDB( + lldb_private::CompilerType &compiler_type) { + if (GetClangASTImporter().CanImport(compiler_type)) + return GetClangASTImporter().CompleteType(compiler_type); + + // Remove the type from the forward declarations to avoid + // an endless recursion for types like a linked list. + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType()); + auto uid_it = m_forward_decl_to_uid.find(record_decl); + if (uid_it == m_forward_decl_to_uid.end()) + return true; + + auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile()); + if (!symbol_file) + return false; + + std::unique_ptr<PDBSymbol> symbol = + symbol_file->GetPDBSession().getSymbolById(uid_it->getSecond()); + if (!symbol) + return false; + + m_forward_decl_to_uid.erase(uid_it); + + ClangASTContext::SetHasExternalStorage(compiler_type.GetOpaqueQualType(), + false); + + switch (symbol->getSymTag()) { + case PDB_SymType::UDT: { + auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(symbol.get()); + if (!udt) + return false; + + return CompleteTypeFromUDT(*symbol_file, compiler_type, *udt); + } + default: + llvm_unreachable("not a forward clang type decl!"); + } +} + +clang::Decl * +PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { + uint32_t sym_id = symbol.getSymIndexId(); + auto it = m_uid_to_decl.find(sym_id); + if (it != m_uid_to_decl.end()) + return it->second; + + auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile()); + if (!symbol_file) + return nullptr; + + // First of all, check if the symbol is a member of a class. Resolve the full + // class type and return the declaration from the cache if so. + auto tag = symbol.getSymTag(); + if (tag == PDB_SymType::Data || tag == PDB_SymType::Function) { + const IPDBSession &session = symbol.getSession(); + const IPDBRawSymbol &raw = symbol.getRawSymbol(); + + auto class_parent_id = raw.getClassParentId(); + if (std::unique_ptr<PDBSymbol> class_parent = + session.getSymbolById(class_parent_id)) { + auto class_parent_type = symbol_file->ResolveTypeUID(class_parent_id); + if (!class_parent_type) + return nullptr; + + CompilerType class_parent_ct = class_parent_type->GetFullCompilerType(); + + // Look a declaration up in the cache after completing the class + clang::Decl *decl = m_uid_to_decl.lookup(sym_id); + if (decl) + return decl; + + // A declaration was not found in the cache. It means that the symbol + // has the class parent, but the class doesn't have the symbol in its + // children list. + if (auto func = llvm::dyn_cast_or_null<PDBSymbolFunc>(&symbol)) { + // Try to find a class child method with the same RVA and use its + // declaration if found. + if (uint32_t rva = func->getRelativeVirtualAddress()) { + if (std::unique_ptr<ConcreteSymbolEnumerator<PDBSymbolFunc>> + methods_enum = + class_parent->findAllChildren<PDBSymbolFunc>()) { + while (std::unique_ptr<PDBSymbolFunc> method = + methods_enum->getNext()) { + if (method->getRelativeVirtualAddress() == rva) { + decl = m_uid_to_decl.lookup(method->getSymIndexId()); + if (decl) + break; + } + } + } + } + + // If no class methods with the same RVA were found, then create a new + // method. It is possible for template methods. + if (!decl) + decl = AddRecordMethod(*symbol_file, class_parent_ct, *func); + } + + if (decl) + m_uid_to_decl[sym_id] = decl; + + return decl; + } + } + + // If we are here, then the symbol is not belonging to a class and is not + // contained in the cache. So create a declaration for it. + switch (symbol.getSymTag()) { + case PDB_SymType::Data: { + auto data = llvm::dyn_cast<PDBSymbolData>(&symbol); + assert(data); + + auto decl_context = GetDeclContextContainingSymbol(symbol); + assert(decl_context); + + // May be the current context is a class really, but we haven't found + // any class parent. This happens e.g. in the case of class static + // variables - they has two symbols, one is a child of the class when + // another is a child of the exe. So always complete the parent and use + // an existing declaration if possible. + 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()); + + // Check if the current context already contains the symbol with the name. + clang::Decl *decl = + GetDeclFromContextByName(*m_ast.getASTContext(), *decl_context, name); + if (!decl) { + auto type = symbol_file->ResolveTypeUID(data->getTypeId()); + if (!type) + return nullptr; + + decl = m_ast.CreateVariableDeclaration( + decl_context, name.c_str(), + ClangUtil::GetQualType(type->GetLayoutCompilerType())); + } + + m_uid_to_decl[sym_id] = decl; + + return decl; + } + case PDB_SymType::Function: { + auto func = llvm::dyn_cast<PDBSymbolFunc>(&symbol); + assert(func); + + auto decl_context = GetDeclContextContainingSymbol(symbol); + assert(decl_context); + + std::string name = MSVCUndecoratedNameParser::DropScope(func->getName()); + + Type *type = symbol_file->ResolveTypeUID(sym_id); + if (!type) + return nullptr; + + auto storage = func->isStatic() ? clang::StorageClass::SC_Static + : clang::StorageClass::SC_None; + + auto decl = m_ast.CreateFunctionDeclaration( + decl_context, name.c_str(), type->GetForwardCompilerType(), storage, + func->hasInlineAttribute()); + + std::vector<clang::ParmVarDecl *> params; + if (std::unique_ptr<PDBSymbolTypeFunctionSig> sig = func->getSignature()) { + if (std::unique_ptr<ConcreteSymbolEnumerator<PDBSymbolTypeFunctionArg>> + arg_enum = sig->findAllChildren<PDBSymbolTypeFunctionArg>()) { + while (std::unique_ptr<PDBSymbolTypeFunctionArg> arg = + arg_enum->getNext()) { + Type *arg_type = symbol_file->ResolveTypeUID(arg->getTypeId()); + if (!arg_type) + continue; + + clang::ParmVarDecl *param = m_ast.CreateParameterDeclaration( + decl, nullptr, arg_type->GetForwardCompilerType(), + clang::SC_None); + if (param) + params.push_back(param); + } + } + } + if (params.size()) + m_ast.SetFunctionParameters(decl, params.data(), params.size()); + + m_uid_to_decl[sym_id] = decl; + + return decl; + } + default: { + // It's not a variable and not a function, check if it's a type + Type *type = symbol_file->ResolveTypeUID(sym_id); + if (!type) + return nullptr; + + return m_uid_to_decl.lookup(sym_id); + } + } +} + +clang::DeclContext * +PDBASTParser::GetDeclContextForSymbol(const llvm::pdb::PDBSymbol &symbol) { + if (symbol.getSymTag() == PDB_SymType::Function) { + clang::DeclContext *result = + llvm::dyn_cast_or_null<clang::FunctionDecl>(GetDeclForSymbol(symbol)); + + if (result) + m_decl_context_to_uid[result] = symbol.getSymIndexId(); + + return result; + } + + auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile()); + if (!symbol_file) + return nullptr; + + auto type = symbol_file->ResolveTypeUID(symbol.getSymIndexId()); + if (!type) + return nullptr; + + clang::DeclContext *result = + m_ast.GetDeclContextForType(type->GetForwardCompilerType()); + + if (result) + m_decl_context_to_uid[result] = symbol.getSymIndexId(); + + return result; +} + +clang::DeclContext *PDBASTParser::GetDeclContextContainingSymbol( + const llvm::pdb::PDBSymbol &symbol) { + auto parent = GetClassOrFunctionParent(symbol); + while (parent) { + if (auto parent_context = GetDeclContextForSymbol(*parent)) + return parent_context; + + parent = GetClassOrFunctionParent(*parent); + } + + // We can't find any class or function parent of the symbol. So analyze + // the full symbol name. The symbol may be belonging to a namespace + // or function (or even to a class if it's e.g. a static variable symbol). + + // TODO: Make clang to emit full names for variables in namespaces + // (as MSVC does) + + std::string name(symbol.getRawSymbol().getName()); + MSVCUndecoratedNameParser parser(name); + llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers(); + if (specs.empty()) + return m_ast.GetTranslationUnitDecl(); + + auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile()); + if (!symbol_file) + return m_ast.GetTranslationUnitDecl(); + + auto global = symbol_file->GetPDBSession().getGlobalScope(); + if (!global) + return m_ast.GetTranslationUnitDecl(); + + bool has_type_or_function_parent = false; + clang::DeclContext *curr_context = m_ast.GetTranslationUnitDecl(); + for (std::size_t i = 0; i < specs.size() - 1; i++) { + // Check if there is a function or a type with the current context's name. + if (std::unique_ptr<IPDBEnumSymbols> children_enum = global->findChildren( + PDB_SymType::None, specs[i].GetFullName(), NS_CaseSensitive)) { + while (IPDBEnumChildren<PDBSymbol>::ChildTypePtr child = + children_enum->getNext()) { + if (clang::DeclContext *child_context = + GetDeclContextForSymbol(*child)) { + // Note that `GetDeclContextForSymbol' retrieves + // a declaration context for functions and types only, + // so if we are here then `child_context' is guaranteed + // a function or a type declaration context. + has_type_or_function_parent = true; + curr_context = child_context; + } + } + } + + // If there were no functions or types above then retrieve a namespace with + // the current context's name. There can be no namespaces inside a function + // 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(); + 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_parent_to_namespaces[curr_context].insert(namespace_decl); + m_namespaces.insert(namespace_decl); + + curr_context = namespace_decl; + } + } + + return curr_context; +} + +void PDBASTParser::ParseDeclsForDeclContext( + const clang::DeclContext *decl_context) { + auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile()); + if (!symbol_file) + return; + + IPDBSession &session = symbol_file->GetPDBSession(); + auto symbol_up = + session.getSymbolById(m_decl_context_to_uid.lookup(decl_context)); + auto global_up = session.getGlobalScope(); + + PDBSymbol *symbol; + if (symbol_up) + symbol = symbol_up.get(); + else if (global_up) + symbol = global_up.get(); + else + return; + + if (auto children = symbol->findAllChildren()) + while (auto child = children->getNext()) + GetDeclForSymbol(*child); +} + +clang::NamespaceDecl * +PDBASTParser::FindNamespaceDecl(const clang::DeclContext *parent, + llvm::StringRef name) { + NamespacesSet *set; + if (parent) { + auto pit = m_parent_to_namespaces.find(parent); + if (pit == m_parent_to_namespaces.end()) + return nullptr; + + set = &pit->second; + } else { + set = &m_namespaces; + } + assert(set); + + for (clang::NamespaceDecl *namespace_decl : *set) + if (namespace_decl->getName().equals(name)) + return namespace_decl; + + for (clang::NamespaceDecl *namespace_decl : *set) + if (namespace_decl->isAnonymousNamespace()) + return FindNamespaceDecl(namespace_decl, name); + + return nullptr; +} + bool PDBASTParser::AddEnumValue(CompilerType enum_type, - const PDBSymbolData &enum_value) const { + const PDBSymbolData &enum_value) { Declaration decl; Variant v = enum_value.getValue(); - std::string name = enum_value.getName(); + std::string name = MSVCUndecoratedNameParser::DropScope(enum_value.getName()); int64_t raw_value; switch (v.Type) { case PDB_VariantType::Int8: @@ -509,7 +1148,213 @@ bool PDBASTParser::AddEnumValue(CompilerType enum_type, m_ast.GetEnumerationIntegerType(enum_type.GetOpaqueQualType()); uint32_t byte_size = m_ast.getASTContext()->getTypeSize( ClangUtil::GetQualType(underlying_type)); - return m_ast.AddEnumerationValueToEnumerationType( - enum_type.GetOpaqueQualType(), underlying_type, decl, name.c_str(), - raw_value, byte_size * 8); + auto enum_constant_decl = m_ast.AddEnumerationValueToEnumerationType( + enum_type, decl, name.c_str(), raw_value, byte_size * 8); + if (!enum_constant_decl) + return false; + + m_uid_to_decl[enum_value.getSymIndexId()] = enum_constant_decl; + + return true; +} + +bool PDBASTParser::CompleteTypeFromUDT( + lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &compiler_type, + llvm::pdb::PDBSymbolTypeUDT &udt) { + ClangASTImporter::LayoutInfo layout_info; + layout_info.bit_size = udt.getLength() * 8; + + auto nested_enums = udt.findAllChildren<PDBSymbolTypeUDT>(); + if (nested_enums) + while (auto nested = nested_enums->getNext()) + symbol_file.ResolveTypeUID(nested->getSymIndexId()); + + auto bases_enum = udt.findAllChildren<PDBSymbolTypeBaseClass>(); + if (bases_enum) + AddRecordBases(symbol_file, compiler_type, + TranslateUdtKind(udt.getUdtKind()), *bases_enum, + layout_info); + + auto members_enum = udt.findAllChildren<PDBSymbolData>(); + if (members_enum) + AddRecordMembers(symbol_file, compiler_type, *members_enum, layout_info); + + auto methods_enum = udt.findAllChildren<PDBSymbolFunc>(); + if (methods_enum) + AddRecordMethods(symbol_file, compiler_type, *methods_enum); + + m_ast.AddMethodOverridesForCXXRecordType(compiler_type.GetOpaqueQualType()); + ClangASTContext::BuildIndirectFields(compiler_type); + ClangASTContext::CompleteTagDeclarationDefinition(compiler_type); + + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType()); + if (!record_decl) + return static_cast<bool>(compiler_type); + + GetClangASTImporter().InsertRecordDecl(record_decl, layout_info); + + return static_cast<bool>(compiler_type); +} + +void PDBASTParser::AddRecordMembers( + lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBDataSymbolEnumerator &members_enum, + lldb_private::ClangASTImporter::LayoutInfo &layout_info) { + while (auto member = members_enum.getNext()) { + if (member->isCompilerGenerated()) + continue; + + auto member_name = member->getName(); + + auto member_type = symbol_file.ResolveTypeUID(member->getTypeId()); + if (!member_type) + continue; + + auto member_comp_type = member_type->GetLayoutCompilerType(); + if (!member_comp_type.GetCompleteType()) { + symbol_file.GetObjectFile()->GetModule()->ReportError( + ":: Class '%s' has a member '%s' of type '%s' " + "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); + } + + auto access = TranslateMemberAccess(member->getAccess()); + + switch (member->getDataKind()) { + case PDB_DataKind::Member: { + auto location_type = member->getLocationType(); + + auto bit_size = member->getLength(); + if (location_type == PDB_LocType::ThisRel) + bit_size *= 8; + + auto decl = ClangASTContext::AddFieldToRecordType( + record_type, member_name.c_str(), member_comp_type, access, bit_size); + if (!decl) + continue; + + m_uid_to_decl[member->getSymIndexId()] = decl; + + auto offset = member->getOffset() * 8; + if (location_type == PDB_LocType::BitField) + offset += member->getBitPosition(); + + layout_info.field_offsets.insert(std::make_pair(decl, offset)); + + break; + } + case PDB_DataKind::StaticMember: { + auto decl = ClangASTContext::AddVariableToRecordType( + record_type, member_name.c_str(), member_comp_type, access); + if (!decl) + continue; + + m_uid_to_decl[member->getSymIndexId()] = decl; + + break; + } + default: + llvm_unreachable("unsupported PDB data kind"); + } + } +} + +void PDBASTParser::AddRecordBases( + lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, int record_kind, + PDBBaseClassSymbolEnumerator &bases_enum, + lldb_private::ClangASTImporter::LayoutInfo &layout_info) const { + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> base_classes; + + while (auto base = bases_enum.getNext()) { + auto base_type = symbol_file.ResolveTypeUID(base->getTypeId()); + if (!base_type) + continue; + + auto base_comp_type = base_type->GetFullCompilerType(); + if (!base_comp_type.GetCompleteType()) { + symbol_file.GetObjectFile()->GetModule()->ReportError( + ":: Class '%s' has a base class '%s' " + "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); + } + + auto access = TranslateMemberAccess(base->getAccess()); + + auto is_virtual = base->isVirtualBaseClass(); + + std::unique_ptr<clang::CXXBaseSpecifier> base_spec = + m_ast.CreateBaseClassSpecifier(base_comp_type.GetOpaqueQualType(), + access, is_virtual, + record_kind == clang::TTK_Class); + lldbassert(base_spec); + + base_classes.push_back(std::move(base_spec)); + + if (is_virtual) + continue; + + auto decl = m_ast.GetAsCXXRecordDecl(base_comp_type.GetOpaqueQualType()); + if (!decl) + continue; + + auto offset = clang::CharUnits::fromQuantity(base->getOffset()); + layout_info.base_offsets.insert(std::make_pair(decl, offset)); + } + + m_ast.TransferBaseClasses(record_type.GetOpaqueQualType(), + std::move(base_classes)); +} + +void PDBASTParser::AddRecordMethods(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBFuncSymbolEnumerator &methods_enum) { + while (std::unique_ptr<PDBSymbolFunc> method = methods_enum.getNext()) + if (clang::CXXMethodDecl *decl = + AddRecordMethod(symbol_file, record_type, *method)) + m_uid_to_decl[method->getSymIndexId()] = decl; +} + +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()); + + Type *method_type = symbol_file.ResolveTypeUID(method.getSymIndexId()); + // MSVC specific __vecDelDtor. + if (!method_type) + return nullptr; + + CompilerType method_comp_type = method_type->GetFullCompilerType(); + if (!method_comp_type.GetCompleteType()) { + symbol_file.GetObjectFile()->GetModule()->ReportError( + ":: 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); + } + + AccessType access = TranslateMemberAccess(method.getAccess()); + if (access == eAccessNone) + access = eAccessPublic; + + // TODO: get mangled name for the method. + return m_ast.AddMethodToCXXRecordType( + record_type.GetOpaqueQualType(), name.c_str(), + /*mangled_name*/ nullptr, method_comp_type, access, method.isVirtual(), + method.isStatic(), method.hasInlineAttribute(), + /*is_explicit*/ false, // FIXME: Need this field in CodeView. + /*is_attr_used*/ false, + /*is_artificial*/ method.isCompilerGenerated()); } diff --git a/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/source/Plugins/SymbolFile/PDB/PDBASTParser.h index d1ac138b8115..02353870ab60 100644 --- a/source/Plugins/SymbolFile/PDB/PDBASTParser.h +++ b/source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -14,6 +14,8 @@ #include "lldb/Symbol/ClangASTImporter.h" +class SymbolFilePDB; + namespace clang { class CharUnits; class CXXRecordDecl; @@ -28,9 +30,14 @@ class CompilerType; namespace llvm { namespace pdb { +template <typename ChildType> class ConcreteSymbolEnumerator; + class PDBSymbol; class PDBSymbolData; +class PDBSymbolFunc; +class PDBSymbolTypeBaseClass; class PDBSymbolTypeBuiltin; +class PDBSymbolTypeUDT; } // namespace pdb } // namespace llvm @@ -40,13 +47,71 @@ public: ~PDBASTParser(); lldb::TypeSP CreateLLDBTypeFromPDBType(const llvm::pdb::PDBSymbol &type); + bool CompleteTypeFromPDB(lldb_private::CompilerType &compiler_type); + + clang::Decl *GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol); + + clang::DeclContext * + GetDeclContextForSymbol(const llvm::pdb::PDBSymbol &symbol); + clang::DeclContext * + GetDeclContextContainingSymbol(const llvm::pdb::PDBSymbol &symbol); + + void ParseDeclsForDeclContext(const clang::DeclContext *decl_context); + + clang::NamespaceDecl *FindNamespaceDecl(const clang::DeclContext *parent, + llvm::StringRef name); + + lldb_private::ClangASTImporter &GetClangASTImporter() { + return m_ast_importer; + } private: + typedef llvm::DenseMap<clang::CXXRecordDecl *, lldb::user_id_t> + CXXRecordDeclToUidMap; + typedef llvm::DenseMap<lldb::user_id_t, clang::Decl *> UidToDeclMap; + typedef std::set<clang::NamespaceDecl *> NamespacesSet; + typedef llvm::DenseMap<clang::DeclContext *, NamespacesSet> + ParentToNamespacesMap; + typedef llvm::DenseMap<clang::DeclContext *, lldb::user_id_t> + DeclContextToUidMap; + typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolData> + PDBDataSymbolEnumerator; + typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolTypeBaseClass> + PDBBaseClassSymbolEnumerator; + typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolFunc> + PDBFuncSymbolEnumerator; + bool AddEnumValue(lldb_private::CompilerType enum_type, - const llvm::pdb::PDBSymbolData &data) const; + const llvm::pdb::PDBSymbolData &data); + bool CompleteTypeFromUDT(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &compiler_type, + llvm::pdb::PDBSymbolTypeUDT &udt); + void + AddRecordMembers(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBDataSymbolEnumerator &members_enum, + lldb_private::ClangASTImporter::LayoutInfo &layout_info); + void + AddRecordBases(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, int record_kind, + PDBBaseClassSymbolEnumerator &bases_enum, + lldb_private::ClangASTImporter::LayoutInfo &layout_info) const; + void AddRecordMethods(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBFuncSymbolEnumerator &methods_enum); + clang::CXXMethodDecl * + AddRecordMethod(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + const llvm::pdb::PDBSymbolFunc &method) const; lldb_private::ClangASTContext &m_ast; lldb_private::ClangASTImporter m_ast_importer; + + CXXRecordDeclToUidMap m_forward_decl_to_uid; + UidToDeclMap m_uid_to_decl; + ParentToNamespacesMap m_parent_to_namespaces; + NamespacesSet m_namespaces; + DeclContextToUidMap m_decl_context_to_uid; }; #endif // LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H diff --git a/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp b/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp index 69ef70cc508c..9f398ef9b047 100644 --- a/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp +++ b/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp @@ -26,51 +26,51 @@ using namespace llvm::pdb; namespace { const uint32_t g_code_view_to_lldb_registers_x86[] = { - LLDB_INVALID_REGNUM, // CVRegNONE - lldb_al_i386, // CVRegAL - lldb_cl_i386, // CVRegCL - lldb_dl_i386, // CVRegDL - lldb_bl_i386, // CVRegBL - lldb_ah_i386, // CVRegAH - lldb_ch_i386, // CVRegCH - lldb_dh_i386, // CVRegDH - lldb_bh_i386, // CVRegBH - lldb_ax_i386, // CVRegAX - lldb_cx_i386, // CVRegCX - lldb_dx_i386, // CVRegDX - lldb_bx_i386, // CVRegBX - lldb_sp_i386, // CVRegSP - lldb_bp_i386, // CVRegBP - lldb_si_i386, // CVRegSI - lldb_di_i386, // CVRegDI - lldb_eax_i386, // CVRegEAX - lldb_ecx_i386, // CVRegECX - lldb_edx_i386, // CVRegEDX - lldb_ebx_i386, // CVRegEBX - lldb_esp_i386, // CVRegESP - lldb_ebp_i386, // CVRegEBP - lldb_esi_i386, // CVRegESI - lldb_edi_i386, // CVRegEDI - lldb_es_i386, // CVRegES - lldb_cs_i386, // CVRegCS - lldb_ss_i386, // CVRegSS - lldb_ds_i386, // CVRegDS - lldb_fs_i386, // CVRegFS - lldb_gs_i386, // CVRegGS - LLDB_INVALID_REGNUM, // CVRegIP - LLDB_INVALID_REGNUM, // CVRegFLAGS - lldb_eip_i386, // CVRegEIP - lldb_eflags_i386, // CVRegEFLAGS + LLDB_INVALID_REGNUM, // NONE + lldb_al_i386, // AL + lldb_cl_i386, // CL + lldb_dl_i386, // DL + lldb_bl_i386, // BL + lldb_ah_i386, // AH + lldb_ch_i386, // CH + lldb_dh_i386, // DH + lldb_bh_i386, // BH + lldb_ax_i386, // AX + lldb_cx_i386, // CX + lldb_dx_i386, // DX + lldb_bx_i386, // BX + lldb_sp_i386, // SP + lldb_bp_i386, // BP + lldb_si_i386, // SI + lldb_di_i386, // DI + lldb_eax_i386, // EAX + lldb_ecx_i386, // ECX + lldb_edx_i386, // EDX + lldb_ebx_i386, // EBX + lldb_esp_i386, // ESP + lldb_ebp_i386, // EBP + lldb_esi_i386, // ESI + lldb_edi_i386, // EDI + lldb_es_i386, // ES + lldb_cs_i386, // CS + lldb_ss_i386, // SS + lldb_ds_i386, // DS + lldb_fs_i386, // FS + lldb_gs_i386, // GS + LLDB_INVALID_REGNUM, // IP + LLDB_INVALID_REGNUM, // FLAGS + lldb_eip_i386, // EIP + lldb_eflags_i386, // EFLAGS LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, // CVRegTEMP - LLDB_INVALID_REGNUM, // CVRegTEMPH - LLDB_INVALID_REGNUM, // CVRegQUOTE - LLDB_INVALID_REGNUM, // CVRegPCDR3 - LLDB_INVALID_REGNUM, // CVRegPCDR4 - LLDB_INVALID_REGNUM, // CVRegPCDR5 - LLDB_INVALID_REGNUM, // CVRegPCDR6 - LLDB_INVALID_REGNUM, // CVRegPCDR7 + LLDB_INVALID_REGNUM, // TEMP + LLDB_INVALID_REGNUM, // TEMPH + LLDB_INVALID_REGNUM, // QUOTE + LLDB_INVALID_REGNUM, // PCDR3 + LLDB_INVALID_REGNUM, // PCDR4 + LLDB_INVALID_REGNUM, // PCDR5 + LLDB_INVALID_REGNUM, // PCDR6 + LLDB_INVALID_REGNUM, // PCDR7 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, @@ -82,123 +82,123 @@ const uint32_t g_code_view_to_lldb_registers_x86[] = { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, // CVRegCR0 - LLDB_INVALID_REGNUM, // CVRegCR1 - LLDB_INVALID_REGNUM, // CVRegCR2 - LLDB_INVALID_REGNUM, // CVRegCR3 - LLDB_INVALID_REGNUM, // CVRegCR4 + LLDB_INVALID_REGNUM, // CR0 + LLDB_INVALID_REGNUM, // CR1 + LLDB_INVALID_REGNUM, // CR2 + LLDB_INVALID_REGNUM, // CR3 + LLDB_INVALID_REGNUM, // CR4 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - lldb_dr0_i386, // CVRegDR0 - lldb_dr1_i386, // CVRegDR1 - lldb_dr2_i386, // CVRegDR2 - lldb_dr3_i386, // CVRegDR3 - lldb_dr4_i386, // CVRegDR4 - lldb_dr5_i386, // CVRegDR5 - lldb_dr6_i386, // CVRegDR6 - lldb_dr7_i386, // CVRegDR7 - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, // CVRegGDTR - LLDB_INVALID_REGNUM, // CVRegGDTL - LLDB_INVALID_REGNUM, // CVRegIDTR - LLDB_INVALID_REGNUM, // CVRegIDTL - LLDB_INVALID_REGNUM, // CVRegLDTR - LLDB_INVALID_REGNUM, // CVRegTR - LLDB_INVALID_REGNUM, // CVRegPSEUDO1 - LLDB_INVALID_REGNUM, // CVRegPSEUDO2 - LLDB_INVALID_REGNUM, // CVRegPSEUDO3 - LLDB_INVALID_REGNUM, // CVRegPSEUDO4 - LLDB_INVALID_REGNUM, // CVRegPSEUDO5 - LLDB_INVALID_REGNUM, // CVRegPSEUDO6 - LLDB_INVALID_REGNUM, // CVRegPSEUDO7 - LLDB_INVALID_REGNUM, // CVRegPSEUDO8 - LLDB_INVALID_REGNUM, // CVRegPSEUDO9 - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - lldb_st0_i386, // CVRegST0 - lldb_st1_i386, // CVRegST1 - lldb_st2_i386, // CVRegST2 - lldb_st3_i386, // CVRegST3 - lldb_st4_i386, // CVRegST4 - lldb_st5_i386, // CVRegST5 - lldb_st6_i386, // CVRegST6 - lldb_st7_i386, // CVRegST7 - LLDB_INVALID_REGNUM, // CVRegCTRL - LLDB_INVALID_REGNUM, // CVRegSTAT - LLDB_INVALID_REGNUM, // CVRegTAG - LLDB_INVALID_REGNUM, // CVRegFPIP - LLDB_INVALID_REGNUM, // CVRegFPCS - LLDB_INVALID_REGNUM, // CVRegFPDO - LLDB_INVALID_REGNUM, // CVRegFPDS - LLDB_INVALID_REGNUM, // CVRegISEM - LLDB_INVALID_REGNUM, // CVRegFPEIP - LLDB_INVALID_REGNUM, // CVRegFPEDO - lldb_mm0_i386, // CVRegMM0 - lldb_mm1_i386, // CVRegMM1 - lldb_mm2_i386, // CVRegMM2 - lldb_mm3_i386, // CVRegMM3 - lldb_mm4_i386, // CVRegMM4 - lldb_mm5_i386, // CVRegMM5 - lldb_mm6_i386, // CVRegMM6 - lldb_mm7_i386, // CVRegMM7 - lldb_xmm0_i386, // CVRegXMM0 - lldb_xmm1_i386, // CVRegXMM1 - lldb_xmm2_i386, // CVRegXMM2 - lldb_xmm3_i386, // CVRegXMM3 - lldb_xmm4_i386, // CVRegXMM4 - lldb_xmm5_i386, // CVRegXMM5 - lldb_xmm6_i386, // CVRegXMM6 - lldb_xmm7_i386 // CVRegXMM7 + lldb_dr0_i386, // DR0 + lldb_dr1_i386, // DR1 + lldb_dr2_i386, // DR2 + lldb_dr3_i386, // DR3 + lldb_dr4_i386, // DR4 + lldb_dr5_i386, // DR5 + lldb_dr6_i386, // DR6 + lldb_dr7_i386, // DR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // GDTR + LLDB_INVALID_REGNUM, // GDTL + LLDB_INVALID_REGNUM, // IDTR + LLDB_INVALID_REGNUM, // IDTL + LLDB_INVALID_REGNUM, // LDTR + LLDB_INVALID_REGNUM, // TR + LLDB_INVALID_REGNUM, // PSEUDO1 + LLDB_INVALID_REGNUM, // PSEUDO2 + LLDB_INVALID_REGNUM, // PSEUDO3 + LLDB_INVALID_REGNUM, // PSEUDO4 + LLDB_INVALID_REGNUM, // PSEUDO5 + LLDB_INVALID_REGNUM, // PSEUDO6 + LLDB_INVALID_REGNUM, // PSEUDO7 + LLDB_INVALID_REGNUM, // PSEUDO8 + LLDB_INVALID_REGNUM, // PSEUDO9 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_st0_i386, // ST0 + lldb_st1_i386, // ST1 + lldb_st2_i386, // ST2 + lldb_st3_i386, // ST3 + lldb_st4_i386, // ST4 + lldb_st5_i386, // ST5 + lldb_st6_i386, // ST6 + lldb_st7_i386, // ST7 + LLDB_INVALID_REGNUM, // CTRL + LLDB_INVALID_REGNUM, // STAT + LLDB_INVALID_REGNUM, // TAG + LLDB_INVALID_REGNUM, // FPIP + LLDB_INVALID_REGNUM, // FPCS + LLDB_INVALID_REGNUM, // FPDO + LLDB_INVALID_REGNUM, // FPDS + LLDB_INVALID_REGNUM, // ISEM + LLDB_INVALID_REGNUM, // FPEIP + LLDB_INVALID_REGNUM, // FPEDO + lldb_mm0_i386, // MM0 + lldb_mm1_i386, // MM1 + lldb_mm2_i386, // MM2 + lldb_mm3_i386, // MM3 + lldb_mm4_i386, // MM4 + lldb_mm5_i386, // MM5 + lldb_mm6_i386, // MM6 + lldb_mm7_i386, // MM7 + lldb_xmm0_i386, // XMM0 + lldb_xmm1_i386, // XMM1 + lldb_xmm2_i386, // XMM2 + lldb_xmm3_i386, // XMM3 + lldb_xmm4_i386, // XMM4 + lldb_xmm5_i386, // XMM5 + lldb_xmm6_i386, // XMM6 + lldb_xmm7_i386 // XMM7 }; const uint32_t g_code_view_to_lldb_registers_x86_64[] = { - LLDB_INVALID_REGNUM, // CVRegNONE - lldb_al_x86_64, // CVRegAL - lldb_cl_x86_64, // CVRegCL - lldb_dl_x86_64, // CVRegDL - lldb_bl_x86_64, // CVRegBL - lldb_ah_x86_64, // CVRegAH - lldb_ch_x86_64, // CVRegCH - lldb_dh_x86_64, // CVRegDH - lldb_bh_x86_64, // CVRegBH - lldb_ax_x86_64, // CVRegAX - lldb_cx_x86_64, // CVRegCX - lldb_dx_x86_64, // CVRegDX - lldb_bx_x86_64, // CVRegBX - lldb_sp_x86_64, // CVRegSP - lldb_bp_x86_64, // CVRegBP - lldb_si_x86_64, // CVRegSI - lldb_di_x86_64, // CVRegDI - lldb_eax_x86_64, // CVRegEAX - lldb_ecx_x86_64, // CVRegECX - lldb_edx_x86_64, // CVRegEDX - lldb_ebx_x86_64, // CVRegEBX - lldb_esp_x86_64, // CVRegESP - lldb_ebp_x86_64, // CVRegEBP - lldb_esi_x86_64, // CVRegESI - lldb_edi_x86_64, // CVRegEDI - lldb_es_x86_64, // CVRegES - lldb_cs_x86_64, // CVRegCS - lldb_ss_x86_64, // CVRegSS - lldb_ds_x86_64, // CVRegDS - lldb_fs_x86_64, // CVRegFS - lldb_gs_x86_64, // CVRegGS - LLDB_INVALID_REGNUM, // CVRegIP - LLDB_INVALID_REGNUM, // CVRegFLAGS - LLDB_INVALID_REGNUM, // CVRegEIP - LLDB_INVALID_REGNUM, // CVRegEFLAGS + LLDB_INVALID_REGNUM, // NONE + lldb_al_x86_64, // AL + lldb_cl_x86_64, // CL + lldb_dl_x86_64, // DL + lldb_bl_x86_64, // BL + lldb_ah_x86_64, // AH + lldb_ch_x86_64, // CH + lldb_dh_x86_64, // DH + lldb_bh_x86_64, // BH + lldb_ax_x86_64, // AX + lldb_cx_x86_64, // CX + lldb_dx_x86_64, // DX + lldb_bx_x86_64, // BX + lldb_sp_x86_64, // SP + lldb_bp_x86_64, // BP + lldb_si_x86_64, // SI + lldb_di_x86_64, // DI + lldb_eax_x86_64, // EAX + lldb_ecx_x86_64, // ECX + lldb_edx_x86_64, // EDX + lldb_ebx_x86_64, // EBX + lldb_esp_x86_64, // ESP + lldb_ebp_x86_64, // EBP + lldb_esi_x86_64, // ESI + lldb_edi_x86_64, // EDI + lldb_es_x86_64, // ES + lldb_cs_x86_64, // CS + lldb_ss_x86_64, // SS + lldb_ds_x86_64, // DS + lldb_fs_x86_64, // FS + lldb_gs_x86_64, // GS + LLDB_INVALID_REGNUM, // IP + LLDB_INVALID_REGNUM, // FLAGS + LLDB_INVALID_REGNUM, // EIP + LLDB_INVALID_REGNUM, // EFLAGS LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, // CVRegTEMP - LLDB_INVALID_REGNUM, // CVRegTEMPH - LLDB_INVALID_REGNUM, // CVRegQUOTE - LLDB_INVALID_REGNUM, // CVRegPCDR3 - LLDB_INVALID_REGNUM, // CVRegPCDR4 - LLDB_INVALID_REGNUM, // CVRegPCDR5 - LLDB_INVALID_REGNUM, // CVRegPCDR6 - LLDB_INVALID_REGNUM, // CVRegPCDR7 + LLDB_INVALID_REGNUM, // TEMP + LLDB_INVALID_REGNUM, // TEMPH + LLDB_INVALID_REGNUM, // QUOTE + LLDB_INVALID_REGNUM, // PCDR3 + LLDB_INVALID_REGNUM, // PCDR4 + LLDB_INVALID_REGNUM, // PCDR5 + LLDB_INVALID_REGNUM, // PCDR6 + LLDB_INVALID_REGNUM, // PCDR7 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, @@ -210,75 +210,75 @@ const uint32_t g_code_view_to_lldb_registers_x86_64[] = { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, // CVRegCR0 - LLDB_INVALID_REGNUM, // CVRegCR1 - LLDB_INVALID_REGNUM, // CVRegCR2 - LLDB_INVALID_REGNUM, // CVRegCR3 - LLDB_INVALID_REGNUM, // CVRegCR4 + LLDB_INVALID_REGNUM, // CR0 + LLDB_INVALID_REGNUM, // CR1 + LLDB_INVALID_REGNUM, // CR2 + LLDB_INVALID_REGNUM, // CR3 + LLDB_INVALID_REGNUM, // CR4 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - lldb_dr0_x86_64, // CVRegDR0 - lldb_dr1_x86_64, // CVRegDR1 - lldb_dr2_x86_64, // CVRegDR2 - lldb_dr3_x86_64, // CVRegDR3 - lldb_dr4_x86_64, // CVRegDR4 - lldb_dr5_x86_64, // CVRegDR5 - lldb_dr6_x86_64, // CVRegDR6 - lldb_dr7_x86_64, // CVRegDR7 + lldb_dr0_x86_64, // DR0 + lldb_dr1_x86_64, // DR1 + lldb_dr2_x86_64, // DR2 + lldb_dr3_x86_64, // DR3 + lldb_dr4_x86_64, // DR4 + lldb_dr5_x86_64, // DR5 + lldb_dr6_x86_64, // DR6 + lldb_dr7_x86_64, // DR7 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, // CVRegGDTR - LLDB_INVALID_REGNUM, // CVRegGDTL - LLDB_INVALID_REGNUM, // CVRegIDTR - LLDB_INVALID_REGNUM, // CVRegIDTL - LLDB_INVALID_REGNUM, // CVRegLDTR - LLDB_INVALID_REGNUM, // CVRegTR - LLDB_INVALID_REGNUM, // CVRegPSEUDO1 - LLDB_INVALID_REGNUM, // CVRegPSEUDO2 - LLDB_INVALID_REGNUM, // CVRegPSEUDO3 - LLDB_INVALID_REGNUM, // CVRegPSEUDO4 - LLDB_INVALID_REGNUM, // CVRegPSEUDO5 - LLDB_INVALID_REGNUM, // CVRegPSEUDO6 - LLDB_INVALID_REGNUM, // CVRegPSEUDO7 - LLDB_INVALID_REGNUM, // CVRegPSEUDO8 - LLDB_INVALID_REGNUM, // CVRegPSEUDO9 + LLDB_INVALID_REGNUM, // GDTR + LLDB_INVALID_REGNUM, // GDTL + LLDB_INVALID_REGNUM, // IDTR + LLDB_INVALID_REGNUM, // IDTL + LLDB_INVALID_REGNUM, // LDTR + LLDB_INVALID_REGNUM, // TR + LLDB_INVALID_REGNUM, // PSEUDO1 + LLDB_INVALID_REGNUM, // PSEUDO2 + LLDB_INVALID_REGNUM, // PSEUDO3 + LLDB_INVALID_REGNUM, // PSEUDO4 + LLDB_INVALID_REGNUM, // PSEUDO5 + LLDB_INVALID_REGNUM, // PSEUDO6 + LLDB_INVALID_REGNUM, // PSEUDO7 + LLDB_INVALID_REGNUM, // PSEUDO8 + LLDB_INVALID_REGNUM, // PSEUDO9 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - lldb_st0_x86_64, // CVRegST0 - lldb_st1_x86_64, // CVRegST1 - lldb_st2_x86_64, // CVRegST2 - lldb_st3_x86_64, // CVRegST3 - lldb_st4_x86_64, // CVRegST4 - lldb_st5_x86_64, // CVRegST5 - lldb_st6_x86_64, // CVRegST6 - lldb_st7_x86_64, // CVRegST7 - LLDB_INVALID_REGNUM, // CVRegCTRL - LLDB_INVALID_REGNUM, // CVRegSTAT - LLDB_INVALID_REGNUM, // CVRegTAG - LLDB_INVALID_REGNUM, // CVRegFPIP - LLDB_INVALID_REGNUM, // CVRegFPCS - LLDB_INVALID_REGNUM, // CVRegFPDO - LLDB_INVALID_REGNUM, // CVRegFPDS - LLDB_INVALID_REGNUM, // CVRegISEM - LLDB_INVALID_REGNUM, // CVRegFPEIP - LLDB_INVALID_REGNUM, // CVRegFPEDO - lldb_mm0_x86_64, // CVRegMM0 - lldb_mm1_x86_64, // CVRegMM1 - lldb_mm2_x86_64, // CVRegMM2 - lldb_mm3_x86_64, // CVRegMM3 - lldb_mm4_x86_64, // CVRegMM4 - lldb_mm5_x86_64, // CVRegMM5 - lldb_mm6_x86_64, // CVRegMM6 - lldb_mm7_x86_64, // CVRegMM7 - lldb_xmm0_x86_64, // CVRegXMM0 - lldb_xmm1_x86_64, // CVRegXMM1 - lldb_xmm2_x86_64, // CVRegXMM2 - lldb_xmm3_x86_64, // CVRegXMM3 - lldb_xmm4_x86_64, // CVRegXMM4 - lldb_xmm5_x86_64, // CVRegXMM5 - lldb_xmm6_x86_64, // CVRegXMM6 - lldb_xmm7_x86_64, // CVRegXMM7 + lldb_st0_x86_64, // ST0 + lldb_st1_x86_64, // ST1 + lldb_st2_x86_64, // ST2 + lldb_st3_x86_64, // ST3 + lldb_st4_x86_64, // ST4 + lldb_st5_x86_64, // ST5 + lldb_st6_x86_64, // ST6 + lldb_st7_x86_64, // ST7 + LLDB_INVALID_REGNUM, // CTRL + LLDB_INVALID_REGNUM, // STAT + LLDB_INVALID_REGNUM, // TAG + LLDB_INVALID_REGNUM, // FPIP + LLDB_INVALID_REGNUM, // FPCS + LLDB_INVALID_REGNUM, // FPDO + LLDB_INVALID_REGNUM, // FPDS + LLDB_INVALID_REGNUM, // ISEM + LLDB_INVALID_REGNUM, // FPEIP + LLDB_INVALID_REGNUM, // FPEDO + lldb_mm0_x86_64, // MM0 + lldb_mm1_x86_64, // MM1 + lldb_mm2_x86_64, // MM2 + lldb_mm3_x86_64, // MM3 + lldb_mm4_x86_64, // MM4 + lldb_mm5_x86_64, // MM5 + lldb_mm6_x86_64, // MM6 + lldb_mm7_x86_64, // MM7 + lldb_xmm0_x86_64, // XMM0 + lldb_xmm1_x86_64, // XMM1 + lldb_xmm2_x86_64, // XMM2 + lldb_xmm3_x86_64, // XMM3 + lldb_xmm4_x86_64, // XMM4 + lldb_xmm5_x86_64, // XMM5 + lldb_xmm6_x86_64, // XMM6 + lldb_xmm7_x86_64, // XMM7 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, @@ -296,51 +296,51 @@ const uint32_t g_code_view_to_lldb_registers_x86_64[] = { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - lldb_mxcsr_x86_64, // CVRegMXCSR - LLDB_INVALID_REGNUM, // CVRegEDXEAX + lldb_mxcsr_x86_64, // MXCSR + LLDB_INVALID_REGNUM, // EDXEAX LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, // CVRegEMM0L - LLDB_INVALID_REGNUM, // CVRegEMM1L - LLDB_INVALID_REGNUM, // CVRegEMM2L - LLDB_INVALID_REGNUM, // CVRegEMM3L - LLDB_INVALID_REGNUM, // CVRegEMM4L - LLDB_INVALID_REGNUM, // CVRegEMM5L - LLDB_INVALID_REGNUM, // CVRegEMM6L - LLDB_INVALID_REGNUM, // CVRegEMM7L - LLDB_INVALID_REGNUM, // CVRegEMM0H - LLDB_INVALID_REGNUM, // CVRegEMM1H - LLDB_INVALID_REGNUM, // CVRegEMM2H - LLDB_INVALID_REGNUM, // CVRegEMM3H - LLDB_INVALID_REGNUM, // CVRegEMM4H - LLDB_INVALID_REGNUM, // CVRegEMM5H - LLDB_INVALID_REGNUM, // CVRegEMM6H - LLDB_INVALID_REGNUM, // CVRegEMM7H - LLDB_INVALID_REGNUM, // CVRegMM00 - LLDB_INVALID_REGNUM, // CVRegMM01 - LLDB_INVALID_REGNUM, // CVRegMM10 - LLDB_INVALID_REGNUM, // CVRegMM11 - LLDB_INVALID_REGNUM, // CVRegMM20 - LLDB_INVALID_REGNUM, // CVRegMM21 - LLDB_INVALID_REGNUM, // CVRegMM30 - LLDB_INVALID_REGNUM, // CVRegMM31 - LLDB_INVALID_REGNUM, // CVRegMM40 - LLDB_INVALID_REGNUM, // CVRegMM41 - LLDB_INVALID_REGNUM, // CVRegMM50 - LLDB_INVALID_REGNUM, // CVRegMM51 - LLDB_INVALID_REGNUM, // CVRegMM60 - LLDB_INVALID_REGNUM, // CVRegMM61 - LLDB_INVALID_REGNUM, // CVRegMM70 - LLDB_INVALID_REGNUM, // CVRegMM71 - lldb_xmm8_x86_64, // CVRegXMM8 - lldb_xmm9_x86_64, // CVRegXMM9 - lldb_xmm10_x86_64, // CVRegXMM10 - lldb_xmm11_x86_64, // CVRegXMM11 - lldb_xmm12_x86_64, // CVRegXMM12 - lldb_xmm13_x86_64, // CVRegXMM13 - lldb_xmm14_x86_64, // CVRegXMM14 - lldb_xmm15_x86_64, // CVRegXMM15 + LLDB_INVALID_REGNUM, // EMM0L + LLDB_INVALID_REGNUM, // EMM1L + LLDB_INVALID_REGNUM, // EMM2L + LLDB_INVALID_REGNUM, // EMM3L + LLDB_INVALID_REGNUM, // EMM4L + LLDB_INVALID_REGNUM, // EMM5L + LLDB_INVALID_REGNUM, // EMM6L + LLDB_INVALID_REGNUM, // EMM7L + LLDB_INVALID_REGNUM, // EMM0H + LLDB_INVALID_REGNUM, // EMM1H + LLDB_INVALID_REGNUM, // EMM2H + LLDB_INVALID_REGNUM, // EMM3H + LLDB_INVALID_REGNUM, // EMM4H + LLDB_INVALID_REGNUM, // EMM5H + LLDB_INVALID_REGNUM, // EMM6H + LLDB_INVALID_REGNUM, // EMM7H + LLDB_INVALID_REGNUM, // MM00 + LLDB_INVALID_REGNUM, // MM01 + LLDB_INVALID_REGNUM, // MM10 + LLDB_INVALID_REGNUM, // MM11 + LLDB_INVALID_REGNUM, // MM20 + LLDB_INVALID_REGNUM, // MM21 + LLDB_INVALID_REGNUM, // MM30 + LLDB_INVALID_REGNUM, // MM31 + LLDB_INVALID_REGNUM, // MM40 + LLDB_INVALID_REGNUM, // MM41 + LLDB_INVALID_REGNUM, // MM50 + LLDB_INVALID_REGNUM, // MM51 + LLDB_INVALID_REGNUM, // MM60 + LLDB_INVALID_REGNUM, // MM61 + LLDB_INVALID_REGNUM, // MM70 + LLDB_INVALID_REGNUM, // MM71 + lldb_xmm8_x86_64, // XMM8 + lldb_xmm9_x86_64, // XMM9 + lldb_xmm10_x86_64, // XMM10 + lldb_xmm11_x86_64, // XMM11 + lldb_xmm12_x86_64, // XMM12 + lldb_xmm13_x86_64, // XMM13 + lldb_xmm14_x86_64, // XMM14 + lldb_xmm15_x86_64, // XMM15 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, @@ -363,73 +363,73 @@ const uint32_t g_code_view_to_lldb_registers_x86_64[] = { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - lldb_sil_x86_64, // CVRegSIL - lldb_dil_x86_64, // CVRegDIL - lldb_bpl_x86_64, // CVRegBPL - lldb_spl_x86_64, // CVRegSPL - lldb_rax_x86_64, // CVRegRAX - lldb_rbx_x86_64, // CVRegRBX - lldb_rcx_x86_64, // CVRegRCX - lldb_rdx_x86_64, // CVRegRDX - lldb_rsi_x86_64, // CVRegRSI - lldb_rdi_x86_64, // CVRegRDI - lldb_rbp_x86_64, // CVRegRBP - lldb_rsp_x86_64, // CVRegRSP - lldb_r8_x86_64, // CVRegR8 - lldb_r9_x86_64, // CVRegR9 - lldb_r10_x86_64, // CVRegR10 - lldb_r11_x86_64, // CVRegR11 - lldb_r12_x86_64, // CVRegR12 - lldb_r13_x86_64, // CVRegR13 - lldb_r14_x86_64, // CVRegR14 - lldb_r15_x86_64, // CVRegR15 - lldb_r8l_x86_64, // CVRegR8B - lldb_r9l_x86_64, // CVRegR9B - lldb_r10l_x86_64, // CVRegR10B - lldb_r11l_x86_64, // CVRegR11B - lldb_r12l_x86_64, // CVRegR12B - lldb_r13l_x86_64, // CVRegR13B - lldb_r14l_x86_64, // CVRegR14B - lldb_r15l_x86_64, // CVRegR15B - lldb_r8w_x86_64, // CVRegR8W - lldb_r9w_x86_64, // CVRegR9W - lldb_r10w_x86_64, // CVRegR10W - lldb_r11w_x86_64, // CVRegR11W - lldb_r12w_x86_64, // CVRegR12W - lldb_r13w_x86_64, // CVRegR13W - lldb_r14w_x86_64, // CVRegR14W - lldb_r15w_x86_64, // CVRegR15W - lldb_r8d_x86_64, // CVRegR8D - lldb_r9d_x86_64, // CVRegR9D - lldb_r10d_x86_64, // CVRegR10D - lldb_r11d_x86_64, // CVRegR11D - lldb_r12d_x86_64, // CVRegR12D - lldb_r13d_x86_64, // CVRegR13D - lldb_r14d_x86_64, // CVRegR14D - lldb_r15d_x86_64, // CVRegR15D - lldb_ymm0_x86_64, // CVRegAMD64_YMM0 - lldb_ymm1_x86_64, // CVRegAMD64_YMM1 - lldb_ymm2_x86_64, // CVRegAMD64_YMM2 - lldb_ymm3_x86_64, // CVRegAMD64_YMM3 - lldb_ymm4_x86_64, // CVRegAMD64_YMM4 - lldb_ymm5_x86_64, // CVRegAMD64_YMM5 - lldb_ymm6_x86_64, // CVRegAMD64_YMM6 - lldb_ymm7_x86_64, // CVRegAMD64_YMM7 - lldb_ymm8_x86_64, // CVRegAMD64_YMM8 - lldb_ymm9_x86_64, // CVRegAMD64_YMM9 - lldb_ymm10_x86_64, // CVRegAMD64_YMM10 - lldb_ymm11_x86_64, // CVRegAMD64_YMM11 - lldb_ymm12_x86_64, // CVRegAMD64_YMM12 - lldb_ymm13_x86_64, // CVRegAMD64_YMM13 - lldb_ymm14_x86_64, // CVRegAMD64_YMM14 - lldb_ymm15_x86_64, // CVRegAMD64_YMM15 - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, - lldb_bnd0_x86_64, // CVRegBND0 - lldb_bnd1_x86_64, // CVRegBND1 - lldb_bnd2_x86_64 // CVRegBND2 + lldb_sil_x86_64, // SIL + lldb_dil_x86_64, // DIL + lldb_bpl_x86_64, // BPL + lldb_spl_x86_64, // SPL + lldb_rax_x86_64, // RAX + lldb_rbx_x86_64, // RBX + lldb_rcx_x86_64, // RCX + lldb_rdx_x86_64, // RDX + lldb_rsi_x86_64, // RSI + lldb_rdi_x86_64, // RDI + lldb_rbp_x86_64, // RBP + lldb_rsp_x86_64, // RSP + lldb_r8_x86_64, // R8 + lldb_r9_x86_64, // R9 + lldb_r10_x86_64, // R10 + lldb_r11_x86_64, // R11 + lldb_r12_x86_64, // R12 + lldb_r13_x86_64, // R13 + lldb_r14_x86_64, // R14 + lldb_r15_x86_64, // R15 + lldb_r8l_x86_64, // R8B + lldb_r9l_x86_64, // R9B + lldb_r10l_x86_64, // R10B + lldb_r11l_x86_64, // R11B + lldb_r12l_x86_64, // R12B + lldb_r13l_x86_64, // R13B + lldb_r14l_x86_64, // R14B + lldb_r15l_x86_64, // R15B + lldb_r8w_x86_64, // R8W + lldb_r9w_x86_64, // R9W + lldb_r10w_x86_64, // R10W + lldb_r11w_x86_64, // R11W + lldb_r12w_x86_64, // R12W + lldb_r13w_x86_64, // R13W + lldb_r14w_x86_64, // R14W + lldb_r15w_x86_64, // R15W + lldb_r8d_x86_64, // R8D + lldb_r9d_x86_64, // R9D + lldb_r10d_x86_64, // R10D + lldb_r11d_x86_64, // R11D + lldb_r12d_x86_64, // R12D + lldb_r13d_x86_64, // R13D + lldb_r14d_x86_64, // R14D + lldb_r15d_x86_64, // R15D + lldb_ymm0_x86_64, // AMD64_YMM0 + lldb_ymm1_x86_64, // AMD64_YMM1 + lldb_ymm2_x86_64, // AMD64_YMM2 + lldb_ymm3_x86_64, // AMD64_YMM3 + lldb_ymm4_x86_64, // AMD64_YMM4 + lldb_ymm5_x86_64, // AMD64_YMM5 + lldb_ymm6_x86_64, // AMD64_YMM6 + lldb_ymm7_x86_64, // AMD64_YMM7 + lldb_ymm8_x86_64, // AMD64_YMM8 + lldb_ymm9_x86_64, // AMD64_YMM9 + lldb_ymm10_x86_64, // AMD64_YMM10 + lldb_ymm11_x86_64, // AMD64_YMM11 + lldb_ymm12_x86_64, // AMD64_YMM12 + lldb_ymm13_x86_64, // AMD64_YMM13 + lldb_ymm14_x86_64, // AMD64_YMM14 + lldb_ymm15_x86_64, // AMD64_YMM15 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_bnd0_x86_64, // BND0 + lldb_bnd1_x86_64, // BND1 + lldb_bnd2_x86_64 // BND2 }; uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type, @@ -443,13 +443,13 @@ uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type, register_id)]; switch (register_id) { - case llvm::codeview::RegisterId::CVRegMXCSR: + case llvm::codeview::RegisterId::MXCSR: return lldb_mxcsr_i386; - case llvm::codeview::RegisterId::CVRegBND0: + case llvm::codeview::RegisterId::BND0: return lldb_bnd0_i386; - case llvm::codeview::RegisterId::CVRegBND1: + case llvm::codeview::RegisterId::BND1: return lldb_bnd1_i386; - case llvm::codeview::RegisterId::CVRegBND2: + case llvm::codeview::RegisterId::BND2: return lldb_bnd2_i386; default: return LLDB_INVALID_REGNUM; @@ -468,7 +468,7 @@ uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type, } uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) { - if (register_id == llvm::codeview::RegisterId::CVRegVFRAME) + if (register_id == llvm::codeview::RegisterId::VFRAME) return LLDB_REGNUM_GENERIC_FP; return LLDB_INVALID_REGNUM; diff --git a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index 05f3017819fa..ad25842f4d05 100644 --- a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -9,6 +9,9 @@ #include "SymbolFilePDB.h" +#include "PDBASTParser.h" +#include "PDBLocationToDWARFExpression.h" + #include "clang/Lex/Lexer.h" #include "lldb/Core/Module.h" @@ -46,8 +49,8 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" -#include "Plugins/SymbolFile/PDB/PDBASTParser.h" -#include "Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h" +#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h" #include <regex> @@ -74,14 +77,32 @@ bool ShouldAddLine(uint32_t requested_line, uint32_t actual_line, } } // namespace +static bool ShouldUseNativeReader() { +#if defined(_WIN32) + llvm::StringRef use_native = ::getenv("LLDB_USE_NATIVE_PDB_READER"); + return use_native.equals_lower("on") || use_native.equals_lower("yes") || + use_native.equals_lower("1") || use_native.equals_lower("true"); +#else + return true; +#endif +} + void SymbolFilePDB::Initialize() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), CreateInstance, - DebuggerInitialize); + if (ShouldUseNativeReader()) { + npdb::SymbolFileNativePDB::Initialize(); + } else { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); + } } void SymbolFilePDB::Terminate() { - PluginManager::UnregisterPlugin(CreateInstance); + if (ShouldUseNativeReader()) { + npdb::SymbolFileNativePDB::Terminate(); + } else { + PluginManager::UnregisterPlugin(CreateInstance); + } } void SymbolFilePDB::DebuggerInitialize(lldb_private::Debugger &debugger) {} @@ -246,14 +267,8 @@ lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitAtIndex(uint32_t index) { return ParseCompileUnitForUID(compiland_up->getSymIndexId(), index); } -lldb::LanguageType -SymbolFilePDB::ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) { - // What fields should I expect to be filled out on the SymbolContext? Is it - // safe to assume that `sc.comp_unit` is valid? - if (!sc.comp_unit) - return lldb::eLanguageTypeUnknown; - - auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); +lldb::LanguageType SymbolFilePDB::ParseLanguage(CompileUnit &comp_unit) { + auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID()); if (!compiland_up) return lldb::eLanguageTypeUnknown; auto details = compiland_up->findOneChild<PDBSymbolCompilandDetails>(); @@ -262,9 +277,11 @@ SymbolFilePDB::ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) { return TranslateLanguage(details->getLanguage()); } -lldb_private::Function *SymbolFilePDB::ParseCompileUnitFunctionForPDBFunc( - const PDBSymbolFunc &pdb_func, const lldb_private::SymbolContext &sc) { - lldbassert(sc.comp_unit && sc.module_sp.get()); +lldb_private::Function * +SymbolFilePDB::ParseCompileUnitFunctionForPDBFunc(const PDBSymbolFunc &pdb_func, + CompileUnit &comp_unit) { + if (FunctionSP result = comp_unit.FindFunctionByUID(pdb_func.getSymIndexId())) + return result.get(); auto file_vm_addr = pdb_func.getVirtualAddress(); if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0) @@ -272,7 +289,8 @@ lldb_private::Function *SymbolFilePDB::ParseCompileUnitFunctionForPDBFunc( auto func_length = pdb_func.getLength(); AddressRange func_range = - AddressRange(file_vm_addr, func_length, sc.module_sp->GetSectionList()); + AddressRange(file_vm_addr, func_length, + GetObjectFile()->GetModule()->GetSectionList()); if (!func_range.GetBaseAddress().IsValid()) return nullptr; @@ -285,59 +303,61 @@ lldb_private::Function *SymbolFilePDB::ParseCompileUnitFunctionForPDBFunc( Mangled mangled = GetMangledForPDBFunc(pdb_func); FunctionSP func_sp = - std::make_shared<Function>(sc.comp_unit, pdb_func.getSymIndexId(), + std::make_shared<Function>(&comp_unit, pdb_func.getSymIndexId(), func_type_uid, mangled, func_type, func_range); - sc.comp_unit->AddFunction(func_sp); + comp_unit.AddFunction(func_sp); + + TypeSystem *type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + if (!type_system) + return nullptr; + ClangASTContext *clang_type_system = + llvm::dyn_cast_or_null<ClangASTContext>(type_system); + if (!clang_type_system) + return nullptr; + clang_type_system->GetPDBParser()->GetDeclForSymbol(pdb_func); + return func_sp.get(); } -size_t SymbolFilePDB::ParseCompileUnitFunctions( - const lldb_private::SymbolContext &sc) { - lldbassert(sc.comp_unit); +size_t SymbolFilePDB::ParseFunctions(CompileUnit &comp_unit) { size_t func_added = 0; - auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); + auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID()); if (!compiland_up) return 0; auto results_up = compiland_up->findAllChildren<PDBSymbolFunc>(); if (!results_up) return 0; while (auto pdb_func_up = results_up->getNext()) { - auto func_sp = - sc.comp_unit->FindFunctionByUID(pdb_func_up->getSymIndexId()); + auto func_sp = comp_unit.FindFunctionByUID(pdb_func_up->getSymIndexId()); if (!func_sp) { - if (ParseCompileUnitFunctionForPDBFunc(*pdb_func_up, sc)) + if (ParseCompileUnitFunctionForPDBFunc(*pdb_func_up, comp_unit)) ++func_added; } } return func_added; } -bool SymbolFilePDB::ParseCompileUnitLineTable( - const lldb_private::SymbolContext &sc) { - lldbassert(sc.comp_unit); - if (sc.comp_unit->GetLineTable()) +bool SymbolFilePDB::ParseLineTable(CompileUnit &comp_unit) { + if (comp_unit.GetLineTable()) return true; - return ParseCompileUnitLineTable(sc, 0); + return ParseCompileUnitLineTable(comp_unit, 0); } -bool SymbolFilePDB::ParseCompileUnitDebugMacros( - const lldb_private::SymbolContext &sc) { +bool SymbolFilePDB::ParseDebugMacros(CompileUnit &comp_unit) { // PDB doesn't contain information about macros return false; } -bool SymbolFilePDB::ParseCompileUnitSupportFiles( - const lldb_private::SymbolContext &sc, - lldb_private::FileSpecList &support_files) { - lldbassert(sc.comp_unit); +bool SymbolFilePDB::ParseSupportFiles( + CompileUnit &comp_unit, lldb_private::FileSpecList &support_files) { // In theory this is unnecessary work for us, because all of this information // is easily (and quickly) accessible from DebugInfoPDB, so caching it a // second time seems like a waste. Unfortunately, there's no good way around // this short of a moderate refactor since SymbolVendor depends on being able // to cache this list. - auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); + auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID()); if (!compiland_up) return false; auto files = m_session_up->getSourceFilesForCompiland(*compiland_up); @@ -345,13 +365,13 @@ bool SymbolFilePDB::ParseCompileUnitSupportFiles( return false; while (auto file = files->getNext()) { - FileSpec spec(file->getFileName(), false, FileSpec::Style::windows); + FileSpec spec(file->getFileName(), FileSpec::Style::windows); support_files.AppendIfUnique(spec); } // LLDB uses the DWARF-like file numeration (one based), // the zeroth file is the compile unit itself - support_files.Insert(0, *sc.comp_unit); + support_files.Insert(0, comp_unit); return true; } @@ -364,9 +384,8 @@ bool SymbolFilePDB::ParseImportedModules( } static size_t ParseFunctionBlocksForPDBSymbol( - const lldb_private::SymbolContext &sc, uint64_t func_file_vm_addr, - const llvm::pdb::PDBSymbol *pdb_symbol, lldb_private::Block *parent_block, - bool is_top_parent) { + uint64_t func_file_vm_addr, const llvm::pdb::PDBSymbol *pdb_symbol, + lldb_private::Block *parent_block, bool is_top_parent) { assert(pdb_symbol && parent_block); size_t num_added = 0; @@ -405,7 +424,7 @@ static size_t ParseFunctionBlocksForPDBSymbol( break; while (auto symbol_up = results_up->getNext()) { num_added += ParseFunctionBlocksForPDBSymbol( - sc, func_file_vm_addr, symbol_up.get(), block, false); + func_file_vm_addr, symbol_up.get(), block, false); } } break; default: @@ -414,28 +433,22 @@ static size_t ParseFunctionBlocksForPDBSymbol( return num_added; } -size_t -SymbolFilePDB::ParseFunctionBlocks(const lldb_private::SymbolContext &sc) { - lldbassert(sc.comp_unit && sc.function); +size_t SymbolFilePDB::ParseBlocksRecursive(Function &func) { size_t num_added = 0; - auto uid = sc.function->GetID(); + auto uid = func.GetID(); auto pdb_func_up = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(uid); if (!pdb_func_up) return 0; - Block &parent_block = sc.function->GetBlock(false); - num_added = - ParseFunctionBlocksForPDBSymbol(sc, pdb_func_up->getVirtualAddress(), - pdb_func_up.get(), &parent_block, true); + Block &parent_block = func.GetBlock(false); + num_added = ParseFunctionBlocksForPDBSymbol( + pdb_func_up->getVirtualAddress(), pdb_func_up.get(), &parent_block, true); return num_added; } -size_t SymbolFilePDB::ParseTypes(const lldb_private::SymbolContext &sc) { - lldbassert(sc.module_sp.get()); - if (!sc.comp_unit) - return 0; +size_t SymbolFilePDB::ParseTypes(CompileUnit &comp_unit) { size_t num_added = 0; - auto compiland = GetPDBCompilandByUID(sc.comp_unit->GetID()); + auto compiland = GetPDBCompilandByUID(comp_unit.GetID()); if (!compiland) return 0; @@ -459,31 +472,26 @@ size_t SymbolFilePDB::ParseTypes(const lldb_private::SymbolContext &sc) { // This should cause the type to get cached and stored in the `m_types` // lookup. - if (!ResolveTypeUID(symbol->getSymIndexId())) - continue; - - ++num_added; + if (auto type = ResolveTypeUID(symbol->getSymIndexId())) { + // Resolve the type completely to avoid a completion + // (and so a list change, which causes an iterators invalidation) + // during a TypeList dumping + type->GetFullCompilerType(); + ++num_added; + } } } }; - if (sc.function) { - auto pdb_func = m_session_up->getConcreteSymbolById<PDBSymbolFunc>( - sc.function->GetID()); - if (!pdb_func) - return 0; - ParseTypesByTagFn(*pdb_func); - } else { - ParseTypesByTagFn(*compiland); - - // Also parse global types particularly coming from this compiland. - // Unfortunately, PDB has no compiland information for each global type. We - // have to parse them all. But ensure we only do this once. - static bool parse_all_global_types = false; - if (!parse_all_global_types) { - ParseTypesByTagFn(*m_global_scope_up); - parse_all_global_types = true; - } + ParseTypesByTagFn(*compiland); + + // Also parse global types particularly coming from this compiland. + // Unfortunately, PDB has no compiland information for each global type. We + // have to parse them all. But ensure we only do this once. + static bool parse_all_global_types = false; + if (!parse_all_global_types) { + ParseTypesByTagFn(*m_global_scope_up); + parse_all_global_types = true; } return num_added; } @@ -513,7 +521,7 @@ SymbolFilePDB::ParseVariablesForContext(const lldb_private::SymbolContext &sc) { auto results = m_global_scope_up->findAllChildren<PDBSymbolData>(); if (results && results->getChildCount()) { while (auto result = results->getNext()) { - auto cu_id = result->getCompilandId(); + auto cu_id = GetCompilandId(*result); // FIXME: We are not able to determine variable's compile unit. if (cu_id == 0) continue; @@ -548,8 +556,7 @@ lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) { llvm::dyn_cast_or_null<ClangASTContext>(type_system); if (!clang_type_system) return nullptr; - PDBASTParser *pdb = - llvm::dyn_cast<PDBASTParser>(clang_type_system->GetPDBParser()); + PDBASTParser *pdb = clang_type_system->GetPDBParser(); if (!pdb) return nullptr; @@ -567,34 +574,109 @@ lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) { return result.get(); } +llvm::Optional<SymbolFile::ArrayInfo> SymbolFilePDB::GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) { + return llvm::None; +} + bool SymbolFilePDB::CompleteType(lldb_private::CompilerType &compiler_type) { - // TODO: Implement this - return false; + std::lock_guard<std::recursive_mutex> guard( + GetObjectFile()->GetModule()->GetMutex()); + + ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>( + GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return false; + + PDBASTParser *pdb = clang_ast_ctx->GetPDBParser(); + if (!pdb) + return false; + + return pdb->CompleteTypeFromPDB(compiler_type); } lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) { - return lldb_private::CompilerDecl(); + ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>( + GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return CompilerDecl(); + + PDBASTParser *pdb = clang_ast_ctx->GetPDBParser(); + if (!pdb) + return CompilerDecl(); + + auto symbol = m_session_up->getSymbolById(uid); + if (!symbol) + return CompilerDecl(); + + auto decl = pdb->GetDeclForSymbol(*symbol); + if (!decl) + return CompilerDecl(); + + return CompilerDecl(clang_ast_ctx, decl); } lldb_private::CompilerDeclContext SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) { - // PDB always uses the translation unit decl context for everything. We can - // improve this later but it's not easy because PDB doesn't provide a high - // enough level of type fidelity in this area. - return *m_tu_decl_ctx_up; + ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>( + GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return CompilerDeclContext(); + + PDBASTParser *pdb = clang_ast_ctx->GetPDBParser(); + if (!pdb) + return CompilerDeclContext(); + + auto symbol = m_session_up->getSymbolById(uid); + if (!symbol) + return CompilerDeclContext(); + + auto decl_context = pdb->GetDeclContextForSymbol(*symbol); + if (!decl_context) + return GetDeclContextContainingUID(uid); + + return CompilerDeclContext(clang_ast_ctx, decl_context); } lldb_private::CompilerDeclContext SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid) { - return *m_tu_decl_ctx_up; + ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>( + GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return CompilerDeclContext(); + + PDBASTParser *pdb = clang_ast_ctx->GetPDBParser(); + if (!pdb) + return CompilerDeclContext(); + + auto symbol = m_session_up->getSymbolById(uid); + if (!symbol) + return CompilerDeclContext(); + + auto decl_context = pdb->GetDeclContextContainingSymbol(*symbol); + assert(decl_context); + + return CompilerDeclContext(clang_ast_ctx, decl_context); } void SymbolFilePDB::ParseDeclsForContext( - lldb_private::CompilerDeclContext decl_ctx) {} + lldb_private::CompilerDeclContext decl_ctx) { + ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>( + GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return; + + PDBASTParser *pdb = clang_ast_ctx->GetPDBParser(); + if (!pdb) + return; + + pdb->ParseDeclsForDeclContext( + static_cast<clang::DeclContext *>(decl_ctx.GetOpaqueDeclContext())); +} uint32_t SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr, - uint32_t resolve_scope, + SymbolContextItem resolve_scope, lldb_private::SymbolContext &sc) { uint32_t resolved_flags = 0; if (resolve_scope & eSymbolContextCompUnit || @@ -614,7 +696,8 @@ SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr, lldbassert(sc.module_sp == cu_sp->GetModule()); } - if (resolve_scope & eSymbolContextFunction) { + if (resolve_scope & eSymbolContextFunction || + resolve_scope & eSymbolContextBlock) { addr_t file_vm_addr = so_addr.GetFileAddress(); auto symbol_up = m_session_up->findSymbolByAddress(file_vm_addr, PDB_SymType::Function); @@ -624,12 +707,16 @@ SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr, auto func_uid = pdb_func->getSymIndexId(); sc.function = sc.comp_unit->FindFunctionByUID(func_uid).get(); if (sc.function == nullptr) - sc.function = ParseCompileUnitFunctionForPDBFunc(*pdb_func, sc); + sc.function = + ParseCompileUnitFunctionForPDBFunc(*pdb_func, *sc.comp_unit); if (sc.function) { resolved_flags |= eSymbolContextFunction; if (resolve_scope & eSymbolContextBlock) { - Block &block = sc.function->GetBlock(true); - sc.block = block.FindBlockByID(sc.function->GetID()); + auto block_symbol = m_session_up->findSymbolByAddress( + file_vm_addr, PDB_SymType::Block); + auto block_id = block_symbol ? block_symbol->getSymIndexId() + : sc.function->GetID(); + sc.block = sc.function->GetBlock(true).FindBlockByID(block_id); if (sc.block) resolved_flags |= eSymbolContextBlock; } @@ -650,7 +737,7 @@ SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr, uint32_t SymbolFilePDB::ResolveSymbolContext( const lldb_private::FileSpec &file_spec, uint32_t line, bool check_inlines, - uint32_t resolve_scope, lldb_private::SymbolContextList &sc_list) { + SymbolContextItem resolve_scope, lldb_private::SymbolContextList &sc_list) { const size_t old_size = sc_list.GetSize(); if (resolve_scope & lldb::eSymbolContextCompUnit) { // Locate all compilation units with line numbers referencing the specified @@ -674,7 +761,7 @@ uint32_t SymbolFilePDB::ResolveSymbolContext( std::string source_file = compiland->getSourceFileFullPath(); if (source_file.empty()) continue; - FileSpec this_spec(source_file, false, FileSpec::Style::windows); + FileSpec this_spec(source_file, FileSpec::Style::windows); bool need_full_match = !file_spec.GetDirectory().IsEmpty(); if (FileSpec::Compare(file_spec, this_spec, need_full_match) != 0) continue; @@ -691,7 +778,7 @@ uint32_t SymbolFilePDB::ResolveSymbolContext( // table that match the requested line (or all lines if `line` == 0). if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock | eSymbolContextLineEntry)) { - bool has_line_table = ParseCompileUnitLineTable(sc, line); + bool has_line_table = ParseCompileUnitLineTable(*sc.comp_unit, line); if ((resolve_scope & eSymbolContextLineEntry) && !has_line_table) { // The query asks for line entries, but we can't get them for the @@ -734,7 +821,8 @@ uint32_t SymbolFilePDB::ResolveSymbolContext( if (sc.function == nullptr) { auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(symbol_up.get()); assert(pdb_func); - sc.function = ParseCompileUnitFunctionForPDBFunc(*pdb_func, sc); + sc.function = ParseCompileUnitFunctionForPDBFunc(*pdb_func, + *sc.comp_unit); } if (sc.function && (resolve_scope & eSymbolContextBlock)) { Block &block = sc.function->GetBlock(true); @@ -759,24 +847,16 @@ uint32_t SymbolFilePDB::ResolveSymbolContext( } std::string SymbolFilePDB::GetMangledForPDBData(const PDBSymbolData &pdb_data) { - std::string decorated_name; - auto vm_addr = pdb_data.getVirtualAddress(); - if (vm_addr != LLDB_INVALID_ADDRESS && vm_addr) { - auto result_up = - m_global_scope_up->findAllChildren(PDB_SymType::PublicSymbol); - if (result_up) { - while (auto symbol_up = result_up->getNext()) { - if (symbol_up->getRawSymbol().getVirtualAddress() == vm_addr) { - decorated_name = symbol_up->getRawSymbol().getName(); - break; - } - } - } - } - if (!decorated_name.empty()) - return decorated_name; - - return std::string(); + // Cache public names at first + if (m_public_names.empty()) + if (auto result_up = + m_global_scope_up->findAllChildren(PDB_SymType::PublicSymbol)) + while (auto symbol_up = result_up->getNext()) + if (auto addr = symbol_up->getRawSymbol().getVirtualAddress()) + m_public_names[addr] = symbol_up->getRawSymbol().getName(); + + // Look up the name in the cache + return m_public_names.lookup(pdb_data.getVirtualAddress()); } VariableSP SymbolFilePDB::ParseVariableForPDBData( @@ -843,7 +923,7 @@ VariableSP SymbolFilePDB::ParseVariableForPDBData( uint32_t src_file_id = first_line->getSourceFileId(); auto src_file = m_session_up->getSourceFileById(src_file_id); if (src_file) { - FileSpec spec(src_file->getFileName(), /*resolve_path*/ false); + FileSpec spec(src_file->getFileName()); decl.SetFile(spec); decl.SetColumn(first_line->getColumnNumber()); decl.SetLine(first_line->getLineNumber()); @@ -857,7 +937,7 @@ VariableSP SymbolFilePDB::ParseVariableForPDBData( if (scope == eValueTypeVariableLocal) { if (sc.function) { context_scope = sc.function->GetBlock(true).FindBlockByID( - pdb_data.getClassParentId()); + pdb_data.getLexicalParentId()); if (context_scope == nullptr) context_scope = sc.function; } @@ -937,6 +1017,9 @@ SymbolFilePDB::ParseVariables(const lldb_private::SymbolContext &sc, if (variable_list) variable_list->AddVariableIfUnique(var_sp); ++num_added; + PDBASTParser *ast = GetPDBAstParser(); + if (ast) + ast->GetDeclForSymbol(*pdb_data); } } } @@ -959,9 +1042,7 @@ uint32_t SymbolFilePDB::FindGlobalVariables( if (name.IsEmpty()) return 0; - auto results = - m_global_scope_up->findChildren(PDB_SymType::Data, name.GetStringRef(), - PDB_NameSearchFlags::NS_CaseSensitive); + auto results = m_global_scope_up->findAllChildren<PDBSymbolData>(); if (!results) return 0; @@ -976,11 +1057,19 @@ uint32_t SymbolFilePDB::FindGlobalVariables( sc.module_sp = m_obj_file->GetModule(); lldbassert(sc.module_sp.get()); - sc.comp_unit = ParseCompileUnitForUID(pdb_data->getCompilandId()).get(); + if (!name.GetStringRef().equals( + MSVCUndecoratedNameParser::DropScope(pdb_data->getName()))) + continue; + + sc.comp_unit = ParseCompileUnitForUID(GetCompilandId(*pdb_data)).get(); // FIXME: We are not able to determine the compile unit. if (sc.comp_unit == nullptr) continue; + if (parent_decl_ctx && GetDeclContextContainingUID( + result->getSymIndexId()) != *parent_decl_ctx) + continue; + ParseVariables(sc, *pdb_data, &variables); matches = variables.GetSize() - old_size; } @@ -1013,7 +1102,7 @@ SymbolFilePDB::FindGlobalVariables(const lldb_private::RegularExpression ®ex, sc.module_sp = m_obj_file->GetModule(); lldbassert(sc.module_sp.get()); - sc.comp_unit = ParseCompileUnitForUID(pdb_data->getCompilandId()).get(); + sc.comp_unit = ParseCompileUnitForUID(GetCompilandId(*pdb_data)).get(); // FIXME: We are not able to determine the compile unit. if (sc.comp_unit == nullptr) continue; @@ -1033,7 +1122,7 @@ bool SymbolFilePDB::ResolveFunction(const llvm::pdb::PDBSymbolFunc &pdb_func, if (!sc.comp_unit) return false; sc.module_sp = sc.comp_unit->GetModule(); - sc.function = ParseCompileUnitFunctionForPDBFunc(pdb_func, sc); + sc.function = ParseCompileUnitFunctionForPDBFunc(pdb_func, *sc.comp_unit); if (!sc.function) return false; @@ -1075,22 +1164,11 @@ void SymbolFilePDB::CacheFunctionNames() { // Class. We won't bother to check if the parent is UDT or Enum here. m_func_method_names.Append(ConstString(name), uid); - ConstString cstr_name(name); - // 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 // by our own effort. - llvm::StringRef basename; - CPlusPlusLanguage::MethodName cpp_method(cstr_name); - if (cpp_method.IsValid()) { - llvm::StringRef context; - basename = cpp_method.GetBasename(); - if (basename.empty()) - CPlusPlusLanguage::ExtractContextAndIdentifier(name.c_str(), - context, basename); - } - + llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(name); if (!basename.empty()) m_func_base_names.Append(ConstString(basename), uid); else { @@ -1103,11 +1181,12 @@ void SymbolFilePDB::CacheFunctionNames() { } else { // Handle not-method symbols. - // The function name might contain namespace, or its lexical scope. It - // is not safe to get its base name by applying same scheme as we deal - // with the method names. - // FIXME: Remove namespace if function is static in a scope. - m_func_base_names.Append(ConstString(name), uid); + // The function name might contain namespace, or its lexical scope. + llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(name); + if (!basename.empty()) + m_func_base_names.Append(ConstString(basename), uid); + else + m_func_base_names.Append(ConstString(name), uid); if (name == "main") { m_func_full_names.Append(ConstString(name), uid); @@ -1157,7 +1236,7 @@ void SymbolFilePDB::CacheFunctionNames() { uint32_t SymbolFilePDB::FindFunctions( const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, - uint32_t name_type_mask, bool include_inlines, bool append, + FunctionNameType name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList &sc_list) { if (!append) sc_list.Clear(); @@ -1177,20 +1256,28 @@ uint32_t SymbolFilePDB::FindFunctions( CacheFunctionNames(); std::set<uint32_t> resolved_ids; - auto ResolveFn = [include_inlines, &name, &sc_list, &resolved_ids, - this](UniqueCStringMap<uint32_t> &Names) { + auto ResolveFn = [this, &name, parent_decl_ctx, include_inlines, &sc_list, + &resolved_ids](UniqueCStringMap<uint32_t> &Names) { std::vector<uint32_t> ids; - if (Names.GetValues(name, ids)) { - for (auto id : ids) { - if (resolved_ids.find(id) == resolved_ids.end()) { - if (ResolveFunction(id, include_inlines, sc_list)) - resolved_ids.insert(id); - } - } + if (!Names.GetValues(name, ids)) + return; + + for (uint32_t id : ids) { + if (resolved_ids.find(id) != resolved_ids.end()) + continue; + + if (parent_decl_ctx && + GetDeclContextContainingUID(id) != *parent_decl_ctx) + continue; + + if (ResolveFunction(id, include_inlines, sc_list)) + resolved_ids.insert(id); } }; if (name_type_mask & eFunctionNameTypeFull) { ResolveFn(m_func_full_names); + ResolveFn(m_func_base_names); + ResolveFn(m_func_method_names); } if (name_type_mask & eFunctionNameTypeBase) { ResolveFn(m_func_base_names); @@ -1236,8 +1323,59 @@ void SymbolFilePDB::GetMangledNamesForFunction( const std::string &scope_qualified_name, std::vector<lldb_private::ConstString> &mangled_names) {} +void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) { + std::set<lldb::addr_t> sym_addresses; + for (size_t i = 0; i < symtab.GetNumSymbols(); i++) + sym_addresses.insert(symtab.SymbolAtIndex(i)->GetFileAddress()); + + auto results = m_global_scope_up->findAllChildren<PDBSymbolPublicSymbol>(); + if (!results) + return; + + auto section_list = m_obj_file->GetSectionList(); + if (!section_list) + return; + + while (auto pub_symbol = results->getNext()) { + auto section_idx = pub_symbol->getAddressSection() - 1; + if (section_idx >= section_list->GetSize()) + continue; + + auto section = section_list->GetSectionAtIndex(section_idx); + if (!section) + continue; + + auto offset = pub_symbol->getAddressOffset(); + + auto file_addr = section->GetFileAddress() + offset; + if (sym_addresses.find(file_addr) != sym_addresses.end()) + continue; + sym_addresses.insert(file_addr); + + auto size = pub_symbol->getLength(); + symtab.AddSymbol( + Symbol(pub_symbol->getSymIndexId(), // symID + pub_symbol->getName().c_str(), // name + true, // name_is_mangled + pub_symbol->isCode() ? eSymbolTypeCode : eSymbolTypeData, // type + true, // external + false, // is_debug + false, // is_trampoline + false, // is_artificial + section, // section_sp + offset, // value + size, // size + size != 0, // size_is_valid + false, // contains_linker_annotations + 0 // flags + )); + } + + symtab.CalculateSymbolSizes(); + symtab.Finalize(); +} + uint32_t SymbolFilePDB::FindTypes( - const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, @@ -1253,14 +1391,20 @@ uint32_t SymbolFilePDB::FindTypes( searched_symbol_files.clear(); searched_symbol_files.insert(this); - std::string name_str = name.AsCString(); - // There is an assumption 'name' is not a regex - FindTypesByName(name_str, max_matches, types); + FindTypesByName(name.GetStringRef(), parent_decl_ctx, max_matches, types); return types.GetSize(); } +void SymbolFilePDB::DumpClangAST(Stream &s) { + auto type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + auto clang = llvm::dyn_cast_or_null<ClangASTContext>(type_system); + if (!clang) + return; + clang->Dump(s); +} + void SymbolFilePDB::FindTypesByRegex( const lldb_private::RegularExpression ®ex, uint32_t max_matches, lldb_private::TypeMap &types) { @@ -1316,14 +1460,14 @@ void SymbolFilePDB::FindTypesByRegex( } } -void SymbolFilePDB::FindTypesByName(const std::string &name, - uint32_t max_matches, - lldb_private::TypeMap &types) { +void SymbolFilePDB::FindTypesByName( + llvm::StringRef name, + const lldb_private::CompilerDeclContext *parent_decl_ctx, + uint32_t max_matches, lldb_private::TypeMap &types) { std::unique_ptr<IPDBEnumSymbols> results; if (name.empty()) return; - results = m_global_scope_up->findChildren(PDB_SymType::None, name, - PDB_NameSearchFlags::NS_Default); + results = m_global_scope_up->findAllChildren(PDB_SymType::None); if (!results) return; @@ -1332,6 +1476,11 @@ void SymbolFilePDB::FindTypesByName(const std::string &name, while (auto result = results->getNext()) { if (max_matches > 0 && matches >= max_matches) break; + + if (MSVCUndecoratedNameParser::DropScope( + result->getRawSymbol().getName()) != name) + continue; + switch (result->getSymTag()) { case PDB_SymType::Enum: case PDB_SymType::UDT: @@ -1348,6 +1497,10 @@ void SymbolFilePDB::FindTypesByName(const std::string &name, if (!ResolveTypeUID(result->getSymIndexId())) continue; + if (parent_decl_ctx && GetDeclContextContainingUID( + result->getSymIndexId()) != *parent_decl_ctx) + continue; + auto iter = m_types.find(result->getSymIndexId()); if (iter == m_types.end()) continue; @@ -1417,7 +1570,7 @@ void SymbolFilePDB::GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol, } size_t SymbolFilePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope, - uint32_t type_mask, + TypeClass type_mask, lldb_private::TypeList &type_list) { TypeCollection type_collection; uint32_t old_size = type_list.GetSize(); @@ -1454,11 +1607,40 @@ SymbolFilePDB::GetTypeSystemForLanguage(lldb::LanguageType language) { return type_system; } +PDBASTParser *SymbolFilePDB::GetPDBAstParser() { + auto type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + auto clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system); + if (!clang_type_system) + return nullptr; + + return clang_type_system->GetPDBParser(); +} + + lldb_private::CompilerDeclContext SymbolFilePDB::FindNamespace( - const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx) { - return lldb_private::CompilerDeclContext(); + auto type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + auto clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system); + if (!clang_type_system) + return CompilerDeclContext(); + + PDBASTParser *pdb = clang_type_system->GetPDBParser(); + if (!pdb) + return CompilerDeclContext(); + + clang::DeclContext *decl_context = nullptr; + if (parent_decl_ctx) + decl_context = static_cast<clang::DeclContext *>( + parent_decl_ctx->GetOpaqueDeclContext()); + + auto namespace_decl = + pdb->FindNamespaceDecl(decl_context, name.GetStringRef()); + if (!namespace_decl) + return CompilerDeclContext(); + + return CompilerDeclContext(type_system, + static_cast<clang::DeclContext *>(namespace_decl)); } lldb_private::ConstString SymbolFilePDB::GetPluginName() { @@ -1516,11 +1698,9 @@ lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitForUID(uint32_t id, return cu_sp; } -bool SymbolFilePDB::ParseCompileUnitLineTable( - const lldb_private::SymbolContext &sc, uint32_t match_line) { - lldbassert(sc.comp_unit); - - auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); +bool SymbolFilePDB::ParseCompileUnitLineTable(CompileUnit &comp_unit, + uint32_t match_line) { + auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID()); if (!compiland_up) return false; @@ -1530,10 +1710,10 @@ bool SymbolFilePDB::ParseCompileUnitLineTable( // to do a mapping so that we can hand out indices. llvm::DenseMap<uint32_t, uint32_t> index_map; BuildSupportFileIdToSupportFileIndexMap(*compiland_up, index_map); - auto line_table = llvm::make_unique<LineTable>(sc.comp_unit); + auto line_table = llvm::make_unique<LineTable>(&comp_unit); // Find contributions to `compiland` from all source and header files. - std::string path = sc.comp_unit->GetPath(); + std::string path = comp_unit.GetPath(); auto files = m_session_up->getSourceFilesForCompiland(*compiland_up); if (!files) return false; @@ -1617,7 +1797,7 @@ bool SymbolFilePDB::ParseCompileUnitLineTable( } if (line_table->GetSize()) { - sc.comp_unit->SetLineTable(line_table.release()); + comp_unit.SetLineTable(line_table.release()); return true; } return false; @@ -1747,3 +1927,68 @@ bool SymbolFilePDB::DeclContextMatchesThisSymbolFile( return false; } + +uint32_t SymbolFilePDB::GetCompilandId(const llvm::pdb::PDBSymbolData &data) { + static const auto pred_upper = [](uint32_t lhs, SecContribInfo rhs) { + return lhs < rhs.Offset; + }; + + // Cache section contributions + if (m_sec_contribs.empty()) { + if (auto SecContribs = m_session_up->getSectionContribs()) { + while (auto SectionContrib = SecContribs->getNext()) { + auto comp_id = SectionContrib->getCompilandId(); + if (!comp_id) + continue; + + auto sec = SectionContrib->getAddressSection(); + auto &sec_cs = m_sec_contribs[sec]; + + auto offset = SectionContrib->getAddressOffset(); + auto it = + std::upper_bound(sec_cs.begin(), sec_cs.end(), offset, pred_upper); + + auto size = SectionContrib->getLength(); + sec_cs.insert(it, {offset, size, comp_id}); + } + } + } + + // Check by line number + if (auto Lines = data.getLineNumbers()) { + if (auto FirstLine = Lines->getNext()) + return FirstLine->getCompilandId(); + } + + // Retrieve section + offset + uint32_t DataSection = data.getAddressSection(); + uint32_t DataOffset = data.getAddressOffset(); + if (DataSection == 0) { + if (auto RVA = data.getRelativeVirtualAddress()) + m_session_up->addressForRVA(RVA, DataSection, DataOffset); + } + + if (DataSection) { + // Search by section contributions + auto &sec_cs = m_sec_contribs[DataSection]; + auto it = + std::upper_bound(sec_cs.begin(), sec_cs.end(), DataOffset, pred_upper); + if (it != sec_cs.begin()) { + --it; + if (DataOffset < it->Offset + it->Size) + return it->CompilandId; + } + } else { + // Search in lexical tree + auto LexParentId = data.getLexicalParentId(); + while (auto LexParent = m_session_up->getSymbolById(LexParentId)) { + if (LexParent->getSymTag() == PDB_SymType::Exe) + break; + if (LexParent->getSymTag() == PDB_SymType::Compiland) + return LexParentId; + LexParentId = LexParent->getRawSymbol().getLexicalParentId(); + } + } + + return 0; +} diff --git a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h index 96b62d68a6c2..81288093b7d8 100644 --- a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -20,6 +20,8 @@ #include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +class PDBASTParser; + class SymbolFilePDB : public lldb_private::SymbolFile { public: //------------------------------------------------------------------ @@ -58,33 +60,32 @@ public: lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; lldb::LanguageType - ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) override; + ParseLanguage(lldb_private::CompileUnit &comp_unit) override; - size_t - ParseCompileUnitFunctions(const lldb_private::SymbolContext &sc) override; + size_t ParseFunctions(lldb_private::CompileUnit &comp_unit) override; - bool - ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc) override; + bool ParseLineTable(lldb_private::CompileUnit &comp_unit) override; - bool - ParseCompileUnitDebugMacros(const lldb_private::SymbolContext &sc) override; + bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; - bool ParseCompileUnitSupportFiles( - const lldb_private::SymbolContext &sc, - lldb_private::FileSpecList &support_files) override; + bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, + lldb_private::FileSpecList &support_files) override; + + size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override; bool ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules) override; - size_t ParseFunctionBlocks(const lldb_private::SymbolContext &sc) override; - - size_t ParseTypes(const lldb_private::SymbolContext &sc) override; + size_t ParseBlocksRecursive(lldb_private::Function &func) override; size_t ParseVariablesForContext(const lldb_private::SymbolContext &sc) override; lldb_private::Type *ResolveTypeUID(lldb::user_id_t type_uid) override; + llvm::Optional<ArrayInfo> GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, + const lldb_private::ExecutionContext *exe_ctx) override; bool CompleteType(lldb_private::CompilerType &compiler_type) override; @@ -100,12 +101,13 @@ public: ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override; uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr, - uint32_t resolve_scope, + lldb::SymbolContextItem resolve_scope, lldb_private::SymbolContext &sc) override; uint32_t ResolveSymbolContext(const lldb_private::FileSpec &file_spec, uint32_t line, - bool check_inlines, uint32_t resolve_scope, + bool check_inlines, + lldb::SymbolContextItem resolve_scope, lldb_private::SymbolContextList &sc_list) override; uint32_t @@ -121,8 +123,8 @@ public: uint32_t FindFunctions(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, - uint32_t name_type_mask, bool include_inlines, bool append, - lldb_private::SymbolContextList &sc_list) override; + lldb::FunctionNameType name_type_mask, bool include_inlines, + bool append, lldb_private::SymbolContextList &sc_list) override; uint32_t FindFunctions(const lldb_private::RegularExpression ®ex, bool include_inlines, bool append, @@ -132,9 +134,10 @@ public: const std::string &scope_qualified_name, std::vector<lldb_private::ConstString> &mangled_names) override; + void AddSymbols(lldb_private::Symtab &symtab) override; + uint32_t - FindTypes(const lldb_private::SymbolContext &sc, - const lldb_private::ConstString &name, + FindTypes(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, @@ -149,14 +152,13 @@ public: lldb_private::TypeList *GetTypeList() override; size_t GetTypes(lldb_private::SymbolContextScope *sc_scope, - uint32_t type_mask, + lldb::TypeClass type_mask, lldb_private::TypeList &type_list) override; lldb_private::TypeSystem * GetTypeSystemForLanguage(lldb::LanguageType language) override; lldb_private::CompilerDeclContext FindNamespace( - const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx) override; @@ -168,19 +170,29 @@ public: const llvm::pdb::IPDBSession &GetPDBSession() const; + void DumpClangAST(lldb_private::Stream &s) override; + private: + struct SecContribInfo { + uint32_t Offset; + uint32_t Size; + uint32_t CompilandId; + }; + using SecContribsMap = std::map<uint32_t, std::vector<SecContribInfo>>; + lldb::CompUnitSP ParseCompileUnitForUID(uint32_t id, uint32_t index = UINT32_MAX); - bool ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc, + bool ParseCompileUnitLineTable(lldb_private::CompileUnit &comp_unit, uint32_t match_line); void BuildSupportFileIdToSupportFileIndexMap( const llvm::pdb::PDBSymbolCompiland &pdb_compiland, llvm::DenseMap<uint32_t, uint32_t> &index_map) const; - void FindTypesByName(const std::string &name, uint32_t max_matches, - lldb_private::TypeMap &types); + void FindTypesByName(llvm::StringRef name, + const lldb_private::CompilerDeclContext *parent_decl_ctx, + uint32_t max_matches, lldb_private::TypeMap &types); std::string GetMangledForPDBData(const llvm::pdb::PDBSymbolData &pdb_data); @@ -203,11 +215,13 @@ private: lldb_private::Function * ParseCompileUnitFunctionForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func, - const lldb_private::SymbolContext &sc); + lldb_private::CompileUnit &comp_unit); void GetCompileUnitIndex(const llvm::pdb::PDBSymbolCompiland &pdb_compiland, uint32_t &index); + PDBASTParser *GetPDBAstParser(); + std::unique_ptr<llvm::pdb::PDBSymbolCompiland> GetPDBCompilandByUID(uint32_t uid); @@ -226,9 +240,14 @@ private: bool DeclContextMatchesThisSymbolFile( const lldb_private::CompilerDeclContext *decl_ctx); + uint32_t GetCompilandId(const llvm::pdb::PDBSymbolData &data); + llvm::DenseMap<uint32_t, lldb::CompUnitSP> m_comp_units; llvm::DenseMap<uint32_t, lldb::TypeSP> m_types; llvm::DenseMap<uint32_t, lldb::VariableSP> m_variables; + llvm::DenseMap<uint64_t, std::string> m_public_names; + + SecContribsMap m_sec_contribs; std::vector<lldb::TypeSP> m_builtin_types; std::unique_ptr<llvm::pdb::IPDBSession> m_session_up; diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index 64e2daf60ee5..08778bd1ba70 100644 --- a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -46,7 +46,7 @@ SymbolFile *SymbolFileSymtab::CreateInstance(ObjectFile *obj_file) { } size_t SymbolFileSymtab::GetTypes(SymbolContextScope *sc_scope, - uint32_t type_mask, + TypeClass type_mask, lldb_private::TypeList &type_list) { return 0; } @@ -131,15 +131,13 @@ CompUnitSP SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx) { return cu_sp; } -lldb::LanguageType -SymbolFileSymtab::ParseCompileUnitLanguage(const SymbolContext &sc) { +lldb::LanguageType SymbolFileSymtab::ParseLanguage(CompileUnit &comp_unit) { return eLanguageTypeUnknown; } -size_t SymbolFileSymtab::ParseCompileUnitFunctions(const SymbolContext &sc) { +size_t SymbolFileSymtab::ParseFunctions(CompileUnit &comp_unit) { size_t num_added = 0; // We must at least have a valid compile unit - assert(sc.comp_unit != NULL); const Symtab *symtab = m_obj_file->GetSymtab(); const Symbol *curr_symbol = NULL; const Symbol *next_symbol = NULL; @@ -185,7 +183,7 @@ size_t SymbolFileSymtab::ParseCompileUnitFunctions(const SymbolContext &sc) { } FunctionSP func_sp( - new Function(sc.comp_unit, + new Function(&comp_unit, symbol_idx, // UserID is the DIE offset LLDB_INVALID_UID, // We don't have any type info // for this function @@ -194,7 +192,7 @@ size_t SymbolFileSymtab::ParseCompileUnitFunctions(const SymbolContext &sc) { func_range)); // first address range if (func_sp.get() != NULL) { - sc.comp_unit->AddFunction(func_sp); + comp_unit.AddFunction(func_sp); ++num_added; } } @@ -207,16 +205,16 @@ size_t SymbolFileSymtab::ParseCompileUnitFunctions(const SymbolContext &sc) { return num_added; } -bool SymbolFileSymtab::ParseCompileUnitLineTable(const SymbolContext &sc) { - return false; -} +size_t SymbolFileSymtab::ParseTypes(CompileUnit &comp_unit) { return 0; } -bool SymbolFileSymtab::ParseCompileUnitDebugMacros(const SymbolContext &sc) { +bool SymbolFileSymtab::ParseLineTable(CompileUnit &comp_unit) { return false; } + +bool SymbolFileSymtab::ParseDebugMacros(CompileUnit &comp_unit) { return false; } -bool SymbolFileSymtab::ParseCompileUnitSupportFiles( - const SymbolContext &sc, FileSpecList &support_files) { +bool SymbolFileSymtab::ParseSupportFiles(CompileUnit &comp_unit, + FileSpecList &support_files) { return false; } @@ -225,11 +223,7 @@ bool SymbolFileSymtab::ParseImportedModules( return false; } -size_t SymbolFileSymtab::ParseFunctionBlocks(const SymbolContext &sc) { - return 0; -} - -size_t SymbolFileSymtab::ParseTypes(const SymbolContext &sc) { return 0; } +size_t SymbolFileSymtab::ParseBlocksRecursive(Function &func) { return 0; } size_t SymbolFileSymtab::ParseVariablesForContext(const SymbolContext &sc) { return 0; @@ -239,12 +233,18 @@ Type *SymbolFileSymtab::ResolveTypeUID(lldb::user_id_t type_uid) { return NULL; } +llvm::Optional<SymbolFile::ArrayInfo> +SymbolFileSymtab::GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) { + return llvm::None; +} + bool SymbolFileSymtab::CompleteType(lldb_private::CompilerType &compiler_type) { return false; } uint32_t SymbolFileSymtab::ResolveSymbolContext(const Address &so_addr, - uint32_t resolve_scope, + SymbolContextItem resolve_scope, SymbolContext &sc) { if (m_obj_file->GetSymtab() == NULL) return 0; diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h index d1887a707ea6..e4ec7a181333 100644 --- a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h +++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h @@ -10,13 +10,9 @@ #ifndef liblldb_SymbolFileSymtab_h_ #define liblldb_SymbolFileSymtab_h_ -// C Includes -// C++ Includes #include <map> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/Symtab.h" @@ -53,42 +49,41 @@ public: lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; lldb::LanguageType - ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) override; + ParseLanguage(lldb_private::CompileUnit &comp_unit) override; - size_t - ParseCompileUnitFunctions(const lldb_private::SymbolContext &sc) override; + size_t ParseFunctions(lldb_private::CompileUnit &comp_unit) override; - bool - ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc) override; + bool ParseLineTable(lldb_private::CompileUnit &comp_unit) override; - bool - ParseCompileUnitDebugMacros(const lldb_private::SymbolContext &sc) override; + bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; - bool ParseCompileUnitSupportFiles( - const lldb_private::SymbolContext &sc, - lldb_private::FileSpecList &support_files) override; + bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, + lldb_private::FileSpecList &support_files) override; + + size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override; bool ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules) override; - size_t ParseFunctionBlocks(const lldb_private::SymbolContext &sc) override; - - size_t ParseTypes(const lldb_private::SymbolContext &sc) override; + size_t ParseBlocksRecursive(lldb_private::Function &func) override; size_t ParseVariablesForContext(const lldb_private::SymbolContext &sc) override; lldb_private::Type *ResolveTypeUID(lldb::user_id_t type_uid) override; + llvm::Optional<ArrayInfo> GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, + const lldb_private::ExecutionContext *exe_ctx) override; bool CompleteType(lldb_private::CompilerType &compiler_type) override; uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr, - uint32_t resolve_scope, + lldb::SymbolContextItem resolve_scope, lldb_private::SymbolContext &sc) override; size_t GetTypes(lldb_private::SymbolContextScope *sc_scope, - uint32_t type_mask, + lldb::TypeClass type_mask, lldb_private::TypeList &type_list) override; //------------------------------------------------------------------ diff --git a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp index d24510966878..425b612d786f 100644 --- a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -101,16 +101,17 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp, const FileSpec fspec = file_spec_list.GetFileSpecAtIndex(idx); module_spec.GetFileSpec() = obj_file->GetFileSpec(); - module_spec.GetFileSpec().ResolvePath(); + FileSystem::Instance().Resolve(module_spec.GetFileSpec()); module_spec.GetSymbolFileSpec() = fspec; module_spec.GetUUID() = uuid; FileSpec dsym_fspec = Symbols::LocateExecutableSymbolFile(module_spec); if (dsym_fspec) { DataBufferSP dsym_file_data_sp; lldb::offset_t dsym_file_data_offset = 0; - ObjectFileSP dsym_objfile_sp = ObjectFile::FindPlugin( - module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), - dsym_file_data_sp, dsym_file_data_offset); + ObjectFileSP dsym_objfile_sp = + ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, + FileSystem::Instance().GetByteSize(dsym_fspec), + dsym_file_data_sp, dsym_file_data_offset); if (dsym_objfile_sp) { // This objfile is for debugging purposes. Sadly, ObjectFileELF won't // be able to figure this out consistently as the symbol file may not diff --git a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h index e7aeebc96b94..b0d956e31dc9 100644 --- a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h +++ b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h @@ -10,10 +10,6 @@ #ifndef liblldb_SymbolVendorELF_h_ #define liblldb_SymbolVendorELF_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/SymbolVendor.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp index c69eb7fd51c7..169eed817566 100644 --- a/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp +++ b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp @@ -153,9 +153,10 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, if (dsym_fspec) { DataBufferSP dsym_file_data_sp; lldb::offset_t dsym_file_data_offset = 0; - dsym_objfile_sp = ObjectFile::FindPlugin( - module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), - dsym_file_data_sp, dsym_file_data_offset); + dsym_objfile_sp = + ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, + FileSystem::Instance().GetByteSize(dsym_fspec), + dsym_file_data_sp, dsym_file_data_offset); if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm)) { // We need a XML parser if we hope to parse a plist... if (XMLDocument::XMLEnabled()) { @@ -172,8 +173,8 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, resources[strlen("/Contents/Resources/")] = '\0'; snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), "%s%s.plist", dsym_path, uuid_str.c_str()); - FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path, false); - if (dsym_uuid_plist_spec.Exists()) { + FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path); + if (FileSystem::Instance().Exists(dsym_uuid_plist_spec)) { ApplePropertyList plist(dsym_uuid_plist_path); if (plist) { std::string DBGBuildSourcePath; @@ -236,14 +237,15 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, // object is DBGSourcePath std::string DBGSourcePath = object->GetStringValue(); - if (new_style_source_remapping_dictionary == - false && + if (!new_style_source_remapping_dictionary && !original_DBGSourcePath_value.empty()) { DBGSourcePath = original_DBGSourcePath_value; } if (DBGSourcePath[0] == '~') { FileSpec resolved_source_path( - DBGSourcePath.c_str(), true); + DBGSourcePath.c_str()); + FileSystem::Instance().Resolve( + resolved_source_path); DBGSourcePath = resolved_source_path.GetPath(); } @@ -256,8 +258,8 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, // Add this as another option in addition to // the full source path remap. if (do_truncate_remapping_names) { - FileSpec build_path(key.AsCString(), false); - FileSpec source_path(DBGSourcePath.c_str(), false); + FileSpec build_path(key.AsCString()); + FileSpec source_path(DBGSourcePath.c_str()); build_path.RemoveLastPathComponent(); build_path.RemoveLastPathComponent(); source_path.RemoveLastPathComponent(); @@ -280,8 +282,8 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { if (DBGSourcePath[0] == '~') { - FileSpec resolved_source_path(DBGSourcePath.c_str(), - true); + FileSpec resolved_source_path(DBGSourcePath.c_str()); + FileSystem::Instance().Resolve(resolved_source_path); DBGSourcePath = resolved_source_path.GetPath(); } module_sp->GetSourceMappingList().Append( diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp index 007a59378fc5..43e401330c5c 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp @@ -10,10 +10,6 @@ #include "AppleGetItemInfoHandler.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" @@ -242,7 +238,7 @@ AppleGetItemInfoHandler::GetItemInfo(Thread &thread, uint64_t item, error.Clear(); - if (thread.SafeToCallFunctions() == false) { + if (!thread.SafeToCallFunctions()) { if (log) log->Printf("Not safe to call functions on thread 0x%" PRIx64, thread.GetID()); @@ -340,6 +336,7 @@ AppleGetItemInfoHandler::GetItemInfo(Thread &thread, uint64_t item, options.SetStopOthers(true); options.SetTimeout(std::chrono::milliseconds(500)); options.SetTryAllThreads(false); + options.SetIsForUtilityExpr(true); thread.CalculateExecutionContext(exe_ctx); if (!m_get_item_info_impl_code) { diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h b/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h index 373808e0f7e8..ac3711ead878 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h @@ -10,14 +10,10 @@ #ifndef lldb_AppleGetItemInfoHandler_h_ #define lldb_AppleGetItemInfoHandler_h_ -// C Includes -// C++ Includes #include <map> #include <mutex> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Expression/UtilityFunction.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Utility/Status.h" diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp index 0de32bf11416..78e50e673af0 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp @@ -10,10 +10,6 @@ #include "AppleGetPendingItemsHandler.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" @@ -245,7 +241,7 @@ AppleGetPendingItemsHandler::GetPendingItems(Thread &thread, addr_t queue, error.Clear(); - if (thread.SafeToCallFunctions() == false) { + if (!thread.SafeToCallFunctions()) { if (log) log->Printf("Not safe to call functions on thread 0x%" PRIx64, thread.GetID()); @@ -349,6 +345,7 @@ AppleGetPendingItemsHandler::GetPendingItems(Thread &thread, addr_t queue, options.SetStopOthers(true); options.SetTimeout(std::chrono::milliseconds(500)); options.SetTryAllThreads(false); + options.SetIsForUtilityExpr(true); thread.CalculateExecutionContext(exe_ctx); if (get_pending_items_caller == NULL) { diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h b/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h index 139e05b1b6c9..d35a72c2ff43 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h @@ -11,14 +11,10 @@ #ifndef lldb_AppleGetPendingItemsHandler_h_ #define lldb_AppleGetPendingItemsHandler_h_ -// C Includes -// C++ Includes #include <map> #include <mutex> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/CompilerType.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-public.h" diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp index 7855b3603a3a..245ff6742b43 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp @@ -9,10 +9,6 @@ #include "AppleGetQueuesHandler.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DiagnosticManager.h" @@ -247,7 +243,7 @@ AppleGetQueuesHandler::GetCurrentQueues(Thread &thread, addr_t page_to_free, error.Clear(); - if (thread.SafeToCallFunctions() == false) { + if (!thread.SafeToCallFunctions()) { if (log) log->Printf("Not safe to call functions on thread 0x%" PRIx64, thread.GetID()); @@ -354,6 +350,7 @@ AppleGetQueuesHandler::GetCurrentQueues(Thread &thread, addr_t page_to_free, options.SetStopOthers(true); options.SetTimeout(std::chrono::milliseconds(500)); options.SetTryAllThreads(false); + options.SetIsForUtilityExpr(true); thread.CalculateExecutionContext(exe_ctx); ExpressionResults func_call_ret; diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h b/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h index f1c79044496f..0d8e4dc64a68 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h @@ -10,14 +10,10 @@ #ifndef lldb_AppleGetQueuesHandler_h_ #define lldb_AppleGetQueuesHandler_h_ -// C Includes -// C++ Includes #include <map> #include <mutex> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/CompilerType.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-public.h" diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index 09ab6600a9f0..ede81333a3e6 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -10,10 +10,6 @@ #include "AppleGetThreadItemInfoHandler.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" @@ -252,7 +248,7 @@ AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, error.Clear(); - if (thread.SafeToCallFunctions() == false) { + if (!thread.SafeToCallFunctions()) { if (log) log->Printf("Not safe to call functions on thread 0x%" PRIx64, thread.GetID()); @@ -351,6 +347,7 @@ AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, options.SetStopOthers(true); options.SetTimeout(std::chrono::milliseconds(500)); options.SetTryAllThreads(false); + options.SetIsForUtilityExpr(true); thread.CalculateExecutionContext(exe_ctx); if (!m_get_thread_item_info_impl_code) { diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h b/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h index 62730809e0d1..47e196102362 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h @@ -11,14 +11,10 @@ #ifndef lldb_AppleGetThreadItemInfoHandler_h_ #define lldb_AppleGetThreadItemInfoHandler_h_ -// C Includes -// C++ Includes #include <map> #include <mutex> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Symbol/CompilerType.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-public.h" diff --git a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index 4748d5e8622e..e61f04e489e8 100644 --- a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -59,6 +59,7 @@ SystemRuntime *SystemRuntimeMacOSX::CreateInstance(Process *process) { case llvm::Triple::IOS: case llvm::Triple::TvOS: case llvm::Triple::WatchOS: + // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: create = triple_ref.getVendor() == llvm::Triple::Apple; break; default: @@ -276,7 +277,7 @@ void SystemRuntimeMacOSX::ReadLibdispatchOffsetsAddress() { // libdispatch symbols were in libSystem.B.dylib up through Mac OS X 10.6 // ("Snow Leopard") - ModuleSpec libSystem_module_spec(FileSpec("libSystem.B.dylib", false)); + ModuleSpec libSystem_module_spec(FileSpec("libSystem.B.dylib")); ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule( libSystem_module_spec)); if (module_sp) @@ -286,7 +287,7 @@ void SystemRuntimeMacOSX::ReadLibdispatchOffsetsAddress() { // libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") // and later if (dispatch_queue_offsets_symbol == NULL) { - ModuleSpec libdispatch_module_spec(FileSpec("libdispatch.dylib", false)); + ModuleSpec libdispatch_module_spec(FileSpec("libdispatch.dylib")); module_sp = m_process->GetTarget().GetImages().FindFirstModule( libdispatch_module_spec); if (module_sp) @@ -330,7 +331,7 @@ void SystemRuntimeMacOSX::ReadLibpthreadOffsetsAddress() { "pthread_layout_offsets"); const Symbol *libpthread_layout_offsets_symbol = NULL; - ModuleSpec libpthread_module_spec(FileSpec("libsystem_pthread.dylib", false)); + ModuleSpec libpthread_module_spec(FileSpec("libsystem_pthread.dylib")); ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule( libpthread_module_spec)); if (module_sp) { @@ -378,7 +379,7 @@ void SystemRuntimeMacOSX::ReadLibdispatchTSDIndexesAddress() { "dispatch_tsd_indexes"); const Symbol *libdispatch_tsd_indexes_symbol = NULL; - ModuleSpec libpthread_module_spec(FileSpec("libdispatch.dylib", false)); + ModuleSpec libpthread_module_spec(FileSpec("libdispatch.dylib")); ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule( libpthread_module_spec)); if (module_sp) { diff --git a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h index 2dc5740da9b6..5fa78cee4640 100644 --- a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h +++ b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h @@ -10,14 +10,11 @@ #ifndef liblldb_SystemRuntimeMacOSX_h_ #define liblldb_SystemRuntimeMacOSX_h_ -// C Includes -// C++ Includes #include <mutex> #include <string> #include <vector> // Other libraries and framework include -// Project includes #include "lldb/Core/ModuleList.h" #include "lldb/Target/Process.h" #include "lldb/Target/QueueItem.h" diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index 54e182b30b6f..b70c2c44d3e6 100644 --- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -606,7 +606,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister( assert( (generic_regnum == LLDB_REGNUM_GENERIC_PC || generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) && - "eInfoTypeISA used for poping a register other the the PC/FLAGS"); + "eInfoTypeISA used for popping a register other the PC/FLAGS"); if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) { m_curr_row->SetRegisterLocationToSame(reg_num, false /*must_replace*/); diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h index e587c93b427c..5539b5217e9e 100644 --- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h +++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h @@ -10,14 +10,10 @@ #ifndef liblldb_UnwindAssemblyInstEmulation_h_ #define liblldb_UnwindAssemblyInstEmulation_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "lldb/Core/EmulateInstruction.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/UnwindAssembly.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/lldb-private.h" class UnwindAssemblyInstEmulation : public lldb_private::UnwindAssembly { diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp index 327d0b0e4f71..04f9cbbf03ae 100644 --- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp +++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp @@ -92,7 +92,7 @@ bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite( // assembly parsing instead. if (first_row->GetCFAValue().GetValueType() != - UnwindPlan::Row::CFAValue::isRegisterPlusOffset || + UnwindPlan::Row::FAValue::isRegisterPlusOffset || RegisterNumber(thread, unwind_plan.GetRegisterKind(), first_row->GetCFAValue().GetRegisterNumber()) != sp_regnum || @@ -100,10 +100,10 @@ bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite( return false; } UnwindPlan::Row::RegisterLocation first_row_pc_loc; - if (first_row->GetRegisterInfo( + if (!first_row->GetRegisterInfo( pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()), - first_row_pc_loc) == false || - first_row_pc_loc.IsAtCFAPlusOffset() == false || + first_row_pc_loc) || + !first_row_pc_loc.IsAtCFAPlusOffset() || first_row_pc_loc.GetOffset() != -wordsize) { return false; } diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h index 2beaa4a6510a..c4052a8489da 100644 --- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h +++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h @@ -10,12 +10,8 @@ #ifndef liblldb_UnwindAssembly_x86_h_ #define liblldb_UnwindAssembly_x86_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes #include "x86AssemblyInspectionEngine.h" -// Project includes #include "lldb/Target/UnwindAssembly.h" #include "lldb/lldb-private.h" diff --git a/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp index 10a56980594f..f8e70204e509 100644 --- a/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp +++ b/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp @@ -59,6 +59,7 @@ void x86AssemblyInspectionEngine::Initialize(RegisterContextSP ®_ctx) { m_machine_ip_regnum = k_machine_eip; m_machine_sp_regnum = k_machine_esp; m_machine_fp_regnum = k_machine_ebp; + m_machine_alt_fp_regnum = k_machine_ebx; m_wordsize = 4; struct lldb_reg_info reginfo; @@ -84,6 +85,7 @@ void x86AssemblyInspectionEngine::Initialize(RegisterContextSP ®_ctx) { m_machine_ip_regnum = k_machine_rip; m_machine_sp_regnum = k_machine_rsp; m_machine_fp_regnum = k_machine_rbp; + m_machine_alt_fp_regnum = k_machine_rbx; m_wordsize = 8; struct lldb_reg_info reginfo; @@ -135,6 +137,8 @@ void x86AssemblyInspectionEngine::Initialize(RegisterContextSP ®_ctx) { m_lldb_sp_regnum = lldb_regno; if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno)) m_lldb_fp_regnum = lldb_regno; + if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno)) + m_lldb_alt_fp_regnum = lldb_regno; if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno)) m_lldb_ip_regnum = lldb_regno; @@ -160,6 +164,7 @@ void x86AssemblyInspectionEngine::Initialize( m_machine_ip_regnum = k_machine_eip; m_machine_sp_regnum = k_machine_esp; m_machine_fp_regnum = k_machine_ebp; + m_machine_alt_fp_regnum = k_machine_ebx; m_wordsize = 4; struct lldb_reg_info reginfo; @@ -185,6 +190,7 @@ void x86AssemblyInspectionEngine::Initialize( m_machine_ip_regnum = k_machine_rip; m_machine_sp_regnum = k_machine_rsp; m_machine_fp_regnum = k_machine_rbp; + m_machine_alt_fp_regnum = k_machine_rbx; m_wordsize = 8; struct lldb_reg_info reginfo; @@ -239,6 +245,8 @@ void x86AssemblyInspectionEngine::Initialize( m_lldb_sp_regnum = lldb_regno; if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno)) m_lldb_fp_regnum = lldb_regno; + if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno)) + m_lldb_alt_fp_regnum = lldb_regno; if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno)) m_lldb_ip_regnum = lldb_regno; @@ -296,26 +304,20 @@ bool x86AssemblyInspectionEngine::nonvolatile_reg_p(int machine_regno) { // pushq %rbp [0x55] bool x86AssemblyInspectionEngine::push_rbp_pattern_p() { uint8_t *p = m_cur_insn; - if (*p == 0x55) - return true; - return false; + return *p == 0x55; } // pushq $0 ; the first instruction in start() [0x6a 0x00] bool x86AssemblyInspectionEngine::push_0_pattern_p() { uint8_t *p = m_cur_insn; - if (*p == 0x6a && *(p + 1) == 0x0) - return true; - return false; + return *p == 0x6a && *(p + 1) == 0x0; } // pushq $0 // pushl $0 bool x86AssemblyInspectionEngine::push_imm_pattern_p() { uint8_t *p = m_cur_insn; - if (*p == 0x68 || *p == 0x6a) - return true; - return false; + return *p == 0x68 || *p == 0x6a; } // pushl imm8(%esp) @@ -387,6 +389,45 @@ bool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() { return false; } +// movq %rsp, %rbx [0x48 0x8b 0xdc] or [0x48 0x89 0xe3] +// movl %esp, %ebx [0x8b 0xdc] or [0x89 0xe3] +bool x86AssemblyInspectionEngine::mov_rsp_rbx_pattern_p() { + uint8_t *p = m_cur_insn; + if (m_wordsize == 8 && *p == 0x48) + p++; + if (*(p) == 0x8b && *(p + 1) == 0xdc) + return true; + if (*(p) == 0x89 && *(p + 1) == 0xe3) + return true; + return false; +} + +// movq %rbp, %rsp [0x48 0x8b 0xe5] or [0x48 0x89 0xec] +// movl %ebp, %esp [0x8b 0xe5] or [0x89 0xec] +bool x86AssemblyInspectionEngine::mov_rbp_rsp_pattern_p() { + uint8_t *p = m_cur_insn; + if (m_wordsize == 8 && *p == 0x48) + p++; + if (*(p) == 0x8b && *(p + 1) == 0xe5) + return true; + if (*(p) == 0x89 && *(p + 1) == 0xec) + return true; + return false; +} + +// movq %rbx, %rsp [0x48 0x8b 0xe3] or [0x48 0x89 0xdc] +// movl %ebx, %esp [0x8b 0xe3] or [0x89 0xdc] +bool x86AssemblyInspectionEngine::mov_rbx_rsp_pattern_p() { + uint8_t *p = m_cur_insn; + if (m_wordsize == 8 && *p == 0x48) + p++; + if (*(p) == 0x8b && *(p + 1) == 0xe3) + return true; + if (*(p) == 0x89 && *(p + 1) == 0xdc) + return true; + return false; +} + // subq $0x20, %rsp bool x86AssemblyInspectionEngine::sub_rsp_pattern_p(int &amount) { uint8_t *p = m_cur_insn; @@ -476,6 +517,46 @@ bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) { return false; } +// lea -0x28(%ebx), %esp +// (32-bit and 64-bit variants, 8-bit and 32-bit displacement) +bool x86AssemblyInspectionEngine::lea_rbx_rsp_pattern_p(int &amount) { + uint8_t *p = m_cur_insn; + if (m_wordsize == 8 && *p == 0x48) + p++; + + // Check opcode + if (*p != 0x8d) + return false; + ++p; + + // 8 bit displacement + if (*p == 0x63) { + amount = (int8_t)p[1]; + return true; + } + + // 32 bit displacement + if (*p == 0xa3) { + amount = (int32_t)extract_4(p + 1); + return true; + } + + return false; +} + +// and -0xfffffff0, %esp +// (32-bit and 64-bit variants, 8-bit and 32-bit displacement) +bool x86AssemblyInspectionEngine::and_rsp_pattern_p() { + uint8_t *p = m_cur_insn; + if (m_wordsize == 8 && *p == 0x48) + p++; + + if (*p != 0x81 && *p != 0x83) + return false; + + return *++p == 0xe4; +} + // popq %rbx // popl %ebx bool x86AssemblyInspectionEngine::pop_reg_p(int ®no) { @@ -588,9 +669,7 @@ bool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p( // ret [0xc9] or [0xc2 imm8] or [0xca imm8] bool x86AssemblyInspectionEngine::ret_pattern_p() { uint8_t *p = m_cur_insn; - if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3) - return true; - return false; + return *p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3; } uint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) { @@ -636,11 +715,12 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( if (data == nullptr || size == 0) return false; - if (m_register_map_initialized == false) + if (!m_register_map_initialized) return false; addr_t current_func_text_offset = 0; - int current_sp_bytes_offset_from_cfa = 0; + int current_sp_bytes_offset_from_fa = 0; + bool is_aligned = false; UnwindPlan::Row::RegisterLocation initial_regloc; UnwindPlan::RowSP row(new UnwindPlan::Row); @@ -657,8 +737,8 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( row->SetRegisterInfo(m_lldb_sp_regnum, initial_regloc); // saved instruction pointer can be found at CFA - wordsize. - current_sp_bytes_offset_from_cfa = m_wordsize; - initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_cfa); + current_sp_bytes_offset_from_fa = m_wordsize; + initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa); row->SetRegisterInfo(m_lldb_ip_regnum, initial_regloc); unwind_plan.AppendRow(row); @@ -682,6 +762,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the // epilogue started executed + bool prologue_completed_is_aligned; std::vector<bool> prologue_completed_saved_registers; while (current_func_text_offset < size) { @@ -701,22 +782,59 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( break; } - if (push_rbp_pattern_p()) { - current_sp_bytes_offset_from_cfa += m_wordsize; - row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa); - UnwindPlan::Row::RegisterLocation regloc; - regloc.SetAtCFAPlusOffset(-row->GetCFAValue().GetOffset()); - row->SetRegisterInfo(m_lldb_fp_regnum, regloc); - saved_registers[m_machine_fp_regnum] = true; - row_updated = true; + auto &cfa_value = row->GetCFAValue(); + auto &afa_value = row->GetAFAValue(); + auto fa_value_ptr = is_aligned ? &afa_value : &cfa_value; + + if (mov_rsp_rbp_pattern_p()) { + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetIsRegisterPlusOffset( + m_lldb_fp_regnum, fa_value_ptr->GetOffset()); + row_updated = true; + } + } + + else if (mov_rsp_rbx_pattern_p()) { + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetIsRegisterPlusOffset( + m_lldb_alt_fp_regnum, fa_value_ptr->GetOffset()); + row_updated = true; + } } - else if (mov_rsp_rbp_pattern_p()) { - row->GetCFAValue().SetIsRegisterPlusOffset( - m_lldb_fp_regnum, row->GetCFAValue().GetOffset()); + else if (and_rsp_pattern_p()) { + current_sp_bytes_offset_from_fa = 0; + afa_value.SetIsRegisterPlusOffset( + m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); + fa_value_ptr = &afa_value; + is_aligned = true; row_updated = true; } + else if (mov_rbp_rsp_pattern_p()) { + if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) + { + is_aligned = false; + fa_value_ptr = &cfa_value; + afa_value.SetUnspecified(); + row_updated = true; + } + if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) + current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); + } + + else if (mov_rbx_rsp_pattern_p()) { + if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) + { + is_aligned = false; + fa_value_ptr = &cfa_value; + afa_value.SetUnspecified(); + row_updated = true; + } + if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) + current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); + } + // This is the start() function (or a pthread equivalent), it starts with a // pushl $0x0 which puts the saved pc value of 0 on the stack. In this // case we want to pretend we didn't see a stack movement at all -- @@ -726,21 +844,24 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( } else if (push_reg_p(machine_regno)) { - current_sp_bytes_offset_from_cfa += m_wordsize; - // the PUSH instruction has moved the stack pointer - if the CFA is set + current_sp_bytes_offset_from_fa += m_wordsize; + // the PUSH instruction has moved the stack pointer - if the FA is set // in terms of the stack pointer, we need to add a new row of // instructions. - if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa); + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); row_updated = true; } // record where non-volatile (callee-saved, spilled) registers are saved // on the stack if (nonvolatile_reg_p(machine_regno) && machine_regno_to_lldb_regno(machine_regno, lldb_regno) && - saved_registers[machine_regno] == false) { + !saved_registers[machine_regno]) { UnwindPlan::Row::RegisterLocation regloc; - regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_cfa); + if (is_aligned) + regloc.SetAtAFAPlusOffset(-current_sp_bytes_offset_from_fa); + else + regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa); row->SetRegisterInfo(lldb_regno, regloc); saved_registers[machine_regno] = true; row_updated = true; @@ -748,37 +869,37 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( } else if (pop_reg_p(machine_regno)) { - current_sp_bytes_offset_from_cfa -= m_wordsize; + current_sp_bytes_offset_from_fa -= m_wordsize; if (nonvolatile_reg_p(machine_regno) && machine_regno_to_lldb_regno(machine_regno, lldb_regno) && - saved_registers[machine_regno] == true) { + saved_registers[machine_regno]) { saved_registers[machine_regno] = false; row->RemoveRegisterInfo(lldb_regno); - if (machine_regno == (int)m_machine_fp_regnum) { - row->GetCFAValue().SetIsRegisterPlusOffset( - m_lldb_sp_regnum, row->GetCFAValue().GetOffset()); + if (lldb_regno == fa_value_ptr->GetRegisterNumber()) { + fa_value_ptr->SetIsRegisterPlusOffset( + m_lldb_sp_regnum, fa_value_ptr->GetOffset()); } in_epilogue = true; row_updated = true; } - // the POP instruction has moved the stack pointer - if the CFA is set in + // the POP instruction has moved the stack pointer - if the FA is set in // terms of the stack pointer, we need to add a new row of instructions. - if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->GetCFAValue().SetIsRegisterPlusOffset( - m_lldb_sp_regnum, current_sp_bytes_offset_from_cfa); + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetIsRegisterPlusOffset( + m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); row_updated = true; } } else if (pop_misc_reg_p()) { - current_sp_bytes_offset_from_cfa -= m_wordsize; - if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->GetCFAValue().SetIsRegisterPlusOffset( - m_lldb_sp_regnum, current_sp_bytes_offset_from_cfa); + current_sp_bytes_offset_from_fa -= m_wordsize; + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetIsRegisterPlusOffset( + m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); row_updated = true; } } @@ -787,41 +908,57 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( // off the stack into rbp (restoring the caller's rbp value). It is the // opposite of ENTER, or 'push rbp, mov rsp rbp'. else if (leave_pattern_p()) { - // We're going to copy the value in rbp into rsp, so re-set the sp offset - // based on the CFAValue. Also, adjust it to recognize that we're - // popping the saved rbp value off the stack. - current_sp_bytes_offset_from_cfa = row->GetCFAValue().GetOffset(); - current_sp_bytes_offset_from_cfa -= m_wordsize; - row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa); - - // rbp is restored to the caller's value - saved_registers[m_machine_fp_regnum] = false; - row->RemoveRegisterInfo(m_lldb_fp_regnum); - - // cfa is now in terms of rsp again. - row->GetCFAValue().SetIsRegisterPlusOffset( - m_lldb_sp_regnum, row->GetCFAValue().GetOffset()); - row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa); + if (saved_registers[m_machine_fp_regnum]) { + saved_registers[m_machine_fp_regnum] = false; + row->RemoveRegisterInfo(m_lldb_fp_regnum); + + row_updated = true; + } + + if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) + { + is_aligned = false; + fa_value_ptr = &cfa_value; + afa_value.SetUnspecified(); + row_updated = true; + } + + if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) + { + fa_value_ptr->SetIsRegisterPlusOffset( + m_lldb_sp_regnum, fa_value_ptr->GetOffset()); + + current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); + } + + current_sp_bytes_offset_from_fa -= m_wordsize; + + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetIsRegisterPlusOffset( + m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); + row_updated = true; + } in_epilogue = true; - row_updated = true; } else if (mov_reg_to_local_stack_frame_p(machine_regno, stack_offset) && nonvolatile_reg_p(machine_regno) && machine_regno_to_lldb_regno(machine_regno, lldb_regno) && - saved_registers[machine_regno] == false) { + !saved_registers[machine_regno]) { saved_registers[machine_regno] = true; UnwindPlan::Row::RegisterLocation regloc; // stack_offset for 'movq %r15, -80(%rbp)' will be 80. In the Row, we - // want to express this as the offset from the CFA. If the frame base is - // rbp (like the above instruction), the CFA offset for rbp is probably - // 16. So we want to say that the value is stored at the CFA address - + // want to express this as the offset from the FA. If the frame base is + // rbp (like the above instruction), the FA offset for rbp is probably + // 16. So we want to say that the value is stored at the FA address - // 96. - regloc.SetAtCFAPlusOffset( - -(stack_offset + row->GetCFAValue().GetOffset())); + if (is_aligned) + regloc.SetAtAFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset())); + else + regloc.SetAtCFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset())); row->SetRegisterInfo(lldb_regno, regloc); @@ -829,17 +966,17 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( } else if (sub_rsp_pattern_p(stack_offset)) { - current_sp_bytes_offset_from_cfa += stack_offset; - if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa); + current_sp_bytes_offset_from_fa += stack_offset; + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); row_updated = true; } } else if (add_rsp_pattern_p(stack_offset)) { - current_sp_bytes_offset_from_cfa -= stack_offset; - if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa); + current_sp_bytes_offset_from_fa -= stack_offset; + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); row_updated = true; } in_epilogue = true; @@ -847,27 +984,48 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( else if (push_extended_pattern_p() || push_imm_pattern_p() || push_misc_reg_p()) { - current_sp_bytes_offset_from_cfa += m_wordsize; - if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa); + current_sp_bytes_offset_from_fa += m_wordsize; + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); row_updated = true; } } else if (lea_rsp_pattern_p(stack_offset)) { - current_sp_bytes_offset_from_cfa -= stack_offset; - if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa); + current_sp_bytes_offset_from_fa -= stack_offset; + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); row_updated = true; } if (stack_offset > 0) in_epilogue = true; } - else if (lea_rbp_rsp_pattern_p(stack_offset) && - row->GetCFAValue().GetRegisterNumber() == m_lldb_fp_regnum) { - current_sp_bytes_offset_from_cfa = - row->GetCFAValue().GetOffset() - stack_offset; + else if (lea_rbp_rsp_pattern_p(stack_offset)) { + if (is_aligned && + cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) { + is_aligned = false; + fa_value_ptr = &cfa_value; + afa_value.SetUnspecified(); + row_updated = true; + } + if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) { + current_sp_bytes_offset_from_fa = + fa_value_ptr->GetOffset() - stack_offset; + } + } + + else if (lea_rbx_rsp_pattern_p(stack_offset)) { + if (is_aligned && + cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) { + is_aligned = false; + fa_value_ptr = &cfa_value; + afa_value.SetUnspecified(); + row_updated = true; + } + if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) { + current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset() - stack_offset; + } } else if (ret_pattern_p() && prologue_completed_row.get()) { @@ -877,8 +1035,9 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( UnwindPlan::Row *newrow = new UnwindPlan::Row; *newrow = *prologue_completed_row.get(); row.reset(newrow); - current_sp_bytes_offset_from_cfa = + current_sp_bytes_offset_from_fa = prologue_completed_sp_bytes_offset_from_cfa; + is_aligned = prologue_completed_is_aligned; saved_registers.clear(); saved_registers.resize(prologue_completed_saved_registers.size(), false); @@ -896,9 +1055,9 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( // This is used in i386 programs to get the PIC base address for finding // global data else if (call_next_insn_pattern_p()) { - current_sp_bytes_offset_from_cfa += m_wordsize; - if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa); + current_sp_bytes_offset_from_fa += m_wordsize; + if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { + fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); row_updated = true; } } @@ -914,7 +1073,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( } } - if (in_epilogue == false && row_updated) { + if (!in_epilogue && row_updated) { // If we're not in an epilogue sequence, save the updated Row UnwindPlan::Row *newrow = new UnwindPlan::Row; *newrow = *row.get(); @@ -929,9 +1088,10 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( // We may change the sp value without adding a new Row necessarily -- keep // track of it either way. - if (in_epilogue == false) { + if (!in_epilogue) { prologue_completed_sp_bytes_offset_from_cfa = - current_sp_bytes_offset_from_cfa; + current_sp_bytes_offset_from_fa; + prologue_completed_is_aligned = is_aligned; } m_cur_insn = m_cur_insn + insn_len; @@ -1194,7 +1354,7 @@ bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction( uint8_t *data, size_t size, size_t &offset) { offset = 0; - if (m_register_map_initialized == false) + if (!m_register_map_initialized) return false; while (offset < size) { diff --git a/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h b/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h index cec9803c8a49..e02b510ba1f9 100644 --- a/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h +++ b/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h @@ -98,10 +98,15 @@ private: bool push_extended_pattern_p(); bool push_misc_reg_p(); bool mov_rsp_rbp_pattern_p(); + bool mov_rsp_rbx_pattern_p(); + bool mov_rbp_rsp_pattern_p(); + bool mov_rbx_rsp_pattern_p(); bool sub_rsp_pattern_p(int &amount); bool add_rsp_pattern_p(int &amount); bool lea_rsp_pattern_p(int &amount); bool lea_rbp_rsp_pattern_p(int &amount); + bool lea_rbx_rsp_pattern_p(int &amount); + bool and_rsp_pattern_p(); bool push_reg_p(int ®no); bool pop_reg_p(int ®no); bool pop_rbp_pattern_p(); @@ -157,9 +162,11 @@ private: uint32_t m_machine_ip_regnum; uint32_t m_machine_sp_regnum; uint32_t m_machine_fp_regnum; + uint32_t m_machine_alt_fp_regnum; uint32_t m_lldb_ip_regnum; uint32_t m_lldb_sp_regnum; uint32_t m_lldb_fp_regnum; + uint32_t m_lldb_alt_fp_regnum; typedef std::map<uint32_t, lldb_reg_info> MachineRegnumToNameAndLLDBRegnum; |