diff options
Diffstat (limited to 'source/Plugins')
349 files changed, 16776 insertions, 13510 deletions
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp index 1bd1c1bf8dd4..e0e293d7ae68 100644 --- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp +++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp @@ -1466,8 +1466,8 @@ bool ABIMacOSX_arm::GetArgumentValues(Thread &thread, ValueList &values) const { addr_t sp = 0; for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) { - // We currently only support extracting values with Clang QualTypes. - // Do we care about others? + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? Value *value = values.GetValueAtIndex(value_idx); if (!value) @@ -1589,10 +1589,8 @@ ValueObjectSP ABIMacOSX_arm::GetReturnValueObjectImpl( case 128: if (IsArmv7kProcess()) { // "A composite type not larger than 16 bytes is returned in r0-r3. The - // format is - // as if the result had been stored in memory at a word-aligned address - // and then - // loaded into r0-r3 with an ldm instruction" + // format is as if the result had been stored in memory at a word- + // aligned address and then loaded into r0-r3 with an ldm instruction" { const RegisterInfo *r1_reg_info = reg_ctx->GetRegisterInfoByName("r1", 0); @@ -1756,10 +1754,8 @@ Status ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, } } else if (num_bytes <= 16 && IsArmv7kProcess()) { // "A composite type not larger than 16 bytes is returned in r0-r3. The - // format is - // as if the result had been stored in memory at a word-aligned address - // and then - // loaded into r0-r3 with an ldm instruction" + // format is as if the result had been stored in memory at a word-aligned + // address and then loaded into r0-r3 with an ldm instruction" const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("r0", 0); const RegisterInfo *r1_info = reg_ctx->GetRegisterInfoByName("r1", 0); diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp index e301b21d542a..85f864ec7561 100644 --- a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp +++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp @@ -1760,8 +1760,8 @@ bool ABIMacOSX_arm64::GetArgumentValues(Thread &thread, addr_t sp = 0; for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) { - // We currently only support extracting values with Clang QualTypes. - // Do we care about others? + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? Value *value = values.GetValueAtIndex(value_idx); if (!value) @@ -2022,10 +2022,9 @@ bool ABIMacOSX_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { } // AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says -// registers x19 through x28 and sp are callee preserved. -// v8-v15 are non-volatile (and specifically only the lower 8 bytes of these -// regs), -// the rest of the fp/SIMD registers are volatile. +// registers x19 through x28 and sp are callee preserved. v8-v15 are non- +// volatile (and specifically only the lower 8 bytes of these regs), the rest +// of the fp/SIMD registers are volatile. // We treat x29 as callee preserved also, else the unwinder won't try to // retrieve fp saves. @@ -2209,14 +2208,14 @@ static bool LoadValueFromConsecutiveGPRRegisters( } else { const RegisterInfo *reg_info = nullptr; if (is_return_value) { - // We are assuming we are decoding this immediately after returning - // from a function call and that the address of the structure is in x8 + // We are assuming we are decoding this immediately after returning from + // a function call and that the address of the structure is in x8 reg_info = reg_ctx->GetRegisterInfoByName("x8", 0); } else { // We are assuming we are stopped at the first instruction in a function - // and that the ABI is being respected so all parameters appear where they - // should be (functions with no external linkage can legally violate the - // ABI). + // and that the ABI is being respected so all parameters appear where + // they should be (functions with no external linkage can legally violate + // the ABI). if (NGRN >= 8) return false; diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp index 716a73b854b3..9e5e39ec28ca 100644 --- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp +++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp @@ -736,10 +736,10 @@ bool ABIMacOSX_i386::PrepareTrivialCall(Thread &thread, addr_t sp, uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); - // When writing a register value down to memory, the register info used - // to write memory just needs to have the correct size of a 32 bit register, - // the actual register it pertains to is not important, just the size needs - // to be correct. Here we use "eax"... + // When writing a register value down to memory, the register info used to + // write memory just needs to have the correct size of a 32 bit register, the + // actual register it pertains to is not important, just the size needs to be + // correct. Here we use "eax"... const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax"); if (!reg_info_32) return false; // TODO this should actually never happen @@ -828,8 +828,8 @@ bool ABIMacOSX_i386::GetArgumentValues(Thread &thread, if (!value) return false; - // We currently only support extracting values with Clang QualTypes. - // Do we care about others? + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? CompilerType compiler_type(value->GetCompilerType()); if (compiler_type) { bool is_signed; @@ -1075,12 +1075,13 @@ bool ABIMacOSX_i386::RegisterIsVolatile(const RegisterInfo *reg_info) { } // v. -// http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4 +// http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130 +// -IA- +// 32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4 // // This document ("OS X ABI Function Call Guide", chapter "IA-32 Function -// Calling Conventions") -// says that the following registers on i386 are preserved aka non-volatile aka -// callee-saved: +// Calling Conventions") says that the following registers on i386 are +// preserved aka non-volatile aka callee-saved: // // ebx, ebp, esi, edi, esp diff --git a/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp b/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp index 882d5cd23e58..af7ac469e6db 100644 --- a/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp +++ b/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp @@ -1470,8 +1470,8 @@ bool ABISysV_arm::GetArgumentValues(Thread &thread, ValueList &values) const { addr_t sp = 0; for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) { - // We currently only support extracting values with Clang QualTypes. - // Do we care about others? + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? Value *value = values.GetValueAtIndex(value_idx); if (!value) diff --git a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp index dbe333c4649e..2c221689954c 100644 --- a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp +++ b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp @@ -1763,8 +1763,8 @@ bool ABISysV_arm64::GetArgumentValues(Thread &thread, ValueList &values) const { addr_t sp = 0; for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) { - // We currently only support extracting values with Clang QualTypes. - // Do we care about others? + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? Value *value = values.GetValueAtIndex(value_idx); if (!value) @@ -1994,10 +1994,9 @@ bool ABISysV_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { } // AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says -// registers x19 through x28 and sp are callee preserved. -// v8-v15 are non-volatile (and specifically only the lower 8 bytes of these -// regs), -// the rest of the fp/SIMD registers are volatile. +// registers x19 through x28 and sp are callee preserved. v8-v15 are non- +// volatile (and specifically only the lower 8 bytes of these regs), the rest +// of the fp/SIMD registers are volatile. // We treat x29 as callee preserved also, else the unwinder won't try to // retrieve fp saves. @@ -2020,10 +2019,10 @@ bool ABISysV_arm64::RegisterIsVolatile(const RegisterInfo *reg_info) { if (name[0] == 'x' || name[0] == 'r') { // Volatile registers: x0-x18 - // Although documentation says only x19-28 + sp are callee saved - // We ll also have to treat x30 as non-volatile. - // Each dwarf frame has its own value of lr. - // Return false for the non-volatile gpr regs, true for everything else + // Although documentation says only x19-28 + sp are callee saved We ll + // also have to treat x30 as non-volatile. Each dwarf frame has its own + // value of lr. Return false for the non-volatile gpr regs, true for + // everything else switch (name[1]) { case '1': switch (name[2]) { @@ -2180,14 +2179,14 @@ static bool LoadValueFromConsecutiveGPRRegisters( } else { const RegisterInfo *reg_info = nullptr; if (is_return_value) { - // We are assuming we are decoding this immediately after returning - // from a function call and that the address of the structure is in x8 + // We are assuming we are decoding this immediately after returning from + // a function call and that the address of the structure is in x8 reg_info = reg_ctx->GetRegisterInfoByName("x8", 0); } else { // We are assuming we are stopped at the first instruction in a function - // and that the ABI is being respected so all parameters appear where they - // should be (functions with no external linkage can legally violate the - // ABI). + // and that the ABI is being respected so all parameters appear where + // they should be (functions with no external linkage can legally violate + // the ABI). if (NGRN >= 8) return false; diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp index 74274f08b24f..a30416cf5a8e 100644 --- a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp +++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp @@ -1214,8 +1214,8 @@ ValueObjectSP ABISysV_hexagon::GetReturnValueObjectImpl( return return_valobj_sp; } -// called when we are on the first instruction of a new function -// for hexagon the return address is in RA (R31) +// called when we are on the first instruction of a new function for hexagon +// the return address is in RA (R31) bool ABISysV_hexagon::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { unwind_plan.Clear(); unwind_plan.SetRegisterKind(eRegisterKindGeneric); diff --git a/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp b/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp index d799c587dd07..e7ddfccea338 100644 --- a/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp +++ b/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp @@ -3,8 +3,7 @@ // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source -// License. -// See LICENSE.TXT for details. +// License. See LICENSE.TXT for details. //===----------------------------------------------------------------------===// #include "ABISysV_i386.h" @@ -56,8 +55,8 @@ using namespace lldb_private; // DWARF Register Number Mapping // See Table 2.14 of the reference document (specified on top of this file) -// Comment: Table 2.14 is followed till 'mm' entries. -// After that, all entries are ignored here. +// Comment: Table 2.14 is followed till 'mm' entries. After that, all entries +// are ignored here. enum dwarf_regnums { dwarf_eax = 0, @@ -228,12 +227,10 @@ bool ABISysV_i386::PrepareTrivialCall(Thread &thread, addr_t sp, uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); - // While using register info to write a register value to memory, the register - // info - // just needs to have the correct size of a 32 bit register, the actual - // register it - // pertains to is not important, just the size needs to be correct. - // "eax" is used here for this purpose. + // While using register info to write a register value to memory, the + // register info just needs to have the correct size of a 32 bit register, + // the actual register it pertains to is not important, just the size needs + // to be correct. "eax" is used here for this purpose. const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax"); if (!reg_info_32) return false; // TODO this should actually never happen @@ -364,8 +361,8 @@ Status ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, } // Following "IF ELSE" block categorizes various 'Fundamental Data Types'. - // The terminology 'Fundamental Data Types' used here is adopted from - // Table 2.1 of the reference document (specified on top of this file) + // The terminology 'Fundamental Data Types' used here is adopted from Table + // 2.1 of the reference document (specified on top of this file) if (type_flags & eTypeIsPointer) // 'Pointer' { @@ -390,8 +387,8 @@ Status ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, default: break; case 16: - // For clang::BuiltinType::UInt128 & Int128 - // ToDo: Need to decide how to handle it + // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to + // handle it break; case 8: { uint32_t raw_value_low = data.GetMaxU32(&offset, 4); @@ -470,8 +467,8 @@ Status ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, error.SetErrorString("Implementation is missing for this clang type."); } } else { - // Neither 'Integral' nor 'Floating Point'. If flow reaches here - // then check type_flags. This type_flags is not a valid type. + // Neither 'Integral' nor 'Floating Point'. If flow reaches here then + // check type_flags. This type_flags is not a valid type. error.SetErrorString("Invalid clang type"); } } else { @@ -508,8 +505,8 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB]; // Following "IF ELSE" block categorizes various 'Fundamental Data Types'. - // The terminology 'Fundamental Data Types' used here is adopted from - // Table 2.1 of the reference document (specified on top of this file) + // The terminology 'Fundamental Data Types' used here is adopted from Table + // 2.1 of the reference document (specified on top of this file) if (type_flags & eTypeIsPointer) // 'Pointer' { @@ -543,8 +540,8 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( break; case 16: - // For clang::BuiltinType::UInt128 & Int128 - // ToDo: Need to decide how to handle it + // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to + // handle it break; case 8: @@ -612,8 +609,8 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( success = true; } else if (byte_size == 8) // double is 8 bytes { - // On Android Platform: long double is also 8 bytes - // It will be handled here only. + // 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; @@ -639,8 +636,8 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( } } else // Neither 'Integral' nor 'Floating Point' { - // If flow reaches here then check type_flags - // This type_flags is unhandled + // If flow reaches here then check type_flags This type_flags is + // unhandled } } else if (type_flags & eTypeIsComplex) // 'Complex Floating Point' { @@ -797,9 +794,9 @@ bool ABISysV_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { return true; } -// According to "Register Usage" in reference document (specified on top -// of this source file) ebx, ebp, esi, edi and esp registers are preserved -// i.e. non-volatile i.e. callee-saved on i386 +// According to "Register Usage" in reference document (specified on top of +// this source file) ebx, ebp, esi, edi and esp registers are preserved i.e. +// non-volatile i.e. callee-saved on i386 bool ABISysV_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { if (!reg_info) return false; diff --git a/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp b/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp index 95e2a7b0afeb..ce02f8677a63 100644 --- a/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp +++ b/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp @@ -698,8 +698,8 @@ bool ABISysV_mips::PrepareTrivialCall(Thread &thread, addr_t sp, if (log) log->Printf("Writing r25: 0x%" PRIx64, (uint64_t)func_addr); - // All callers of position independent functions must place the address of the - // called function in t9 (r25) + // All callers of position independent functions must place the address of + // the called function in t9 (r25) if (!reg_ctx->WriteRegisterFromUnsigned(r25_info, func_addr)) return false; @@ -867,8 +867,8 @@ ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl( UINT32_MAX; value.GetScalar() = ptr; } else if (return_compiler_type.IsAggregateType()) { - // Structure/Vector is always passed in memory and pointer to that memory is - // passed in r2. + // Structure/Vector is always passed in memory and pointer to that memory + // is passed in r2. uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned( reg_ctx->GetRegisterInfoByName("r2", 0), 0); // We have got the address. Create a memory object out of it diff --git a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp index 749e170fa17d..b958abf25637 100644 --- a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp +++ b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp @@ -661,8 +661,8 @@ bool ABISysV_mips64::PrepareTrivialCall(Thread &thread, addr_t sp, if (log) log->Printf("Writing r25: 0x%" PRIx64, (uint64_t)func_addr); - // All callers of position independent functions must place the address of the - // called function in t9 (r25) + // All callers of position independent functions must place the address of + // the called function in t9 (r25) if (!reg_ctx->WriteRegisterFromUnsigned(r25_info, func_addr)) return false; @@ -1035,10 +1035,9 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( } } - // If we reach here, it means this structure either contains more than two - // fields or - // it contains at least one non floating point type. - // In that case, all fields are returned in GP return registers. + // If we reach here, it means this structure either contains more than + // two fields or it contains at least one non floating point type. In + // that case, all fields are returned in GP return registers. for (uint32_t idx = 0; idx < num_children; idx++) { uint64_t field_bit_offset = 0; bool is_signed; @@ -1049,8 +1048,8 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( const size_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 we don't know the size of the field (e.g. invalid type), just + // bail out if (field_byte_width == 0) break; @@ -1078,16 +1077,15 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( } } // 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. + // 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; use_r3 = 1; } else { - // There isn't any space left for this field, this should not happen - // as we have already checked - // the overall size is not greater than 16 bytes. For now, return a - // nullptr return value object. + // There isn't any space left for this field, this should not + // happen as we have already checked the overall size is not + // greater than 16 bytes. For now, return a nullptr return value + // object. return return_valobj_sp; } } @@ -1123,15 +1121,16 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( sucess = 1; } if (sucess) { - // The result is in our data buffer. Create a variable object out of it + // The result is in our data buffer. Create a variable object out of + // it return_valobj_sp = ValueObjectConstResult::Create( &thread, return_compiler_type, ConstString(""), return_ext); } return return_valobj_sp; } - // Any structure/vector greater than 16 bytes in size is returned in memory. - // The pointer to that memory is returned in r2. + // Any structure/vector greater than 16 bytes in size is returned in + // memory. The pointer to that memory is returned in r2. uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned( reg_ctx->GetRegisterInfoByName("r2", 0), 0); diff --git a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp index 2fee176739f3..e93dcdbe1a59 100644 --- a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp +++ b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp @@ -402,8 +402,8 @@ bool ABISysV_ppc::GetArgumentValues(Thread &thread, ValueList &values) const { if (!value) return false; - // We currently only support extracting values with Clang QualTypes. - // Do we care about others? + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? CompilerType compiler_type = value->GetCompilerType(); if (!compiler_type) return false; @@ -501,8 +501,8 @@ Status ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp, if (!set_it_simple) { // Okay we've got a structure or something that doesn't fit in a simple - // register. - // We should figure out where it really goes, but we don't support this yet. + // register. We should figure out where it really goes, but we don't + // support this yet. error.SetErrorString("We only support setting simple integer and float " "return types at present."); } @@ -735,10 +735,9 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( copy_from_offset = integer_bytes - 8; integer_bytes += field_byte_width; } else { - // The last field didn't fit. I can't see how that would happen w/o - // the overall size being - // greater than 16 bytes. For now, return a nullptr return value - // object. + // The last field didn't fit. I can't see how that would happen + // w/o the overall size being greater than 16 bytes. For now, + // return a nullptr return value object. return return_valobj_sp; } } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) { @@ -751,10 +750,9 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( fp_bytes += field_byte_width; } 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 will be stuffed into the appropriate GPR with them. + // 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 + // will be stuffed into the appropriate GPR with them. bool in_gpr; if (field_byte_offset % 8 == 0) { // We are at the beginning of one of the eightbytes, so check the @@ -776,9 +774,9 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( } } } else if (field_byte_offset % 4 == 0) { - // We are inside of an eightbyte, so see if the field before us is - // floating point: - // This could happen if somebody put padding in the structure. + // We are inside of an eightbyte, so see if the field before us + // is floating point: This could happen if somebody put padding + // in the structure. if (idx == 0) in_gpr = false; else { @@ -819,9 +817,9 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( } } - // These two tests are just sanity checks. If I somehow get the - // type calculation wrong above it is better to just return nothing - // than to assert or crash. + // These two tests are just sanity checks. If I somehow get the type + // calculation wrong above it is better to just return nothing than to + // assert or crash. if (!copy_from_extractor) return return_valobj_sp; if (copy_from_offset + field_byte_width > @@ -845,9 +843,8 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( // FIXME: This is just taking a guess, r3 may very well no longer hold the // return storage location. // If we are going to do this right, when we make a new frame we should - // check to see if it uses a memory - // return, and if we are at the first instruction and if so stash away the - // return location. Then we would + // check to see if it uses a memory return, and if we are at the first + // instruction and if so stash away the return location. Then we would // only return the memory return value if we know it is valid. if (is_memory) { @@ -918,9 +915,9 @@ bool ABISysV_ppc::RegisterIsVolatile(const RegisterInfo *reg_info) { // See "Register Usage" in the // "System V Application Binary Interface" -// "64-bit PowerPC ELF Application Binary Interface Supplement" -// current version is 1.9 released 2004 at -// http://refspecs.linuxfoundation.org/ELF/ppc/PPC-elf64abi-1.9.pdf +// "64-bit PowerPC ELF Application Binary Interface Supplement" current version +// is 1.9 released 2004 at http://refspecs.linuxfoundation.org/ELF/ppc/PPC- +// elf64abi-1.9.pdf bool ABISysV_ppc::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { if (reg_info) { diff --git a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp index 0348853c7fa0..d0140a0c894a 100644 --- a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp +++ b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp @@ -16,6 +16,8 @@ #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" @@ -23,6 +25,7 @@ #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" #include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -34,201 +37,48 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" -using namespace lldb; -using namespace lldb_private; +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" -enum dwarf_regnums { - dwarf_r0 = 0, - dwarf_r1, - dwarf_r2, - dwarf_r3, - dwarf_r4, - dwarf_r5, - dwarf_r6, - dwarf_r7, - dwarf_r8, - dwarf_r9, - dwarf_r10, - dwarf_r11, - dwarf_r12, - dwarf_r13, - dwarf_r14, - dwarf_r15, - dwarf_r16, - dwarf_r17, - dwarf_r18, - dwarf_r19, - dwarf_r20, - dwarf_r21, - dwarf_r22, - dwarf_r23, - dwarf_r24, - dwarf_r25, - dwarf_r26, - dwarf_r27, - dwarf_r28, - dwarf_r29, - dwarf_r30, - dwarf_r31, - dwarf_f0, - dwarf_f1, - dwarf_f2, - dwarf_f3, - dwarf_f4, - dwarf_f5, - dwarf_f6, - dwarf_f7, - dwarf_f8, - dwarf_f9, - dwarf_f10, - dwarf_f11, - dwarf_f12, - dwarf_f13, - dwarf_f14, - dwarf_f15, - dwarf_f16, - dwarf_f17, - dwarf_f18, - dwarf_f19, - dwarf_f20, - dwarf_f21, - dwarf_f22, - dwarf_f23, - dwarf_f24, - dwarf_f25, - dwarf_f26, - dwarf_f27, - dwarf_f28, - dwarf_f29, - dwarf_f30, - dwarf_f31, - dwarf_cr, - dwarf_fpscr, - dwarf_xer = 101, - dwarf_lr = 108, - dwarf_ctr, - dwarf_pc, - dwarf_cfa, -}; +#define DECLARE_REGISTER_INFOS_PPC64_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64.h" +#undef DECLARE_REGISTER_INFOS_PPC64_STRUCT -// Note that the size and offset will be updated by platform-specific classes. -#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ - { \ - #reg, alt, 8, 0, eEncodingUint, eFormatHex, {kind1, kind2, kind3, kind4 }, \ - nullptr, nullptr, nullptr, 0 \ - } +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT -static const RegisterInfo g_register_infos[] = { - // General purpose registers. eh_frame, DWARF, - // Generic, Process Plugin - DEFINE_GPR(r0, nullptr, dwarf_r0, dwarf_r0, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r1, "sp", dwarf_r1, dwarf_r1, LLDB_REGNUM_GENERIC_SP, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r2, nullptr, dwarf_r2, dwarf_r2, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r3, "arg1", dwarf_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG1, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r4, "arg2", dwarf_r4, dwarf_r4, LLDB_REGNUM_GENERIC_ARG2, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r5, "arg3", dwarf_r5, dwarf_r5, LLDB_REGNUM_GENERIC_ARG3, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r6, "arg4", dwarf_r6, dwarf_r6, LLDB_REGNUM_GENERIC_ARG4, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r7, "arg5", dwarf_r7, dwarf_r7, LLDB_REGNUM_GENERIC_ARG5, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r8, "arg6", dwarf_r8, dwarf_r8, LLDB_REGNUM_GENERIC_ARG6, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r9, "arg7", dwarf_r9, dwarf_r9, LLDB_REGNUM_GENERIC_ARG7, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r10, "arg8", dwarf_r10, dwarf_r10, LLDB_REGNUM_GENERIC_ARG8, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r11, nullptr, dwarf_r11, dwarf_r11, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r12, nullptr, dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r13, nullptr, dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r14, nullptr, dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r15, nullptr, dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r16, nullptr, dwarf_r16, dwarf_r16, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r17, nullptr, dwarf_r17, dwarf_r17, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r18, nullptr, dwarf_r18, dwarf_r18, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r19, nullptr, dwarf_r19, dwarf_r19, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r20, nullptr, dwarf_r20, dwarf_r20, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r21, nullptr, dwarf_r21, dwarf_r21, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r22, nullptr, dwarf_r22, dwarf_r22, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r23, nullptr, dwarf_r23, dwarf_r23, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r24, nullptr, dwarf_r24, dwarf_r24, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r25, nullptr, dwarf_r25, dwarf_r25, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r26, nullptr, dwarf_r26, dwarf_r26, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r27, nullptr, dwarf_r27, dwarf_r27, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r28, nullptr, dwarf_r28, dwarf_r28, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r29, nullptr, dwarf_r29, dwarf_r29, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r30, nullptr, dwarf_r30, dwarf_r30, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r31, nullptr, dwarf_r31, dwarf_r31, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(lr, "lr", dwarf_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, - LLDB_INVALID_REGNUM), - DEFINE_GPR(cr, "cr", dwarf_cr, dwarf_cr, LLDB_REGNUM_GENERIC_FLAGS, - LLDB_INVALID_REGNUM), - DEFINE_GPR(xer, "xer", dwarf_xer, dwarf_xer, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(ctr, "ctr", dwarf_ctr, dwarf_ctr, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM), - DEFINE_GPR(pc, "pc", dwarf_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, - LLDB_INVALID_REGNUM), - {nullptr, - nullptr, - 8, - 0, - eEncodingUint, - eFormatHex, - {dwarf_cfa, dwarf_cfa, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, - nullptr, - nullptr, - nullptr, - 0}}; - -static const uint32_t k_num_register_infos = - llvm::array_lengthof(g_register_infos); +using namespace lldb; +using namespace lldb_private; const lldb_private::RegisterInfo * ABISysV_ppc64::GetRegisterInfoArray(uint32_t &count) { - count = k_num_register_infos; - return g_register_infos; + if (GetByteOrder() == lldb::eByteOrderLittle) { + count = llvm::array_lengthof(g_register_infos_ppc64le); + return g_register_infos_ppc64le; + } else { + count = llvm::array_lengthof(g_register_infos_ppc64); + return g_register_infos_ppc64; + } } size_t ABISysV_ppc64::GetRedZoneSize() const { return 224; } +lldb::ByteOrder ABISysV_ppc64::GetByteOrder() const { + return GetProcessSP()->GetByteOrder(); +} + //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ ABISP -ABISysV_ppc64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; - if (arch.GetTriple().getArch() == llvm::Triple::ppc64) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_ppc64(process_sp)); - return g_abi_sp; +ABISysV_ppc64::CreateInstance(lldb::ProcessSP process_sp, + const ArchSpec &arch) { + if (arch.GetTriple().getArch() == llvm::Triple::ppc64 || + arch.GetTriple().getArch() == llvm::Triple::ppc64le) { + return ABISP(new ABISysV_ppc64(process_sp)); } return ABISP(); } @@ -280,28 +130,68 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, sp &= ~(0xfull); // 16-byte alignment - sp -= 8; + sp -= 544; // allocate frame to save TOC, RA and SP. Status error; + uint64_t reg_value; const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); ProcessSP process_sp(thread.GetProcess()); + const RegisterInfo *lr_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2); + const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12); - RegisterValue reg_value; - + // Save return address onto the stack. if (log) log->Printf("Pushing the return address onto the stack: 0x%" PRIx64 - ": 0x%" PRIx64, + "(+16): 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr); + if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error)) + return false; - // Save return address onto the stack - if (!process_sp->WritePointerToMemory(sp, return_addr, error)) + // Write the return address to link register. + if (log) + log->Printf("Writing LR: 0x%" PRIx64, (uint64_t)return_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr)) return false; - // %r1 is set to the actual stack value. + // Write target address to %r12 register. + if (log) + log->Printf("Writing R12: 0x%" PRIx64, (uint64_t)func_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) + return false; + + // Read TOC pointer value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); + + // Write TOC pointer onto the stack. + uint64_t stack_offset; + if (GetByteOrder() == lldb::eByteOrderLittle) + stack_offset = 24; + else + stack_offset = 40; + + if (log) + log->Printf("Writing R2 (TOC) at SP(0x%" PRIx64 ")+%d: 0x%" PRIx64, + (uint64_t)(sp + stack_offset), (int)stack_offset, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error)) + return false; + + // Read the current SP value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); + + // Save current SP onto the stack. + if (log) + log->Printf("Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, (uint64_t)sp, + (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp, reg_value, error)) + return false; + // %r1 is set to the actual stack value. if (log) log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); @@ -365,34 +255,23 @@ bool ABISysV_ppc64::GetArgumentValues(Thread &thread, ValueList &values) const { if (!sp) return false; - addr_t current_stack_argument = sp + 48; // jump over return address + uint64_t stack_offset; + if (GetByteOrder() == lldb::eByteOrderLittle) + stack_offset = 32; + else + stack_offset = 48; + // jump over return address. + addr_t current_stack_argument = sp + stack_offset; uint32_t argument_register_ids[8]; - argument_register_ids[0] = - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1) - ->kinds[eRegisterKindLLDB]; - argument_register_ids[1] = - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2) - ->kinds[eRegisterKindLLDB]; - argument_register_ids[2] = - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG3) - ->kinds[eRegisterKindLLDB]; - argument_register_ids[3] = - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG4) - ->kinds[eRegisterKindLLDB]; - argument_register_ids[4] = - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG5) - ->kinds[eRegisterKindLLDB]; - argument_register_ids[5] = - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG6) - ->kinds[eRegisterKindLLDB]; - argument_register_ids[6] = - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG7) - ->kinds[eRegisterKindLLDB]; - argument_register_ids[7] = - reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG8) - ->kinds[eRegisterKindLLDB]; + for (size_t i = 0; i < 8; ++i) { + argument_register_ids[i] = + reg_ctx + ->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1 + i) + ->kinds[eRegisterKindLLDB]; + } unsigned int current_argument_register = 0; @@ -402,8 +281,8 @@ bool ABISysV_ppc64::GetArgumentValues(Thread &thread, ValueList &values) const { if (!value) return false; - // We currently only support extracting values with Clang QualTypes. - // Do we care about others? + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? CompilerType compiler_type = value->GetCompilerType(); if (!compiler_type) return false; @@ -501,8 +380,8 @@ Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, if (!set_it_simple) { // Okay we've got a structure or something that doesn't fit in a simple - // register. - // We should figure out where it really goes, but we don't support this yet. + // register. We should figure out where it really goes, but we don't + // support this yet. error.SetErrorString("We only support setting simple integer and float " "return types at present."); } @@ -510,367 +389,584 @@ Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, return error; } -ValueObjectSP ABISysV_ppc64::GetReturnValueObjectSimple( - Thread &thread, CompilerType &return_compiler_type) const { - ValueObjectSP return_valobj_sp; - Value value; +// +// ReturnValueExtractor +// - if (!return_compiler_type) - return return_valobj_sp; +namespace { + +#define LOG_PREFIX "ReturnValueExtractor: " + +class ReturnValueExtractor { + // This class represents a register, from which data may be extracted. + // + // It may be constructed by directly specifying its index (where 0 is the + // first register used to return values) or by specifying the offset of a + // given struct field, in which case the appropriated register index will be + // calculated. + class Register { + public: + enum Type { + GPR, // General Purpose Register + FPR // Floating Point Register + }; + + // main constructor + // + // offs - field offset in struct + Register(Type ty, uint32_t index, uint32_t offs, RegisterContext *reg_ctx, + ByteOrder byte_order) + : m_index(index), m_offs(offs % sizeof(uint64_t)), + m_avail(sizeof(uint64_t) - m_offs), m_type(ty), m_reg_ctx(reg_ctx), + m_byte_order(byte_order) {} + + // explicit index, no offset + Register(Type ty, uint32_t index, RegisterContext *reg_ctx, + ByteOrder byte_order) + : Register(ty, index, 0, reg_ctx, byte_order) {} + + // GPR, calculate index from offs + Register(uint32_t offs, RegisterContext *reg_ctx, ByteOrder byte_order) + : Register(GPR, offs / sizeof(uint64_t), offs, reg_ctx, byte_order) {} + + uint32_t Index() const { return m_index; } + + // register offset where data is located + uint32_t Offs() const { return m_offs; } + + // available bytes in this register + uint32_t Avail() const { return m_avail; } + + bool IsValid() const { + if (m_index > 7) { + LLDB_LOG(m_log, LOG_PREFIX + "No more than 8 registers should be used to return values"); + return false; + } + return true; + } - // value.SetContext (Value::eContextTypeClangType, return_value_type); - value.SetCompilerType(return_compiler_type); + std::string GetName() const { + if (m_type == GPR) + return ("r" + llvm::Twine(m_index + 3)).str(); + else + return ("f" + llvm::Twine(m_index + 1)).str(); + } - RegisterContext *reg_ctx = thread.GetRegisterContext().get(); - if (!reg_ctx) - return return_valobj_sp; - - const uint32_t type_flags = return_compiler_type.GetTypeInfo(); - if (type_flags & eTypeIsScalar) { - value.SetValueType(Value::eValueTypeScalar); - - 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); - uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( - reg_ctx->GetRegisterInfoByName("r3", 0), 0); - const bool is_signed = (type_flags & eTypeIsSigned) != 0; - switch (byte_size) { - default: - break; - - case sizeof(uint64_t): - if (is_signed) - value.GetScalar() = (int64_t)(raw_value); - else - value.GetScalar() = (uint64_t)(raw_value); - success = true; - break; - - case sizeof(uint32_t): - if (is_signed) - value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); - else - value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); - success = true; - break; - - case sizeof(uint16_t): - if (is_signed) - value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); - else - value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); - success = true; - break; - - case sizeof(uint8_t): - if (is_signed) - value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); - else - value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); - success = true; - break; + // get raw register data + bool GetRawData(uint64_t &raw_data) { + const RegisterInfo *reg_info = + m_reg_ctx->GetRegisterInfoByName(GetName()); + if (!reg_info) { + LLDB_LOG(m_log, LOG_PREFIX "Failed to get RegisterInfo"); + return false; } - } else if (type_flags & eTypeIsFloat) { - 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)) { - 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)) { - value.GetScalar() = (float)data.GetFloat(&offset); - success = true; - } else if (byte_size == sizeof(double)) { - value.GetScalar() = (double)data.GetDouble(&offset); - success = true; - } - } - } - } + + RegisterValue reg_val; + if (!m_reg_ctx->ReadRegister(reg_info, reg_val)) { + LLDB_LOG(m_log, LOG_PREFIX "ReadRegister() failed"); + return false; } + + Status error; + uint32_t rc = reg_val.GetAsMemoryData( + reg_info, &raw_data, sizeof(raw_data), m_byte_order, error); + if (rc != sizeof(raw_data)) { + LLDB_LOG(m_log, LOG_PREFIX "GetAsMemoryData() failed"); + return false; + } + + return true; } - if (success) - return_valobj_sp = ValueObjectConstResult::Create( - thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); - } else if (type_flags & eTypeIsPointer) { - unsigned r3_id = - reg_ctx->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB]; - value.GetScalar() = - (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0); - value.SetValueType(Value::eValueTypeScalar); - 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) { - const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v2", 0); - if (altivec_reg) { - 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)); - const ByteOrder byte_order = process_sp->GetByteOrder(); - RegisterValue reg_value; - if (reg_ctx->ReadRegister(altivec_reg, reg_value)) { - Status error; - if (reg_value.GetAsMemoryData( - 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()); - return_valobj_sp = ValueObjectConstResult::Create( - &thread, return_compiler_type, ConstString(""), data); - } - } - } + private: + uint32_t m_index; + uint32_t m_offs; + uint32_t m_avail; + Type m_type; + RegisterContext *m_reg_ctx; + ByteOrder m_byte_order; + Log *m_log = + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + }; + + Register GetGPR(uint32_t index) const { + return Register(Register::GPR, index, m_reg_ctx, m_byte_order); + } + + Register GetFPR(uint32_t index) const { + return Register(Register::FPR, index, m_reg_ctx, m_byte_order); + } + + Register GetGPRByOffs(uint32_t offs) const { + return Register(offs, m_reg_ctx, m_byte_order); + } + +public: + // factory + static llvm::Expected<ReturnValueExtractor> Create(Thread &thread, + CompilerType &type) { + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return llvm::make_error<llvm::StringError>( + LOG_PREFIX "Failed to get RegisterContext", + llvm::inconvertibleErrorCode()); + + ProcessSP process_sp = thread.GetProcess(); + if (!process_sp) + return llvm::make_error<llvm::StringError>( + LOG_PREFIX "GetProcess() failed", llvm::inconvertibleErrorCode()); + + return ReturnValueExtractor(thread, type, reg_ctx, process_sp); + } + + // main method: get value of the type specified at construction time + ValueObjectSP GetValue() { + const uint32_t type_flags = m_type.GetTypeInfo(); + + // call the appropriate type handler + ValueSP value_sp; + ValueObjectSP valobj_sp; + if (type_flags & eTypeIsScalar) { + if (type_flags & eTypeIsInteger) { + value_sp = GetIntegerValue(0); + } else if (type_flags & eTypeIsFloat) { + if (type_flags & eTypeIsComplex) { + LLDB_LOG(m_log, LOG_PREFIX "Complex numbers are not supported yet"); + return ValueObjectSP(); + } else { + value_sp = GetFloatValue(m_type, 0); } } + } else if (type_flags & eTypeIsPointer) { + value_sp = GetPointerValue(0); } + + if (value_sp) { + valobj_sp = ValueObjectConstResult::Create( + m_thread.GetStackFrameAtIndex(0).get(), *value_sp, ConstString("")); + } else if (type_flags & eTypeIsVector) { + valobj_sp = GetVectorValueObject(); + } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass) { + valobj_sp = GetStructValueObject(); + } + + return valobj_sp; } - return return_valobj_sp; -} +private: + // data + Thread &m_thread; + CompilerType &m_type; + uint64_t m_byte_size; + std::unique_ptr<DataBufferHeap> m_data_ap; + int32_t m_src_offs = 0; + int32_t m_dst_offs = 0; + bool m_packed = false; + Log *m_log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + RegisterContext *m_reg_ctx; + ProcessSP m_process_sp; + ByteOrder m_byte_order; + uint32_t m_addr_size; + + // methods + + // constructor + 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_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( + process_sp->GetTarget().GetArchitecture().GetAddressByteSize()) {} + + // build a new scalar value + ValueSP NewScalarValue(CompilerType &type) { + ValueSP value_sp(new Value); + value_sp->SetCompilerType(type); + value_sp->SetValueType(Value::eValueTypeScalar); + return value_sp; + } -ValueObjectSP ABISysV_ppc64::GetReturnValueObjectImpl( - Thread &thread, CompilerType &return_compiler_type) const { - ValueObjectSP return_valobj_sp; - - if (!return_compiler_type) - return return_valobj_sp; - - ExecutionContext exe_ctx(thread.shared_from_this()); - return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type); - if (return_valobj_sp) - return return_valobj_sp; - - RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); - if (!reg_ctx_sp) - return return_valobj_sp; - - const size_t bit_width = return_compiler_type.GetBitSize(&thread); - if (return_compiler_type.IsAggregateType()) { - Target *target = exe_ctx.GetTargetPtr(); - bool is_memory = true; - 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, - target->GetArchitecture().GetAddressByteSize()); - - const RegisterInfo *r3_info = reg_ctx_sp->GetRegisterInfoByName("r3", 0); - const RegisterInfo *rdx_info = - reg_ctx_sp->GetRegisterInfoByName("rdx", 0); - - RegisterValue r3_value, rdx_value; - reg_ctx_sp->ReadRegister(r3_info, r3_value); - reg_ctx_sp->ReadRegister(rdx_info, rdx_value); - - DataExtractor r3_data, rdx_data; - - r3_value.GetData(r3_data); - rdx_value.GetData(rdx_data); - - uint32_t fp_bytes = - 0; // Tracks how much of the xmm registers we've consumed so far - uint32_t integer_bytes = - 0; // Tracks how much of the r3/rds registers we've consumed so far - - const uint32_t num_children = return_compiler_type.GetNumFields(); - - // Since we are in the small struct regime, assume we are not in memory. - is_memory = false; - - for (uint32_t idx = 0; idx < num_children; idx++) { - std::string name; - uint64_t field_bit_offset = 0; - bool is_signed; - bool is_complex; - uint32_t count; - - CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( - idx, name, &field_bit_offset, nullptr, nullptr); - const size_t field_bit_width = field_compiler_type.GetBitSize(&thread); - - // If there are any unaligned fields, this is stored in memory. - if (field_bit_offset % field_bit_width != 0) { - is_memory = true; - break; + // get an integer value in the specified register + ValueSP GetIntegerValue(uint32_t reg_index) { + uint64_t raw_value; + auto reg = GetGPR(reg_index); + if (!reg.GetRawData(raw_value)) + return ValueSP(); + + // build value from data + ValueSP value_sp(NewScalarValue(m_type)); + + uint32_t type_flags = m_type.GetTypeInfo(); + bool is_signed = (type_flags & eTypeIsSigned) != 0; + + switch (m_byte_size) { + case sizeof(uint64_t): + if (is_signed) + value_sp->GetScalar() = (int64_t)(raw_value); + else + value_sp->GetScalar() = (uint64_t)(raw_value); + break; + + case sizeof(uint32_t): + if (is_signed) + value_sp->GetScalar() = (int32_t)(raw_value & UINT32_MAX); + else + value_sp->GetScalar() = (uint32_t)(raw_value & UINT32_MAX); + break; + + case sizeof(uint16_t): + if (is_signed) + value_sp->GetScalar() = (int16_t)(raw_value & UINT16_MAX); + else + value_sp->GetScalar() = (uint16_t)(raw_value & UINT16_MAX); + break; + + case sizeof(uint8_t): + if (is_signed) + value_sp->GetScalar() = (int8_t)(raw_value & UINT8_MAX); + else + value_sp->GetScalar() = (uint8_t)(raw_value & UINT8_MAX); + break; + + default: + llvm_unreachable("Invalid integer size"); + } + + return value_sp; + } + + // get a floating point value on the specified register + ValueSP GetFloatValue(CompilerType &type, uint32_t reg_index) { + uint64_t raw_data; + auto reg = GetFPR(reg_index); + if (!reg.GetRawData(raw_data)) + return ValueSP(); + + // build value from data + ValueSP value_sp(NewScalarValue(type)); + + 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) { + case sizeof(float): + value_sp->GetScalar() = (float)de.GetDouble(&offset); + break; + + case sizeof(double): + value_sp->GetScalar() = de.GetDouble(&offset); + break; + + default: + llvm_unreachable("Invalid floating point size"); + } + + return value_sp; + } + + // get pointer value from register + ValueSP GetPointerValue(uint32_t reg_index) { + uint64_t raw_data; + auto reg = GetGPR(reg_index); + if (!reg.GetRawData(raw_data)) + return ValueSP(); + + // build value from raw data + ValueSP value_sp(NewScalarValue(m_type)); + value_sp->GetScalar() = raw_data; + return value_sp; + } + + // build the ValueObject from our data buffer + ValueObjectSP BuildValueObject() { + DataExtractor de(DataBufferSP(m_data_ap.release()), m_byte_order, + m_addr_size); + return ValueObjectConstResult::Create(&m_thread, m_type, ConstString(""), + de); + } + + // get a vector return value + ValueObjectSP GetVectorValueObject() { + const uint32_t MAX_VRS = 2; + + // get first V register used to return values + const RegisterInfo *vr[MAX_VRS]; + vr[0] = m_reg_ctx->GetRegisterInfoByName("vr2"); + if (!vr[0]) { + LLDB_LOG(m_log, LOG_PREFIX "Failed to get vr2 RegisterInfo"); + return ValueObjectSP(); + } + + const uint32_t vr_size = vr[0]->byte_size; + size_t vrs = 1; + if (m_byte_size > 2 * vr_size) { + LLDB_LOG( + m_log, LOG_PREFIX + "Returning vectors that don't fit in 2 VR regs is not supported"); + return ValueObjectSP(); + } + + // load vr3, if needed + if (m_byte_size > vr_size) { + vrs++; + vr[1] = m_reg_ctx->GetRegisterInfoByName("vr3"); + if (!vr[1]) { + LLDB_LOG(m_log, LOG_PREFIX "Failed to get vr3 RegisterInfo"); + return ValueObjectSP(); + } + } + + // Get the whole contents of vector registers and let the logic here + // arrange the data properly. + + RegisterValue vr_val[MAX_VRS]; + Status error; + std::unique_ptr<DataBufferHeap> vr_data( + new DataBufferHeap(vrs * vr_size, 0)); + + for (uint32_t i = 0; i < vrs; i++) { + if (!m_reg_ctx->ReadRegister(vr[i], vr_val[i])) { + LLDB_LOG(m_log, LOG_PREFIX "Failed to read vector register contents"); + return ValueObjectSP(); + } + if (!vr_val[i].GetAsMemoryData(vr[i], vr_data->GetBytes() + i * vr_size, + vr_size, m_byte_order, error)) { + LLDB_LOG(m_log, LOG_PREFIX "Failed to extract vector register bytes"); + return ValueObjectSP(); + } + } + + // The compiler generated code seems to always put the vector elements at + // the end of the vector register, in case they don't occupy all of it. + // This offset variable handles this. + uint32_t offs = 0; + if (m_byte_size < vr_size) + offs = vr_size - m_byte_size; + + // copy extracted data to our buffer + memcpy(m_data_ap->GetBytes(), vr_data->GetBytes() + offs, m_byte_size); + return BuildValueObject(); + } + + // get a struct return value + ValueObjectSP GetStructValueObject() { + // case 1: get from stack + if (m_byte_size > 2 * sizeof(uint64_t)) { + uint64_t addr; + auto reg = GetGPR(0); + if (!reg.GetRawData(addr)) + return ValueObjectSP(); + + Status error; + size_t rc = m_process_sp->ReadMemory(addr, m_data_ap->GetBytes(), + m_byte_size, error); + if (rc != m_byte_size) { + LLDB_LOG(m_log, LOG_PREFIX "Failed to read memory pointed by r3"); + return ValueObjectSP(); + } + return BuildValueObject(); + } + + // get number of children + const bool omit_empty_base_classes = true; + uint32_t n = m_type.GetNumChildren(omit_empty_base_classes); + if (!n) { + LLDB_LOG(m_log, LOG_PREFIX "No children found in struct"); + return ValueObjectSP(); + } + + // 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); + if (type_flags & eTypeIsComplex || !(type_flags & eTypeIsFloat)) { + LLDB_LOG(m_log, + LOG_PREFIX "Unexpected type found in homogeneous aggregate"); + return ValueObjectSP(); + } + + for (uint32_t i = 0; i < n; i++) { + ValueSP val_sp = GetFloatValue(elem_type, i); + if (!val_sp) + return ValueObjectSP(); + + // 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) { + LLDB_LOG(m_log, LOG_PREFIX "Failed to get float data"); + return ValueObjectSP(); } + m_dst_offs += elem_size; + } + return BuildValueObject(); + } - uint32_t field_byte_width = field_bit_width / 8; - uint32_t field_byte_offset = field_bit_offset / 8; - - DataExtractor *copy_from_extractor = nullptr; - uint32_t copy_from_offset = 0; - - if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) || - field_compiler_type.IsPointerType()) { - if (integer_bytes < 8) { - if (integer_bytes + field_byte_width <= 8) { - // This is in RAX, copy from register to our result structure: - copy_from_extractor = &r3_data; - copy_from_offset = integer_bytes; - integer_bytes += field_byte_width; - } else { - // The next field wouldn't fit in the remaining space, so we - // pushed it to rdx. - copy_from_extractor = &rdx_data; - copy_from_offset = 0; - integer_bytes = 8 + field_byte_width; - } - } else if (integer_bytes + field_byte_width <= 16) { - copy_from_extractor = &rdx_data; - copy_from_offset = integer_bytes - 8; - integer_bytes += field_byte_width; - } else { - // The last field didn't fit. I can't see how that would happen w/o - // the overall size being - // greater than 16 bytes. For now, return a nullptr return value - // object. - return return_valobj_sp; - } - } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) { - // Structs with long doubles are always passed in memory. - if (field_bit_width == 128) { - is_memory = true; + // case 3: get from GPRs + + // first, check if this is a packed struct or not + ClangASTContext *ast = + llvm::dyn_cast<ClangASTContext>(m_type.GetTypeSystem()); + if (ast) { + clang::RecordDecl *record_decl = ClangASTContext::GetAsRecordDecl(m_type); + + if (record_decl) { + auto attrs = record_decl->attrs(); + for (const auto &attr : attrs) { + if (attr->getKind() == clang::attr::Packed) { + m_packed = true; break; - } else if (field_bit_width == 64) { - copy_from_offset = 0; - fp_bytes += field_byte_width; - } 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 will be stuffed into the appropriate GPR with them. - bool in_gpr; - if (field_byte_offset % 8 == 0) { - // We are at the beginning of one of the eightbytes, so check the - // next element (if any) - if (idx == num_children - 1) - in_gpr = false; - else { - uint64_t next_field_bit_offset = 0; - CompilerType next_field_compiler_type = - return_compiler_type.GetFieldAtIndex(idx + 1, name, - &next_field_bit_offset, - nullptr, nullptr); - if (next_field_compiler_type.IsIntegerOrEnumerationType( - is_signed)) - in_gpr = true; - else { - copy_from_offset = 0; - in_gpr = false; - } - } - } else if (field_byte_offset % 4 == 0) { - // We are inside of an eightbyte, so see if the field before us is - // floating point: - // This could happen if somebody put padding in the structure. - if (idx == 0) - in_gpr = false; - else { - uint64_t prev_field_bit_offset = 0; - CompilerType prev_field_compiler_type = - return_compiler_type.GetFieldAtIndex(idx - 1, name, - &prev_field_bit_offset, - nullptr, nullptr); - if (prev_field_compiler_type.IsIntegerOrEnumerationType( - is_signed)) - in_gpr = true; - else { - copy_from_offset = 4; - in_gpr = false; - } - } - } else { - is_memory = true; - continue; - } - - // Okay, we've figured out whether we are in GPR or XMM, now figure - // out which one. - if (in_gpr) { - if (integer_bytes < 8) { - // This is in RAX, copy from register to our result structure: - copy_from_extractor = &r3_data; - copy_from_offset = integer_bytes; - integer_bytes += field_byte_width; - } else { - copy_from_extractor = &rdx_data; - copy_from_offset = integer_bytes - 8; - integer_bytes += field_byte_width; - } - } else { - fp_bytes += field_byte_width; - } } } - - // These two tests are just sanity checks. If I somehow get the - // type calculation wrong above it is better to just return nothing - // than to assert or crash. - if (!copy_from_extractor) - return return_valobj_sp; - if (copy_from_offset + field_byte_width > - copy_from_extractor->GetByteSize()) - return return_valobj_sp; - - copy_from_extractor->CopyByteOrderedData( - copy_from_offset, field_byte_width, - data_sp->GetBytes() + field_byte_offset, field_byte_width, - target_byte_order); } + } - if (!is_memory) { - // The result is in our data buffer. Let's make a variable object out - // of it: - return_valobj_sp = ValueObjectConstResult::Create( - &thread, return_compiler_type, ConstString(""), return_ext); - } + LLDB_LOG(m_log, LOG_PREFIX "{0} struct", + m_packed ? "packed" : "not packed"); + + for (uint32_t i = 0; i < n; i++) { + std::string name; + uint32_t size; + GetChildType(i, name, size); + // NOTE: the offset returned by GetChildCompilerTypeAtIndex() + // can't be used because it never considers alignment bytes + // between struct fields. + LLDB_LOG(m_log, LOG_PREFIX "field={0}, size={1}", name, size); + if (!ExtractField(size)) + return ValueObjectSP(); } - // FIXME: This is just taking a guess, r3 may very well no longer hold the - // return storage location. - // If we are going to do this right, when we make a new frame we should - // check to see if it uses a memory - // return, and if we are at the first instruction and if so stash away the - // return location. Then we would - // only return the memory return value if we know it is valid. - - if (is_memory) { - unsigned r3_id = - reg_ctx_sp->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB]; - lldb::addr_t storage_addr = - (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, - 0); - return_valobj_sp = ValueObjectMemory::Create( - &thread, "", Address(storage_addr, nullptr), return_compiler_type); + return BuildValueObject(); + } + + // extract 'size' bytes at 'offs' from GPRs + bool ExtractFromRegs(int32_t offs, uint32_t size, void *buf) { + while (size) { + auto reg = GetGPRByOffs(offs); + if (!reg.IsValid()) + return false; + + uint32_t n = std::min(reg.Avail(), size); + uint64_t raw_data; + + if (!reg.GetRawData(raw_data)) + return false; + + memcpy(buf, (char *)&raw_data + reg.Offs(), n); + offs += n; + size -= n; + buf = (char *)buf + n; } + return true; } - return return_valobj_sp; + // extract one field from GPRs and put it in our buffer + bool ExtractField(uint32_t size) { + auto reg = GetGPRByOffs(m_src_offs); + if (!reg.IsValid()) + return false; + + // handle padding + if (!m_packed) { + uint32_t n = m_src_offs % size; + + // not 'size' bytes aligned + if (n) { + LLDB_LOG(m_log, + LOG_PREFIX "Extracting {0} alignment bytes at offset {1}", n, + m_src_offs); + // get alignment bytes + if (!ExtractFromRegs(m_src_offs, n, m_data_ap->GetBytes() + m_dst_offs)) + return false; + m_src_offs += n; + m_dst_offs += n; + } + } + + // get field + LLDB_LOG(m_log, LOG_PREFIX "Extracting {0} field bytes at offset {1}", size, + m_src_offs); + if (!ExtractFromRegs(m_src_offs, size, m_data_ap->GetBytes() + m_dst_offs)) + return false; + m_src_offs += size; + m_dst_offs += size; + return true; + } + + // get child + CompilerType GetChildType(uint32_t i, std::string &name, uint32_t &size) { + // GetChild constant inputs + const bool transparent_pointers = false; + const bool omit_empty_base_classes = true; + const bool ignore_array_bounds = false; + // GetChild output params + int32_t child_offs; + uint32_t child_bitfield_bit_size; + uint32_t child_bitfield_bit_offset; + bool child_is_base_class; + bool child_is_deref_of_parent; + ValueObject *valobj = nullptr; + uint64_t language_flags; + ExecutionContext exe_ctx; + m_thread.CalculateExecutionContext(exe_ctx); + + return m_type.GetChildCompilerTypeAtIndex( + &exe_ctx, i, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, name, size, child_offs, child_bitfield_bit_size, + child_bitfield_bit_offset, child_is_base_class, + child_is_deref_of_parent, valobj, language_flags); + } +}; + +#undef LOG_PREFIX + +} // anonymous namespace + +ValueObjectSP +ABISysV_ppc64::GetReturnValueObjectSimple(Thread &thread, + CompilerType &type) const { + if (!type) + return ValueObjectSP(); + + auto exp_extractor = ReturnValueExtractor::Create(thread, type); + if (!exp_extractor) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + LLDB_LOG_ERROR(log, exp_extractor.takeError(), + "Extracting return value failed: {0}"); + return ValueObjectSP(); + } + + return exp_extractor.get().GetValue(); +} + +ValueObjectSP ABISysV_ppc64::GetReturnValueObjectImpl( + Thread &thread, CompilerType &return_compiler_type) const { + return GetReturnValueObjectSimple(thread, return_compiler_type); } bool ABISysV_ppc64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { unwind_plan.Clear(); unwind_plan.SetRegisterKind(eRegisterKindDWARF); - uint32_t lr_reg_num = dwarf_lr; - uint32_t sp_reg_num = dwarf_r1; - uint32_t pc_reg_num = dwarf_pc; + uint32_t lr_reg_num; + uint32_t sp_reg_num; + uint32_t pc_reg_num; + + if (GetByteOrder() == lldb::eByteOrderLittle) { + lr_reg_num = ppc64le_dwarf::dwarf_lr_ppc64le; + sp_reg_num = ppc64le_dwarf::dwarf_r1_ppc64le; + pc_reg_num = ppc64le_dwarf::dwarf_pc_ppc64le; + } else { + lr_reg_num = ppc64_dwarf::dwarf_lr_ppc64; + sp_reg_num = ppc64_dwarf::dwarf_r1_ppc64; + pc_reg_num = ppc64_dwarf::dwarf_pc_ppc64; + } UnwindPlan::RowSP row(new UnwindPlan::Row); @@ -893,23 +989,33 @@ bool ABISysV_ppc64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { unwind_plan.Clear(); unwind_plan.SetRegisterKind(eRegisterKindDWARF); - uint32_t sp_reg_num = dwarf_r1; - uint32_t pc_reg_num = dwarf_lr; + uint32_t sp_reg_num; + uint32_t pc_reg_num; + uint32_t cr_reg_num; - UnwindPlan::RowSP row(new UnwindPlan::Row); + if (GetByteOrder() == lldb::eByteOrderLittle) { + sp_reg_num = ppc64le_dwarf::dwarf_r1_ppc64le; + pc_reg_num = ppc64le_dwarf::dwarf_lr_ppc64le; + cr_reg_num = ppc64le_dwarf::dwarf_cr_ppc64le; + } else { + sp_reg_num = ppc64_dwarf::dwarf_r1_ppc64; + pc_reg_num = ppc64_dwarf::dwarf_lr_ppc64; + cr_reg_num = ppc64_dwarf::dwarf_cr_ppc64; + } + UnwindPlan::RowSP row(new UnwindPlan::Row); const int32_t ptr_size = 8; row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true); row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); - row->SetRegisterLocationToAtCFAPlusOffset(dwarf_cr, ptr_size, true); + row->SetRegisterLocationToAtCFAPlusOffset(cr_reg_num, ptr_size, true); unwind_plan.AppendRow(row); unwind_plan.SetSourceName("ppc64 default unwind plan"); unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); - unwind_plan.SetReturnAddressRegister(dwarf_lr); + unwind_plan.SetReturnAddressRegister(pc_reg_num); return true; } @@ -919,10 +1025,9 @@ bool ABISysV_ppc64::RegisterIsVolatile(const RegisterInfo *reg_info) { // See "Register Usage" in the // "System V Application Binary Interface" -// "64-bit PowerPC ELF Application Binary Interface Supplement" -// current version is 1.9 released 2004 at -// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.pdf - +// "64-bit PowerPC ELF Application Binary Interface Supplement" current version +// is 2 released 2015 at +// https://members.openpowerfoundation.org/document/dl/576 bool ABISysV_ppc64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { if (reg_info) { // Preserved registers are : @@ -954,7 +1059,7 @@ bool ABISysV_ppc64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp return true; if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp - return true; + return false; if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc return true; } diff --git a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h index 21608a5c1cdd..52765a773c0b 100644 --- a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h +++ b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h @@ -108,6 +108,8 @@ private: ABISysV_ppc64(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) { // Call CreateInstance instead. } + + lldb::ByteOrder GetByteOrder() const; }; #endif // liblldb_ABISysV_ppc64_h_ diff --git a/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp b/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp index 967e407188fa..31e2825c0fa2 100644 --- a/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp +++ b/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp @@ -380,8 +380,8 @@ bool ABISysV_s390x::GetArgumentValues(Thread &thread, ValueList &values) const { if (!value) return false; - // We currently only support extracting values with Clang QualTypes. - // Do we care about others? + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? CompilerType compiler_type = value->GetCompilerType(); if (!compiler_type) return false; @@ -483,8 +483,8 @@ Status ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp, if (!set_it_simple) { // Okay we've got a structure or something that doesn't fit in a simple - // register. - // We should figure out where it really goes, but we don't support this yet. + // register. We should figure out where it really goes, but we don't + // support this yet. error.SetErrorString("We only support setting simple integer and float " "return types at present."); } @@ -618,9 +618,8 @@ ValueObjectSP ABISysV_s390x::GetReturnValueObjectImpl( // FIXME: This is just taking a guess, r2 may very well no longer hold the // return storage location. // If we are going to do this right, when we make a new frame we should - // check to see if it uses a memory - // return, and if we are at the first instruction and if so stash away the - // return location. Then we would + // check to see if it uses a memory return, and if we are at the first + // instruction and if so stash away the return location. Then we would // only return the memory return value if we know it is valid. unsigned r2_id = @@ -654,8 +653,8 @@ bool ABISysV_s390x::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { } bool ABISysV_s390x::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { - // There's really no default way to unwind on s390x. - // Trust the .eh_frame CFI, which should always be good. + // There's really no default way to unwind on s390x. Trust the .eh_frame CFI, + // which should always be good. return false; } @@ -663,8 +662,8 @@ bool ABISysV_s390x::GetFallbackRegisterLocation( const RegisterInfo *reg_info, UnwindPlan::Row::RegisterLocation &unwind_regloc) { // If a volatile register is being requested, we don't want to forward the - // next frame's register contents - // up the stack -- the register is not retrievable at this frame. + // next frame's register contents up the stack -- the register is not + // retrievable at this frame. if (RegisterIsVolatile(reg_info)) { unwind_regloc.SetUndefined(); return true; 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 41d146f24526..36ae3a49827c 100644 --- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp +++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp @@ -1267,8 +1267,8 @@ bool ABISysV_x86_64::GetArgumentValues(Thread &thread, if (!value) return false; - // We currently only support extracting values with Clang QualTypes. - // Do we care about others? + // We currently only support extracting values with Clang QualTypes. Do we + // care about others? CompilerType compiler_type = value->GetCompilerType(); if (!compiler_type) return false; @@ -1371,8 +1371,8 @@ Status ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, if (!set_it_simple) { // Okay we've got a structure or something that doesn't fit in a simple - // register. - // We should figure out where it really goes, but we don't support this yet. + // register. We should figure out where it really goes, but we don't + // support this yet. error.SetErrorString("We only support setting simple integer and float " "return types at present."); } @@ -1624,8 +1624,8 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( idx, name, &field_bit_offset, nullptr, nullptr); const size_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 we don't know the size of the field (e.g. invalid type), just + // bail out if (field_bit_width == 0) break; @@ -1661,10 +1661,9 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( copy_from_offset = integer_bytes - 8; integer_bytes += field_byte_width; } else { - // The last field didn't fit. I can't see how that would happen w/o - // the overall size being - // greater than 16 bytes. For now, return a nullptr return value - // object. + // The last field didn't fit. I can't see how that would happen + // w/o the overall size being greater than 16 bytes. For now, + // return a nullptr return value object. return return_valobj_sp; } } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) { @@ -1683,10 +1682,9 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( fp_bytes += field_byte_width; } 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 will be stuffed into the appropriate GPR with them. + // 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 + // will be stuffed into the appropriate GPR with them. bool in_gpr; if (field_byte_offset % 8 == 0) { // We are at the beginning of one of the eightbytes, so check the @@ -1708,9 +1706,9 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( } } } else if (field_byte_offset % 4 == 0) { - // We are inside of an eightbyte, so see if the field before us is - // floating point: - // This could happen if somebody put padding in the structure. + // We are inside of an eightbyte, so see if the field before us + // is floating point: This could happen if somebody put padding + // in the structure. if (idx == 0) in_gpr = false; else { @@ -1756,9 +1754,9 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( } } - // These two tests are just sanity checks. If I somehow get the - // type calculation wrong above it is better to just return nothing - // than to assert or crash. + // These two tests are just sanity checks. If I somehow get the type + // calculation wrong above it is better to just return nothing than to + // assert or crash. if (!copy_from_extractor) return return_valobj_sp; if (copy_from_offset + field_byte_width > @@ -1782,9 +1780,8 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( // FIXME: This is just taking a guess, rax may very well no longer hold the // return storage location. // If we are going to do this right, when we make a new frame we should - // check to see if it uses a memory - // return, and if we are at the first instruction and if so stash away the - // return location. Then we would + // check to see if it uses a memory return, and if we are at the first + // instruction and if so stash away the return location. Then we would // only return the memory return value if we know it is valid. if (is_memory) { @@ -1858,12 +1855,11 @@ bool ABISysV_x86_64::RegisterIsVolatile(const RegisterInfo *reg_info) { // See "Register Usage" in the // "System V Application Binary Interface" -// "AMD64 Architecture Processor Supplement" -// (or "x86-64(tm) Architecture Processor Supplement" in earlier revisions) -// (this doc is also commonly referred to as the x86-64/AMD64 psABI) -// Edited by Michael Matz, Jan Hubicka, Andreas Jaeger, and Mark Mitchell -// current version is 0.99.6 released 2012-07-02 at -// http://refspecs.linuxfoundation.org/elf/x86-64-abi-0.99.pdf +// "AMD64 Architecture Processor Supplement" (or "x86-64(tm) Architecture +// Processor Supplement" in earlier revisions) (this doc is also commonly +// referred to as the x86-64/AMD64 psABI) Edited by Michael Matz, Jan Hubicka, +// Andreas Jaeger, and Mark Mitchell current version is 0.99.6 released +// 2012-07-02 at http://refspecs.linuxfoundation.org/elf/x86-64-abi-0.99.pdf // It's being revised & updated at https://github.com/hjl-tools/x86-psABI/ bool ABISysV_x86_64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { diff --git a/source/Plugins/Architecture/Arm/ArchitectureArm.cpp b/source/Plugins/Architecture/Arm/ArchitectureArm.cpp index abac6d3001af..1b7ecc88c35e 100644 --- a/source/Plugins/Architecture/Arm/ArchitectureArm.cpp +++ b/source/Plugins/Architecture/Arm/ArchitectureArm.cpp @@ -41,32 +41,32 @@ std::unique_ptr<Architecture> ArchitectureArm::Create(const ArchSpec &arch) { ConstString ArchitectureArm::GetPluginName() { return GetPluginNameStatic(); } uint32_t ArchitectureArm::GetPluginVersion() { return 1; } -void ArchitectureArm::OverrideStopInfo(Thread &thread) { - // We need to check if we are stopped in Thumb mode in a IT instruction - // and detect if the condition doesn't pass. If this is the case it means - // we won't actually execute this instruction. If this happens we need to - // clear the stop reason to no thread plans think we are stopped for a - // reason and the plans should keep going. +void ArchitectureArm::OverrideStopInfo(Thread &thread) const { + // We need to check if we are stopped in Thumb mode in a IT instruction and + // detect if the condition doesn't pass. If this is the case it means we + // won't actually execute this instruction. If this happens we need to clear + // the stop reason to no thread plans think we are stopped for a reason and + // the plans should keep going. // // We do this because when single stepping many ARM processes, debuggers - // often use the BVR/BCR registers that says "stop when the PC is not - // equal to its current value". This method of stepping means we can end - // up stopping on instructions inside an if/then block that wouldn't get - // executed. By fixing this we can stop the debugger from seeming like - // you stepped through both the "if" _and_ the "else" clause when source - // level stepping because the debugger stops regardless due to the BVR/BCR + // often use the BVR/BCR registers that says "stop when the PC is not equal + // to its current value". This method of stepping means we can end up + // stopping on instructions inside an if/then block that wouldn't get + // executed. By fixing this we can stop the debugger from seeming like you + // stepped through both the "if" _and_ the "else" clause when source level + // stepping because the debugger stops regardless due to the BVR/BCR // triggering a stop. // - // It also means we can set breakpoints on instructions inside an an - // if/then block and correctly skip them if we use the BKPT instruction. - // The ARM and Thumb BKPT instructions are unconditional even when executed - // in a Thumb IT block. + // It also means we can set breakpoints on instructions inside an an if/then + // block and correctly skip them if we use the BKPT instruction. The ARM and + // Thumb BKPT instructions are unconditional even when executed in a Thumb IT + // block. // - // If your debugger inserts software traps in ARM/Thumb code, it will - // need to use 16 and 32 bit instruction for 16 and 32 bit thumb - // instructions respectively. If your debugger inserts a 16 bit thumb - // trap on top of a 32 bit thumb instruction for an opcode that is inside - // an if/then, it will change the it/then to conditionally execute your + // If your debugger inserts software traps in ARM/Thumb code, it will need to + // use 16 and 32 bit instruction for 16 and 32 bit thumb instructions + // respectively. If your debugger inserts a 16 bit thumb trap on top of a 32 + // bit thumb instruction for an opcode that is inside an if/then, it will + // change the it/then to conditionally execute your // 16 bit trap and then cause your program to crash if it executes the // trailing 16 bits (the second half of the 32 bit thumb instruction you // partially overwrote). @@ -85,23 +85,20 @@ void ArchitectureArm::OverrideStopInfo(Thread &thread) { const uint32_t ISETSTATE = J << 1 | T; if (ISETSTATE == 0) { // NOTE: I am pretty sure we want to enable the code below -// that detects when we stop on an instruction in ARM mode -// that is conditional and the condition doesn't pass. This -// can happen if you set a breakpoint on an instruction that -// is conditional. We currently will _always_ stop on the -// instruction which is bad. You can also run into this while -// single stepping and you could appear to run code in the "if" -// and in the "else" clause because it would stop at all of the -// conditional instructions in both. -// In such cases, we really don't want to stop at this location. +// that detects when we stop on an instruction in ARM mode that is conditional +// and the condition doesn't pass. This can happen if you set a breakpoint on +// an instruction that is conditional. We currently will _always_ stop on the +// instruction which is bad. You can also run into this while single stepping +// and you could appear to run code in the "if" and in the "else" clause +// because it would stop at all of the conditional instructions in both. In +// such cases, we really don't want to stop at this location. // I will check with the lldb-dev list first before I enable this. #if 0 - // ARM mode: check for condition on intsruction + // ARM mode: check for condition on instruction const addr_t pc = reg_ctx_sp->GetPC(); Status error; - // If we fail to read the opcode we will get UINT64_MAX as the - // result in "opcode" which we can use to detect if we read a - // valid opcode. + // If we fail to read the opcode we will get UINT64_MAX as the result in + // "opcode" which we can use to detect if we read a valid opcode. const uint64_t opcode = thread.GetProcess()->ReadUnsignedIntegerFromMemory(pc, 4, UINT64_MAX, error); if (opcode <= UINT32_MAX) { @@ -109,8 +106,8 @@ void ArchitectureArm::OverrideStopInfo(Thread &thread) { if (!ARMConditionPassed(condition, cpsr)) { // We ARE stopped on an ARM instruction whose condition doesn't - // pass so this instruction won't get executed. - // Regardless of why it stopped, we need to clear the stop info + // pass so this instruction won't get executed. Regardless of why + // it stopped, we need to clear the stop info thread.SetStopInfo (StopInfoSP()); } } diff --git a/source/Plugins/Architecture/Arm/ArchitectureArm.h b/source/Plugins/Architecture/Arm/ArchitectureArm.h index 9ce6c69ef271..484c4a52fcc6 100644 --- a/source/Plugins/Architecture/Arm/ArchitectureArm.h +++ b/source/Plugins/Architecture/Arm/ArchitectureArm.h @@ -23,7 +23,7 @@ public: ConstString GetPluginName() override; uint32_t GetPluginVersion() override; - void OverrideStopInfo(Thread &thread) override; + void OverrideStopInfo(Thread &thread) const override; private: static std::unique_ptr<Architecture> Create(const ArchSpec &arch); diff --git a/source/Plugins/Architecture/CMakeLists.txt b/source/Plugins/Architecture/CMakeLists.txt index 5abaa8e68231..01365a64cf96 100644 --- a/source/Plugins/Architecture/CMakeLists.txt +++ b/source/Plugins/Architecture/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(Arm) +add_subdirectory(PPC64) diff --git a/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp b/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp new file mode 100644 index 000000000000..619de093aacc --- /dev/null +++ b/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp @@ -0,0 +1,69 @@ +//===-- ArchitecturePPC64.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/PPC64/ArchitecturePPC64.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/ArchSpec.h" + +#include "llvm/BinaryFormat/ELF.h" + +using namespace lldb_private; +using namespace lldb; + +ConstString ArchitecturePPC64::GetPluginNameStatic() { + return ConstString("ppc64"); +} + +void ArchitecturePPC64::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "PPC64-specific algorithms", + &ArchitecturePPC64::Create); +} + +void ArchitecturePPC64::Terminate() { + PluginManager::UnregisterPlugin(&ArchitecturePPC64::Create); +} + +std::unique_ptr<Architecture> ArchitecturePPC64::Create(const ArchSpec &arch) { + if ((arch.GetMachine() != llvm::Triple::ppc64 && + arch.GetMachine() != llvm::Triple::ppc64le) || + arch.GetTriple().getObjectFormat() != llvm::Triple::ObjectFormatType::ELF) + return nullptr; + return std::unique_ptr<Architecture>(new ArchitecturePPC64()); +} + +ConstString ArchitecturePPC64::GetPluginName() { return GetPluginNameStatic(); } +uint32_t ArchitecturePPC64::GetPluginVersion() { return 1; } + +static int32_t GetLocalEntryOffset(const Symbol &sym) { + unsigned char other = sym.GetFlags() >> 8 & 0xFF; + return llvm::ELF::decodePPC64LocalEntryOffset(other); +} + +size_t ArchitecturePPC64::GetBytesToSkip(Symbol &func, + const Address &curr_addr) const { + if (curr_addr.GetFileAddress() == + func.GetFileAddress() + GetLocalEntryOffset(func)) + return func.GetPrologueByteSize(); + return 0; +} + +void ArchitecturePPC64::AdjustBreakpointAddress(const Symbol &func, + Address &addr) const { + int32_t loffs = GetLocalEntryOffset(func); + if (!loffs) + return; + + addr.SetOffset(addr.GetOffset() + loffs); +} diff --git a/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h b/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h new file mode 100644 index 000000000000..95638853ad3d --- /dev/null +++ b/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h @@ -0,0 +1,44 @@ +//===-- ArchitecturePPC64.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_PPC64_H +#define LLDB_PLUGIN_ARCHITECTURE_PPC64_H + +#include "lldb/Core/Architecture.h" + +namespace lldb_private { + +class ArchitecturePPC64 : 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 {} + + //------------------------------------------------------------------ + /// This method compares current address with current function's + /// local entry point, returning the bytes to skip if they match. + //------------------------------------------------------------------ + size_t GetBytesToSkip(Symbol &func, const Address &curr_addr) const override; + + void AdjustBreakpointAddress(const Symbol &func, + Address &addr) const override; + +private: + static std::unique_ptr<Architecture> Create(const ArchSpec &arch); + ArchitecturePPC64() = default; +}; + +} // namespace lldb_private + +#endif // LLDB_PLUGIN_ARCHITECTURE_PPC64_H diff --git a/source/Plugins/Architecture/PPC64/CMakeLists.txt b/source/Plugins/Architecture/PPC64/CMakeLists.txt new file mode 100644 index 000000000000..2cba112cf882 --- /dev/null +++ b/source/Plugins/Architecture/PPC64/CMakeLists.txt @@ -0,0 +1,11 @@ +add_lldb_library(lldbPluginArchitecturePPC64 PLUGIN + ArchitecturePPC64.cpp + + LINK_LIBS + lldbPluginProcessUtility + lldbCore + lldbTarget + lldbUtility + LINK_COMPONENTS + Support + ) diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp index a61abb9898ac..9b381dd3b96c 100644 --- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -10,6 +10,9 @@ // 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" @@ -27,9 +30,6 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" -// Other libraries and framework includes -#include "DisassemblerLLVMC.h" - #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/SymbolContext.h" @@ -41,13 +41,47 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/Stream.h" - #include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/Stream.h" using namespace lldb; using namespace lldb_private; +class DisassemblerLLVMC::MCDisasmInstance { +public: + static std::unique_ptr<MCDisasmInstance> + Create(const char *triple, const char *cpu, const char *features_str, + unsigned flavor, DisassemblerLLVMC &owner); + + ~MCDisasmInstance() = default; + + uint64_t GetMCInst(const uint8_t *opcode_data, size_t opcode_data_len, + lldb::addr_t pc, llvm::MCInst &mc_inst) const; + void PrintMCInst(llvm::MCInst &mc_inst, std::string &inst_string, + std::string &comments_string); + void SetStyle(bool use_hex_immed, HexImmediateStyle hex_style); + bool CanBranch(llvm::MCInst &mc_inst) const; + bool HasDelaySlot(llvm::MCInst &mc_inst) const; + bool IsCall(llvm::MCInst &mc_inst) const; + +private: + MCDisasmInstance(std::unique_ptr<llvm::MCInstrInfo> &&instr_info_up, + std::unique_ptr<llvm::MCRegisterInfo> &®_info_up, + std::unique_ptr<llvm::MCSubtargetInfo> &&subtarget_info_up, + std::unique_ptr<llvm::MCAsmInfo> &&asm_info_up, + std::unique_ptr<llvm::MCContext> &&context_up, + std::unique_ptr<llvm::MCDisassembler> &&disasm_up, + std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up); + + std::unique_ptr<llvm::MCInstrInfo> m_instr_info_up; + std::unique_ptr<llvm::MCRegisterInfo> m_reg_info_up; + std::unique_ptr<llvm::MCSubtargetInfo> m_subtarget_info_up; + std::unique_ptr<llvm::MCAsmInfo> m_asm_info_up; + std::unique_ptr<llvm::MCContext> m_context_up; + std::unique_ptr<llvm::MCDisassembler> m_disasm_up; + std::unique_ptr<llvm::MCInstPrinter> m_instr_printer_up; +}; + class InstructionLLVMC : public lldb_private::Instruction { public: InstructionLLVMC(DisassemblerLLVMC &disasm, @@ -72,7 +106,7 @@ public: bool is_alternate_isa; lldb::addr_t pc = m_address.GetFileAddress(); - DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = + DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr = GetDisasmToUse(is_alternate_isa); const uint8_t *opcode_data = data.GetDataStart(); const size_t opcode_data_len = data.GetByteSize(); @@ -107,7 +141,7 @@ public: bool is_alternate_isa; lldb::addr_t pc = m_address.GetFileAddress(); - DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = + DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr = GetDisasmToUse(is_alternate_isa); const uint8_t *opcode_data = data.GetDataStart(); const size_t opcode_data_len = data.GetByteSize(); @@ -132,19 +166,19 @@ public: return m_has_delay_slot == eLazyBoolYes; } - DisassemblerLLVMC::LLVMCDisassembler *GetDisasmToUse(bool &is_alternate_isa) { + 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_ap.get() != NULL) { + if (disasm_sp->m_alternate_disasm_up) { const AddressClass address_class = GetAddressClass(); - if (address_class == eAddressClassCodeAlternateISA) { + if (address_class == AddressClass::eCodeAlternateISA) { is_alternate_isa = true; - return disasm_sp->m_alternate_disasm_ap.get(); + return disasm_sp->m_alternate_disasm_up.get(); } } - return disasm_sp->m_disasm_ap.get(); + return disasm_sp->m_disasm_up.get(); } return nullptr; } @@ -197,7 +231,7 @@ public: } if (!got_op) { bool is_alternate_isa = false; - DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = + DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr = GetDisasmToUse(is_alternate_isa); const llvm::Triple::ArchType machine = arch.GetMachine(); @@ -264,12 +298,12 @@ public: std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler()); if (disasm_sp) { - DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr; + DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr; - if (address_class == eAddressClassCodeAlternateISA) - mc_disasm_ptr = disasm_sp->m_alternate_disasm_ap.get(); + if (address_class == AddressClass::eCodeAlternateISA) + mc_disasm_ptr = disasm_sp->m_alternate_disasm_up.get(); else - mc_disasm_ptr = disasm_sp->m_disasm_ap.get(); + mc_disasm_ptr = disasm_sp->m_disasm_up.get(); lldb::addr_t pc = m_address.GetFileAddress(); m_using_file_addr = true; @@ -850,7 +884,7 @@ public: bool is_alternate_isa; lldb::addr_t pc = m_address.GetFileAddress(); - DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = + DisassemblerLLVMC::MCDisasmInstance *mc_disasm_ptr = GetDisasmToUse(is_alternate_isa); const uint8_t *opcode_data = data.GetDataStart(); const size_t opcode_data_len = data.GetByteSize(); @@ -881,80 +915,103 @@ protected: bool m_using_file_addr; }; -DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler( - const char *triple, const char *cpu, const char *features_str, - unsigned flavor, DisassemblerLLVMC &owner) - : m_is_valid(true) { +std::unique_ptr<DisassemblerLLVMC::MCDisasmInstance> +DisassemblerLLVMC::MCDisasmInstance::Create(const char *triple, const char *cpu, + const char *features_str, + unsigned flavor, + DisassemblerLLVMC &owner) { + using Instance = std::unique_ptr<DisassemblerLLVMC::MCDisasmInstance>; + std::string Status; const llvm::Target *curr_target = llvm::TargetRegistry::lookupTarget(triple, Status); - if (!curr_target) { - m_is_valid = false; - return; - } + if (!curr_target) + return Instance(); - m_instr_info_ap.reset(curr_target->createMCInstrInfo()); - m_reg_info_ap.reset(curr_target->createMCRegInfo(triple)); - - m_subtarget_info_ap.reset( - curr_target->createMCSubtargetInfo(triple, cpu, features_str)); + std::unique_ptr<llvm::MCInstrInfo> instr_info_up( + curr_target->createMCInstrInfo()); + if (!instr_info_up) + return Instance(); - std::unique_ptr<llvm::MCRegisterInfo> reg_info( + std::unique_ptr<llvm::MCRegisterInfo> reg_info_up( curr_target->createMCRegInfo(triple)); - m_asm_info_ap.reset(curr_target->createMCAsmInfo(*reg_info, triple)); + if (!reg_info_up) + return Instance(); - if (m_instr_info_ap.get() == NULL || m_reg_info_ap.get() == NULL || - m_subtarget_info_ap.get() == NULL || m_asm_info_ap.get() == NULL) { - m_is_valid = false; - return; - } - - m_context_ap.reset( - new llvm::MCContext(m_asm_info_ap.get(), m_reg_info_ap.get(), 0)); - - m_disasm_ap.reset(curr_target->createMCDisassembler( - *m_subtarget_info_ap.get(), *m_context_ap.get())); - if (m_disasm_ap.get() && m_context_ap.get()) { - std::unique_ptr<llvm::MCRelocationInfo> RelInfo( - curr_target->createMCRelocationInfo(triple, *m_context_ap.get())); - if (!RelInfo) { - m_is_valid = false; - return; - } - std::unique_ptr<llvm::MCSymbolizer> symbolizer_up( - curr_target->createMCSymbolizer( - triple, NULL, DisassemblerLLVMC::SymbolLookupCallback, - (void *)&owner, m_context_ap.get(), std::move(RelInfo))); - m_disasm_ap->setSymbolizer(std::move(symbolizer_up)); - - unsigned asm_printer_variant; - if (flavor == ~0U) - asm_printer_variant = m_asm_info_ap->getAssemblerDialect(); - else { - asm_printer_variant = flavor; - } - - m_instr_printer_ap.reset(curr_target->createMCInstPrinter( - llvm::Triple{triple}, asm_printer_variant, *m_asm_info_ap.get(), - *m_instr_info_ap.get(), *m_reg_info_ap.get())); - if (m_instr_printer_ap.get() == NULL) { - m_disasm_ap.reset(); - m_is_valid = false; - } - } else - m_is_valid = false; + std::unique_ptr<llvm::MCSubtargetInfo> subtarget_info_up( + curr_target->createMCSubtargetInfo(triple, cpu, features_str)); + if (!subtarget_info_up) + return Instance(); + + std::unique_ptr<llvm::MCAsmInfo> asm_info_up( + curr_target->createMCAsmInfo(*reg_info_up, triple)); + if (!asm_info_up) + return Instance(); + + std::unique_ptr<llvm::MCContext> context_up( + new llvm::MCContext(asm_info_up.get(), reg_info_up.get(), 0)); + if (!context_up) + return Instance(); + + std::unique_ptr<llvm::MCDisassembler> disasm_up( + curr_target->createMCDisassembler(*subtarget_info_up, *context_up)); + if (!disasm_up) + return Instance(); + + std::unique_ptr<llvm::MCRelocationInfo> rel_info_up( + curr_target->createMCRelocationInfo(triple, *context_up)); + if (!rel_info_up) + return Instance(); + + std::unique_ptr<llvm::MCSymbolizer> symbolizer_up( + curr_target->createMCSymbolizer( + triple, nullptr, DisassemblerLLVMC::SymbolLookupCallback, &owner, + context_up.get(), std::move(rel_info_up))); + disasm_up->setSymbolizer(std::move(symbolizer_up)); + + unsigned asm_printer_variant = + flavor == ~0U ? asm_info_up->getAssemblerDialect() : flavor; + + std::unique_ptr<llvm::MCInstPrinter> instr_printer_up( + curr_target->createMCInstPrinter(llvm::Triple{triple}, + asm_printer_variant, *asm_info_up, + *instr_info_up, *reg_info_up)); + if (!instr_printer_up) + return Instance(); + + return Instance( + new MCDisasmInstance(std::move(instr_info_up), std::move(reg_info_up), + std::move(subtarget_info_up), std::move(asm_info_up), + std::move(context_up), std::move(disasm_up), + std::move(instr_printer_up))); } -DisassemblerLLVMC::LLVMCDisassembler::~LLVMCDisassembler() = default; +DisassemblerLLVMC::MCDisasmInstance::MCDisasmInstance( + std::unique_ptr<llvm::MCInstrInfo> &&instr_info_up, + std::unique_ptr<llvm::MCRegisterInfo> &®_info_up, + std::unique_ptr<llvm::MCSubtargetInfo> &&subtarget_info_up, + std::unique_ptr<llvm::MCAsmInfo> &&asm_info_up, + std::unique_ptr<llvm::MCContext> &&context_up, + std::unique_ptr<llvm::MCDisassembler> &&disasm_up, + std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up) + : m_instr_info_up(std::move(instr_info_up)), + m_reg_info_up(std::move(reg_info_up)), + m_subtarget_info_up(std::move(subtarget_info_up)), + m_asm_info_up(std::move(asm_info_up)), + m_context_up(std::move(context_up)), m_disasm_up(std::move(disasm_up)), + m_instr_printer_up(std::move(instr_printer_up)) { + assert(m_instr_info_up && m_reg_info_up && m_subtarget_info_up && + m_asm_info_up && m_context_up && m_disasm_up && m_instr_printer_up); +} -uint64_t DisassemblerLLVMC::LLVMCDisassembler::GetMCInst( +uint64_t DisassemblerLLVMC::MCDisasmInstance::GetMCInst( const uint8_t *opcode_data, size_t opcode_data_len, lldb::addr_t pc, - llvm::MCInst &mc_inst) { + llvm::MCInst &mc_inst) const { llvm::ArrayRef<uint8_t> data(opcode_data, opcode_data_len); llvm::MCDisassembler::DecodeStatus status; uint64_t new_inst_size; - status = m_disasm_ap->getInstruction(mc_inst, new_inst_size, data, pc, + status = m_disasm_up->getInstruction(mc_inst, new_inst_size, data, pc, llvm::nulls(), llvm::nulls()); if (status == llvm::MCDisassembler::Success) return new_inst_size; @@ -962,16 +1019,16 @@ uint64_t DisassemblerLLVMC::LLVMCDisassembler::GetMCInst( return 0; } -void DisassemblerLLVMC::LLVMCDisassembler::PrintMCInst( +void DisassemblerLLVMC::MCDisasmInstance::PrintMCInst( llvm::MCInst &mc_inst, std::string &inst_string, std::string &comments_string) { llvm::raw_string_ostream inst_stream(inst_string); llvm::raw_string_ostream comments_stream(comments_string); - m_instr_printer_ap->setCommentStream(comments_stream); - m_instr_printer_ap->printInst(&mc_inst, inst_stream, llvm::StringRef(), - *m_subtarget_info_ap); - m_instr_printer_ap->setCommentStream(llvm::nulls()); + m_instr_printer_up->setCommentStream(comments_stream); + m_instr_printer_up->printInst(&mc_inst, inst_stream, llvm::StringRef(), + *m_subtarget_info_up); + m_instr_printer_up->setCommentStream(llvm::nulls()); comments_stream.flush(); static std::string g_newlines("\r\n"); @@ -985,30 +1042,32 @@ void DisassemblerLLVMC::LLVMCDisassembler::PrintMCInst( } } -void DisassemblerLLVMC::LLVMCDisassembler::SetStyle( +void DisassemblerLLVMC::MCDisasmInstance::SetStyle( bool use_hex_immed, HexImmediateStyle hex_style) { - m_instr_printer_ap->setPrintImmHex(use_hex_immed); + m_instr_printer_up->setPrintImmHex(use_hex_immed); switch (hex_style) { case eHexStyleC: - m_instr_printer_ap->setPrintHexStyle(llvm::HexStyle::C); + m_instr_printer_up->setPrintHexStyle(llvm::HexStyle::C); break; case eHexStyleAsm: - m_instr_printer_ap->setPrintHexStyle(llvm::HexStyle::Asm); + m_instr_printer_up->setPrintHexStyle(llvm::HexStyle::Asm); break; } } -bool DisassemblerLLVMC::LLVMCDisassembler::CanBranch(llvm::MCInst &mc_inst) { - return m_instr_info_ap->get(mc_inst.getOpcode()) - .mayAffectControlFlow(mc_inst, *m_reg_info_ap.get()); +bool DisassemblerLLVMC::MCDisasmInstance::CanBranch( + llvm::MCInst &mc_inst) const { + return m_instr_info_up->get(mc_inst.getOpcode()) + .mayAffectControlFlow(mc_inst, *m_reg_info_up); } -bool DisassemblerLLVMC::LLVMCDisassembler::HasDelaySlot(llvm::MCInst &mc_inst) { - return m_instr_info_ap->get(mc_inst.getOpcode()).hasDelaySlot(); +bool DisassemblerLLVMC::MCDisasmInstance::HasDelaySlot( + llvm::MCInst &mc_inst) const { + return m_instr_info_up->get(mc_inst.getOpcode()).hasDelaySlot(); } -bool DisassemblerLLVMC::LLVMCDisassembler::IsCall(llvm::MCInst &mc_inst) { - return m_instr_info_ap->get(mc_inst.getOpcode()).isCall(); +bool DisassemblerLLVMC::MCDisasmInstance::IsCall(llvm::MCInst &mc_inst) const { + return m_instr_info_up->get(mc_inst.getOpcode()).isCall(); } DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, @@ -1023,8 +1082,7 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, llvm::Triple triple = arch.GetTriple(); // So far the only supported flavor is "intel" on x86. The base class will - // set this - // correctly coming in. + // set this correctly coming in. if (triple.getArch() == llvm::Triple::x86 || triple.getArch() == llvm::Triple::x86_64) { if (m_flavor == "intel") { @@ -1048,12 +1106,10 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, } // If no sub architecture specified then use the most recent arm architecture - // so the - // disassembler will return all instruction. Without it we will see a lot of - // unknow opcode - // in case the code uses instructions which are not available in the oldest - // arm version - // (used when no sub architecture is specified) + // so the disassembler will return all instruction. Without it we will see a + // lot of unknow opcode in case the code uses instructions which are not + // available in the oldest arm version (used when no sub architecture is + // specified) if (triple.getArch() == llvm::Triple::arm && triple.getSubArch() == llvm::Triple::NoSubArch) triple.setArchName("armv8.2a"); @@ -1127,20 +1183,16 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, features_str += "+dspr2,"; } - // If any AArch64 variant, enable the ARMv8.2 ISA - // extensions so we can disassemble newer instructions. + // If any AArch64 variant, enable the ARMv8.2 ISA extensions so we can + // disassemble newer instructions. if (triple.getArch() == llvm::Triple::aarch64) features_str += "+v8.2a"; - m_disasm_ap.reset(new LLVMCDisassembler(triple_str, cpu, features_str.c_str(), - flavor, *this)); - if (!m_disasm_ap->IsValid()) { - // We use m_disasm_ap.get() to tell whether we are valid or not, so if this - // isn't good for some reason, - // we reset it, and then we won't be valid and FindPlugin will fail and we - // won't get used. - m_disasm_ap.reset(); - } + // We use m_disasm_ap.get() to tell whether we are valid or not, so if this + // isn't good for some reason, we won't be valid and FindPlugin will fail and + // we won't get used. + m_disasm_up = MCDisasmInstance::Create(triple_str, cpu, features_str.c_str(), + flavor, *this); llvm::Triple::ArchType llvm_arch = triple.getArch(); @@ -1148,12 +1200,11 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, // thumb instruction disassembler. if (llvm_arch == llvm::Triple::arm) { std::string thumb_triple(thumb_arch.GetTriple().getTriple()); - m_alternate_disasm_ap.reset( - new LLVMCDisassembler(thumb_triple.c_str(), "", "", flavor, *this)); - if (!m_alternate_disasm_ap->IsValid()) { - m_disasm_ap.reset(); - m_alternate_disasm_ap.reset(); - } + m_alternate_disasm_up = + MCDisasmInstance::Create(thumb_triple.c_str(), "", "", flavor, *this); + if (!m_alternate_disasm_up) + m_disasm_up.reset(); + } else if (llvm_arch == llvm::Triple::mips || llvm_arch == llvm::Triple::mipsel || llvm_arch == llvm::Triple::mips64 || @@ -1165,12 +1216,10 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, else if (arch_flags & ArchSpec::eMIPSAse_micromips) features_str += "+micromips,"; - m_alternate_disasm_ap.reset(new LLVMCDisassembler( - triple_str, cpu, features_str.c_str(), flavor, *this)); - if (!m_alternate_disasm_ap->IsValid()) { - m_disasm_ap.reset(); - m_alternate_disasm_ap.reset(); - } + m_alternate_disasm_up = MCDisasmInstance::Create( + triple_str, cpu, features_str.c_str(), flavor, *this); + if (!m_alternate_disasm_up) + m_disasm_up.reset(); } } @@ -1208,9 +1257,9 @@ size_t DisassemblerLLVMC::DecodeInstructions(const Address &base_addr, while (data_cursor < data_byte_size && instructions_parsed < num_instructions) { - AddressClass address_class = eAddressClassCode; + AddressClass address_class = AddressClass::eCode; - if (m_alternate_disasm_ap.get() != NULL) + if (m_alternate_disasm_up) address_class = inst_addr.GetAddressClass(); InstructionSP inst_sp( @@ -1285,6 +1334,8 @@ bool DisassemblerLLVMC::FlavorValidForArchSpec( return false; } +bool DisassemblerLLVMC::IsValid() const { return m_disasm_up.operator bool(); } + int DisassemblerLLVMC::OpInfo(uint64_t PC, uint64_t Offset, uint64_t Size, int tag_type, void *tag_bug) { switch (tag_type) { @@ -1337,8 +1388,8 @@ const char *DisassemblerLLVMC::SymbolLookup(uint64_t value, uint64_t *type_ptr, } } - // If the "value" address (the target address we're symbolicating) - // is inside the same SymbolContext as the current instruction pc + // If the "value" address (the target address we're symbolicating) is + // inside the same SymbolContext as the current instruction pc // (pc_so_addr), don't print the full function name - just print it // with DumpStyleNoFunctionName style, e.g. "<+36>". if (format_omitting_current_func_name) { @@ -1353,9 +1404,8 @@ const char *DisassemblerLLVMC::SymbolLookup(uint64_t value, uint64_t *type_ptr, if (!ss.GetString().empty()) { // If Address::Dump returned a multi-line description, most commonly - // seen when we - // have multiple levels of inlined functions at an address, only show - // the first line. + // seen when we have multiple levels of inlined functions at an + // address, only show the first line. std::string str = ss.GetString(); size_t first_eol_char = str.find_first_of("\r\n"); if (first_eol_char != std::string::npos) { diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h index 26bed7ee0d7b..b7e9ccb34701 100644 --- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h +++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h @@ -16,62 +16,14 @@ #include <mutex> #include <string> -// Other libraries and framework includes -#include "llvm-c/Disassembler.h" - // Project includes #include "lldb/Core/Address.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/PluginManager.h" -// Opaque references to C++ Objects in LLVM's MC. -namespace llvm { -class MCContext; -class MCInst; -class MCInstrInfo; -class MCRegisterInfo; -class MCDisassembler; -class MCInstPrinter; -class MCAsmInfo; -class MCSubtargetInfo; -} // namespace llvm - class InstructionLLVMC; class DisassemblerLLVMC : public lldb_private::Disassembler { - // Since we need to make two actual MC Disassemblers for ARM (ARM & THUMB), - // and there's a bit of goo to set up and own - // in the MC disassembler world, I added this class to manage the actual - // disassemblers. - class LLVMCDisassembler { - public: - LLVMCDisassembler(const char *triple, const char *cpu, - const char *features_str, unsigned flavor, - DisassemblerLLVMC &owner); - - ~LLVMCDisassembler(); - - uint64_t GetMCInst(const uint8_t *opcode_data, size_t opcode_data_len, - lldb::addr_t pc, llvm::MCInst &mc_inst); - void PrintMCInst(llvm::MCInst &mc_inst, std::string &inst_string, - std::string &comments_string); - void SetStyle(bool use_hex_immed, HexImmediateStyle hex_style); - bool CanBranch(llvm::MCInst &mc_inst); - bool HasDelaySlot(llvm::MCInst &mc_inst); - bool IsCall(llvm::MCInst &mc_inst); - bool IsValid() { return m_is_valid; } - - private: - bool m_is_valid; - std::unique_ptr<llvm::MCContext> m_context_ap; - std::unique_ptr<llvm::MCAsmInfo> m_asm_info_ap; - std::unique_ptr<llvm::MCSubtargetInfo> m_subtarget_info_ap; - std::unique_ptr<llvm::MCInstrInfo> m_instr_info_ap; - std::unique_ptr<llvm::MCRegisterInfo> m_reg_info_ap; - std::unique_ptr<llvm::MCInstPrinter> m_instr_printer_ap; - std::unique_ptr<llvm::MCDisassembler> m_disasm_ap; - }; - public: DisassemblerLLVMC(const lldb_private::ArchSpec &arch, const char *flavor /* = NULL */); @@ -108,9 +60,7 @@ protected: bool FlavorValidForArchSpec(const lldb_private::ArchSpec &arch, const char *flavor) override; - bool IsValid() { - return (m_disasm_ap.get() != NULL && m_disasm_ap->IsValid()); - } + bool IsValid() const; int OpInfo(uint64_t PC, uint64_t Offset, uint64_t Size, int TagType, void *TagBug); @@ -145,8 +95,12 @@ protected: std::mutex m_mutex; bool m_data_from_file; - std::unique_ptr<LLVMCDisassembler> m_disasm_ap; - std::unique_ptr<LLVMCDisassembler> m_alternate_disasm_ap; + // Since we need to make two actual MC Disassemblers for ARM (ARM & THUMB), + // and there's a bit of goo to set up and own in the MC disassembler world, + // this class was added to manage the actual disassemblers. + class MCDisasmInstance; + std::unique_ptr<MCDisasmInstance> m_disasm_up; + std::unique_ptr<MCDisasmInstance> m_alternate_disasm_up; }; #endif // liblldb_DisassemblerLLVM_h_ diff --git a/source/Plugins/DynamicLoader/CMakeLists.txt b/source/Plugins/DynamicLoader/CMakeLists.txt index 8e1b316a3c25..9f3b2ab0e50f 100644 --- a/source/Plugins/DynamicLoader/CMakeLists.txt +++ b/source/Plugins/DynamicLoader/CMakeLists.txt @@ -1,9 +1,6 @@ +add_subdirectory(Darwin-Kernel) add_subdirectory(MacOSX-DYLD) add_subdirectory(POSIX-DYLD) add_subdirectory(Static) add_subdirectory(Hexagon-DYLD) add_subdirectory(Windows-DYLD) - -if (CMAKE_SYSTEM_NAME MATCHES "Darwin") - add_subdirectory(Darwin-Kernel) -endif() diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index a81a0306671e..8999000dff8c 100644 --- a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -8,8 +8,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Utility/SafeMachO.h" - #include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" @@ -45,10 +43,10 @@ using namespace lldb; using namespace lldb_private; -// Progressively greater amounts of scanning we will allow -// For some targets very early in startup, we can't do any random reads of -// memory or we can crash the device -// so a setting is needed that can completely disable the KASLR scans. +// Progressively greater amounts of scanning we will allow For some targets +// very early in startup, we can't do any random reads of memory or we can +// crash the device so a setting is needed that can completely disable the +// KASLR scans. enum KASLRScanType { eKASLRScanNone = 0, // No reading into the inferior at all @@ -122,15 +120,15 @@ static const DynamicLoaderDarwinKernelPropertiesSP &GetGlobalProperties() { } //---------------------------------------------------------------------- -// Create an instance of this class. This function is filled into -// the plugin info class that gets handed out by the plugin factory and -// allows the lldb to instantiate an instance of this class. +// Create an instance of this class. This function is filled into the plugin +// info class that gets handed out by the plugin factory and allows the lldb to +// instantiate an instance of this class. //---------------------------------------------------------------------- DynamicLoader *DynamicLoaderDarwinKernel::CreateInstance(Process *process, bool force) { if (!force) { - // If the user provided an executable binary and it is not a kernel, - // this plugin should not create an instance. + // If the user provided an executable binary and it is not a kernel, this + // plugin should not create an instance. Module *exe_module = process->GetTarget().GetExecutableModulePointer(); if (exe_module) { ObjectFile *object_file = exe_module->GetObjectFile(); @@ -155,8 +153,8 @@ DynamicLoader *DynamicLoaderDarwinKernel::CreateInstance(Process *process, return NULL; } break; - // If we have triple like armv7-unknown-unknown, we should try looking for a - // Darwin kernel. + // If we have triple like armv7-unknown-unknown, we should try looking for + // a Darwin kernel. case llvm::Triple::UnknownOS: break; default: @@ -166,9 +164,8 @@ DynamicLoader *DynamicLoaderDarwinKernel::CreateInstance(Process *process, } // At this point if there is an ExecutableModule, it is a kernel and the - // Target is some variant of an Apple system. - // If the Process hasn't provided the kernel load address, we need to look - // around in memory to find it. + // Target is some variant of an Apple system. If the Process hasn't provided + // the kernel load address, we need to look around in memory to find it. const addr_t kernel_load_address = SearchForDarwinKernel(process); if (CheckForKernelImageAtAddress(kernel_load_address, process).IsValid()) { @@ -197,10 +194,9 @@ DynamicLoaderDarwinKernel::SearchForDarwinKernel(Process *process) { } //---------------------------------------------------------------------- -// Check if the kernel binary is loaded in memory without a slide. -// First verify that the ExecutableModule is a kernel before we proceed. -// Returns the address of the kernel if one was found, else -// LLDB_INVALID_ADDRESS. +// Check if the kernel binary is loaded in memory without a slide. First verify +// that the ExecutableModule is a kernel before we proceed. Returns the address +// of the kernel if one was found, else LLDB_INVALID_ADDRESS. //---------------------------------------------------------------------- lldb::addr_t DynamicLoaderDarwinKernel::SearchForKernelAtSameLoadAddr(Process *process) { @@ -229,10 +225,8 @@ DynamicLoaderDarwinKernel::SearchForKernelAtSameLoadAddr(Process *process) { //---------------------------------------------------------------------- // If the debug flag is included in the boot-args nvram setting, the kernel's -// load address -// will be noted in the lowglo page at a fixed address -// Returns the address of the kernel if one was found, else -// LLDB_INVALID_ADDRESS. +// load address will be noted in the lowglo page at a fixed address Returns the +// address of the kernel if one was found, else LLDB_INVALID_ADDRESS. //---------------------------------------------------------------------- lldb::addr_t DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { @@ -282,8 +276,8 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { } //---------------------------------------------------------------------- -// If the kernel is currently executing when lldb attaches, and we don't have -// a better way of finding the kernel's load address, try searching backwards +// If the kernel is currently executing when lldb attaches, and we don't have a +// better way of finding the kernel's load address, try searching backwards // from the current pc value looking for the kernel's Mach header in memory. // Returns the address of the kernel if one was found, else // LLDB_INVALID_ADDRESS. @@ -304,9 +298,8 @@ DynamicLoaderDarwinKernel::SearchForKernelNearPC(Process *process) { return LLDB_INVALID_ADDRESS; // The kernel will load at at one megabyte boundary (0x100000), or at that - // boundary plus - // an offset of one page (0x1000) or two, or four (0x4000), depending on the - // device. + // boundary plus an offset of one page (0x1000) or two, or four (0x4000), + // depending on the device. // Round the current pc down to the nearest one megabyte boundary - the place // where we will start searching. @@ -329,11 +322,10 @@ DynamicLoaderDarwinKernel::SearchForKernelNearPC(Process *process) { } //---------------------------------------------------------------------- -// Scan through the valid address range for a kernel binary. -// This is uselessly slow in 64-bit environments so we don't even try it. -// This scan is not enabled by default even for 32-bit targets. -// Returns the address of the kernel if one was found, else -// LLDB_INVALID_ADDRESS. +// Scan through the valid address range for a kernel binary. This is uselessly +// slow in 64-bit environments so we don't even try it. This scan is not +// enabled by default even for 32-bit targets. Returns the address of the +// kernel if one was found, else LLDB_INVALID_ADDRESS. //---------------------------------------------------------------------- lldb::addr_t DynamicLoaderDarwinKernel::SearchForKernelViaExhaustiveSearch( Process *process) { @@ -374,47 +366,30 @@ lldb::addr_t DynamicLoaderDarwinKernel::SearchForKernelViaExhaustiveSearch( } //---------------------------------------------------------------------- -// Given an address in memory, look to see if there is a kernel image at that -// address. -// Returns a UUID; if a kernel was not found at that address, UUID.IsValid() -// will be false. +// Read the mach_header struct out of memory and return it. +// Returns true if the mach_header was successfully read, +// Returns false if there was a problem reading the header, or it was not +// a Mach-O header. //---------------------------------------------------------------------- -lldb_private::UUID -DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress(lldb::addr_t addr, - Process *process) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if (addr == LLDB_INVALID_ADDRESS) - return UUID(); - - if (log) - log->Printf("DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress: " - "looking for kernel binary at 0x%" PRIx64, - addr); - - // First try a quick test -- read the first 4 bytes and see if there is a - // valid Mach-O magic field there - // (the first field of the mach_header/mach_header_64 struct). +bool +DynamicLoaderDarwinKernel::ReadMachHeader(addr_t addr, Process *process, llvm::MachO::mach_header &header) { Status read_error; - uint8_t magicbuf[4]; - if (process->ReadMemoryFromInferior (addr, magicbuf, sizeof (magicbuf), read_error) != sizeof (magicbuf)) - return UUID(); + + // Read the mach header and see whether it looks like a kernel + if (process->DoReadMemory (addr, &header, sizeof(header), read_error) != + sizeof(header)) + return false; const uint32_t magicks[] = { llvm::MachO::MH_MAGIC_64, llvm::MachO::MH_MAGIC, llvm::MachO::MH_CIGAM, llvm::MachO::MH_CIGAM_64}; bool found_matching_pattern = false; for (size_t i = 0; i < llvm::array_lengthof (magicks); i++) - if (::memcmp (magicbuf, &magicks[i], sizeof (magicbuf)) == 0) + if (::memcmp (&header.magic, &magicks[i], sizeof (uint32_t)) == 0) found_matching_pattern = true; if (found_matching_pattern == false) - return UUID(); - - // Read the mach header and see whether it looks like a kernel - llvm::MachO::mach_header header; - if (process->DoReadMemory(addr, &header, sizeof(header), read_error) != - sizeof(header)) - return UUID(); + return false; if (header.magic == llvm::MachO::MH_CIGAM || header.magic == llvm::MachO::MH_CIGAM_64) { @@ -427,6 +402,35 @@ DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress(lldb::addr_t addr, header.flags = llvm::ByteSwap_32(header.flags); } + return true; +} + +//---------------------------------------------------------------------- +// Given an address in memory, look to see if there is a kernel image at that +// address. +// Returns a UUID; if a kernel was not found at that address, UUID.IsValid() +// will be false. +//---------------------------------------------------------------------- +lldb_private::UUID +DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress(lldb::addr_t addr, + Process *process) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (addr == LLDB_INVALID_ADDRESS) + return UUID(); + + if (log) + log->Printf("DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress: " + "looking for kernel binary at 0x%" PRIx64, + addr); + + llvm::MachO::mach_header header; + + if (ReadMachHeader (addr, process, header) == false) + return UUID(); + + // First try a quick test -- read the first 4 bytes and see if there is a + // valid Mach-O magic field there + // (the first field of the mach_header/mach_header_64 struct). // A kernel is an executable which does not have the dynamic link object flag // set. if (header.filetype == llvm::MachO::MH_EXECUTE && @@ -630,10 +634,8 @@ UUID DynamicLoaderDarwinKernel::KextImageInfo::GetUUID() const { } // Given the m_load_address from the kext summaries, and a UUID, try to create -// an in-memory -// Module at that address. Require that the MemoryModule have a matching UUID -// and detect -// if this MemoryModule is a kernel or a kext. +// an in-memory Module at that address. Require that the MemoryModule have a +// matching UUID and detect if this MemoryModule is a kernel or a kext. // // Returns true if m_memory_module_sp is now set to a valid Module. @@ -646,10 +648,19 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::ReadMemoryModule( return false; FileSpec file_spec; - file_spec.SetFile(m_name.c_str(), false); + file_spec.SetFile(m_name.c_str(), false, FileSpec::Style::native); + + 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; + } ModuleSP memory_module_sp = - process->ReadModuleFromMemory(file_spec, m_load_address); + process->ReadModuleFromMemory(file_spec, m_load_address, size_to_read); if (memory_module_sp.get() == NULL) return false; @@ -668,10 +679,8 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::ReadMemoryModule( } // If this is a kext, and the kernel specified what UUID we should find at - // this - // load address, require that the memory module have a matching UUID or - // something - // has gone wrong and we should discard it. + // this load address, require that the memory module have a matching UUID or + // something has gone wrong and we should discard it. if (m_uuid.IsValid()) { if (m_uuid != memory_module_sp->GetUUID()) { if (log) { @@ -737,9 +746,8 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( Target &target = process->GetTarget(); - // If we don't have / can't create a memory module for this kext, don't try to - // load it - we won't - // have the correct segment load addresses. + // If we don't have / can't create a memory module for this kext, don't try + // to load it - we won't have the correct segment load addresses. if (!ReadMemoryModule(process)) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); if (log) @@ -772,9 +780,8 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( module_spec.GetUUID() = m_uuid; module_spec.GetArchitecture() = target.GetArchitecture(); - // For the kernel, we really do need an on-disk file copy of the binary to - // do anything useful. - // This will force a clal to + // For the kernel, we really do need an on-disk file copy of the binary + // to do anything useful. This will force a clal to if (IsKernel()) { if (Symbols::DownloadObjectAndSymbolFile(module_spec, true)) { if (module_spec.GetFileSpec().Exists()) { @@ -791,10 +798,8 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( } // If the current platform is PlatformDarwinKernel, create a ModuleSpec - // with the filename set - // to be the bundle ID for this kext, e.g. - // "com.apple.filesystems.msdosfs", and ask the platform - // to find it. + // with the filename set to be the bundle ID for this kext, e.g. + // "com.apple.filesystems.msdosfs", and ask the platform to find it. PlatformSP platform_sp(target.GetPlatform()); if (!m_module_sp && platform_sp) { ConstString platform_name(platform_sp->GetPluginName()); @@ -828,8 +833,9 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( } } - // If we managed to find a module, append it to the target's list of images. - // If we also have a memory module, require that they have matching UUIDs + // If we managed to find a module, append it to the target's list of + // images. If we also have a memory module, require that they have matching + // UUIDs if (m_module_sp) { bool uuid_match_ok = true; if (m_memory_module_sp) { @@ -871,15 +877,15 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( SectionList *memory_section_list = memory_object_file->GetSectionList(); if (memory_section_list && ondisk_section_list) { const uint32_t num_ondisk_sections = ondisk_section_list->GetSize(); - // There may be CTF sections in the memory image so we can't - // always just compare the number of sections (which are actually - // segments in mach-o parlance) + // There may be CTF sections in the memory image so we can't always + // just compare the number of sections (which are actually segments + // in mach-o parlance) uint32_t sect_idx = 0; - // Use the memory_module's addresses for each section to set the - // file module's load address as appropriate. We don't want to use - // a single slide value for the entire kext - different segments may - // be slid different amounts by the kext loader. + // Use the memory_module's addresses for each section to set the file + // module's load address as appropriate. We don't want to use a + // single slide value for the entire kext - different segments may be + // slid different amounts by the kext loader. uint32_t num_sections_loaded = 0; for (sect_idx = 0; sect_idx < num_ondisk_sections; ++sect_idx) { @@ -969,10 +975,9 @@ DynamicLoaderDarwinKernel::KextImageInfo::GetArchitecture() const { } //---------------------------------------------------------------------- -// Load the kernel module and initialize the "m_kernel" member. Return -// true _only_ if the kernel is loaded the first time through (subsequent -// calls to this function should return false after the kernel has been -// already loaded). +// Load the kernel module and initialize the "m_kernel" member. Return true +// _only_ if the kernel is loaded the first time through (subsequent calls to +// this function should return false after the kernel has been already loaded). //---------------------------------------------------------------------- void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() { if (!m_kext_summary_header_ptr_addr.IsValid()) { @@ -996,9 +1001,8 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() { m_kernel.SetLoadAddress(m_kernel_load_address); if (m_kernel.GetLoadAddress() == LLDB_INVALID_ADDRESS && m_kernel.GetModule()) { - // We didn't get a hint from the process, so we will - // try the kernel at the address that it exists at in - // the file if we have one + // We didn't get a hint from the process, so we will try the kernel at + // the address that it exists at in the file if we have one ObjectFile *kernel_object_file = m_kernel.GetModule()->GetObjectFile(); if (kernel_object_file) { addr_t load_address = @@ -1011,8 +1015,7 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() { if (load_address != file_address) { // Don't accidentally relocate the kernel to the File address -- // the Load address has already been set to its actual in-memory - // address. - // Mark it as IsLoaded. + // address. Mark it as IsLoaded. m_kernel.SetProcessStopId(m_process->GetStopID()); } } else { @@ -1028,10 +1031,10 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() { } } - // The operating system plugin gets loaded and initialized in - // LoadImageUsingMemoryModule when we discover the kernel dSYM. For a - // core file in particular, that's the wrong place to do this, since - // we haven't fixed up the section addresses yet. So let's redo it here. + // The operating system plugin gets loaded and initialized in + // LoadImageUsingMemoryModule when we discover the kernel dSYM. For a core + // file in particular, that's the wrong place to do this, since we haven't + // fixed up the section addresses yet. So let's redo it here. LoadOperatingSystemPlugin(false); if (m_kernel.IsLoaded() && m_kernel.GetModule()) { @@ -1052,9 +1055,9 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() { //---------------------------------------------------------------------- // Static callback function that gets called when our DYLD notification -// breakpoint gets hit. We update all of our image infos and then -// let our super class DynamicLoader class decide if we should stop -// or not (based on global preference). +// breakpoint gets hit. We update all of our image infos and then let our super +// class DynamicLoader class decide if we should stop or not (based on global +// preference). //---------------------------------------------------------------------- bool DynamicLoaderDarwinKernel::BreakpointHitCallback( void *baton, StoppointCallbackContext *context, user_id_t break_id, @@ -1087,8 +1090,8 @@ bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() { const uint32_t addr_size = m_kernel.GetAddressByteSize(); const ByteOrder byte_order = m_kernel.GetByteOrder(); Status error; - // Read enough bytes for a "OSKextLoadedKextSummaryHeader" structure - // which is currently 4 uint32_t and a pointer. + // Read enough bytes for a "OSKextLoadedKextSummaryHeader" structure which + // is currently 4 uint32_t and a pointer. uint8_t buf[24]; DataExtractor data(buf, sizeof(buf), byte_order, addr_size); const size_t count = 4 * sizeof(uint32_t) + addr_size; @@ -1130,7 +1133,8 @@ bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() { return false; } } else { - // Versions less than 2 didn't have an entry size, it was hard coded + // Versions less than 2 didn't have an entry size, it was hard + // coded m_kext_summary_header.entry_size = KERNEL_MODULE_ENTRY_SIZE_VERSION_1; } @@ -1156,13 +1160,10 @@ bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() { } // We've either (a) just attached to a new kernel, or (b) the kexts-changed -// breakpoint was hit -// and we need to figure out what kexts have been added or removed. -// Read the kext summaries from the inferior kernel memory, compare them against -// the -// m_known_kexts vector and update the m_known_kexts vector as needed to keep in -// sync with the -// inferior. +// breakpoint was hit and we need to figure out what kexts have been added or +// removed. Read the kext summaries from the inferior kernel memory, compare +// them against the m_known_kexts vector and update the m_known_kexts vector as +// needed to keep in sync with the inferior. bool DynamicLoaderDarwinKernel::ParseKextSummaries( const Address &kext_summary_addr, uint32_t count) { @@ -1178,14 +1179,13 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries( return false; // read the plugin.dynamic-loader.darwin-kernel.load-kexts setting -- if the - // user requested no - // kext loading, don't print any messages about kexts & don't try to read - // them. + // user requested no kext loading, don't print any messages about kexts & + // don't try to read them. const bool load_kexts = GetGlobalProperties()->GetLoadKexts(); // By default, all kexts we've loaded in the past are marked as "remove" and - // all of the kexts - // we just found out about from ReadKextSummaries are marked as "add". + // all of the kexts we just found out about from ReadKextSummaries are marked + // as "add". std::vector<bool> to_be_removed(m_known_kexts.size(), true); std::vector<bool> to_be_added(count, true); @@ -1195,8 +1195,8 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries( const uint32_t new_kexts_size = kext_summaries.size(); const uint32_t old_kexts_size = m_known_kexts.size(); - // The m_known_kexts vector may have entries that have been Cleared, - // or are a kernel. + // The m_known_kexts vector may have entries that have been Cleared, or are a + // kernel. for (uint32_t old_kext = 0; old_kext < old_kexts_size; old_kext++) { bool ignore = false; KextImageInfo &image_info = m_known_kexts[old_kext]; @@ -1229,10 +1229,9 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries( break; } } - // If this "kext" entry is actually an alias for the kernel -- - // the kext was compiled into the kernel or something -- then - // we don't want to load the kernel's text section at a different - // address. Ignore this kext entry. + // If this "kext" entry is actually an alias for the kernel -- the kext was + // compiled into the kernel or something -- then we don't want to load the + // kernel's text section at a different address. Ignore this kext entry. if (kext_summaries[new_kext].GetUUID().IsValid() && m_kernel.GetUUID().IsValid() && kext_summaries[new_kext].GetUUID() == m_kernel.GetUUID()) { @@ -1322,9 +1321,8 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries( s->Printf("."); image_info.Clear(); // should pull it out of the KextImageInfos vector but that would - // mutate the list and invalidate - // the to_be_removed bool vector; leaving it in place once Cleared() - // is relatively harmless. + // mutate the list and invalidate the to_be_removed bool vector; + // leaving it in place once Cleared() is relatively harmless. } } m_process->GetTarget().ModulesDidUnload(unloaded_module_list, false); @@ -1370,7 +1368,7 @@ uint32_t DynamicLoaderDarwinKernel::ReadKextSummaries( if (name_data == NULL) break; image_infos[i].SetName((const char *)name_data); - UUID uuid(extractor.GetData(&offset, 16), 16); + UUID uuid = UUID::fromOptionalData(extractor.GetData(&offset, 16), 16); image_infos[i].SetUUID(uuid); image_infos[i].SetLoadAddress(extractor.GetU64(&offset)); image_infos[i].SetSize(extractor.GetU64(&offset)); @@ -1405,36 +1403,18 @@ bool DynamicLoaderDarwinKernel::ReadAllKextSummaries() { // Dump an image info structure to the file handle provided. //---------------------------------------------------------------------- void DynamicLoaderDarwinKernel::KextImageInfo::PutToLog(Log *log) const { - if (log == NULL) - return; - const uint8_t *u = static_cast<const uint8_t *>(m_uuid.GetBytes()); - if (m_load_address == LLDB_INVALID_ADDRESS) { - if (u) { - log->Printf("\tuuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2." - "2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X name=\"%s\" (UNLOADED)", - u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], u[9], - u[10], u[11], u[12], u[13], u[14], u[15], m_name.c_str()); - } else - log->Printf("\tname=\"%s\" (UNLOADED)", m_name.c_str()); + LLDB_LOG(log, "uuid={0} name=\"{1}\" (UNLOADED)", m_uuid.GetAsString(), + m_name); } else { - if (u) { - log->Printf("\taddr=0x%16.16" PRIx64 " size=0x%16.16" PRIx64 - " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-" - "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X name=\"%s\"", - m_load_address, m_size, u[0], u[1], u[2], u[3], u[4], u[5], - u[6], u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], - u[15], m_name.c_str()); - } else { - log->Printf("\t[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") name=\"%s\"", - m_load_address, m_load_address + m_size, m_name.c_str()); - } + LLDB_LOG(log, "addr={0:x+16} size={1:x+16} uuid={2} name=\"{3}\"", + m_load_address, m_size, m_uuid.GetAsString(), m_name); } } //---------------------------------------------------------------------- -// Dump the _dyld_all_image_infos members and all current image infos -// that we have parsed to the file handle provided. +// Dump the _dyld_all_image_infos members and all current image infos that we +// have parsed to the file handle provided. //---------------------------------------------------------------------- void DynamicLoaderDarwinKernel::PutToLog(Log *log) const { if (log == NULL) diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h index ad4f7c631d84..75998f1cc3be 100644 --- a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h +++ b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h @@ -17,6 +17,9 @@ #include <vector> // Other libraries and framework includes + +#include "lldb/Utility/SafeMachO.h" + // Project includes #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" @@ -284,6 +287,9 @@ protected: static lldb::addr_t SearchForKernelViaExhaustiveSearch(lldb_private::Process *process); + static bool + ReadMachHeader(lldb::addr_t addr, lldb_private::Process *process, llvm::MachO::mach_header &mh); + static lldb_private::UUID CheckForKernelImageAtAddress(lldb::addr_t addr, lldb_private::Process *process); diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp index d0d60017e869..5ca20229d018 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp @@ -127,8 +127,8 @@ void DynamicLoaderHexagonDYLD::DidAttach() { executable = GetTargetExecutable(); - // Find the difference between the desired load address in the elf file - // and the real load address in memory + // Find the difference between the desired load address in the elf file and + // the real load address in memory load_offset = ComputeLoadOffset(); // Check that there is a valid executable @@ -157,10 +157,10 @@ void DynamicLoaderHexagonDYLD::DidAttach() { // Callback for the target to give it the loaded module list m_process->GetTarget().ModulesDidLoad(module_list); - // Try to set a breakpoint at the rendezvous breakpoint. - // DidLaunch uses ProbeEntry() instead. That sets a breakpoint, - // at the dyld breakpoint address, with a callback so that when hit, - // the dyld structure can be parsed. + // Try to set a breakpoint at the rendezvous breakpoint. DidLaunch uses + // ProbeEntry() instead. That sets a breakpoint, at the dyld breakpoint + // address, with a callback so that when hit, the dyld structure can be + // parsed. if (!SetRendezvousBreakpoint()) { // fail } @@ -203,8 +203,8 @@ ModuleSP DynamicLoaderHexagonDYLD::GetTargetExecutable() { // TODO: What case is this code used? executable = target.GetSharedModule(module_spec); 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 + // 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); } @@ -270,9 +270,8 @@ bool DynamicLoaderHexagonDYLD::SetRendezvousBreakpoint() { // This is the original code, which want to look in the rendezvous structure // to find the breakpoint address. Its backwards for us, since we can easily - // find the breakpoint address, since it is exported in our executable. - // We however know that we cant read the Rendezvous structure until we have - // hit + // find the breakpoint address, since it is exported in our executable. We + // however know that we cant read the Rendezvous structure until we have hit // the breakpoint once. const ConstString dyldBpName("_rtld_debug_state"); addr_t break_addr = findSymbolAddress(m_process, dyldBpName); @@ -326,8 +325,8 @@ bool DynamicLoaderHexagonDYLD::RendezvousBreakpointHit( DynamicLoaderHexagonDYLD *dyld_instance = nullptr; dyld_instance = static_cast<DynamicLoaderHexagonDYLD *>(baton); - // if the dyld_instance is still not valid then - // try to locate it on the symbol table + // if the dyld_instance is still not valid then try to locate it on the + // symbol table if (!dyld_instance->m_rendezvous.IsValid()) { Process *proc = dyld_instance->m_process; @@ -480,8 +479,8 @@ void DynamicLoaderHexagonDYLD::LoadAllCurrentModules() { return; } - // The rendezvous class doesn't enumerate the main module, so track - // that ourselves here. + // The rendezvous class doesn't enumerate the main module, so track that + // ourselves here. ModuleSP executable = GetTargetExecutable(); m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); @@ -517,12 +516,11 @@ addr_t DynamicLoaderHexagonDYLD::ComputeLoadOffset() { return 0; } -// Here we must try to read the entry point directly from -// the elf header. This is possible if the process is not -// relocatable or dynamically linked. +// Here we must try to read the entry point directly from the elf header. This +// is possible if the process is not relocatable or dynamically linked. // -// an alternative is to look at the PC if we can be sure -// that we have connected when the process is at the entry point. +// an alternative is to look at the PC if we can be sure that we have connected +// when the process is at the entry point. // I dont think that is reliable for us. addr_t DynamicLoaderHexagonDYLD::GetEntryPoint() { if (m_entry_point != LLDB_INVALID_ADDRESS) diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp index c49cdc2f11b1..d5f60e07bd77 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp @@ -115,8 +115,8 @@ bool HexagonDYLDRendezvous::UpdateSOEntries() { if (m_current.map_addr == 0) return false; - // When the previous and current states are consistent this is the first - // time we have been asked to update. Just take a snapshot of the currently + // When the previous and current states are consistent this is the first time + // we have been asked to update. Just take a snapshot of the currently // loaded modules. if (m_previous.state == eConsistent && m_current.state == eConsistent) return TakeSnapshot(m_soentries); @@ -126,8 +126,8 @@ bool HexagonDYLDRendezvous::UpdateSOEntries() { if (m_current.state == eAdd || m_current.state == eDelete) { // this is a fudge so that we can clear the assert below. m_previous.state = eConsistent; - // We hit this assert on the 2nd run of this function after running the calc - // example + // We hit this assert on the 2nd run of this function after running the + // calc example assert(m_previous.state == eConsistent); m_soentries.clear(); m_added_soentries.clear(); @@ -159,9 +159,9 @@ bool HexagonDYLDRendezvous::UpdateSOEntriesForAddition() { if (!ReadSOEntryFromMemory(cursor, entry)) return false; - // Only add shared libraries and not the executable. - // On Linux this is indicated by an empty path in the entry. - // On FreeBSD it is the name of the executable. + // Only add shared libraries and not the executable. On Linux this is + // indicated by an empty path in the entry. On FreeBSD it is the name of + // the executable. if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) continue; @@ -204,9 +204,9 @@ bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) { if (!ReadSOEntryFromMemory(cursor, entry)) return false; - // Only add shared libraries and not the executable. - // On Linux this is indicated by an empty path in the entry. - // On FreeBSD it is the name of the executable. + // Only add shared libraries and not the executable. On Linux this is + // indicated by an empty path in the entry. On FreeBSD it is the name of + // the executable. if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) continue; diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h index b68f89b9ce83..bdf6bae75197 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h @@ -11,8 +11,10 @@ #define liblldb_HexagonDYLDRendezvous_H_ // C Includes +#include <limits.h> // for PATH_MAX // C++ Includes #include <list> +#include <map> #include <string> // Other libraries and framework includes @@ -24,12 +26,12 @@ class Process; } /// @class HexagonDYLDRendezvous -/// @brief Interface to the runtime linker. +/// Interface to the runtime linker. /// /// A structure is present in a processes memory space which is updated by the -/// runtime liker each time a module is loaded or unloaded. This class provides -/// an interface to this structure and maintains a consistent snapshot of the -/// currently loaded modules. +/// runtime liker each time a module is loaded or unloaded. This class +/// provides an interface to this structure and maintains a consistent +/// snapshot of the currently loaded modules. class HexagonDYLDRendezvous { // This structure is used to hold the contents of the debug rendezvous @@ -124,7 +126,7 @@ public: void DumpToLog(lldb_private::Log *log) const; - /// @brief Constants describing the state of the rendezvous. + /// Constants describing the state of the rendezvous. /// /// @see GetState(). enum RendezvousState { @@ -133,8 +135,8 @@ public: eDelete, }; - /// @brief Structure representing the shared objects currently loaded into - /// the inferior process. + /// Structure representing the shared objects currently loaded into the + /// inferior process. /// /// This object is a rough analogue to the struct link_map object which /// actually lives in the inferiors memory. @@ -198,7 +200,8 @@ protected: /// List of SOEntry objects corresponding to the current link map state. SOEntryList m_soentries; - /// List of SOEntry's added to the link map since the last call to Resolve(). + /// List of SOEntry's added to the link map since the last call to + /// Resolve(). SOEntryList m_added_soentries; /// List of SOEntry's removed from the link map since the last call to diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 703b461f6fe1..c6439a30c8a3 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -112,8 +112,8 @@ ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo( if (module_sp && !module_spec.GetUUID().IsValid() && !module_sp->GetUUID().IsValid()) { - // No UUID, we must rely upon the cached module modification - // time and the modification time of the file on disk + // 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())) module_sp.reset(); @@ -198,8 +198,7 @@ void DynamicLoaderDarwin::UnloadAllImages() { ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i); // Don't remove dyld - else we'll lose our breakpoint notifying us about - // libraries - // being re-loaded... + // libraries being re-loaded... if (module_sp.get() != nullptr && module_sp.get() != dyld_sp.get()) { UnloadSections(module_sp); unloaded_modules_list.Append(module_sp); @@ -219,8 +218,8 @@ void DynamicLoaderDarwin::UnloadAllImages() { } //---------------------------------------------------------------------- -// Update the load addresses for all segments in MODULE using the -// updated INFO that is passed in. +// Update the load addresses for all segments in MODULE using the updated INFO +// that is passed in. //---------------------------------------------------------------------- bool DynamicLoaderDarwin::UpdateImageLoadAddress(Module *module, ImageInfo &info) { @@ -231,13 +230,12 @@ bool DynamicLoaderDarwin::UpdateImageLoadAddress(Module *module, SectionList *section_list = image_object_file->GetSectionList(); if (section_list) { std::vector<uint32_t> inaccessible_segment_indexes; - // We now know the slide amount, so go through all sections - // and update the load addresses with the correct values. + // We now know the slide amount, so go through all sections and update + // the load addresses with the correct values. const size_t num_segments = info.segments.size(); for (size_t i = 0; i < num_segments; ++i) { - // Only load a segment if it has protections. Things like - // __PAGEZERO don't have any protections, and they shouldn't - // be slid + // Only load a segment if it has protections. Things like __PAGEZERO + // don't have any protections, and they shouldn't be slid SectionSP section_sp( section_list->FindSectionByName(info.segments[i].name)); @@ -249,10 +247,10 @@ bool DynamicLoaderDarwin::UpdateImageLoadAddress(Module *module, static ConstString g_section_name_LINKEDIT("__LINKEDIT"); if (section_sp) { - // __LINKEDIT sections from files in the shared cache - // can overlap so check to see what the segment name is - // and pass "false" so we don't warn of overlapping - // "Section" objects, and "true" for all other sections. + // __LINKEDIT sections from files in the shared cache can overlap + // so check to see what the segment name is and pass "false" so + // we don't warn of overlapping "Section" objects, and "true" for + // all other sections. const bool warn_multiple = section_sp->GetName() != g_section_name_LINKEDIT; @@ -270,13 +268,12 @@ bool DynamicLoaderDarwin::UpdateImageLoadAddress(Module *module, } } - // If the loaded the file (it changed) and we have segments that - // are not readable or writeable, add them to the invalid memory - // region cache for the process. This will typically only be - // the __PAGEZERO segment in the main executable. We might be able - // to apply this more generally to more sections that have no - // protections in the future, but for now we are going to just - // do __PAGEZERO. + // If the loaded the file (it changed) and we have segments that are + // not readable or writeable, add them to the invalid memory region + // cache for the process. This will typically only be the __PAGEZERO + // segment in the main executable. We might be able to apply this more + // generally to more sections that have no protections in the future, + // but for now we are going to just do __PAGEZERO. if (changed && !inaccessible_segment_indexes.empty()) { for (uint32_t i = 0; i < inaccessible_segment_indexes.size(); ++i) { const uint32_t seg_idx = inaccessible_segment_indexes[i]; @@ -344,8 +341,7 @@ bool DynamicLoaderDarwin::UnloadModuleSections(Module *module, } // Given a JSON dictionary (from debugserver, most likely) of binary images -// loaded in the inferior -// process, add the images to the ImageInfo collection. +// loaded in the inferior process, add the images to the ImageInfo collection. bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo( StructuredData::ObjectSP image_details, @@ -378,7 +374,8 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo( 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(), false, + FileSpec::Style::native); StructuredData::Dictionary *mh = image->GetValueForKey("mach_header")->GetAsDictionary(); @@ -412,8 +409,7 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo( } // Fields that aren't used by DynamicLoaderDarwin so debugserver doesn't - // currently send them - // in the reply. + // currently send them in the reply. if (mh->HasKey("flags")) image_infos[i].header.flags = @@ -454,8 +450,7 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo( seg->GetValueForKey("maxprot")->GetAsInteger()->GetValue(); // Fields that aren't used by DynamicLoaderDarwin so debugserver doesn't - // currently send them - // in the reply. + // currently send them in the reply. if (seg->HasKey("initprot")) segment.initprot = @@ -481,25 +476,23 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo( image_infos[i].uuid.SetFromStringRef( image->GetValueForKey("uuid")->GetAsString()->GetValue()); - // All sections listed in the dyld image info structure will all - // either be fixed up already, or they will all be off by a single - // slide amount that is determined by finding the first segment - // that is at file offset zero which also has bytes (a file size - // that is greater than zero) in the object file. + // All sections listed in the dyld image info structure will all either be + // fixed up already, or they will all be off by a single slide amount that + // is determined by finding the first segment that is at file offset zero + // which also has bytes (a file size that is greater than zero) in the + // object file. // Determine the slide amount (if any) const size_t num_sections = image_infos[i].segments.size(); for (size_t k = 0; k < num_sections; ++k) { - // Iterate through the object file sections to find the - // first section that starts of file offset zero and that - // has bytes in the file... + // Iterate through the object file sections to find the first section + // that starts of file offset zero and that has bytes in the file... if ((image_infos[i].segments[k].fileoff == 0 && image_infos[i].segments[k].filesize > 0) || (image_infos[i].segments[k].name == ConstString("__TEXT"))) { image_infos[i].slide = image_infos[i].address - image_infos[i].segments[k].vmaddr; - // We have found the slide amount, so we can exit - // this for loop. + // We have found the slide amount, so we can exit this for loop. break; } } @@ -520,16 +513,15 @@ 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 + // 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. - // 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 filename check as our next best guess. + // 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 + // filename check as our next best guess. if (image_infos[i].os_type == llvm::Triple::OSType::UnknownOS) { if (image_infos[i].file_spec.GetFilename() != g_dyld_sim_filename) { dyld_idx = i; @@ -543,7 +535,8 @@ void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos( } } else { - // catch-all for any other environment -- trust that dyld is actually dyld + // catch-all for any other environment -- trust that dyld is actually + // dyld dyld_idx = i; } } else if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE) { @@ -669,11 +662,10 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos( } } - // UpdateImageLoadAddress will return true if any segments - // change load address. We need to check this so we don't - // mention that all loaded shared libraries are newly loaded - // each time we hit out dyld breakpoint since dyld will list all - // shared libraries each time. + // UpdateImageLoadAddress will return true if any segments change load + // address. We need to check this so we don't mention that all loaded + // shared libraries are newly loaded each time we hit out dyld breakpoint + // since dyld will list all shared libraries each time. if (UpdateImageLoadAddress(image_module_sp.get(), image_infos[idx])) { target_images.AppendIfNeeded(image_module_sp); loaded_module_list.AppendIfNeeded(image_module_sp); @@ -692,12 +684,11 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos( //---------------------------------------------------------------------- // On Mac OS X libobjc (the Objective-C runtime) has several critical dispatch -// functions written in hand-written assembly, and also have hand-written unwind -// information in the eh_frame section. Normally we prefer analyzing the -// assembly instructions of a currently executing frame to unwind from that -// frame -- -// but on hand-written functions this profiling can fail. We should use the -// eh_frame instructions for these functions all the time. +// functions written in hand-written assembly, and also have hand-written +// unwind information in the eh_frame section. Normally we prefer analyzing +// the assembly instructions of a currently executing frame to unwind from that +// frame -- but on hand-written functions this profiling can fail. We should +// use the eh_frame instructions for these functions all the time. // // As an aside, it would be better if the eh_frame entries had a flag (or were // extensible so they could have an Apple-specific flag) which indicates that @@ -756,35 +747,14 @@ DynamicLoaderDarwin::ImageInfo::FindSegment(const ConstString &name) const { // Dump an image info structure to the file handle provided. //---------------------------------------------------------------------- void DynamicLoaderDarwin::ImageInfo::PutToLog(Log *log) const { - if (log == NULL) + if (!log) return; - const uint8_t *u = (const uint8_t *)uuid.GetBytes(); - if (address == LLDB_INVALID_ADDRESS) { - if (u) { - log->Printf("\t modtime=0x%8.8" PRIx64 - " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-" - "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X path='%s' (UNLOADED)", - mod_date, u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], - u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15], - file_spec.GetPath().c_str()); - } else - log->Printf("\t modtime=0x%8.8" PRIx64 - " path='%s' (UNLOADED)", - mod_date, file_spec.GetPath().c_str()); + LLDB_LOG(log, "modtime={0:x+8} uuid={1} path='{2}' (UNLOADED)", mod_date, + uuid.GetAsString(), file_spec.GetPath()); } else { - if (u) { - log->Printf("\taddress=0x%16.16" PRIx64 " modtime=0x%8.8" PRIx64 - " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-" - "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X path='%s'", - address, mod_date, u[0], u[1], u[2], u[3], u[4], u[5], u[6], - u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15], - file_spec.GetPath().c_str()); - } else { - log->Printf("\taddress=0x%16.16" PRIx64 " modtime=0x%8.8" PRIx64 - " path='%s'", - address, mod_date, file_spec.GetPath().c_str()); - } + LLDB_LOG(log, "address={0:x+16} modtime={1:x+8} uuid={2} path='{3}'", + address, mod_date, uuid.GetAsString(), file_spec.GetPath()); for (uint32_t i = 0; i < segments.size(); ++i) segments[i].PutToLog(log, slide); } @@ -817,8 +787,8 @@ void DynamicLoaderDarwin::PrivateProcessStateChanged(Process *process, break; case eStateStopped: - // Keep trying find dyld and set our notification breakpoint each time - // we stop until we succeed + // Keep trying find dyld and set our notification breakpoint each time we + // stop until we succeed if (!DidSetNotificationBreakpoint() && m_process->IsAlive()) { if (NeedToDoInitialImageFetch()) DoInitialImageFetch(); @@ -956,8 +926,8 @@ DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread, } if (addresses.size() > 0) { - // First check whether any of the addresses point to Indirect symbols, and - // if they do, resolve them: + // First check whether any of the addresses point to Indirect symbols, + // and if they do, resolve them: std::vector<lldb::addr_t> load_addrs; for (Address address : addresses) { Symbol *symbol = address.CalculateSymbolContextSymbol(); @@ -1073,10 +1043,10 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, const lldb::addr_t pthread_key = data.GetAddress(&offset); const lldb::addr_t tls_offset = data.GetAddress(&offset); if (pthread_key != 0) { - // First check to see if we have already figured out the location - // of TLS data for the pthread_key on a specific thread yet. If we - // have we can re-use it since its location will not change unless - // the process execs. + // First check to see if we have already figured out the location of + // TLS data for the pthread_key on a specific thread yet. If we have we + // can re-use it since its location will not change unless the process + // execs. const tid_t tid = thread_sp->GetID(); auto tid_pos = m_tid_to_tls_map.find(tid); if (tid_pos != m_tid_to_tls_map.end()) { @@ -1131,34 +1101,29 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, bool DynamicLoaderDarwin::UseDYLDSPI(Process *process) { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - uint32_t major, minor, update; - bool use_new_spi_interface = false; - if (process->GetHostOSVersion(major, minor, update)) { + llvm::VersionTuple version = process->GetHostOSVersion(); + if (!version.empty()) { const llvm::Triple::OSType os_type = process->GetTarget().GetArchitecture().GetTriple().getOS(); // macOS 10.12 and newer if (os_type == llvm::Triple::MacOSX && - (major > 10 || (major == 10 && minor >= 12))) { + version >= llvm::VersionTuple(10, 12)) use_new_spi_interface = true; - } // iOS 10 and newer - if (os_type == llvm::Triple::IOS && major >= 10) { + if (os_type == llvm::Triple::IOS && version >= llvm::VersionTuple(10)) use_new_spi_interface = true; - } // tvOS 10 and newer - if (os_type == llvm::Triple::TvOS && major >= 10) { + if (os_type == llvm::Triple::TvOS && version >= llvm::VersionTuple(10)) use_new_spi_interface = true; - } // watchOS 3 and newer - if (os_type == llvm::Triple::WatchOS && major >= 3) { + if (os_type == llvm::Triple::WatchOS && version >= llvm::VersionTuple(3)) use_new_spi_interface = true; - } } if (log) { diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp index 66085a23759b..4a8ad38d1785 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp @@ -29,9 +29,9 @@ using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- -// Create an instance of this class. This function is filled into -// the plugin info class that gets handed out by the plugin factory and -// allows the lldb to instantiate an instance of this class. +// Create an instance of this class. This function is filled into the plugin +// info class that gets handed out by the plugin factory and allows the lldb to +// instantiate an instance of this class. //---------------------------------------------------------------------- DynamicLoader *DynamicLoaderMacOS::CreateInstance(Process *process, bool force) { @@ -144,17 +144,18 @@ void DynamicLoaderMacOS::ClearNotificationBreakpoint() { } //---------------------------------------------------------------------- -// Try and figure out where dyld is by first asking the Process -// if it knows (which currently calls down in the lldb::Process -// to get the DYLD info (available on SnowLeopard only). If that fails, -// then check in the default addresses. +// Try and figure out where dyld is by first asking the Process if it knows +// (which currently calls down in the lldb::Process to get the DYLD info +// (available on SnowLeopard only). If that fails, then check in the default +// addresses. //---------------------------------------------------------------------- void DynamicLoaderMacOS::DoInitialImageFetch() { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - // Remove any binaries we pre-loaded in the Target before launching/attaching. - // If the same binaries are present in the process, we'll get them from the - // shared module cache, we won't need to re-load them from disk. + // Remove any binaries we pre-loaded in the Target before + // launching/attaching. If the same binaries are present in the process, + // we'll get them from the shared module cache, we won't need to re-load them + // from disk. UnloadAllImages(); StructuredData::ObjectSP all_image_info_json_sp( @@ -184,9 +185,9 @@ bool DynamicLoaderMacOS::NeedToDoInitialImageFetch() { return true; } //---------------------------------------------------------------------- // Static callback function that gets called when our DYLD notification -// breakpoint gets hit. We update all of our image infos and then -// let our super class DynamicLoader class decide if we should stop -// or not (based on global preference). +// breakpoint gets hit. We update all of our image infos and then let our super +// class DynamicLoader class decide if we should stop or not (based on global +// preference). //---------------------------------------------------------------------- bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, @@ -194,11 +195,10 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton, lldb::user_id_t break_loc_id) { // Let the event know that the images have changed // DYLD passes three arguments to the notification breakpoint. - // Arg1: enum dyld_notify_mode mode - 0 = adding, 1 = removing, 2 = remove all - // Arg2: unsigned long icount - Number of shared libraries - // added/removed - // Arg3: uint64_t mach_headers[] - Array of load addresses of binaries - // added/removed + // Arg1: enum dyld_notify_mode mode - 0 = adding, 1 = removing, 2 = remove + // all Arg2: unsigned long icount - Number of shared libraries + // added/removed Arg3: uint64_t mach_headers[] - Array of load addresses + // of binaries added/removed DynamicLoaderMacOS *dyld_instance = (DynamicLoaderMacOS *)baton; @@ -328,8 +328,8 @@ void DynamicLoaderMacOS::AddBinaries( } } -// Dump the _dyld_all_image_infos members and all current image infos -// that we have parsed to the file handle provided. +// Dump the _dyld_all_image_infos members and all current image infos that we +// have parsed to the file handle provided. //---------------------------------------------------------------------- void DynamicLoaderMacOS::PutToLog(Log *log) const { if (log == NULL) @@ -432,9 +432,9 @@ Status DynamicLoaderMacOS::CanLoadImage() { } } - // Default assumption is that it is OK to load images. - // Only say that we cannot load images if we find the symbol in libdyld and it - // indicates that we cannot. + // Default assumption is that it is OK to load images. Only say that we + // cannot load images if we find the symbol in libdyld and it indicates that + // we cannot. if (symbol_address != LLDB_INVALID_ADDRESS) { { @@ -445,11 +445,11 @@ Status DynamicLoaderMacOS::CanLoadImage() { } } } else { - // If we were unable to find _dyld_global_lock_held in any modules, or it is - // not loaded into memory yet, we may be at process startup (sitting - // at _dyld_start) - so we should not allow dlopen calls. - // But if we found more than one module then we are clearly past _dyld_start - // so in that case we'll default to "it's safe". + // If we were unable to find _dyld_global_lock_held in any modules, or it + // is not loaded into memory yet, we may be at process startup (sitting at + // _dyld_start) - so we should not allow dlopen calls. But if we found more + // than one module then we are clearly past _dyld_start so in that case + // we'll default to "it's safe". if (num_modules <= 1) error.SetErrorString("could not find the dyld library or " "the dyld lock symbol"); @@ -472,7 +472,9 @@ bool DynamicLoaderMacOS::GetSharedCacheInformation( info_dict = info->GetAsDictionary(); } - // {"shared_cache_base_address":140735683125248,"shared_cache_uuid":"DDB8D70C-C9A2-3561-B2C8-BE48A4F33F96","no_shared_cache":false,"shared_cache_private_cache":false} + // {"shared_cache_base_address":140735683125248,"shared_cache_uuid + // ":"DDB8D70C- + // C9A2-3561-B2C8-BE48A4F33F96","no_shared_cache":false,"shared_cache_private_cache":false} if (info_dict && info_dict->HasKey("shared_cache_uuid") && info_dict->HasKey("no_shared_cache") && @@ -482,7 +484,7 @@ bool DynamicLoaderMacOS::GetSharedCacheInformation( std::string uuid_str = info_dict->GetValueForKey("shared_cache_uuid")->GetStringValue(); if (!uuid_str.empty()) - uuid.SetFromCString(uuid_str.c_str()); + uuid.SetFromStringRef(uuid_str); if (info_dict->GetValueForKey("no_shared_cache")->GetBooleanValue() == false) using_shared_cache = eLazyBoolYes; diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index e0def58f41c1..265f19d0ca06 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -49,9 +49,9 @@ using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- -// Create an instance of this class. This function is filled into -// the plugin info class that gets handed out by the plugin factory and -// allows the lldb to instantiate an instance of this class. +// Create an instance of this class. This function is filled into the plugin +// info class that gets handed out by the plugin factory and allows the lldb to +// instantiate an instance of this class. //---------------------------------------------------------------------- DynamicLoader *DynamicLoaderMacOSXDYLD::CreateInstance(Process *process, bool force) { @@ -123,17 +123,18 @@ bool DynamicLoaderMacOSXDYLD::ProcessDidExec() { const addr_t shlib_addr = m_process->GetImageInfoAddress(); if (m_process_image_addr_is_all_images_infos == true && 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. + // 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 && shlib_addr == m_dyld.address) { - // The image info address from the process is the mach_header - // address for dyld and it has changed. + // The image info address from the process is the mach_header address + // for dyld and it has changed. did_exec = true; } else { // ASLR might be disabled and dyld could have ended up in the same - // location. We should try and detect if we are stopped at '_dyld_start' + // location. We should try and detect 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)); @@ -185,16 +186,15 @@ void DynamicLoaderMacOSXDYLD::ClearNotificationBreakpoint() { } //---------------------------------------------------------------------- -// Try and figure out where dyld is by first asking the Process -// if it knows (which currently calls down in the lldb::Process -// to get the DYLD info (available on SnowLeopard only). If that fails, -// then check in the default addresses. +// Try and figure out where dyld is by first asking the Process if it knows +// (which currently calls down in the lldb::Process to get the DYLD info +// (available on SnowLeopard only). If that fails, then check in the default +// addresses. //---------------------------------------------------------------------- void DynamicLoaderMacOSXDYLD::DoInitialImageFetch() { if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS) { - // Check the image info addr as it might point to the - // mach header for dyld, or it might point to the - // dyld_all_image_infos struct + // Check the image info addr as it might point to the mach header for dyld, + // or it might point to the dyld_all_image_infos struct const addr_t shlib_addr = m_process->GetImageInfoAddress(); if (shlib_addr != LLDB_INVALID_ADDRESS) { ByteOrder byte_order = @@ -255,8 +255,7 @@ void DynamicLoaderMacOSXDYLD::DoInitialImageFetch() { } //---------------------------------------------------------------------- -// Assume that dyld is in memory at ADDR and try to parse it's load -// commands +// Assume that dyld is in memory at ADDR and try to parse it's load commands //---------------------------------------------------------------------- bool DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback( lldb::addr_t addr) { @@ -287,10 +286,10 @@ bool DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback( // Update all image infos InitializeFromAllImageInfos(); - // If we didn't have an executable before, but now we do, then the - // dyld module shared pointer might be unique and we may need to add - // it again (since Target::SetExecutableModule() will clear the - // images). So append the dyld module back to the list if it is + // If we didn't have an executable before, but now we do, then the dyld + // module shared pointer might be unique and we may need to add it again + // (since Target::SetExecutableModule() will clear the images). So append + // the dyld module back to the list if it is /// unique! if (dyld_module_sp) { target.GetImages().AppendIfNeeded(dyld_module_sp); @@ -315,18 +314,18 @@ bool DynamicLoaderMacOSXDYLD::NeedToDoInitialImageFetch() { //---------------------------------------------------------------------- // Static callback function that gets called when our DYLD notification -// breakpoint gets hit. We update all of our image infos and then -// let our super class DynamicLoader class decide if we should stop -// or not (based on global preference). +// breakpoint gets hit. We update all of our image infos and then let our super +// class DynamicLoader class decide if we should stop or not (based on global +// preference). //---------------------------------------------------------------------- bool DynamicLoaderMacOSXDYLD::NotifyBreakpointHit( void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id) { // Let the event know that the images have changed // DYLD passes three arguments to the notification breakpoint. - // Arg1: enum dyld_image_mode mode - 0 = adding, 1 = removing - // Arg2: uint32_t infoCount - Number of shared libraries added - // Arg3: dyld_image_info info[] - Array of structs of the form: + // Arg1: enum dyld_image_mode mode - 0 = adding, 1 = removing Arg2: uint32_t + // infoCount - Number of shared libraries added Arg3: dyld_image_info + // info[] - Array of structs of the form: // const struct mach_header // *imageLoadAddress // const char *imageFilePath @@ -335,11 +334,10 @@ bool DynamicLoaderMacOSXDYLD::NotifyBreakpointHit( DynamicLoaderMacOSXDYLD *dyld_instance = (DynamicLoaderMacOSXDYLD *)baton; // First step is to see if we've already initialized the all image infos. If - // we haven't then this function - // will do so and return true. In the course of initializing the - // all_image_infos it will read the complete - // current state, so we don't need to figure out what has changed from the - // data passed in to us. + // we haven't then this function will do so and return true. In the course + // of initializing the all_image_infos it will read the complete current + // state, so we don't need to figure out what has changed from the data + // passed in to us. ExecutionContext exe_ctx(context->exe_ctx_ref); Process *process = exe_ctx.GetProcessPtr(); @@ -388,11 +386,9 @@ bool DynamicLoaderMacOSXDYLD::NotifyBreakpointHit( argument_values.GetValueAtIndex(1)->GetScalar().UInt(-1); if (image_infos_count != static_cast<uint32_t>(-1)) { // Got the number added, now go through the array of added elements, - // putting out the mach header - // address, and adding the image. - // Note, I'm not putting in logging here, since the AddModules & - // RemoveModules functions do - // all the logging internally. + // putting out the mach header address, and adding the image. Note, + // I'm not putting in logging here, since the AddModules & + // RemoveModules functions do all the logging internally. lldb::addr_t image_infos_addr = argument_values.GetValueAtIndex(2)->GetScalar().ULongLong(); @@ -467,12 +463,12 @@ bool DynamicLoaderMacOSXDYLD::ReadAllImageInfosStructure() { if (m_process->ReadMemory(m_dyld_all_image_infos_addr, buf, 4, error) == 4) { m_dyld_all_image_infos.version = data.GetU32(&offset); - // If anything in the high byte is set, we probably got the byte - // order incorrect (the process might not have it set correctly - // yet due to attaching to a program without a specified file). + // If anything in the high byte is set, we probably got the byte order + // incorrect (the process might not have it set correctly yet due to + // attaching to a program without a specified file). if (m_dyld_all_image_infos.version & 0xff000000) { - // We have guessed the wrong byte order. Swap it and try - // reading the version again. + // We have guessed the wrong byte order. Swap it and try reading the + // version again. if (byte_order == eByteOrderLittle) byte_order = eByteOrderBig; else @@ -508,21 +504,17 @@ bool DynamicLoaderMacOSXDYLD::ReadAllImageInfosStructure() { uint64_t dyld_all_image_infos_addr = data.GetPointer(&offset); // When we started, we were given the actual address of the - // all_image_infos - // struct (probably via TASK_DYLD_INFO) in memory - this address is - // stored in - // m_dyld_all_image_infos_addr and is the most accurate address we have. + // all_image_infos struct (probably via TASK_DYLD_INFO) in memory - + // this address is stored in m_dyld_all_image_infos_addr and is the + // most accurate address we have. // We read the dyld_all_image_infos struct from memory; it contains its - // own address. - // If the address in the struct does not match the actual address, - // the dyld we're looking at has been loaded at a different location - // (slid) from - // where it intended to load. The addresses in the dyld_all_image_infos - // struct - // are the original, non-slid addresses, and need to be adjusted. Most - // importantly - // the address of dyld and the notification address need to be adjusted. + // own address. If the address in the struct does not match the actual + // address, the dyld we're looking at has been loaded at a different + // location (slid) from where it intended to load. The addresses in + // the dyld_all_image_infos struct are the original, non-slid + // addresses, and need to be adjusted. Most importantly the address of + // dyld and the notification address need to be adjusted. if (dyld_all_image_infos_addr != m_dyld_all_image_infos_addr) { uint64_t image_infos_offset = @@ -615,14 +607,13 @@ bool DynamicLoaderMacOSXDYLD::RemoveModulesUsingImageInfosAddress( image_infos[idx].PutToLog(log); } - // Remove this image_infos from the m_all_image_infos. We do the comparison - // by address - // rather than by file spec because we can have many modules with the same - // "file spec" in the - // case that they are modules loaded from memory. + // Remove this image_infos from the m_all_image_infos. We do the + // comparison by address rather than by file spec because we can have many + // modules with the same "file spec" in the case that they are modules + // loaded from memory. // - // Also copy over the uuid from the old entry to the removed entry so we can - // use it to lookup the module in the module list. + // Also copy over the uuid from the old entry to the removed entry so we + // can use it to lookup the module in the module list. ImageInfo::collection::iterator pos, end = m_dyld_image_infos.end(); for (pos = m_dyld_image_infos.begin(); pos != end; pos++) { @@ -630,8 +621,7 @@ bool DynamicLoaderMacOSXDYLD::RemoveModulesUsingImageInfosAddress( image_infos[idx].uuid = (*pos).uuid; // Add the module from this image_info to the "unloaded_module_list". - // We'll remove them all at - // one go later on. + // We'll remove them all at one go later on. ModuleSP unload_image_module_sp( FindTargetModuleForImageInfo(image_infos[idx], false, NULL)); @@ -703,7 +693,8 @@ bool DynamicLoaderMacOSXDYLD::ReadImageInfos( // don't resolve the path if (error.Success()) { const bool resolve_path = false; - image_infos[i].file_spec.SetFile(raw_path, resolve_path); + image_infos[i].file_spec.SetFile(raw_path, resolve_path, + FileSpec::Style::native); } } return true; @@ -713,11 +704,10 @@ bool DynamicLoaderMacOSXDYLD::ReadImageInfos( } //---------------------------------------------------------------------- -// If we have found where the "_dyld_all_image_infos" lives in memory, -// read the current info from it, and then update all image load -// addresses (or lack thereof). Only do this if this is the first time -// we're reading the dyld infos. Return true if we actually read anything, -// and false otherwise. +// If we have found where the "_dyld_all_image_infos" lives in memory, read the +// current info from it, and then update all image load addresses (or lack +// thereof). Only do this if this is the first time we're reading the dyld +// infos. Return true if we actually read anything, and false otherwise. //---------------------------------------------------------------------- bool DynamicLoaderMacOSXDYLD::InitializeFromAllImageInfos() { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); @@ -748,14 +738,11 @@ bool DynamicLoaderMacOSXDYLD::InitializeFromAllImageInfos() { } // Now we have one more bit of business. If there is a library left in the - // images for our target that - // doesn't have a load address, then it must be something that we were - // expecting to load (for instance we - // read a load command for it) but it didn't in fact load - probably because - // DYLD_*_PATH pointed - // to an equivalent version. We don't want it to stay in the target's - // module list or it will confuse - // us, so unload it here. + // images for our target that doesn't have a load address, then it must be + // something that we were expecting to load (for instance we read a load + // command for it) but it didn't in fact load - probably because + // DYLD_*_PATH pointed to an equivalent version. We don't want it to stay + // in the target's module list or it will confuse us, so unload it here. Target &target = m_process->GetTarget(); const ModuleList &target_modules = target.GetImages(); ModuleList not_loaded_modules; @@ -784,8 +771,8 @@ bool DynamicLoaderMacOSXDYLD::InitializeFromAllImageInfos() { } //---------------------------------------------------------------------- -// Read a mach_header at ADDR into HEADER, and also fill in the load -// command data into LOAD_COMMAND_DATA if it is non-NULL. +// Read a mach_header at ADDR into HEADER, and also fill in the load command +// data into LOAD_COMMAND_DATA if it is non-NULL. // // Returns true if we succeed, false if we fail for any reason. //---------------------------------------------------------------------- @@ -840,8 +827,8 @@ bool DynamicLoaderMacOSXDYLD::ReadMachHeader(lldb::addr_t addr, load_cmd_data_sp->GetByteSize(), error); if (load_cmd_bytes_read == header->sizeofcmds) { - // Set the load command data and also set the correct endian - // swap settings and the correct address size + // Set the load command data and also set the correct endian swap + // settings and the correct address size load_command_data->SetData(load_cmd_data_sp, 0, header->sizeofcmds); load_command_data->SetByteOrder(data.GetByteOrder()); load_command_data->SetAddressByteSize(data.GetAddressByteSize()); @@ -867,8 +854,8 @@ uint32_t DynamicLoaderMacOSXDYLD::ParseLoadCommands(const DataExtractor &data, dylib_info.Clear(true); for (cmd_idx = 0; cmd_idx < dylib_info.header.ncmds; cmd_idx++) { - // Clear out any load command specific data from DYLIB_INFO since - // we are about to read it. + // Clear out any load command specific data from DYLIB_INFO since we are + // about to read it. if (data.ValidOffsetForDataOfSize(offset, sizeof(llvm::MachO::load_command))) { @@ -880,8 +867,8 @@ uint32_t DynamicLoaderMacOSXDYLD::ParseLoadCommands(const DataExtractor &data, case llvm::MachO::LC_SEGMENT: { segment.name.SetTrimmedCStringWithLength( (const char *)data.GetData(&offset, 16), 16); - // We are putting 4 uint32_t values 4 uint64_t values so - // we have to use multiple 32 bit gets below. + // We are putting 4 uint32_t values 4 uint64_t values so we have to use + // multiple 32 bit gets below. segment.vmaddr = data.GetU32(&offset); segment.vmsize = data.GetU32(&offset); segment.fileoff = data.GetU32(&offset); @@ -906,12 +893,12 @@ 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); + lc_id_dylinker->SetFile(path, true, FileSpec::Style::native); } break; case llvm::MachO::LC_UUID: - dylib_info.uuid.SetBytes(data.GetData(&offset, 16)); + dylib_info.uuid = UUID::fromOptionalData(data.GetData(&offset, 16), 16); break; default: @@ -922,24 +909,21 @@ uint32_t DynamicLoaderMacOSXDYLD::ParseLoadCommands(const DataExtractor &data, } } - // All sections listed in the dyld image info structure will all - // either be fixed up already, or they will all be off by a single - // slide amount that is determined by finding the first segment - // that is at file offset zero which also has bytes (a file size - // that is greater than zero) in the object file. + // All sections listed in the dyld image info structure will all either be + // fixed up already, or they will all be off by a single slide amount that is + // determined by finding the first segment that is at file offset zero which + // also has bytes (a file size that is greater than zero) in the object file. // Determine the slide amount (if any) const size_t num_sections = dylib_info.segments.size(); for (size_t i = 0; i < num_sections; ++i) { - // Iterate through the object file sections to find the - // first section that starts of file offset zero and that - // has bytes in the file... + // Iterate through the object file sections to find the first section that + // starts of file offset zero and that has bytes in the file... if ((dylib_info.segments[i].fileoff == 0 && dylib_info.segments[i].filesize > 0) || (dylib_info.segments[i].name == ConstString("__TEXT"))) { dylib_info.slide = dylib_info.address - dylib_info.segments[i].vmaddr; - // We have found the slide amount, so we can exit - // this for loop. + // We have found the slide amount, so we can exit this for loop. break; } } @@ -984,11 +968,11 @@ void DynamicLoaderMacOSXDYLD::UpdateImageInfosHeaderAndLoadCommands( // Don't load dependent images since we are in dyld where we will know // and find out about all images that are loaded. Also when setting the // executable module, it will clear the targets module list, and if we - // have an in memory dyld module, it will get removed from the list - // so we will need to add it back after setting the executable module, - // so we first try and see if we already have a weak pointer to the - // dyld module, make it into a shared pointer, then add the executable, - // then re-add it back to make sure it is always in the list. + // have an in memory dyld module, it will get removed from the list so + // we will need to add it back after setting the executable module, so + // we first try and see if we already have a weak pointer to the dyld + // module, make it into a shared pointer, then add the executable, then + // re-add it back to make sure it is always in the list. ModuleSP dyld_module_sp(GetDYLDModule()); const bool get_dependent_images = false; @@ -1009,8 +993,8 @@ void DynamicLoaderMacOSXDYLD::UpdateImageInfosHeaderAndLoadCommands( } //---------------------------------------------------------------------- -// Dump the _dyld_all_image_infos members and all current image infos -// that we have parsed to the file handle provided. +// Dump the _dyld_all_image_infos members and all current image infos that we +// have parsed to the file handle provided. //---------------------------------------------------------------------- void DynamicLoaderMacOSXDYLD::PutToLog(Log *log) const { if (log == NULL) @@ -1039,10 +1023,9 @@ bool DynamicLoaderMacOSXDYLD::SetNotificationBreakpoint() { if (m_break_id == LLDB_INVALID_BREAK_ID) { if (m_dyld_all_image_infos.notification != LLDB_INVALID_ADDRESS) { Address so_addr; - // Set the notification breakpoint and install a breakpoint - // callback function that will get called each time the - // breakpoint gets hit. We will use this to track when shared - // libraries get loaded/unloaded. + // Set the notification breakpoint and install a breakpoint callback + // function that will get called each time the breakpoint gets hit. We + // will use this to track when shared libraries get loaded/unloaded. bool resolved = m_process->GetTarget().ResolveLoadAddress( m_dyld_all_image_infos.notification, so_addr); if (!resolved) { @@ -1071,9 +1054,9 @@ bool DynamicLoaderMacOSXDYLD::SetNotificationBreakpoint() { Status DynamicLoaderMacOSXDYLD::CanLoadImage() { Status error; - // In order for us to tell if we can load a shared library we verify that - // the dylib_info_addr isn't zero (which means no shared libraries have - // been set yet, or dyld is currently mucking with the shared library list). + // In order for us to tell if we can load a shared library we verify that the + // dylib_info_addr isn't zero (which means no shared libraries have been set + // yet, or dyld is currently mucking with the shared library list). if (ReadAllImageInfosStructure()) { // TODO: also check the _dyld_global_lock_held variable in // libSystem.B.dylib? @@ -1099,13 +1082,10 @@ bool DynamicLoaderMacOSXDYLD::GetSharedCacheInformation( addr_t all_image_infos = m_process->GetImageInfoAddress(); // The address returned by GetImageInfoAddress may be the address of dyld - // (don't want) - // or it may be the address of the dyld_all_image_infos structure (want). - // The first four - // bytes will be either the version field (all_image_infos) or a Mach-O file - // magic constant. - // Version 13 and higher of dyld_all_image_infos is required to get the - // sharedCacheUUID field. + // (don't want) or it may be the address of the dyld_all_image_infos + // structure (want). The first four bytes will be either the version field + // (all_image_infos) or a Mach-O file magic constant. Version 13 and higher + // of dyld_all_image_infos is required to get the sharedCacheUUID field. Status err; uint32_t version_or_magic = @@ -1130,7 +1110,7 @@ bool DynamicLoaderMacOSXDYLD::GetSharedCacheInformation( uuid_t shared_cache_uuid; if (m_process->ReadMemory(sharedCacheUUID_address, shared_cache_uuid, sizeof(uuid_t), err) == sizeof(uuid_t)) { - uuid.SetBytes(shared_cache_uuid); + uuid = UUID::fromOptionalData(shared_cache_uuid, 16); if (uuid.IsValid()) { using_shared_cache = eLazyBoolYes; } diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h index cf9da0808357..3b06fe18f0c6 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h @@ -22,12 +22,12 @@ class DataExtractor; } /// @class AuxVector -/// @brief Represents a processes auxiliary vector. +/// Represents a processes auxiliary vector. /// /// When a process is loaded on Linux a vector of values is placed onto the -/// stack communicating operating system specific information. On construction -/// this class locates and parses this information and provides a simple -/// read-only interface to the entries found. +/// stack communicating operating system specific information. On +/// construction this class locates and parses this information and provides a +/// simple read-only interface to the entries found. class AuxVector { public: @@ -41,8 +41,9 @@ public: }; /// Constants describing the type of entry. - /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX information. - /// Added AUXV prefix to avoid potential conflicts with system-defined macros + /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX + /// information. Added AUXV prefix to avoid potential conflicts with system- + /// defined macros enum EntryType { AUXV_AT_NULL = 0, ///< End of auxv. AUXV_AT_IGNORE = 1, ///< Ignore entry. diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp index e601d64f0d8d..b1513b51a90a 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -45,8 +45,8 @@ static addr_t ResolveRendezvousAddress(Process *process) { if (log) log->Printf("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location); - // If the process fails to return an address, fall back to seeing if the local - // object file can help us find it. + // If the process fails to return an address, fall back to seeing if the + // local object file can help us find it. if (info_location == LLDB_INVALID_ADDRESS) { Target *target = &process->GetTarget(); if (target) { @@ -190,8 +190,8 @@ bool DYLDRendezvous::UpdateSOEntries(bool fromRemote) { if (!fromRemote && m_current.map_addr == 0) return false; - // When the previous and current states are consistent this is the first - // time we have been asked to update. Just take a snapshot of the currently + // When the previous and current states are consistent this is the first time + // we have been asked to update. Just take a snapshot of the currently // loaded modules. if (m_previous.state == eConsistent && m_current.state == eConsistent) return fromRemote ? SaveSOEntriesFromRemote(module_list) @@ -200,9 +200,9 @@ bool DYLDRendezvous::UpdateSOEntries(bool fromRemote) { // If we are about to add or remove a shared object clear out the current // state and take a snapshot of the currently loaded images. if (m_current.state == eAdd || m_current.state == eDelete) { - // Some versions of the android dynamic linker might send two - // notifications with state == eAdd back to back. Ignore them - // until we get an eConsistent notification. + // Some versions of the android dynamic linker might send two notifications + // with state == eAdd back to back. Ignore them until we get an eConsistent + // notification. if (!(m_previous.state == eConsistent || (m_previous.state == eAdd && m_current.state == eDelete))) return false; @@ -243,7 +243,7 @@ bool DYLDRendezvous::FillSOEntryFromModuleInfo( entry.base_addr = base_addr; entry.dyn_addr = dyn_addr; - entry.file_spec.SetFile(name, false); + entry.file_spec.SetFile(name, false, FileSpec::Style::native); UpdateBaseAddrIfNecessary(entry, name); @@ -449,16 +449,13 @@ std::string DYLDRendezvous::ReadStringFromMemory(addr_t addr) { } // Returns true if the load bias reported by the linker is incorrect for the -// given entry. This -// function is used to handle cases where we want to work around a bug in the -// system linker. +// given entry. This function is used to handle cases where we want to work +// around a bug in the system linker. 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. - uint32_t os_major = 0, os_minor = 0, os_update = 0; + // isn't filled in correctly. + unsigned os_major = target.GetPlatform()->GetOSVersion().getMajor(); if (target.GetArchitecture().GetTriple().isAndroid() && - target.GetPlatform()->GetOSVersion(os_major, os_minor, os_update) && (os_major == 21 || os_major == 22) && (file_path == "/system/bin/linker" || file_path == "/system/bin/linker64")) { @@ -471,8 +468,7 @@ static bool isLoadBiasIncorrect(Target &target, const std::string &file_path) { void DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path) { // If the load bias reported by the linker is incorrect then fetch the load - // address of the file - // from the proc file system. + // address of the file from the proc file system. if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) { lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; bool is_loaded = false; @@ -491,8 +487,8 @@ bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) { if (!(addr = ReadPointer(addr, &entry.base_addr))) return false; - // mips adds an extra load offset field to the link map struct on - // FreeBSD and NetBSD (need to validate other OSes). + // mips adds an extra load offset field to the link map struct on FreeBSD and + // NetBSD (need to validate other OSes). // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57 const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD || @@ -521,7 +517,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); + entry.file_spec.SetFile(file_path, false, 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 295ae55e1b85..a7071801f569 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h @@ -29,12 +29,12 @@ class Process; } /// @class DYLDRendezvous -/// @brief Interface to the runtime linker. +/// Interface to the runtime linker. /// /// A structure is present in a processes memory space which is updated by the -/// runtime liker each time a module is loaded or unloaded. This class provides -/// an interface to this structure and maintains a consistent snapshot of the -/// currently loaded modules. +/// runtime liker each time a module is loaded or unloaded. This class +/// provides an interface to this structure and maintains a consistent +/// snapshot of the currently loaded modules. class DYLDRendezvous { // This structure is used to hold the contents of the debug rendezvous @@ -119,13 +119,13 @@ public: void DumpToLog(lldb_private::Log *log) const; - /// @brief Constants describing the state of the rendezvous. + /// Constants describing the state of the rendezvous. /// /// @see GetState(). enum RendezvousState { eConsistent, eAdd, eDelete }; - /// @brief Structure representing the shared objects currently loaded into - /// the inferior process. + /// Structure representing the shared objects currently loaded into the + /// inferior process. /// /// This object is a rough analogue to the struct link_map object which /// actually lives in the inferiors memory. @@ -194,7 +194,8 @@ protected: /// List of SOEntry objects corresponding to the current link map state. SOEntryList m_soentries; - /// List of SOEntry's added to the link map since the last call to Resolve(). + /// List of SOEntry's added to the link map since the last call to + /// Resolve(). SOEntryList m_added_soentries; /// List of SOEntry's removed from the link map since the last call to diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index a7afeb6d68c3..26825d879f04 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -79,7 +79,8 @@ DynamicLoaderPOSIXDYLD::DynamicLoaderPOSIXDYLD(Process *process) : DynamicLoader(process), m_rendezvous(process), m_load_offset(LLDB_INVALID_ADDRESS), m_entry_point(LLDB_INVALID_ADDRESS), m_auxv(), m_dyld_bid(LLDB_INVALID_BREAK_ID), - m_vdso_base(LLDB_INVALID_ADDRESS) {} + m_vdso_base(LLDB_INVALID_ADDRESS), + m_interpreter_base(LLDB_INVALID_ADDRESS) {} DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD() { if (m_dyld_bid != LLDB_INVALID_BREAK_ID) { @@ -117,7 +118,7 @@ void DynamicLoaderPOSIXDYLD::DidAttach() { : "<null executable>", load_offset); - EvalVdsoStatus(); + EvalSpecialModulesStatus(); // if we dont have a load address we cant re-base bool rebase_exec = (load_offset == LLDB_INVALID_ADDRESS) ? false : true; @@ -152,31 +153,10 @@ void DynamicLoaderPOSIXDYLD::DidAttach() { UpdateLoadedSections(executable_sp, LLDB_INVALID_ADDRESS, load_offset, true); - // When attaching to a target, there are two possible states: - // (1) We already crossed the entry point and therefore the rendezvous - // structure is ready to be used and we can load the list of modules - // and place the rendezvous breakpoint. - // (2) We didn't cross the entry point yet, so these structures are not - // ready; we should behave as if we just launched the target and - // call ProbeEntry(). This will place a breakpoint on the entry - // point which itself will be hit after the rendezvous structure is - // set up and will perform actions described in (1). - if (m_rendezvous.Resolve()) { - if (log) - log->Printf("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64 - " rendezvous could resolve: attach assuming dynamic loader " - "info is available now", - __FUNCTION__, - m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); - LoadAllCurrentModules(); - SetRendezvousBreakpoint(); - } else { - if (log) - log->Printf("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64 - " rendezvous could not yet resolve: adding breakpoint to " - "catch future rendezvous setup", - __FUNCTION__, - m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + LoadAllCurrentModules(); + if (!SetRendezvousBreakpoint()) { + // If we cannot establish rendezvous breakpoint right now we'll try again + // at entry point. ProbeEntry(); } @@ -207,7 +187,7 @@ void DynamicLoaderPOSIXDYLD::DidLaunch() { executable = GetTargetExecutable(); load_offset = ComputeLoadOffset(); - EvalVdsoStatus(); + EvalSpecialModulesStatus(); if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) { ModuleList module_list; @@ -217,8 +197,14 @@ void DynamicLoaderPOSIXDYLD::DidLaunch() { if (log) log->Printf("DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()", __FUNCTION__); - ProbeEntry(); + if (!SetRendezvousBreakpoint()) { + // If we cannot establish rendezvous breakpoint right now we'll try again + // at entry point. + ProbeEntry(); + } + + LoadVDSO(); m_process->GetTarget().ModulesDidLoad(module_list); } } @@ -273,11 +259,11 @@ void DynamicLoaderPOSIXDYLD::ProbeEntry() { } // The runtime linker has run and initialized the rendezvous structure once the -// process has hit its entry point. When we hit the corresponding breakpoint we -// interrogate the rendezvous structure to get the load addresses of all +// process has hit its entry point. When we hit the corresponding breakpoint +// we interrogate the rendezvous structure to get the load addresses of all // dependent modules for the process. Similarly, we can discover the runtime -// linker function and setup a breakpoint to notify us of any dynamically loaded -// modules (via dlopen). +// linker function and setup a breakpoint to notify us of any dynamically +// loaded modules (via dlopen). bool DynamicLoaderPOSIXDYLD::EntryBreakpointHit( void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id) { @@ -295,13 +281,11 @@ bool DynamicLoaderPOSIXDYLD::EntryBreakpointHit( : LLDB_INVALID_PROCESS_ID); // Disable the breakpoint --- if a stop happens right after this, which we've - // seen on occasion, we don't - // want the breakpoint stepping thread-plan logic to show a breakpoint - // instruction at the disassembled - // entry point to the program. Disabling it prevents it. (One-shot is not - // enough - one-shot removal logic - // only happens after the breakpoint goes public, which wasn't happening in - // our scenario). + // seen on occasion, we don't want the breakpoint stepping thread-plan logic + // to show a breakpoint instruction at the disassembled entry point to the + // program. Disabling it prevents it. (One-shot is not enough - one-shot + // removal logic only happens after the breakpoint goes public, which wasn't + // happening in our scenario). if (dyld_instance->m_process) { BreakpointSP breakpoint_sp = dyld_instance->m_process->GetTarget().GetBreakpointByID(break_id); @@ -329,38 +313,77 @@ bool DynamicLoaderPOSIXDYLD::EntryBreakpointHit( return false; // Continue running. } -void DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() { +bool DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (m_dyld_bid != LLDB_INVALID_BREAK_ID) { + LLDB_LOG(log, + "Rendezvous breakpoint breakpoint id {0} for pid {1}" + "is already set.", + m_dyld_bid, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + return true; + } - addr_t break_addr = m_rendezvous.GetBreakAddress(); + addr_t break_addr; Target &target = m_process->GetTarget(); - - if (m_dyld_bid == LLDB_INVALID_BREAK_ID) { - if (log) - log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 - " setting rendezvous break address at 0x%" PRIx64, - __FUNCTION__, - m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, - break_addr); - Breakpoint *dyld_break = - target.CreateBreakpoint(break_addr, true, false).get(); - dyld_break->SetCallback(RendezvousBreakpointHit, this, true); - dyld_break->SetBreakpointKind("shared-library-event"); - m_dyld_bid = dyld_break->GetID(); + BreakpointSP dyld_break; + if (m_rendezvous.IsValid()) { + break_addr = m_rendezvous.GetBreakAddress(); + LLDB_LOG(log, "Setting rendezvous break address for pid {0} at {1:x}", + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, + break_addr); + dyld_break = target.CreateBreakpoint(break_addr, true, false); } else { - if (log) - log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 - " reusing break id %" PRIu32 ", address at 0x%" PRIx64, - __FUNCTION__, - m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, - m_dyld_bid, break_addr); + LLDB_LOG(log, "Rendezvous structure is not set up yet. " + "Trying to locate rendezvous breakpoint in the interpreter " + "by symbol name."); + ModuleSP interpreter = LoadInterpreterModule(); + if (!interpreter) { + LLDB_LOG(log, "Can't find interpreter, rendezvous breakpoint isn't set."); + return false; + } + + // Function names from different dynamic loaders that are known to be used + // as rendezvous between the loader and debuggers. + static std::vector<std::string> DebugStateCandidates{ + "_dl_debug_state", "rtld_db_dlactivity", "__dl_rtld_db_dlactivity", + "r_debug_state", "_r_debug_state", "_rtld_debug_state", + }; + + FileSpecList containingModules; + containingModules.Append(interpreter->GetFileSpec()); + dyld_break = target.CreateBreakpoint( + &containingModules, nullptr /* containingSourceFiles */, + DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC, + 0, /* offset */ + eLazyBoolNo, /* skip_prologue */ + true, /* internal */ + false /* request_hardware */); + } + + if (dyld_break->GetNumResolvedLocations() != 1) { + LLDB_LOG( + log, + "Rendezvous breakpoint has abnormal number of" + " resolved locations ({0}) in pid {1}. It's supposed to be exactly 1.", + dyld_break->GetNumResolvedLocations(), + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + + target.RemoveBreakpointByID(dyld_break->GetID()); + return false; } - // Make sure our breakpoint is at the right address. - assert(target.GetBreakpointByID(m_dyld_bid) - ->FindLocationByAddress(break_addr) - ->GetBreakpoint() - .GetID() == m_dyld_bid); + BreakpointLocationSP location = dyld_break->GetLocationAtIndex(0); + LLDB_LOG(log, + "Successfully set rendezvous breakpoint at address {0:x} " + "for pid {1}", + location->GetLoadAddress(), + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + + dyld_break->SetCallback(RendezvousBreakpointHit, this, true); + dyld_break->SetBreakpointKind("shared-library-event"); + m_dyld_bid = dyld_break->GetID(); + return true; } bool DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit( @@ -485,7 +508,7 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, return thread_plan_sp; } -void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) { +void DynamicLoaderPOSIXDYLD::LoadVDSO() { if (m_vdso_base == LLDB_INVALID_ADDRESS) return; @@ -506,13 +529,40 @@ void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) { } } +ModuleSP DynamicLoaderPOSIXDYLD::LoadInterpreterModule() { + if (m_interpreter_base == LLDB_INVALID_ADDRESS) + return nullptr; + + MemoryRegionInfo info; + Target &target = m_process->GetTarget(); + Status status = m_process->GetMemoryRegionInfo(m_interpreter_base, info); + if (status.Fail() || info.GetMapped() != MemoryRegionInfo::eYes || + info.GetName().IsEmpty()) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + LLDB_LOG(log, "Failed to get interpreter region info: {0}", status); + return nullptr; + } + + FileSpec file(info.GetName().GetCString(), false); + ModuleSpec module_spec(file, target.GetArchitecture()); + + if (ModuleSP module_sp = target.GetSharedModule(module_spec)) { + UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_interpreter_base, + false); + return module_sp; + } + return nullptr; +} + void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() { DYLDRendezvous::iterator I; DYLDRendezvous::iterator E; ModuleList module_list; + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + LoadVDSO(); if (!m_rendezvous.Resolve()) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); if (log) log->Printf("DynamicLoaderPOSIXDYLD::%s unable to resolve POSIX DYLD " "rendezvous address", @@ -520,11 +570,10 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() { return; } - // The rendezvous class doesn't enumerate the main module, so track - // that ourselves here. + // The rendezvous class doesn't enumerate the main module, so track that + // ourselves here. ModuleSP executable = GetTargetExecutable(); m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); - LoadVDSO(module_list); std::vector<FileSpec> module_names; for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) @@ -536,6 +585,8 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() { ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true); if (module_sp.get()) { + LLDB_LOG(log, "LoadAllCurrentModules loading module: {0}", + I->file_spec.GetFilename()); module_list.Append(module_sp); } else { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); @@ -575,11 +626,14 @@ addr_t DynamicLoaderPOSIXDYLD::ComputeLoadOffset() { return m_load_offset; } -void DynamicLoaderPOSIXDYLD::EvalVdsoStatus() { - AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AUXV_AT_SYSINFO_EHDR); - - if (I != m_auxv->end()) +void DynamicLoaderPOSIXDYLD::EvalSpecialModulesStatus() { + auto I = m_auxv->FindEntry(AuxVector::AUXV_AT_SYSINFO_EHDR); + if (I != m_auxv->end() && I->value != 0) m_vdso_base = I->value; + + I = m_auxv->FindEntry(AuxVector::AUXV_AT_BASE); + if (I != m_auxv->end() && I->value != 0) + m_interpreter_base = I->value; } addr_t DynamicLoaderPOSIXDYLD::GetEntryPoint() { diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index 2e9670587e66..0456baf4a658 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -85,13 +85,17 @@ protected: /// mapped to the address space lldb::addr_t m_vdso_base; + /// Contains AT_BASE, which means a dynamic loader has been + /// mapped to the address space + lldb::addr_t m_interpreter_base; + /// Loaded module list. (link map for each module) std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>> m_loaded_modules; - /// Enables a breakpoint on a function called by the runtime + /// If possible sets a breakpoint on a function called by the runtime /// linker each time a module is loaded or unloaded. - virtual void SetRendezvousBreakpoint(); + bool SetRendezvousBreakpoint(); /// Callback routine which updates the current list of loaded modules based /// on the information supplied by the runtime linker. @@ -138,7 +142,11 @@ protected: /// of all dependent modules. virtual void LoadAllCurrentModules(); - void LoadVDSO(lldb_private::ModuleList &modules); + void LoadVDSO(); + + // Loading an interpreter module (if present) assumming m_interpreter_base + // already points to its base address. + lldb::ModuleSP LoadInterpreterModule(); /// Computes a value for m_load_offset returning the computed address on /// success and LLDB_INVALID_ADDRESS on failure. @@ -148,9 +156,10 @@ protected: /// success and LLDB_INVALID_ADDRESS on failure. lldb::addr_t GetEntryPoint(); - /// Evaluate if Aux vectors contain vDSO information + /// Evaluate if Aux vectors contain vDSO and LD information /// in case they do, read and assign the address to m_vdso_base - void EvalVdsoStatus(); + /// and m_interpreter_base. + void EvalSpecialModulesStatus(); /// Loads Module from inferior process. void ResolveExecutableModule(lldb::ModuleSP &module_sp); diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp index 291695cb68c1..2960e3939461 100644 --- a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp +++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp @@ -19,9 +19,9 @@ using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- -// Create an instance of this class. This function is filled into -// the plugin info class that gets handed out by the plugin factory and -// allows the lldb to instantiate an instance of this class. +// Create an instance of this class. This function is filled into the plugin +// info class that gets handed out by the plugin factory and allows the lldb to +// instantiate an instance of this class. //---------------------------------------------------------------------- DynamicLoader *DynamicLoaderStatic::CreateInstance(Process *process, bool force) { @@ -97,17 +97,17 @@ void DynamicLoaderStatic::LoadAllImagesAtFileAddresses() { if (section_list) { // All sections listed in the dyld image info structure will all // either be fixed up already, or they will all be off by a single - // slide amount that is determined by finding the first segment - // that is at file offset zero which also has bytes (a file size - // that is greater than zero) in the object file. + // slide amount that is determined by finding the first segment that + // is at file offset zero which also has bytes (a file size that is + // greater than zero) in the object file. // Determine the slide amount (if any) const size_t num_sections = section_list->GetSize(); size_t sect_idx = 0; for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { - // Iterate through the object file sections to find the - // first section that starts of file offset zero and that - // has bytes in the file... + // Iterate through the object file sections to find the first + // section that starts of file offset zero and that has bytes in + // the file... SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); if (section_sp) { if (m_process->GetTarget().SetSectionLoadAddress( diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index 9e6a2f3acafe..fa49a51f32a6 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -226,8 +226,7 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, return true; // In C++11, last_expr can be a LValueToRvalue implicit cast. Strip that off - // if that's the - // case. + // if that's the case. do { ImplicitCastExpr *implicit_cast = dyn_cast<ImplicitCastExpr>(last_expr); @@ -242,8 +241,8 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, } while (0); // is_lvalue is used to record whether the expression returns an assignable - // Lvalue or an - // Rvalue. This is relevant because they are handled differently. + // Lvalue or an Rvalue. This is relevant because they are handled + // differently. // // For Lvalues // @@ -293,9 +292,8 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, // // - During dematerialization, $0 is ignored. - bool is_lvalue = (last_expr->getValueKind() == VK_LValue || - last_expr->getValueKind() == VK_XValue) && - (last_expr->getObjectKind() == OK_Ordinary); + bool is_lvalue = last_expr->getValueKind() == VK_LValue && + last_expr->getObjectKind() == OK_Ordinary; QualType expr_qual_type = last_expr->getType(); const clang::Type *expr_type = expr_qual_type.getTypePtr(); diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h index c0e6c0358a23..859a1dfa5f73 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h +++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h @@ -18,18 +18,17 @@ namespace lldb_private { //---------------------------------------------------------------------- /// @class ASTResultSynthesizer ASTResultSynthesizer.h -/// "lldb/Expression/ASTResultSynthesizer.h" -/// @brief Adds a result variable declaration to the ASTs for an expression. +/// "lldb/Expression/ASTResultSynthesizer.h" Adds a result variable +/// declaration to the ASTs for an expression. /// /// Users expect the expression "i + 3" to return a result, even if a result /// variable wasn't specifically declared. To fulfil this requirement, LLDB -/// adds -/// a result variable to the expression, transforming it to -/// "int $__lldb_expr_result = i + 3." The IR transformers ensure that the +/// adds a result variable to the expression, transforming it to "int +/// $__lldb_expr_result = i + 3." The IR transformers ensure that the /// resulting variable is mapped to the right piece of memory. -/// ASTResultSynthesizer's job is to add the variable and its initialization to -/// the ASTs for the expression, and it does so by acting as a SemaConsumer for -/// Clang. +/// ASTResultSynthesizer's job is to add the variable and its initialization +/// to the ASTs for the expression, and it does so by acting as a SemaConsumer +/// for Clang. //---------------------------------------------------------------------- class ASTResultSynthesizer : public clang::SemaConsumer { public: @@ -68,8 +67,8 @@ public: void Initialize(clang::ASTContext &Context) override; //---------------------------------------------------------------------- - /// Examine a list of Decls to find the function $__lldb_expr and - /// transform its code + /// Examine a list of Decls to find the function $__lldb_expr and transform + /// its code /// /// @param[in] D /// The list of Decls to search. These may contain LinkageSpecDecls, @@ -124,8 +123,8 @@ public: private: //---------------------------------------------------------------------- - /// Hunt the given Decl for FunctionDecls named $__lldb_expr, recursing - /// as necessary through LinkageSpecDecls, and calling SynthesizeResult on + /// Hunt the given Decl for FunctionDecls named $__lldb_expr, recursing as + /// necessary through LinkageSpecDecls, and calling SynthesizeResult on /// anything that was found /// /// @param[in] D @@ -164,8 +163,8 @@ private: bool SynthesizeBodyResult(clang::CompoundStmt *Body, clang::DeclContext *DC); //---------------------------------------------------------------------- - /// Given a DeclContext for a function or method, find all types - /// declared in the context and record any persistent types found. + /// Given a DeclContext for a function or method, find all types declared in + /// the context and record any persistent types found. /// /// @param[in] FunDeclCtx /// The context for the function to process. @@ -173,8 +172,8 @@ private: void RecordPersistentTypes(clang::DeclContext *FunDeclCtx); //---------------------------------------------------------------------- - /// Given a TypeDecl, if it declares a type whose name starts with a - /// dollar sign, register it as a pointer type in the target's scratch + /// Given a TypeDecl, if it declares a type whose name starts with a dollar + /// sign, register it as a pointer type in the target's scratch /// AST context. /// /// @param[in] Body diff --git a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h index 63e3161cae85..65f4b00a8651 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h +++ b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h @@ -20,20 +20,19 @@ namespace lldb_private { //---------------------------------------------------------------------- /// @class ASTStructExtractor ASTStructExtractor.h -/// "lldb/Expression/ASTStructExtractor.h" -/// @brief Extracts and describes the argument structure for a wrapped function. +/// "lldb/Expression/ASTStructExtractor.h" Extracts and describes the argument +/// structure for a wrapped function. /// /// This pass integrates with ClangFunctionCaller, which calls functions with -/// custom -/// sets of arguments. To avoid having to implement the full calling convention -/// for the target's architecture, ClangFunctionCaller writes a simple wrapper -/// function that takes a pointer to an argument structure that contains room -/// for the address of the function to be called, the values of all its -/// arguments, and room for the function's return value. +/// custom sets of arguments. To avoid having to implement the full calling +/// convention for the target's architecture, ClangFunctionCaller writes a +/// simple wrapper function that takes a pointer to an argument structure that +/// contains room for the address of the function to be called, the values of +/// all its arguments, and room for the function's return value. /// -/// The definition of this struct is itself in the body of the wrapper function, -/// so Clang does the structure layout itself. ASTStructExtractor reads through -/// the AST for the wrapper function and finds the struct. +/// The definition of this struct is itself in the body of the wrapper +/// function, so Clang does the structure layout itself. ASTStructExtractor +/// reads through the AST for the wrapper function and finds the struct. //---------------------------------------------------------------------- class ASTStructExtractor : public clang::SemaConsumer { public: @@ -73,8 +72,8 @@ public: void Initialize(clang::ASTContext &Context) override; //---------------------------------------------------------------------- - /// Examine a list of Decls to find the function $__lldb_expr and - /// transform its code + /// Examine a list of Decls to find the function $__lldb_expr and transform + /// its code /// /// @param[in] D /// The list of Decls to search. These may contain LinkageSpecDecls, diff --git a/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/source/Plugins/ExpressionParser/Clang/CMakeLists.txt index a780e7d597b1..ec4f6d5674e1 100644 --- a/source/Plugins/ExpressionParser/Clang/CMakeLists.txt +++ b/source/Plugins/ExpressionParser/Clang/CMakeLists.txt @@ -11,6 +11,7 @@ add_lldb_library(lldbPluginExpressionParserClang PLUGIN ClangExpressionParser.cpp ClangExpressionVariable.cpp ClangFunctionCaller.cpp + ClangHost.cpp ClangModulesDeclVendor.cpp ClangPersistentVariables.cpp ClangUserExpression.cpp @@ -23,6 +24,7 @@ add_lldb_library(lldbPluginExpressionParserClang PLUGIN LINK_LIBS clangAST clangCodeGen + clangDriver clangEdit clangFrontend clangLex diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 7f031356b3c3..d98a2b25fbb7 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -33,8 +33,8 @@ using namespace clang; using namespace lldb_private; //------------------------------------------------------------------ -// Scoped class that will remove an active lexical decl from the set -// when it goes out of scope. +// Scoped class that will remove an active lexical decl from the set when it +// goes out of scope. //------------------------------------------------------------------ namespace { class ScopedLexicalDeclEraser { @@ -141,8 +141,8 @@ ClangASTSource::~ClangASTSource() { m_ast_importer_sp->ForgetDestination(m_ast_context); // We are in the process of destruction, don't create clang ast context on - // demand - // by passing false to Target::GetScratchClangASTContext(create_on_demand). + // demand by passing false to + // Target::GetScratchClangASTContext(create_on_demand). ClangASTContext *scratch_clang_ast_context = m_target->GetScratchClangASTContext(false); @@ -231,8 +231,8 @@ bool ClangASTSource::FindExternalVisibleDeclsByName( } if (!GetLookupsEnabled()) { - // Wait until we see a '$' at the start of a name before we start doing - // any lookups so we can avoid lookup up all of the builtin types. + // Wait until we see a '$' at the start of a name before we start doing any + // lookups so we can avoid lookup up all of the builtin types. if (!decl_name.empty() && decl_name[0] == '$') { SetLookupsEnabled(true); } else { @@ -297,8 +297,8 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { } if (!m_ast_importer_sp->CompleteTagDecl(tag_decl)) { - // We couldn't complete the type. Maybe there's a definition - // somewhere else that can be completed. + // We couldn't complete the type. Maybe there's a definition somewhere + // else that can be completed. if (log) log->Printf(" CTD[%u] Type could not be completed in the module in " @@ -398,8 +398,8 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { const_cast<TagDecl *>(tag_type->getDecl()); // We have found a type by basename and we need to make sure the decl - // contexts - // are the same before we can try to complete this type with another + // contexts are the same before we can try to complete this type with + // another if (!ClangASTContext::DeclsAreEquivalent(tag_decl, candidate_tag_decl)) continue; @@ -861,13 +861,16 @@ void ClangASTSource::FindExternalVisibleDecls( TypeList types; SymbolContext null_sc; - const bool exact_match = false; + 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); - else - m_target->GetImages().FindTypes(null_sc, name, exact_match, 1, + else { + SymbolContext sc; + sc.module_sp = module_sp; + m_target->GetImages().FindTypes(sc, name, exact_match, 1, searched_symbol_files, types); + } if (size_t num_types = types.GetSize()) { for (size_t ti = 0; ti < num_types; ++ti) { @@ -1243,8 +1246,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { break; // Fall back and check for methods in categories. If we find methods this - // way, we need to check that they're actually in - // categories on the desired class. + // way, we need to check that they're actually in categories on the desired + // class. SymbolContextList candidate_sc_list; @@ -1591,8 +1594,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { do { // Check the runtime only if the debug information didn't have a complete - // interface - // and nothing was in the modules. + // interface and nothing was in the modules. lldb::ProcessSP process(m_target->GetProcessSP()); @@ -1645,12 +1647,9 @@ static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map, ClangASTSource &source) { // When importing fields into a new record, clang has a hard requirement that // fields be imported in field offset order. Since they are stored in a - // DenseMap - // with a pointer as the key type, this means we cannot simply iterate over - // the - // map, as the order will be non-deterministic. Instead we have to sort by - // the offset - // and then insert in sorted order. + // DenseMap with a pointer as the key type, this means we cannot simply + // iterate over the map, as the order will be non-deterministic. Instead we + // have to sort by the offset and then insert in sorted order. typedef llvm::DenseMap<const D *, O> MapType; typedef typename MapType::value_type PairType; std::vector<PairType> sorted_items; @@ -2051,9 +2050,8 @@ CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { if (copied_qual_type.getAsOpaquePtr() && copied_qual_type->getCanonicalTypeInternal().isNull()) - // this shouldn't happen, but we're hardening because the AST importer seems - // to be generating bad types - // on occasion. + // this shouldn't happen, but we're hardening because the AST importer + // seems to be generating bad types on occasion. return CompilerType(); return CompilerType(m_ast_context, copied_qual_type); @@ -2156,6 +2154,18 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, log->Printf("Function type wasn't a FunctionProtoType"); } + // If this is an operator (e.g. operator new or operator==), only insert the + // declaration we inferred from the symbol if we can provide the correct + // number of arguments. We shouldn't really inject random decl(s) for + // functions that are analyzed semantically in a special way, otherwise we + // will crash in clang. + clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; + if (func_proto_type && + ClangASTContext::IsOperator(decl_name.getAsString().c_str(), op_kind)) { + if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount( + false, op_kind, func_proto_type->getNumParams())) + return NULL; + } m_decls.push_back(func_decl); return func_decl; diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index 6f72ad92dc8c..a42422b0f97f 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -25,14 +25,13 @@ namespace lldb_private { //---------------------------------------------------------------------- /// @class ClangASTSource ClangASTSource.h "lldb/Expression/ClangASTSource.h" -/// @brief Provider for named objects defined in the debug info for Clang +/// Provider for named objects defined in the debug info for Clang /// -/// As Clang parses an expression, it may encounter names that are not -/// defined inside the expression, including variables, functions, and -/// types. Clang knows the name it is looking for, but nothing else. -/// The ExternalSemaSource class provides Decls (VarDecl, FunDecl, TypeDecl) -/// to Clang for these names, consulting the ClangExpressionDeclMap to do -/// the actual lookups. +/// As Clang parses an expression, it may encounter names that are not defined +/// inside the expression, including variables, functions, and types. Clang +/// knows the name it is looking for, but nothing else. The ExternalSemaSource +/// class provides Decls (VarDecl, FunDecl, TypeDecl) to Clang for these +/// names, consulting the ClangExpressionDeclMap to do the actual lookups. //---------------------------------------------------------------------- class ClangASTSource : public ClangExternalASTSourceCommon, public ClangASTImporter::MapCompleter { @@ -78,8 +77,8 @@ public: //------------------------------------------------------------------ /// Look up all Decls that match a particular name. Only handles /// Identifiers and DeclContexts that are either NamespaceDecls or - /// TranslationUnitDecls. Calls SetExternalVisibleDeclsForName with - /// the result. + /// TranslationUnitDecls. Calls SetExternalVisibleDeclsForName with the + /// result. /// /// The work for this function is done by /// void FindExternalVisibleDecls (NameSearchContext &); @@ -173,8 +172,8 @@ public: //------------------------------------------------------------------ /// Called on entering a translation unit. Tells Clang by calling - /// setHasExternalVisibleStorage() and setHasExternalLexicalStorage() - /// that this object has something to say about undefined names. + /// setHasExternalVisibleStorage() and setHasExternalLexicalStorage() that + /// this object has something to say about undefined names. /// /// @param[in] ASTConsumer /// Unused. @@ -186,8 +185,8 @@ public: // //------------------------------------------------------------------ - /// Look up the modules containing a given namespace and put the - /// appropriate entries in the namespace map. + /// Look up the modules containing a given namespace and put the appropriate + /// entries in the namespace map. /// /// @param[in] namespace_map /// The map to be completed. @@ -231,11 +230,10 @@ public: //---------------------------------------------------------------------- /// @class ClangASTSourceProxy ClangASTSource.h - /// "lldb/Expression/ClangASTSource.h" - /// @brief Proxy for ClangASTSource + /// "lldb/Expression/ClangASTSource.h" Proxy for ClangASTSource /// - /// Clang AST contexts like to own their AST sources, so this is a - /// state-free proxy object. + /// Clang AST contexts like to own their AST sources, so this is a state- + /// free proxy object. //---------------------------------------------------------------------- class ClangASTSourceProxy : public ClangExternalASTSourceCommon { public: @@ -298,8 +296,8 @@ public: protected: //------------------------------------------------------------------ - /// Look for the complete version of an Objective-C interface, and - /// return it if found. + /// Look for the complete version of an Objective-C interface, and return it + /// if found. /// /// @param[in] interface_decl /// An ObjCInterfaceDecl that may not be the complete one. @@ -312,8 +310,8 @@ protected: GetCompleteObjCInterface(const clang::ObjCInterfaceDecl *interface_decl); //------------------------------------------------------------------ - /// Find all entities matching a given name in a given module, - /// using a NameSearchContext to make Decls for them. + /// Find all entities matching a given name in a given module, using a + /// NameSearchContext to make Decls for them. /// /// @param[in] context /// The NameSearchContext that can construct Decls for this name. @@ -474,8 +472,9 @@ protected: }; //---------------------------------------------------------------------- -/// @class NameSearchContext ClangASTSource.h "lldb/Expression/ClangASTSource.h" -/// @brief Container for all objects relevant to a single name lookup +/// @class NameSearchContext ClangASTSource.h +/// "lldb/Expression/ClangASTSource.h" Container for all objects relevant to a +/// single name lookup /// /// LLDB needs to create Decls for entities it finds. This class communicates /// what name is being searched for and provides helper functions to construct @@ -532,8 +531,8 @@ struct NameSearchContext { } //------------------------------------------------------------------ - /// Create a VarDecl with the name being searched for and the provided - /// type and register it in the right places. + /// Create a VarDecl with the name being searched for and the provided type + /// and register it in the right places. /// /// @param[in] type /// The opaque QualType for the VarDecl being registered. @@ -541,8 +540,8 @@ struct NameSearchContext { clang::NamedDecl *AddVarDecl(const CompilerType &type); //------------------------------------------------------------------ - /// Create a FunDecl with the name being searched for and the provided - /// type and register it in the right places. + /// Create a FunDecl with the name being searched for and the provided type + /// and register it in the right places. /// /// @param[in] type /// The opaque QualType for the FunDecl being registered. @@ -553,15 +552,14 @@ struct NameSearchContext { clang::NamedDecl *AddFunDecl(const CompilerType &type, bool extern_c = false); //------------------------------------------------------------------ - /// Create a FunDecl with the name being searched for and generic - /// type (i.e. intptr_t NAME_GOES_HERE(...)) and register it in the - /// right places. + /// Create a FunDecl with the name being searched for and generic type (i.e. + /// intptr_t NAME_GOES_HERE(...)) and register it in the right places. //------------------------------------------------------------------ clang::NamedDecl *AddGenericFunDecl(); //------------------------------------------------------------------ - /// Create a TypeDecl with the name being searched for and the provided - /// type and register it in the right places. + /// Create a TypeDecl with the name being searched for and the provided type + /// and register it in the right places. /// /// @param[in] compiler_type /// The opaque QualType for the TypeDecl being registered. @@ -569,8 +567,8 @@ struct NameSearchContext { clang::NamedDecl *AddTypeDecl(const CompilerType &compiler_type); //------------------------------------------------------------------ - /// Add Decls from the provided DeclContextLookupResult to the list - /// of results. + /// Add Decls from the provided DeclContextLookupResult to the list of + /// results. /// /// @param[in] result /// The DeclContextLookupResult, usually returned as the result diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 07ff2e97aac7..0811a7999920 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -213,8 +213,8 @@ private: m_exporter.getFromContext().getSourceManager().getFileID(loc); if (file != m_file) return false; - // We are assuming the Decl was parsed in this very expression, so it should - // not have external storage. + // We are assuming the Decl was parsed in this very expression, so it + // should not have external storage. lldbassert(!llvm::cast<DeclContext>(decl)->hasExternalLexicalStorage()); return true; } @@ -591,8 +591,8 @@ bool ClangExpressionDeclMap::GetFunctionInfo(const NamedDecl *decl, if (!entity) return false; - // We know m_parser_vars is valid since we searched for the variable by - // its NamedDecl + // We know m_parser_vars is valid since we searched for the variable by its + // NamedDecl ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID()); @@ -720,9 +720,9 @@ lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable( VariableList vars; if (module && namespace_decl) - module->FindGlobalVariables(name, namespace_decl, true, -1, vars); + module->FindGlobalVariables(name, namespace_decl, -1, vars); else - target.GetImages().FindGlobalVariables(name, true, -1, vars); + target.GetImages().FindGlobalVariables(name, -1, vars); if (vars.GetSize()) { if (type) { @@ -867,8 +867,8 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( if (IgnoreName(name, false)) return; - // Only look for functions by name out in our symbols if the function - // doesn't start with our phony prefix of '$' + // Only look for functions by name out in our symbols if the function doesn't + // start with our phony prefix of '$' Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); SymbolContext sym_ctx; @@ -977,13 +977,11 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( m_struct_vars->m_object_pointer_type = self_user_type; } } else { - // This branch will get hit if we are executing code in the context of a - // function that - // claims to have an object pointer (through DW_AT_object_pointer?) but - // is not formally a - // method of the class. In that case, just look up the "this" variable - // in the current - // scope and use its type. + // This branch will get hit if we are executing code in the context of + // a function that claims to have an object pointer (through + // DW_AT_object_pointer?) but is not formally a method of the class. + // In that case, just look up the "this" variable in the current scope + // and use its type. // FIXME: This code is formally correct, but clang doesn't currently // emit DW_AT_object_pointer // for C++ so it hasn't actually been tested. @@ -1093,13 +1091,11 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( return; } else { - // This branch will get hit if we are executing code in the context of a - // function that - // claims to have an object pointer (through DW_AT_object_pointer?) but - // is not formally a - // method of the class. In that case, just look up the "self" variable - // in the current - // scope and use its type. + // This branch will get hit if we are executing code in the context of + // a function that claims to have an object pointer (through + // DW_AT_object_pointer?) but is not formally a method of the class. + // In that case, just look up the "self" variable in the current scope + // and use its type. VariableList *vars = frame->GetVariableList(false); @@ -1217,9 +1213,8 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( vars->GetVariableAtIndex(i)->GetDecl(); // Search for declarations matching the name. Do not include imported - // decls - // in the search if we are looking for decls in the artificial namespace - // $__lldb_local_vars. + // decls in the search if we are looking for decls in the artificial + // namespace $__lldb_local_vars. std::vector<CompilerDecl> found_decls = compiler_decl_context.FindDeclByName(name, namespace_decl.IsValid()); @@ -1285,15 +1280,15 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( append, sc_list); } - // If we found more than one function, see if we can use the - // frame's decl context to remove functions that are shadowed - // by other functions which match in type but are nearer in scope. + // If we found more than one function, see if we can use the frame's decl + // context to remove functions that are shadowed by other functions which + // match in type but are nearer in scope. // // AddOneFunction will not add a function whose type has already been - // added, so if there's another function in the list with a matching - // type, check to see if their decl context is a parent of the current - // frame's or was imported via a and using statement, and pick the - // best match according to lookup rules. + // added, so if there's another function in the list with a matching type, + // check to see if their decl context is a parent of the current frame's or + // was imported via a and using statement, and pick the best match + // according to lookup rules. if (sc_list.GetSize() > 1) { // Collect some info about our frame's context. StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); @@ -1321,11 +1316,10 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( SymbolContext m_sym_ctx; }; - // First, symplify things by looping through the symbol contexts - // to remove unwanted functions and separate out the functions we - // want to compare and prune into a separate list. - // Cache the info needed about the function declarations in a - // vector for efficiency. + // First, symplify things by looping through the symbol contexts to + // remove unwanted functions and separate out the functions we want to + // compare and prune into a separate list. Cache the info needed about + // the function declarations in a vector for efficiency. SymbolContextList sc_sym_list; uint32_t num_indices = sc_list.GetSize(); std::vector<FuncDeclInfo> fdi_cache; @@ -1335,16 +1329,16 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( SymbolContext sym_ctx; sc_list.GetContextAtIndex(index, sym_ctx); - // We don't know enough about symbols to compare them, - // but we should keep them in the list. + // We don't know enough about symbols to compare them, but we should + // keep them in the list. Function *function = sym_ctx.function; if (!function) { sc_sym_list.Append(sym_ctx); continue; } // Filter out functions without declaration contexts, as well as - // class/instance methods, since they'll be skipped in the - // code that follows anyway. + // class/instance methods, since they'll be skipped in the code that + // follows anyway. CompilerDeclContext func_decl_context = function->GetDeclContext(); if (!func_decl_context || func_decl_context.IsClassMethod(nullptr, nullptr, nullptr)) @@ -1363,11 +1357,10 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( fdi.m_copied_type = copied_func_type; fdi.m_decl_lvl = LLDB_INVALID_DECL_LEVEL; if (fdi.m_copied_type && func_decl_context) { - // Call CountDeclLevels to get the number of parent scopes we - // have to look through before we find the function declaration. - // When comparing functions of the same type, the one with a - // lower count will be closer to us in the lookup scope and - // shadows the other. + // Call CountDeclLevels to get the number of parent scopes we have + // to look through before we find the function declaration. When + // comparing functions of the same type, the one with a lower count + // will be closer to us in the lookup scope and shadows the other. clang::DeclContext *func_decl_ctx = (clang::DeclContext *)func_decl_context.GetOpaqueDeclContext(); fdi.m_decl_lvl = ast->CountDeclLevels( @@ -1536,9 +1529,8 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( } if (target && !context.m_found.variable && !namespace_decl) { - // We couldn't find a non-symbol variable for this. Now we'll hunt for - // a generic - // data symbol, and -- if it is found -- treat it as a variable. + // We couldn't find a non-symbol variable for this. Now we'll hunt for a + // generic data symbol, and -- if it is found -- treat it as a variable. Status error; const Symbol *data_symbol = @@ -2116,7 +2108,8 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, parser_vars->m_llvm_value = NULL; if (log) { - ASTDumper ast_dumper(function_decl); + std::string function_str = + function_decl ? ASTDumper(function_decl).GetCString() : "nullptr"; StreamString ss; @@ -2127,7 +2120,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, log->Printf( " CEDM::FEVD[%u] Found %s function %s (description %s), returned %s", current_id, (function ? "specific" : "generic"), decl_name.c_str(), - ss.GetData(), ast_dumper.GetCString()); + ss.GetData(), function_str.c_str()); } } @@ -2165,7 +2158,7 @@ void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, CXXMethodDecl *method_decl = ClangASTContext::GetASTContext(m_ast_context) ->AddMethodToCXXRecordType( - copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", + copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", NULL, method_type, lldb::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index d163ad4f7e29..b67387930190 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -36,29 +36,28 @@ namespace lldb_private { //---------------------------------------------------------------------- /// @class ClangExpressionDeclMap ClangExpressionDeclMap.h -/// "lldb/Expression/ClangExpressionDeclMap.h" -/// @brief Manages named entities that are defined in LLDB's debug information. +/// "lldb/Expression/ClangExpressionDeclMap.h" Manages named entities that are +/// defined in LLDB's debug information. /// /// The Clang parser uses the ClangASTSource as an interface to request named /// entities from outside an expression. The ClangASTSource reports back, -/// listing -/// all possible objects corresponding to a particular name. But it in turn -/// relies on ClangExpressionDeclMap, which performs several important +/// listing all possible objects corresponding to a particular name. But it +/// in turn relies on ClangExpressionDeclMap, which performs several important /// functions. /// -/// First, it records what variables and functions were looked up and what Decls -/// were returned for them. +/// First, it records what variables and functions were looked up and what +/// Decls were returned for them. /// /// Second, it constructs a struct on behalf of IRForTarget, recording which -/// variables should be placed where and relaying this information back so that -/// IRForTarget can generate context-independent code. +/// variables should be placed where and relaying this information back so +/// that IRForTarget can generate context-independent code. /// /// Third, it "materializes" this struct on behalf of the expression command, /// finding the current values of each variable and placing them into the /// struct so that it can be passed to the JITted version of the IR. /// -/// Fourth and finally, it "dematerializes" the struct after the JITted code has -/// has executed, placing the new values back where it found the old ones. +/// Fourth and finally, it "dematerializes" the struct after the JITted code +/// has has executed, placing the new values back where it found the old ones. //---------------------------------------------------------------------- class ClangExpressionDeclMap : public ClangASTSource { public: @@ -169,8 +168,8 @@ public: lldb::offset_t alignment); //------------------------------------------------------------------ - /// [Used by IRForTarget] Finalize the struct, laying out the position - /// of each object in it. + /// [Used by IRForTarget] Finalize the struct, laying out the position of + /// each object in it. /// /// @return /// True on success; false otherwise. @@ -178,8 +177,8 @@ public: bool DoStructLayout(); //------------------------------------------------------------------ - /// [Used by IRForTarget] Get general information about the laid-out - /// struct after DoStructLayout() has been called. + /// [Used by IRForTarget] Get general information about the laid-out struct + /// after DoStructLayout() has been called. /// /// @param[out] num_elements /// The number of elements in the struct. @@ -197,8 +196,8 @@ public: lldb::offset_t &alignment); //------------------------------------------------------------------ - /// [Used by IRForTarget] Get specific information about one field - /// of the laid-out struct after DoStructLayout() has been called. + /// [Used by IRForTarget] Get specific information about one field of the + /// laid-out struct after DoStructLayout() has been called. /// /// @param[out] decl /// The parsed Decl for the field, as generated by ClangASTSource @@ -232,8 +231,7 @@ public: uint32_t index); //------------------------------------------------------------------ - /// [Used by IRForTarget] Get information about a function given its - /// Decl. + /// [Used by IRForTarget] Get information about a function given its Decl. /// /// @param[in] decl /// The parsed Decl for the Function, as generated by ClangASTSource @@ -248,8 +246,8 @@ public: bool GetFunctionInfo(const clang::NamedDecl *decl, uint64_t &ptr); //------------------------------------------------------------------ - /// [Used by IRForTarget] Get the address of a symbol given nothing - /// but its name. + /// [Used by IRForTarget] Get the address of a symbol given nothing but its + /// name. /// /// @param[in] target /// The target to find the symbol in. If not provided, @@ -303,8 +301,8 @@ public: TargetInfo GetTargetInfo(); //------------------------------------------------------------------ - /// [Used by ClangASTSource] Find all entities matching a given name, - /// using a NameSearchContext to make Decls for them. + /// [Used by ClangASTSource] Find all entities matching a given name, using + /// a NameSearchContext to make Decls for them. /// /// @param[in] context /// The NameSearchContext that can construct Decls for this name. @@ -442,14 +440,13 @@ private: void DisableStructVars() { m_struct_vars.reset(); } //---------------------------------------------------------------------- - /// Get this parser's ID for use in extracting parser- and JIT-specific - /// data from persistent variables. + /// Get this parser's ID for use in extracting parser- and JIT-specific data + /// from persistent variables. //---------------------------------------------------------------------- uint64_t GetParserID() { return (uint64_t) this; } //------------------------------------------------------------------ - /// Given a target, find a variable that matches the given name and - /// type. + /// Given a target, find a variable that matches the given name and type. /// /// @param[in] target /// The target to use as a basis for finding the variable. @@ -477,8 +474,8 @@ private: TypeFromUser *type = NULL); //------------------------------------------------------------------ - /// Get the value of a variable in a given execution context and return - /// the associated Types if needed. + /// Get the value of a variable in a given execution context and return the + /// associated Types if needed. /// /// @param[in] var /// The variable to evaluate. @@ -524,8 +521,8 @@ private: lldb::ValueObjectSP valobj, unsigned int current_id); //------------------------------------------------------------------ - /// Use the NameSearchContext to generate a Decl for the given - /// persistent variable, and put it in the list of found entities. + /// Use the NameSearchContext to generate a Decl for the given persistent + /// variable, and put it in the list of found entities. /// /// @param[in] context /// The NameSearchContext to use when constructing the Decl. @@ -542,9 +539,8 @@ private: unsigned int current_id); //------------------------------------------------------------------ - /// Use the NameSearchContext to generate a Decl for the given LLDB - /// symbol (treated as a variable), and put it in the list of found - /// entities. + /// Use the NameSearchContext to generate a Decl for the given LLDB symbol + /// (treated as a variable), and put it in the list of found entities. /// /// @param[in] context /// The NameSearchContext to use when constructing the Decl. @@ -556,9 +552,9 @@ private: unsigned int current_id); //------------------------------------------------------------------ - /// Use the NameSearchContext to generate a Decl for the given - /// function. (Functions are not placed in the Tuple list.) Can - /// handle both fully typed functions and generic functions. + /// Use the NameSearchContext to generate a Decl for the given function. + /// (Functions are not placed in the Tuple list.) Can handle both fully + /// typed functions and generic functions. /// /// @param[in] context /// The NameSearchContext to use when constructing the Decl. @@ -575,8 +571,7 @@ private: unsigned int current_id); //------------------------------------------------------------------ - /// Use the NameSearchContext to generate a Decl for the given - /// register. + /// Use the NameSearchContext to generate a Decl for the given register. /// /// @param[in] context /// The NameSearchContext to use when constructing the Decl. @@ -588,8 +583,8 @@ private: unsigned int current_id); //------------------------------------------------------------------ - /// Use the NameSearchContext to generate a Decl for the given - /// type. (Types are not placed in the Tuple list.) + /// Use the NameSearchContext to generate a Decl for the given type. (Types + /// are not placed in the Tuple list.) /// /// @param[in] context /// The NameSearchContext to use when constructing the Decl. @@ -601,8 +596,8 @@ private: unsigned int current_id); //------------------------------------------------------------------ - /// Generate a Decl for "*this" and add a member function declaration - /// to it for the expression, then report it. + /// Generate a Decl for "*this" and add a member function declaration to it + /// for the expression, then report it. /// /// @param[in] context /// The NameSearchContext to use when constructing the Decl. diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index d9e53074b3fb..c5406fcc3340 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -182,8 +182,7 @@ public: m_manager->AddDiagnostic(new_diagnostic); // Don't store away warning fixits, since the compiler doesn't have - // enough - // context in an expression for the warning to be useful. + // enough context in an expression for the warning to be useful. // FIXME: Should we try to filter out FixIts that apply to our generated // code, and not the user's expression? if (severity == eDiagnosticSeverityError) { @@ -226,10 +225,9 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, m_code_generator(), 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 null - // or doesn't have a target, - // then we just need to get out of here. I'll lldb_assert and not make any of - // the compiler objects since + // We can't compile expressions without a target. So if the exe_scope is + // null or doesn't have a target, then we just need to get out of here. I'll + // lldb_assert and not make any of the compiler objects since // I can't return errors directly from the constructor. Further calls will // check if the compiler was made and // bag out if it wasn't. @@ -262,14 +260,14 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, const auto target_machine = target_arch.GetMachine(); - // If the expression is being evaluated in the context of an existing - // stack frame, we introspect to see if the language runtime is available. + // If the expression is being evaluated in the context of an existing stack + // frame, we introspect to see if the language runtime is available. lldb::StackFrameSP frame_sp = exe_scope->CalculateStackFrame(); lldb::ProcessSP process_sp = exe_scope->CalculateProcess(); - // Make sure the user hasn't provided a preferred execution language - // with `expression --language X -- ...` + // Make sure the user hasn't provided a preferred execution language with + // `expression --language X -- ...` if (frame_sp && frame_lang == lldb::eLanguageTypeUnknown) frame_lang = frame_sp->GetLanguage(); @@ -281,8 +279,7 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, } // 2. Configure the compiler with a set of default options that are - // appropriate - // for most situations. + // appropriate for most situations. if (target_arch.IsValid()) { std::string triple = target_arch.GetTriple().str(); m_compiler->getTargetOpts().Triple = triple; @@ -292,19 +289,17 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, } else { // If we get here we don't have a valid target and just have to guess. // Sometimes this will be ok to just use the host target triple (when we - // evaluate say "2+3", but other - // expressions like breakpoint conditions and other things that _are_ target - // specific really shouldn't just be - // using the host triple. In such a case the language runtime should expose - // an overridden options set (3), - // below. + // evaluate say "2+3", but other expressions like breakpoint conditions and + // other things that _are_ target specific really shouldn't just be using + // the host triple. In such a case the language runtime should expose an + // overridden options set (3), below. m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple(); if (log) log->Printf("Using default target triple of %s", m_compiler->getTargetOpts().Triple.c_str()); } - // Now add some special fixes for known architectures: - // Any arm32 iOS environment, but not on arm64 + // Now add some special fixes for known architectures: Any arm32 iOS + // environment, but not on arm64 if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos && m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos && m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos) { @@ -317,8 +312,8 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, m_compiler->getTargetOpts().Features.push_back("+sse2"); } - // Set the target CPU to generate code for. - // This will be empty for any CPU that doesn't really need to make a special + // Set the target CPU to generate code for. This will be empty for any CPU + // that doesn't really need to make a special // CPU string. m_compiler->getTargetOpts().CPU = target_arch.GetClangTargetCPU(); @@ -328,11 +323,9 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, m_compiler->getTargetOpts().ABI = abi; // 3. Now allow the runtime to provide custom configuration options for the - // target. - // In this case, a specialized language runtime is available and we can query - // it for extra options. - // For 99% of use cases, this will not be needed and should be provided when - // basic platform detection is not enough. + // target. In this case, a specialized language runtime is available and we + // can query it for extra options. For 99% of use cases, this will not be + // needed and should be provided when basic platform detection is not enough. if (lang_rt) overridden_target_opts = lang_rt->GetOverrideExprOptions(m_compiler->getTargetOpts()); @@ -378,9 +371,9 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, case lldb::eLanguageTypeC11: // FIXME: the following language option is a temporary workaround, // to "ask for C, get C++." - // For now, the expression parser must use C++ anytime the - // language is a C family language, because the expression parser - // uses features of C++ to capture values. + // For now, the expression parser must use C++ anytime the language is a C + // family language, because the expression parser uses features of C++ to + // capture values. m_compiler->getLangOpts().CPlusPlus = true; break; case lldb::eLanguageTypeObjC: @@ -392,10 +385,10 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, // Clang now sets as default C++14 as the default standard (with // GNU extensions), so we do the same here to avoid mismatches that - // cause compiler error when evaluating expressions (e.g. nullptr - // not found as it's a C++11 feature). Currently lldb evaluates - // C++14 as C++11 (see two lines below) so we decide to be consistent - // with that, but this could be re-evaluated in the future. + // cause compiler error when evaluating expressions (e.g. nullptr not found + // as it's a C++11 feature). Currently lldb evaluates C++14 as C++11 (see + // two lines below) so we decide to be consistent with that, but this could + // be re-evaluated in the future. m_compiler->getLangOpts().CPlusPlus11 = true; break; case lldb::eLanguageTypeC_plus_plus: @@ -407,8 +400,8 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, 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. + // 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; break; case lldb::eLanguageTypeObjC_plus_plus: @@ -434,10 +427,9 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, ArchSpec(m_compiler->getTargetOpts().Triple.c_str()) .CharIsSignedByDefault(); - // Spell checking is a nice feature, but it ends up completing a - // lot of types that we didn't strictly speaking need to complete. - // As a result, we spend a long time parsing and importing debug - // information. + // Spell checking is a nice feature, but it ends up completing a lot of types + // that we didn't strictly speaking need to complete. As a result, we spend a + // long time parsing and importing debug information. m_compiler->getLangOpts().SpellChecking = false; if (process_sp && m_compiler->getLangOpts().ObjC1) { @@ -513,8 +505,8 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks)); } - // 8. Most of this we get from the CompilerInstance, but we - // also want to give the context an ExternalASTSource. + // 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()); @@ -569,9 +561,7 @@ unsigned ClangExpressionParser::Parse(DiagnosticManager &diagnostic_manager) { codegenoptions::FullDebugInfo) { int temp_fd = -1; llvm::SmallString<PATH_MAX> result_path; - FileSpec tmpdir_file_spec; - if (HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, - tmpdir_file_spec)) { + if (FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir()) { tmpdir_file_spec.AppendPathComponent("lldb-%%%%%%.expr"); std::string temp_source_path = tmpdir_file_spec.GetPath(); llvm::sys::fs::createUniqueFile(temp_source_path, temp_fd, result_path); @@ -811,7 +801,7 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( { auto lang = m_expr.Language(); if (log) - log->Printf("%s - Currrent expression language is %s\n", __FUNCTION__, + log->Printf("%s - Current expression language is %s\n", __FUNCTION__, Language::GetNameForLanguageType(lang)); lldb::ProcessSP process_sp = exe_ctx.GetProcessSP(); if (process_sp && lang != lldb::eLanguageTypeUnknown) { diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h index 41f290f2e127..4058ec1270b3 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h @@ -26,14 +26,14 @@ class IRExecutionUnit; //---------------------------------------------------------------------- /// @class ClangExpressionParser ClangExpressionParser.h -/// "lldb/Expression/ClangExpressionParser.h" -/// @brief Encapsulates an instance of Clang that can parse expressions. +/// "lldb/Expression/ClangExpressionParser.h" Encapsulates an instance of +/// Clang that can parse expressions. /// /// ClangExpressionParser is responsible for preparing an instance of /// ClangExpression for execution. ClangExpressionParser uses ClangExpression /// as a glorified parameter list, performing the required parsing and -/// conversion to formats (DWARF bytecode, or JIT compiled machine code) -/// that can be executed. +/// conversion to formats (DWARF bytecode, or JIT compiled machine code) that +/// can be executed. //---------------------------------------------------------------------- class ClangExpressionParser : public ExpressionParser { public: @@ -59,8 +59,8 @@ public: ~ClangExpressionParser() override; //------------------------------------------------------------------ - /// Parse a single expression and convert it to IR using Clang. Don't - /// wrap the expression in anything at all. + /// Parse a single expression and convert it to IR using Clang. Don't wrap + /// the expression in anything at all. /// /// @param[in] diagnostic_manager /// The diagnostic manager to report errors to. @@ -74,8 +74,8 @@ public: bool RewriteExpression(DiagnosticManager &diagnostic_manager) override; //------------------------------------------------------------------ - /// Ready an already-parsed expression for execution, possibly - /// evaluating it statically. + /// Ready an already-parsed expression for execution, possibly evaluating it + /// statically. /// /// @param[out] func_addr /// The address to which the function has been written. diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h index baa80d7ba0d4..7d5ced5b4705 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h @@ -41,27 +41,25 @@ class ValueObjectConstResult; //---------------------------------------------------------------------- /// @class ClangExpressionVariable ClangExpressionVariable.h -/// "lldb/Expression/ClangExpressionVariable.h" -/// @brief Encapsulates one variable for the expression parser. +/// "lldb/Expression/ClangExpressionVariable.h" Encapsulates one variable for +/// the expression parser. /// /// The expression parser uses variables in three different contexts: /// -/// First, it stores persistent variables along with the process for use -/// in expressions. These persistent variables contain their own data -/// and are typed. +/// First, it stores persistent variables along with the process for use in +/// expressions. These persistent variables contain their own data and are +/// typed. /// -/// Second, in an interpreted expression, it stores the local variables -/// for the expression along with the expression. These variables -/// contain their own data and are typed. +/// Second, in an interpreted expression, it stores the local variables for +/// the expression along with the expression. These variables contain their +/// own data and are typed. /// -/// Third, in a JIT-compiled expression, it stores the variables that -/// the expression needs to have materialized and dematerialized at each -/// execution. These do not contain their own data but are named and -/// typed. +/// Third, in a JIT-compiled expression, it stores the variables that the +/// expression needs to have materialized and dematerialized at each +/// execution. These do not contain their own data but are named and typed. /// -/// This class supports all of these use cases using simple type -/// polymorphism, and provides necessary support methods. Its interface -/// is RTTI-neutral. +/// This class supports all of these use cases using simple type polymorphism, +/// and provides necessary support methods. Its interface is RTTI-neutral. //---------------------------------------------------------------------- class ClangExpressionVariable : public ExpressionVariable { public: @@ -79,8 +77,8 @@ public: lldb::ByteOrder byte_order, uint32_t addr_byte_size); //---------------------------------------------------------------------- - /// Utility functions for dealing with ExpressionVariableLists in - /// Clang-specific ways + /// Utility functions for dealing with ExpressionVariableLists in Clang- + /// specific ways //---------------------------------------------------------------------- //---------------------------------------------------------------------- @@ -112,9 +110,9 @@ public: } //---------------------------------------------------------------------- - /// If the variable contains its own data, make a Value point at it. - /// If \a exe_ctx in not NULL, the value will be resolved in with - /// that execution context. + /// If the variable contains its own data, make a Value point at it. If \a + /// exe_ctx in not NULL, the value will be resolved in with that execution + /// context. /// /// @param[in] value /// The value to point at the data. @@ -156,8 +154,8 @@ private: public: //---------------------------------------------------------------------- - /// Make this variable usable by the parser by allocating space for - /// parser-specific variables + /// Make this variable usable by the parser by allocating space for parser- + /// specific variables //---------------------------------------------------------------------- void EnableParserVars(uint64_t parser_id) { m_parser_vars.insert(std::make_pair(parser_id, ParserVars())); diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index a26ceda82d5f..e3e0ed49181e 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -101,14 +101,12 @@ ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp, m_wrapper_function_text.append(" (*fn_ptr) ("); // Get the number of arguments. If we have a function type and it is - // prototyped, - // trust that, otherwise use the values we were given. + // prototyped, trust that, otherwise use the values we were given. // FIXME: This will need to be extended to handle Variadic functions. We'll // need // to pull the defined arguments out of the function, then add the types from - // the - // arguments list for the variable arguments. + // the arguments list for the variable arguments. uint32_t num_args = UINT32_MAX; bool trust_function = false; diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h index 0596d8fde7b9..438cf0c713da 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h +++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h @@ -31,8 +31,8 @@ class ClangExpressionParser; //---------------------------------------------------------------------- /// @class ClangFunctionCaller ClangFunctionCaller.h -/// "lldb/Expression/ClangFunctionCaller.h" -/// @brief Encapsulates a function that can be called. +/// "lldb/Expression/ClangFunctionCaller.h" Encapsulates a function that can +/// be called. /// /// A given ClangFunctionCaller object can handle a single function signature. /// Once constructed, it can set up any number of concurrent calls to @@ -56,8 +56,8 @@ class ClangExpressionParser; /// If you need to call the function on the thread plan stack, you can also /// call InsertFunction() followed by GetThreadPlanToCallFunction(). /// -/// Any of the methods that take arg_addr_ptr or arg_addr_ref can be passed -/// a pointer set to LLDB_INVALID_ADDRESS and new structure will be allocated +/// Any of the methods that take arg_addr_ptr or arg_addr_ref can be passed a +/// pointer set to LLDB_INVALID_ADDRESS and new structure will be allocated /// and its address returned in that variable. /// /// Any of the methods that take arg_addr_ptr can be passed NULL, and the @@ -79,8 +79,8 @@ class ClangFunctionCaller : public FunctionCaller { ClangExpressionDeclMap *DeclMap() override { return NULL; } //------------------------------------------------------------------ - /// Return the object that the parser should allow to access ASTs. - /// May be NULL if the ASTs do not need to be transformed. + /// Return the object that the parser should allow to access ASTs. May be + /// NULL if the ASTs do not need to be transformed. /// /// @param[in] passthrough /// The ASTConsumer that the returned transformer should send diff --git a/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/source/Plugins/ExpressionParser/Clang/ClangHost.cpp new file mode 100644 index 000000000000..4251d2ee75b9 --- /dev/null +++ b/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -0,0 +1,142 @@ +//===-- ClangHost.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClangHost.h" + +#include "clang/Basic/Version.h" +#include "clang/Config/config.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Threading.h" + +// Project includes +#include "lldb/Host/HostInfo.h" +#if !defined(_WIN32) +#include "lldb/Host/posix/HostInfoPosix.h" +#endif +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Log.h" + +#include <string> + +using namespace lldb_private; + +#if defined(_WIN32) +static bool ComputeClangDirectory(FileSpec &file_spec) { return false; } +#else +static bool DefaultComputeClangDirectory(FileSpec &file_spec) { + return HostInfoPosix::ComputePathRelativeToLibrary( + file_spec, (llvm::Twine("/lib") + CLANG_LIBDIR_SUFFIX + "/clang/" + + CLANG_VERSION_STRING) + .str()); +} + +#if defined(__APPLE__) + +static bool VerifyClangPath(const llvm::Twine &clang_path) { + if (llvm::sys::fs::is_directory(clang_path)) + return true; + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("VerifyClangPath(): " + "failed to stat clang resource directory at \"%s\"", + clang_path.str().c_str()); + return false; +} + +bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, + FileSpec &file_spec, bool verify) { + std::string raw_path = lldb_shlib_spec.GetPath(); + + auto rev_it = llvm::sys::path::rbegin(raw_path); + auto r_end = llvm::sys::path::rend(raw_path); + + // Check for a Posix-style build of LLDB. + while (rev_it != r_end) { + if (*rev_it == "LLDB.framework") + break; + ++rev_it; + } + + if (rev_it == r_end) + return DefaultComputeClangDirectory(file_spec); + + // Inside Xcode and in Xcode toolchains LLDB is always in lockstep + // with the Swift compiler, so it can reuse its Clang resource + // directory. This allows LLDB and the Swift compiler to share the + // same Clang module cache. + llvm::SmallString<256> clang_path; + const char *swift_clang_resource_dir = "usr/lib/swift/clang"; + auto parent = std::next(rev_it); + if (parent != r_end && *parent == "SharedFrameworks") { + // This is the top-level LLDB in the Xcode.app bundle. + // E.g., "Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A" + raw_path.resize(parent - r_end); + llvm::sys::path::append(clang_path, raw_path, + "Developer/Toolchains/XcodeDefault.xctoolchain", + swift_clang_resource_dir); + if (!verify || VerifyClangPath(clang_path)) { + file_spec.SetFile(clang_path.c_str(), true, FileSpec::Style::native); + return true; + } + } else if (parent != r_end && *parent == "PrivateFrameworks" && + std::distance(parent, r_end) > 2) { + ++parent; + ++parent; + if (*parent == "System") { + // This is LLDB inside an Xcode toolchain. + // E.g., "Xcode.app/Contents/Developer/Toolchains/" \ + // "My.xctoolchain/System/Library/PrivateFrameworks/LLDB.framework" + 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); + return true; + } + raw_path = lldb_shlib_spec.GetPath(); + } + raw_path.resize(rev_it - r_end); + } else { + raw_path.resize(rev_it - r_end); + } + + // Fall back to the Clang resource directory inside the framework. + raw_path.append("LLDB.framework/Resources/Clang"); + file_spec.SetFile(raw_path.c_str(), true, FileSpec::Style::native); + return true; +} + +static bool ComputeClangDirectory(FileSpec &file_spec) { + if (FileSpec lldb_file_spec = HostInfo::GetShlibDir()) + return ComputeClangDirectory(lldb_file_spec, file_spec, true); + return false; +} +#else // __APPLE__ + +// All non-Apple posix systems. +static bool ComputeClangDirectory(FileSpec &file_spec) { + return DefaultComputeClangDirectory(file_spec); +} +#endif // __APPLE__ +#endif // _WIN32 + +FileSpec lldb_private::GetClangResourceDir() { + static FileSpec g_cached_resource_dir; + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, []() { + ::ComputeClangDirectory(g_cached_resource_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("GetClangResourceDir() => '%s'", + g_cached_resource_dir.GetPath().c_str()); + }); + return g_cached_resource_dir; +} diff --git a/source/Plugins/ExpressionParser/Clang/ClangHost.h b/source/Plugins/ExpressionParser/Clang/ClangHost.h new file mode 100644 index 000000000000..4fe423adb1a5 --- /dev/null +++ b/source/Plugins/ExpressionParser/Clang/ClangHost.h @@ -0,0 +1,26 @@ +//===-- ClangHost.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_EXPRESSIONPARSER_CLANG_CLANGHOST_H +#define LLDB_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H + +namespace lldb_private { + +class FileSpec; + +#if defined(__APPLE__) +bool ComputeClangDirectory(FileSpec &lldb_shlib_spec, FileSpec &file_spec, + bool verify); +#endif + +FileSpec GetClangResourceDir(); + +} // namespace lldb_private + +#endif diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index b42ceb9afee8..665195f01774 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -25,8 +25,10 @@ #include "llvm/Support/Threading.h" // Project includes +#include "ClangHost.h" #include "ClangModulesDeclVendor.h" +#include "lldb/Core/ModuleList.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/CompileUnit.h" @@ -39,9 +41,9 @@ using namespace lldb_private; namespace { -// Any Clang compiler requires a consumer for diagnostics. This one stores them -// as strings -// so we can provide them to the user in case a module failed to load. +// Any Clang compiler requires a consumer for diagnostics. This one stores +// them as strings so we can provide them to the user in case a module failed +// to load. class StoringDiagnosticConsumer : public clang::DiagnosticConsumer { public: StoringDiagnosticConsumer(); @@ -61,8 +63,7 @@ private: }; // The private implementation of our ClangModulesDeclVendor. Contains all the -// Clang state required -// to load modules. +// Clang state required to load modules. class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor { public: ClangModulesDeclVendorImpl( @@ -144,18 +145,6 @@ void StoringDiagnosticConsumer::DumpDiagnostics(Stream &error_stream) { } } -static FileSpec GetResourceDir() { - static FileSpec g_cached_resource_dir; - - static llvm::once_flag g_once_flag; - - llvm::call_once(g_once_flag, []() { - HostInfo::GetLLDBPath(lldb::ePathTypeClangDir, g_cached_resource_dir); - }); - - return g_cached_resource_dir; -} - ClangModulesDeclVendor::ClangModulesDeclVendor() {} ClangModulesDeclVendor::~ClangModulesDeclVendor() {} @@ -168,7 +157,7 @@ ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl( : m_diagnostics_engine(std::move(diagnostics_engine)), m_compiler_invocation(std::move(compiler_invocation)), m_compiler_instance(std::move(compiler_instance)), - m_parser(std::move(parser)) {} + m_parser(std::move(parser)), m_origin_map() {} void ClangModulesDeclVendorImpl::ReportModuleExportsHelper( std::set<ClangModulesDeclVendor::ModuleID> &exports, @@ -590,14 +579,11 @@ ClangModulesDeclVendor::Create(Target &target) { // Add additional search paths with { "-I", path } or { "-F", path } here. { - llvm::SmallString<128> DefaultModuleCache; - const bool erased_on_reboot = false; - llvm::sys::path::system_temp_directory(erased_on_reboot, - DefaultModuleCache); - llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang"); - llvm::sys::path::append(DefaultModuleCache, "ModuleCache"); + llvm::SmallString<128> path; + auto props = ModuleList::GetGlobalModuleListProperties(); + props.GetClangModulesCachePath().GetPath(path); std::string module_cache_argument("-fmodules-cache-path="); - module_cache_argument.append(DefaultModuleCache.str().str()); + module_cache_argument.append(path.str()); compiler_invocation_arguments.push_back(module_cache_argument); } @@ -613,7 +599,7 @@ ClangModulesDeclVendor::Create(Target &target) { } { - FileSpec clang_resource_dir = GetResourceDir(); + FileSpec clang_resource_dir = GetClangResourceDir(); if (llvm::sys::fs::is_directory(clang_resource_dir.GetPath())) { compiler_invocation_arguments.push_back("-resource-dir"); diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index 8ebf78409a03..bb73d55a9a41 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -10,6 +10,7 @@ #include "ClangPersistentVariables.h" #include "lldb/Core/Value.h" +#include "lldb/Target/Target.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" @@ -52,14 +53,6 @@ void ClangPersistentVariables::RemovePersistentVariable( m_next_persistent_variable_id--; } -ConstString ClangPersistentVariables::GetNextPersistentVariableName() { - char name_cstr[256]; - ::snprintf(name_cstr, sizeof(name_cstr), "$%u", - m_next_persistent_variable_id++); - ConstString name(name_cstr); - return name; -} - void ClangPersistentVariables::RegisterPersistentDecl(const ConstString &name, clang::NamedDecl *decl) { m_persistent_decls.insert( diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index 16981a7fe14a..59126974616d 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -25,9 +25,8 @@ namespace lldb_private { //---------------------------------------------------------------------- /// @class ClangPersistentVariables ClangPersistentVariables.h -/// "lldb/Expression/ClangPersistentVariables.h" -/// @brief Manages persistent values that need to be preserved between -/// expression invocations. +/// "lldb/Expression/ClangPersistentVariables.h" Manages persistent values +/// that need to be preserved between expression invocations. /// /// A list of variables that can be accessed and updated by any expression. See /// ClangPersistentVariable for more discussion. Also provides an increasing, @@ -54,16 +53,11 @@ public: const CompilerType &compiler_type, lldb::ByteOrder byte_order, uint32_t addr_byte_size) override; - //---------------------------------------------------------------------- - /// Return the next entry in the sequence of strings "$0", "$1", ... for - /// use naming persistent expression convenience variables. - /// - /// @return - /// A string that contains the next persistent variable name. - //---------------------------------------------------------------------- - ConstString GetNextPersistentVariableName() override; - void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override; + llvm::StringRef + GetPersistentVariablePrefix(bool is_error) const override { + return "$"; + } void RegisterPersistentDecl(const ConstString &name, clang::NamedDecl *decl); diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 18fe8b49227b..2e61f704127a 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -65,7 +65,8 @@ ClangUserExpression::ClangUserExpression( options), m_type_system_helper(*m_target_wp.lock().get(), options.GetExecutionPolicy() == - eExecutionPolicyTopLevel) { + eExecutionPolicyTopLevel), + m_result_delegate(exe_scope.CalculateTarget()) { switch (m_language) { case lldb::eLanguageTypeC_plus_plus: m_allow_cxx = true; @@ -195,12 +196,10 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { } else if (clang::FunctionDecl *function_decl = ClangASTContext::DeclContextGetAsFunctionDecl(decl_context)) { // We might also have a function that said in the debug information that it - // captured an - // object pointer. The best way to deal with getting to the ivars at - // present is by pretending - // that this is a method of a class in whatever runtime the debug info says - // the object pointer - // belongs to. Do that here. + // captured an object pointer. The best way to deal with getting to the + // ivars at present is by pretending that this is a method of a class in + // whatever runtime the debug info says the object pointer belongs to. Do + // that here. ClangASTMetadata *metadata = ClangASTContext::DeclContextGetMetaData(decl_context, function_decl); @@ -290,10 +289,10 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { } } -// This is a really nasty hack, meant to fix Objective-C expressions of the form -// (int)[myArray count]. Right now, because the type information for count is -// not available, [myArray count] returns id, which can't be directly cast to -// int without causing a clang error. +// This is a really nasty hack, meant to fix Objective-C expressions of the +// form (int)[myArray count]. Right now, because the type information for +// count is not available, [myArray count] returns id, which can't be directly +// cast to int without causing a clang error. static void ApplyObjcCastHack(std::string &expr) { #define OBJC_CAST_HACK_FROM "(int)[" #define OBJC_CAST_HACK_TO "(int)(long long)[" @@ -308,17 +307,23 @@ static void ApplyObjcCastHack(std::string &expr) { #undef OBJC_CAST_HACK_FROM } -bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx, - lldb_private::ExecutionPolicy execution_policy, - bool keep_result_in_memory, - bool generate_debug_info) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); +namespace { +// Utility guard that calls a callback when going out of scope. +class OnExit { +public: + typedef std::function<void(void)> Callback; - Status err; + OnExit(Callback const &callback) : m_callback(callback) {} - InstallContext(exe_ctx); + ~OnExit() { m_callback(); } + +private: + Callback m_callback; +}; +} // namespace +bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx) { if (Target *target = exe_ctx.GetTargetPtr()) { if (PersistentExpressionState *persistent_state = target->GetPersistentExpressionStateForLanguage( @@ -335,26 +340,15 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, "error: couldn't start parsing (no target)"); return false; } + return true; +} - ScanContext(exe_ctx, err); - - if (!err.Success()) { - diagnostic_manager.PutString(eDiagnosticSeverityWarning, err.AsCString()); - } - - //////////////////////////////////// - // Generate the expression - // - - ApplyObjcCastHack(m_expr_text); - - std::string prefix = m_expr_prefix; - +static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) { if (ClangModulesDeclVendor *decl_vendor = - m_target->GetClangModulesDeclVendor()) { + target->GetClangModulesDeclVendor()) { const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = llvm::cast<ClangPersistentVariables>( - m_target->GetPersistentExpressionStateForLanguage( + target->GetPersistentExpressionStateForLanguage( lldb::eLanguageTypeC)) ->GetHandLoadedClangModules(); ClangModulesDeclVendor::ModuleVector modules_for_macros; @@ -363,7 +357,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, modules_for_macros.push_back(module); } - if (m_target->GetEnableAutoImportClangModules()) { + if (target->GetEnableAutoImportClangModules()) { if (StackFrame *frame = exe_ctx.GetFramePtr()) { if (Block *block = frame->GetFrameBlock()) { SymbolContext sc; @@ -380,8 +374,13 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, } } } +} - lldb::LanguageType lang_type = lldb::eLanguageTypeUnknown; +llvm::Optional<lldb::LanguageType> ClangUserExpression::GetLanguageForExpr( + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { + lldb::LanguageType lang_type = lldb::LanguageType::eLanguageTypeUnknown; + + std::string prefix = m_expr_prefix; if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) { m_transformed_text = m_expr_text; @@ -401,9 +400,50 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, exe_ctx)) { diagnostic_manager.PutString(eDiagnosticSeverityError, "couldn't construct expression body"); - return false; + return llvm::Optional<lldb::LanguageType>(); } } + return lang_type; +} + +bool ClangUserExpression::PrepareForParsing( + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { + InstallContext(exe_ctx); + + if (!SetupPersistentState(diagnostic_manager, exe_ctx)) + return false; + + Status err; + ScanContext(exe_ctx, err); + + if (!err.Success()) { + diagnostic_manager.PutString(eDiagnosticSeverityWarning, err.AsCString()); + } + + //////////////////////////////////// + // Generate the expression + // + + ApplyObjcCastHack(m_expr_text); + + SetupDeclVendor(exe_ctx, m_target); + return true; +} + +bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, + bool generate_debug_info) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (!PrepareForParsing(diagnostic_manager, exe_ctx)) + 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()); @@ -427,28 +467,12 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory); - class OnExit { - public: - typedef std::function<void(void)> Callback; - - OnExit(Callback const &callback) : m_callback(callback) {} - - ~OnExit() { m_callback(); } - - private: - Callback m_callback; - }; - 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"); - - ResetDeclMap(); // We are being careful here in the case of breakpoint - // conditions. - return false; } @@ -463,17 +487,15 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, exe_scope = exe_ctx.GetTargetPtr(); // We use a shared pointer here so we can use the original parser - if it - // succeeds - // or the rewrite parser we might make if it fails. But the parser_sp will - // never be empty. + // succeeds or the rewrite parser we might make if it fails. But the + // parser_sp will never be empty. ClangExpressionParser parser(exe_scope, *this, generate_debug_info); unsigned num_errors = parser.Parse(diagnostic_manager); // Check here for FixItHints. If there are any try to apply the fixits and - // set the fixed text in m_fixed_text - // before returning an error. + // set the fixed text in m_fixed_text before returning an error. if (num_errors) { if (diagnostic_manager.HasFixIts()) { if (parser.RewriteExpression(diagnostic_manager)) { @@ -487,16 +509,12 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, fixed_expression.substr(fixed_start, fixed_end - fixed_start); } } - - ResetDeclMap(); // We are being careful here in the case of breakpoint - // conditions. - return false; } ////////////////////////////////////////////////////////////////////////////////////////// - // Prepare the output of the parser for execution, evaluating it statically if - // possible + // Prepare the output of the parser for execution, evaluating it statically + // if possible // { @@ -539,9 +557,9 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, register_execution_unit = true; } - // If there is more than one external function in the execution - // unit, it needs to keep living even if it's not top level, because - // the result could refer to that function. + // If there is more than one external function in the execution unit, it + // needs to keep living even if it's not top level, because the result + // could refer to that function. if (m_execution_unit_sp->GetJittedFunctions().size() > 1) { register_execution_unit = true; @@ -568,10 +586,6 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, } } - ResetDeclMap(); // Make this go away since we don't need any of its state - // after parsing. This also gets rid of any - // ClangASTImporter::Minions. - if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS) m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); return true; @@ -667,10 +681,10 @@ void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() { } } -ClangUserExpression::ResultDelegate::ResultDelegate() {} - ConstString ClangUserExpression::ResultDelegate::GetName() { - return m_persistent_state->GetNextPersistentVariableName(); + auto prefix = m_persistent_state->GetPersistentVariablePrefix(); + return m_persistent_state->GetNextPersistentVariableName(*m_target_sp, + prefix); } void ClangUserExpression::ResultDelegate::DidDematerialize( diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index 88a78798b657..ac363bf91747 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -35,13 +35,13 @@ namespace lldb_private { //---------------------------------------------------------------------- /// @class ClangUserExpression ClangUserExpression.h -/// "lldb/Expression/ClangUserExpression.h" -/// @brief Encapsulates a single expression for use with Clang +/// "lldb/Expression/ClangUserExpression.h" Encapsulates a single expression +/// for use with Clang /// /// LLDB uses expressions for various purposes, notably to call functions /// and as a backend for the expr command. ClangUserExpression encapsulates -/// the objects needed to parse and interpret or JIT an expression. It -/// uses the Clang parser to produce LLVM IR from the expression. +/// the objects needed to parse and interpret or JIT an expression. It uses +/// the Clang parser to produce LLVM IR from the expression. //---------------------------------------------------------------------- class ClangUserExpression : public LLVMUserExpression { public: @@ -69,8 +69,8 @@ public: bool keep_result_in_memory); //------------------------------------------------------------------ - /// Return the object that the parser should allow to access ASTs. - /// May be NULL if the ASTs do not need to be transformed. + /// Return the object that the parser should allow to access ASTs. May be + /// NULL if the ASTs do not need to be transformed. /// /// @param[in] passthrough /// The ASTConsumer that the returned transformer should send @@ -174,11 +174,18 @@ private: lldb::addr_t struct_address, DiagnosticManager &diagnostic_manager) override; + llvm::Optional<lldb::LanguageType> GetLanguageForExpr( + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx); + bool SetupPersistentState(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx); + bool PrepareForParsing(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx); + ClangUserExpressionHelper m_type_system_helper; class ResultDelegate : public Materializer::PersistentVariableDelegate { public: - ResultDelegate(); + ResultDelegate(lldb::TargetSP target) : m_target_sp(target) {} ConstString GetName() override; void DidDematerialize(lldb::ExpressionVariableSP &variable) override; @@ -188,6 +195,7 @@ private: private: PersistentExpressionState *m_persistent_state; lldb::ExpressionVariableSP m_variable; + lldb::TargetSP m_target_sp; }; ResultDelegate m_result_delegate; diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index 80577199b818..a897a2b17087 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -29,15 +29,15 @@ namespace lldb_private { //---------------------------------------------------------------------- /// @class ClangUtilityFunction ClangUtilityFunction.h -/// "lldb/Expression/ClangUtilityFunction.h" -/// @brief Encapsulates a single expression for use with Clang +/// "lldb/Expression/ClangUtilityFunction.h" Encapsulates a single expression +/// for use with Clang /// /// LLDB uses expressions for various purposes, notably to call functions /// and as a backend for the expr command. ClangUtilityFunction encapsulates /// a self-contained function meant to be used from other code. Utility /// functions can perform error-checking for ClangUserExpressions, or can -/// simply provide a way to push a function into the target for the debugger to -/// call later on. +/// simply provide a way to push a function into the target for the debugger +/// to call later on. //---------------------------------------------------------------------- class ClangUtilityFunction : public UtilityFunction { public: @@ -60,8 +60,8 @@ public: void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory); //------------------------------------------------------------------ - /// Return the object that the parser should allow to access ASTs. - /// May be NULL if the ASTs do not need to be transformed. + /// Return the object that the parser should allow to access ASTs. May be + /// NULL if the ASTs do not need to be transformed. /// /// @param[in] passthrough /// The ASTConsumer that the returned transformer should send diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 13f5657eedd8..e51c9ee07b9f 100644 --- a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -263,8 +263,7 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { } // Get the next available result name from m_decl_map and create the - // persistent - // variable for it + // persistent variable for it // If the result is an Lvalue, it is emitted as a pointer; see // ASTResultSynthesizer::SynthesizeBodyResult. @@ -345,9 +344,9 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { GlobalValue::ExternalLinkage, NULL, /* no initializer */ m_result_name.GetCString()); - // It's too late in compilation to create a new VarDecl for this, but we don't - // need to. We point the metadata at the old VarDecl. This creates an odd - // anomaly: a variable with a Value whose name is something like $0 and a + // It's too late in compilation to create a new VarDecl for this, but we + // don't need to. We point the metadata at the old VarDecl. This creates an + // odd anomaly: a variable with a Value whose name is something like $0 and a // Decl whose name is $__lldb_expr_result. This condition is handled in // ClangExpressionDeclMap::DoMaterialize, and the name of the variable is // fixed up. @@ -464,9 +463,7 @@ bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str, // CFAllocatorRef -> i8* // UInt8 * -> i8* // CFIndex -> long (i32 or i64, as appropriate; we ask the module for its - // pointer size for now) - // CFStringEncoding -> i32 - // Boolean -> i8 + // pointer size for now) CFStringEncoding -> i32 Boolean -> i8 Type *arg_type_array[5]; @@ -801,9 +798,8 @@ bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) { // Unpack the message name from the selector. In LLVM IR, an objc_msgSend // gets represented as // - // %tmp = load i8** @"OBJC_SELECTOR_REFERENCES_" ; <i8*> - // %call = call i8* (i8*, i8*, ...)* @objc_msgSend(i8* %obj, i8* %tmp, ...) - // ; <i8*> + // %tmp = load i8** @"OBJC_SELECTOR_REFERENCES_" ; <i8*> %call = call + // i8* (i8*, i8*, ...)* @objc_msgSend(i8* %obj, i8* %tmp, ...) ; <i8*> // // where %obj is the object pointer and %tmp is the selector. // @@ -870,7 +866,8 @@ bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) { log->Printf("Found sel_registerName at 0x%" PRIx64, sel_registerName_addr); - // Build the function type: struct objc_selector *sel_registerName(uint8_t*) + // Build the function type: struct objc_selector + // *sel_registerName(uint8_t*) // The below code would be "more correct," but in actuality what's required // is uint8_t* @@ -980,11 +977,10 @@ bool IRForTarget::RewriteObjCClassReference(Instruction *class_load) { // %struct._objc_class** @OBJC_CLASS_REFERENCES_, align 4 // // @"OBJC_CLASS_REFERENCES_ is a bitcast of a character array called - // @OBJC_CLASS_NAME_. - // @OBJC_CLASS_NAME contains the string. + // @OBJC_CLASS_NAME_. @OBJC_CLASS_NAME contains the string. - // Find the pointer's initializer (a ConstantExpr with opcode BitCast) - // and get the string from its target + // Find the pointer's initializer (a ConstantExpr with opcode BitCast) and + // get the string from its target GlobalVariable *_objc_class_references_ = dyn_cast<GlobalVariable>(load->getPointerOperand()); @@ -1159,8 +1155,8 @@ bool IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc) { GlobalValue::ExternalLinkage, NULL, /* no initializer */ alloc->getName().str()); - // What we're going to do here is make believe this was a regular old external - // variable. That means we need to make the metadata valid. + // What we're going to do here is make believe this was a regular old + // external variable. That means we need to make the metadata valid. NamedMDNode *named_metadata = m_module->getOrInsertNamedMetadata("clang.global.decl.ptrs"); @@ -1175,8 +1171,7 @@ bool IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc) { named_metadata->addOperand(persistent_global_md); // Now, since the variable is a pointer variable, we will drop in a load of - // that - // pointer variable. + // that pointer variable. LoadInst *persistent_load = new LoadInst(persistent_global, "", alloc); @@ -1366,16 +1361,13 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { if (name[0] == '$') { // The $__lldb_expr_result name indicates the return value has allocated - // as - // a static variable. Per the comment at - // ASTResultSynthesizer::SynthesizeBodyResult, - // accesses to this static variable need to be redirected to the result of - // dereferencing - // a pointer that is passed in as one of the arguments. + // as a static variable. Per the comment at + // ASTResultSynthesizer::SynthesizeBodyResult, accesses to this static + // variable need to be redirected to the result of dereferencing a + // pointer that is passed in as one of the arguments. // // Consequently, when reporting the size of the type, we report a pointer - // type pointing - // to the type of $__lldb_expr_result, not the type itself. + // type pointing to the type of $__lldb_expr_result, not the type itself. // // We also do this for any user-declared persistent variables. compiler_type = compiler_type.GetPointerType(); @@ -1965,12 +1957,11 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) { FunctionValueCache body_result_maker( [this, name, offset_type, offset, argument, value](llvm::Function *function) -> llvm::Value * { - // Per the comment at ASTResultSynthesizer::SynthesizeBodyResult, in - // cases where the result - // variable is an rvalue, we have to synthesize a dereference of the - // appropriate structure - // entry in order to produce the static variable that the AST thinks - // it is accessing. + // Per the comment at ASTResultSynthesizer::SynthesizeBodyResult, + // in cases where the result variable is an rvalue, we have to + // synthesize a dereference of the appropriate structure entry in + // order to produce the static variable that the AST thinks it is + // accessing. llvm::Instruction *entry_instruction = llvm::cast<Instruction>( m_entry_instruction_finder.GetValue(function)); @@ -2194,7 +2185,8 @@ bool IRForTarget::runOnModule(Module &llvm_module) { if (log) log->Printf("RewriteObjCSelectors() failed"); - // RewriteObjCSelectors() reports its own errors, so we don't do so here + // RewriteObjCSelectors() reports its own errors, so we don't do so + // here return false; } diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/source/Plugins/ExpressionParser/Clang/IRForTarget.h index 93ce8aa44eb2..c6c44b46023c 100644 --- a/source/Plugins/ExpressionParser/Clang/IRForTarget.h +++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.h @@ -47,12 +47,11 @@ class IRMemoryMap; //---------------------------------------------------------------------- /// @class IRForTarget IRForTarget.h "lldb/Expression/IRForTarget.h" -/// @brief Transforms the IR for a function to run in the target +/// Transforms the IR for a function to run in the target /// -/// Once an expression has been parsed and converted to IR, it can run -/// in two contexts: interpreted by LLDB as a DWARF location expression, -/// or compiled by the JIT and inserted into the target process for -/// execution. +/// Once an expression has been parsed and converted to IR, it can run in two +/// contexts: interpreted by LLDB as a DWARF location expression, or compiled +/// by the JIT and inserted into the target process for execution. /// /// IRForTarget makes the second possible, by applying a series of /// transformations to the IR which make it relocatable. These @@ -126,8 +125,7 @@ public: //------------------------------------------------------------------ /// Interface stub /// - /// Implementation of the llvm::ModulePass::assignPassManager() - /// function. + /// Implementation of the llvm::ModulePass::assignPassManager() function. //------------------------------------------------------------------ void assignPassManager(llvm::PMStack &pass_mgr_stack, llvm::PassManagerType pass_mgr_type = @@ -179,8 +177,8 @@ private: //------------------------------------------------------------------ //------------------------------------------------------------------ - /// Get the address of a function, and a location to put the complete - /// Value of the function if one is available. + /// Get the address of a function, and a location to put the complete Value + /// of the function if one is available. /// /// @param[in] function /// The function to find the location of. @@ -204,13 +202,13 @@ private: //------------------------------------------------------------------ /// A function-level pass to take the generated global value - /// $__lldb_expr_result and make it into a persistent variable. - /// Also see ASTResultSynthesizer. + /// $__lldb_expr_result and make it into a persistent variable. Also see + /// ASTResultSynthesizer. //------------------------------------------------------------------ //------------------------------------------------------------------ - /// Find the NamedDecl corresponding to a Value. This interface is - /// exposed for the IR interpreter. + /// Find the NamedDecl corresponding to a Value. This interface is exposed + /// for the IR interpreter. /// /// @param[in] module /// The module containing metadata to search @@ -230,8 +228,8 @@ private: //------------------------------------------------------------------ /// Set the constant result variable m_const_result to the provided - /// constant, assuming it can be evaluated. The result variable - /// will be reset to NULL later if the expression has side effects. + /// constant, assuming it can be evaluated. The result variable will be + /// reset to NULL later if the expression has side effects. /// /// @param[in] initializer /// The constant initializer for the variable. @@ -247,8 +245,8 @@ private: lldb_private::TypeFromParser type); //------------------------------------------------------------------ - /// If the IR represents a cast of a variable, set m_const_result - /// to the result of the cast. The result variable will be reset to + /// If the IR represents a cast of a variable, set m_const_result to the + /// result of the cast. The result variable will be reset to /// NULL latger if the expression has side effects. /// /// @param[in] type @@ -301,10 +299,9 @@ private: /// rewrite them to use sel_registerName instead of statically allocated /// selectors. The reason is that the selectors are created on the /// assumption that the Objective-C runtime will scan the appropriate - /// section and prepare them. This doesn't happen when code is copied - /// into the target, though, and there's no easy way to induce the - /// runtime to scan them. So instead we get our selectors from - /// sel_registerName. + /// section and prepare them. This doesn't happen when code is copied into + /// the target, though, and there's no easy way to induce the runtime to + /// scan them. So instead we get our selectors from sel_registerName. //------------------------------------------------------------------ //------------------------------------------------------------------ @@ -359,13 +356,12 @@ private: //------------------------------------------------------------------ /// A basic block-level pass to find all newly-declared persistent - /// variables and register them with the ClangExprDeclMap. This - /// allows them to be materialized and dematerialized like normal - /// external variables. Before transformation, these persistent - /// variables look like normal locals, so they have an allocation. - /// This pass excises these allocations and makes references look - /// like external references where they will be resolved -- like all - /// other external references -- by ResolveExternals(). + /// variables and register them with the ClangExprDeclMap. This allows them + /// to be materialized and dematerialized like normal external variables. + /// Before transformation, these persistent variables look like normal + /// locals, so they have an allocation. This pass excises these allocations + /// and makes references look like external references where they will be + /// resolved -- like all other external references -- by ResolveExternals(). //------------------------------------------------------------------ //------------------------------------------------------------------ @@ -389,15 +385,14 @@ private: //------------------------------------------------------------------ /// A function-level pass to find all external variables and functions - /// used in the IR. Each found external variable is added to the - /// struct, and each external function is resolved in place, its call - /// replaced with a call to a function pointer whose value is the - /// address of the function in the target process. + /// used in the IR. Each found external variable is added to the struct, + /// and each external function is resolved in place, its call replaced with + /// a call to a function pointer whose value is the address of the function + /// in the target process. //------------------------------------------------------------------ //------------------------------------------------------------------ - /// Write an initializer to a memory array of assumed sufficient - /// size. + /// Write an initializer to a memory array of assumed sufficient size. /// /// @param[in] data /// A pointer to the data to write to. @@ -504,8 +499,8 @@ private: //------------------------------------------------------------------ /// A basic block-level pass to excise guard variables from the code. /// The result for the function is passed through Clang as a static - /// variable. Static variables normally have guard variables to - /// ensure that they are only initialized once. + /// variable. Static variables normally have guard variables to ensure that + /// they are only initialized once. //------------------------------------------------------------------ //------------------------------------------------------------------ @@ -529,9 +524,9 @@ private: //------------------------------------------------------------------ /// A function-level pass to make all external variable references - /// point at the correct offsets from the void* passed into the - /// function. ClangExpressionDeclMap::DoStructLayout() must be called - /// beforehand, so that the offsets are valid. + /// point at the correct offsets from the void* passed into the function. + /// ClangExpressionDeclMap::DoStructLayout() must be called beforehand, so + /// that the offsets are valid. //------------------------------------------------------------------ //------------------------------------------------------------------ @@ -583,7 +578,8 @@ private: llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that ///writes to the result variable. If - /// m_has_side_effects is true, this is NULL. + /// m_has_side_effects is true, this is + /// NULL. bool m_result_is_pointer; ///< True if the function's result in the AST is a ///pointer (see comments in /// ASTResultSynthesizer::SynthesizeBodyResult) @@ -594,18 +590,17 @@ private: /// location of the static allocation. //------------------------------------------------------------------ - /// UnfoldConstant operates on a constant [Old] which has just been - /// replaced with a value [New]. We assume that new_value has - /// been properly placed early in the function, in front of the - /// first instruction in the entry basic block - /// [FirstEntryInstruction]. + /// UnfoldConstant operates on a constant [Old] which has just been replaced + /// with a value [New]. We assume that new_value has been properly placed + /// early in the function, in front of the first instruction in the entry + /// basic block [FirstEntryInstruction]. /// - /// UnfoldConstant reads through the uses of Old and replaces Old - /// in those uses with New. Where those uses are constants, the - /// function generates new instructions to compute the result of the - /// new, non-constant expression and places them before - /// FirstEntryInstruction. These instructions replace the constant - /// uses, so UnfoldConstant calls itself recursively for those. + /// UnfoldConstant reads through the uses of Old and replaces Old in those + /// uses with New. Where those uses are constants, the function generates + /// new instructions to compute the result of the new, non-constant + /// expression and places them before FirstEntryInstruction. These + /// instructions replace the constant uses, so UnfoldConstant calls itself + /// recursively for those. /// /// @param[in] llvm_function /// The function currently being processed. @@ -637,8 +632,8 @@ private: lldb_private::Stream &error_stream); //------------------------------------------------------------------ - /// Construct a reference to m_reloc_placeholder with a given type - /// and offset. This typically happens after inserting data into + /// Construct a reference to m_reloc_placeholder with a given type and + /// offset. This typically happens after inserting data into /// m_data_allocator. /// /// @param[in] type @@ -653,8 +648,8 @@ private: llvm::Constant *BuildRelocation(llvm::Type *type, uint64_t offset); //------------------------------------------------------------------ - /// Commit the allocation in m_data_allocator and use its final - /// location to replace m_reloc_placeholder. + /// Commit the allocation in m_data_allocator and use its final location to + /// replace m_reloc_placeholder. /// /// @param[in] module /// The module that m_data_allocator resides in diff --git a/source/Plugins/ExpressionParser/Go/GoParser.cpp b/source/Plugins/ExpressionParser/Go/GoParser.cpp index 538bd05e25f8..9c845d02bca0 100644 --- a/source/Plugins/ExpressionParser/Go/GoParser.cpp +++ b/source/Plugins/ExpressionParser/Go/GoParser.cpp @@ -67,7 +67,9 @@ private: size_t m_pos; }; -GoParser::GoParser(const char *src) : m_lexer(src), m_pos(0), m_failed(false) {} +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); @@ -437,8 +439,10 @@ GoASTExpr *GoParser::CompositeLit() { if (!type) return r.error(); GoASTCompositeLit *lit = LiteralValue(); - if (!lit) + if (!lit) { + delete type; return r.error(); + } lit->SetType(type); return lit; } @@ -546,6 +550,7 @@ GoASTExpr *GoParser::Arguments(GoASTExpr *e) { 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) @@ -555,6 +560,7 @@ GoASTExpr *GoParser::Conversion() { return r.error(); GoASTCallExpr *call = new GoASTCallExpr(false); call->SetFun(t); + owner.release(); call->AddArgs(v); return call; } diff --git a/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp b/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp index f4b8cfbe03d4..3a10a1dc767a 100644 --- a/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp +++ b/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp @@ -171,12 +171,11 @@ private: VariableSP FindGlobalVariable(TargetSP target, llvm::Twine name) { ConstString fullname(name.str()); VariableList variable_list; - const bool append = true; if (!target) { return nullptr; } - const uint32_t match_count = target->GetImages().FindGlobalVariables( - fullname, append, 1, variable_list); + const uint32_t match_count = + target->GetImages().FindGlobalVariables(fullname, 1, variable_list); if (match_count == 1) { return variable_list.GetVariableAtIndex(0); } @@ -272,7 +271,8 @@ GoUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, PersistentExpressionState *pv = target->GetPersistentExpressionStateForLanguage(eLanguageTypeGo); if (pv != nullptr) { - result->SetName(pv->GetNextPersistentVariableName()); + result->SetName(pv->GetNextPersistentVariableName( + *target, pv->GetPersistentVariablePrefix())); pv->AddVariable(result); } return lldb::eExpressionCompleted; @@ -400,8 +400,7 @@ ValueObjectSP GoUserExpression::GoInterpreter::VisitIdent(const GoASTIdent *e) { 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'. + // 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); @@ -651,15 +650,6 @@ ValueObjectSP GoUserExpression::GoInterpreter::VisitCallExpr( GoPersistentExpressionState::GoPersistentExpressionState() : PersistentExpressionState(eKindGo) {} -ConstString GoPersistentExpressionState::GetNextPersistentVariableName() { - char name_cstr[256]; - // We can't use the same variable format as clang. - ::snprintf(name_cstr, sizeof(name_cstr), "$go%u", - m_next_persistent_variable_id++); - ConstString name(name_cstr); - return name; -} - void GoPersistentExpressionState::RemovePersistentVariable( lldb::ExpressionVariableSP variable) { RemoveVariable(variable); diff --git a/source/Plugins/ExpressionParser/Go/GoUserExpression.h b/source/Plugins/ExpressionParser/Go/GoUserExpression.h index 03ceb76b8431..e2839da9bfdd 100644 --- a/source/Plugins/ExpressionParser/Go/GoUserExpression.h +++ b/source/Plugins/ExpressionParser/Go/GoUserExpression.h @@ -29,8 +29,10 @@ class GoPersistentExpressionState : public PersistentExpressionState { public: GoPersistentExpressionState(); - ConstString GetNextPersistentVariableName() override; - + llvm::StringRef + GetPersistentVariablePrefix(bool is_error) const override { + return "$go"; + } void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override; lldb::addr_t LookupSymbol(const ConstString &name) override { @@ -48,12 +50,12 @@ private: //---------------------------------------------------------------------- /// @class GoUserExpression GoUserExpression.h -/// "lldb/Expression/GoUserExpression.h" -/// @brief Encapsulates a single expression for use with Go +/// "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. +/// and as a backend for the expr command. GoUserExpression encapsulates the +/// objects needed to parse and interpret an expression. //---------------------------------------------------------------------- class GoUserExpression : public UserExpression { public: diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index 262a7914d249..86744520ad63 100644 --- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -258,8 +258,8 @@ static bool GetARMDWARFRegisterInfo(unsigned reg_num, RegisterInfo ®_info) { reg_info.name = "f7"; break; - // Intel wireless MMX general purpose registers 0 - 7 - // XScale accumulator register 0 - 7 (they do overlap with wCGR0 - wCGR7) + // Intel wireless MMX general purpose registers 0 - 7 XScale accumulator + // register 0 - 7 (they do overlap with wCGR0 - wCGR7) case dwarf_wCGR0: reg_info.name = "wCGR0/ACC0"; break; @@ -901,7 +901,8 @@ uint32_t EmulateInstructionARM::GetFramePointerDWARFRegisterNumber() const { } // Push Multiple Registers stores multiple registers to the stack, storing to -// consecutive memory locations ending just below the address in SP, and updates +// consecutive memory locations ending just below the address in SP, and +// updates // SP to point to the start of the stored data. bool EmulateInstructionARM::EmulatePUSH(const uint32_t opcode, const ARMEncoding encoding) { @@ -1390,8 +1391,8 @@ bool EmulateInstructionARM::EmulateMOVRdImm(const uint32_t opcode, uint32_t imm32; // the immediate value to be written to Rd uint32_t carry = 0; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C. - // for setflags == false, this value is a don't care - // initialized to 0 to silence the static analyzer + // for setflags == false, this value is a don't care initialized to + // 0 to silence the static analyzer bool setflags; switch (encoding) { case eEncodingT1: @@ -1473,12 +1474,11 @@ bool EmulateInstructionARM::EmulateMOVRdImm(const uint32_t opcode, // MUL multiplies two register values. The least significant 32 bits of the // result are written to the destination // register. These 32 bits do not depend on whether the source register values -// are considered to be signed values or -// unsigned values. +// are considered to be signed values or unsigned values. // // Optionally, it can update the condition flags based on the result. In the -// Thumb instruction set, this option is -// limited to only a few forms of the instruction. +// Thumb instruction set, this option is limited to only a few forms of the +// instruction. bool EmulateInstructionARM::EmulateMUL(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -1606,8 +1606,8 @@ bool EmulateInstructionARM::EmulateMUL(const uint32_t opcode, } // Bitwise NOT (immediate) writes the bitwise inverse of an immediate value to -// the destination register. -// It can optionally update the condition flags based on the value. +// the destination register. It can optionally update the condition flags based +// on the value. bool EmulateInstructionARM::EmulateMVNImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -1666,8 +1666,8 @@ bool EmulateInstructionARM::EmulateMVNImm(const uint32_t opcode, } // Bitwise NOT (register) writes the bitwise inverse of a register value to the -// destination register. -// It can optionally update the condition flags based on the result. +// destination register. It can optionally update the condition flags based on +// the result. bool EmulateInstructionARM::EmulateMVNReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -2005,9 +2005,9 @@ bool EmulateInstructionARM::EmulateADDSPRm(const uint32_t opcode, return true; } -// Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine -// at a PC-relative address, and changes instruction set from ARM to Thumb, or -// from Thumb to ARM. +// Branch with Link and Exchange Instruction Sets (immediate) calls a +// subroutine at a PC-relative address, and changes instruction set from ARM to +// Thumb, or from Thumb to ARM. // BLX (immediate) bool EmulateInstructionARM::EmulateBLXImmediate(const uint32_t opcode, const ARMEncoding encoding) { @@ -2110,8 +2110,8 @@ bool EmulateInstructionARM::EmulateBLXImmediate(const uint32_t opcode, return true; } -// Branch with Link and Exchange (register) calls a subroutine at an address and -// instruction set specified by a register. +// Branch with Link and Exchange (register) calls a subroutine at an address +// and instruction set specified by a register. // BLX (register) bool EmulateInstructionARM::EmulateBLXRm(const uint32_t opcode, const ARMEncoding encoding) { @@ -2220,9 +2220,8 @@ bool EmulateInstructionARM::EmulateBXRm(const uint32_t opcode, } // Branch and Exchange Jazelle attempts to change to Jazelle state. If the -// attempt fails, it branches to an -// address and instruction set specified by a register as though it were a BX -// instruction. +// attempt fails, it branches to an address and instruction set specified by a +// register as though it were a BX instruction. // // TODO: Emulate Jazelle architecture? // We currently assume that switching to Jazelle state fails, thus @@ -2561,8 +2560,8 @@ bool EmulateInstructionARM::EmulateSTRRtSP(const uint32_t opcode, return true; } -// Vector Push stores multiple extension registers to the stack. -// It also updates SP to point to the start of the stored data. +// Vector Push stores multiple extension registers to the stack. It also +// updates SP to point to the start of the stored data. bool EmulateInstructionARM::EmulateVPUSH(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -2577,7 +2576,8 @@ bool EmulateInstructionARM::EmulateVPUSH(const uint32_t opcode, MemA[address,4] = S[d+r]; address = address+4; else for r = 0 to regs-1 - // Store as two word-aligned words in the correct order for current endianness. + // Store as two word-aligned words in the correct order for + // current endianness. MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>; MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>; address = address+8; @@ -2653,8 +2653,8 @@ bool EmulateInstructionARM::EmulateVPUSH(const uint32_t opcode, return true; } -// Vector Pop loads multiple extension registers from the stack. -// It also updates SP to point just above the loaded data. +// Vector Pop loads multiple extension registers from the stack. It also +// updates SP to point just above the loaded data. bool EmulateInstructionARM::EmulateVPOP(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -2670,7 +2670,8 @@ bool EmulateInstructionARM::EmulateVPOP(const uint32_t opcode, else for r = 0 to regs-1 word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8; - // Combine the word-aligned words in the correct order for current endianness. + // Combine the word-aligned words in the correct order for + // current endianness. D[d+r] = if BigEndian() then word1:word2 else word2:word1; } #endif @@ -2892,10 +2893,8 @@ bool EmulateInstructionARM::EmulateB(const uint32_t opcode, } // Compare and Branch on Nonzero and Compare and Branch on Zero compare the -// value in a register with -// zero and conditionally branch forward a constant value. They do not affect -// the condition flags. -// CBNZ, CBZ +// value in a register with zero and conditionally branch forward a constant +// value. They do not affect the condition flags. CBNZ, CBZ bool EmulateInstructionARM::EmulateCB(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -2938,8 +2937,8 @@ bool EmulateInstructionARM::EmulateCB(const uint32_t opcode, return true; } -// Table Branch Byte causes a PC-relative forward branch using a table of single -// byte offsets. +// Table Branch Byte causes a PC-relative forward branch using a table of +// single byte offsets. // A base register provides a pointer to the table, and a second register // supplies an index into the table. // The branch length is twice the value of the byte returned from the table. @@ -2948,8 +2947,8 @@ bool EmulateInstructionARM::EmulateCB(const uint32_t opcode, // single halfword offsets. // A base register provides a pointer to the table, and a second register // supplies an index into the table. -// The branch length is twice the value of the halfword returned from the table. -// TBB, TBH +// The branch length is twice the value of the halfword returned from the +// table. TBB, TBH bool EmulateInstructionARM::EmulateTB(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -2984,9 +2983,8 @@ bool EmulateInstructionARM::EmulateTB(const uint32_t opcode, return false; } - // Read the address of the table from the operand register Rn. - // The PC can be used, in which case the table immediately follows this - // instruction. + // Read the address of the table from the operand register Rn. The PC can + // be used, in which case the table immediately follows this instruction. uint32_t base = ReadCoreReg(Rn, &success); if (!success) return false; @@ -3023,8 +3021,8 @@ bool EmulateInstructionARM::EmulateTB(const uint32_t opcode, } // This instruction adds an immediate value to a register value, and writes the -// result to the destination register. -// It can optionally update the condition flags based on the result. +// result to the destination register. It can optionally update the condition +// flags based on the result. bool EmulateInstructionARM::EmulateADDImmThumb(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3145,8 +3143,8 @@ bool EmulateInstructionARM::EmulateADDImmThumb(const uint32_t opcode, } // This instruction adds an immediate value to a register value, and writes the -// result to the destination -// register. It can optionally update the condition flags based on the result. +// result to the destination register. It can optionally update the condition +// flags based on the result. bool EmulateInstructionARM::EmulateADDImmARM(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3210,9 +3208,8 @@ bool EmulateInstructionARM::EmulateADDImmARM(const uint32_t opcode, } // This instruction adds a register value and an optionally-shifted register -// value, and writes the result -// to the destination register. It can optionally update the condition flags -// based on the result. +// value, and writes the result to the destination register. It can optionally +// update the condition flags based on the result. bool EmulateInstructionARM::EmulateADDReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3350,8 +3347,8 @@ bool EmulateInstructionARM::EmulateCMNImm(const uint32_t opcode, } // Compare Negative (register) adds a register value and an optionally-shifted -// register value. -// It updates the condition flags based on the result, and discards the result. +// register value. It updates the condition flags based on the result, and +// discards the result. bool EmulateInstructionARM::EmulateCMNReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3419,8 +3416,8 @@ bool EmulateInstructionARM::EmulateCMNReg(const uint32_t opcode, return true; } -// Compare (immediate) subtracts an immediate value from a register value. -// It updates the condition flags based on the result, and discards the result. +// Compare (immediate) subtracts an immediate value from a register value. It +// updates the condition flags based on the result, and discards the result. bool EmulateInstructionARM::EmulateCMPImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3473,8 +3470,8 @@ bool EmulateInstructionARM::EmulateCMPImm(const uint32_t opcode, } // Compare (register) subtracts an optionally-shifted register value from a -// register value. -// It updates the condition flags based on the result, and discards the result. +// register value. It updates the condition flags based on the result, and +// discards the result. bool EmulateInstructionARM::EmulateCMPReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3552,10 +3549,9 @@ bool EmulateInstructionARM::EmulateCMPReg(const uint32_t opcode, } // Arithmetic Shift Right (immediate) shifts a register value right by an -// immediate number of bits, -// shifting in copies of its sign bit, and writes the result to the destination -// register. It can -// optionally update the condition flags based on the result. +// immediate number of bits, shifting in copies of its sign bit, and writes the +// result to the destination register. It can optionally update the condition +// flags based on the result. bool EmulateInstructionARM::EmulateASRImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3577,13 +3573,11 @@ bool EmulateInstructionARM::EmulateASRImm(const uint32_t opcode, return EmulateShiftImm(opcode, encoding, SRType_ASR); } -// Arithmetic Shift Right (register) shifts a register value right by a variable -// number of bits, -// shifting in copies of its sign bit, and writes the result to the destination -// register. -// The variable number of bits is read from the bottom byte of a register. It -// can optionally update -// the condition flags based on the result. +// Arithmetic Shift Right (register) shifts a register value right by a +// variable number of bits, shifting in copies of its sign bit, and writes the +// result to the destination register. The variable number of bits is read from +// the bottom byte of a register. It can optionally update the condition flags +// based on the result. bool EmulateInstructionARM::EmulateASRReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3604,10 +3598,8 @@ bool EmulateInstructionARM::EmulateASRReg(const uint32_t opcode, } // Logical Shift Left (immediate) shifts a register value left by an immediate -// number of bits, -// shifting in zeros, and writes the result to the destination register. It can -// optionally -// update the condition flags based on the result. +// number of bits, shifting in zeros, and writes the result to the destination +// register. It can optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateLSLImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3630,12 +3622,9 @@ bool EmulateInstructionARM::EmulateLSLImm(const uint32_t opcode, } // Logical Shift Left (register) shifts a register value left by a variable -// number of bits, -// shifting in zeros, and writes the result to the destination register. The -// variable number -// of bits is read from the bottom byte of a register. It can optionally update -// the condition -// flags based on the result. +// number of bits, shifting in zeros, and writes the result to the destination +// register. The variable number of bits is read from the bottom byte of a +// register. It can optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateLSLReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3655,11 +3644,10 @@ bool EmulateInstructionARM::EmulateLSLReg(const uint32_t opcode, return EmulateShiftReg(opcode, encoding, SRType_LSL); } -// Logical Shift Right (immediate) shifts a register value right by an immediate -// number of bits, -// shifting in zeros, and writes the result to the destination register. It can -// optionally -// update the condition flags based on the result. +// Logical Shift Right (immediate) shifts a register value right by an +// immediate number of bits, shifting in zeros, and writes the result to the +// destination register. It can optionally update the condition flags based on +// the result. bool EmulateInstructionARM::EmulateLSRImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3682,12 +3670,9 @@ bool EmulateInstructionARM::EmulateLSRImm(const uint32_t opcode, } // Logical Shift Right (register) shifts a register value right by a variable -// number of bits, -// shifting in zeros, and writes the result to the destination register. The -// variable number -// of bits is read from the bottom byte of a register. It can optionally update -// the condition -// flags based on the result. +// number of bits, shifting in zeros, and writes the result to the destination +// register. The variable number of bits is read from the bottom byte of a +// register. It can optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateLSRReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3708,10 +3693,9 @@ bool EmulateInstructionARM::EmulateLSRReg(const uint32_t opcode, } // Rotate Right (immediate) provides the value of the contents of a register -// rotated by a constant value. -// The bits that are rotated off the right end are inserted into the vacated bit -// positions on the left. -// It can optionally update the condition flags based on the result. +// rotated by a constant value. The bits that are rotated off the right end are +// inserted into the vacated bit positions on the left. It can optionally +// update the condition flags based on the result. bool EmulateInstructionARM::EmulateRORImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3734,12 +3718,10 @@ bool EmulateInstructionARM::EmulateRORImm(const uint32_t opcode, } // Rotate Right (register) provides the value of the contents of a register -// rotated by a variable number of bits. -// The bits that are rotated off the right end are inserted into the vacated bit -// positions on the left. -// The variable number of bits is read from the bottom byte of a register. It -// can optionally update the condition -// flags based on the result. +// rotated by a variable number of bits. The bits that are rotated off the +// right end are inserted into the vacated bit positions on the left. The +// variable number of bits is read from the bottom byte of a register. It can +// optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateRORReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -3760,8 +3742,7 @@ bool EmulateInstructionARM::EmulateRORReg(const uint32_t opcode, } // Rotate Right with Extend provides the value of the contents of a register -// shifted right by one place, -// with the carry flag shifted into bit [31]. +// shifted right by one place, with the carry flag shifted into bit [31]. // // RRX can optionally update the condition flags based on the result. // In that case, bit [0] is shifted into the carry flag. @@ -3808,10 +3789,9 @@ bool EmulateInstructionARM::EmulateShiftImm(const uint32_t opcode, // A8.6.139 ROR (immediate) -- Encoding T1 ARMEncoding use_encoding = encoding; if (shift_type == SRType_ROR && use_encoding == eEncodingT1) { - // Morph the T1 encoding from the ARM Architecture Manual into T2 encoding - // to - // have the same decoding of bit fields as the other Thumb2 shift - // operations. + // Morph the T1 encoding from the ARM Architecture Manual into T2 + // encoding to have the same decoding of bit fields as the other Thumb2 + // shift operations. use_encoding = eEncodingT2; } @@ -3950,8 +3930,7 @@ bool EmulateInstructionARM::EmulateShiftReg(const uint32_t opcode, // LDM loads multiple registers from consecutive memory locations, using an // address from a base register. Optionally the address just above the highest -// of those locations -// can be written back to the base register. +// of those locations can be written back to the base register. bool EmulateInstructionARM::EmulateLDM(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -4093,8 +4072,8 @@ bool EmulateInstructionARM::EmulateLDM(const uint32_t opcode, // LDMDA loads multiple registers from consecutive memory locations using an // address from a base register. // The consecutive memory locations end at this address and the address just -// below the lowest of those locations -// can optionally be written back to the base register. +// below the lowest of those locations can optionally be written back to the +// base register. bool EmulateInstructionARM::EmulateLDMDA(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -4210,8 +4189,8 @@ bool EmulateInstructionARM::EmulateLDMDA(const uint32_t opcode, // LDMDB loads multiple registers from consecutive memory locations using an // address from a base register. The // consecutive memory locations end just below this address, and the address of -// the lowest of those locations can -// be optionally written back to the base register. +// the lowest of those locations can be optionally written back to the base +// register. bool EmulateInstructionARM::EmulateLDMDB(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -4349,8 +4328,8 @@ bool EmulateInstructionARM::EmulateLDMDB(const uint32_t opcode, // LDMIB loads multiple registers from consecutive memory locations using an // address from a base register. The // consecutive memory locations start just above this address, and thea ddress -// of the last of those locations can -// optinoally be written back to the base register. +// of the last of those locations can optinoally be written back to the base +// register. bool EmulateInstructionARM::EmulateLDMIB(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -4461,8 +4440,7 @@ bool EmulateInstructionARM::EmulateLDMIB(const uint32_t opcode, } // Load Register (immediate) calculates an address from a base register value -// and -// an immediate offset, loads a word from memory, and writes to a register. +// and an immediate offset, loads a word from memory, and writes to a register. // LDR (immediate, Thumb) bool EmulateInstructionARM::EmulateLDRRtRnImm(const uint32_t opcode, const ARMEncoding encoding) { @@ -4625,8 +4603,8 @@ bool EmulateInstructionARM::EmulateLDRRtRnImm(const uint32_t opcode, // STM (Store Multiple Increment After) stores multiple registers to consecutive // memory locations using an address // from a base register. The consecutive memory locations start at this -// address, and the address just above the last -// of those locations can optionally be written back to the base register. +// address, and the address just above the last of those locations can +// optionally be written back to the base register. bool EmulateInstructionARM::EmulateSTM(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -4775,10 +4753,10 @@ bool EmulateInstructionARM::EmulateSTM(const uint32_t opcode, } // STMDA (Store Multiple Decrement After) stores multiple registers to -// consecutive memory locations using an address -// from a base register. The consecutive memory locations end at this address, -// and the address just below the lowest -// of those locations can optionally be written back to the base register. +// consecutive memory locations using an address from a base register. The +// consecutive memory locations end at this address, and the address just below +// the lowest of those locations can optionally be written back to the base +// register. bool EmulateInstructionARM::EmulateSTMDA(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -4897,10 +4875,10 @@ bool EmulateInstructionARM::EmulateSTMDA(const uint32_t opcode, } // STMDB (Store Multiple Decrement Before) stores multiple registers to -// consecutive memory locations using an address -// from a base register. The consecutive memory locations end just below this -// address, and the address of the first of -// those locations can optionally be written back to the base register. +// consecutive memory locations using an address from a base register. The +// consecutive memory locations end just below this address, and the address of +// the first of those locations can optionally be written back to the base +// register. bool EmulateInstructionARM::EmulateSTMDB(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -5046,10 +5024,10 @@ bool EmulateInstructionARM::EmulateSTMDB(const uint32_t opcode, } // STMIB (Store Multiple Increment Before) stores multiple registers to -// consecutive memory locations using an address -// from a base register. The consecutive memory locations start just above this -// address, and the address of the last -// of those locations can optionally be written back to the base register. +// consecutive memory locations using an address from a base register. The +// consecutive memory locations start just above this address, and the address +// of the last of those locations can optionally be written back to the base +// register. bool EmulateInstructionARM::EmulateSTMIB(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -5337,8 +5315,8 @@ bool EmulateInstructionARM::EmulateSTRThumb(const uint32_t opcode, // STR (Store Register) calculates an address from a base register value and an // offset register value, stores a -// word from a register to memory. The offset register value can optionally be -// shifted. +// word from a register to memory. The offset register value can optionally +// be shifted. bool EmulateInstructionARM::EmulateSTRRegister(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -5423,7 +5401,7 @@ bool EmulateInstructionARM::EmulateSTRRegister(const uint32_t opcode, n = Bits32(opcode, 19, 16); m = Bits32(opcode, 3, 0); - // index = (P == '1'); add = (U == '1'); wback = (P == '0') || + // index = (P == '1'); add = (U == '1'); wback = (P == '0') || // (W == '1'); index = BitIsSet(opcode, 24); add = BitIsSet(opcode, 23); @@ -5664,8 +5642,8 @@ bool EmulateInstructionARM::EmulateSTRBThumb(const uint32_t opcode, // STRH (register) calculates an address from a base register value and an // offset register value, and stores a -// halfword from a register to memory. The offset register value can be shifted -// left by 0, 1, 2, or 3 bits. +// halfword from a register to memory. The offset register value can be +// shifted left by 0, 1, 2, or 3 bits. bool EmulateInstructionARM::EmulateSTRHRegister(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -5745,7 +5723,7 @@ bool EmulateInstructionARM::EmulateSTRHRegister(const uint32_t opcode, n = Bits32(opcode, 19, 16); m = Bits32(opcode, 3, 0); - // index = (P == '1'); add = (U == '1'); wback = (P == '0') || + // index = (P == '1'); add = (U == '1'); wback = (P == '0') || // (W == '1'); index = BitIsSet(opcode, 24); add = BitIsSet(opcode, 23); @@ -5842,10 +5820,8 @@ bool EmulateInstructionARM::EmulateSTRHRegister(const uint32_t opcode, } // Add with Carry (immediate) adds an immediate value and the carry flag value -// to a register value, -// and writes the result to the destination register. It can optionally update -// the condition flags -// based on the result. +// to a register value, and writes the result to the destination register. It +// can optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateADCImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -5911,11 +5887,10 @@ bool EmulateInstructionARM::EmulateADCImm(const uint32_t opcode, return true; } -// Add with Carry (register) adds a register value, the carry flag value, and an -// optionally-shifted -// register value, and writes the result to the destination register. It can -// optionally update the -// condition flags based on the result. +// Add with Carry (register) adds a register value, the carry flag value, and +// an optionally-shifted register value, and writes the result to the +// destination register. It can optionally update the condition flags based on +// the result. bool EmulateInstructionARM::EmulateADCReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -5999,9 +5974,8 @@ bool EmulateInstructionARM::EmulateADCReg(const uint32_t opcode, return true; } -// This instruction adds an immediate value to the PC value to form a -// PC-relative address, -// and writes the result to the destination register. +// This instruction adds an immediate value to the PC value to form a PC- +// relative address, and writes the result to the destination register. bool EmulateInstructionARM::EmulateADR(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -6063,9 +6037,8 @@ bool EmulateInstructionARM::EmulateADR(const uint32_t opcode, } // This instruction performs a bitwise AND of a register value and an immediate -// value, and writes the result -// to the destination register. It can optionally update the condition flags -// based on the result. +// value, and writes the result to the destination register. It can optionally +// update the condition flags based on the result. bool EmulateInstructionARM::EmulateANDImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -6139,10 +6112,8 @@ bool EmulateInstructionARM::EmulateANDImm(const uint32_t opcode, } // This instruction performs a bitwise AND of a register value and an -// optionally-shifted register value, -// and writes the result to the destination register. It can optionally update -// the condition flags -// based on the result. +// optionally-shifted register value, and writes the result to the destination +// register. It can optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateANDReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -6230,10 +6201,9 @@ bool EmulateInstructionARM::EmulateANDReg(const uint32_t opcode, } // Bitwise Bit Clear (immediate) performs a bitwise AND of a register value and -// the complement of an -// immediate value, and writes the result to the destination register. It can -// optionally update the -// condition flags based on the result. +// the complement of an immediate value, and writes the result to the +// destination register. It can optionally update the condition flags based on +// the result. bool EmulateInstructionARM::EmulateBICImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -6306,10 +6276,9 @@ bool EmulateInstructionARM::EmulateBICImm(const uint32_t opcode, } // Bitwise Bit Clear (register) performs a bitwise AND of a register value and -// the complement of an -// optionally-shifted register value, and writes the result to the destination -// register. -// It can optionally update the condition flags based on the result. +// the complement of an optionally-shifted register value, and writes the +// result to the destination register. It can optionally update the condition +// flags based on the result. bool EmulateInstructionARM::EmulateBICReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -6439,7 +6408,7 @@ bool EmulateInstructionARM::EmulateLDRImmediateARM(const uint32_t opcode, n = Bits32(opcode, 19, 16); imm32 = Bits32(opcode, 11, 0); - // index = (P == '1'); add = (U == '1'); wback = (P == '0') || + // index = (P == '1'); add = (U == '1'); wback = (P == '0') || // (W == '1'); index = BitIsSet(opcode, 24); add = BitIsSet(opcode, 23); @@ -6624,7 +6593,7 @@ bool EmulateInstructionARM::EmulateLDRRegister(const uint32_t opcode, n = Bits32(opcode, 19, 16); m = Bits32(opcode, 3, 0); - // index = (P == '1'); add = (U == '1'); wback = (P == '0') || + // index = (P == '1'); add = (U == '1'); wback = (P == '0') || // (W == '1'); index = BitIsSet(opcode, 24); add = BitIsSet(opcode, 23); @@ -6661,8 +6630,8 @@ bool EmulateInstructionARM::EmulateLDRRegister(const uint32_t opcode, addr_t offset_addr; addr_t address; - // offset = Shift(R[m], shift_t, shift_n, APSR.C); -- Note "The APSR is an - // application level alias for the CPSR". + // offset = Shift(R[m], shift_t, shift_n, APSR.C); -- Note "The APSR is + // an application level alias for the CPSR". addr_t offset = Shift(Rm, shift_t, shift_n, Bit32(m_opcode_cpsr, APSR_C), &success); if (!success) @@ -6968,9 +6937,8 @@ bool EmulateInstructionARM::EmulateLDRBLiteral(const uint32_t opcode, } // LDRB (register) calculates an address from a base register value and an -// offset rigister value, loads a byte from -// memory, zero-extends it to form a 32-bit word, and writes it to a register. -// The offset register value can +// offset rigister value, loads a byte from memory, zero-extends it to form a +// 32-bit word, and writes it to a register. The offset register value can // optionally be shifted. bool EmulateInstructionARM::EmulateLDRBRegister(const uint32_t opcode, const ARMEncoding encoding) { @@ -7049,7 +7017,7 @@ bool EmulateInstructionARM::EmulateLDRBRegister(const uint32_t opcode, n = Bits32(opcode, 19, 16); m = Bits32(opcode, 3, 0); - // index = (P == '1'); add = (U == '1'); wback = (P == '0') || + // index = (P == '1'); add = (U == '1'); wback = (P == '0') || // (W == '1'); index = BitIsSet(opcode, 24); add = BitIsSet(opcode, 23); @@ -7132,9 +7100,8 @@ bool EmulateInstructionARM::EmulateLDRBRegister(const uint32_t opcode, // LDRH (immediate, Thumb) calculates an address from a base register value and // an immediate offset, loads a -// halfword from memory, zero-extends it to form a 32-bit word, and writes it to -// a register. It can use offset, -// post-indexed, or pre-indexed addressing. +// halfword from memory, zero-extends it to form a 32-bit word, and writes it +// to a register. It can use offset, post-indexed, or pre-indexed addressing. bool EmulateInstructionARM::EmulateLDRHImmediate(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -7384,8 +7351,8 @@ bool EmulateInstructionARM::EmulateLDRHLiteral(const uint32_t opcode, // LDRH (literal) calculates an address from a base register value and an offset // register value, loads a halfword // from memory, zero-extends it to form a 32-bit word, and writes it to a -// register. The offset register value can -// be shifted left by 0, 1, 2, or 3 bits. +// register. The offset register value can be shifted left by 0, 1, 2, or 3 +// bits. bool EmulateInstructionARM::EmulateLDRHRegister(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -7464,7 +7431,7 @@ bool EmulateInstructionARM::EmulateLDRHRegister(const uint32_t opcode, n = Bits32(opcode, 19, 16); m = Bits32(opcode, 3, 0); - // index = (P == '1'); add = (U == '1'); wback = (P == '0') || + // index = (P == '1'); add = (U == '1'); wback = (P == '0') || // (W == '1'); index = BitIsSet(opcode, 24); add = BitIsSet(opcode, 23); @@ -7561,8 +7528,7 @@ bool EmulateInstructionARM::EmulateLDRHRegister(const uint32_t opcode, // LDRSB (immediate) calculates an address from a base register value and an // immediate offset, loads a byte from // memory, sign-extends it to form a 32-bit word, and writes it to a register. -// It can use offset, post-indexed, -// or pre-indexed addressing. +// It can use offset, post-indexed, or pre-indexed addressing. bool EmulateInstructionARM::EmulateLDRSBImmediate(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -7643,7 +7609,7 @@ bool EmulateInstructionARM::EmulateLDRSBImmediate(const uint32_t opcode, uint32_t imm4L = Bits32(opcode, 3, 0); imm32 = (imm4H << 4) | imm4L; - // index = (P == '1'); add = (U == '1'); wback = (P == '0') || + // index = (P == '1'); add = (U == '1'); wback = (P == '0') || // (W == '1'); index = BitIsSet(opcode, 24); add = BitIsSet(opcode, 23); @@ -7799,8 +7765,7 @@ bool EmulateInstructionARM::EmulateLDRSBLiteral(const uint32_t opcode, // LDRSB (register) calculates an address from a base register value and an // offset register value, loadsa byte from // memory, sign-extends it to form a 32-bit word, and writes it to a register. -// The offset register value can be -// shifted left by 0, 1, 2, or 3 bits. +// The offset register value can be shifted left by 0, 1, 2, or 3 bits. bool EmulateInstructionARM::EmulateLDRSBRegister(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -7873,7 +7838,7 @@ bool EmulateInstructionARM::EmulateLDRSBRegister(const uint32_t opcode, n = Bits32(opcode, 19, 16); m = Bits32(opcode, 3, 0); - // index = (P == '1'); add = (U == '1'); wback = (P == '0') || + // index = (P == '1'); add = (U == '1'); wback = (P == '0') || // (W == '1'); index = BitIsSet(opcode, 24); add = BitIsSet(opcode, 23); @@ -7960,8 +7925,7 @@ bool EmulateInstructionARM::EmulateLDRSBRegister(const uint32_t opcode, // LDRSH (immediate) calculates an address from a base register value and an // immediate offset, loads a halfword from // memory, sign-extends it to form a 32-bit word, and writes it to a register. -// It can use offset, post-indexed, or -// pre-indexed addressing. +// It can use offset, post-indexed, or pre-indexed addressing. bool EmulateInstructionARM::EmulateLDRSHImmediate(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -8043,7 +8007,7 @@ bool EmulateInstructionARM::EmulateLDRSHImmediate(const uint32_t opcode, uint32_t imm4L = Bits32(opcode, 3, 0); imm32 = (imm4H << 4) | imm4L; - // index = (P == '1'); add = (U == '1'); wback = (P == '0') || + // index = (P == '1'); add = (U == '1'); wback = (P == '0') || // (W == '1'); index = BitIsSet(opcode, 24); add = BitIsSet(opcode, 23); @@ -8220,8 +8184,8 @@ bool EmulateInstructionARM::EmulateLDRSHLiteral(const uint32_t opcode, // LDRSH (register) calculates an address from a base register value and an // offset register value, loads a halfword // from memory, sign-extends it to form a 32-bit word, and writes it to a -// register. The offset register value can be -// shifted left by 0, 1, 2, or 3 bits. +// register. The offset register value can be shifted left by 0, 1, 2, or 3 +// bits. bool EmulateInstructionARM::EmulateLDRSHRegister(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -8301,7 +8265,7 @@ bool EmulateInstructionARM::EmulateLDRSHRegister(const uint32_t opcode, n = Bits32(opcode, 19, 16); m = Bits32(opcode, 3, 0); - // index = (P == '1'); add = (U == '1'); wback = (P == '0') || + // index = (P == '1'); add = (U == '1'); wback = (P == '0') || // (W == '1'); index = BitIsSet(opcode, 24); add = BitIsSet(opcode, 23); @@ -8879,9 +8843,8 @@ bool EmulateInstructionARM::EmulateRFE(const uint32_t opcode, } // Bitwise Exclusive OR (immediate) performs a bitwise exclusive OR of a -// register value and an immediate value, -// and writes the result to the destination register. It can optionally update -// the condition flags based on +// register value and an immediate value, and writes the result to the +// destination register. It can optionally update the condition flags based on // the result. bool EmulateInstructionARM::EmulateEORImm(const uint32_t opcode, const ARMEncoding encoding) { @@ -8957,11 +8920,10 @@ bool EmulateInstructionARM::EmulateEORImm(const uint32_t opcode, return true; } -// Bitwise Exclusive OR (register) performs a bitwise exclusive OR of a register -// value and an -// optionally-shifted register value, and writes the result to the destination -// register. -// It can optionally update the condition flags based on the result. +// Bitwise Exclusive OR (register) performs a bitwise exclusive OR of a +// register value and an optionally-shifted register value, and writes the +// result to the destination register. It can optionally update the condition +// flags based on the result. bool EmulateInstructionARM::EmulateEORReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -9051,10 +9013,8 @@ bool EmulateInstructionARM::EmulateEORReg(const uint32_t opcode, } // Bitwise OR (immediate) performs a bitwise (inclusive) OR of a register value -// and an immediate value, and -// writes the result to the destination register. It can optionally update the -// condition flags based -// on the result. +// and an immediate value, and writes the result to the destination register. +// It can optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateORRImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -9128,10 +9088,9 @@ bool EmulateInstructionARM::EmulateORRImm(const uint32_t opcode, } // Bitwise OR (register) performs a bitwise (inclusive) OR of a register value -// and an optionally-shifted register -// value, and writes the result to the destination register. It can optionally -// update the condition flags based -// on the result. +// and an optionally-shifted register value, and writes the result to the +// destination register. It can optionally update the condition flags based on +// the result. bool EmulateInstructionARM::EmulateORRReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -9219,9 +9178,8 @@ bool EmulateInstructionARM::EmulateORRReg(const uint32_t opcode, } // Reverse Subtract (immediate) subtracts a register value from an immediate -// value, and writes the result to -// the destination register. It can optionally update the condition flags based -// on the result. +// value, and writes the result to the destination register. It can optionally +// update the condition flags based on the result. bool EmulateInstructionARM::EmulateRSBImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -9294,10 +9252,9 @@ bool EmulateInstructionARM::EmulateRSBImm(const uint32_t opcode, return true; } -// Reverse Subtract (register) subtracts a register value from an -// optionally-shifted register value, and writes the -// result to the destination register. It can optionally update the condition -// flags based on the result. +// Reverse Subtract (register) subtracts a register value from an optionally- +// shifted register value, and writes the result to the destination register. +// It can optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateRSBReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -9377,10 +9334,9 @@ bool EmulateInstructionARM::EmulateRSBReg(const uint32_t opcode, } // Reverse Subtract with Carry (immediate) subtracts a register value and the -// value of NOT (Carry flag) from -// an immediate value, and writes the result to the destination register. It can -// optionally update the condition -// flags based on the result. +// value of NOT (Carry flag) from an immediate value, and writes the result to +// the destination register. It can optionally update the condition flags based +// on the result. bool EmulateInstructionARM::EmulateRSCImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -9440,9 +9396,8 @@ bool EmulateInstructionARM::EmulateRSCImm(const uint32_t opcode, } // Reverse Subtract with Carry (register) subtracts a register value and the -// value of NOT (Carry flag) from an -// optionally-shifted register value, and writes the result to the destination -// register. It can optionally update the +// value of NOT (Carry flag) from an optionally-shifted register value, and +// writes the result to the destination register. It can optionally update the // condition flags based on the result. bool EmulateInstructionARM::EmulateRSCReg(const uint32_t opcode, const ARMEncoding encoding) { @@ -9512,7 +9467,8 @@ bool EmulateInstructionARM::EmulateRSCReg(const uint32_t opcode, return true; } -// Subtract with Carry (immediate) subtracts an immediate value and the value of +// Subtract with Carry (immediate) subtracts an immediate value and the value +// of // NOT (Carry flag) from a register value, and writes the result to the // destination register. // It can optionally update the condition flags based on the result. @@ -9582,8 +9538,8 @@ bool EmulateInstructionARM::EmulateSBCImm(const uint32_t opcode, return true; } -// Subtract with Carry (register) subtracts an optionally-shifted register value -// and the value of +// Subtract with Carry (register) subtracts an optionally-shifted register +// value and the value of // NOT (Carry flag) from a register value, and writes the result to the // destination register. // It can optionally update the condition flags based on the result. @@ -9672,9 +9628,8 @@ bool EmulateInstructionARM::EmulateSBCReg(const uint32_t opcode, } // This instruction subtracts an immediate value from a register value, and -// writes the result -// to the destination register. It can optionally update the condition flags -// based on the result. +// writes the result to the destination register. It can optionally update the +// condition flags based on the result. bool EmulateInstructionARM::EmulateSUBImmThumb(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -9766,9 +9721,8 @@ bool EmulateInstructionARM::EmulateSUBImmThumb(const uint32_t opcode, } // This instruction subtracts an immediate value from a register value, and -// writes the result -// to the destination register. It can optionally update the condition flags -// based on the result. +// writes the result to the destination register. It can optionally update the +// condition flags based on the result. bool EmulateInstructionARM::EmulateSUBImmARM(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -9844,9 +9798,8 @@ bool EmulateInstructionARM::EmulateSUBImmARM(const uint32_t opcode, } // Test Equivalence (immediate) performs a bitwise exclusive OR operation on a -// register value and an -// immediate value. It updates the condition flags based on the result, and -// discards the result. +// register value and an immediate value. It updates the condition flags based +// on the result, and discards the result. bool EmulateInstructionARM::EmulateTEQImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -9904,10 +9857,8 @@ bool EmulateInstructionARM::EmulateTEQImm(const uint32_t opcode, } // Test Equivalence (register) performs a bitwise exclusive OR operation on a -// register value and an -// optionally-shifted register value. It updates the condition flags based on -// the result, and discards -// the result. +// register value and an optionally-shifted register value. It updates the +// condition flags based on the result, and discards the result. bool EmulateInstructionARM::EmulateTEQReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -9972,8 +9923,8 @@ bool EmulateInstructionARM::EmulateTEQReg(const uint32_t opcode, } // Test (immediate) performs a bitwise AND operation on a register value and an -// immediate value. -// It updates the condition flags based on the result, and discards the result. +// immediate value. It updates the condition flags based on the result, and +// discards the result. bool EmulateInstructionARM::EmulateTSTImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -10031,8 +9982,8 @@ bool EmulateInstructionARM::EmulateTSTImm(const uint32_t opcode, } // Test (register) performs a bitwise AND operation on a register value and an -// optionally-shifted register value. -// It updates the condition flags based on the result, and discards the result. +// optionally-shifted register value. It updates the condition flags based on +// the result, and discards the result. bool EmulateInstructionARM::EmulateTSTReg(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -10403,9 +10354,8 @@ bool EmulateInstructionARM::EmulateSUBReg(const uint32_t opcode, AddWithCarryResult res = AddWithCarry(Rn, ~shifted, 1); - // if d == 15 then // Can only occur for ARM encoding - // ALUWritePC(result); // setflags is always FALSE here - // else + // if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); + // // setflags is always FALSE here else // R[d] = result; // if setflags then // APSR.N = result<31>; @@ -10429,10 +10379,9 @@ bool EmulateInstructionARM::EmulateSUBReg(const uint32_t opcode, } // A8.6.202 STREX -// Store Register Exclusive calculates an address from a base register value and -// an immediate offset, and stores a -// word from a register to memory if the executing processor has exclusive -// access to the memory addressed. +// Store Register Exclusive calculates an address from a base register value +// and an immediate offset, and stores a word from a register to memory if the +// executing processor has exclusive access to the memory addressed. bool EmulateInstructionARM::EmulateSTREX(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -10457,7 +10406,8 @@ bool EmulateInstructionARM::EmulateSTREX(const uint32_t opcode, switch (encoding) { case eEncodingT1: - // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8:'00', + // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = + // ZeroExtend(imm8:'00', // 32); d = Bits32(opcode, 11, 8); t = Bits32(opcode, 15, 12); @@ -10511,9 +10461,9 @@ bool EmulateInstructionARM::EmulateSTREX(const uint32_t opcode, context.type = eContextRegisterStore; context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, imm32); - // if ExclusiveMonitorsPass(address,4) then - // if (ExclusiveMonitorsPass (address, addr_byte_size)) -- For now, for the - // sake of emulation, we will say this + // if ExclusiveMonitorsPass(address,4) then if (ExclusiveMonitorsPass + // (address, addr_byte_size)) -- For now, for the sake of emulation, we + // will say this // always return // true. if (true) { @@ -10742,9 +10692,9 @@ bool EmulateInstructionARM::EmulateSTRImmARM(const uint32_t opcode, // A8.6.66 LDRD (immediate) // Load Register Dual (immediate) calculates an address from a base register -// value and an immediate offset, loads two -// words from memory, and writes them to two registers. It can use offset, -// post-indexed, or pre-indexed addressing. +// value and an immediate offset, loads two words from memory, and writes them +// to two registers. It can use offset, post-indexed, or pre-indexed +// addressing. bool EmulateInstructionARM::EmulateLDRDImmediate(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -10891,9 +10841,8 @@ bool EmulateInstructionARM::EmulateLDRDImmediate(const uint32_t opcode, // A8.6.68 LDRD (register) // Load Register Dual (register) calculates an address from a base register -// value and a register offset, loads two -// words from memory, and writes them to two registers. It can use offset, -// post-indexed or pre-indexed addressing. +// value and a register offset, loads two words from memory, and writes them to +// two registers. It can use offset, post-indexed or pre-indexed addressing. bool EmulateInstructionARM::EmulateLDRDRegister(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -11021,9 +10970,8 @@ bool EmulateInstructionARM::EmulateLDRDRegister(const uint32_t opcode, // A8.6.200 STRD (immediate) // Store Register Dual (immediate) calculates an address from a base register -// value and an immediate offset, and -// stores two words from two registers to memory. It can use offset, -// post-indexed, or pre-indexed addressing. +// value and an immediate offset, and stores two words from two registers to +// memory. It can use offset, post-indexed, or pre-indexed addressing. bool EmulateInstructionARM::EmulateSTRDImm(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -11314,8 +11262,7 @@ bool EmulateInstructionARM::EmulateSTRDReg(const uint32_t opcode, // A8.6.319 VLDM // Vector Load Multiple loads multiple extension registers from consecutive -// memory locations using an address from -// an ARM core register. +// memory locations using an address from an ARM core register. bool EmulateInstructionARM::EmulateVLDM(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -11328,7 +11275,8 @@ bool EmulateInstructionARM::EmulateVLDM(const uint32_t opcode, S[d+r] = MemA[address,4]; address = address+4; else word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8; - // Combine the word-aligned words in the correct order for current endianness. + // Combine the word-aligned words in the correct order for + // current endianness. D[d+r] = if BigEndian() then word1:word2 else word2:word1; #endif @@ -11389,8 +11337,8 @@ bool EmulateInstructionARM::EmulateVLDM(const uint32_t opcode, return false; // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with - // !), 101 (DB with !) - // single_regs = TRUE; add = (U == '1'); wback = (W == '1'); d = + // !), 101 (DB with !) single_regs = TRUE; add = (U == '1'); wback = (W + // == '1'); d = // UInt(Vd:D); n = UInt(Rn); single_regs = true; add = BitIsSet(opcode, 23); @@ -11519,7 +11467,8 @@ bool EmulateInstructionARM::EmulateVSTM(const uint32_t opcode, if single_regs then MemA[address,4] = S[d+r]; address = address+4; else - // Store as two word-aligned words in the correct order for current endianness. + // Store as two word-aligned words in the correct order for + // current endianness. MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>; MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>; address = address+8; @@ -11582,8 +11531,8 @@ bool EmulateInstructionARM::EmulateVSTM(const uint32_t opcode, return false; // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with - // !), 101 (DB with !) - // single_regs = TRUE; add = (U == '1'); wback = (W == '1'); d = + // !), 101 (DB with !) single_regs = TRUE; add = (U == '1'); wback = (W + // == '1'); d = // UInt(Vd:D); n = UInt(Rn); single_regs = true; add = BitIsSet(opcode, 23); @@ -11665,8 +11614,7 @@ bool EmulateInstructionARM::EmulateVSTM(const uint32_t opcode, address = address + 4; } else { // // Store as two word-aligned words in the correct order for current - // endianness. - // MemA[address,4] = if BigEndian() then D[d+r]<63:32> else + // endianness. MemA[address,4] = if BigEndian() then D[d+r]<63:32> else // D[d+r]<31:0>; // MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else // D[d+r]<63:32>; @@ -11712,8 +11660,7 @@ bool EmulateInstructionARM::EmulateVSTM(const uint32_t opcode, // A8.6.320 // This instruction loads a single extension register from memory, using an -// address from an ARM core register, with -// an optional offset. +// address from an ARM core register, with an optional offset. bool EmulateInstructionARM::EmulateVLDR(const uint32_t opcode, ARMEncoding encoding) { #if 0 @@ -11725,7 +11672,8 @@ bool EmulateInstructionARM::EmulateVLDR(const uint32_t opcode, S[d] = MemA[address,4]; else word1 = MemA[address,4]; word2 = MemA[address+4,4]; - // Combine the word-aligned words in the correct order for current endianness. + // Combine the word-aligned words in the correct order for current + // endianness. D[d] = if BigEndian() then word1:word2 else word2:word1; #endif @@ -11839,8 +11787,7 @@ bool EmulateInstructionARM::EmulateVLDR(const uint32_t opcode, // A8.6.400 VSTR // This instruction stores a signle extension register to memory, using an -// address from an ARM core register, with an -// optional offset. +// address from an ARM core register, with an optional offset. bool EmulateInstructionARM::EmulateVSTR(const uint32_t opcode, ARMEncoding encoding) { #if 0 @@ -11850,7 +11797,8 @@ bool EmulateInstructionARM::EmulateVSTR(const uint32_t opcode, if single_reg then MemA[address,4] = S[d]; else - // Store as two word-aligned words in the correct order for current endianness. + // Store as two word-aligned words in the correct order for current + // endianness. MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>; MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>; #endif @@ -11970,10 +11918,9 @@ bool EmulateInstructionARM::EmulateVSTR(const uint32_t opcode, return true; } -// A8.6.307 VLDI1 (multiple single elements) -// This instruction loads elements from memory into one, two, three or four -// registers, without de-interleaving. Every -// element of each register is loaded. +// A8.6.307 VLDI1 (multiple single elements) This instruction loads elements +// from memory into one, two, three or four registers, without de-interleaving. +// Every element of each register is loaded. bool EmulateInstructionARM::EmulateVLD1Multiple(const uint32_t opcode, ARMEncoding encoding) { #if 0 @@ -12291,8 +12238,7 @@ bool EmulateInstructionARM::EmulateVLD1Single(const uint32_t opcode, if (index > 0) mask = mask | Bits64(all_ones, (index * esize) - 1, 0); // add 1's to the right of where 'element' goes. - // now mask should be 0's where element goes & 1's - // everywhere else. + // now mask should be 0's where element goes & 1's everywhere else. uint64_t masked_reg = reg_data & mask; // Take original reg value & zero out 'element' bits @@ -12307,10 +12253,9 @@ bool EmulateInstructionARM::EmulateVLD1Single(const uint32_t opcode, return true; } -// A8.6.391 VST1 (multiple single elements) -// Vector Store (multiple single elements) stores elements to memory from one, -// two, three, or four registers, without -// interleaving. Every element of each register is stored. +// A8.6.391 VST1 (multiple single elements) Vector Store (multiple single +// elements) stores elements to memory from one, two, three, or four registers, +// without interleaving. Every element of each register is stored. bool EmulateInstructionARM::EmulateVST1Multiple(const uint32_t opcode, ARMEncoding encoding) { #if 0 @@ -12465,8 +12410,8 @@ bool EmulateInstructionARM::EmulateVST1Multiple(const uint32_t opcode, return true; } -// A8.6.392 VST1 (single element from one lane) -// This instruction stores one element to memory from one element of a register. +// A8.6.392 VST1 (single element from one lane) This instruction stores one +// element to memory from one element of a register. bool EmulateInstructionARM::EmulateVST1Single(const uint32_t opcode, ARMEncoding encoding) { #if 0 @@ -12624,9 +12569,8 @@ bool EmulateInstructionARM::EmulateVST1Single(const uint32_t opcode, return true; } -// A8.6.309 VLD1 (single element to all lanes) -// This instruction loads one element from memory into every element of one or -// two vectors. +// A8.6.309 VLD1 (single element to all lanes) This instruction loads one +// element from memory into every element of one or two vectors. bool EmulateInstructionARM::EmulateVLD1SingleAll(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -12754,11 +12698,10 @@ bool EmulateInstructionARM::EmulateVLD1SingleAll(const uint32_t opcode, return true; } -// B6.2.13 SUBS PC, LR and related instructions -// The SUBS PC, LR, #<const? instruction provides an exception return without -// the use of the stack. It subtracts the -// immediate constant from the LR, branches to the resulting address, and also -// copies the SPSR to the CPSR. +// B6.2.13 SUBS PC, LR and related instructions The SUBS PC, LR, #<const? +// instruction provides an exception return without the use of the stack. It +// subtracts the immediate constant from the LR, branches to the resulting +// address, and also copies the SPSR to the CPSR. bool EmulateInstructionARM::EmulateSUBSPcLrEtc(const uint32_t opcode, const ARMEncoding encoding) { #if 0 @@ -12797,9 +12740,9 @@ bool EmulateInstructionARM::EmulateSUBSPcLrEtc(const uint32_t opcode, switch (encoding) { case eEncodingT1: - // if CurrentInstrSet() == InstrSet_ThumbEE then UNPREDICTABLE - // n = 14; imm32 = ZeroExtend(imm8, 32); register_form = FALSE; opcode = - // '0010'; // = SUB + // if CurrentInstrSet() == InstrSet_ThumbEE then UNPREDICTABLE n = 14; + // imm32 = ZeroExtend(imm8, 32); register_form = FALSE; opcode = '0010'; + // // = SUB n = 14; imm32 = Bits32(opcode, 7, 0); register_form = false; @@ -12924,8 +12867,7 @@ bool EmulateInstructionARM::EmulateSUBSPcLrEtc(const uint32_t opcode, // CPSRWriteByInstr(SPSR[], '1111', TRUE); // For now, in emulation mode, we don't have access to the SPSR, so we will - // use the CPSR instead, and hope for - // the best. + // use the CPSR instead, and hope for the best. uint32_t spsr = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_cpsr, 0, &success); if (!success) @@ -13946,10 +13888,10 @@ bool EmulateInstructionARM::SetInstruction(const Opcode &insn_opcode, else { AddressClass addr_class = inst_addr.GetAddressClass(); - if ((addr_class == eAddressClassCode) || - (addr_class == eAddressClassUnknown)) + if ((addr_class == AddressClass::eCode) || + (addr_class == AddressClass::eUnknown)) m_opcode_mode = eModeARM; - else if (addr_class == eAddressClassCodeAlternateISA) + else if (addr_class == AddressClass::eCodeAlternateISA) m_opcode_mode = eModeThumb; else return false; @@ -13999,8 +13941,7 @@ bool EmulateInstructionARM::ReadInstruction() { if (!m_ignore_conditions) { // If we are not ignoreing the conditions then init the it session from - // the current - // value of cpsr. + // the current value of cpsr. uint32_t it = (Bits32(m_opcode_cpsr, 15, 10) << 2) | Bits32(m_opcode_cpsr, 26, 25); if (it != 0) @@ -14018,10 +13959,9 @@ bool EmulateInstructionARM::ReadInstruction() { uint32_t EmulateInstructionARM::ArchVersion() { return m_arm_isa; } bool EmulateInstructionARM::ConditionPassed(const uint32_t opcode) { - // If we are ignoring conditions, then always return true. - // this allows us to iterate over disassembly code and still - // emulate an instruction even if we don't have all the right - // bits set in the CPSR register... + // If we are ignoring conditions, then always return true. this allows us to + // iterate over disassembly code and still emulate an instruction even if we + // don't have all the right bits set in the CPSR register... if (m_ignore_conditions) return true; @@ -14225,8 +14165,8 @@ bool EmulateInstructionARM::BranchWritePC(const Context &context, bool EmulateInstructionARM::BXWritePC(Context &context, uint32_t addr) { addr_t target; // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE, - // we want to record it and issue a WriteRegister callback so the clients - // can track the mode changes accordingly. + // we want to record it and issue a WriteRegister callback so the clients can + // track the mode changes accordingly. bool cpsr_changed = false; if (BitIsSet(addr, 0)) { @@ -14307,9 +14247,10 @@ bool EmulateInstructionARM::UnalignedSupport() { return (ArchVersion() >= ARMv7); } -// The main addition and subtraction instructions can produce status information -// about both unsigned carry and signed overflow conditions. This status -// information can be used to synthesize multi-word additions and subtractions. +// The main addition and subtraction instructions can produce status +// information about both unsigned carry and signed overflow conditions. This +// status information can be used to synthesize multi-word additions and +// subtractions. EmulateInstructionARM::AddWithCarryResult EmulateInstructionARM::AddWithCarry(uint32_t x, uint32_t y, uint8_t carry_in) { uint32_t result; @@ -14364,9 +14305,8 @@ uint32_t EmulateInstructionARM::ReadCoreReg(uint32_t num, bool *success) { uint32_t val = ReadRegisterUnsigned(reg_kind, reg_num, 0, success); // When executing an ARM instruction , PC reads as the address of the current - // instruction plus 8. - // When executing a Thumb instruction , PC reads as the address of the current - // instruction plus 4. + // instruction plus 8. When executing a Thumb instruction , PC reads as the + // address of the current instruction plus 4. if (num == 15) { if (CurrentInstrSet() == eModeARM) val += 8; @@ -14434,8 +14374,7 @@ bool EmulateInstructionARM::WriteCoreRegOptionalFlags( // APSR.V = overflow // // Default arguments can be specified for carry and overflow parameters, which -// means -// not to update the respective flags. +// means not to update the respective flags. bool EmulateInstructionARM::WriteFlags(Context &context, const uint32_t result, const uint32_t carry, const uint32_t overflow) { @@ -14496,8 +14435,7 @@ bool EmulateInstructionARM::EvaluateInstruction(uint32_t evaluate_options) { } // Advance the ITSTATE bits to their values for the next instruction if we - // haven't just executed - // an IT instruction what initialized it. + // haven't just executed an IT instruction what initialized it. if (m_opcode_mode == eModeThumb && m_it_session.InITBlock() && (opcode_data == nullptr || opcode_data->callback != &EmulateInstructionARM::EmulateIT)) diff --git a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp index d882108c25f4..2f484ab5ea97 100644 --- a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp +++ b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp @@ -76,19 +76,6 @@ static inline bool IsZero(uint64_t x) { return x == 0; } static inline uint64_t NOT(uint64_t x) { return ~x; } -#if 0 -// LSL_C() -// ======= -static inline uint64_t -LSL_C (uint64_t x, integer shift, bool &carry_out) -{ - assert (shift >= 0); - uint64_t result = x << shift; - carry_out = ((1ull << (64-1)) >> (shift - 1)) != 0; - return result; -} -#endif - // LSL() // ===== @@ -519,8 +506,8 @@ bool EmulateInstructionARM64::UsingAArch32() { bool EmulateInstructionARM64::BranchTo(const Context &context, uint32_t N, addr_t target) { #if 0 - // Set program counter to a new address, with a branch reason hint - // for possible use by hardware fetching the next instruction. + // Set program counter to a new address, with a branch reason hint for + // possible use by hardware fetching the next instruction. BranchTo(bits(N) target, BranchType branch_type) Hint_Branch(branch_type); if N == 32 then @@ -568,10 +555,9 @@ bool EmulateInstructionARM64::BranchTo(const Context &context, uint32_t N, } bool EmulateInstructionARM64::ConditionHolds(const uint32_t cond) { - // If we are ignoring conditions, then always return true. - // this allows us to iterate over disassembly code and still - // emulate an instruction even if we don't have all the right - // bits set in the CPSR register... + // If we are ignoring conditions, then always return true. this allows us to + // iterate over disassembly code and still emulate an instruction even if we + // don't have all the right bits set in the CPSR register... if (m_ignore_conditions) return true; @@ -703,8 +689,8 @@ bool EmulateInstructionARM64::EmulateADDSUBImm(const uint32_t opcode) { context.SetRegisterPlusOffset(reg_info_Rn, imm); if (n == GetFramePointerRegisterNumber() && d == gpr_sp_arm64 && !setflags) { - // 'mov sp, fp' - common epilogue instruction, CFA is now in terms - // of the stack pointer, instead of frame pointer. + // 'mov sp, fp' - common epilogue instruction, CFA is now in terms of the + // stack pointer, instead of frame pointer. context.type = EmulateInstruction::eContextRestoreStackPointer; } else if ((n == gpr_sp_arm64 || n == GetFramePointerRegisterNumber()) && d == gpr_sp_arm64 && !setflags) { diff --git a/source/Plugins/Instruction/CMakeLists.txt b/source/Plugins/Instruction/CMakeLists.txt index 78f2f64cf1ab..89771e8f46d1 100644 --- a/source/Plugins/Instruction/CMakeLists.txt +++ b/source/Plugins/Instruction/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(ARM) add_subdirectory(ARM64) add_subdirectory(MIPS) add_subdirectory(MIPS64) +add_subdirectory(PPC64) diff --git a/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp index db3d8fc1b8ca..b65747e12890 100644 --- a/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp +++ b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp @@ -1015,7 +1015,7 @@ bool EmulateInstructionMIPS::SetInstruction(const Opcode &insn_opcode, m_use_alt_disaasm = false; if (EmulateInstruction::SetInstruction(insn_opcode, inst_addr, target)) { - if (inst_addr.GetAddressClass() == eAddressClassCodeAlternateISA) { + if (inst_addr.GetAddressClass() == AddressClass::eCodeAlternateISA) { Status error; lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; @@ -1044,7 +1044,7 @@ bool EmulateInstructionMIPS::SetInstruction(const Opcode &insn_opcode, return true; } else { /* - * If the address class is not eAddressClassCodeAlternateISA then + * If the address class is not AddressClass::eCodeAlternateISA then * the function is not microMIPS. In this case instruction size is * always 4 bytes. */ @@ -1205,13 +1205,10 @@ bool EmulateInstructionMIPS::Emulate_ADDiu(llvm::MCInst &insn) { dst = m_reg_info->getEncodingValue(insn.getOperand(0).getReg()); src = m_reg_info->getEncodingValue(insn.getOperand(1).getReg()); - // If immediate value is greater then 2^16 - 1 then clang generate - // LUI, ADDIU, SUBU instructions in prolog. - // Example - // lui $1, 0x2 - // addiu $1, $1, -0x5920 - // subu $sp, $sp, $1 - // In this case, ADDIU dst and src will be same and not equal to sp + // If immediate value is greater then 2^16 - 1 then clang generate LUI, + // ADDIU, SUBU instructions in prolog. Example lui $1, 0x2 addiu $1, $1, + // -0x5920 subu $sp, $sp, $1 In this case, ADDIU dst and src will be same + // and not equal to sp if (dst == src) { Context context; @@ -1545,8 +1542,8 @@ bool EmulateInstructionMIPS::Emulate_SWSP(llvm::MCInst &insn) { address = address + imm5; // We use bad_vaddr_context to store base address which is used by H/W - // watchpoint - // Set the bad_vaddr register with base address used in the instruction + // watchpoint Set the bad_vaddr register with base address used in the + // instruction bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, address); @@ -1682,8 +1679,8 @@ bool EmulateInstructionMIPS::Emulate_LWSP(llvm::MCInst &insn) { base_address = base_address + imm5; // We use bad_vaddr_context to store base address which is used by H/W - // watchpoint - // Set the bad_vaddr register with base address used in the instruction + // watchpoint Set the bad_vaddr register with base address used in the + // instruction bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, base_address); diff --git a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp index d298589afdd9..5af12ad141aa 100644 --- a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp +++ b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp @@ -1091,13 +1091,10 @@ bool EmulateInstructionMIPS64::Emulate_DADDiu(llvm::MCInst &insn) { dst = m_reg_info->getEncodingValue(insn.getOperand(0).getReg()); src = m_reg_info->getEncodingValue(insn.getOperand(1).getReg()); - // If immediate is greater than 2^16 - 1 then clang generate - // LUI, (D)ADDIU,(D)SUBU instructions in prolog. - // Example - // lui $1, 0x2 - // daddiu $1, $1, -0x5920 - // dsubu $sp, $sp, $1 - // In this case, (D)ADDIU dst and src will be same and not equal to sp + // If immediate is greater than 2^16 - 1 then clang generate LUI, + // (D)ADDIU,(D)SUBU instructions in prolog. Example lui $1, 0x2 daddiu $1, + // $1, -0x5920 dsubu $sp, $sp, $1 In this case, (D)ADDIU dst and src will be + // same and not equal to sp if (dst == src) { Context context; diff --git a/source/Plugins/Instruction/PPC64/CMakeLists.txt b/source/Plugins/Instruction/PPC64/CMakeLists.txt new file mode 100644 index 000000000000..0926433fc77c --- /dev/null +++ b/source/Plugins/Instruction/PPC64/CMakeLists.txt @@ -0,0 +1,11 @@ +add_lldb_library(lldbPluginInstructionPPC64 PLUGIN + EmulateInstructionPPC64.cpp + + LINK_LIBS + lldbCore + lldbInterpreter + lldbSymbol + lldbPluginProcessUtility + LINK_COMPONENTS + Support + ) diff --git a/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp b/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp new file mode 100644 index 000000000000..f3a9ca570a4a --- /dev/null +++ b/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp @@ -0,0 +1,406 @@ +//===-- EmulateInstructionPPC64.cpp ------------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "EmulateInstructionPPC64.h" + +#include <stdlib.h> + +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/ConstString.h" + +#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" + +#include "Plugins/Process/Utility/InstructionUtils.h" + +using namespace lldb; +using namespace lldb_private; + +EmulateInstructionPPC64::EmulateInstructionPPC64(const ArchSpec &arch) + : EmulateInstruction(arch) {} + +void EmulateInstructionPPC64::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); +} + +void EmulateInstructionPPC64::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString EmulateInstructionPPC64::GetPluginNameStatic() { + ConstString g_plugin_name("lldb.emulate-instruction.ppc64"); + return g_plugin_name; +} + +ConstString EmulateInstructionPPC64::GetPluginName() { + static ConstString g_plugin_name("EmulateInstructionPPC64"); + return g_plugin_name; +} + +const char *EmulateInstructionPPC64::GetPluginDescriptionStatic() { + return "Emulate instructions for the PPC64 architecture."; +} + +EmulateInstruction * +EmulateInstructionPPC64::CreateInstance(const ArchSpec &arch, + InstructionType inst_type) { + if (EmulateInstructionPPC64::SupportsEmulatingInstructionsOfTypeStatic( + inst_type)) { + if (arch.GetTriple().getArch() == llvm::Triple::ppc64 || + arch.GetTriple().getArch() == llvm::Triple::ppc64le) { + return new EmulateInstructionPPC64(arch); + } + } + + return nullptr; +} + +bool EmulateInstructionPPC64::SetTargetTriple(const ArchSpec &arch) { + if (arch.GetTriple().getArch() == llvm::Triple::ppc64) + return true; + else if (arch.GetTriple().getArch() == llvm::Triple::ppc64le) + return true; + + return false; +} + +static bool LLDBTableGetRegisterInfo(uint32_t reg_num, RegisterInfo ®_info) { + if (reg_num >= llvm::array_lengthof(g_register_infos_ppc64le)) + return false; + reg_info = g_register_infos_ppc64le[reg_num]; + return true; +} + +bool EmulateInstructionPPC64::GetRegisterInfo(RegisterKind reg_kind, + uint32_t reg_num, + RegisterInfo ®_info) { + if (reg_kind == eRegisterKindGeneric) { + switch (reg_num) { + case LLDB_REGNUM_GENERIC_PC: + reg_kind = eRegisterKindLLDB; + reg_num = gpr_pc_ppc64le; + break; + case LLDB_REGNUM_GENERIC_SP: + reg_kind = eRegisterKindLLDB; + reg_num = gpr_r1_ppc64le; + break; + case LLDB_REGNUM_GENERIC_RA: + reg_kind = eRegisterKindLLDB; + reg_num = gpr_lr_ppc64le; + break; + case LLDB_REGNUM_GENERIC_FLAGS: + reg_kind = eRegisterKindLLDB; + reg_num = gpr_cr_ppc64le; + break; + + default: + return false; + } + } + + if (reg_kind == eRegisterKindLLDB) + return LLDBTableGetRegisterInfo(reg_num, reg_info); + return false; +} + +bool EmulateInstructionPPC64::ReadInstruction() { + bool success = false; + m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, + LLDB_INVALID_ADDRESS, &success); + if (success) { + Context ctx; + ctx.type = eContextReadOpcode; + ctx.SetNoArgs(); + m_opcode.SetOpcode32(ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success), + GetByteOrder()); + } + if (!success) + m_addr = LLDB_INVALID_ADDRESS; + return success; +} + +bool EmulateInstructionPPC64::CreateFunctionEntryUnwind( + UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindLLDB); + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our previous Call Frame Address is the stack pointer + row->GetCFAValue().SetIsRegisterPlusOffset(gpr_r1_ppc64le, 0); + + unwind_plan.AppendRow(row); + unwind_plan.SetSourceName("EmulateInstructionPPC64"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); + unwind_plan.SetReturnAddressRegister(gpr_lr_ppc64le); + return true; +} + +EmulateInstructionPPC64::Opcode * +EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) { + static EmulateInstructionPPC64::Opcode g_opcodes[] = { + {0xfc0007ff, 0x7c0002a6, &EmulateInstructionPPC64::EmulateMFSPR, + "mfspr RT, SPR"}, + {0xfc000003, 0xf8000000, &EmulateInstructionPPC64::EmulateSTD, + "std RS, DS(RA)"}, + {0xfc000003, 0xf8000001, &EmulateInstructionPPC64::EmulateSTD, + "stdu RS, DS(RA)"}, + {0xfc0007fe, 0x7c000378, &EmulateInstructionPPC64::EmulateOR, + "or RA, RS, RB"}, + {0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI, + "addi RT, RA, SI"}, + {0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD, + "ld RT, DS(RA)"}}; + static const size_t k_num_ppc_opcodes = llvm::array_lengthof(g_opcodes); + + for (size_t i = 0; i < k_num_ppc_opcodes; ++i) { + if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value) + return &g_opcodes[i]; + } + return nullptr; +} + +bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { + const uint32_t opcode = m_opcode.GetOpcode32(); + // LLDB_LOG(log, "PPC64::EvaluateInstruction: opcode={0:X+8}", opcode); + Opcode *opcode_data = GetOpcodeForInstruction(opcode); + if (!opcode_data) + return false; + + // LLDB_LOG(log, "PPC64::EvaluateInstruction: {0}", opcode_data->name); + const bool auto_advance_pc = + evaluate_options & eEmulateInstructionOptionAutoAdvancePC; + + bool success = false; + + uint32_t orig_pc_value = 0; + if (auto_advance_pc) { + orig_pc_value = + ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + if (!success) + return false; + } + + // Call the Emulate... function. + success = (this->*opcode_data->callback)(opcode); + if (!success) + return false; + + if (auto_advance_pc) { + uint32_t new_pc_value = + ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); + if (!success) + return false; + + if (auto_advance_pc && (new_pc_value == orig_pc_value)) { + EmulateInstruction::Context context; + context.type = eContextAdvancePC; + context.SetNoArgs(); + if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_pc_ppc64le, + orig_pc_value + 4)) + return false; + } + } + return true; +} + +bool EmulateInstructionPPC64::EmulateMFSPR(uint32_t opcode) { + uint32_t rt = Bits32(opcode, 25, 21); + uint32_t spr = Bits32(opcode, 20, 11); + + enum { SPR_LR = 0x100 }; + + // For now, we're only insterested in 'mfspr r0, lr' + if (rt != gpr_r0_ppc64le || spr != SPR_LR) + return false; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + LLDB_LOG(log, "EmulateMFSPR: {0:X+8}: mfspr r0, lr", m_addr); + + bool success; + uint64_t lr = + ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + if (!success) + return false; + Context context; + context.type = eContextWriteRegisterRandomBits; + WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_r0_ppc64le, lr); + LLDB_LOG(log, "EmulateMFSPR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateLD(uint32_t opcode) { + uint32_t rt = Bits32(opcode, 25, 21); + uint32_t ra = Bits32(opcode, 20, 16); + uint32_t ds = Bits32(opcode, 15, 2); + + int32_t ids = llvm::SignExtend32<16>(ds << 2); + + // For now, tracking only loads from 0(r1) to r1 (0(r1) is the ABI defined + // location to save previous SP) + if (ra != gpr_r1_ppc64le || rt != gpr_r1_ppc64le || ids != 0) + return false; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + LLDB_LOG(log, "EmulateLD: {0:X+8}: ld r{1}, {2}(r{3})", m_addr, rt, ids, ra); + + RegisterInfo r1_info; + if (!GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le, r1_info)) + return false; + + // restore SP + Context ctx; + ctx.type = eContextRestoreStackPointer; + ctx.SetRegisterToRegisterPlusOffset(r1_info, r1_info, 0); + + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, 0); + LLDB_LOG(log, "EmulateLD: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateSTD(uint32_t opcode) { + uint32_t rs = Bits32(opcode, 25, 21); + uint32_t ra = Bits32(opcode, 20, 16); + uint32_t ds = Bits32(opcode, 15, 2); + uint32_t u = Bits32(opcode, 1, 0); + + // For now, tracking only stores to r1 + if (ra != gpr_r1_ppc64le) + return false; + // ... and only stores of SP, FP and LR (moved into r0 by a previous mfspr) + if (rs != gpr_r1_ppc64le && rs != gpr_r31_ppc64le && rs != gpr_r30_ppc64le && + rs != gpr_r0_ppc64le) + return false; + + bool success; + uint64_t rs_val = ReadRegisterUnsigned(eRegisterKindLLDB, rs, 0, &success); + if (!success) + return false; + + int32_t ids = llvm::SignExtend32<16>(ds << 2); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + LLDB_LOG(log, "EmulateSTD: {0:X+8}: std{1} r{2}, {3}(r{4})", m_addr, + u ? "u" : "", rs, ids, ra); + + // Make sure that r0 is really holding LR value (this won't catch unlikely + // cases, such as r0 being overwritten after mfspr) + uint32_t rs_num = rs; + if (rs == gpr_r0_ppc64le) { + uint64_t lr = + ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); + if (!success || lr != rs_val) + return false; + rs_num = gpr_lr_ppc64le; + } + + // set context + RegisterInfo rs_info; + if (!GetRegisterInfo(eRegisterKindLLDB, rs_num, rs_info)) + return false; + RegisterInfo ra_info; + if (!GetRegisterInfo(eRegisterKindLLDB, ra, ra_info)) + return false; + + Context ctx; + ctx.type = eContextPushRegisterOnStack; + ctx.SetRegisterToRegisterPlusOffset(rs_info, ra_info, ids); + + // store + uint64_t ra_val = ReadRegisterUnsigned(eRegisterKindLLDB, ra, 0, &success); + if (!success) + return false; + + lldb::addr_t addr = ra_val + ids; + WriteMemory(ctx, addr, &rs_val, sizeof(rs_val)); + + // update RA? + if (u) { + Context ctx; + // NOTE Currently, RA will always be equal to SP(r1) + ctx.type = eContextAdjustStackPointer; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, ra, addr); + } + + LLDB_LOG(log, "EmulateSTD: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateOR(uint32_t opcode) { + uint32_t rs = Bits32(opcode, 25, 21); + uint32_t ra = Bits32(opcode, 20, 16); + uint32_t rb = Bits32(opcode, 15, 11); + + // to be safe, process only the known 'mr r31/r30, r1' prologue instructions + if (m_fp != LLDB_INVALID_REGNUM || rs != rb || + (ra != gpr_r30_ppc64le && ra != gpr_r31_ppc64le) || rb != gpr_r1_ppc64le) + return false; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + LLDB_LOG(log, "EmulateOR: {0:X+8}: mr r{1}, r{2}", m_addr, ra, rb); + + // set context + RegisterInfo ra_info; + if (!GetRegisterInfo(eRegisterKindLLDB, ra, ra_info)) + return false; + + Context ctx; + ctx.type = eContextSetFramePointer; + ctx.SetRegister(ra_info); + + // move + bool success; + uint64_t rb_val = ReadRegisterUnsigned(eRegisterKindLLDB, rb, 0, &success); + if (!success) + return false; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, ra, rb_val); + m_fp = ra; + LLDB_LOG(log, "EmulateOR: success!"); + return true; +} + +bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) { + uint32_t rt = Bits32(opcode, 25, 21); + uint32_t ra = Bits32(opcode, 20, 16); + uint32_t si = Bits32(opcode, 15, 0); + + // handle stack adjustments only + // (this is a typical epilogue operation, with ra == r1. If it's + // something else, then we won't know the correct value of ra) + if (rt != gpr_r1_ppc64le || ra != gpr_r1_ppc64le) + return false; + + int32_t si_val = llvm::SignExtend32<16>(si); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + LLDB_LOG(log, "EmulateADDI: {0:X+8}: addi r1, r1, {1}", m_addr, si_val); + + // set context + RegisterInfo r1_info; + if (!GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le, r1_info)) + return false; + + Context ctx; + ctx.type = eContextRestoreStackPointer; + ctx.SetRegisterToRegisterPlusOffset(r1_info, r1_info, 0); + + // adjust SP + bool success; + uint64_t r1 = + ReadRegisterUnsigned(eRegisterKindLLDB, gpr_r1_ppc64le, 0, &success); + if (!success) + return false; + WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val); + LLDB_LOG(log, "EmulateADDI: success!"); + return true; +} diff --git a/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h new file mode 100644 index 000000000000..be65de9a5063 --- /dev/null +++ b/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h @@ -0,0 +1,97 @@ +//===-- EmulateInstructionPPC64.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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" + +namespace lldb_private { + +class EmulateInstructionPPC64 : public EmulateInstruction { +public: + EmulateInstructionPPC64(const ArchSpec &arch); + + static void Initialize(); + + static void Terminate(); + + static ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + static EmulateInstruction *CreateInstance(const ArchSpec &arch, + InstructionType inst_type); + + static bool + SupportsEmulatingInstructionsOfTypeStatic(InstructionType inst_type) { + switch (inst_type) { + case eInstructionTypeAny: + case eInstructionTypePrologueEpilogue: + return true; + + case eInstructionTypePCModifying: + case eInstructionTypeAll: + return false; + } + return false; + } + + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override { return 1; } + + bool SetTargetTriple(const ArchSpec &arch) override; + + bool SupportsEmulatingInstructionsOfType(InstructionType inst_type) override { + return SupportsEmulatingInstructionsOfTypeStatic(inst_type); + } + + bool ReadInstruction() override; + + bool EvaluateInstruction(uint32_t evaluate_options) override; + + bool TestEmulation(Stream *out_stream, ArchSpec &arch, + OptionValueDictionary *test_data) override { + return false; + } + + bool GetRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num, + RegisterInfo ®_info) override; + + bool CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) override; + +private: + struct Opcode { + uint32_t mask; + uint32_t value; + bool (EmulateInstructionPPC64::*callback)(uint32_t opcode); + const char *name; + }; + + uint32_t m_fp = LLDB_INVALID_REGNUM; + + Opcode *GetOpcodeForInstruction(uint32_t opcode); + + bool EmulateMFSPR(uint32_t opcode); + bool EmulateLD(uint32_t opcode); + bool EmulateSTD(uint32_t opcode); + bool EmulateOR(uint32_t opcode); + bool EmulateADDI(uint32_t opcode); +}; + +} // namespace lldb_private + +#endif // EmulateInstructionPPC64_h_ diff --git a/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp b/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp index eb238419ab18..32da327ee465 100644 --- a/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp +++ b/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp @@ -267,8 +267,8 @@ MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo( new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid); ThreadSP new_thread_sp(history_thread); - // Save this in the Process' ExtendedThreadList so a strong pointer - // retains the object + // Save this in the Process' ExtendedThreadList so a strong pointer retains + // the object process_sp->GetExtendedThreadList().AddThread(new_thread_sp); threads->AddThread(new_thread_sp); diff --git a/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp b/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp index cf9ba60c7b60..6ce50f5c6839 100644 --- a/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp +++ b/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp @@ -282,9 +282,8 @@ GetRenumberedThreadIds(ProcessSP process_sp, ValueObjectSP data, } else { // This isn't a live thread anymore. Ask process to assign a new // Index ID (or return an old one if we've already seen this - // thread_os_id). - // It will also make sure that no new threads are assigned this Index - // ID. + // thread_os_id). It will also make sure that no new threads are + // assigned this Index ID. lldb_user_id = process_sp->AssignIndexIDToThread(thread_os_id); } @@ -574,7 +573,7 @@ static void GetSymbolDeclarationFromAddress(ProcessSP process_sp, addr_t addr, return; VariableList var_list; - module->FindGlobalVariables(sym_name, nullptr, true, 1U, var_list); + module->FindGlobalVariables(sym_name, nullptr, 1U, var_list); if (var_list.GetSize() < 1) return; diff --git a/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp b/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp index 28c28e41ef44..1e9280c8c064 100644 --- a/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp +++ b/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp @@ -334,8 +334,8 @@ UndefinedBehaviorSanitizerRuntime::GetBacktracesFromExtendedStopInfo( std::string stop_reason_description = GetStopReasonDescription(info); new_thread_sp->SetName(stop_reason_description.c_str()); - // Save this in the Process' ExtendedThreadList so a strong pointer - // retains the object + // Save this in the Process' ExtendedThreadList so a strong pointer retains + // the object process_sp->GetExtendedThreadList().AddThread(new_thread_sp); threads->AddThread(new_thread_sp); diff --git a/source/Plugins/JITLoader/GDB/CMakeLists.txt b/source/Plugins/JITLoader/GDB/CMakeLists.txt index 25e8d1ee231f..190599cbd588 100644 --- a/source/Plugins/JITLoader/GDB/CMakeLists.txt +++ b/source/Plugins/JITLoader/GDB/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(.) - add_lldb_library(lldbPluginJITLoaderGDB PLUGIN JITLoaderGDB.cpp diff --git a/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/source/Plugins/Language/CPlusPlus/BlockPointer.cpp index 5e8f051dec98..82b7ac1675fa 100644 --- a/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -147,9 +147,8 @@ public: return child_sp; } - // return true if this object is now safe to use forever without - // ever updating again; the typical (and tested) answer here is - // 'false' + // return true if this object is now safe to use forever without ever + // updating again; the typical (and tested) answer here is 'false' bool Update() override { return false; } // maybe return false if the block pointer is, say, null diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 51ed88065c84..2c63e6467d4c 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -120,10 +120,9 @@ static bool ReverseFindMatchingChars(const llvm::StringRef &s, static bool IsTrivialBasename(const llvm::StringRef &basename) { // Check that the basename matches with the following regular expression - // "^~?([A-Za-z_][A-Za-z_0-9]*)$" - // We are using a hand written implementation because it is significantly more - // efficient then - // using the general purpose regular expression library. + // "^~?([A-Za-z_][A-Za-z_0-9]*)$" We are using a hand written implementation + // because it is significantly more efficient then using the general purpose + // regular expression library. size_t idx = 0; if (basename.size() > 0 && basename[0] == '~') idx = 1; @@ -151,10 +150,9 @@ static bool IsTrivialBasename(const llvm::StringRef &basename) { } bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() { - // This method tries to parse simple method definitions - // which are presumably most comman in user programs. - // Definitions that can be parsed by this function don't have return types - // and templates in the name. + // This method tries to parse simple method definitions which are presumably + // most comman in user programs. Definitions that can be parsed by this + // function don't have return types and templates in the name. // A::B::C::fun(std::vector<T> &) const size_t arg_start, arg_end; llvm::StringRef full(m_full.GetCString()); @@ -251,13 +249,17 @@ 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, but we can put that off till there is actually - // more than one - // we care about. - - return (name != nullptr && name[0] == '_' && name[1] == 'Z'); + // 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 + if (name[0] == '?') + return true; + + return (name[0] != '\0' && name[0] == '_' && name[1] == 'Z'); } bool CPlusPlusLanguage::ExtractContextAndIdentifier( @@ -307,13 +309,15 @@ static ConstString SubsPrimitiveParmItanium(llvm::StringRef mangled, // FastDemangle will call our hook for each instance of a primitive type, // allowing us to perform substitution - const char *const demangled = + char *const demangled = FastDemangle(mangled.str().c_str(), mangled.size(), swap_parms_hook); 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); return output_buf == mangled ? ConstString() : ConstString(output_buf); } @@ -419,18 +423,20 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { SyntheticChildren::Flags stl_synth_flags; stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences( false); + SyntheticChildren::Flags stl_deref_flags = stl_synth_flags; + stl_deref_flags.SetFrontEndWantsDereference(); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxBitsetSyntheticFrontEndCreator, "libc++ std::bitset synthetic children", - ConstString("^std::__(ndk)?1::bitset<.+>(( )?&)?$"), stl_synth_flags, + ConstString("^std::__(ndk)?1::bitset<.+>(( )?&)?$"), stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, "libc++ std::vector synthetic children", - ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_synth_flags, + ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, @@ -453,13 +459,13 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::set synthetic children", - ConstString("^std::__(ndk)?1::set<.+> >(( )?&)?$"), stl_synth_flags, + ConstString("^std::__(ndk)?1::set<.+> >(( )?&)?$"), stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multiset synthetic children", - ConstString("^std::__(ndk)?1::multiset<.+> >(( )?&)?$"), stl_synth_flags, + ConstString("^std::__(ndk)?1::multiset<.+> >(( )?&)?$"), stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp index aebea6ae3569..b32fe9588965 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -25,8 +25,8 @@ Optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() { m_next_token_index = 0; Optional<ParsedFunction> result(None); - // Try to parse the name as function without a return type specified - // e.g. main(int, char*[]) + // Try to parse the name as function without a return type specified e.g. + // main(int, char*[]) { Bookmark start_position = SetBookmark(); result = ParseFunctionImpl(false); @@ -34,8 +34,8 @@ Optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() { return result; } - // Try to parse the name as function with function pointer return type - // e.g. void (*get_func(const char*))() + // Try to parse the name as function with function pointer return type e.g. + // void (*get_func(const char*))() result = ParseFuncPtr(true); if (result) return result; @@ -183,13 +183,13 @@ bool CPlusPlusNameParser::ConsumeTemplateArgs() { Advance(); // Consuming template arguments is a bit trickier than consuming function - // arguments, because '<' '>' brackets are not always trivially balanced. - // In some rare cases tokens '<' and '>' can appear inside template arguments - // as arithmetic or shift operators not as template brackets. - // Examples: std::enable_if<(10u)<(64), bool> + // arguments, because '<' '>' brackets are not always trivially balanced. In + // some rare cases tokens '<' and '>' can appear inside template arguments as + // arithmetic or shift operators not as template brackets. Examples: + // std::enable_if<(10u)<(64), bool> // f<A<operator<(X,Y)::Subclass>> - // Good thing that compiler makes sure that really ambiguous cases of - // '>' usage should be enclosed within '()' brackets. + // Good thing that compiler makes sure that really ambiguous cases of '>' + // usage should be enclosed within '()' brackets. int template_counter = 1; bool can_open_template = false; while (HasMoreTokens() && template_counter > 0) { @@ -208,9 +208,9 @@ bool CPlusPlusNameParser::ConsumeTemplateArgs() { case tok::less: // '<' is an attempt to open a subteamplte // check if parser is at the point where it's actually possible, - // otherwise it's just a part of an expression like 'sizeof(T)<(10)'. - // No need to do the same for '>' because compiler actually makes sure - // that '>' always surrounded by brackets to avoid ambiguity. + // otherwise it's just a part of an expression like 'sizeof(T)<(10)'. No + // need to do the same for '>' because compiler actually makes sure that + // '>' always surrounded by brackets to avoid ambiguity. if (can_open_template) ++template_counter; can_open_template = false; @@ -242,8 +242,7 @@ bool CPlusPlusNameParser::ConsumeTemplateArgs() { } } - assert(template_counter >= 0); - if (template_counter > 0) { + if (template_counter != 0) { return false; } start_position.Remove(); @@ -389,10 +388,9 @@ void CPlusPlusNameParser::SkipFunctionQualifiers() { bool CPlusPlusNameParser::ConsumeBuiltinType() { bool result = false; bool continue_parsing = true; - // Built-in types can be made of a few keywords - // like 'unsigned long long int'. This function - // consumes all built-in type keywords without - // checking if they make sense like 'unsigned char void'. + // Built-in types can be made of a few keywords like 'unsigned long long + // int'. This function consumes all built-in type keywords without checking + // if they make sense like 'unsigned char void'. while (continue_parsing && HasMoreTokens()) { switch (Peek().getKind()) { case tok::kw_short: diff --git a/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/source/Plugins/Language/CPlusPlus/LibCxx.cpp index f6d1f18cb596..95e02a473cd7 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -123,12 +123,11 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { 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 that would in turn leak memory by never allowing the ValueObjects to - // die and free their memory + // 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 + // that would in turn leak memory by never allowing the ValueObjects to die + // and free their memory m_pair_ptr = valobj_sp ->GetValueForExpressionPath( ".__i_.__ptr_->__value_", nullptr, nullptr, @@ -386,7 +385,8 @@ enum LibcxxStringLayoutMode { }; // this function abstracts away the layout and mode details of a libc++ string -// and returns the address of the data and the size ready for callers to consume +// and returns the address of the data and the size ready for callers to +// consume static bool ExtractLibcxxStringInfo(ValueObject &valobj, ValueObjectSP &location_sp, uint64_t &size) { diff --git a/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 6407ae129ad7..6066f14b18cc 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -206,8 +206,7 @@ bool AbstractListFrontEnd::HasLoop(size_t count) { if (m_loop_detected == 0) { // This is the first time we are being run (after the last update). Set up - // the loop - // invariant for the first element. + // the loop invariant for the first element. m_slow_runner = ListEntry(m_head).next(); m_fast_runner = m_slow_runner.next(); m_loop_detected = 1; @@ -215,9 +214,8 @@ bool AbstractListFrontEnd::HasLoop(size_t count) { // Loop invariant: // Loop detection has been run over the first m_loop_detected elements. If - // m_slow_runner == - // m_fast_runner then the loop has been detected after m_loop_detected - // elements. + // m_slow_runner == m_fast_runner then the loop has been detected after + // m_loop_detected elements. const size_t steps_to_run = std::min(count, m_count); while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner && m_slow_runner != m_fast_runner) { diff --git a/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index be96a6d95bcd..8f82bdcbfd59 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -382,8 +382,8 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex( return lldb::ValueObjectSP(); } } else { - // because of the way our debug info is made, we need to read item 0 first - // so that we can cache information used to generate other elements + // because of the way our debug info is made, we need to read item 0 + // first so that we can cache information used to generate other elements if (m_skip_size == UINT32_MAX) GetChildAtIndex(0); if (m_skip_size == UINT32_MAX) { diff --git a/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp b/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp index b6d664df16ef..9d46e3e3ee58 100644 --- a/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp +++ b/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp @@ -43,6 +43,8 @@ private: ValueObjectSP m_ptr_obj; ValueObjectSP m_obj_obj; ValueObjectSP m_del_obj; + + ValueObjectSP GetTuple(); }; } // end of anonymous namespace @@ -53,17 +55,36 @@ LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd( Update(); } -bool LibStdcppUniquePtrSyntheticFrontEnd::Update() { +ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetTuple() { ValueObjectSP valobj_backend_sp = m_backend.GetSP(); + if (!valobj_backend_sp) - return false; + return nullptr; ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue(); if (!valobj_sp) - return false; + return nullptr; - ValueObjectSP tuple_sp = + ValueObjectSP obj_child_sp = valobj_sp->GetChildMemberWithName(ConstString("_M_t"), true); + if (!obj_child_sp) + return nullptr; + + ValueObjectSP obj_subchild_sp = + obj_child_sp->GetChildMemberWithName(ConstString("_M_t"), true); + + // if there is a _M_t subchild, the tuple is found in the obj_subchild_sp + // (for libstdc++ 6.0.23). + if (obj_subchild_sp) { + return obj_subchild_sp; + } + + return obj_child_sp; +} + +bool LibStdcppUniquePtrSyntheticFrontEnd::Update() { + ValueObjectSP tuple_sp = GetTuple(); + if (!tuple_sp) return false; diff --git a/source/Plugins/Language/ObjC/Cocoa.cpp b/source/Plugins/Language/ObjC/Cocoa.cpp index 8f4997533212..8f278fc2d513 100644 --- a/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/source/Plugins/Language/ObjC/Cocoa.cpp @@ -67,12 +67,12 @@ bool lldb_private::formatters::NSBundleSummaryProvider( if (!valobj_addr) return false; - const char *class_name = descriptor->GetClassName().GetCString(); + llvm::StringRef class_name(descriptor->GetClassName().GetCString()); - if (!class_name || !*class_name) + if (class_name.empty()) return false; - if (!strcmp(class_name, "NSBundle")) { + if (class_name == "NSBundle") { uint64_t offset = 5 * ptr_size; ValueObjectSP text(valobj.GetSyntheticChildAtOffset( offset, @@ -117,12 +117,12 @@ bool lldb_private::formatters::NSTimeZoneSummaryProvider( if (!valobj_addr) return false; - const char *class_name = descriptor->GetClassName().GetCString(); + llvm::StringRef class_name(descriptor->GetClassName().GetCString()); - if (!class_name || !*class_name) + if (class_name.empty()) return false; - if (!strcmp(class_name, "__NSTimeZone")) { + if (class_name == "__NSTimeZone") { uint64_t offset = ptr_size; ValueObjectSP text(valobj.GetSyntheticChildAtOffset( offset, valobj.GetCompilerType(), true)); @@ -164,12 +164,12 @@ bool lldb_private::formatters::NSNotificationSummaryProvider( if (!valobj_addr) return false; - const char *class_name = descriptor->GetClassName().GetCString(); + llvm::StringRef class_name(descriptor->GetClassName().GetCString()); - if (!class_name || !*class_name) + if (class_name.empty()) return false; - if (!strcmp(class_name, "NSConcreteNotification")) { + if (class_name == "NSConcreteNotification") { uint64_t offset = ptr_size; ValueObjectSP text(valobj.GetSyntheticChildAtOffset( offset, valobj.GetCompilerType(), true)); @@ -211,14 +211,14 @@ bool lldb_private::formatters::NSMachPortSummaryProvider( if (!valobj_addr) return false; - const char *class_name = descriptor->GetClassName().GetCString(); + llvm::StringRef class_name(descriptor->GetClassName().GetCString()); - if (!class_name || !*class_name) + if (class_name.empty()) return false; uint64_t port_number = 0; - if (!strcmp(class_name, "NSMachPort")) { + if (class_name == "NSMachPort") { uint64_t offset = (ptr_size == 4 ? 12 : 20); Status error; port_number = process_sp->ReadUnsignedIntegerFromMemory( @@ -259,16 +259,15 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider( if (!valobj_addr) return false; - const char *class_name = descriptor->GetClassName().GetCString(); + llvm::StringRef class_name(descriptor->GetClassName().GetCString()); - if (!class_name || !*class_name) + if (class_name.empty()) return false; uint64_t count = 0; do { - if (!strcmp(class_name, "NSIndexSet") || - !strcmp(class_name, "NSMutableIndexSet")) { + if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") { Status error; uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory( valobj_addr + ptr_size, 4, 0, error); @@ -451,15 +450,18 @@ bool lldb_private::formatters::NSNumberSummaryProvider( if (!valobj_addr) return false; - const char *class_name = descriptor->GetClassName().GetCString(); + llvm::StringRef class_name(descriptor->GetClassName().GetCString()); - if (!class_name || !*class_name) + if (class_name.empty()) return false; - if (!strcmp(class_name, "__NSCFBoolean")) + if (class_name == "__NSCFBoolean") return ObjCBooleanSummaryProvider(valobj, stream, options); - if (!strcmp(class_name, "NSNumber") || !strcmp(class_name, "__NSCFNumber")) { + if (class_name == "NSDecimalNumber") + return NSDecimalNumberSummaryProvider(valobj, stream, options); + + if (class_name == "NSNumber" || class_name == "__NSCFNumber") { uint64_t value = 0; uint64_t i_bits = 0; if (descriptor->GetTaggedPointerInfo(&i_bits, &value)) { @@ -626,6 +628,55 @@ bool lldb_private::formatters::NSNumberSummaryProvider( return false; } +bool lldb_private::formatters::NSDecimalNumberSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ProcessSP process_sp = valobj.GetProcessSP(); + if (!process_sp) + return false; + + lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); + uint32_t ptr_size = process_sp->GetAddressByteSize(); + + Status error; + int8_t exponent = process_sp->ReadUnsignedIntegerFromMemory( + valobj_addr + ptr_size, 1, 0, error); + if (error.Fail()) + return false; + + uint8_t length_and_negative = process_sp->ReadUnsignedIntegerFromMemory( + valobj_addr + ptr_size + 1, 1, 0, error); + if (error.Fail()) + return false; + + // Fifth bit marks negativity. + const bool is_negative = (length_and_negative >> 4) & 1; + + // Zero length and negative means NaN. + uint8_t length = length_and_negative & 0xf; + const bool is_nan = is_negative && (length == 0); + + if (is_nan) { + stream.Printf("NaN"); + return true; + } + + if (length == 0) { + stream.Printf("0"); + return true; + } + + uint64_t mantissa = process_sp->ReadUnsignedIntegerFromMemory( + valobj_addr + ptr_size + 4, 8, 0, error); + if (error.Fail()) + return false; + + if (is_negative) + stream.Printf("-"); + + stream.Printf("%" PRIu64 " x 10^%" PRIi8, mantissa, exponent); + return true; +} + bool lldb_private::formatters::NSURLSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { ProcessSP process_sp = valobj.GetProcessSP(); @@ -766,9 +817,9 @@ bool lldb_private::formatters::NSDateSummaryProvider( stream.Printf("0001-12-30 00:00:00 +0000"); return true; } - // 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 + // 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 time_t epoch = GetOSXEpoch(); epoch = epoch + (time_t)date_value; tm *tm_date = gmtime(&epoch); @@ -871,28 +922,34 @@ bool lldb_private::formatters::NSDataSummaryProvider( uint64_t value = 0; - const char *class_name = descriptor->GetClassName().GetCString(); + llvm::StringRef class_name = descriptor->GetClassName().GetCString(); - if (!class_name || !*class_name) + if (class_name.empty()) return false; - if (!strcmp(class_name, "NSConcreteData") || - !strcmp(class_name, "NSConcreteMutableData") || - !strcmp(class_name, "__NSCFData")) { - uint32_t offset = (is_64bit ? 16 : 8); + bool isNSConcreteData = class_name == "NSConcreteData"; + bool isNSConcreteMutableData = class_name == "NSConcreteMutableData"; + bool isNSCFData = class_name == "__NSCFData"; + if (isNSConcreteData || isNSConcreteMutableData || isNSCFData) { + uint32_t offset; + if (isNSConcreteData) + offset = is_64bit ? 8 : 4; + else + offset = is_64bit ? 16 : 8; + Status error; value = process_sp->ReadUnsignedIntegerFromMemory( valobj_addr + offset, is_64bit ? 8 : 4, 0, error); if (error.Fail()) return false; - } else if (!strcmp(class_name, "_NSInlineData")) { + } else if (class_name == "_NSInlineData") { uint32_t offset = (is_64bit ? 8 : 4); Status error; value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, 2, 0, error); if (error.Fail()) return false; - } else if (!strcmp(class_name, "_NSZeroData")) { + } else if (class_name == "_NSZeroData") { value = 0; } else return false; diff --git a/source/Plugins/Language/ObjC/Cocoa.h b/source/Plugins/Language/ObjC/Cocoa.h index 10ff3bce3b98..0f2ca5496302 100644 --- a/source/Plugins/Language/ObjC/Cocoa.h +++ b/source/Plugins/Language/ObjC/Cocoa.h @@ -32,6 +32,9 @@ bool NSDataSummaryProvider(ValueObject &valobj, Stream &stream, bool NSNumberSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); +bool NSDecimalNumberSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + bool NSNotificationSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); diff --git a/source/Plugins/Language/ObjC/NSDictionary.cpp b/source/Plugins/Language/ObjC/NSDictionary.cpp index c564aa1a8571..5be051b46bd6 100644 --- a/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -396,6 +396,8 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable"); static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); + static const ConstString g_Dictionary0("__NSDictionary0"); + static const ConstString g_DictionaryCF("__NSCFDictionary"); if (class_name.IsEmpty()) return false; @@ -407,7 +409,8 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( if (error.Fail()) return false; value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); - } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) { + } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy || + class_name == g_DictionaryCF) { AppleObjCRuntime *apple_runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); Status error; @@ -423,17 +426,9 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( return false; } else if (class_name == g_Dictionary1) { value = 1; + } else if (class_name == g_Dictionary0) { + value = 0; } - /*else if (!strcmp(class_name,"__NSCFDictionary")) - { - Status error; - value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? - 20 : 12), 4, 0, error); - if (error.Fail()) - return false; - if (is_64bit) - value &= ~0x0f1f000000000000UL; - }*/ else { auto &map(NSDictionary_Additionals::GetAdditionalSummaries()); for (auto &candidate : map) { @@ -491,6 +486,7 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable"); static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); + static const ConstString g_Dictionary0("__NSDictionary0"); if (class_name.IsEmpty()) return nullptr; @@ -673,11 +669,7 @@ lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: GetIndexOfChildWithName(const ConstString &name) { static const ConstString g_zero("[0]"); - - if (name == g_zero) - return 0; - - return UINT32_MAX; + return name == g_zero ? 0 : UINT32_MAX; } size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: diff --git a/source/Plugins/Language/ObjC/NSError.cpp b/source/Plugins/Language/ObjC/NSError.cpp index 4365a12b54e1..77721e2db326 100644 --- a/source/Plugins/Language/ObjC/NSError.cpp +++ b/source/Plugins/Language/ObjC/NSError.cpp @@ -177,12 +177,11 @@ public: 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! + // 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; }; diff --git a/source/Plugins/Language/ObjC/NSException.cpp b/source/Plugins/Language/ObjC/NSException.cpp index 1da4f6de19a0..c6970efae4d3 100644 --- a/source/Plugins/Language/ObjC/NSException.cpp +++ b/source/Plugins/Language/ObjC/NSException.cpp @@ -171,12 +171,11 @@ public: 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! + // 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; }; diff --git a/source/Plugins/Language/ObjC/NSSet.cpp b/source/Plugins/Language/ObjC/NSSet.cpp index fa2483ecc094..2da4bc034f32 100644 --- a/source/Plugins/Language/ObjC/NSSet.cpp +++ b/source/Plugins/Language/ObjC/NSSet.cpp @@ -269,7 +269,8 @@ bool lldb_private::formatters::NSSetSummaryProvider( if (!class_name || !*class_name) return false; - if (!strcmp(class_name, "__NSSetI")) { + if (!strcmp(class_name, "__NSSetI") || + !strcmp(class_name, "__NSOrderedSetI")) { Status error; value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); @@ -289,32 +290,7 @@ bool lldb_private::formatters::NSSetSummaryProvider( } if (error.Fail()) return false; - } - /*else if (!strcmp(class_name,"__NSCFSet")) - { - Status error; - value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? - 20 : 12), 4, 0, error); - if (error.Fail()) - return false; - if (is_64bit) - value &= ~0x1fff000000000000UL; - } - else if (!strcmp(class_name,"NSCountedSet")) - { - Status error; - value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, - ptr_size, 0, error); - if (error.Fail()) - return false; - value = process_sp->ReadUnsignedIntegerFromMemory(value + (is_64bit ? 20 : - 12), 4, 0, error); - if (error.Fail()) - return false; - if (is_64bit) - value &= ~0x1fff000000000000UL; - }*/ - else { + } else { auto &map(NSSet_Additionals::GetAdditionalSummaries()); auto iter = map.find(class_name_cs), end = map.end(); if (iter != end) @@ -371,7 +347,8 @@ lldb_private::formatters::NSSetSyntheticFrontEndCreator( if (!class_name || !*class_name) return nullptr; - if (!strcmp(class_name, "__NSSetI")) { + if (!strcmp(class_name, "__NSSetI") || + !strcmp(class_name, "__NSOrderedSetI")) { return (new NSSetISyntheticFrontEnd(valobj_sp)); } else if (!strcmp(class_name, "__NSSetM")) { AppleObjCRuntime *apple_runtime = diff --git a/source/Plugins/Language/ObjC/NSString.cpp b/source/Plugins/Language/ObjC/NSString.cpp index 3b4edf68e063..0b12edb53d7a 100644 --- a/source/Plugins/Language/ObjC/NSString.cpp +++ b/source/Plugins/Language/ObjC/NSString.cpp @@ -256,8 +256,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( uint64_t location = valobj_addr + 2 * ptr_size; if (!has_explicit_length) { // in this kind of string, the byte before the string content is a length - // byte - // so let's try and use it to handle the embedded NUL case + // byte so let's try and use it to handle the embedded NUL case Status error; explicit_length = process_sp->ReadUnsignedIntegerFromMemory(location, 1, 0, error); @@ -368,9 +367,7 @@ bool lldb_private::formatters::NSTaggedString_SummaryProvider( } // this is a fairly ugly trick - pretend that the numeric value is actually a - // char* - // this works under a few assumptions: - // little endian architecture + // char* this works under a few assumptions: little endian architecture // sizeof(uint64_t) > g_MaxNonBitmaskedLen if (len_bits <= g_MaxNonBitmaskedLen) { stream.Printf("%s", prefix.c_str()); diff --git a/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/source/Plugins/Language/ObjC/ObjCLanguage.cpp index ea2eec7b33b7..47874b3be8fd 100644 --- a/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -90,9 +90,8 @@ bool ObjCLanguage::MethodName::SetName(llvm::StringRef name, bool strict) { if (name.empty()) return IsValid(strict); - // If "strict" is true. then the method must be specified with a - // '+' or '-' at the beginning. If "strict" is false, then the '+' - // or '-' can be omitted + // If "strict" is true. then the method must be specified with a '+' or '-' + // at the beginning. If "strict" is false, then the '+' or '-' can be omitted bool valid_prefix = false; if (name.size() > 1 && (name[0] == '+' || name[0] == '-')) { @@ -108,7 +107,7 @@ bool ObjCLanguage::MethodName::SetName(llvm::StringRef name, bool strict) { if (valid_prefix) { int name_len = name.size(); - // Objective C methods must have at least: + // Objective-C methods must have at least: // "-[" or "+[" prefix // One character for a class name // One character for the space between the class name @@ -134,8 +133,8 @@ const ConstString &ObjCLanguage::MethodName::GetClassName() { if (paren_pos) { m_class.SetCStringWithLength(class_start, paren_pos - class_start); } else { - // No '(' was found in the full name, we can definitively say - // that our category was valid (and empty). + // No '(' was found in the full name, we can definitively say that our + // category was valid (and empty). m_category_is_valid = true; const char *space_pos = strchr(full, ' '); if (space_pos) { @@ -164,8 +163,8 @@ const ConstString &ObjCLanguage::MethodName::GetClassNameWithCategory() { // contain a '(', then we can also fill in the m_class if (!m_class && strchr(m_class_category.GetCString(), '(') == nullptr) { m_class = m_class_category; - // No '(' was found in the full name, we can definitively say - // that our category was valid (and empty). + // No '(' was found in the full name, we can definitively say that + // our category was valid (and empty). m_category_is_valid = true; } } @@ -764,6 +763,10 @@ static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { AddCXXSummary( objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", ConstString("NSCFNumber"), appkit_flags); + AddCXXSummary(objc_category_sp, + lldb_private::formatters::NSNumberSummaryProvider, + "NSDecimalNumber summary provider", + ConstString("NSDecimalNumber"), appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSURLSummaryProvider, @@ -796,8 +799,8 @@ static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { objc_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", ConstString("__NSTimeZone"), appkit_flags); - // CFAbsoluteTime is actually a double rather than a pointer to an object - // we do not care about the numeric value, since it is probably meaningless to + // CFAbsoluteTime is actually a double rather than a pointer to an object we + // do not care about the numeric value, since it is probably meaningless to // users appkit_flags.SetDontShowValue(true); AddCXXSummary(objc_category_sp, diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index e5a459dfe861..fc661bbbf2c9 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -83,26 +83,30 @@ TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( // We are a C++ class, that's good. Get the class name and look it // up: const char *class_name = name + strlen(vtable_demangled_prefix); + // We know the class name is absolute, so tell FindTypes that by + // prefixing it with the root namespace: + std::string lookup_name("::"); + lookup_name.append(class_name); + type_info.SetName(class_name); const bool exact_match = true; TypeList class_types; uint32_t num_matches = 0; - // First look in the module that the vtable symbol came from - // and look for a single exact match. + // First look in the module that the vtable symbol came from and + // look for a single exact match. llvm::DenseSet<SymbolFile *> searched_symbol_files; if (sc.module_sp) { num_matches = sc.module_sp->FindTypes( - sc, ConstString(class_name), exact_match, 1, + sc, ConstString(lookup_name), exact_match, 1, searched_symbol_files, class_types); } - // If we didn't find a symbol, then move on to the entire - // module list in the target and get as many unique matches - // as possible + // If we didn't find a symbol, then move on to the entire module + // list in the target and get as many unique matches as possible if (num_matches == 0) { num_matches = target.GetImages().FindTypes( - sc, ConstString(class_name), exact_match, UINT32_MAX, + sc, ConstString(lookup_name), exact_match, UINT32_MAX, searched_symbol_files, class_types); } @@ -187,15 +191,12 @@ bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( TypeAndOrName &class_type_or_name, Address &dynamic_address, Value::ValueType &value_type) { // For Itanium, if the type has a vtable pointer in the object, it will be at - // offset 0 - // in the object. That will point to the "address point" within the vtable - // (not the beginning of the - // vtable.) We can then look up the symbol containing this "address point" - // and that symbol's name - // demangled will contain the full class name. - // The second pointer above the "address point" is the "offset_to_top". We'll - // use that to get the - // start of the value object which holds the dynamic type. + // offset 0 in the object. That will point to the "address point" within the + // vtable (not the beginning of the vtable.) We can then look up the symbol + // containing this "address point" and that symbol's name demangled will + // contain the full class name. The second pointer above the "address point" + // is the "offset_to_top". We'll use that to get the start of the value + // object which holds the dynamic type. // class_type_or_name.Clear(); @@ -230,17 +231,15 @@ bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( 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. + // 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... + // The dynamic type we found was the same type, so we don't have a + // dynamic type here... return false; } @@ -257,8 +256,8 @@ bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( 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. + // 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)) { @@ -280,10 +279,9 @@ TypeAndOrName ItaniumABILanguageRuntime::FixUpDynamicType( TypeAndOrName ret(type_and_or_name); if (type_and_or_name.HasType()) { // The type will always be the type of the dynamic object. If our parent's - // type was a pointer, - // then our type should be a pointer to the type of the dynamic object. If - // a reference, then the original type - // should be okay... + // type was a pointer, then our type should be a pointer to the type of the + // dynamic object. If a reference, then the original type should be + // okay... CompilerType orig_type = type_and_or_name.GetCompilerType(); CompilerType corrected_type = orig_type; if (static_type_flags.AllSet(eTypeIsPointer)) @@ -368,8 +366,8 @@ protected: // the actual Mangled class should be strict about this, but on the // command line if you're copying mangled names out of 'nm' on Darwin, - // they will come out with an extra underscore - be willing to strip - // this on behalf of the user. This is the moral equivalent of the -_/-n + // they will come out with an extra underscore - be willing to strip this + // on behalf of the user. This is the moral equivalent of the -_/-n // options to c++filt auto name = entry.ref; if (name.startswith("__Z")) @@ -448,13 +446,12 @@ BreakpointResolverSP ItaniumABILanguageRuntime::CreateExceptionResolver( BreakpointResolverSP ItaniumABILanguageRuntime::CreateExceptionResolver( Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions) { // One complication here is that most users DON'T want to stop at - // __cxa_allocate_expression, but until we can do - // anything better with predicting unwinding the expression parser does. So - // we have two forms of the exception - // breakpoints, one for expressions that leaves out __cxa_allocate_exception, - // and one that includes it. - // The SetExceptionBreakpoints does the latter, the CreateExceptionBreakpoint - // in the runtime the former. + // __cxa_allocate_expression, but until we can do anything better with + // predicting unwinding the expression parser does. So we have two forms of + // the exception breakpoints, one for expressions that leaves out + // __cxa_allocate_exception, and one that includes it. The + // SetExceptionBreakpoints does the latter, the CreateExceptionBreakpoint in + // the runtime the former. static const char *g_catch_name = "__cxa_begin_catch"; static const char *g_throw_name1 = "__cxa_throw"; static const char *g_throw_name2 = "__cxa_rethrow"; @@ -517,8 +514,7 @@ void ItaniumABILanguageRuntime::SetExceptionBreakpoints() { const bool for_expressions = true; // For the exception breakpoints set by the Expression parser, we'll be a - // little more aggressive and - // stop at exception allocation as well. + // little more aggressive and stop at exception allocation as well. if (m_cxx_exception_bp_sp) { m_cxx_exception_bp_sp->SetEnabled(true); diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp index ecb0b64f2346..edb29e735ca9 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp @@ -378,8 +378,7 @@ bool ClassDescriptorV2::Describe( AppleObjCRuntime::ClassDescriptorSP metaclass(GetMetaclass()); // We don't care about the metaclass's superclass, or its class methods. - // Its instance methods are - // our class methods. + // Its instance methods are our class methods. if (metaclass) { metaclass->Describe( diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index eacc98a07193..fef42c78b24f 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -54,23 +54,20 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &str, ValueObject &valobj) { CompilerType compiler_type(valobj.GetCompilerType()); bool is_signed; // ObjC objects can only be pointers (or numbers that actually represents - // pointers - // but haven't been typecast, because reasons..) + // pointers but haven't been typecast, because reasons..) if (!compiler_type.IsIntegerType(is_signed) && !compiler_type.IsPointerType()) return false; - // Make the argument list: we pass one arg, the address of our pointer, to the - // print function. + // Make the argument list: we pass one arg, the address of our pointer, to + // the print function. Value val; if (!valobj.ResolveValue(val.GetScalar())) return false; // Value Objects may not have a process in their ExecutionContextRef. But we - // need to have one - // in the ref we pass down to eventually call description. Get it from the - // target if it isn't - // present. + // need to have one in the ref we pass down to eventually call description. + // Get it from the target if it isn't present. ExecutionContext exe_ctx; if (valobj.GetProcessSP()) { exe_ctx = ExecutionContext(valobj.GetExecutionContextRef()); @@ -257,10 +254,9 @@ AppleObjCRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, TypeAndOrName ret(type_and_or_name); if (type_and_or_name.HasType()) { // The type will always be the type of the dynamic object. If our parent's - // type was a pointer, - // then our type should be a pointer to the type of the dynamic object. If - // a reference, then the original type - // should be okay... + // type was a pointer, then our type should be a pointer to the type of the + // dynamic object. If a reference, then the original type should be + // okay... CompilerType orig_type = type_and_or_name.GetCompilerType(); CompilerType corrected_type = orig_type; if (static_type_flags.AllSet(eTypeIsPointer)) @@ -297,16 +293,14 @@ bool AppleObjCRuntime::AppleIsModuleObjCLibrary(const ModuleSP &module_sp) { uint32_t AppleObjCRuntime::GetFoundationVersion() { if (!m_Foundation_major.hasValue()) { const ModuleList &modules = m_process->GetTarget().GetImages(); - uint32_t major = UINT32_MAX; for (uint32_t idx = 0; idx < modules.GetSize(); idx++) { lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx); if (!module_sp) continue; if (strcmp(module_sp->GetFileSpec().GetFilename().AsCString(""), "Foundation") == 0) { - module_sp->GetVersion(&major, 1); - m_Foundation_major = major; - return major; + m_Foundation_major = module_sp->GetVersion().getMajor(); + return *m_Foundation_major; } } return LLDB_INVALID_MODULE_VERSION; @@ -325,8 +319,8 @@ bool AppleObjCRuntime::IsModuleObjCLibrary(const ModuleSP &module_sp) { bool AppleObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) { // Maybe check here and if we have a handler already, and the UUID of this - // module is the same as the one in the - // current module, then we don't have to reread it? + // module is the same as the one in the current module, then we don't have to + // reread it? m_objc_trampoline_handler_ap.reset( new AppleObjCTrampolineHandler(m_process->shared_from_this(), module_sp)); if (m_objc_trampoline_handler_ap.get() != NULL) { @@ -365,11 +359,9 @@ AppleObjCRuntime::GetObjCVersion(Process *process, ModuleSP &objc_module_sp) { for (size_t i = 0; i < num_images; i++) { ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i); // One tricky bit here is that we might get called as part of the initial - // module loading, but - // before all the pre-run libraries get winnowed from the module list. So - // there might actually - // be an old and incorrect ObjC library sitting around in the list, and we - // don't want to look at that. + // module loading, but before all the pre-run libraries get winnowed from + // the module list. So there might actually be an old and incorrect ObjC + // library sitting around in the list, and we don't want to look at that. // That's why we call IsLoadedInTarget. if (AppleIsModuleObjCLibrary(module_sp) && diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 9cac499c0ff0..5001c0461b3b 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -42,8 +42,7 @@ AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process) m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS) {} // for V1 runtime we just try to return a class name as that is the minimum -// level of support -// required for the data formatters to work +// level of support required for the data formatters to work bool AppleObjCRuntimeV1::GetDynamicTypeAndAddress( ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &address, @@ -85,7 +84,7 @@ AppleObjCRuntimeV1::CreateInstance(Process *process, void AppleObjCRuntimeV1::Initialize() { PluginManager::RegisterPlugin( - GetPluginNameStatic(), "Apple Objective C Language Runtime - Version 1", + GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 1", CreateInstance); } @@ -284,6 +283,10 @@ bool AppleObjCRuntimeV1::ClassDescriptorV1::Describe( return false; } +lldb::addr_t AppleObjCRuntimeV1::GetTaggedPointerObfuscator() { + return 0; +} + lldb::addr_t AppleObjCRuntimeV1::GetISAHashTablePointer() { if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) { ModuleSP objc_module_sp(GetObjCModule()); @@ -383,8 +386,8 @@ void AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() { ObjCISA isa; if (bucket_isa_count == 1) { - // When we only have one entry in the bucket, the bucket data is - // the "isa" + // When we only have one entry in the bucket, the bucket data + // is the "isa" isa = bucket_data; if (isa) { if (!ISAIsCached(isa)) { @@ -402,8 +405,7 @@ void AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() { } } else { // When we have more than one entry in the bucket, the bucket - // data is a pointer - // to an array of "isa" values + // data is a pointer to an array of "isa" values addr_t isa_addr = bucket_data; for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count; ++isa_idx, isa_addr += addr_size) { diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h index 3dddf1b094e1..52eec0f692fb 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h @@ -45,6 +45,8 @@ public: } } + lldb::addr_t GetTaggedPointerObfuscator(); + class ClassDescriptorV1 : public ObjCLanguageRuntime::ClassDescriptor { public: ClassDescriptorV1(ValueObject &isa_pointer); diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index bdf79f7b82bd..d217ed3ff325 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -37,6 +37,7 @@ #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionValueBoolean.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ObjectFile.h" @@ -76,8 +77,7 @@ static constexpr std::chrono::seconds g_utility_function_timeout(2); static const char *g_get_dynamic_class_info_name = "__lldb_apple_objc_v2_get_dynamic_class_info"; // Testing using the new C++11 raw string literals. If this breaks GCC then we -// will -// need to revert to the code above... +// will need to revert to the code above... static const char *g_get_dynamic_class_info_body = R"( extern "C" @@ -161,8 +161,7 @@ __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr static const char *g_get_shared_cache_class_info_name = "__lldb_apple_objc_v2_get_shared_cache_class_info"; // Testing using the new C++11 raw string literals. If this breaks GCC then we -// will -// need to revert to the code above... +// will need to revert to the code above... static const char *g_get_shared_cache_class_info_body = R"( extern "C" @@ -385,7 +384,9 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process, m_get_class_info_args_mutex(), m_get_shared_cache_class_info_code(), m_get_shared_cache_class_info_args(LLDB_INVALID_ADDRESS), m_get_shared_cache_class_info_args_mutex(), m_decl_vendor_ap(), - m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS), m_hash_signature(), + m_tagged_pointer_obfuscator(LLDB_INVALID_ADDRESS), + m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS), + m_hash_signature(), m_has_object_getClass(false), m_loaded_objc_opt(false), m_non_pointer_isa_cache_ap( NonPointerISACache::CreateInstance(*this, objc_module_sp)), @@ -406,10 +407,9 @@ bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress( assert(m_process != NULL); // The Runtime is attached to a particular process, you shouldn't pass in a - // value from another process. - // Note, however, the process might be NULL (e.g. if the value was made with - // SBTarget::EvaluateExpression...) - // in which case it is sufficient if the target's match: + // value from another process. Note, however, the process might be NULL (e.g. + // if the value was made with SBTarget::EvaluateExpression...) in which case + // it is sufficient if the target's match: Process *process = in_value.GetProcessSP().get(); if (process) @@ -422,8 +422,8 @@ bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress( // Make sure we can have a dynamic value before starting... if (CouldHaveDynamicValue(in_value)) { - // First job, pull out the address at 0 offset from the object That will be - // the ISA pointer. + // First job, pull out the address at 0 offset from the object That will + // be the ISA pointer. ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(in_value)); if (objc_class_sp) { const addr_t object_ptr = in_value.GetPointerValue(); @@ -682,7 +682,7 @@ protected: if (!arg_str) continue; Status error; - lldb::addr_t arg_addr = Args::StringToAddress( + lldb::addr_t arg_addr = OptionArgParser::ToAddress( &exe_ctx, arg_str, LLDB_INVALID_ADDRESS, &error); if (arg_addr == 0 || arg_addr == LLDB_INVALID_ADDRESS || error.Fail()) continue; @@ -771,7 +771,7 @@ public: void AppleObjCRuntimeV2::Initialize() { PluginManager::RegisterPlugin( - GetPluginNameStatic(), "Apple Objective C Language Runtime - Version 2", + GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 2", CreateInstance, [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP { return CommandObjectSP(new CommandObjectMultiwordObjC(interpreter)); @@ -870,8 +870,8 @@ size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type, const char *class_name = parent_ast_type.GetConstTypeName().AsCString(); if (class_name && class_name[0] && ivar_name && ivar_name[0]) { //---------------------------------------------------------------------- - // Make the objective C V2 mangled name for the ivar offset from the - // class name and ivar name + // Make the objective C V2 mangled name for the ivar offset from the class + // name and ivar name //---------------------------------------------------------------------- std::string buffer("OBJC_IVAR_$_"); buffer.append(class_name); @@ -880,8 +880,8 @@ size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type, ConstString ivar_const_str(buffer.c_str()); //---------------------------------------------------------------------- - // Try to get the ivar offset address from the symbol table first using - // the name we created above + // Try to get the ivar offset address from the symbol table first using the + // name we created above //---------------------------------------------------------------------- SymbolContextList sc_list; Target &target = m_process->GetTarget(); @@ -914,11 +914,9 @@ size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type, } // tagged pointers are special not-a-real-pointer values that contain both type -// and value information -// this routine attempts to check with as little computational effort as -// possible whether something -// could possibly be a tagged pointer - false positives are possible but false -// negatives shouldn't +// and value information this routine attempts to check with as little +// computational effort as possible whether something could possibly be a +// tagged pointer - false positives are possible but false negatives shouldn't bool AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) { if (!m_tagged_pointer_vendor_ap) return false; @@ -950,11 +948,11 @@ public: Status err; // This currently holds true for all platforms we support, but we might - // need to change this to use get the actually byte size of "unsigned" - // from the target AST... + // need to change this to use get the actually byte size of "unsigned" from + // the target AST... const uint32_t unsigned_byte_size = sizeof(uint32_t); - // Skip the prototype as we don't need it (const struct +NXMapTablePrototype - // *prototype) + // Skip the prototype as we don't need it (const struct + // +NXMapTablePrototype *prototype) bool success = true; if (load_addr == LLDB_INVALID_ADDRESS) @@ -988,8 +986,8 @@ public: return success; } - // const_iterator mimics NXMapState and its code comes from NXInitMapState and - // NXNextMapState. + // const_iterator mimics NXMapState and its code comes from NXInitMapState + // and NXNextMapState. typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element; friend class const_iterator; @@ -1132,8 +1130,8 @@ bool AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate( return false; // Failed to parse the header, no need to update anything } - // Check with out current signature and return true if the count, - // number of buckets or the hash table address changes. + // Check with out current signature and return true if the count, number of + // buckets or the hash table address changes. if (m_count == hash_table.GetCount() && m_num_buckets == hash_table.GetBucketCount() && m_buckets_ptr == hash_table.GetBucketDataPointer()) { @@ -1167,9 +1165,9 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { } return nullptr; } - // if we get an invalid VO (which might still happen when playing around - // with pointers returned by the expression parser, don't consider this - // a valid ObjC object) + // if we get an invalid VO (which might still happen when playing around with + // pointers returned by the expression parser, don't consider this a valid + // ObjC object) if (valobj.GetCompilerType().IsValid()) { addr_t isa_pointer = valobj.GetPointerValue(); @@ -1200,6 +1198,38 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { return objc_class_sp; } +lldb::addr_t AppleObjCRuntimeV2::GetTaggedPointerObfuscator() { + if (m_tagged_pointer_obfuscator != LLDB_INVALID_ADDRESS) + return m_tagged_pointer_obfuscator; + + + Process *process = GetProcess(); + ModuleSP objc_module_sp(GetObjCModule()); + + if (!objc_module_sp) + return LLDB_INVALID_ADDRESS; + + static ConstString g_gdb_objc_obfuscator("objc_debug_taggedpointer_obfuscator"); + + const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType( + g_gdb_objc_obfuscator, lldb::eSymbolTypeAny); + if (symbol) { + lldb::addr_t g_gdb_obj_obfuscator_ptr = + symbol->GetLoadAddress(&process->GetTarget()); + + if (g_gdb_obj_obfuscator_ptr != LLDB_INVALID_ADDRESS) { + Status error; + m_tagged_pointer_obfuscator = process->ReadPointerFromMemory( + g_gdb_obj_obfuscator_ptr, error); + } + } + // If we don't have a correct value at this point, there must be no obfuscation. + if (m_tagged_pointer_obfuscator == LLDB_INVALID_ADDRESS) + m_tagged_pointer_obfuscator = 0; + + return m_tagged_pointer_obfuscator; +} + lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() { if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) { Process *process = GetProcess(); @@ -1359,8 +1389,8 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; - // Only dump the runtime classes from the expression evaluation if the - // log is verbose: + // Only dump the runtime classes from the expression evaluation if the log is + // verbose: Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES); bool dump_log = type_log && type_log->GetVerbose(); @@ -1440,7 +1470,8 @@ uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data, // uint32_t hash; // } __attribute__((__packed__)); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES)); + bool should_log = log && log->GetVerbose(); uint32_t num_parsed = 0; @@ -1450,15 +1481,15 @@ uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data, ObjCISA isa = data.GetPointer(&offset); if (isa == 0) { - if (log) + if (should_log) log->Printf( "AppleObjCRuntimeV2 found NULL isa, ignoring this class info"); continue; } - // Check if we already know about this ISA, if we do, the info will - // never change, so we can just skip it. + // Check if we already know about this ISA, if we do, the info will never + // change, so we can just skip it. if (ISAIsCached(isa)) { - if (log) + if (should_log) log->Printf("AppleObjCRuntimeV2 found cached isa=0x%" PRIx64 ", ignoring this class info", isa); @@ -1469,14 +1500,14 @@ uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data, ClassDescriptorSP descriptor_sp(new ClassDescriptorV2(*this, isa, NULL)); AddClass(isa, descriptor_sp, name_hash); num_parsed++; - if (log) + if (should_log) log->Printf("AppleObjCRuntimeV2 added isa=0x%" PRIx64 ", hash=0x%8.8x, name=%s", isa, name_hash, descriptor_sp->GetClassName().AsCString("<unknown>")); } } - if (log) + if (should_log) log->Printf("AppleObjCRuntimeV2 parsed %" PRIu32 " class infos", num_parsed); return num_parsed; @@ -1607,8 +1638,8 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr; arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; - // Only dump the runtime classes from the expression evaluation if the - // log is verbose: + // Only dump the runtime classes from the expression evaluation if the log is + // verbose: Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES); bool dump_log = type_log && type_log->GetVerbose(); @@ -1788,21 +1819,17 @@ void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() { DescriptorMapUpdateResult dynamic_update_result = UpdateISAToDescriptorMapDynamic(hash_table); - // Now get the objc classes that are baked into the Objective C runtime - // in the shared cache, but only once per process as this data never - // changes + // Now get the objc classes that are baked into the Objective-C runtime in + // the shared cache, but only once per process as this data never changes if (!m_loaded_objc_opt) { // it is legitimately possible for the shared cache to be empty - in that - // case, the dynamic hash table - // will contain all the class information we need; the situation we're - // trying to detect is one where - // we aren't seeing class information from the runtime - in order to - // detect that vs. just the shared cache - // being empty or sparsely populated, we set an arbitrary (very low) - // threshold for the number of classes - // that we want to see in a "good" scenario - anything below that is - // suspicious (Foundation alone has thousands - // of classes) + // case, the dynamic hash table will contain all the class information we + // need; the situation we're trying to detect is one where we aren't + // seeing class information from the runtime - in order to detect that + // vs. just the shared cache being empty or sparsely populated, we set an + // arbitrary (very low) threshold for the number of classes that we want + // to see in a "good" scenario - anything below that is suspicious + // (Foundation alone has thousands of classes) const uint32_t num_classes_to_warn_at = 500; DescriptorMapUpdateResult shared_cache_update_result = @@ -2089,8 +2116,8 @@ AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance( if (error.Fail()) return new TaggedPointerVendorLegacy(runtime); - // try to detect the "extended tagged pointer" variables - if any are missing, - // use the non-extended vendor + // try to detect the "extended tagged pointer" variables - if any are + // missing, use the non-extended vendor do { auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol( process, ConstString("objc_debug_taggedpointer_ext_mask"), @@ -2143,8 +2170,8 @@ AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance( objc_debug_taggedpointer_classes, objc_debug_taggedpointer_ext_classes); } while (false); - // we might want to have some rules to outlaw these values (e.g if the table's - // address is zero) + // we might want to have some rules to outlaw these values (e.g if the + // table's address is zero) return new TaggedPointerVendorRuntimeAssisted( runtime, objc_debug_taggedpointer_mask, @@ -2217,7 +2244,9 @@ AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor( return ObjCLanguageRuntime::ClassDescriptorSP(); } } - return ClassDescriptorSP(new ClassDescriptorV2Tagged(name, ptr)); + + lldb::addr_t unobfuscated = ptr ^ m_runtime.GetTaggedPointerObfuscator(); + return ClassDescriptorSP(new ClassDescriptorV2Tagged(name, unobfuscated)); } AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted:: @@ -2249,8 +2278,9 @@ AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor( lldb::addr_t ptr) { ClassDescriptorSP actual_class_descriptor_sp; uint64_t data_payload; + uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator(); - if (!IsPossibleTaggedPointer(ptr)) + if (!IsPossibleTaggedPointer(unobfuscated)) return ObjCLanguageRuntime::ClassDescriptorSP(); uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) & @@ -2276,7 +2306,7 @@ AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor( } data_payload = - (((uint64_t)ptr << m_objc_debug_taggedpointer_payload_lshift) >> + (((uint64_t)unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >> m_objc_debug_taggedpointer_payload_rshift); return ClassDescriptorSP( @@ -2333,11 +2363,12 @@ AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor( lldb::addr_t ptr) { ClassDescriptorSP actual_class_descriptor_sp; uint64_t data_payload; + uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator(); - if (!IsPossibleTaggedPointer(ptr)) + if (!IsPossibleTaggedPointer(unobfuscated)) return ObjCLanguageRuntime::ClassDescriptorSP(); - if (!IsPossibleExtendedTaggedPointer(ptr)) + if (!IsPossibleExtendedTaggedPointer(unobfuscated)) return this->TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(ptr); uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_ext_slot_shift) & @@ -2363,7 +2394,7 @@ AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor( } data_payload = - (((uint64_t)ptr << m_objc_debug_taggedpointer_ext_payload_lshift) >> + (((uint64_t)unobfuscated << m_objc_debug_taggedpointer_ext_payload_lshift) >> m_objc_debug_taggedpointer_ext_payload_rshift); return ClassDescriptorSP( @@ -2414,11 +2445,10 @@ bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( if ((isa & ~m_objc_debug_isa_class_mask) == 0) return false; - // 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 one of their values to 0 if they aren't needed. + // 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 + // 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 && m_objc_debug_indexed_isa_index_mask && @@ -2431,10 +2461,10 @@ bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( // Magic bits are correct, so try extract the index. uintptr_t index = (isa & m_objc_debug_indexed_isa_index_mask) >> m_objc_debug_indexed_isa_index_shift; - // If the index is out of bounds of the length of the array then - // check if the array has been updated. If that is the case then - // we should try read the count again, and update the cache if the - // count has been updated. + // If the index is out of bounds of the length of the array then check if + // the array has been updated. If that is the case then we should try + // read the count again, and update the cache if the count has been + // updated. if (index > m_indexed_isa_cache.size()) { if (log) log->Printf("AOCRT::NPI (index = %" PRIu64 @@ -2459,9 +2489,9 @@ bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( (uint64_t)objc_indexed_classes_count); if (objc_indexed_classes_count > m_indexed_isa_cache.size()) { - // Read the class entries we don't have. We should just - // read all of them instead of just the one we need as then - // we can cache those we may need later. + // Read the class entries we don't have. We should just read all of + // them instead of just the one we need as then we can cache those we + // may need later. auto num_new_classes = objc_indexed_classes_count - m_indexed_isa_cache.size(); const uint32_t addr_size = process->GetAddressByteSize(); @@ -2504,8 +2534,8 @@ bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( return false; } - // Definately not an indexed ISA, so try to use a mask to extract - // the pointer from the ISA. + // Definately 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; return (ret_isa != 0); // this is a pointer so 0 is not a valid value @@ -2533,14 +2563,14 @@ bool AppleObjCRuntimeV2::GetCFBooleanValuesIfNeeded() { if (m_CFBoolean_values) return true; - static ConstString g_kCFBooleanFalse("kCFBooleanFalse"); - static ConstString g_kCFBooleanTrue("kCFBooleanTrue"); + static ConstString g_kCFBooleanFalse("__kCFBooleanFalse"); + static ConstString g_kCFBooleanTrue("__kCFBooleanTrue"); std::function<lldb::addr_t(ConstString)> get_symbol = [this](ConstString sym) -> lldb::addr_t { SymbolContextList sc_list; if (GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType( - g_kCFBooleanFalse, lldb::eSymbolTypeData, sc_list) == 1) { + sym, lldb::eSymbolTypeData, sc_list) == 1) { SymbolContext sc; sc_list.GetContextAtIndex(0, sc); if (sc.symbol) diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index 89e81d5b181e..487b67ca6271 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -94,6 +94,8 @@ public: return m_tagged_pointer_vendor_ap.get(); } + lldb::addr_t GetTaggedPointerObfuscator(); + void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, lldb::addr_t &cf_false) override; @@ -330,6 +332,7 @@ private: std::mutex m_get_shared_cache_class_info_args_mutex; std::unique_ptr<DeclVendor> m_decl_vendor_ap; + lldb::addr_t m_tagged_pointer_obfuscator; lldb::addr_t m_isa_hash_table_ptr; HashTableSignature m_hash_signature; bool m_has_object_getClass; diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index a6e9c0c16f16..c75fa71ba131 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -49,227 +49,237 @@ const char *AppleObjCTrampolineHandler::g_lookup_implementation_function_name = const char *AppleObjCTrampolineHandler:: g_lookup_implementation_with_stret_function_code = " \n\ -extern \"C\" \n\ -{ \n\ - extern void *class_getMethodImplementation(void *objc_class, void *sel); \n\ - extern void *class_getMethodImplementation_stret(void *objc_class, void *sel); \n\ - extern void * object_getClass (id object); \n\ - extern void * sel_getUid(char *name); \n\ - extern int printf(const char *format, ...); \n\ -} \n\ -extern \"C\" void * __lldb_objc_find_implementation_for_selector (void *object, \n\ - void *sel, \n\ - int is_stret, \n\ - int is_super, \n\ - int is_super2, \n\ - int is_fixup, \n\ - int is_fixed, \n\ - int debug) \n\ -{ \n\ - struct __lldb_imp_return_struct \n\ - { \n\ - void *class_addr; \n\ - void *sel_addr; \n\ - void *impl_addr; \n\ - }; \n\ - \n\ - struct __lldb_objc_class { \n\ - void *isa; \n\ - void *super_ptr; \n\ - }; \n\ - struct __lldb_objc_super { \n\ - void *reciever; \n\ - struct __lldb_objc_class *class_ptr; \n\ - }; \n\ - struct __lldb_msg_ref { \n\ - void *dont_know; \n\ - void *sel; \n\ - }; \n\ - \n\ - struct __lldb_imp_return_struct return_struct; \n\ - \n\ - if (debug) \n\ - printf (\"\\n*** Called with obj: 0x%p sel: 0x%p is_stret: %d is_super: %d, \" \n\ - \"is_super2: %d, is_fixup: %d, is_fixed: %d\\n\", \n\ - object, sel, is_stret, is_super, is_super2, is_fixup, is_fixed); \n\ - if (is_super) \n\ - { \n\ - if (is_super2) \n\ - { \n\ - return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr->super_ptr; \n\ - } \n\ - else \n\ - { \n\ - return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr; \n\ - } \n\ - } \n\ - else \n\ - { \n\ - // This code seems a little funny, but has its reasons... \n\ - // The call to [object class] is here because if this is a class, and has not been called into \n\ - // yet, we need to do something to force the class to initialize itself. \n\ - // Then the call to object_getClass will actually return the correct class, either the class \n\ - // if object is a class instance, or the meta-class if it is a class pointer. \n\ - void *class_ptr = (void *) [(id) object class]; \n\ - return_struct.class_addr = (id) object_getClass((id) object); \n\ - if (debug) \n\ - { \n\ - if (class_ptr == object) \n\ - { \n\ - printf (\"Found a class object, need to use the meta class %p -> %p\\n\", \n\ - class_ptr, return_struct.class_addr); \n\ - } \n\ - else \n\ - { \n\ - printf (\"[object class] returned: %p object_getClass: %p.\\n\", \n\ - class_ptr, return_struct.class_addr); \n\ - } \n\ - } \n\ - } \n\ - \n\ - if (is_fixup) \n\ - { \n\ - if (is_fixed) \n\ - { \n\ - return_struct.sel_addr = ((__lldb_msg_ref *) sel)->sel; \n\ - } \n\ - else \n\ - { \n\ - char *sel_name = (char *) ((__lldb_msg_ref *) sel)->sel; \n\ - return_struct.sel_addr = sel_getUid (sel_name); \n\ - if (debug) \n\ - printf (\"\\n*** Got fixed up selector: %p for name %s.\\n\", \n\ - return_struct.sel_addr, sel_name); \n\ - } \n\ - } \n\ - else \n\ - { \n\ - return_struct.sel_addr = sel; \n\ - } \n\ - \n\ - if (is_stret) \n\ - { \n\ - return_struct.impl_addr = class_getMethodImplementation_stret (return_struct.class_addr, \n\ - return_struct.sel_addr); \n\ - } \n\ - else \n\ - { \n\ - return_struct.impl_addr = class_getMethodImplementation (return_struct.class_addr, \n\ - return_struct.sel_addr); \n\ - } \n\ - if (debug) \n\ - printf (\"\\n*** Returning implementation: %p.\\n\", return_struct.impl_addr); \n\ - \n\ - return return_struct.impl_addr; \n\ -} \n\ +extern \"C\" \n\ +{ \n\ + extern void *class_getMethodImplementation(void *objc_class, void *sel); \n\ + extern void *class_getMethodImplementation_stret(void *objc_class, \n\ + void *sel); \n\ + extern void * object_getClass (id object); \n\ + extern void * sel_getUid(char *name); \n\ + extern int printf(const char *format, ...); \n\ +} \n\ +extern \"C\" void * __lldb_objc_find_implementation_for_selector ( \n\ + void *object, \n\ + void *sel, \n\ + int is_stret, \n\ + int is_super, \n\ + int is_super2, \n\ + int is_fixup, \n\ + int is_fixed, \n\ + int debug) \n\ +{ \n\ + struct __lldb_imp_return_struct \n\ + { \n\ + void *class_addr; \n\ + void *sel_addr; \n\ + void *impl_addr; \n\ + }; \n\ + \n\ + struct __lldb_objc_class { \n\ + void *isa; \n\ + void *super_ptr; \n\ + }; \n\ + struct __lldb_objc_super { \n\ + void *reciever; \n\ + struct __lldb_objc_class *class_ptr; \n\ + }; \n\ + struct __lldb_msg_ref { \n\ + void *dont_know; \n\ + void *sel; \n\ + }; \n\ + \n\ + struct __lldb_imp_return_struct return_struct; \n\ + \n\ + if (debug) \n\ + printf (\"\\n*** Called with obj: 0x%p sel: 0x%p is_stret: %d is_super: %d, \"\n\ + \"is_super2: %d, is_fixup: %d, is_fixed: %d\\n\", \n\ + object, sel, is_stret, is_super, is_super2, is_fixup, is_fixed);\n\ + if (is_super) \n\ + { \n\ + if (is_super2) \n\ + { \n\ + return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr->super_ptr;\n\ + } \n\ + else \n\ + { \n\ + return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr;\n\ + } \n\ + } \n\ + else \n\ + { \n\ + // This code seems a little funny, but has its reasons... \n\ + \n\ + // The call to [object class] is here because if this is a \n\ + // class, and has not been called into yet, we need to do \n\ + // something to force the class to initialize itself. \n\ + // Then the call to object_getClass will actually return the \n\ + // correct class, either the class if object is a class \n\ + // instance, or the meta-class if it is a class pointer. \n\ + void *class_ptr = (void *) [(id) object class]; \n\ + return_struct.class_addr = (id) object_getClass((id) object); \n\ + if (debug) \n\ + { \n\ + if (class_ptr == object) \n\ + { \n\ + printf (\"Found a class object, need to use the meta class %p -> %p\\n\",\n\ + class_ptr, return_struct.class_addr); \n\ + } \n\ + else \n\ + { \n\ + printf (\"[object class] returned: %p object_getClass: %p.\\n\", \n\ + class_ptr, return_struct.class_addr); \n\ + } \n\ + } \n\ + } \n\ + \n\ + if (is_fixup) \n\ + { \n\ + if (is_fixed) \n\ + { \n\ + return_struct.sel_addr = ((__lldb_msg_ref *) sel)->sel; \n\ + } \n\ + else \n\ + { \n\ + char *sel_name = (char *) ((__lldb_msg_ref *) sel)->sel; \n\ + return_struct.sel_addr = sel_getUid (sel_name); \n\ + if (debug) \n\ + printf (\"\\n*** Got fixed up selector: %p for name %s.\\n\",\n\ + return_struct.sel_addr, sel_name); \n\ + } \n\ + } \n\ + else \n\ + { \n\ + return_struct.sel_addr = sel; \n\ + } \n\ + \n\ + if (is_stret) \n\ + { \n\ + return_struct.impl_addr = \n\ + class_getMethodImplementation_stret (return_struct.class_addr, \n\ + return_struct.sel_addr); \n\ + } \n\ + else \n\ + { \n\ + return_struct.impl_addr = \n\ + class_getMethodImplementation (return_struct.class_addr, \n\ + return_struct.sel_addr); \n\ + } \n\ + if (debug) \n\ + printf (\"\\n*** Returning implementation: %p.\\n\", \n\ + return_struct.impl_addr); \n\ + \n\ + return return_struct.impl_addr; \n\ +} \n\ "; const char * AppleObjCTrampolineHandler::g_lookup_implementation_no_stret_function_code = " \n\ -extern \"C\" \n\ -{ \n\ - extern void *class_getMethodImplementation(void *objc_class, void *sel); \n\ - extern void * object_getClass (id object); \n\ - extern void * sel_getUid(char *name); \n\ - extern int printf(const char *format, ...); \n\ -} \n\ +extern \"C\" \n\ +{ \n\ + extern void *class_getMethodImplementation(void *objc_class, void *sel); \n\ + extern void * object_getClass (id object); \n\ + extern void * sel_getUid(char *name); \n\ + extern int printf(const char *format, ...); \n\ +} \n\ extern \"C\" void * __lldb_objc_find_implementation_for_selector (void *object, \n\ - void *sel, \n\ - int is_stret, \n\ - int is_super, \n\ - int is_super2, \n\ - int is_fixup, \n\ - int is_fixed, \n\ - int debug) \n\ -{ \n\ - struct __lldb_imp_return_struct \n\ - { \n\ - void *class_addr; \n\ - void *sel_addr; \n\ - void *impl_addr; \n\ - }; \n\ - \n\ - struct __lldb_objc_class { \n\ - void *isa; \n\ - void *super_ptr; \n\ - }; \n\ - struct __lldb_objc_super { \n\ - void *reciever; \n\ - struct __lldb_objc_class *class_ptr; \n\ - }; \n\ - struct __lldb_msg_ref { \n\ - void *dont_know; \n\ - void *sel; \n\ - }; \n\ - \n\ - struct __lldb_imp_return_struct return_struct; \n\ - \n\ - if (debug) \n\ + void *sel, \n\ + int is_stret, \n\ + int is_super, \n\ + int is_super2, \n\ + int is_fixup, \n\ + int is_fixed, \n\ + int debug) \n\ +{ \n\ + struct __lldb_imp_return_struct \n\ + { \n\ + void *class_addr; \n\ + void *sel_addr; \n\ + void *impl_addr; \n\ + }; \n\ + \n\ + struct __lldb_objc_class { \n\ + void *isa; \n\ + void *super_ptr; \n\ + }; \n\ + struct __lldb_objc_super { \n\ + void *reciever; \n\ + struct __lldb_objc_class *class_ptr; \n\ + }; \n\ + struct __lldb_msg_ref { \n\ + void *dont_know; \n\ + void *sel; \n\ + }; \n\ + \n\ + struct __lldb_imp_return_struct return_struct; \n\ + \n\ + if (debug) \n\ printf (\"\\n*** Called with obj: 0x%p sel: 0x%p is_stret: %d is_super: %d, \" \n\ - \"is_super2: %d, is_fixup: %d, is_fixed: %d\\n\", \n\ + \"is_super2: %d, is_fixup: %d, is_fixed: %d\\n\", \n\ object, sel, is_stret, is_super, is_super2, is_fixup, is_fixed); \n\ - if (is_super) \n\ - { \n\ - if (is_super2) \n\ - { \n\ + if (is_super) \n\ + { \n\ + if (is_super2) \n\ + { \n\ return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr->super_ptr; \n\ - } \n\ - else \n\ - { \n\ + } \n\ + else \n\ + { \n\ return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr; \n\ - } \n\ - } \n\ - else \n\ - { \n\ - // This code seems a little funny, but has its reasons... \n\ + } \n\ + } \n\ + else \n\ + { \n\ + // This code seems a little funny, but has its reasons... \n\ // The call to [object class] is here because if this is a class, and has not been called into \n\ // yet, we need to do something to force the class to initialize itself. \n\ // Then the call to object_getClass will actually return the correct class, either the class \n\ // if object is a class instance, or the meta-class if it is a class pointer. \n\ - void *class_ptr = (void *) [(id) object class]; \n\ - return_struct.class_addr = (id) object_getClass((id) object); \n\ - if (debug) \n\ - { \n\ - if (class_ptr == object) \n\ - { \n\ + void *class_ptr = (void *) [(id) object class]; \n\ + return_struct.class_addr = (id) object_getClass((id) object); \n\ + if (debug) \n\ + { \n\ + if (class_ptr == object) \n\ + { \n\ printf (\"Found a class object, need to return the meta class %p -> %p\\n\", \n\ - class_ptr, return_struct.class_addr); \n\ - } \n\ - else \n\ - { \n\ + class_ptr, return_struct.class_addr); \n\ + } \n\ + else \n\ + { \n\ printf (\"[object class] returned: %p object_getClass: %p.\\n\", \n\ - class_ptr, return_struct.class_addr); \n\ - } \n\ - } \n\ - } \n\ - \n\ - if (is_fixup) \n\ - { \n\ - if (is_fixed) \n\ - { \n\ - return_struct.sel_addr = ((__lldb_msg_ref *) sel)->sel; \n\ - } \n\ - else \n\ - { \n\ - char *sel_name = (char *) ((__lldb_msg_ref *) sel)->sel; \n\ - return_struct.sel_addr = sel_getUid (sel_name); \n\ - if (debug) \n\ - printf (\"\\n*** Got fixed up selector: %p for name %s.\\n\", \n\ - return_struct.sel_addr, sel_name); \n\ - } \n\ - } \n\ - else \n\ - { \n\ - return_struct.sel_addr = sel; \n\ - } \n\ - \n\ - return_struct.impl_addr = class_getMethodImplementation (return_struct.class_addr, \n\ - return_struct.sel_addr); \n\ - if (debug) \n\ - printf (\"\\n*** Returning implementation: 0x%p.\\n\", return_struct.impl_addr); \n\ - \n\ - return return_struct.impl_addr; \n\ -} \n\ + class_ptr, return_struct.class_addr); \n\ + } \n\ + } \n\ + } \n\ + \n\ + if (is_fixup) \n\ + { \n\ + if (is_fixed) \n\ + { \n\ + return_struct.sel_addr = ((__lldb_msg_ref *) sel)->sel; \n\ + } \n\ + else \n\ + { \n\ + char *sel_name = (char *) ((__lldb_msg_ref *) sel)->sel; \n\ + return_struct.sel_addr = sel_getUid (sel_name); \n\ + if (debug) \n\ + printf (\"\\n*** Got fixed up selector: %p for name %s.\\n\",\n\ + return_struct.sel_addr, sel_name); \n\ + } \n\ + } \n\ + else \n\ + { \n\ + return_struct.sel_addr = sel; \n\ + } \n\ + \n\ + return_struct.impl_addr = \n\ + class_getMethodImplementation (return_struct.class_addr, \n\ + return_struct.sel_addr); \n\ + if (debug) \n\ + printf (\"\\n*** Returning implementation: 0x%p.\\n\", \n\ + return_struct.impl_addr); \n\ + \n\ + return return_struct.impl_addr; \n\ +} \n\ "; AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::VTableRegion( @@ -328,12 +338,11 @@ void AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::SetUpRegion() { // uint32_t offset // uint32_t flags // - // Where offset is either 0 - in which case it is unused, or - // it is the offset of the vtable code from the beginning of the descriptor - // record. - // Below, we'll convert that into an absolute code address, since I don't want - // to have - // to compute it over and over. + // Where offset is either 0 - in which case it is unused, or it is + // the offset of the vtable code from the beginning of the + // descriptor record. Below, we'll convert that into an absolute + // code address, since I don't want to have to compute it over and + // over. // Ingest the whole descriptor array: const lldb::addr_t desc_ptr = m_header_addr + header_size; @@ -370,10 +379,9 @@ void AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::SetUpRegion() { offset = start_offset + descriptor_size; } - // Finally, a little bird told me that all the vtable code blocks are the same - // size. - // Let's compute the blocks and if they are all the same add the size to the - // code end address: + // Finally, a little bird told me that all the vtable code blocks + // are the same size. Let's compute the blocks and if they are all + // the same add the size to the code end address: lldb::addr_t code_size = 0; bool all_the_same = true; for (size_t i = 0; i < num_descriptors - 1; i++) { @@ -548,9 +556,8 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines( } bool AppleObjCTrampolineHandler::AppleObjCVTables::ReadRegions() { - // The no argument version reads the start region from the value of the - // gdb_regions_header, and - // gets started from there. + // The no argument version reads the start region from the value of + // the gdb_regions_header, and gets started from there. m_regions.clear(); if (!InitializeVTableSymbols()) @@ -718,13 +725,12 @@ AppleObjCTrampolineHandler::AppleObjCTrampolineHandler( g_lookup_implementation_with_stret_function_code; } - // Look up the addresses for the objc dispatch functions and cache them. For - // now I'm inspecting the symbol - // names dynamically to figure out how to dispatch to them. If it becomes - // more complicated than this we can - // turn the g_dispatch_functions char * array into a template table, and - // populate the DispatchFunction map - // from there. + // Look up the addresses for the objc dispatch functions and cache + // them. For now I'm inspecting the symbol names dynamically to + // figure out how to dispatch to them. If it becomes more + // complicated than this we can turn the g_dispatch_functions char * + // array into a template table, and populate the DispatchFunction + // map from there. for (size_t i = 0; i != llvm::array_lengthof(g_dispatch_functions); i++) { ConstString name_const_str(g_dispatch_functions[i].name); @@ -732,11 +738,11 @@ AppleObjCTrampolineHandler::AppleObjCTrampolineHandler( m_objc_module_sp->FindFirstSymbolWithNameAndType(name_const_str, eSymbolTypeCode); if (msgSend_symbol && msgSend_symbol->ValueIsAddress()) { - // FixMe: Make g_dispatch_functions static table of DispatchFunctions, and - // have the map be address->index. - // Problem is we also need to lookup the dispatch function. For now we - // could have a side table of stret & non-stret - // dispatch functions. If that's as complex as it gets, we're fine. + // FIXME: Make g_dispatch_functions static table of + // DispatchFunctions, and have the map be address->index. + // Problem is we also need to lookup the dispatch function. For + // now we could have a side table of stret & non-stret dispatch + // functions. If that's as complex as it gets, we're fine. lldb::addr_t sym_addr = msgSend_symbol->GetAddressRef().GetOpcodeLoadAddress(target); @@ -820,11 +826,11 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, diagnostics.Clear(); - // Now write down the argument values for this particular call. This looks - // like it might be a race condition - // if other threads were calling into here, but actually it isn't because we - // allocate a new args structure for - // this call by passing args_addr = LLDB_INVALID_ADDRESS... + // Now write down the argument values for this particular call. + // This looks like it might be a race condition if other threads + // were calling into here, but actually it isn't because we allocate + // a new args structure for this call by passing args_addr = + // LLDB_INVALID_ADDRESS... if (!impl_function_caller->WriteFunctionArguments( exe_ctx, args_addr, dispatch_values, diagnostics)) { @@ -847,9 +853,9 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, DispatchFunction this_dispatch; bool found_it = false; - // First step is to look and see if we are in one of the known ObjC dispatch - // functions. We've already compiled - // a table of same, so consult it. + // First step is to look and see if we are in one of the known ObjC + // dispatch functions. We've already compiled a table of same, so + // consult it. MsgsendMap::iterator pos; pos = m_msgSend_map.find(curr_pc); @@ -879,8 +885,8 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, if (found_it) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - // We are decoding a method dispatch. - // First job is to pull the arguments out: + // We are decoding a method dispatch. First job is to pull the + // arguments out: lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0); @@ -906,10 +912,10 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, int obj_index; int sel_index; - // If this is a struct return dispatch, then the first argument is the - // return struct pointer, and the object is the second, and the selector is - // the third. - // Otherwise the object is the first and the selector the second. + // If this is a struct return dispatch, then the first argument is + // the return struct pointer, and the object is the second, and + // the selector is the third. Otherwise the object is the first + // and the selector the second. if (this_dispatch.stret_return) { obj_index = 1; sel_index = 2; @@ -938,29 +944,26 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, ExecutionContext exe_ctx(thread.shared_from_this()); Process *process = exe_ctx.GetProcessPtr(); - // isa_addr will store the class pointer that the method is being dispatched - // to - so either the class - // directly or the super class if this is one of the objc_msgSendSuper - // flavors. That's mostly used to - // look up the class/selector pair in our cache. + // isa_addr will store the class pointer that the method is being + // dispatched to - so either the class directly or the super class + // if this is one of the objc_msgSendSuper flavors. That's mostly + // used to look up the class/selector pair in our cache. lldb::addr_t isa_addr = LLDB_INVALID_ADDRESS; lldb::addr_t sel_addr = argument_values.GetValueAtIndex(sel_index)->GetScalar().ULongLong(); - // Figure out the class this is being dispatched to and see if we've already - // cached this method call, - // If so we can push a run-to-address plan directly. Otherwise we have to - // figure out where - // the implementation lives. + // Figure out the class this is being dispatched to and see if + // we've already cached this method call, If so we can push a + // run-to-address plan directly. Otherwise we have to figure out + // where the implementation lives. if (this_dispatch.is_super) { if (this_dispatch.is_super2) { - // In the objc_msgSendSuper2 case, we don't get the object directly, we - // get a structure containing - // the object and the class to which the super message is being sent. - // So we need to dig the super - // out of the class and use that. + // In the objc_msgSendSuper2 case, we don't get the object + // directly, we get a structure containing the object and the + // class to which the super message is being sent. So we need + // to dig the super out of the class and use that. Value super_value(*(argument_values.GetValueAtIndex(obj_index))); super_value.GetScalar() += process->GetAddressByteSize(); @@ -984,11 +987,11 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, log->Printf("Failed to extract the class value from objc_super."); } } else { - // In the objc_msgSendSuper case, we don't get the object directly, we - // get a two element structure containing - // the object and the super class to which the super message is being - // sent. So the class we want is - // the second element of this structure. + // In the objc_msgSendSuper case, we don't get the object + // directly, we get a two element structure containing the + // object and the super class to which the super message is + // being sent. So the class we want is the second element of + // this structure. Value super_value(*(argument_values.GetValueAtIndex(obj_index))); super_value.GetScalar() += process->GetAddressByteSize(); @@ -1009,9 +1012,9 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, // making the object value a load address value and resolving it will get // the pointer sized data pointed to by that value... - // Note, it isn't a fatal error not to be able to get the address from the - // object, since this might - // be a "tagged pointer" which isn't a real object, but rather some word + // Note, it isn't a fatal error not to be able to get the + // address from the object, since this might be a "tagged + // pointer" which isn't a real object, but rather some word // length encoded dingus. Value isa_value(*(argument_values.GetValueAtIndex(obj_index))); @@ -1126,9 +1129,9 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, flag_value.GetScalar() = 0; // FIXME - Set to 0 when debugging is done. dispatch_values.PushValue(flag_value); - // The step through code might have to fill in the cache, so it is not - // safe to run only one thread. - // So we override the stop_others value passed in to us here: + // The step through code might have to fill in the cache, so it + // is not safe to run only one thread. So we override the + // stop_others value passed in to us here: const bool trampoline_stop_others = false; ret_plan_sp.reset(new AppleThreadPlanStepThroughObjCTrampoline( thread, this, dispatch_values, isa_addr, sel_addr, diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index 316115b0dcb1..9bb1a4e0ee42 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -105,10 +105,9 @@ clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( return clang::QualType(); std::string name(ReadStructName(type)); - // We do not handle templated classes/structs at the moment. - // If the name has a < in it, we are going to abandon this. - // We're still obliged to parse it, so we just set a flag that - // means "Don't actually build anything." + // We do not handle templated classes/structs at the moment. If the name has + // a < in it, we are going to abandon this. We're still obliged to parse it, + // so we just set a flag that means "Don't actually build anything." const bool is_templated = name.find('<') != std::string::npos; @@ -180,11 +179,9 @@ AppleObjCTypeEncodingParser::BuildArray(clang::ASTContext &ast_ctx, // the runtime can emit these in the form of @"SomeType", giving more specifics // this would be interesting for expression parser interop, but since we -// actually try -// to avoid exposing the ivar info to the expression evaluator, consume but -// ignore the type info -// and always return an 'id'; if anything, dynamic typing will resolve things -// for us anyway +// actually try to avoid exposing the ivar info to the expression evaluator, +// consume but ignore the type info and always return an 'id'; if anything, +// dynamic typing will resolve things for us anyway clang::QualType AppleObjCTypeEncodingParser::BuildObjCObjectPointerType( clang::ASTContext &ast_ctx, lldb_utility::StringLexer &type, bool for_expression) { @@ -197,24 +194,21 @@ clang::QualType AppleObjCTypeEncodingParser::BuildObjCObjectPointerType( // We have to be careful here. We're used to seeing // @"NSString" // but in records it is possible that the string following an @ is the name - // of the next field and @ means "id". - // This is the case if anything unquoted except for "}", the end of the - // type, or another name follows the quoted string. + // of the next field and @ means "id". This is the case if anything + // unquoted except for "}", the end of the type, or another name follows + // the quoted string. // // E.g. // - @"NSString"@ means "id, followed by a field named NSString of type id" - // - @"NSString"} means "a pointer to NSString and the end of the struct" - // - @"NSString""nextField" means "a pointer to NSString and a field named - // nextField" - // - @"NSString" followed by the end of the string means "a pointer to - // NSString" + // - @"NSString"} means "a pointer to NSString and the end of the struct" - + // @"NSString""nextField" means "a pointer to NSString and a field named + // nextField" - @"NSString" followed by the end of the string means "a + // pointer to NSString" // // As a result, the rule is: If we see @ followed by a quoted string, we - // peek. - // - If we see }, ), ], the end of the string, or a quote ("), the quoted - // string is a class name. - // - If we see anything else, the quoted string is a field name and we push - // it back onto type. + // peek. - If we see }, ), ], the end of the string, or a quote ("), the + // quoted string is a class name. - If we see anything else, the quoted + // string is a field name and we push it back onto type. name = ReadQuotedString(type); @@ -260,9 +254,8 @@ clang::QualType AppleObjCTypeEncodingParser::BuildObjCObjectPointerType( decl_vendor->FindDecls(ConstString(name), append, max_matches, decls); // The user can forward-declare something that has no definition. The runtime -// doesn't prohibit this at all. -// This is a rare and very weird case. We keep this assert in debug builds so -// we catch other weird cases. +// doesn't prohibit this at all. This is a rare and very weird case. We keep +// this assert in debug builds so we catch other weird cases. #ifdef LLDB_CONFIGURATION_DEBUG assert(num_types); #else @@ -315,8 +308,8 @@ AppleObjCTypeEncodingParser::BuildType(clang::ASTContext &ast_ctx, // if (!lldb_ctx) // return clang::QualType(); // return lldb_ctx->GetIntTypeFromBitSize(32, true).GetQualType(); - // which uses one of the constants if one is available, but we don't think all - // this work is necessary. + // which uses one of the constants if one is available, but we don't think + // all this work is necessary. case 'q': return ast_ctx.LongLongTy; case 'C': @@ -364,11 +357,10 @@ AppleObjCTypeEncodingParser::BuildType(clang::ASTContext &ast_ctx, case '^': { if (!for_expression && type.NextIf('?')) { // if we are not supporting the concept of unknownAny, but what is being - // created here is an unknownAny*, then - // we can just get away with a void* + // created here is an unknownAny*, then we can just get away with a void* // this is theoretically wrong (in the same sense as 'theoretically - // nothing exists') but is way better than outright failure - // in many practical cases + // nothing exists') but is way better than outright failure in many + // practical cases return ast_ctx.VoidPtrTy; } else { clang::QualType target_type = BuildType(ast_ctx, type, for_expression); diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index a295d1b4ce76..75b670739427 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -52,8 +52,8 @@ AppleThreadPlanStepThroughObjCTrampoline:: void AppleThreadPlanStepThroughObjCTrampoline::DidPush() { // Setting up the memory space for the called function text might require - // allocations, - // i.e. a nested function call. This needs to be done as a PreResumeAction. + // allocations, i.e. a nested function call. This needs to be done as a + // PreResumeAction. m_thread.GetProcess()->AddPreResumeAction(PreResumeInitializeFunctionCaller, (void *)this); } @@ -110,8 +110,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::DoPlanExplainsStop( Event *event_ptr) { // If we get asked to explain the stop it will be because something went // wrong (like the implementation for selector function crashed... We're - // going - // to figure out what to do about that, so we do explain the stop. + // going to figure out what to do about that, so we do explain the stop. return true; } @@ -135,8 +134,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { } // Second stage, if all went well with the function calling, then fetch the - // target address, and - // queue up a "run to that address" plan. + // target address, and queue up a "run to that address" plan. if (!m_run_to_sp) { Value target_addr_value; ExecutionContext exc_ctx; @@ -201,8 +199,8 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { return false; } -// The base class MischiefManaged does some cleanup - so you have to call it -// in your MischiefManaged derived class. +// 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; diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp index 654ac9abfcab..cbbc35f1c08a 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp @@ -38,14 +38,12 @@ using namespace lldb_renderscript; // [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang), // the compiler frontend for RenderScript embeds an ARM specific triple in IR -// that is shipped in the app, after -// generating IR that has some assumptions that an ARM device is the target. -// As the IR is then compiled on a device of unknown (at time the IR was -// generated at least) architecture, -// when calling RenderScript API function as part of debugger expressions, we -// have to perform a fixup pass that -// removes those assumptions right before the module is sent to be generated by -// the llvm backend. +// that is shipped in the app, after generating IR that has some assumptions +// that an ARM device is the target. As the IR is then compiled on a device of +// unknown (at time the IR was generated at least) architecture, when calling +// RenderScript API function as part of debugger expressions, we have to +// perform a fixup pass that removes those assumptions right before the module +// is sent to be generated by the llvm backend. namespace { bool registerRSDefaultTargetOpts(clang::TargetOptions &proto, @@ -107,10 +105,9 @@ bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { case llvm::Triple::ArchType::x86: changed_module |= fixupX86FunctionCalls(module); // For some reason this triple gets totally missed by the backend, and must - // be set manually. - // There a reference in bcc/Main.cpp about auto feature-detection being - // removed from LLVM3.5, but I can't - // see that discussion anywhere public. + // be set manually. There a reference in bcc/Main.cpp about auto feature- + // detection being removed from LLVM3.5, but I can't see that discussion + // anywhere public. real_triple = "i686--linux-android"; break; case llvm::Triple::ArchType::x86_64: @@ -118,12 +115,12 @@ bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { break; case llvm::Triple::ArchType::mipsel: case llvm::Triple::ArchType::mips64el: - // No actual IR fixup pass is needed on MIPS, but the datalayout - // and targetmachine do need to be explicitly set. + // No actual IR fixup pass is needed on MIPS, but the datalayout and + // targetmachine do need to be explicitly set. - // bcc explicitly compiles MIPS code to use the static relocation - // model due to an issue with relocations in mclinker. - // see libbcc/support/CompilerConfig.cpp for details + // bcc explicitly compiles MIPS code to use the static relocation model due + // to an issue with relocations in mclinker. see + // libbcc/support/CompilerConfig.cpp for details reloc_model = llvm::Reloc::Static; changed_module = true; break; @@ -146,8 +143,7 @@ bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { assert(target_machine && "failed to identify RenderScriptRuntime target machine"); // We've been using a triple and datalayout of some ARM variant all along, - // so - // we need to let the backend know that this is no longer the case. + // so we need to let the backend know that this is no longer the case. if (log) { log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__, real_triple.str().c_str()); diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp index ad1083be0285..4eb15369aa1e 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -26,7 +26,6 @@ #include "lldb/Expression/UserExpression.h" #include "lldb/Host/OptionParser.h" #include "lldb/Host/StringConvert.h" -#include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -40,6 +39,7 @@ #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #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" @@ -312,7 +312,8 @@ bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { Status err; - // find offset to arguments on the stack (+16 to skip over a0-a3 shadow space) + // find offset to arguments on the stack (+16 to skip over a0-a3 shadow + // space) uint64_t sp = ctx.reg_ctx->GetSP() + 16; for (size_t i = 0; i < num_args; ++i) { @@ -447,12 +448,11 @@ bool IsRenderScriptScriptModule(ModuleSP module) { } bool ParseCoordinate(llvm::StringRef coord_s, RSCoordinate &coord) { - // takes an argument of the form 'num[,num][,num]'. - // Where 'coord_s' is a comma separated 1,2 or 3-dimensional coordinate - // with the whitespace trimmed. - // Missing coordinates are defaulted to zero. - // If parsing of any elements fails the contents of &coord are undefined - // and `false` is returned, `true` otherwise + // takes an argument of the form 'num[,num][,num]'. Where 'coord_s' is a + // comma separated 1,2 or 3-dimensional coordinate with the whitespace + // trimmed. Missing coordinates are defaulted to zero. If parsing of any + // elements fails the contents of &coord are undefined and `false` is + // returned, `true` otherwise RegularExpression regex; RegularExpression::Match regex_match(3); @@ -593,7 +593,7 @@ struct RenderScriptRuntime::Element { empirical_type<uint32_t> datum_size; // Size of a single Element with padding empirical_type<uint32_t> padding; // Number of padding bytes empirical_type<uint32_t> - array_size; // Number of items in array, only needed for strucrs + array_size; // Number of items in array, only needed for structs ConstString type_name; // Name of type, only needed for structs static const ConstString & @@ -633,8 +633,9 @@ struct RenderScriptRuntime::AllocationDetails { // subelements, there may be more than one instance of the ElementHeader // struct. With this first instance being the root element, and the other // instances being the root's descendants. To identify which instances are an - // ElementHeader's children, each struct is immediately followed by a sequence - // of consecutive offsets to the start of its child structs. These offsets are + // ElementHeader's children, each struct is immediately followed by a + // sequence of consecutive offsets to the start of its child structs. These + // offsets are // 4 bytes in size, and the 0 offset signifies no more children. struct FileHeader { uint8_t ident[4]; // ASCII 'RSAD' identifying the file @@ -653,8 +654,8 @@ struct RenderScriptRuntime::AllocationDetails { // Monotonically increasing from 1 static uint32_t ID; - // Maps Allocation DataType enum and vector size to printable strings - // using mapping from RenderScript numerical types summary documentation + // Maps Allocation DataType enum and vector size to printable strings using + // mapping from RenderScript numerical types summary documentation static const char *RsDataTypeToString[][4]; // Maps Allocation DataKind enum to printable strings @@ -844,11 +845,10 @@ RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter, lldb_private::SymbolContext &context, Address *, bool) { // We need to have access to the list of reductions currently parsed, as - // reduce names don't actually exist as - // symbols in a module. They are only identifiable by parsing the .rs.info - // packet, or finding the expand symbol. We - // therefore need access to the list of parsed rs modules to properly resolve - // reduction names. + // reduce names don't actually exist as symbols in a module. They are only + // identifiable by parsing the .rs.info packet, or finding the expand symbol. + // We therefore need access to the list of parsed rs modules to properly + // resolve reduction names. Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); ModuleSP module = context.module_sp; @@ -967,8 +967,8 @@ Searcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback( log->Printf("%s: Placed %sbreakpoint on %s", __FUNCTION__, new_bp ? "new " : "", k.m_name.AsCString()); - // exit after placing the first breakpoint if we do not intend to stop - // on all kernels making up this script group + // exit after placing the first breakpoint if we do not intend to stop on + // all kernels making up this script group if (!m_stop_on_all) break; } @@ -1684,8 +1684,8 @@ void RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) { const ModuleSP module = rsmodule_sp->m_module; const FileSpec &file = module->GetPlatformFileSpec(); - // Iterate over all of the scripts that we currently know of. - // Note: We cant push or pop to m_scripts here or it may invalidate rs_script. + // Iterate over all of the scripts that we currently know of. Note: We cant + // push or pop to m_scripts here or it may invalidate rs_script. for (const auto &rs_script : m_scripts) { // Extract the expected .so file path for this script. std::string shared_lib; @@ -1825,9 +1825,9 @@ const char *JITTemplate(ExpressionStrings e) { // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) Pack the // data in the following way mHal.state.dimX; mHal.state.dimY; - // mHal.state.dimZ; mHal.state.lodCount; mHal.state.faces; mElement; into - // typeData Need to specify 32 or 64 bit for uint_t since this differs - // between devices + // mHal.state.dimZ; mHal.state.lodCount; mHal.state.faces; mElement; + // into typeData Need to specify 32 or 64 bit for uint_t since this + // differs between devices JIT_TEMPLATE_CONTEXT "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt" ", 0x%" PRIx64 ", data, 6); data[0]", // eExprTypeDimX @@ -1882,10 +1882,10 @@ const char *JITTemplate(ExpressionStrings e) { } } // end of the anonymous namespace -// JITs the RS runtime for the internal data pointer of an allocation. Is passed -// x,y,z coordinates for the pointer to a specific element. Then sets the -// data_ptr member in Allocation with the result. Returns true on success, false -// otherwise +// JITs the RS runtime for the internal data pointer of an allocation. Is +// passed x,y,z coordinates for the pointer to a specific element. Then sets +// the data_ptr member in Allocation with the result. Returns true on success, +// false otherwise bool RenderScriptRuntime::JITDataPointer(AllocationDetails *alloc, StackFrame *frame_ptr, uint32_t x, uint32_t y, uint32_t z) { @@ -1961,8 +1961,8 @@ bool RenderScriptRuntime::JITTypePointer(AllocationDetails *alloc, } // JITs the RS runtime for information about the dimensions and type of an -// allocation Then sets dimension and element_ptr members in Allocation with the -// result. Returns true on success, false otherwise +// allocation Then sets dimension and element_ptr members in Allocation with +// the result. Returns true on success, false otherwise bool RenderScriptRuntime::JITTypePacked(AllocationDetails *alloc, StackFrame *frame_ptr) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); @@ -2245,9 +2245,8 @@ bool RenderScriptRuntime::JITAllocationSize(AllocationDetails *alloc, } // JITs the RS runtime for information about the stride between rows in the -// allocation. This is done to detect padding, since allocated memory is 16-byte -// aligned. -// Returns true on success, false otherwise +// allocation. This is done to detect padding, since allocated memory is +// 16-byte aligned. Returns true on success, false otherwise bool RenderScriptRuntime::JITAllocationStride(AllocationDetails *alloc, StackFrame *frame_ptr) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); @@ -2313,9 +2312,8 @@ bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *alloc, } // Function attempts to set the type_name member of the paramaterised Element -// object. -// This string should be the name of the struct type the Element represents. -// We need this string for pretty printing the Element to users. +// object. This string should be the name of the struct type the Element +// represents. We need this string for pretty printing the Element to users. void RenderScriptRuntime::FindStructTypeName(Element &elem, StackFrame *frame_ptr) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); @@ -2330,12 +2328,11 @@ void RenderScriptRuntime::FindStructTypeName(Element &elem, VariableList var_list; for (auto module_sp : m_rsmodules) module_sp->m_module->FindGlobalVariables( - RegularExpression(llvm::StringRef(".")), true, UINT32_MAX, var_list); + RegularExpression(llvm::StringRef(".")), UINT32_MAX, var_list); // Iterate over all the global variables looking for one with a matching type - // to the Element. - // We make the assumption a match exists since there needs to be a global - // variable to reflect the struct type back into java host code. + // to the Element. We make the assumption a match exists since there needs to + // be a global variable to reflect the struct type back into java host code. for (uint32_t i = 0; i < var_list.GetSize(); ++i) { const VariableSP var_sp(var_list.GetVariableAtIndex(i)); if (!var_sp) @@ -2347,15 +2344,14 @@ void RenderScriptRuntime::FindStructTypeName(Element &elem, // Find the number of variable fields. // If it has no fields, or more fields than our Element, then it can't be - // the struct we're looking for. - // Don't check for equality since RS can add extra struct members for - // padding. + // the struct we're looking for. Don't check for equality since RS can add + // extra struct members for padding. size_t num_children = valobj_sp->GetNumChildren(); if (num_children > elem.children.size() || num_children == 0) continue; - // Iterate over children looking for members with matching field names. - // If all the field names match, this is likely the struct we want. + // Iterate over children looking for members with matching field names. If + // all the field names match, this is likely the struct we want. // TODO: This could be made more robust by also checking children data // sizes, or array size bool found = true; @@ -2404,8 +2400,8 @@ void RenderScriptRuntime::FindStructTypeName(Element &elem, } // Function sets the datum_size member of Element. Representing the size of a -// single instance including padding. -// Assumes the relevant allocation information has already been jitted. +// single instance including padding. Assumes the relevant allocation +// information has already been jitted. void RenderScriptRuntime::SetElementSize(Element &elem) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); const Element::DataType type = *elem.type.get(); @@ -2446,9 +2442,9 @@ void RenderScriptRuntime::SetElementSize(Element &elem) { data_size + padding); } -// Given an allocation, this function copies the allocation contents from device -// into a buffer on the heap. -// Returning a shared pointer to the buffer containing the data. +// Given an allocation, this function copies the allocation contents from +// device into a buffer on the heap. Returning a shared pointer to the buffer +// containing the data. std::shared_ptr<uint8_t> RenderScriptRuntime::GetAllocationData(AllocationDetails *alloc, StackFrame *frame_ptr) { @@ -2496,9 +2492,8 @@ RenderScriptRuntime::GetAllocationData(AllocationDetails *alloc, return buffer; } -// Function copies data from a binary file into an allocation. -// There is a header at the start of the file, FileHeader, before the data -// content itself. +// Function copies data from a binary file into an allocation. There is a +// header at the start of the file, FileHeader, before the data content itself. // Information from this header is used to display warnings to the user about // incompatibilities bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, @@ -2630,7 +2625,8 @@ bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, // Calculate size of allocation data in file size_t size = data_sp->GetByteSize() - file_header->hdr_size; - // Check if the target allocation and file both have the same total data size. + // Check if the target allocation and file both have the same total data + // size. const uint32_t alloc_size = *alloc->size.get(); if (alloc_size != size) { strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 @@ -2660,15 +2656,15 @@ bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, // Function takes as parameters a byte buffer, which will eventually be written // to file as the element header, an offset into that buffer, and an Element -// that will be saved into the buffer at the parametrised offset. -// Return value is the new offset after writing the element into the buffer. -// Elements are saved to the file as the ElementHeader struct followed by -// offsets to the structs of all the element's children. +// that will be saved into the buffer at the parametrised offset. Return value +// is the new offset after writing the element into the buffer. Elements are +// saved to the file as the ElementHeader struct followed by offsets to the +// structs of all the element's children. size_t RenderScriptRuntime::PopulateElementHeaders( const std::shared_ptr<uint8_t> header_buffer, size_t offset, const Element &elem) { - // File struct for an element header with all the relevant details copied from - // elem. We assume members are valid already. + // File struct for an element header with all the relevant details copied + // from elem. We assume members are valid already. AllocationDetails::ElementHeader elem_header; elem_header.type = *elem.type.get(); elem_header.kind = *elem.type_kind.get(); @@ -2678,9 +2674,8 @@ size_t RenderScriptRuntime::PopulateElementHeaders( elem.array_size.isValid() ? *elem.array_size.get() : 0; const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); - // Copy struct into buffer and advance offset - // We assume that header_buffer has been checked for nullptr before this - // method is called + // Copy struct into buffer and advance offset We assume that header_buffer + // has been checked for nullptr before this method is called memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); offset += elem_header_size; @@ -2721,8 +2716,8 @@ size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) { return size; } -// Function copies allocation contents into a binary file. This file can then be -// loaded later into a different allocation. There is a header, FileHeader, +// Function copies allocation contents into a binary file. This file can then +// be loaded later into a different allocation. There is a header, FileHeader, // before the allocation data containing meta-data. bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const char *path, @@ -2852,8 +2847,8 @@ bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) { if (module_sp) { for (const auto &rs_module : m_rsmodules) { if (rs_module->m_module == module_sp) { - // Check if the user has enabled automatically breaking on - // all RS kernels. + // Check if the user has enabled automatically breaking on all RS + // kernels. if (m_breakAllKernels) BreakOnModuleKernels(rs_module); @@ -2975,11 +2970,10 @@ bool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines, size_t n_lines) { // The list of reduction kernels in the `.rs.info` symbol is of the form // "signature - accumulatordatasize - reduction_name - initializer_name - - // accumulator_name - combiner_name - - // outconverter_name - halter_name" - // Where a function is not explicitly named by the user, or is not generated - // by the compiler, it is named "." so the - // dash separated list should always be 8 items long + // accumulator_name - combiner_name - outconverter_name - halter_name" Where + // a function is not explicitly named by the user, or is not generated by the + // compiler, it is named "." so the dash separated list should always be 8 + // items long Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); // Skip the exportReduceCount line ++lines; @@ -3069,8 +3063,7 @@ bool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines, } // The .rs.info symbol in renderscript modules contains a string which needs to -// be parsed. -// The string is basic and is parsed on a line by line basis. +// be parsed. The string is basic and is parsed on a line by line basis. bool RSModuleDescriptor::ParseRSInfo() { assert(m_module); Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); @@ -3137,8 +3130,8 @@ bool RSModuleDescriptor::ParseRSInfo() { const auto handler = rs_info_handler(key); if (handler == -1) continue; - // getAsInteger returns `true` on an error condition - we're only interested - // in numeric fields at the moment + // getAsInteger returns `true` on an error condition - we're only + // interested in numeric fields at the moment uint64_t n_lines; if (val.getAsInteger(10, n_lines)) { LLDB_LOGV(log, "Failed to parse non-numeric '.rs.info' section {0}", @@ -3213,9 +3206,8 @@ void RenderScriptRuntime::DumpContexts(Stream &strm) const { std::map<addr_t, uint64_t> contextReferences; - // Iterate over all of the currently discovered scripts. - // Note: We cant push or pop from m_scripts inside this loop or it may - // invalidate script. + // Iterate over all of the currently discovered scripts. Note: We cant push + // or pop from m_scripts inside this loop or it may invalidate script. for (const auto &script : m_scripts) { if (!script->context.isValid()) continue; @@ -3393,15 +3385,15 @@ bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr, if ((type == Element::RS_TYPE_NONE) && (alloc->element.children.size() > 0) && (alloc->element.type_name != Element::GetFallbackStructName())) { - // Here we are dumping an Element of struct type. - // This is done using expression evaluation with the name of the - // struct type and pointer to element. - // Don't print the name of the resulting expression, since this will - // be '$[0-9]+' + // Here we are dumping an Element of struct type. This is done using + // expression evaluation with the name of the struct type and pointer + // to element. Don't print the name of the resulting expression, + // since this will be '$[0-9]+' DumpValueObjectOptions expr_options; expr_options.SetHideName(true); - // Setup expression as derefrencing a pointer cast to element address. + // Setup expression as dereferencing a pointer cast to element + // address. char expr_char_buffer[jit_max_expr_size]; int written = snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64, @@ -3435,9 +3427,9 @@ bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr, return true; } -// Function recalculates all our cached information about allocations by jitting -// the RS runtime regarding each allocation we know about. Returns true if all -// allocations could be recomputed, false otherwise. +// Function recalculates all our cached information about allocations by +// jitting the RS runtime regarding each allocation we know about. Returns true +// if all allocations could be recomputed, false otherwise. bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm, StackFrame *frame_ptr) { bool success = true; @@ -3601,8 +3593,8 @@ void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) { } } -// Given the name of a kernel this function creates a breakpoint using our -// own breakpoint resolver, and returns the Breakpoint shared pointer. +// Given the name of a kernel this function creates a breakpoint using our own +// breakpoint resolver, and returns the Breakpoint shared pointer. BreakpointSP RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) { Log *log( @@ -3743,8 +3735,8 @@ bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, log->Printf("%s - Found .expand function '%s'", __FUNCTION__, func_name.GetCString()); - // Get values for variables in .expand frame that tell us the current kernel - // invocation + // Get values for variables in .expand frame that tell us the current + // kernel invocation uint64_t x, y, z; bool found = GetFrameVarAsUnsigned(frame_sp, x_expr, x) && GetFrameVarAsUnsigned(frame_sp, y_expr, y) && @@ -3765,12 +3757,11 @@ bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, // Callback when a kernel breakpoint hits and we're looking for a specific // coordinate. Baton parameter contains a pointer to the target coordinate we -// want to break on. -// Function then checks the .expand frame for the current coordinate and breaks -// to user if it matches. -// Parameter 'break_id' is the id of the Breakpoint which made the callback. -// Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit, -// a single logical breakpoint can have multiple addresses. +// want to break on. Function then checks the .expand frame for the current +// coordinate and breaks to user if it matches. Parameter 'break_id' is the id +// of the Breakpoint which made the callback. Parameter 'break_loc_id' is the +// id for the BreakpointLocation which was hit, a single logical breakpoint can +// have multiple addresses. bool RenderScriptRuntime::KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx, user_id_t break_id, @@ -3845,12 +3836,10 @@ void RenderScriptRuntime::SetConditional(BreakpointSP bp, Stream &messages, m_conditional_breaks[bp->GetID()] = std::unique_ptr<RSCoordinate>(baton); } -// Tries to set a breakpoint on the start of a kernel, resolved using the kernel -// name. Argument 'coords', represents a three dimensional coordinate which can -// be -// used to specify a single kernel instance to break on. If this is set then we -// add a callback -// to the breakpoint. +// Tries to set a breakpoint on the start of a kernel, resolved using the +// kernel name. Argument 'coords', represents a three dimensional coordinate +// which can be used to specify a single kernel instance to break on. If this +// is set then we add a callback to the breakpoint. bool RenderScriptRuntime::PlaceBreakpointOnKernel(TargetSP target, Stream &messages, const char *name, @@ -4076,7 +4065,7 @@ void RSModuleDescriptor::Dump(Stream &strm) const { void RSGlobalDescriptor::Dump(Stream &strm) const { strm.Indent(m_name.AsCString()); VariableList var_list; - m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list); + m_module->m_module->FindGlobalVariables(m_name, nullptr, 1U, var_list); if (var_list.GetSize() == 1) { auto var = var_list.GetVariableAtIndex(0); auto type = var->GetType(); @@ -4270,8 +4259,8 @@ public: }; // Matching a comma separated list of known words is fairly - // straightforward with PCRE, but we're - // using ERE, so we end up with a little ugliness... + // straightforward with PCRE, but we're using ERE, so we end up with a + // little ugliness... RegularExpression::Match match(/* max_matches */ 5); RegularExpression match_type_list( llvm::StringRef("^([[:alpha:]]+)(,[[:alpha:]]+){0,4}$")); @@ -4661,7 +4650,7 @@ public: switch (short_option) { case 'f': - m_outfile.SetFile(option_arg, true); + m_outfile.SetFile(option_arg, true, FileSpec::Style::native); if (m_outfile.Exists()) { m_outfile.Clear(); err.SetErrorStringWithFormat("file already exists: '%s'", diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp index fe4ae21a0c39..7786d686ad6a 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp @@ -10,7 +10,6 @@ #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -20,6 +19,7 @@ #include "lldb/Symbol/VariableList.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/Args.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp index 439d372fadeb..e1f8ea648414 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp @@ -46,18 +46,15 @@ bool isRSAPICall(llvm::Module &module, llvm::CallInst *call_inst) { bool isRSLargeReturnCall(llvm::Module &module, llvm::CallInst *call_inst) { // i686 and x86_64 returns for large vectors in the RenderScript API are not - // handled as normal - // register pairs, but as a hidden sret type. This is not reflected in the - // debug info or mangled - // symbol name, and the android ABI for x86 and x86_64, (as well as the - // emulators) specifies there is - // no AVX, so bcc generates an sret function because we cannot natively return + // handled as normal register pairs, but as a hidden sret type. This is not + // reflected in the debug info or mangled symbol name, and the android ABI + // for x86 and x86_64, (as well as the emulators) specifies there is no AVX, + // so bcc generates an sret function because we cannot natively return // 256 bit vectors. // This function simply checks whether a function has a > 128bit return type. - // It is perhaps an - // unreliable heuristic, and relies on bcc not generating AVX code, so if the - // android ABI one day - // provides for AVX, this function may go out of fashion. + // It is perhaps an unreliable heuristic, and relies on bcc not generating + // AVX code, so if the android ABI one day provides for AVX, this function + // may go out of fashion. (void)module; if (!call_inst || !call_inst->getCalledFunction()) return false; @@ -88,12 +85,11 @@ bool isRSAllocationTyCallSite(llvm::Module &module, llvm::CallInst *call_inst) { llvm::FunctionType *cloneToStructRetFnTy(llvm::CallInst *call_inst) { // on x86 StructReturn functions return a pointer to the return value, rather - // than the return - // value itself [ref](http://www.agner.org/optimize/calling_conventions.pdf - // section 6). - // We create a return type by getting the pointer type of the old return type, - // and inserting a new - // initial argument of pointer type of the original return type. + // than the return value itself + // [ref](http://www.agner.org/optimize/calling_conventions.pdf section 6). We + // create a return type by getting the pointer type of the old return type, + // and inserting a new initial argument of pointer type of the original + // return type. Log *log( GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); @@ -112,8 +108,7 @@ llvm::FunctionType *cloneToStructRetFnTy(llvm::CallInst *call_inst) { orig_type->param_end()}; // This may not work if the function is somehow declared void as llvm is - // strongly typed - // and represents void* with i8* + // strongly typed and represents void* with i8* assert(!orig_type->getReturnType()->isVoidTy() && "Cannot add StructRet attribute to void function"); llvm::PointerType *return_type_ptr_type = @@ -126,8 +121,8 @@ llvm::FunctionType *cloneToStructRetFnTy(llvm::CallInst *call_inst) { if (log) log->Printf("%s - return type pointer type for StructRet clone @ '0x%p':\n", __FUNCTION__, (void *)return_type_ptr_type); - // put the the sret pointer argument in place at the beginning of the argument - // list. + // put the sret pointer argument in place at the beginning of the + // argument list. params.emplace(params.begin(), return_type_ptr_type); assert(params.size() == num_params + 1); return llvm::FunctionType::get(return_type_ptr_type, params, @@ -157,11 +152,9 @@ bool findRSCallSites(llvm::Module &module, bool fixupX86StructRetCalls(llvm::Module &module) { bool changed = false; - // changing a basic block while iterating over it seems to have some undefined - // behaviour - // going on so we find all RS callsites first, then fix them up after - // consuming - // the iterator. + // changing a basic block while iterating over it seems to have some + // undefined behaviour going on so we find all RS callsites first, then fix + // them up after consuming the iterator. std::set<llvm::CallInst *> rs_callsites; if (!findRSCallSites(module, rs_callsites, isRSLargeReturnCall)) return false; @@ -180,8 +173,7 @@ bool fixupX86StructRetCalls(llvm::Module &module) { // Allocate enough space to store the return value of the original function // we pass a pointer to this allocation as the StructRet param, and then - // copy its - // value into the lldb return value + // copy its value into the lldb return value const llvm::DataLayout &DL = module.getDataLayout(); llvm::AllocaInst *return_value_alloc = new llvm::AllocaInst( func->getReturnType(), DL.getAllocaAddrSpace(), "var_vector_return_alloc", @@ -222,19 +214,15 @@ bool fixupX86StructRetCalls(llvm::Module &module) { bool fixupRSAllocationStructByValCalls(llvm::Module &module) { // On x86_64, calls to functions in the RS runtime that take an - // `rs_allocation` type argument - // are actually handled as by-ref params by bcc, but appear to be passed by - // value by lldb (the callsite all use - // `struct byval`). - // On x86_64 Linux, struct arguments are transferred in registers if the - // struct size is no bigger than - // 128bits [ref](http://www.agner.org/optimize/calling_conventions.pdf) - // section 7.1 "Passing and returning objects" - // otherwise passed on the stack. - // an object of type `rs_allocation` is actually 256bits, so should be passed - // on the stack. However, code generated - // by bcc actually treats formal params of type `rs_allocation` as - // `rs_allocation *` so we need to convert the + // `rs_allocation` type argument are actually handled as by-ref params by + // bcc, but appear to be passed by value by lldb (the callsite all use + // `struct byval`). On x86_64 Linux, struct arguments are transferred in + // registers if the struct size is no bigger than 128bits + // [ref](http://www.agner.org/optimize/calling_conventions.pdf) section 7.1 + // "Passing and returning objects" otherwise passed on the stack. an object + // of type `rs_allocation` is actually 256bits, so should be passed on the + // stack. However, code generated by bcc actually treats formal params of + // type `rs_allocation` as `rs_allocation *` so we need to convert the // calling convention to pass by reference, and remove any hint of byval from // formal parameters. bool changed = false; diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index d7bef836d9d8..275f1fa2f70b 100644 --- a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -89,9 +89,9 @@ ObjectContainerBSDArchive::Object::Extract(const DataExtractor &data, str.assign((const char *)data.GetData(&offset, 16), 16); if (str.find("#1/") == 0) { - // If the name is longer than 16 bytes, or contains an embedded space - // then it will use this format where the length of the name is - // here and the name characters are after this header. + // If the name is longer than 16 bytes, or contains an embedded space then + // it will use this format where the length of the name is here and the + // name characters are after this header. ar_name_len = strtoul(str.c_str() + 3, &err, 10); } else { // Strip off any trailing spaces. @@ -203,8 +203,8 @@ ObjectContainerBSDArchive::Archive::FindCachedArchive( shared_ptr archive_sp; Archive::Map &archive_map = Archive::GetArchiveCache(); Archive::Map::iterator pos = archive_map.find(file); - // Don't cache a value for "archive_map.end()" below since we might - // delete an archive entry... + // Don't cache a value for "archive_map.end()" below since we might delete an + // archive entry... while (pos != archive_map.end() && pos->first == file) { bool match = true; if (arch.IsValid() && @@ -217,14 +217,13 @@ ObjectContainerBSDArchive::Archive::FindCachedArchive( if (pos->second->GetModificationTime() == time) { return pos->second; } else { - // We have a file at the same path with the same architecture - // whose modification time doesn't match. It doesn't make sense - // for us to continue to use this BSD archive since we cache only - // the object info which consists of file time info and also the - // file offset and file size of any contained objects. Since - // this information is now out of date, we won't get the correct - // information if we go and extract the file data, so we should - // remove the old and outdated entry. + // We have a file at the same path with the same architecture whose + // modification time doesn't match. It doesn't make sense for us to + // continue to use this BSD archive since we cache only the object info + // which consists of file time info and also the file offset and file + // size of any contained objects. Since this information is now out of + // date, we won't get the correct information if we go and extract the + // file data, so we should remove the old and outdated entry. archive_map.erase(pos); pos = archive_map.find(file); continue; // Continue to next iteration so we don't increment pos @@ -295,9 +294,9 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance( return nullptr; if (data_sp) { - // We have data, which means this is the first 512 bytes of the file - // Check to see if the magic bytes match and if they do, read the entire - // table of contents for the archive and cache it + // We have data, which means this is the first 512 bytes of the file Check + // to see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it DataExtractor data; data.SetData(data_sp, data_offset, length); if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data)) { @@ -389,8 +388,8 @@ bool ObjectContainerBSDArchive::ParseHeader() { m_file, module_sp->GetArchitecture(), module_sp->GetModificationTime(), m_offset, m_data); } - // Clear the m_data that contains the entire archive - // data and let our m_archive_sp hold onto the data. + // Clear the m_data that contains the entire archive data and let our + // m_archive_sp hold onto the data. m_data.Clear(); } } @@ -453,9 +452,9 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) { - // We have data, which means this is the first 512 bytes of the file - // Check to see if the magic bytes match and if they do, read the entire - // table of contents for the archive and cache it + // We have data, which means this is the first 512 bytes of the file Check to + // see if the magic bytes match and if they do, read the entire table of + // contents for the archive and cache it DataExtractor data; data.SetData(data_sp, data_offset, data_sp->GetByteSize()); if (!file || !data_sp || !ObjectContainerBSDArchive::MagicBytesMatch(data)) @@ -505,8 +504,8 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( const size_t end_count = specs.GetSize(); size_t num_specs_added = end_count - initial_count; if (set_archive_arch && num_specs_added > 0) { - // The archive was created but we didn't have an architecture - // so we need to set it + // The archive was created but we didn't have an architecture so we need to + // set it for (size_t i = initial_count; i < end_count; ++i) { ModuleSpec module_spec; if (specs.GetModuleSpecAtIndex(i, module_spec)) { diff --git a/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp index 0266bbe27e7d..4c48d641829a 100644 --- a/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp +++ b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp @@ -44,8 +44,8 @@ ObjectContainer *ObjectContainerUniversalMachO::CreateInstance( const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length) { - // We get data when we aren't trying to look for cached container information, - // so only try and look for an architecture slice if we get data + // We get data when we aren't trying to look for cached container + // information, so only try and look for an architecture slice if we get data if (data_sp) { DataExtractor data; data.SetData(data_sp, data_offset, length); @@ -81,8 +81,8 @@ ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO() {} bool ObjectContainerUniversalMachO::ParseHeader() { bool success = ParseHeader(m_data, m_header, m_fat_archs); - // We no longer need any data, we parsed all we needed to parse - // and cached it in m_header and m_fat_archs + // We no longer need any data, we parsed all we needed to parse and cached it + // in m_header and m_fat_archs m_data.Clear(); return success; } @@ -92,8 +92,7 @@ bool ObjectContainerUniversalMachO::ParseHeader( std::vector<llvm::MachO::fat_arch> &fat_archs) { bool success = false; // Store the file offset for this universal file as we could have a universal - // .o file - // in a BSD archive, or be contained in another kind of object. + // .o file in a BSD archive, or be contained in another kind of object. // Universal mach-o files always have their headers in big endian. lldb::offset_t offset = 0; data.SetByteOrder(eByteOrderBig); diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index 39ea49208700..16cbb6e5753b 100644 --- a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -140,13 +140,12 @@ bool ELFHeader::Parse(lldb_private::DataExtractor &data, if (data.GetU32(offset, &e_flags, 1) == NULL) return false; - // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and - // e_shstrndx. + // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and e_shstrndx. if (data.GetU16(offset, &e_ehsize, 6) == NULL) return false; - // Initialize e_phnum, e_shnum, and e_shstrndx with the values - // read from the header. + // Initialize e_phnum, e_shnum, and e_shstrndx with the values read from the + // header. e_phnum = e_phnum_hdr; e_shnum = e_shnum_hdr; e_shstrndx = e_shstrndx_hdr; diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.h b/source/Plugins/ObjectFile/ELF/ELFHeader.h index 4e2d3155ebb9..faaf8be99d68 100644 --- a/source/Plugins/ObjectFile/ELF/ELFHeader.h +++ b/source/Plugins/ObjectFile/ELF/ELFHeader.h @@ -8,14 +8,14 @@ //===----------------------------------------------------------------------===// // /// @file -/// @brief Generic structures and typedefs for ELF files. +/// Generic structures and typedefs for ELF files. /// /// This file provides definitions for the various entities comprising an ELF /// file. The structures are generic in the sense that they do not correspond /// to the exact binary layout of an ELF, but can be used to hold the /// information present in both 32 and 64 bit variants of the format. Each -/// entity provides a \c Parse method which is capable of transparently reading -/// both 32 and 64 bit instances of the object. +/// entity provides a \c Parse method which is capable of transparently +/// reading both 32 and 64 bit instances of the object. //===----------------------------------------------------------------------===// #ifndef liblldb_ELFHeader_h_ @@ -35,8 +35,9 @@ namespace elf { //------------------------------------------------------------------------------ /// @name ELF type definitions. /// -/// Types used to represent the various components of ELF structures. All types -/// are signed or unsigned integral types wide enough to hold values from both +/// Types used to represent the various components of ELF structures. All +/// types are signed or unsigned integral types wide enough to hold values +/// from both /// 32 and 64 bit ELF variants. //@{ typedef uint64_t elf_addr; @@ -51,10 +52,10 @@ typedef int64_t elf_sxword; //------------------------------------------------------------------------------ /// @class ELFHeader -/// @brief Generic representation of an ELF file header. +/// Generic representation of an ELF file header. /// -/// This object is used to identify the general attributes on an ELF file and to -/// locate additional sections within the file. +/// This object is used to identify the general attributes on an ELF file and +/// to locate additional sections within the file. struct ELFHeader { unsigned char e_ident[llvm::ELF::EI_NIDENT]; ///< ELF file identification. elf_addr e_entry; ///< Virtual address program entry point. @@ -118,9 +119,9 @@ struct ELFHeader { bool HasHeaderExtension() const; //-------------------------------------------------------------------------- - /// Parse an ELFHeader entry starting at position \p offset and - /// update the data extractor with the address size and byte order - /// attributes as defined by the header. + /// Parse an ELFHeader entry starting at position \p offset and update the + /// data extractor with the address size and byte order attributes as + /// defined by the header. /// /// @param[in,out] data /// The DataExtractor to read from. Updated with the address size and @@ -157,8 +158,8 @@ struct ELFHeader { private: //-------------------------------------------------------------------------- - /// Parse an ELFHeader header extension entry. This method is called - /// by Parse(). + /// Parse an ELFHeader header extension entry. This method is called by + /// Parse(). /// /// @param[in] data /// The DataExtractor to read from. @@ -167,7 +168,7 @@ private: //------------------------------------------------------------------------------ /// @class ELFSectionHeader -/// @brief Generic representation of an ELF section header. +/// Generic representation of an ELF section header. struct ELFSectionHeader { elf_word sh_name; ///< Section name string index. elf_word sh_type; ///< Section type. @@ -202,7 +203,7 @@ struct ELFSectionHeader { //------------------------------------------------------------------------------ /// @class ELFProgramHeader -/// @brief Generic representation of an ELF program header. +/// Generic representation of an ELF program header. struct ELFProgramHeader { elf_word p_type; ///< Type of program segment. elf_word p_flags; ///< Segment attributes. @@ -235,7 +236,7 @@ struct ELFProgramHeader { //------------------------------------------------------------------------------ /// @class ELFSymbol -/// @brief Represents a symbol within an ELF symbol table. +/// Represents a symbol within an ELF symbol table. struct ELFSymbol { elf_addr st_value; ///< Absolute or relocatable address. elf_xword st_size; ///< Size of the symbol or zero. @@ -288,7 +289,7 @@ struct ELFSymbol { //------------------------------------------------------------------------------ /// @class ELFDynamic -/// @brief Represents an entry in an ELF dynamic table. +/// Represents an entry in an ELF dynamic table. struct ELFDynamic { elf_sxword d_tag; ///< Type of dynamic table entry. union { @@ -318,7 +319,7 @@ struct ELFDynamic { //------------------------------------------------------------------------------ /// @class ELFRel -/// @brief Represents a relocation entry with an implicit addend. +/// Represents a relocation entry with an implicit addend. struct ELFRel { elf_addr r_offset; ///< Address of reference. elf_xword r_info; ///< symbol index and type of relocation. @@ -360,7 +361,7 @@ struct ELFRel { //------------------------------------------------------------------------------ /// @class ELFRela -/// @brief Represents a relocation entry with an explicit addend. +/// Represents a relocation entry with an explicit addend. struct ELFRela { elf_addr r_offset; ///< Address of reference. elf_xword r_info; ///< Symbol index and type of relocation. diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 36027dde0432..8701908378f1 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -113,7 +113,7 @@ const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02; //===----------------------------------------------------------------------===// /// @class ELFRelocation -/// @brief Generic wrapper for ELFRel and ELFRela. +/// Generic wrapper for ELFRel and ELFRela. /// /// This helper class allows us to parse both ELFRel and ELFRela relocation /// entries in a generic manner. @@ -240,11 +240,10 @@ bool ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) { if (data.GetU32(offset, &n_namesz, 3) == NULL) return false; - // The name field is required to be nul-terminated, and n_namesz - // includes the terminating nul in observed implementations (contrary - // to the ELF-64 spec). A special case is needed for cores generated - // by some older Linux versions, which write a note named "CORE" - // without a nul terminator and n_namesz = 4. + // The name field is required to be nul-terminated, and n_namesz includes the + // terminating nul in observed implementations (contrary to the ELF-64 spec). + // A special case is needed for cores generated by some older Linux versions, + // which write a note named "CORE" without a nul terminator and n_namesz = 4. if (n_namesz == 4) { char buf[4]; if (data.ExtractBytes(*offset, 4, data.GetByteOrder(), buf) != 4) @@ -295,7 +294,8 @@ static uint32_t mipsVariantFromElfFlags (const elf::ELFHeader &header) { uint32_t arch_variant = ArchSpec::eMIPSSubType_unknown; uint32_t fileclass = header.e_ident[EI_CLASS]; - // If there aren't any elf flags available (e.g core elf file) then return default + // If there aren't any elf flags available (e.g core elf file) then return + // default // 32 or 64 bit arch (without any architecture revision) based on object file's class. if (header.e_type == ET_CORE) { switch (fileclass) { @@ -549,8 +549,8 @@ uint32_t ObjectFileELF::CalculateELFNotesSegmentsCRC32( DataExtractor segment_data; if (segment_data.SetData(object_data, ph_offset, ph_size) != ph_size) { - // The ELF program header contained incorrect data, - // probably corefile is incomplete or corrupted. + // The ELF program header contained incorrect data, probably corefile + // is incomplete or corrupted. break; } @@ -595,8 +595,8 @@ static const char *OSABIAsCString(unsigned char osabi_byte) { // // WARNING : This function is being deprecated -// It's functionality has moved to ArchSpec::SetArchitecture -// This function is only being kept to validate the move. +// It's functionality has moved to ArchSpec::SetArchitecture This function is +// only being kept to validate the move. // // TODO : Remove this function static bool GetOsFromOSABI(unsigned char osabi_byte, @@ -674,29 +674,16 @@ size_t ObjectFileELF::GetModuleSpecifications( __FUNCTION__, file.GetPath().c_str()); } - // In case there is header extension in the section #0, the header - // we parsed above could have sentinel values for e_phnum, e_shnum, - // and e_shstrndx. In this case we need to reparse the header - // with a bigger data source to get the actual values. - size_t section_header_end = header.e_shoff + header.e_shentsize; - if (header.HasHeaderExtension() && - section_header_end > data_sp->GetByteSize()) { - data_sp = MapFileData(file, section_header_end, file_offset); - if (data_sp) { - data.SetData(data_sp); - lldb::offset_t header_offset = data_offset; - header.Parse(data, &header_offset); - } - } - - // Try to get the UUID from the section list. Usually that's at the - // end, so map the file in if we don't have it already. - section_header_end = - header.e_shoff + header.e_shnum * header.e_shentsize; - if (section_header_end > data_sp->GetByteSize()) { - data_sp = MapFileData(file, section_header_end, file_offset); - if (data_sp) - data.SetData(data_sp); + data_sp = MapFileData(file, -1, file_offset); + if (data_sp) + data.SetData(data_sp); + // In case there is header extension in the section #0, the header we + // parsed above could have sentinel values for e_phnum, e_shnum, and + // e_shstrndx. In this case we need to reparse the header with a + // bigger data source to get the actual values. + if (header.HasHeaderExtension()) { + lldb::offset_t header_offset = data_offset; + header.Parse(data, &header_offset); } uint32_t gnu_debuglink_crc = 0; @@ -733,51 +720,27 @@ size_t ObjectFileELF::GetModuleSpecifications( // contents crc32 would be too much of luxury. Thus we will need // to fallback to something simpler. if (header.e_type == llvm::ELF::ET_CORE) { - size_t program_headers_end = - header.e_phoff + header.e_phnum * header.e_phentsize; - if (program_headers_end > data_sp->GetByteSize()) { - data_sp = MapFileData(file, program_headers_end, file_offset); - if (data_sp) - data.SetData(data_sp); - } ProgramHeaderColl program_headers; GetProgramHeaderInfo(program_headers, data, header); - size_t segment_data_end = 0; - for (ProgramHeaderCollConstIter I = program_headers.begin(); - I != program_headers.end(); ++I) { - segment_data_end = std::max<unsigned long long>( - I->p_offset + I->p_filesz, segment_data_end); - } - - if (segment_data_end > data_sp->GetByteSize()) { - data_sp = MapFileData(file, segment_data_end, file_offset); - if (data_sp) - data.SetData(data_sp); - } - core_notes_crc = CalculateELFNotesSegmentsCRC32(program_headers, data); } else { - // Need to map entire file into memory to calculate the crc. - data_sp = MapFileData(file, -1, file_offset); - if (data_sp) { - data.SetData(data_sp); - gnu_debuglink_crc = calc_gnu_debuglink_crc32( - data.GetDataStart(), data.GetByteSize()); - } + gnu_debuglink_crc = calc_gnu_debuglink_crc32( + data.GetDataStart(), data.GetByteSize()); } } + using u32le = llvm::support::ulittle32_t; if (gnu_debuglink_crc) { // Use 4 bytes of crc from the .gnu_debuglink section. - uint32_t uuidt[4] = {gnu_debuglink_crc, 0, 0, 0}; - uuid.SetBytes(uuidt, sizeof(uuidt)); + u32le data(gnu_debuglink_crc); + uuid = UUID::fromData(&data, sizeof(data)); } else if (core_notes_crc) { // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make - // it look different form - // .gnu_debuglink crc followed by 4 bytes of note segments crc. - uint32_t uuidt[4] = {g_core_uuid_magic, core_notes_crc, 0, 0}; - uuid.SetBytes(uuidt, sizeof(uuidt)); + // it look different form .gnu_debuglink crc followed by 4 bytes + // of note segments crc. + u32le data[] = {u32le(g_core_uuid_magic), u32le(core_notes_crc)}; + uuid = UUID::fromData(data, sizeof(data)); } } @@ -861,21 +824,19 @@ bool ObjectFileELF::SetLoadAddress(Target &target, lldb::addr_t value, size_t sect_idx = 0; for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { - // Iterate through the object file sections to find all - // of the sections that have SHF_ALLOC in their flag bits. + // 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)) { 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 - // address - // already specified + // address already specified if (section_sp->GetType() != eSectionTypeAbsoluteAddress) load_addr += value; // On 32-bit systems the load address have to fit into 4 bytes. The - // rest of - // the bytes are the overflow from the addition. + // rest of the bytes are the overflow from the addition. if (GetAddressByteSize() == 4) load_addr &= 0xFFFFFFFF; @@ -905,24 +866,23 @@ uint32_t ObjectFileELF::GetAddressByteSize() const { AddressClass ObjectFileELF::GetAddressClass(addr_t file_addr) { Symtab *symtab = GetSymtab(); if (!symtab) - return eAddressClassUnknown; + return AddressClass::eUnknown; - // The address class is determined based on the symtab. Ask it from the object - // file what - // contains the symtab information. + // The address class is determined based on the symtab. Ask it from the + // object file what contains the symtab information. ObjectFile *symtab_objfile = symtab->GetObjectFile(); if (symtab_objfile != nullptr && symtab_objfile != this) return symtab_objfile->GetAddressClass(file_addr); auto res = ObjectFile::GetAddressClass(file_addr); - if (res != eAddressClassCode) + if (res != AddressClass::eCode) return res; auto ub = m_address_class_map.upper_bound(file_addr); if (ub == m_address_class_map.begin()) { - // No entry in the address class map before the address. Return - // default address class for an address in a code section. - return eAddressClassCode; + // No entry in the address class map before the address. Return default + // address class for an address in a code section. + return AddressClass::eCode; } // Move iterator to the address class entry preceding address @@ -950,6 +910,7 @@ bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) { if (!ParseSectionHeaders() && GetType() != ObjectFile::eTypeCoreFile) return false; + using u32le = llvm::support::ulittle32_t; if (m_uuid.IsValid()) { // We have the full build id uuid. *uuid = m_uuid; @@ -963,11 +924,11 @@ bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) { core_notes_crc = CalculateELFNotesSegmentsCRC32(m_program_headers, m_data); if (core_notes_crc) { - // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it - // look different form .gnu_debuglink crc - followed by 4 bytes of note + // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it look + // different form .gnu_debuglink crc - followed by 4 bytes of note // segments crc. - uint32_t uuidt[4] = {g_core_uuid_magic, core_notes_crc, 0, 0}; - m_uuid.SetBytes(uuidt, sizeof(uuidt)); + u32le data[] = {u32le(g_core_uuid_magic), u32le(core_notes_crc)}; + m_uuid = UUID::fromData(data, sizeof(data)); } } else { if (!m_gnu_debuglink_crc) @@ -975,8 +936,8 @@ bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) { calc_gnu_debuglink_crc32(m_data.GetDataStart(), m_data.GetByteSize()); if (m_gnu_debuglink_crc) { // Use 4 bytes of crc from the .gnu_debuglink section. - uint32_t uuidt[4] = {m_gnu_debuglink_crc, 0, 0, 0}; - m_uuid.SetBytes(uuidt, sizeof(uuidt)); + u32le data(m_gnu_debuglink_crc); + m_uuid = UUID::fromData(&data, sizeof(data)); } } @@ -1034,8 +995,8 @@ Address ObjectFileELF::GetImageInfoAddress(Target *target) { ELFDynamic &symbol = m_dynamic_symbols[i]; if (symbol.d_tag == DT_DEBUG) { - // Compute the offset as the number of previous entries plus the - // size of d_tag. + // Compute the offset as the number of previous entries plus the size of + // d_tag. addr_t offset = i * dynsym_hdr->sh_entsize + GetAddressByteSize(); return Address(dynsym_section_sp, offset); } @@ -1314,18 +1275,16 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, // Only bother processing this if we don't already have the uuid set. if (!uuid.IsValid()) { // 16 bytes is UUID|MD5, 20 bytes is SHA1. Other linkers may produce a - // build-id of a different - // length. Accept it as long as it's at least 4 bytes as it will be - // better than our own crc32. - if (note.n_descsz >= 4 && note.n_descsz <= 20) { - uint8_t uuidbuf[20]; - if (data.GetU8(&offset, &uuidbuf, note.n_descsz) == nullptr) { + // build-id of a different length. Accept it as long as it's at least + // 4 bytes as it will be better than our own crc32. + if (note.n_descsz >= 4) { + if (const uint8_t *buf = data.PeekData(offset, note.n_descsz)) { + // Save the build id as the UUID for the module. + uuid = UUID::fromData(buf, note.n_descsz); + } else { error.SetErrorString("failed to read GNU_BUILD_ID note payload"); return error; } - - // Save the build id as the UUID for the module. - uuid.SetBytes(uuidbuf, note.n_descsz); } } break; @@ -1368,8 +1327,8 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::CSR); // TODO At some point the description string could be processed. - // It could provide a steer towards the kalimba variant which - // this ELF targets. + // It could provide a steer towards the kalimba variant which this ELF + // targets. if (note.n_descsz) { const char *cstr = data.GetCStr(&offset, llvm::alignTo(note.n_descsz, 4)); @@ -1384,36 +1343,28 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, // register info arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); } else if (note.n_name == LLDB_NT_OWNER_CORE) { - // Parse the NT_FILE to look for stuff in paths to shared libraries - // As the contents look like this in a 64 bit ELF core file: - // count = 0x000000000000000a (10) - // page_size = 0x0000000000001000 (4096) - // Index start end file_ofs path - // ===== ------------------ ------------------ ------------------ - // ------------------------------------- - // [ 0] 0x0000000000400000 0x0000000000401000 0x0000000000000000 - // /tmp/a.out - // [ 1] 0x0000000000600000 0x0000000000601000 0x0000000000000000 - // /tmp/a.out - // [ 2] 0x0000000000601000 0x0000000000602000 0x0000000000000001 - // /tmp/a.out + // Parse the NT_FILE to look for stuff in paths to shared libraries As + // the contents look like this in a 64 bit ELF core file: count = + // 0x000000000000000a (10) page_size = 0x0000000000001000 (4096) Index + // start end file_ofs path ===== + // ------------------ ------------------ ------------------ + // ------------------------------------- [ 0] 0x0000000000400000 + // 0x0000000000401000 0x0000000000000000 /tmp/a.out [ 1] + // 0x0000000000600000 0x0000000000601000 0x0000000000000000 /tmp/a.out [ + // 2] 0x0000000000601000 0x0000000000602000 0x0000000000000001 /tmp/a.out // [ 3] 0x00007fa79c9ed000 0x00007fa79cba8000 0x0000000000000000 - // /lib/x86_64-linux-gnu/libc-2.19.so - // [ 4] 0x00007fa79cba8000 0x00007fa79cda7000 0x00000000000001bb - // /lib/x86_64-linux-gnu/libc-2.19.so - // [ 5] 0x00007fa79cda7000 0x00007fa79cdab000 0x00000000000001ba - // /lib/x86_64-linux-gnu/libc-2.19.so - // [ 6] 0x00007fa79cdab000 0x00007fa79cdad000 0x00000000000001be - // /lib/x86_64-linux-gnu/libc-2.19.so - // [ 7] 0x00007fa79cdb2000 0x00007fa79cdd5000 0x0000000000000000 - // /lib/x86_64-linux-gnu/ld-2.19.so - // [ 8] 0x00007fa79cfd4000 0x00007fa79cfd5000 0x0000000000000022 - // /lib/x86_64-linux-gnu/ld-2.19.so - // [ 9] 0x00007fa79cfd5000 0x00007fa79cfd6000 0x0000000000000023 - // /lib/x86_64-linux-gnu/ld-2.19.so - // In the 32 bit ELFs the count, page_size, start, end, file_ofs are - // uint32_t - // For reference: see readelf source code (in binutils). + // /lib/x86_64-linux-gnu/libc-2.19.so [ 4] 0x00007fa79cba8000 + // 0x00007fa79cda7000 0x00000000000001bb /lib/x86_64-linux- + // gnu/libc-2.19.so [ 5] 0x00007fa79cda7000 0x00007fa79cdab000 + // 0x00000000000001ba /lib/x86_64-linux-gnu/libc-2.19.so [ 6] + // 0x00007fa79cdab000 0x00007fa79cdad000 0x00000000000001be /lib/x86_64 + // -linux-gnu/libc-2.19.so [ 7] 0x00007fa79cdb2000 0x00007fa79cdd5000 + // 0x0000000000000000 /lib/x86_64-linux-gnu/ld-2.19.so [ 8] + // 0x00007fa79cfd4000 0x00007fa79cfd5000 0x0000000000000022 /lib/x86_64 + // -linux-gnu/ld-2.19.so [ 9] 0x00007fa79cfd5000 0x00007fa79cfd6000 + // 0x0000000000000023 /lib/x86_64-linux-gnu/ld-2.19.so In the 32 bit ELFs + // the count, page_size, start, end, file_ofs are uint32_t For reference: + // see readelf source code (in binutils). if (note.n_type == NT_FILE) { uint64_t count = data.GetAddress(&offset); const char *cstr; @@ -1437,15 +1388,14 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, } if (arch_spec.IsMIPS() && 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 + // 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); } } - // Calculate the offset of the next note just in case "offset" has been used - // to poke at the contents of the note data + // Calculate the offset of the next note just in case "offset" has been + // used to poke at the contents of the note data offset = note_offset + note.GetByteSize(); } @@ -1545,13 +1495,12 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, 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 might be not enough: for example - // a shared library might not have any notes at all - // and have EI_OSABI flag set to System V, - // as result the OS will be set to UnknownOS. + // 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 + // might be not enough: for example a shared library might not have any + // notes at all and have EI_OSABI flag set to System V, as result the OS + // will be set to UnknownOS. GetOsFromOSABI(header.e_ident[EI_OSABI], ostype); spec_ostype = arch_spec.GetTriple().getOS(); assert(spec_ostype == ostype); @@ -1842,6 +1791,7 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { 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"); @@ -1857,10 +1807,12 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { 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; @@ -1881,23 +1833,19 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { } // .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 + // 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_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 + // 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; @@ -1919,6 +1867,8 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { 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) @@ -1927,6 +1877,8 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { 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) @@ -1951,6 +1903,8 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { 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) | @@ -1978,13 +1932,21 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { 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". + // It does support linkscripts which (can) give rise to various + // arbitrarily named sections being "Code" or "Data". sect_type = kalimbaSectionType(m_header, header); } + // 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; + } + const uint32_t target_bytes_size = (eSectionTypeData == sect_type || eSectionTypeZeroFill == sect_type) ? m_arch_spec.GetDataByteSize() @@ -2024,46 +1986,16 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { } } - if (m_sections_ap.get()) { - if (GetType() == eTypeDebugInfo) { - static const SectionType g_sections[] = { - eSectionTypeDWARFDebugAbbrev, eSectionTypeDWARFDebugAddr, - eSectionTypeDWARFDebugAranges, eSectionTypeDWARFDebugCuIndex, - eSectionTypeDWARFDebugFrame, eSectionTypeDWARFDebugInfo, - eSectionTypeDWARFDebugLine, eSectionTypeDWARFDebugLoc, - eSectionTypeDWARFDebugMacInfo, eSectionTypeDWARFDebugPubNames, - eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges, - eSectionTypeDWARFDebugStr, eSectionTypeDWARFDebugStrOffsets, - eSectionTypeELFSymbolTable, - }; - SectionList *elf_section_list = m_sections_ap.get(); - for (size_t idx = 0; idx < sizeof(g_sections) / sizeof(g_sections[0]); - ++idx) { - SectionType section_type = g_sections[idx]; - SectionSP section_sp( - elf_section_list->FindSectionByType(section_type, true)); - if (section_sp) { - SectionSP module_section_sp( - unified_section_list.FindSectionByType(section_type, true)); - if (module_section_sp) - unified_section_list.ReplaceSection(module_section_sp->GetID(), - section_sp); - else - unified_section_list.AddSection(section_sp); - } - } - } else { - unified_section_list = *m_sections_ap; - } - } + // For eTypeDebugInfo files, the Symbol Vendor will take care of updating the + // unified section list. + if (GetType() != eTypeDebugInfo) + unified_section_list = *m_sections_ap; } // Find the arm/aarch64 mapping symbol character in the given symbol name. -// Mapping symbols have the -// form of "$<char>[.<any>]*". Additionally we recognize cases when the mapping -// symbol prefixed by -// an arbitrary string because if a symbol prefix added to each symbol in the -// object file with +// Mapping symbols have the form of "$<char>[.<any>]*". Additionally we +// recognize cases when the mapping symbol prefixed by an arbitrary string +// because if a symbol prefix added to each symbol in the object file with // objcopy then the mapping symbols are also prefixed. static char FindArmAarch64MappingSymbol(const char *symbol_name) { if (!symbol_name) @@ -2105,22 +2037,18 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, static ConstString opd_section_name(".opd"); // For ppc64 // On Android the oatdata and the oatexec symbols in the oat and odex files - // covers the full - // .text section what causes issues with displaying unusable symbol name to - // the user and very - // slow unwinding speed because the instruction emulation based unwind plans - // try to emulate all - // instructions in these symbols. Don't add these symbols to the symbol list - // as they have no - // use for the debugger and they are causing a lot of trouble. - // Filtering can't be restricted to Android because this special object file - // don't contain the - // note section specifying the environment to Android but the custom extension - // and file name - // makes it highly unlikely that this will collide with anything else. + // covers the full .text section what causes issues with displaying unusable + // symbol name to the user and very slow unwinding speed because the + // instruction emulation based unwind plans try to emulate all instructions + // in these symbols. Don't add these symbols to the symbol list as they have + // no use for the debugger and they are causing a lot of trouble. Filtering + // can't be restricted to Android because this special object file don't + // contain the note section specifying the environment to Android but the + // custom extension and file name makes it highly unlikely that this will + // collide with anything else. ConstString file_extension = m_file.GetFileNameExtension(); - bool skip_oatdata_oatexec = file_extension == ConstString("oat") || - file_extension == ConstString("odex"); + bool skip_oatdata_oatexec = file_extension == ConstString(".oat") || + file_extension == ConstString(".odex"); ArchSpec arch; GetArchitecture(arch); @@ -2129,8 +2057,8 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, module_sp ? module_sp->GetSectionList() : nullptr; // Local cache to avoid doing a FindSectionByName for each symbol. The "const - // char*" key must - // came from a ConstString object so they can be compared by pointer + // char*" key must came from a ConstString object so they can be compared by + // pointer std::unordered_map<const char *, lldb::SectionSP> section_name_to_section; unsigned i; @@ -2148,8 +2076,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, continue; // Skipping oatdata and oatexec sections if it is requested. See details - // above the - // definition of skip_oatdata_oatexec for the reasons. + // above the definition of skip_oatdata_oatexec for the reasons. if (skip_oatdata_oatexec && (::strcmp(symbol_name, "oatdata") == 0 || ::strcmp(symbol_name, "oatexec") == 0)) continue; @@ -2180,8 +2107,8 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, break; case STT_OBJECT: - // The symbol is associated with a data object, such as a variable, - // an array, etc. + // The symbol is associated with a data object, such as a variable, an + // array, etc. symbol_type = eSymbolTypeData; break; @@ -2192,13 +2119,13 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, case STT_SECTION: // The symbol is associated with a section. Symbol table entries of - // this type exist primarily for relocation and normally have - // STB_LOCAL binding. + // this type exist primarily for relocation and normally have STB_LOCAL + // binding. break; case STT_FILE: - // Conventionally, the symbol's name gives the name of the source - // file associated with the object file. A file symbol has STB_LOCAL + // Conventionally, the symbol's name gives the name of the source file + // associated with the object file. A file symbol has STB_LOCAL // binding, its section index is SHN_ABS, and it precedes the other // STB_LOCAL symbols for the file, if it is present. symbol_type = eSymbolTypeSourceFile; @@ -2240,18 +2167,18 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, switch (mapping_symbol) { case 'a': // $a[.<any>]* - marks an ARM instruction sequence - m_address_class_map[symbol.st_value] = eAddressClassCode; + m_address_class_map[symbol.st_value] = AddressClass::eCode; break; case 'b': case 't': // $b[.<any>]* - marks a THUMB BL instruction sequence // $t[.<any>]* - marks a THUMB instruction sequence m_address_class_map[symbol.st_value] = - eAddressClassCodeAlternateISA; + AddressClass::eCodeAlternateISA; break; case 'd': // $d[.<any>]* - marks a data item sequence (e.g. lit pool) - m_address_class_map[symbol.st_value] = eAddressClassData; + m_address_class_map[symbol.st_value] = AddressClass::eData; break; } } @@ -2265,11 +2192,11 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, switch (mapping_symbol) { case 'x': // $x[.<any>]* - marks an A64 instruction sequence - m_address_class_map[symbol.st_value] = eAddressClassCode; + m_address_class_map[symbol.st_value] = AddressClass::eCode; break; case 'd': // $d[.<any>]* - marks a data item sequence (e.g. lit pool) - m_address_class_map[symbol.st_value] = eAddressClassData; + m_address_class_map[symbol.st_value] = AddressClass::eData; break; } } @@ -2281,18 +2208,17 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, if (arch.GetMachine() == llvm::Triple::arm) { if (symbol_type == eSymbolTypeCode) { if (symbol.st_value & 1) { - // Subtracting 1 from the address effectively unsets - // the low order bit, which results in the address - // actually pointing to the beginning of the symbol. - // This delta will be used below in conjunction with - // symbol.st_value to produce the final symbol_value - // that we store in the symtab. + // Subtracting 1 from the address effectively unsets the low order + // bit, which results in the address actually pointing to the + // beginning of the symbol. This delta will be used below in + // conjunction with symbol.st_value to produce the final + // symbol_value that we store in the symtab. symbol_value_offset = -1; m_address_class_map[symbol.st_value ^ 1] = - eAddressClassCodeAlternateISA; + AddressClass::eCodeAlternateISA; } else { // This address is ARM - m_address_class_map[symbol.st_value] = eAddressClassCode; + m_address_class_map[symbol.st_value] = AddressClass::eCode; } } } @@ -2317,36 +2243,32 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, llvm_arch == llvm::Triple::mips64 || llvm_arch == llvm::Triple::mips64el) { if (IS_MICROMIPS(symbol.st_other)) - m_address_class_map[symbol.st_value] = eAddressClassCodeAlternateISA; + m_address_class_map[symbol.st_value] = AddressClass::eCodeAlternateISA; else if ((symbol.st_value & 1) && (symbol_type == eSymbolTypeCode)) { symbol.st_value = symbol.st_value & (~1ull); - m_address_class_map[symbol.st_value] = eAddressClassCodeAlternateISA; + m_address_class_map[symbol.st_value] = AddressClass::eCodeAlternateISA; } else { if (symbol_type == eSymbolTypeCode) - m_address_class_map[symbol.st_value] = eAddressClassCode; + m_address_class_map[symbol.st_value] = AddressClass::eCode; else if (symbol_type == eSymbolTypeData) - m_address_class_map[symbol.st_value] = eAddressClassData; + m_address_class_map[symbol.st_value] = AddressClass::eData; else - m_address_class_map[symbol.st_value] = eAddressClassUnknown; + m_address_class_map[symbol.st_value] = AddressClass::eUnknown; } } } // symbol_value_offset may contain 0 for ARM symbols or -1 for THUMB - // symbols. See above for - // more details. + // 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 && 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 covered by the - // module (represented - // through the section list). It is needed so module lookup for the - // addresses covered - // by this symbol will be successfull. This case happens for absolute - // symbols. + // section for it so the address range covered by the symbol is also + // covered by the module (represented through the section list). It is + // needed so module lookup for the addresses covered by this symbol will + // be successfull. This case happens for absolute symbols. ConstString fake_section_name(std::string(".absolute.") + symbol_name); symbol_section_sp = std::make_shared<Section>(module_sp, this, SHN_ABS, fake_section_name, @@ -2389,8 +2311,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, Mangled mangled(ConstString(symbol_bare), is_mangled); // Now append the suffix back to mangled and unmangled names. Only do it if - // the - // demangling was successful (string is not empty). + // the demangling was successful (string is not empty). if (has_suffix) { llvm::StringRef suffix = symbol_ref.substr(version_pos); @@ -2406,12 +2327,10 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, } // In ELF all symbol should have a valid size but it is not true for some - // function symbols - // coming from hand written assembly. As none of the function symbol should - // have 0 size we - // try to calculate the size for these symbols in the symtab with saying - // that their original - // size is not valid. + // function symbols coming from hand written assembly. As none of the + // function symbol should have 0 size we try to calculate the size for + // these symbols in the symtab with saying that their original size is not + // valid. bool symbol_size_valid = symbol.st_size != 0 || symbol.getType() != STT_FUNC; @@ -2440,8 +2359,7 @@ unsigned ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, lldb_private::Section *symtab) { if (symtab->GetObjectFile() != this) { // If the symbol table section is owned by a different object file, have it - // do the - // parsing. + // do the parsing. ObjectFileELF *obj_file_elf = static_cast<ObjectFileELF *>(symtab->GetObjectFile()); return obj_file_elf->ParseSymbolTable(symbol_table, start_id, symtab); @@ -2457,8 +2375,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. + // 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; Section *strtab = section_list->FindSectionByID(strtab_id).get(); @@ -2543,19 +2461,17 @@ unsigned ObjectFileELF::PLTRelocationType() { return 0; } -// Returns the size of the normal plt entries and the offset of the first normal -// plt entry. The -// 0th entry in the plt table is usually a resolution entry which have different -// size in some -// architectures then the rest of the plt entries. +// Returns the size of the normal plt entries and the offset of the first +// normal plt entry. The 0th entry in the plt table is usually a resolution +// entry which have different size in some architectures then the rest of the +// plt entries. static std::pair<uint64_t, uint64_t> GetPltEntrySizeAndOffset(const ELFSectionHeader *rel_hdr, const ELFSectionHeader *plt_hdr) { const elf_xword num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize; - // Clang 3.3 sets entsize to 4 for 32-bit binaries, but the plt entries are 16 - // bytes. - // So round the entsize up by the alignment if addralign is set. + // Clang 3.3 sets entsize to 4 for 32-bit binaries, but the plt entries are + // 16 bytes. So round the entsize up by the alignment if addralign is set. elf_xword plt_entsize = plt_hdr->sh_addralign ? llvm::alignTo(plt_hdr->sh_entsize, plt_hdr->sh_addralign) @@ -2567,12 +2483,10 @@ GetPltEntrySizeAndOffset(const ELFSectionHeader *rel_hdr, // just in case. if (plt_entsize <= 4) { // The linker haven't set the plt_hdr->sh_entsize field. Try to guess the - // size of the plt - // entries based on the number of entries and the size of the plt section - // with the - // assumption that the size of the 0th entry is at least as big as the size - // of the normal - // entries and it isn't much bigger then that. + // size of the plt entries based on the number of entries and the size of + // the plt section with the assumption that the size of the 0th entry is at + // least as big as the size of the normal entries and it isn't much bigger + // then that. if (plt_hdr->sh_addralign) plt_entsize = plt_hdr->sh_size / plt_hdr->sh_addralign / (num_relocations + 1) * plt_hdr->sh_addralign; @@ -2865,8 +2779,7 @@ Symtab *ObjectFileELF::GetSymtab() { return NULL; // We always want to use the main object file so we (hopefully) only have one - // cached copy - // of our symtab, dynamic sections, etc. + // cached copy of our symtab, dynamic sections, etc. ObjectFile *module_obj_file = module_sp->GetObjectFile(); if (module_obj_file && module_obj_file != this) return module_obj_file->GetSymtab(); @@ -2881,18 +2794,15 @@ Symtab *ObjectFileELF::GetSymtab() { // Sharable objects and dynamic executables usually have 2 distinct symbol // tables, one named ".symtab", and the other ".dynsym". The dynsym is a - // smaller - // version of the symtab that only contains global symbols. The information - // found - // in the dynsym is therefore also found in the symtab, while the reverse is - // not - // necessarily true. + // smaller version of the symtab that only contains global symbols. The + // information found in the dynsym is therefore also found in the symtab, + // while the reverse is not necessarily true. Section *symtab = section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get(); if (!symtab) { // The symtab section is non-allocable and can be stripped, so if it - // doesn't exist - // then use the dynsym section which should always be there. + // doesn't exist then use the dynsym section which should always be + // there. symtab = section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true) .get(); @@ -2939,8 +2849,7 @@ Symtab *ObjectFileELF::GetSymtab() { } // If we still don't have any symtab then create an empty instance to avoid - // do the section - // lookup next time. + // do the section lookup next time. if (m_symtab_ap == nullptr) m_symtab_ap.reset(new Symtab(this)); @@ -2954,8 +2863,8 @@ void ObjectFileELF::RelocateSection(lldb_private::Section *section) { static const char *debug_prefix = ".debug"; - // Set relocated bit so we stop getting called, regardless of - // whether we actually relocate. + // Set relocated bit so we stop getting called, regardless of whether we + // actually relocate. section->SetIsRelocated(true); // We only relocate in ELF relocatable files @@ -2998,12 +2907,10 @@ void ObjectFileELF::ParseUnwindSymbols(Symtab *symbol_table, return; // First we save the new symbols into a separate list and add them to the - // symbol table after - // we colleced all symbols we want to add. This is neccessary because adding a - // new symbol - // invalidates the internal index of the symtab what causing the next lookup - // to be slow because - // it have to recalculate the index first. + // symbol table after we colleced all symbols we want to add. This is + // neccessary because adding a new symbol invalidates the internal index of + // the symtab what causing the next lookup to be slow because it have to + // recalculate the index first. std::vector<Symbol> new_symbols; eh_frame->ForEachFDEEntries([this, symbol_table, section_list, &new_symbols]( @@ -3197,8 +3104,8 @@ void ObjectFileELF::DumpELFProgramHeader(Stream *s, //---------------------------------------------------------------------- // DumpELFProgramHeader_p_type // -// Dump an token value for the ELF program header member p_type which -// describes the type of the program header +// Dump an token value for the ELF program header member p_type which describes +// the type of the program header // ---------------------------------------------------------------------- void ObjectFileELF::DumpELFProgramHeader_p_type(Stream *s, elf_word p_type) { const int kStrWidth = 15; @@ -3369,8 +3276,7 @@ bool ObjectFileELF::GetArchitecture(ArchSpec &arch) { if (CalculateType() == eTypeCoreFile && 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 + // 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); @@ -3431,22 +3337,22 @@ ObjectFile::Strata ObjectFileELF::CalculateStrata() { case llvm::ELF::ET_EXEC: // 2 - Executable file // TODO: is there any way to detect that an executable is a kernel - // related executable by inspecting the program headers, section - // headers, symbols, or any other flag bits??? + // related executable by inspecting the program headers, section headers, + // symbols, or any other flag bits??? return eStrataUser; case llvm::ELF::ET_DYN: // 3 - Shared object file // TODO: is there any way to detect that an shared library is a kernel - // related executable by inspecting the program headers, section - // headers, symbols, or any other flag bits??? + // related executable by inspecting the program headers, section headers, + // symbols, or any other flag bits??? return eStrataUnknown; case ET_CORE: // 4 - Core file // TODO: is there any way to detect that an core file is a kernel - // related executable by inspecting the program headers, section - // headers, symbols, or any other flag bits??? + // related executable by inspecting the program headers, section headers, + // symbols, or any other flag bits??? return eStrataUnknown; default: @@ -3491,8 +3397,9 @@ size_t ObjectFileELF::ReadSectionData(Section *section, size_t(section_data.GetByteSize())}, GetByteOrder() == eByteOrderLittle, GetAddressByteSize() == 8); if (!Decompressor) { - LLDB_LOG(log, "Unable to initialize decompressor for section {0}: {1}", - section->GetName(), llvm::toString(Decompressor.takeError())); + LLDB_LOG_ERROR(log, Decompressor.takeError(), + "Unable to initialize decompressor for section {0}", + section->GetName()); return result; } auto buffer_sp = @@ -3500,10 +3407,45 @@ size_t ObjectFileELF::ReadSectionData(Section *section, if (auto Error = Decompressor->decompress( {reinterpret_cast<char *>(buffer_sp->GetBytes()), size_t(buffer_sp->GetByteSize())})) { - LLDB_LOG(log, "Decompression of section {0} failed: {1}", - section->GetName(), llvm::toString(std::move(Error))); + LLDB_LOG_ERROR(log, std::move(Error), "Decompression of section {0} failed", + section->GetName()); return result; } section_data.SetData(buffer_sp); return buffer_sp->GetByteSize(); } + +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) + return true; + } + return false; +} + +std::vector<ObjectFile::LoadableData> +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) { + LoadableData loadable; + auto header = GetProgramHeaderByIndex(i); + if (header->p_type != llvm::ELF::PT_LOAD) + continue; + loadable.Dest = should_use_paddr ? header->p_paddr : header->p_vaddr; + if (loadable.Dest == LLDB_INVALID_ADDRESS) + continue; + if (header->p_filesz == 0) + continue; + auto segment_data = GetSegmentDataByIndex(i); + loadable.Contents = llvm::ArrayRef<uint8_t>(segment_data.GetDataStart(), + segment_data.GetByteSize()); + loadables.push_back(loadable); + } + return loadables; +} diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 2909f4e52e4a..2664595fd81d 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -54,10 +54,10 @@ struct ELFNote { //------------------------------------------------------------------------------ /// @class ObjectFileELF -/// @brief Generic ELF object file reader. +/// Generic ELF object file reader. /// -/// This class provides a generic ELF (32/64 bit) reader plugin implementing the -/// ObjectFile protocol. +/// This class provides a generic ELF (32/64 bit) reader plugin implementing +/// the ObjectFile protocol. class ObjectFileELF : public lldb_private::ObjectFile { public: ~ObjectFileELF() override; @@ -113,7 +113,7 @@ public: uint32_t GetAddressByteSize() const override; - lldb::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; lldb_private::Symtab *GetSymtab() override; @@ -161,6 +161,11 @@ public: void RelocateSection(lldb_private::Section *section) override; +protected: + + std::vector<LoadableData> + GetLoadableData(lldb_private::Target &target) override; + private: ObjectFileELF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, const lldb_private::FileSpec *file, @@ -186,7 +191,7 @@ private: typedef DynamicSymbolColl::iterator DynamicSymbolCollIter; typedef DynamicSymbolColl::const_iterator DynamicSymbolCollConstIter; - typedef std::map<lldb::addr_t, lldb::AddressClass> + typedef std::map<lldb::addr_t, lldb_private::AddressClass> FileAddressToAddressClassMap; /// Version of this reader common to all plugins based on this class. @@ -255,8 +260,8 @@ private: uint64_t length, lldb_private::ArchSpec &arch_spec); - /// Parses the elf section headers and returns the uuid, debug link name, crc, - /// archspec. + /// Parses the elf section headers and returns the uuid, debug link name, + /// crc, archspec. static size_t GetSectionHeaderInfo(SectionHeaderColl §ion_headers, lldb_private::DataExtractor &object_data, const elf::ELFHeader &header, @@ -383,6 +388,8 @@ private: RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch_spec, lldb_private::UUID &uuid); + + bool AnySegmentHasPhysicalAddress(); }; #endif // liblldb_ObjectFileELF_h_ diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp index a9ab366fbf53..af040322ec52 100644 --- a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp +++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -65,8 +65,8 @@ ObjectFile *ObjectFileJIT::CreateInstance(const lldb::ModuleSP &module_sp, const FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length) { - // JIT'ed object file is backed by the ObjectFileJITDelegate, never - // read from a file + // JIT'ed object file is backed by the ObjectFileJITDelegate, never read from + // a file return NULL; } @@ -74,8 +74,8 @@ ObjectFile *ObjectFileJIT::CreateMemoryInstance(const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, const ProcessSP &process_sp, lldb::addr_t header_addr) { - // JIT'ed object file is backed by the ObjectFileJITDelegate, never - // read from memory + // JIT'ed object file is backed by the ObjectFileJITDelegate, never read from + // memory return NULL; } @@ -214,9 +214,8 @@ bool ObjectFileJIT::SetLoadAddress(Target &target, lldb::addr_t value, const size_t num_sections = section_list->GetSize(); // "value" is an offset to apply to each top level segment for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { - // Iterate through the object file sections to find all - // of the sections that size on disk (to avoid __PAGEZERO) - // and load them + // 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) { diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index e6941c9f6ed6..91e7f3353270 100644 --- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -161,8 +161,7 @@ public: case 7: case 8: case 9: - // fancy flavors that encapsulate of the above - // flavors... + // fancy flavors that encapsulate of the above flavors... break; default: @@ -393,8 +392,7 @@ public: case 7: case 8: case 9: - // fancy flavors that encapsulate of the above - // flavors... + // fancy flavors that encapsulate of the above flavors... break; default: @@ -517,8 +515,7 @@ public: } // Note that gpr.cpsr is also copied by the above loop; this loop - // technically extends - // one element past the end of the gpr.r[] array. + // technically extends one element past the end of the gpr.r[] array. SetError(GPRRegSet, Read, 0); offset = next_thread_state; @@ -1164,19 +1161,19 @@ AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) { const lldb::SectionType section_type = section_sp->GetType(); switch (section_type) { case eSectionTypeInvalid: - return eAddressClassUnknown; + return AddressClass::eUnknown; case eSectionTypeCode: if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) { - // For ARM we have a bit in the n_desc field of the symbol - // that tells us ARM/Thumb which is bit 0x0008. + // For ARM we have a bit in the n_desc field of the symbol that + // tells us ARM/Thumb which is bit 0x0008. if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB) - return eAddressClassCodeAlternateISA; + return AddressClass::eCodeAlternateISA; } - return eAddressClassCode; + return AddressClass::eCode; case eSectionTypeContainer: - return eAddressClassUnknown; + return AddressClass::eUnknown; case eSectionTypeData: case eSectionTypeDataCString: @@ -1190,7 +1187,7 @@ AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) { case eSectionTypeDataObjCMessageRefs: case eSectionTypeDataObjCCFStrings: case eSectionTypeGoSymtab: - return eAddressClassData; + return AddressClass::eData; case eSectionTypeDebug: case eSectionTypeDWARFDebugAbbrev: @@ -1203,22 +1200,25 @@ AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) { case eSectionTypeDWARFDebugLoc: case eSectionTypeDWARFDebugMacInfo: case eSectionTypeDWARFDebugMacro: + case eSectionTypeDWARFDebugNames: case eSectionTypeDWARFDebugPubNames: case eSectionTypeDWARFDebugPubTypes: case eSectionTypeDWARFDebugRanges: case eSectionTypeDWARFDebugStr: case eSectionTypeDWARFDebugStrOffsets: + case eSectionTypeDWARFDebugTypes: case eSectionTypeDWARFAppleNames: case eSectionTypeDWARFAppleTypes: case eSectionTypeDWARFAppleNamespaces: case eSectionTypeDWARFAppleObjC: - return eAddressClassDebug; + case eSectionTypeDWARFGNUDebugAltLink: + return AddressClass::eDebug; case eSectionTypeEHFrame: case eSectionTypeARMexidx: case eSectionTypeARMextab: case eSectionTypeCompactUnwind: - return eAddressClassRuntime; + return AddressClass::eRuntime; case eSectionTypeAbsoluteAddress: case eSectionTypeELFSymbolTable: @@ -1226,7 +1226,7 @@ AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) { case eSectionTypeELFRelocationEntries: case eSectionTypeELFDynamicLinkInfo: case eSectionTypeOther: - return eAddressClassUnknown; + return AddressClass::eUnknown; } } } @@ -1234,73 +1234,73 @@ AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) { const SymbolType symbol_type = symbol->GetType(); switch (symbol_type) { case eSymbolTypeAny: - return eAddressClassUnknown; + return AddressClass::eUnknown; case eSymbolTypeAbsolute: - return eAddressClassUnknown; + return AddressClass::eUnknown; case eSymbolTypeCode: case eSymbolTypeTrampoline: case eSymbolTypeResolver: if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) { - // For ARM we have a bit in the n_desc field of the symbol - // that tells us ARM/Thumb which is bit 0x0008. + // For ARM we have a bit in the n_desc field of the symbol that tells + // us ARM/Thumb which is bit 0x0008. if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB) - return eAddressClassCodeAlternateISA; + return AddressClass::eCodeAlternateISA; } - return eAddressClassCode; + return AddressClass::eCode; case eSymbolTypeData: - return eAddressClassData; + return AddressClass::eData; case eSymbolTypeRuntime: - return eAddressClassRuntime; + return AddressClass::eRuntime; case eSymbolTypeException: - return eAddressClassRuntime; + return AddressClass::eRuntime; case eSymbolTypeSourceFile: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeHeaderFile: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeObjectFile: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeCommonBlock: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeBlock: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeLocal: - return eAddressClassData; + return AddressClass::eData; case eSymbolTypeParam: - return eAddressClassData; + return AddressClass::eData; case eSymbolTypeVariable: - return eAddressClassData; + return AddressClass::eData; case eSymbolTypeVariableType: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeLineEntry: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeLineHeader: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeScopeBegin: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeScopeEnd: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeAdditional: - return eAddressClassUnknown; + return AddressClass::eUnknown; case eSymbolTypeCompiler: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeInstrumentation: - return eAddressClassDebug; + return AddressClass::eDebug; case eSymbolTypeUndefined: - return eAddressClassUnknown; + return AddressClass::eUnknown; case eSymbolTypeObjCClass: - return eAddressClassRuntime; + return AddressClass::eRuntime; case eSymbolTypeObjCMetaClass: - return eAddressClassRuntime; + return AddressClass::eRuntime; case eSymbolTypeObjCIVar: - return eAddressClassRuntime; + return AddressClass::eRuntime; case eSymbolTypeReExported: - return eAddressClassRuntime; + return AddressClass::eRuntime; } } } - return eAddressClassUnknown; + return AddressClass::eUnknown; } Symtab *ObjectFileMachO::GetSymtab() { @@ -1349,586 +1349,565 @@ bool ObjectFileMachO::IsStripped() { return false; } -void ObjectFileMachO::CreateSections(SectionList &unified_section_list) { - if (!m_sections_ap.get()) { - m_sections_ap.reset(new SectionList()); +ObjectFileMachO::EncryptedFileRanges ObjectFileMachO::GetEncryptedFileRanges() { + EncryptedFileRanges result; + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - const bool is_dsym = (m_header.filetype == MH_DSYM); - lldb::user_id_t segID = 0; - lldb::user_id_t sectID = 0; - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - uint32_t i; - const bool is_core = GetType() == eTypeCoreFile; - // bool dump_sections = false; - ModuleSP module_sp(GetModule()); - // First look up any LC_ENCRYPTION_INFO load commands - typedef RangeArray<uint32_t, uint32_t, 8> EncryptedFileRanges; - EncryptedFileRanges encrypted_file_ranges; - encryption_info_command encryption_cmd; - for (i = 0; i < m_header.ncmds; ++i) { - const lldb::offset_t load_cmd_offset = offset; - if (m_data.GetU32(&offset, &encryption_cmd, 2) == NULL) - break; + encryption_info_command encryption_cmd; + for (uint32_t i = 0; i < m_header.ncmds; ++i) { + const lldb::offset_t load_cmd_offset = offset; + if (m_data.GetU32(&offset, &encryption_cmd, 2) == NULL) + break; - // LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for - // the 3 fields we care about, so treat them the same. - if (encryption_cmd.cmd == LC_ENCRYPTION_INFO || - encryption_cmd.cmd == LC_ENCRYPTION_INFO_64) { - if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3)) { - if (encryption_cmd.cryptid != 0) { - EncryptedFileRanges::Entry entry; - entry.SetRangeBase(encryption_cmd.cryptoff); - entry.SetByteSize(encryption_cmd.cryptsize); - encrypted_file_ranges.Append(entry); - } + // LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for the + // 3 fields we care about, so treat them the same. + if (encryption_cmd.cmd == LC_ENCRYPTION_INFO || + encryption_cmd.cmd == LC_ENCRYPTION_INFO_64) { + if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3)) { + if (encryption_cmd.cryptid != 0) { + EncryptedFileRanges::Entry entry; + entry.SetRangeBase(encryption_cmd.cryptoff); + entry.SetByteSize(encryption_cmd.cryptsize); + result.Append(entry); } } - offset = load_cmd_offset + encryption_cmd.cmdsize; } + offset = load_cmd_offset + encryption_cmd.cmdsize; + } - bool section_file_addresses_changed = false; + return result; +} - offset = MachHeaderSizeFromMagic(m_header.magic); +void ObjectFileMachO::SanitizeSegmentCommand(segment_command_64 &seg_cmd, + uint32_t cmd_idx) { + if (m_length == 0 || seg_cmd.filesize == 0) + return; + + if (seg_cmd.fileoff > m_length) { + // We have a load command that says it extends past the end of the file. + // This is likely a corrupt file. We don't have any way to return an error + // condition here (this method was likely invoked from something like + // ObjectFile::GetSectionList()), so we just null out the section contents, + // and dump a message to stdout. The most common case here is core file + // debugging with a truncated file. + const char *lc_segment_name = + seg_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT"; + GetModule()->ReportWarning( + "load command %u %s has a fileoff (0x%" PRIx64 + ") that extends beyond the end of the file (0x%" PRIx64 + "), ignoring this section", + cmd_idx, lc_segment_name, seg_cmd.fileoff, m_length); + + seg_cmd.fileoff = 0; + seg_cmd.filesize = 0; + } - struct segment_command_64 load_cmd; - for (i = 0; i < m_header.ncmds; ++i) { - const lldb::offset_t load_cmd_offset = offset; - if (m_data.GetU32(&offset, &load_cmd, 2) == NULL) - break; + if (seg_cmd.fileoff + seg_cmd.filesize > m_length) { + // We have a load command that says it extends past the end of the file. + // This is likely a corrupt file. We don't have any way to return an error + // condition here (this method was likely invoked from something like + // ObjectFile::GetSectionList()), so we just null out the section contents, + // and dump a message to stdout. The most common case here is core file + // debugging with a truncated file. + const char *lc_segment_name = + seg_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT"; + GetModule()->ReportWarning( + "load command %u %s has a fileoff + filesize (0x%" PRIx64 + ") that extends beyond the end of the file (0x%" PRIx64 + "), the segment will be truncated to match", + cmd_idx, lc_segment_name, seg_cmd.fileoff + seg_cmd.filesize, m_length); + + // Truncate the length + seg_cmd.filesize = m_length - seg_cmd.fileoff; + } +} - if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64) { - if (m_data.GetU8(&offset, (uint8_t *)load_cmd.segname, 16)) { - bool add_section = true; - bool add_to_unified = true; - ConstString const_segname(load_cmd.segname, - std::min<size_t>(strlen(load_cmd.segname), - sizeof(load_cmd.segname))); - - SectionSP unified_section_sp( - unified_section_list.FindSectionByName(const_segname)); - if (is_dsym && unified_section_sp) { - if (const_segname == GetSegmentNameLINKEDIT()) { - // We need to keep the __LINKEDIT segment private to this object - // file only - add_to_unified = false; - } else { - // This is the dSYM file and this section has already been created - // by - // the object file, no need to create it. - add_section = false; - } - } - load_cmd.vmaddr = m_data.GetAddress(&offset); - load_cmd.vmsize = m_data.GetAddress(&offset); - load_cmd.fileoff = m_data.GetAddress(&offset); - load_cmd.filesize = m_data.GetAddress(&offset); - if (m_length != 0 && load_cmd.filesize != 0) { - if (load_cmd.fileoff > m_length) { - // We have a load command that says it extends past the end of the - // file. This is likely - // a corrupt file. We don't have any way to return an error - // condition here (this method - // was likely invoked from something like - // ObjectFile::GetSectionList()) -- all we can do - // is null out the SectionList vector and if a process has been - // set up, dump a message - // to stdout. The most common case here is core file debugging - // with a truncated file. - const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64 - ? "LC_SEGMENT_64" - : "LC_SEGMENT"; - module_sp->ReportWarning( - "load command %u %s has a fileoff (0x%" PRIx64 - ") that extends beyond the end of the file (0x%" PRIx64 - "), ignoring this section", - i, lc_segment_name, load_cmd.fileoff, m_length); - - load_cmd.fileoff = 0; - load_cmd.filesize = 0; - } +static uint32_t GetSegmentPermissions(const segment_command_64 &seg_cmd) { + uint32_t result = 0; + if (seg_cmd.initprot & VM_PROT_READ) + result |= ePermissionsReadable; + if (seg_cmd.initprot & VM_PROT_WRITE) + result |= ePermissionsWritable; + if (seg_cmd.initprot & VM_PROT_EXECUTE) + result |= ePermissionsExecutable; + return result; +} - if (load_cmd.fileoff + load_cmd.filesize > m_length) { - // We have a load command that says it extends past the end of the - // file. This is likely - // a corrupt file. We don't have any way to return an error - // condition here (this method - // was likely invoked from something like - // ObjectFile::GetSectionList()) -- all we can do - // is null out the SectionList vector and if a process has been - // set up, dump a message - // to stdout. The most common case here is core file debugging - // with a truncated file. - const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64 - ? "LC_SEGMENT_64" - : "LC_SEGMENT"; - GetModule()->ReportWarning( - "load command %u %s has a fileoff + filesize (0x%" PRIx64 - ") that extends beyond the end of the file (0x%" PRIx64 - "), the segment will be truncated to match", - i, lc_segment_name, load_cmd.fileoff + load_cmd.filesize, - m_length); - - // Tuncase the length - load_cmd.filesize = m_length - load_cmd.fileoff; - } - } - if (m_data.GetU32(&offset, &load_cmd.maxprot, 4)) { - uint32_t segment_permissions = 0; - if (load_cmd.initprot & VM_PROT_READ) - segment_permissions |= ePermissionsReadable; - if (load_cmd.initprot & VM_PROT_WRITE) - segment_permissions |= ePermissionsWritable; - if (load_cmd.initprot & VM_PROT_EXECUTE) - segment_permissions |= ePermissionsExecutable; - - const bool segment_is_encrypted = - (load_cmd.flags & SG_PROTECTED_VERSION_1) != 0; - - // Keep a list of mach segments around in case we need to - // get at data that isn't stored in the abstracted Sections. - m_mach_segments.push_back(load_cmd); - - // Use a segment ID of the segment index shifted left by 8 so they - // never conflict with any of the sections. - SectionSP segment_sp; - if (add_section && (const_segname || is_core)) { - segment_sp.reset(new Section( - module_sp, // Module to which this section belongs - this, // Object file to which this sections belongs - ++segID << 8, // 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_segname, // Name of this section - eSectionTypeContainer, // This section is a container of other - // sections. - load_cmd.vmaddr, // File VM address == addresses as they are - // found in the object file - load_cmd.vmsize, // VM size in bytes of this section - load_cmd.fileoff, // Offset to the data for this section in - // the file - load_cmd.filesize, // Size in bytes of this section as found - // in the file - 0, // Segments have no alignment information - load_cmd.flags)); // Flags for this section - - segment_sp->SetIsEncrypted(segment_is_encrypted); - m_sections_ap->AddSection(segment_sp); - segment_sp->SetPermissions(segment_permissions); - if (add_to_unified) - unified_section_list.AddSection(segment_sp); - } 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()) { - // 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 in the new symbol file will still be - // unslid. - // Since everything is stored as section offset, this - // shouldn't - // cause any problems. - - // Make sure we've parsed the symbol table from the - // ObjectFile before we go around changing its Sections. - module_sp->GetObjectFile()->GetSymtab(); - // eh_frame would present the same problems but we parse that - // on - // a per-function basis as-needed so it's more difficult to - // remove its use of the Sections. Realistically, the - // environments - // where this code path will be taken will not have eh_frame - // sections. - - unified_section_sp->SetFileAddress(load_cmd.vmaddr); - - // Notify the module that the section addresses have been - // changed once - // we're done so any file-address caches can be updated. - section_file_addresses_changed = true; - } - } - m_sections_ap->AddSection(unified_section_sp); - } +static lldb::SectionType GetSectionType(uint32_t flags, + ConstString section_name) { + + if (flags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS)) + return eSectionTypeCode; + + uint32_t mach_sect_type = flags & SECTION_TYPE; + static ConstString g_sect_name_objc_data("__objc_data"); + static ConstString g_sect_name_objc_msgrefs("__objc_msgrefs"); + static ConstString g_sect_name_objc_selrefs("__objc_selrefs"); + static ConstString g_sect_name_objc_classrefs("__objc_classrefs"); + static ConstString g_sect_name_objc_superrefs("__objc_superrefs"); + static ConstString g_sect_name_objc_const("__objc_const"); + static ConstString g_sect_name_objc_classlist("__objc_classlist"); + static ConstString g_sect_name_cfstring("__cfstring"); + + 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_dwarf_apple_names("__apple_names"); + static ConstString g_sect_name_dwarf_apple_types("__apple_types"); + static ConstString g_sect_name_dwarf_apple_namespaces("__apple_namespac"); + static ConstString g_sect_name_dwarf_apple_objc("__apple_objc"); + static ConstString g_sect_name_eh_frame("__eh_frame"); + static ConstString g_sect_name_compact_unwind("__unwind_info"); + static ConstString g_sect_name_text("__text"); + static ConstString g_sect_name_data("__data"); + static ConstString g_sect_name_go_symtab("__gosymtab"); + + if (section_name == g_sect_name_dwarf_debug_abbrev) + return eSectionTypeDWARFDebugAbbrev; + if (section_name == g_sect_name_dwarf_debug_aranges) + return eSectionTypeDWARFDebugAranges; + if (section_name == g_sect_name_dwarf_debug_frame) + return eSectionTypeDWARFDebugFrame; + if (section_name == g_sect_name_dwarf_debug_info) + return eSectionTypeDWARFDebugInfo; + if (section_name == g_sect_name_dwarf_debug_line) + return eSectionTypeDWARFDebugLine; + if (section_name == g_sect_name_dwarf_debug_loc) + return eSectionTypeDWARFDebugLoc; + if (section_name == g_sect_name_dwarf_debug_macinfo) + return eSectionTypeDWARFDebugMacInfo; + if (section_name == g_sect_name_dwarf_debug_names) + return eSectionTypeDWARFDebugNames; + if (section_name == g_sect_name_dwarf_debug_pubnames) + return eSectionTypeDWARFDebugPubNames; + if (section_name == g_sect_name_dwarf_debug_pubtypes) + return eSectionTypeDWARFDebugPubTypes; + if (section_name == g_sect_name_dwarf_debug_ranges) + return eSectionTypeDWARFDebugRanges; + if (section_name == g_sect_name_dwarf_debug_str) + return eSectionTypeDWARFDebugStr; + if (section_name == g_sect_name_dwarf_debug_types) + return eSectionTypeDWARFDebugTypes; + if (section_name == g_sect_name_dwarf_apple_names) + return eSectionTypeDWARFAppleNames; + if (section_name == g_sect_name_dwarf_apple_types) + return eSectionTypeDWARFAppleTypes; + if (section_name == g_sect_name_dwarf_apple_namespaces) + return eSectionTypeDWARFAppleNamespaces; + if (section_name == g_sect_name_dwarf_apple_objc) + return eSectionTypeDWARFAppleObjC; + if (section_name == g_sect_name_objc_selrefs) + return eSectionTypeDataCStringPointers; + if (section_name == g_sect_name_objc_msgrefs) + return eSectionTypeDataObjCMessageRefs; + if (section_name == g_sect_name_eh_frame) + return eSectionTypeEHFrame; + if (section_name == g_sect_name_compact_unwind) + return eSectionTypeCompactUnwind; + if (section_name == g_sect_name_cfstring) + return eSectionTypeDataObjCCFStrings; + if (section_name == g_sect_name_go_symtab) + return eSectionTypeGoSymtab; + if (section_name == g_sect_name_objc_data || + section_name == g_sect_name_objc_classrefs || + section_name == g_sect_name_objc_superrefs || + section_name == g_sect_name_objc_const || + section_name == g_sect_name_objc_classlist) { + return eSectionTypeDataPointers; + } - struct section_64 sect64; - ::memset(§64, 0, sizeof(sect64)); - // Push a section into our mach sections for the section at - // index zero (NO_SECT) if we don't have any mach sections yet... - if (m_mach_sections.empty()) - m_mach_sections.push_back(sect64); - uint32_t segment_sect_idx; - const lldb::user_id_t first_segment_sectID = sectID + 1; - - const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8; - for (segment_sect_idx = 0; segment_sect_idx < load_cmd.nsects; - ++segment_sect_idx) { - if (m_data.GetU8(&offset, (uint8_t *)sect64.sectname, - sizeof(sect64.sectname)) == NULL) - break; - if (m_data.GetU8(&offset, (uint8_t *)sect64.segname, - sizeof(sect64.segname)) == NULL) - break; - sect64.addr = m_data.GetAddress(&offset); - sect64.size = m_data.GetAddress(&offset); + switch (mach_sect_type) { + // TODO: categorize sections by other flags for regular sections + case S_REGULAR: + if (section_name == g_sect_name_text) + return eSectionTypeCode; + if (section_name == g_sect_name_data) + return eSectionTypeData; + return eSectionTypeOther; + case S_ZEROFILL: + return eSectionTypeZeroFill; + case S_CSTRING_LITERALS: // section with only literal C strings + return eSectionTypeDataCString; + case S_4BYTE_LITERALS: // section with only 4 byte literals + return eSectionTypeData4; + case S_8BYTE_LITERALS: // section with only 8 byte literals + return eSectionTypeData8; + case S_LITERAL_POINTERS: // section with only pointers to literals + return eSectionTypeDataPointers; + case S_NON_LAZY_SYMBOL_POINTERS: // section with only non-lazy symbol pointers + return eSectionTypeDataPointers; + case S_LAZY_SYMBOL_POINTERS: // section with only lazy symbol pointers + return eSectionTypeDataPointers; + case S_SYMBOL_STUBS: // section with only symbol stubs, byte size of stub in + // the reserved2 field + return eSectionTypeCode; + case S_MOD_INIT_FUNC_POINTERS: // section with only function pointers for + // initialization + return eSectionTypeDataPointers; + case S_MOD_TERM_FUNC_POINTERS: // section with only function pointers for + // termination + return eSectionTypeDataPointers; + case S_COALESCED: + return eSectionTypeOther; + case S_GB_ZEROFILL: + return eSectionTypeZeroFill; + case S_INTERPOSING: // section with only pairs of function pointers for + // interposing + return eSectionTypeCode; + case S_16BYTE_LITERALS: // section with only 16 byte literals + return eSectionTypeData16; + case S_DTRACE_DOF: + return eSectionTypeDebug; + case S_LAZY_DYLIB_SYMBOL_POINTERS: + return eSectionTypeDataPointers; + default: + return eSectionTypeOther; + } +} - if (m_data.GetU32(&offset, §64.offset, num_u32s) == NULL) - break; +struct ObjectFileMachO::SegmentParsingContext { + const EncryptedFileRanges EncryptedRanges; + lldb_private::SectionList &UnifiedList; + uint32_t NextSegmentIdx = 0; + uint32_t NextSectionIdx = 0; + bool FileAddressesChanged = false; - // Keep a list of mach sections around in case we need to - // get at data that isn't stored in the abstracted Sections. - m_mach_sections.push_back(sect64); - - if (add_section) { - ConstString section_name( - sect64.sectname, std::min<size_t>(strlen(sect64.sectname), - sizeof(sect64.sectname))); - if (!const_segname) { - // We have a segment with no name so we need to conjure up - // segments that correspond to the section's segname if there - // isn't already such a section. If there is such a section, - // we resize the section so that it spans all sections. - // We also mark these sections as fake so address matches - // don't - // hit if they land in the gaps between the child sections. - const_segname.SetTrimmedCStringWithLength( - sect64.segname, sizeof(sect64.segname)); - segment_sp = - unified_section_list.FindSectionByName(const_segname); - if (segment_sp.get()) { - Section *segment = segment_sp.get(); - // Grow the section size as needed. - const lldb::addr_t sect64_min_addr = sect64.addr; - const lldb::addr_t sect64_max_addr = - sect64_min_addr + sect64.size; - const lldb::addr_t curr_seg_byte_size = - segment->GetByteSize(); - const lldb::addr_t curr_seg_min_addr = - segment->GetFileAddress(); - const lldb::addr_t curr_seg_max_addr = - curr_seg_min_addr + curr_seg_byte_size; - if (sect64_min_addr >= curr_seg_min_addr) { - const lldb::addr_t new_seg_byte_size = - sect64_max_addr - curr_seg_min_addr; - // Only grow the section size if needed - if (new_seg_byte_size > curr_seg_byte_size) - segment->SetByteSize(new_seg_byte_size); - } else { - // We need to change the base address of the segment and - // adjust the child section offsets for all existing - // children. - const lldb::addr_t slide_amount = - sect64_min_addr - curr_seg_min_addr; - segment->Slide(slide_amount, false); - segment->GetChildren().Slide(-slide_amount, false); - segment->SetByteSize(curr_seg_max_addr - sect64_min_addr); - } + SegmentParsingContext(EncryptedFileRanges EncryptedRanges, + lldb_private::SectionList &UnifiedList) + : EncryptedRanges(std::move(EncryptedRanges)), UnifiedList(UnifiedList) {} +}; - // Grow the section size as needed. - if (sect64.offset) { - const lldb::addr_t segment_min_file_offset = - segment->GetFileOffset(); - const lldb::addr_t segment_max_file_offset = - segment_min_file_offset + segment->GetFileSize(); - - const lldb::addr_t section_min_file_offset = - sect64.offset; - const lldb::addr_t section_max_file_offset = - section_min_file_offset + sect64.size; - const lldb::addr_t new_file_offset = std::min( - section_min_file_offset, segment_min_file_offset); - const lldb::addr_t new_file_size = - std::max(section_max_file_offset, - segment_max_file_offset) - - new_file_offset; - segment->SetFileOffset(new_file_offset); - segment->SetFileSize(new_file_size); - } - } else { - // Create a fake section for the section's named segment - segment_sp.reset(new Section( - segment_sp, // Parent section - module_sp, // Module to which this section belongs - this, // Object file to which this section belongs - ++segID << 8, // 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_segname, // Name of this section - eSectionTypeContainer, // This section is a container of - // other sections. - sect64.addr, // File VM address == addresses as they are - // found in the object file - sect64.size, // VM size in bytes of this section - sect64.offset, // Offset to the data for this section in - // the file - sect64.offset ? sect64.size : 0, // Size in bytes of - // this section as - // found in the file - sect64.align, - load_cmd.flags)); // Flags for this section - segment_sp->SetIsFake(true); - segment_sp->SetPermissions(segment_permissions); - m_sections_ap->AddSection(segment_sp); - if (add_to_unified) - unified_section_list.AddSection(segment_sp); - segment_sp->SetIsEncrypted(segment_is_encrypted); - } - } - assert(segment_sp.get()); - - lldb::SectionType sect_type = eSectionTypeOther; - - if (sect64.flags & - (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS)) - sect_type = eSectionTypeCode; - else { - uint32_t mach_sect_type = sect64.flags & SECTION_TYPE; - static ConstString g_sect_name_objc_data("__objc_data"); - static ConstString g_sect_name_objc_msgrefs("__objc_msgrefs"); - static ConstString g_sect_name_objc_selrefs("__objc_selrefs"); - static ConstString g_sect_name_objc_classrefs( - "__objc_classrefs"); - static ConstString g_sect_name_objc_superrefs( - "__objc_superrefs"); - static ConstString g_sect_name_objc_const("__objc_const"); - static ConstString g_sect_name_objc_classlist( - "__objc_classlist"); - static ConstString g_sect_name_cfstring("__cfstring"); - - 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_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_apple_names( - "__apple_names"); - static ConstString g_sect_name_dwarf_apple_types( - "__apple_types"); - static ConstString g_sect_name_dwarf_apple_namespaces( - "__apple_namespac"); - static ConstString g_sect_name_dwarf_apple_objc( - "__apple_objc"); - static ConstString g_sect_name_eh_frame("__eh_frame"); - static ConstString g_sect_name_compact_unwind( - "__unwind_info"); - static ConstString g_sect_name_text("__text"); - static ConstString g_sect_name_data("__data"); - static ConstString g_sect_name_go_symtab("__gosymtab"); - - if (section_name == g_sect_name_dwarf_debug_abbrev) - sect_type = eSectionTypeDWARFDebugAbbrev; - else if (section_name == g_sect_name_dwarf_debug_aranges) - sect_type = eSectionTypeDWARFDebugAranges; - else if (section_name == g_sect_name_dwarf_debug_frame) - sect_type = eSectionTypeDWARFDebugFrame; - else if (section_name == g_sect_name_dwarf_debug_info) - sect_type = eSectionTypeDWARFDebugInfo; - else if (section_name == g_sect_name_dwarf_debug_line) - sect_type = eSectionTypeDWARFDebugLine; - else if (section_name == g_sect_name_dwarf_debug_loc) - sect_type = eSectionTypeDWARFDebugLoc; - else if (section_name == g_sect_name_dwarf_debug_macinfo) - sect_type = eSectionTypeDWARFDebugMacInfo; - else if (section_name == g_sect_name_dwarf_debug_pubnames) - sect_type = eSectionTypeDWARFDebugPubNames; - else if (section_name == g_sect_name_dwarf_debug_pubtypes) - sect_type = eSectionTypeDWARFDebugPubTypes; - else if (section_name == g_sect_name_dwarf_debug_ranges) - sect_type = eSectionTypeDWARFDebugRanges; - else if (section_name == g_sect_name_dwarf_debug_str) - sect_type = eSectionTypeDWARFDebugStr; - else if (section_name == g_sect_name_dwarf_apple_names) - sect_type = eSectionTypeDWARFAppleNames; - else if (section_name == g_sect_name_dwarf_apple_types) - sect_type = eSectionTypeDWARFAppleTypes; - else if (section_name == g_sect_name_dwarf_apple_namespaces) - sect_type = eSectionTypeDWARFAppleNamespaces; - else if (section_name == g_sect_name_dwarf_apple_objc) - sect_type = eSectionTypeDWARFAppleObjC; - else if (section_name == g_sect_name_objc_selrefs) - sect_type = eSectionTypeDataCStringPointers; - else if (section_name == g_sect_name_objc_msgrefs) - sect_type = eSectionTypeDataObjCMessageRefs; - else if (section_name == g_sect_name_eh_frame) - sect_type = eSectionTypeEHFrame; - else if (section_name == g_sect_name_compact_unwind) - sect_type = eSectionTypeCompactUnwind; - else if (section_name == g_sect_name_cfstring) - sect_type = eSectionTypeDataObjCCFStrings; - else if (section_name == g_sect_name_go_symtab) - sect_type = eSectionTypeGoSymtab; - else if (section_name == g_sect_name_objc_data || - section_name == g_sect_name_objc_classrefs || - section_name == g_sect_name_objc_superrefs || - section_name == g_sect_name_objc_const || - section_name == g_sect_name_objc_classlist) { - sect_type = eSectionTypeDataPointers; - } +void ObjectFileMachO::ProcessSegmentCommand(const load_command &load_cmd_, + lldb::offset_t offset, + uint32_t cmd_idx, + SegmentParsingContext &context) { + segment_command_64 load_cmd; + memcpy(&load_cmd, &load_cmd_, sizeof(load_cmd_)); - if (sect_type == eSectionTypeOther) { - switch (mach_sect_type) { - // TODO: categorize sections by other flags for regular - // sections - case S_REGULAR: - if (section_name == g_sect_name_text) - sect_type = eSectionTypeCode; - else if (section_name == g_sect_name_data) - sect_type = eSectionTypeData; - else - sect_type = eSectionTypeOther; - break; - case S_ZEROFILL: - sect_type = eSectionTypeZeroFill; - break; - case S_CSTRING_LITERALS: - sect_type = eSectionTypeDataCString; - break; // section with only literal C strings - case S_4BYTE_LITERALS: - sect_type = eSectionTypeData4; - break; // section with only 4 byte literals - case S_8BYTE_LITERALS: - sect_type = eSectionTypeData8; - break; // section with only 8 byte literals - case S_LITERAL_POINTERS: - sect_type = eSectionTypeDataPointers; - break; // section with only pointers to literals - case S_NON_LAZY_SYMBOL_POINTERS: - sect_type = eSectionTypeDataPointers; - break; // section with only non-lazy symbol pointers - case S_LAZY_SYMBOL_POINTERS: - sect_type = eSectionTypeDataPointers; - break; // section with only lazy symbol pointers - case S_SYMBOL_STUBS: - sect_type = eSectionTypeCode; - break; // section with only symbol stubs, byte size of - // stub in the reserved2 field - case S_MOD_INIT_FUNC_POINTERS: - sect_type = eSectionTypeDataPointers; - break; // section with only function pointers for - // initialization - case S_MOD_TERM_FUNC_POINTERS: - sect_type = eSectionTypeDataPointers; - break; // section with only function pointers for - // termination - case S_COALESCED: - sect_type = eSectionTypeOther; - break; - case S_GB_ZEROFILL: - sect_type = eSectionTypeZeroFill; - break; - case S_INTERPOSING: - sect_type = eSectionTypeCode; - break; // section with only pairs of function pointers for - // interposing - case S_16BYTE_LITERALS: - sect_type = eSectionTypeData16; - break; // section with only 16 byte literals - case S_DTRACE_DOF: - sect_type = eSectionTypeDebug; - break; - case S_LAZY_DYLIB_SYMBOL_POINTERS: - sect_type = eSectionTypeDataPointers; - break; - default: - break; - } - } - } + if (!m_data.GetU8(&offset, (uint8_t *)load_cmd.segname, 16)) + return; - SectionSP section_sp(new Section( - segment_sp, module_sp, this, ++sectID, section_name, - sect_type, sect64.addr - segment_sp->GetFileAddress(), - sect64.size, sect64.offset, - sect64.offset == 0 ? 0 : sect64.size, sect64.align, - sect64.flags)); - // Set the section to be encrypted to match the segment - - bool section_is_encrypted = false; - if (!segment_is_encrypted && load_cmd.filesize != 0) - section_is_encrypted = - encrypted_file_ranges.FindEntryThatContains( - sect64.offset) != NULL; - - section_sp->SetIsEncrypted(segment_is_encrypted || - section_is_encrypted); - section_sp->SetPermissions(segment_permissions); - segment_sp->GetChildren().AddSection(section_sp); - - if (segment_sp->IsFake()) { - segment_sp.reset(); - const_segname.Clear(); - } - } - } - if (segment_sp && is_dsym) { - if (first_segment_sectID <= sectID) { - lldb::user_id_t sect_uid; - for (sect_uid = first_segment_sectID; sect_uid <= sectID; - ++sect_uid) { - SectionSP curr_section_sp( - segment_sp->GetChildren().FindSectionByID(sect_uid)); - SectionSP next_section_sp; - if (sect_uid + 1 <= sectID) - next_section_sp = - segment_sp->GetChildren().FindSectionByID(sect_uid + 1); - - if (curr_section_sp.get()) { - if (curr_section_sp->GetByteSize() == 0) { - if (next_section_sp.get() != NULL) - curr_section_sp->SetByteSize( - next_section_sp->GetFileAddress() - - curr_section_sp->GetFileAddress()); - else - curr_section_sp->SetByteSize(load_cmd.vmsize); - } - } - } - } - } + ModuleSP module_sp = GetModule(); + const bool is_core = GetType() == eTypeCoreFile; + const bool is_dsym = (m_header.filetype == MH_DSYM); + bool add_section = true; + bool add_to_unified = true; + ConstString const_segname( + load_cmd.segname, + std::min<size_t>(strlen(load_cmd.segname), sizeof(load_cmd.segname))); + + SectionSP unified_section_sp( + context.UnifiedList.FindSectionByName(const_segname)); + if (is_dsym && unified_section_sp) { + if (const_segname == GetSegmentNameLINKEDIT()) { + // We need to keep the __LINKEDIT segment private to this object file + // only + add_to_unified = false; + } else { + // This is the dSYM file and this section has already been created by the + // object file, no need to create it. + add_section = false; + } + } + load_cmd.vmaddr = m_data.GetAddress(&offset); + load_cmd.vmsize = m_data.GetAddress(&offset); + load_cmd.fileoff = m_data.GetAddress(&offset); + load_cmd.filesize = m_data.GetAddress(&offset); + if (!m_data.GetU32(&offset, &load_cmd.maxprot, 4)) + return; + + SanitizeSegmentCommand(load_cmd, cmd_idx); + + const uint32_t segment_permissions = GetSegmentPermissions(load_cmd); + const bool segment_is_encrypted = + (load_cmd.flags & SG_PROTECTED_VERSION_1) != 0; + + // Keep a list of mach segments around in case we need to get at data that + // isn't stored in the abstracted Sections. + m_mach_segments.push_back(load_cmd); + + // Use a segment ID of the segment index shifted left by 8 so they never + // conflict with any of the sections. + SectionSP segment_sp; + if (add_section && (const_segname || is_core)) { + segment_sp.reset(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this sections belongs + ++context.NextSegmentIdx + << 8, // 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_segname, // Name of this section + eSectionTypeContainer, // This section is a container of other + // sections. + load_cmd.vmaddr, // File VM address == addresses as they are + // found in the object file + load_cmd.vmsize, // VM size in bytes of this section + load_cmd.fileoff, // Offset to the data for this section in + // the file + load_cmd.filesize, // Size in bytes of this section as found + // in the file + 0, // Segments have no alignment information + load_cmd.flags)); // Flags for this section + + segment_sp->SetIsEncrypted(segment_is_encrypted); + m_sections_ap->AddSection(segment_sp); + segment_sp->SetPermissions(segment_permissions); + if (add_to_unified) + context.UnifiedList.AddSection(segment_sp); + } 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()) { + // 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 + // in the new symbol file will still be unslid. Since everything is + // stored as section offset, this shouldn't cause any problems. + + // Make sure we've parsed the symbol table from the ObjectFile before + // we go around changing its Sections. + module_sp->GetObjectFile()->GetSymtab(); + // eh_frame would present the same problems but we parse that on a per- + // function basis as-needed so it's more difficult to remove its use of + // the Sections. Realistically, the environments where this code path + // will be taken will not have eh_frame sections. + + unified_section_sp->SetFileAddress(load_cmd.vmaddr); + + // Notify the module that the section addresses have been changed once + // we're done so any file-address caches can be updated. + context.FileAddressesChanged = true; + } + } + m_sections_ap->AddSection(unified_section_sp); + } + + struct section_64 sect64; + ::memset(§64, 0, sizeof(sect64)); + // Push a section into our mach sections for the section at index zero + // (NO_SECT) if we don't have any mach sections yet... + if (m_mach_sections.empty()) + m_mach_sections.push_back(sect64); + uint32_t segment_sect_idx; + const lldb::user_id_t first_segment_sectID = context.NextSectionIdx + 1; + + const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8; + for (segment_sect_idx = 0; segment_sect_idx < load_cmd.nsects; + ++segment_sect_idx) { + if (m_data.GetU8(&offset, (uint8_t *)sect64.sectname, + sizeof(sect64.sectname)) == NULL) + break; + if (m_data.GetU8(&offset, (uint8_t *)sect64.segname, + sizeof(sect64.segname)) == NULL) + break; + sect64.addr = m_data.GetAddress(&offset); + sect64.size = m_data.GetAddress(&offset); + + if (m_data.GetU32(&offset, §64.offset, num_u32s) == NULL) + break; + + // Keep a list of mach sections around in case we need to get at data that + // isn't stored in the abstracted Sections. + m_mach_sections.push_back(sect64); + + if (add_section) { + ConstString section_name( + sect64.sectname, + std::min<size_t>(strlen(sect64.sectname), sizeof(sect64.sectname))); + if (!const_segname) { + // We have a segment with no name so we need to conjure up segments + // that correspond to the section's segname if there isn't already such + // a section. If there is such a section, we resize the section so that + // it spans all sections. We also mark these sections as fake so + // address matches don't hit if they land in the gaps between the child + // sections. + const_segname.SetTrimmedCStringWithLength(sect64.segname, + sizeof(sect64.segname)); + segment_sp = context.UnifiedList.FindSectionByName(const_segname); + if (segment_sp.get()) { + Section *segment = segment_sp.get(); + // Grow the section size as needed. + const lldb::addr_t sect64_min_addr = sect64.addr; + const lldb::addr_t sect64_max_addr = sect64_min_addr + sect64.size; + const lldb::addr_t curr_seg_byte_size = segment->GetByteSize(); + const lldb::addr_t curr_seg_min_addr = segment->GetFileAddress(); + const lldb::addr_t curr_seg_max_addr = + curr_seg_min_addr + curr_seg_byte_size; + if (sect64_min_addr >= curr_seg_min_addr) { + const lldb::addr_t new_seg_byte_size = + sect64_max_addr - curr_seg_min_addr; + // Only grow the section size if needed + if (new_seg_byte_size > curr_seg_byte_size) + segment->SetByteSize(new_seg_byte_size); + } else { + // We need to change the base address of the segment and adjust the + // child section offsets for all existing children. + const lldb::addr_t slide_amount = + sect64_min_addr - curr_seg_min_addr; + segment->Slide(slide_amount, false); + segment->GetChildren().Slide(-slide_amount, false); + segment->SetByteSize(curr_seg_max_addr - sect64_min_addr); } + + // Grow the section size as needed. + if (sect64.offset) { + const lldb::addr_t segment_min_file_offset = + segment->GetFileOffset(); + const lldb::addr_t segment_max_file_offset = + segment_min_file_offset + segment->GetFileSize(); + + const lldb::addr_t section_min_file_offset = sect64.offset; + const lldb::addr_t section_max_file_offset = + section_min_file_offset + sect64.size; + const lldb::addr_t new_file_offset = + std::min(section_min_file_offset, segment_min_file_offset); + const lldb::addr_t new_file_size = + std::max(section_max_file_offset, segment_max_file_offset) - + new_file_offset; + segment->SetFileOffset(new_file_offset); + segment->SetFileSize(new_file_size); + } + } else { + // Create a fake section for the section's named segment + segment_sp.reset(new Section( + segment_sp, // Parent section + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + ++context.NextSegmentIdx + << 8, // 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_segname, // Name of this section + eSectionTypeContainer, // This section is a container of + // other sections. + sect64.addr, // File VM address == addresses as they are + // found in the object file + sect64.size, // VM size in bytes of this section + sect64.offset, // Offset to the data for this section in + // the file + sect64.offset ? sect64.size : 0, // Size in bytes of + // this section as + // found in the file + sect64.align, + load_cmd.flags)); // Flags for this section + segment_sp->SetIsFake(true); + segment_sp->SetPermissions(segment_permissions); + m_sections_ap->AddSection(segment_sp); + if (add_to_unified) + context.UnifiedList.AddSection(segment_sp); + segment_sp->SetIsEncrypted(segment_is_encrypted); } - } else if (load_cmd.cmd == LC_DYSYMTAB) { - m_dysymtab.cmd = load_cmd.cmd; - m_dysymtab.cmdsize = load_cmd.cmdsize; - m_data.GetU32(&offset, &m_dysymtab.ilocalsym, - (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2); } + assert(segment_sp.get()); - offset = load_cmd_offset + load_cmd.cmdsize; - } + lldb::SectionType sect_type = GetSectionType(sect64.flags, section_name); + + SectionSP section_sp(new Section( + segment_sp, module_sp, this, ++context.NextSectionIdx, section_name, + sect_type, sect64.addr - segment_sp->GetFileAddress(), sect64.size, + sect64.offset, sect64.offset == 0 ? 0 : sect64.size, sect64.align, + sect64.flags)); + // Set the section to be encrypted to match the segment + + bool section_is_encrypted = false; + if (!segment_is_encrypted && load_cmd.filesize != 0) + section_is_encrypted = context.EncryptedRanges.FindEntryThatContains( + sect64.offset) != NULL; + + section_sp->SetIsEncrypted(segment_is_encrypted || section_is_encrypted); + section_sp->SetPermissions(segment_permissions); + segment_sp->GetChildren().AddSection(section_sp); - if (section_file_addresses_changed && module_sp.get()) { - module_sp->SectionFileAddressesChanged(); + if (segment_sp->IsFake()) { + segment_sp.reset(); + const_segname.Clear(); + } + } + } + if (segment_sp && is_dsym) { + if (first_segment_sectID <= context.NextSectionIdx) { + lldb::user_id_t sect_uid; + for (sect_uid = first_segment_sectID; sect_uid <= context.NextSectionIdx; + ++sect_uid) { + SectionSP curr_section_sp( + segment_sp->GetChildren().FindSectionByID(sect_uid)); + SectionSP next_section_sp; + if (sect_uid + 1 <= context.NextSectionIdx) + next_section_sp = + segment_sp->GetChildren().FindSectionByID(sect_uid + 1); + + if (curr_section_sp.get()) { + if (curr_section_sp->GetByteSize() == 0) { + if (next_section_sp.get() != NULL) + curr_section_sp->SetByteSize(next_section_sp->GetFileAddress() - + curr_section_sp->GetFileAddress()); + else + curr_section_sp->SetByteSize(load_cmd.vmsize); + } + } + } } } } +void ObjectFileMachO::ProcessDysymtabCommand(const load_command &load_cmd, + lldb::offset_t offset) { + m_dysymtab.cmd = load_cmd.cmd; + m_dysymtab.cmdsize = load_cmd.cmdsize; + m_data.GetU32(&offset, &m_dysymtab.ilocalsym, + (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2); +} + +void ObjectFileMachO::CreateSections(SectionList &unified_section_list) { + if (m_sections_ap) + return; + + m_sections_ap.reset(new SectionList()); + + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + // bool dump_sections = false; + ModuleSP module_sp(GetModule()); + + offset = MachHeaderSizeFromMagic(m_header.magic); + + SegmentParsingContext context(GetEncryptedFileRanges(), unified_section_list); + struct load_command load_cmd; + for (uint32_t i = 0; i < m_header.ncmds; ++i) { + const lldb::offset_t load_cmd_offset = offset; + if (m_data.GetU32(&offset, &load_cmd, 2) == NULL) + break; + + if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64) + ProcessSegmentCommand(load_cmd, offset, i, context); + else if (load_cmd.cmd == LC_DYSYMTAB) + ProcessDysymtabCommand(load_cmd, offset); + + offset = load_cmd_offset + load_cmd.cmdsize; + } + + if (context.FileAddressesChanged && module_sp) + module_sp->SectionFileAddressesChanged(); +} + class MachSymtabSectionInfo { public: MachSymtabSectionInfo(SectionList *section_list) : m_section_list(section_list), m_section_infos() { - // Get the number of sections down to a depth of 1 to include - // all segments and their sections, but no other sections that - // may be added for debug map or + // Get the number of sections down to a depth of 1 to include all segments + // and their sections, but no other sections that may be added for debug + // map or m_section_infos.resize(section_list->GetNumSections(1)); } @@ -1956,9 +1935,9 @@ public: } else if (m_section_infos[n_sect].vm_range.GetByteSize() == 0 && m_section_infos[n_sect].vm_range.GetBaseAddress() == file_addr) { - // Symbol is in section with zero size, but has the same start - // address as the section. This can happen with linker symbols - // (symbols that start with the letter 'l' or 'L'. + // Symbol is in section with zero size, but has the same start address + // as the section. This can happen with linker symbols (symbols that + // start with the letter 'l' or 'L'. return m_section_infos[n_sect].section_sp; } } @@ -2108,10 +2087,13 @@ UUID ObjectFileMachO::GetSharedCacheUUID(FileSpec dyld_shared_cache, version_str[6] = '\0'; if (strcmp(version_str, "dyld_v") == 0) { offset = offsetof(struct lldb_copy_dyld_cache_header_v1, uuid); - uint8_t uuid_bytes[sizeof(uuid_t)]; - memcpy(uuid_bytes, dsc_header_data.GetData(&offset, sizeof(uuid_t)), - sizeof(uuid_t)); - dsc_uuid.SetBytes(uuid_bytes); + dsc_uuid = UUID::fromOptionalData( + dsc_header_data.GetData(&offset, sizeof(uuid_t)), sizeof(uuid_t)); + } + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS)); + if (log && dsc_uuid.IsValid()) { + log->Printf("Shared cache %s has UUID %s", dyld_shared_cache.GetPath().c_str(), + dsc_uuid.GetAsString().c_str()); } return dsc_uuid; } @@ -2267,10 +2249,9 @@ size_t ObjectFileMachO::ParseSymtab() { linkedit_section_sp->GetLoadBaseAddress(&target); if (linkedit_load_addr == LLDB_INVALID_ADDRESS) { // We might be trying to access the symbol table before the - // __LINKEDIT's load - // address has been set in the target. We can't fail to read the - // symbol table, - // so calculate the right address manually + // __LINKEDIT's load address has been set in the target. We can't + // fail to read the symbol table, so calculate the right address + // manually linkedit_load_addr = CalculateSectionLoadAddressForMemoryImage( m_memory_addr, GetMachHeaderSection(), linkedit_section_sp.get()); } @@ -2291,8 +2272,8 @@ size_t ObjectFileMachO::ParseSymtab() { process->GetAddressByteSize() == sizeof(void *)) { // This mach-o memory file is in the dyld shared cache. If this // program is not remote and this is iOS, then this process will - // share the same shared cache as the process we are debugging and - // we can read the entire __LINKEDIT from the address space in this + // share the same shared cache as the process we are debugging and we + // can read the entire __LINKEDIT from the address space in this // process. This is a needed optimization that is used for local iOS // debugging only since all shared libraries in the shared cache do // not have corresponding files that exist in the file system of the @@ -2301,22 +2282,21 @@ size_t ObjectFileMachO::ParseSymtab() { // string tables from all of the __LINKEDIT sections from the shared // libraries in the shared cache have been merged into a single large // symbol and string table. Reading all of this symbol and string - // table - // data across can slow down debug launch times, so we optimize this - // by - // reading the memory for the __LINKEDIT section from this process. - - UUID lldb_shared_cache(GetLLDBSharedCacheUUID()); - UUID process_shared_cache(GetProcessSharedCacheUUID(process)); + // table data across can slow down debug launch times, so we optimize + // this by reading the memory for the __LINKEDIT section from this + // process. + + UUID lldb_shared_cache; + addr_t lldb_shared_cache_addr; + GetLLDBSharedCacheUUID (lldb_shared_cache_addr, lldb_shared_cache); + UUID process_shared_cache; + addr_t process_shared_cache_addr; + GetProcessSharedCacheUUID(process, process_shared_cache_addr, process_shared_cache); bool use_lldb_cache = true; if (lldb_shared_cache.IsValid() && process_shared_cache.IsValid() && - lldb_shared_cache != process_shared_cache) { + (lldb_shared_cache != process_shared_cache + || process_shared_cache_addr != lldb_shared_cache_addr)) { use_lldb_cache = false; - ModuleSP module_sp(GetModule()); - if (module_sp) - module_sp->ReportWarning("shared cache in process does not match " - "lldb's own shared cache, startup will " - "be slow."); } PlatformSP platform_sp(target.GetPlatform()); @@ -2340,10 +2320,9 @@ size_t ObjectFileMachO::ParseSymtab() { if (!data_was_read) { // Always load dyld - the dynamic linker - from memory if we didn't - // find a binary anywhere else. - // lldb will not register dylib/framework/bundle loads/unloads if we - // don't have the dyld symbols, - // we force dyld to load from memory despite the user's + // find a binary anywhere else. lldb will not register + // dylib/framework/bundle loads/unloads if we don't have the dyld + // symbols, we force dyld to load from memory despite the user's // target.memory-module-load-level setting. if (memory_module_load_level == eMemoryModuleLoadLevelComplete || m_header.filetype == llvm::MachO::MH_DYLINKER) { @@ -2353,10 +2332,9 @@ size_t ObjectFileMachO::ParseSymtab() { 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, + // 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, @@ -2460,11 +2438,9 @@ size_t ObjectFileMachO::ParseSymtab() { const bool is_arm = (m_header.cputype == llvm::MachO::CPU_TYPE_ARM); // lldb works best if it knows the start address of all functions in a - // module. - // Linker symbols or debug info are normally the best source of information - // for start addr / size but - // they may be stripped in a released binary. - // Two additional sources of information exist in Mach-O binaries: + // module. Linker symbols or debug info are normally the best source of + // information for start addr / size but they may be stripped in a released + // binary. Two additional sources of information exist in Mach-O binaries: // LC_FUNCTION_STARTS - a list of ULEB128 encoded offsets of each // function's start address in the // binary, relative to the text section. @@ -2489,12 +2465,10 @@ size_t ObjectFileMachO::ParseSymtab() { } } else { // If m_type is eTypeDebugInfo, then this is a dSYM - it will have the - // load command claiming an eh_frame - // but it doesn't actually have the eh_frame content. And if we have a - // dSYM, we don't need to do any - // of this fill-in-the-missing-symbols works anyway - the debug info - // should give us all the functions in - // the module. + // load command claiming an eh_frame but it doesn't actually have the + // eh_frame content. And if we have a dSYM, we don't need to do any of + // this fill-in-the-missing-symbols works anyway - the debug info should + // give us all the functions in the module. if (text_section_sp.get() && eh_frame_section_sp.get() && m_type != eTypeDebugInfo) { DWARFCallFrameInfo eh_frame(*this, eh_frame_section_sp, @@ -2518,18 +2492,14 @@ size_t ObjectFileMachO::ParseSymtab() { const size_t function_starts_count = function_starts.GetSize(); // For user process binaries (executables, dylibs, frameworks, bundles), if - // we don't have - // LC_FUNCTION_STARTS/eh_frame section in this binary, we're going to assume - // the binary - // has been stripped. Don't allow assembly language instruction emulation - // because we don't - // know proper function start boundaries. + // we don't have LC_FUNCTION_STARTS/eh_frame section in this binary, we're + // going to assume the binary has been stripped. Don't allow assembly + // language instruction emulation because we don't know proper function + // start boundaries. // // For all other types of binaries (kernels, stand-alone bare board - // binaries, kexts), they - // may not have LC_FUNCTION_STARTS / eh_frame sections - we should not make - // any assumptions - // about them based on that. + // binaries, kexts), they may not have LC_FUNCTION_STARTS / eh_frame + // sections - we should not make any assumptions about them based on that. if (function_starts_count == 0 && CalculateStrata() == eStrataUser) { m_allow_assembly_emulation_unwind_plans = false; Log *unwind_or_symbol_log(lldb_private::GetLogIfAnyCategoriesSet( @@ -2561,8 +2531,8 @@ size_t ObjectFileMachO::ParseSymtab() { ValueToSymbolIndexMap N_FUN_addr_to_sym_idx; ValueToSymbolIndexMap N_STSYM_addr_to_sym_idx; ConstNameToSymbolIndexMap N_GSYM_name_to_sym_idx; - // Any symbols that get merged into another will get an entry - // in this map so we know + // Any symbols that get merged into another will get an entry in this map + // so we know NListIndexToSymbolIndexMap m_nlist_idx_to_sym_idx; uint32_t nlist_idx = 0; Symbol *symbol_ptr = NULL; @@ -2601,21 +2571,18 @@ size_t ObjectFileMachO::ParseSymtab() { (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) // Some recent builds of the dyld_shared_cache (hereafter: DSC) have been - // optimized by moving LOCAL - // symbols out of the memory mapped portion of the DSC. The symbol - // information has all been retained, - // but it isn't available in the normal nlist data. However, there *are* - // duplicate entries of *some* + // optimized by moving LOCAL symbols out of the memory mapped portion of + // the DSC. The symbol information has all been retained, but it isn't + // available in the normal nlist data. However, there *are* duplicate + // entries of *some* // LOCAL symbols in the normal nlist data. To handle this situation // correctly, we must first attempt // to parse any DSC unmapped symbol information. If we find any, we set a - // flag that tells the normal - // nlist parser to ignore all LOCAL symbols. + // flag that tells the normal nlist parser to ignore all LOCAL symbols. if (m_header.flags & 0x80000000u) { - // Before we can start mapping the DSC, we need to make certain the target - // process is actually - // using the cache we can find. + // Before we can start mapping the DSC, we need to make certain the + // target process is actually using the cache we can find. // Next we need to determine the correct path for the dyld shared cache. @@ -2644,14 +2611,15 @@ size_t ObjectFileMachO::ParseSymtab() { UUID dsc_uuid; UUID process_shared_cache_uuid; + addr_t process_shared_cache_base_addr; if (process) { - process_shared_cache_uuid = GetProcessSharedCacheUUID(process); + GetProcessSharedCacheUUID(process, process_shared_cache_base_addr, process_shared_cache_uuid); } - // First see if we can find an exact match for the inferior process shared - // cache UUID in - // the development or non-development shared caches on disk. + // First see if we can find an exact match for the inferior process + // shared cache UUID in the development or non-development shared caches + // on disk. if (process_shared_cache_uuid.IsValid()) { if (dsc_development_filespec.Exists()) { UUID dsc_development_uuid = GetSharedCacheUUID( @@ -2716,8 +2684,7 @@ size_t ObjectFileMachO::ParseSymtab() { if (process_shared_cache_uuid.IsValid() && dsc_uuid != process_shared_cache_uuid) { // The on-disk dyld_shared_cache file is not the same as the one in - // this - // process' memory, don't use it. + // this process' memory, don't use it. uuid_match = false; ModuleSP module_sp(GetModule()); if (module_sp) @@ -2745,11 +2712,9 @@ size_t ObjectFileMachO::ParseSymtab() { offset = 0; // The File addresses (from the in-memory Mach-O load commands) for - // the shared libraries - // in the shared library cache need to be adjusted by an offset to - // match up with the - // dylibOffset identifying field in the - // dyld_cache_local_symbol_entry's. This offset is + // the shared libraries in the shared library cache need to be + // adjusted by an offset to match up with the dylibOffset identifying + // field in the dyld_cache_local_symbol_entry's. This offset is // recorded in mapping_offset_value. const uint64_t mapping_offset_value = dsc_mapping_info_data.GetU64(&offset); @@ -2843,8 +2808,8 @@ size_t ObjectFileMachO::ParseSymtab() { if (symbol_name == NULL) { // No symbol should be NULL, even the symbols with no - // string values should have an offset zero which points - // to an empty C-string + // string values should have an offset zero which + // points to an empty C-string Host::SystemLog( Host::eSystemLogError, "error: DSC unmapped local symbol[%u] has invalid " @@ -2879,14 +2844,13 @@ size_t ObjectFileMachO::ParseSymtab() { // FIXME: In the .o files, we have a GSYM and a debug // symbol for all the ObjC data. They // have the same address, but we want to ensure that - // we always find only the real symbol, - // 'cause we don't currently correctly attribute the + // we always find only the real symbol, 'cause we + // don't currently correctly attribute the // GSYM one to the ObjCClass/Ivar/MetaClass - // symbol type. This is a temporary hack to make sure - // the ObjectiveC symbols get treated - // correctly. To do this right, we should coalesce - // all the GSYM & global symbols that have the - // same address. + // symbol type. This is a temporary hack to make + // sure the ObjectiveC symbols get treated correctly. + // To do this right, we should coalesce all the GSYM + // & global symbols that have the same address. is_gsym = true; sym[sym_idx].SetExternal(true); @@ -2940,25 +2904,24 @@ size_t ObjectFileMachO::ParseSymtab() { N_FUN_addr_to_sym_idx.insert( std::make_pair(nlist.n_value, sym_idx)); // We use the current number of symbols in the - // symbol table in lieu of - // using nlist_idx in case we ever start trimming - // entries out + // symbol table in lieu of using nlist_idx in case + // we ever start trimming entries out N_FUN_indexes.push_back(sym_idx); } else { type = eSymbolTypeCompiler; if (!N_FUN_indexes.empty()) { - // Copy the size of the function into the original + // Copy the size of the function into the + // original // STAB entry so we don't have // to hunt for it later symtab->SymbolAtIndex(N_FUN_indexes.back()) ->SetByteSize(nlist.n_value); N_FUN_indexes.pop_back(); // We don't really need the end function STAB as - // it contains the size which - // we already placed with the original symbol, so - // don't add it if we want a - // minimal symbol table + // it contains the size which we already placed + // with the original symbol, so don't add it if + // we want a minimal symbol table add_nlist = false; } } @@ -2985,19 +2948,17 @@ size_t ObjectFileMachO::ParseSymtab() { case N_BNSYM: // We use the current number of symbols in the symbol - // table in lieu of - // using nlist_idx in case we ever start trimming - // entries out - // Skip these if we want minimal symbol tables + // table in lieu of using nlist_idx in case we ever + // start trimming entries out Skip these if we want + // minimal symbol tables add_nlist = false; break; case N_ENSYM: // Set the size of the N_BNSYM to the terminating - // index of this N_ENSYM - // so that we can always skip the entire symbol if we - // need to navigate - // more quickly at the source level when parsing STABS + // index of this N_ENSYM so that we can always skip + // the entire symbol if we need to navigate more + // quickly at the source level when parsing STABS // Skip these if we want minimal symbol tables add_nlist = false; break; @@ -3031,11 +2992,9 @@ size_t ObjectFileMachO::ParseSymtab() { add_nlist = false; if (N_SO_index != UINT32_MAX) { // Set the size of the N_SO to the terminating - // index of this N_SO - // so that we can always skip the entire N_SO if - // we need to navigate - // more quickly at the source level when parsing - // STABS + // index of this N_SO so that we can always skip + // the entire N_SO if we need to navigate more + // quickly at the source level when parsing STABS symbol_ptr = symtab->SymbolAtIndex(N_SO_index); symbol_ptr->SetByteSize(sym_idx); symbol_ptr->SetSizeIsSibling(true); @@ -3048,17 +3007,16 @@ size_t ObjectFileMachO::ParseSymtab() { N_SO_index = UINT32_MAX; } else { // We use the current number of symbols in the - // symbol table in lieu of - // using nlist_idx in case we ever start trimming - // entries out + // symbol table in lieu of using nlist_idx in case + // we ever start trimming entries out const bool N_SO_has_full_path = symbol_name[0] == '/'; if (N_SO_has_full_path) { if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) { // We have two consecutive N_SO entries where - // the first contains a directory - // and the second contains a full path. + // the first contains a directory and the + // second contains a full path. sym[sym_idx - 1].GetMangled().SetValue( ConstString(symbol_name), false); m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; @@ -3072,9 +3030,9 @@ size_t ObjectFileMachO::ParseSymtab() { } else if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) { // This is usually the second N_SO entry that - // contains just the filename, - // so here we combine it with the first one if we - // are minimizing the symbol table + // contains just the filename, so here we combine + // it with the first one if we are minimizing the + // symbol table const char *so_path = sym[sym_idx - 1] .GetMangled() @@ -3088,11 +3046,11 @@ size_t ObjectFileMachO::ParseSymtab() { if (double_slash_pos != std::string::npos) { // The linker has been generating bad N_SO // entries with doubled up paths - // in the format "%s%s" where the first 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/" + // in the format "%s%s" where the first + // 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( @@ -3134,11 +3092,10 @@ size_t ObjectFileMachO::ParseSymtab() { // INCL scopes //---------------------------------------------------------------------- case N_BINCL: - // include file beginning: name,,NO_SECT,0,sum - // We use the current number of symbols in the symbol - // table in lieu of - // using nlist_idx in case we ever start trimming - // entries out + // include file beginning: name,,NO_SECT,0,sum We use + // the current number of symbols in the symbol table + // in lieu of using nlist_idx in case we ever start + // trimming entries out N_INCL_indexes.push_back(sym_idx); type = eSymbolTypeScopeBegin; break; @@ -3146,10 +3103,9 @@ size_t ObjectFileMachO::ParseSymtab() { case N_EINCL: // include file end: name,,NO_SECT,0,0 // Set the size of the N_BINCL to the terminating - // index of this N_EINCL - // so that we can always skip the entire symbol if we - // need to navigate - // more quickly at the source level when parsing STABS + // index of this N_EINCL so that we can always skip + // the entire symbol if we need to navigate more + // quickly at the source level when parsing STABS if (!N_INCL_indexes.empty()) { symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back()); @@ -3199,11 +3155,10 @@ size_t ObjectFileMachO::ParseSymtab() { // Left and Right Braces //---------------------------------------------------------------------- case N_LBRAC: - // left bracket: 0,,NO_SECT,nesting level,address - // We use the current number of symbols in the symbol - // table in lieu of - // using nlist_idx in case we ever start trimming - // entries out + // left bracket: 0,,NO_SECT,nesting level,address We + // use the current number of symbols in the symbol + // table in lieu of using nlist_idx in case we ever + // start trimming entries out symbol_section = section_info.GetSection( nlist.n_sect, nlist.n_value); N_BRAC_indexes.push_back(sym_idx); @@ -3213,10 +3168,9 @@ size_t ObjectFileMachO::ParseSymtab() { case N_RBRAC: // right bracket: 0,,NO_SECT,nesting level,address // Set the size of the N_LBRAC to the terminating - // index of this N_RBRAC - // so that we can always skip the entire symbol if we - // need to navigate - // more quickly at the source level when parsing STABS + // index of this N_RBRAC so that we can always skip + // the entire symbol if we need to navigate more + // quickly at the source level when parsing STABS symbol_section = section_info.GetSection( nlist.n_sect, nlist.n_value); if (!N_BRAC_indexes.empty()) { @@ -3240,9 +3194,8 @@ size_t ObjectFileMachO::ParseSymtab() { case N_BCOMM: // begin common: name,,NO_SECT,0,0 // We use the current number of symbols in the symbol - // table in lieu of - // using nlist_idx in case we ever start trimming - // entries out + // table in lieu of using nlist_idx in case we ever + // start trimming entries out type = eSymbolTypeScopeBegin; N_COMM_indexes.push_back(sym_idx); break; @@ -3256,10 +3209,10 @@ size_t ObjectFileMachO::ParseSymtab() { case N_ECOMM: // end common: name,,n_sect,0,0 // Set the size of the N_BCOMM to the terminating - // index of this N_ECOMM/N_ECOML - // so that we can always skip the entire symbol if we - // need to navigate - // more quickly at the source level when parsing STABS + // index of this N_ECOMM/N_ECOML so that we can + // always skip the entire symbol if we need to + // navigate more quickly at the source level when + // parsing STABS if (!N_COMM_indexes.empty()) { symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back()); @@ -3549,16 +3502,16 @@ size_t ObjectFileMachO::ParseSymtab() { function_starts_count > 0) { addr_t symbol_lookup_file_addr = nlist.n_value; // Do an exact address match for non-ARM addresses, - // else get the closest since - // the symbol might be a thumb symbol which has an - // address with bit zero set + // else get the closest since the symbol might be a + // thumb symbol which has an address with bit zero + // set FunctionStarts::Entry *func_start_entry = function_starts.FindEntry( symbol_lookup_file_addr, !is_arm); if (is_arm && func_start_entry) { // Verify that the function start address is the - // symbol address (ARM) - // or the symbol address + 1 (thumb) + // symbol address (ARM) or the symbol address + 1 + // (thumb) if (func_start_entry->addr != symbol_lookup_file_addr && func_start_entry->addr != @@ -3590,8 +3543,8 @@ size_t ObjectFileMachO::ParseSymtab() { addr_t next_symbol_file_addr = next_func_start_entry->addr; // Be sure the clear the Thumb address bit when - // we calculate the size - // from the current and next address + // we calculate the size from the current and + // next address if (is_arm) next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; @@ -3610,12 +3563,10 @@ size_t ObjectFileMachO::ParseSymtab() { if (is_debug == false) { 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 two into just the function symbol - // to avoid - // duplicate entries in the symbol table + // symbols. If we do find a match, and the name + // matches, then we can merge the two into just the + // function symbol to avoid duplicate entries in + // the symbol table std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range; @@ -3663,12 +3614,10 @@ size_t ObjectFileMachO::ParseSymtab() { type == eSymbolTypeObjCMetaClass || type == eSymbolTypeObjCIVar) { // See if we can find a N_STSYM entry for any data - // symbols. - // If we do find a match, and the name matches, then - // we - // can merge the two into just the Static symbol to - // avoid - // duplicate entries in the symbol table + // symbols. If we do find a match, and the name + // matches, then we can merge the two into just the + // Static symbol to avoid duplicate entries in the + // symbol table std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range; @@ -3710,8 +3659,8 @@ size_t ObjectFileMachO::ParseSymtab() { Mangled::ePreferMangled) .GetCString(); if (gsym_name) { - // Combine N_GSYM stab entries with the non stab - // symbol + // Combine N_GSYM stab entries with the non + // stab symbol ConstNameToSymbolIndexMap::const_iterator pos = N_GSYM_name_to_sym_idx.find(gsym_name); if (pos != N_GSYM_name_to_sym_idx.end()) { @@ -3827,9 +3776,8 @@ size_t ObjectFileMachO::ParseSymtab() { symbol_name = strtab_data.PeekCStr(nlist.n_strx); if (symbol_name == NULL) { - // No symbol should be NULL, even the symbols with no - // string values should have an offset zero which points - // to an empty C-string + // No symbol should be NULL, even the symbols with no string values + // should have an offset zero which points to an empty C-string Host::SystemLog(Host::eSystemLogError, "error: symbol[%u] has invalid string table offset " "0x%x in %s, ignoring symbol\n", @@ -3868,14 +3816,12 @@ size_t ObjectFileMachO::ParseSymtab() { // FIXME: In the .o files, we have a GSYM and a debug symbol for all // the ObjC data. They // have the same address, but we want to ensure that we always find - // only the real symbol, - // 'cause we don't currently correctly attribute the GSYM one to the - // ObjCClass/Ivar/MetaClass - // symbol type. This is a temporary hack to make sure the - // ObjectiveC symbols get treated - // correctly. To do this right, we should coalesce all the GSYM & - // global symbols that have the - // same address. + // only the real symbol, 'cause we don't currently correctly + // attribute the GSYM one to the ObjCClass/Ivar/MetaClass symbol + // type. This is a temporary hack to make sure the ObjectiveC + // symbols get treated correctly. To do this right, we should + // coalesce all the GSYM & global symbols that have the same + // address. is_gsym = true; sym[sym_idx].SetExternal(true); @@ -3922,24 +3868,21 @@ size_t ObjectFileMachO::ParseSymtab() { N_FUN_addr_to_sym_idx.insert( std::make_pair(nlist.n_value, sym_idx)); // We use the current number of symbols in the symbol table in - // lieu of - // using nlist_idx in case we ever start trimming entries out + // lieu of using nlist_idx in case we ever start trimming entries + // out N_FUN_indexes.push_back(sym_idx); } else { type = eSymbolTypeCompiler; if (!N_FUN_indexes.empty()) { - // Copy the size of the function into the original STAB entry so - // we don't have - // to hunt for it later + // Copy the size of the function into the original STAB entry + // so we don't have to hunt for it later symtab->SymbolAtIndex(N_FUN_indexes.back()) ->SetByteSize(nlist.n_value); N_FUN_indexes.pop_back(); - // We don't really need the end function STAB as it contains the - // size which - // we already placed with the original symbol, so don't add it - // if we want a - // minimal symbol table + // We don't really need the end function STAB as it contains + // the size which we already placed with the original symbol, + // so don't add it if we want a minimal symbol table add_nlist = false; } } @@ -3966,18 +3909,15 @@ size_t ObjectFileMachO::ParseSymtab() { case N_BNSYM: // We use the current number of symbols in the symbol table in lieu - // of - // using nlist_idx in case we ever start trimming entries out + // of using nlist_idx in case we ever start trimming entries out // Skip these if we want minimal symbol tables add_nlist = false; break; case N_ENSYM: // Set the size of the N_BNSYM to the terminating index of this - // N_ENSYM - // so that we can always skip the entire symbol if we need to - // navigate - // more quickly at the source level when parsing STABS + // N_ENSYM so that we can always skip the entire symbol if we need + // to navigate more quickly at the source level when parsing STABS // Skip these if we want minimal symbol tables add_nlist = false; break; @@ -4011,10 +3951,9 @@ size_t ObjectFileMachO::ParseSymtab() { add_nlist = false; if (N_SO_index != UINT32_MAX) { // Set the size of the N_SO to the terminating index of this - // N_SO - // so that we can always skip the entire N_SO if we need to - // navigate - // more quickly at the source level when parsing STABS + // N_SO so that we can always skip the entire N_SO if we need + // to navigate more quickly at the source level when parsing + // STABS symbol_ptr = symtab->SymbolAtIndex(N_SO_index); symbol_ptr->SetByteSize(sym_idx); symbol_ptr->SetSizeIsSibling(true); @@ -4027,30 +3966,27 @@ size_t ObjectFileMachO::ParseSymtab() { N_SO_index = UINT32_MAX; } else { // We use the current number of symbols in the symbol table in - // lieu of - // using nlist_idx in case we ever start trimming entries out + // lieu of using nlist_idx in case we ever start trimming entries + // out const bool N_SO_has_full_path = symbol_name[0] == '/'; if (N_SO_has_full_path) { if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) { // We have two consecutive N_SO entries where the first - // contains a directory - // and the second contains a full path. + // contains a directory and the second contains a full path. sym[sym_idx - 1].GetMangled().SetValue( ConstString(symbol_name), false); m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; add_nlist = false; } else { - // This is the first entry in a N_SO that contains a directory - // or - // a full path to the source file + // This is the first entry in a N_SO that contains a + // directory or a full path to the source file N_SO_index = sym_idx; } } else if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) { // This is usually the second N_SO entry that contains just the - // filename, - // so here we combine it with the first one if we are minimizing - // the symbol table + // filename, so here we combine it with the first one if we are + // minimizing the symbol table const char *so_path = sym[sym_idx - 1] .GetMangled() @@ -4061,16 +3997,14 @@ size_t ObjectFileMachO::ParseSymtab() { const size_t double_slash_pos = full_so_path.find("//"); if (double_slash_pos != std::string::npos) { // The linker has been generating bad N_SO entries with - // doubled up paths - // in the format "%s%s" where the first 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/" + // doubled up paths in the format "%s%s" where the first + // 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); + so_dir.SetFile(&full_so_path[double_slash_pos + 1], false, + FileSpec::Style::native); if (so_dir.Exists()) { // Trim off the incorrect path full_so_path.erase(0, double_slash_pos + 1); @@ -4106,10 +4040,9 @@ size_t ObjectFileMachO::ParseSymtab() { // INCL scopes //---------------------------------------------------------------------- case N_BINCL: - // include file beginning: name,,NO_SECT,0,sum - // We use the current number of symbols in the symbol table in lieu - // of - // using nlist_idx in case we ever start trimming entries out + // include file beginning: name,,NO_SECT,0,sum We use the current + // number of symbols in the symbol table in lieu of using nlist_idx + // in case we ever start trimming entries out N_INCL_indexes.push_back(sym_idx); type = eSymbolTypeScopeBegin; break; @@ -4117,10 +4050,8 @@ size_t ObjectFileMachO::ParseSymtab() { case N_EINCL: // include file end: name,,NO_SECT,0,0 // Set the size of the N_BINCL to the terminating index of this - // N_EINCL - // so that we can always skip the entire symbol if we need to - // navigate - // more quickly at the source level when parsing STABS + // N_EINCL so that we can always skip the entire symbol if we need + // to navigate more quickly at the source level when parsing STABS if (!N_INCL_indexes.empty()) { symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back()); symbol_ptr->SetByteSize(sym_idx + 1); @@ -4169,10 +4100,9 @@ size_t ObjectFileMachO::ParseSymtab() { // Left and Right Braces //---------------------------------------------------------------------- case N_LBRAC: - // left bracket: 0,,NO_SECT,nesting level,address - // We use the current number of symbols in the symbol table in lieu - // of - // using nlist_idx in case we ever start trimming entries out + // left bracket: 0,,NO_SECT,nesting level,address We use the + // current number of symbols in the symbol table in lieu of using + // nlist_idx in case we ever start trimming entries out symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value); N_BRAC_indexes.push_back(sym_idx); @@ -4180,12 +4110,10 @@ size_t ObjectFileMachO::ParseSymtab() { break; case N_RBRAC: - // right bracket: 0,,NO_SECT,nesting level,address - // Set the size of the N_LBRAC to the terminating index of this - // N_RBRAC - // so that we can always skip the entire symbol if we need to - // navigate - // more quickly at the source level when parsing STABS + // right bracket: 0,,NO_SECT,nesting level,address Set the size of + // the N_LBRAC to the terminating index of this N_RBRAC so that we + // can always skip the entire symbol if we need to navigate more + // quickly at the source level when parsing STABS symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value); if (!N_BRAC_indexes.empty()) { @@ -4208,8 +4136,7 @@ size_t ObjectFileMachO::ParseSymtab() { case N_BCOMM: // begin common: name,,NO_SECT,0,0 // We use the current number of symbols in the symbol table in lieu - // of - // using nlist_idx in case we ever start trimming entries out + // of using nlist_idx in case we ever start trimming entries out type = eSymbolTypeScopeBegin; N_COMM_indexes.push_back(sym_idx); break; @@ -4223,10 +4150,9 @@ size_t ObjectFileMachO::ParseSymtab() { case N_ECOMM: // end common: name,,n_sect,0,0 // Set the size of the N_BCOMM to the terminating index of this - // N_ECOMM/N_ECOML - // so that we can always skip the entire symbol if we need to - // navigate - // more quickly at the source level when parsing STABS + // N_ECOMM/N_ECOML so that we can always skip the entire symbol if + // we need to navigate more quickly at the source level when + // parsing STABS if (!N_COMM_indexes.empty()) { symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back()); symbol_ptr->SetByteSize(sym_idx + 1); @@ -4486,15 +4412,13 @@ size_t ObjectFileMachO::ParseSymtab() { if (symbol_byte_size == 0 && function_starts_count > 0) { addr_t symbol_lookup_file_addr = nlist.n_value; // Do an exact address match for non-ARM addresses, else get the - // closest since - // the symbol might be a thumb symbol which has an address with - // bit zero set + // closest since the symbol might be a thumb symbol which has an + // address with bit zero set FunctionStarts::Entry *func_start_entry = function_starts.FindEntry(symbol_lookup_file_addr, !is_arm); if (is_arm && func_start_entry) { // Verify that the function start address is the symbol address - // (ARM) - // or the symbol address + 1 (thumb) + // (ARM) or the symbol address + 1 (thumb) if (func_start_entry->addr != symbol_lookup_file_addr && func_start_entry->addr != (symbol_lookup_file_addr + 1)) { // Not the right entry, NULL it out... @@ -4515,8 +4439,7 @@ size_t ObjectFileMachO::ParseSymtab() { if (next_func_start_entry) { addr_t next_symbol_file_addr = next_func_start_entry->addr; // Be sure the clear the Thumb address bit when we calculate - // the size - // from the current and next address + // the size from the current and next address if (is_arm) next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; symbol_byte_size = std::min<lldb::addr_t>( @@ -4532,10 +4455,10 @@ size_t ObjectFileMachO::ParseSymtab() { if (is_debug == false) { 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 two into just the function symbol to avoid - // duplicate entries in the symbol table + // 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 + // two into just the function symbol to avoid duplicate entries + // in the symbol table std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range; @@ -4552,9 +4475,8 @@ size_t ObjectFileMachO::ParseSymtab() { Mangled::ePreferMangled)) { m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; // We just need the flags from the linker symbol, so put - // these flags - // into the N_FUN flags to avoid duplicate symbols in the - // symbol table + // these flags into the N_FUN flags to avoid duplicate + // symbols in the symbol table sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); sym[pos->second].SetFlags(nlist.n_type << 16 | nlist.n_desc); @@ -4577,10 +4499,10 @@ size_t ObjectFileMachO::ParseSymtab() { type == eSymbolTypeObjCClass || type == eSymbolTypeObjCMetaClass || type == eSymbolTypeObjCIVar) { - // See if we can find a N_STSYM entry for any data symbols. - // If we do find a match, and the name matches, then we - // can merge the two into just the Static symbol to avoid - // duplicate entries in the symbol table + // See if we can find a N_STSYM entry for any data symbols. If we + // do find a match, and the name matches, then we can merge the + // two into just the Static symbol to avoid duplicate entries in + // the symbol table std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range; @@ -4597,9 +4519,8 @@ size_t ObjectFileMachO::ParseSymtab() { Mangled::ePreferMangled)) { m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; // We just need the flags from the linker symbol, so put - // these flags - // into the N_STSYM flags to avoid duplicate symbols in the - // symbol table + // these flags into the N_STSYM flags to avoid duplicate + // symbols in the symbol table sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); sym[pos->second].SetFlags(nlist.n_type << 16 | nlist.n_desc); @@ -4623,16 +4544,15 @@ size_t ObjectFileMachO::ParseSymtab() { if (pos != N_GSYM_name_to_sym_idx.end()) { const uint32_t GSYM_sym_idx = pos->second; m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx; - // Copy the address, because often the N_GSYM address has an - // invalid address of zero - // when the global is a common symbol + // Copy the address, because often the N_GSYM address has + // an invalid address of zero when the global is a common + // symbol sym[GSYM_sym_idx].GetAddressRef().SetSection( symbol_section); sym[GSYM_sym_idx].GetAddressRef().SetOffset(symbol_value); // We just need the flags from the linker symbol, so put - // these flags - // into the N_GSYM flags to avoid duplicate symbols in the - // symbol table + // these flags into the N_GSYM flags to avoid duplicate + // symbols in the symbol table sym[GSYM_sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc); sym[sym_idx].Clear(); @@ -4739,8 +4659,8 @@ size_t ObjectFileMachO::ParseSymtab() { } } - // Trim our symbols down to just what we ended up with after - // removing any symbols. + // Trim our symbols down to just what we ended up with after removing any + // symbols. if (sym_idx < num_syms) { num_syms = sym_idx; sym = symtab->Resize(num_syms); @@ -4788,13 +4708,12 @@ size_t ObjectFileMachO::ParseSymtab() { m_nlist_idx_to_sym_idx.find(stub_sym_id); Symbol *stub_symbol = NULL; if (index_pos != end_index_pos) { - // We have a remapping from the original nlist index to - // a current symbol index, so just look this up by index + // We have a remapping from the original nlist index to a + // current symbol index, so just look this up by index stub_symbol = symtab->SymbolAtIndex(index_pos->second); } else { - // We need to lookup a symbol using the original nlist - // symbol index since this index is coming from the - // S_SYMBOL_STUBS + // We need to lookup a symbol using the original nlist symbol + // index since this index is coming from the S_SYMBOL_STUBS stub_symbol = symtab->FindSymbolByID(stub_sym_id); } @@ -4803,12 +4722,9 @@ size_t ObjectFileMachO::ParseSymtab() { if (stub_symbol->GetType() == eSymbolTypeUndefined) { // Change the external symbol into a trampoline that makes - // sense - // These symbols were N_UNDF N_EXT, and are useless to us, - // so we - // can re-use them so we don't have to make up a synthetic - // symbol - // for no good reason. + // sense These symbols were N_UNDF N_EXT, and are useless + // to us, so we can re-use them so we don't have to make up + // a synthetic symbol for no good reason. if (resolver_addresses.find(symbol_stub_addr) == resolver_addresses.end()) stub_symbol->SetType(eSymbolTypeTrampoline); @@ -4853,8 +4769,8 @@ size_t ObjectFileMachO::ParseSymtab() { if (!trie_entries.empty()) { for (const auto &e : trie_entries) { if (e.entry.import_name) { - // Only add indirect symbols from the Trie entries if we - // didn't have a N_INDR nlist entry for this already + // Only add indirect symbols from the Trie entries if we didn't have + // a N_INDR nlist entry for this already if (indirect_symbol_names.find(e.entry.name) == indirect_symbol_names.end()) { // Make a synthetic symbol to describe re-exported symbol. @@ -4905,7 +4821,7 @@ void ObjectFileMachO::Dump(Stream *s) { GetArchitecture(header_arch); *s << ", file = '" << m_file - << "', arch = " << header_arch.GetArchitectureName() << "\n"; + << "', triple = " << header_arch.GetTriple().getTriple() << "\n"; SectionList *sections = GetSectionList(); if (sections) @@ -4943,7 +4859,7 @@ bool ObjectFileMachO::GetUUID(const llvm::MachO::mach_header &header, if (!memcmp(uuid_bytes, opencl_uuid, 16)) return false; - uuid.SetBytes(uuid_bytes); + uuid = UUID::fromOptionalData(uuid_bytes, 16); return true; } return false; @@ -4953,6 +4869,21 @@ bool ObjectFileMachO::GetUUID(const llvm::MachO::mach_header &header, return false; } +static const char *GetOSName(uint32_t cmd) { + switch (cmd) { + case llvm::MachO::LC_VERSION_MIN_IPHONEOS: + return "ios"; + case llvm::MachO::LC_VERSION_MIN_MACOSX: + return "macosx"; + case llvm::MachO::LC_VERSION_MIN_TVOS: + return "tvos"; + case llvm::MachO::LC_VERSION_MIN_WATCHOS: + return "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, @@ -4968,16 +4899,16 @@ bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, if (header.filetype == MH_PRELOAD) { if (header.cputype == CPU_TYPE_ARM) { - // If this is a 32-bit arm binary, and it's a standalone binary, - // force the Vendor to Apple so we don't accidentally pick up - // the generic armv7 ABI at runtime. Apple's armv7 ABI always uses - // r7 for the frame pointer register; most other armv7 ABIs use a - // combination of r7 and r11. + // If this is a 32-bit arm binary, and it's a standalone binary, force + // the Vendor to Apple so we don't accidentally pick up the generic + // armv7 ABI at runtime. Apple's armv7 ABI always uses r7 for the + // frame pointer register; most other armv7 ABIs use a combination of + // r7 and r11. triple.setVendor(llvm::Triple::Apple); } else { // Set vendor to an unspecified unknown or a "*" so it can match any - // vendor - // This is required for correct behavior of EFI debugging on x86_64 + // vendor This is required for correct behavior of EFI debugging on + // x86_64 triple.setVendor(llvm::Triple::UnknownVendor); triple.setVendorName(llvm::StringRef()); } @@ -4991,23 +4922,29 @@ bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, 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: - triple.setOS(llvm::Triple::IOS); - return true; - case llvm::MachO::LC_VERSION_MIN_MACOSX: - triple.setOS(llvm::Triple::MacOSX); - return true; - case llvm::MachO::LC_VERSION_MIN_TVOS: - triple.setOS(llvm::Triple::TvOS); - return true; - case llvm::MachO::LC_VERSION_MIN_WATCHOS: - triple.setOS(llvm::Triple::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; + triple.setOSName(os.str()); return true; - default: break; } @@ -5048,7 +4985,8 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { 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 + // 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; @@ -5112,12 +5050,9 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { for (const auto &rpath : rpath_paths) { std::string path = rpath; 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. + // 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); - // Remove any redundant parts of the path (like "../foo") since - // LC_RPATH values often contain "..". - file_spec = file_spec.GetNormalizedPath(); if (file_spec.Exists() && files.AppendIfUnique(file_spec)) { count++; break; @@ -5135,11 +5070,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); - file_spec = file_spec.GetNormalizedPath(); - if (file_spec.Exists() && files.AppendIfUnique(file_spec)) { + if (file_spec.Exists() && files.AppendIfUnique(file_spec)) count++; - break; - } } } } @@ -5148,17 +5080,15 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { lldb_private::Address ObjectFileMachO::GetEntryPointAddress() { // If the object file is not an executable it can't hold the entry point. - // m_entry_point_address - // is initialized to an invalid address, so we can just return that. - // If m_entry_point_address is valid it means we've found it already, so - // return the cached value. + // m_entry_point_address is initialized to an invalid address, so we can just + // return that. If m_entry_point_address is valid it means we've found it + // already, so return the cached value. if (!IsExecutable() || m_entry_point_address.IsValid()) return m_entry_point_address; // Otherwise, look for the UnixThread or Thread command. The data for the - // Thread command is given in - // /usr/include/mach-o.h, but it is basically: + // Thread command is given in /usr/include/mach-o.h, but it is basically: // // uint32_t flavor - this is the flavor argument you would pass to // thread_get_state @@ -5172,9 +5102,9 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() { // FIXME: We will need to have a "RegisterContext data provider" class at some // point that can get all the registers // out of data in this form & attach them to a given thread. That should - // underlie the MacOS X User process plugin, - // and we'll also need it for the MacOS X Core File process plugin. When we - // have that we can also use it here. + // underlie the MacOS X User process plugin, and we'll also need it for the + // MacOS X Core File process plugin. When we have that we can also use it + // here. // // For now we hard-code the offsets and flavors we need: // @@ -5279,16 +5209,14 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() { if (start_address != LLDB_INVALID_ADDRESS) { // We got the start address from the load commands, so now resolve that - // address in the sections - // of this ObjectFile: + // address in the sections of this ObjectFile: if (!m_entry_point_address.ResolveAddressUsingFileSections( start_address, GetSectionList())) { m_entry_point_address.Clear(); } } else { // We couldn't read the UnixThread load command - maybe it wasn't there. - // As a fallback look for the - // "start" symbol in the main executable. + // As a fallback look for the "start" symbol in the main executable. ModuleSP module_sp(GetModule()); @@ -5353,8 +5281,8 @@ std::string ObjectFileMachO::GetIdentifierString() { if (module_sp) { std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - // First, look over the load commands for an LC_NOTE load command - // with data_owner string "kern ver str" & use that if found. + // First, look over the load commands for an LC_NOTE load command with + // data_owner string "kern ver str" & use that if found. lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); for (uint32_t i = 0; i < m_header.ncmds; ++i) { const uint32_t cmd_offset = offset; @@ -5370,8 +5298,8 @@ std::string ObjectFileMachO::GetIdentifierString() { uint64_t fileoff = m_data.GetU64_unchecked (&offset); uint64_t size = m_data.GetU64_unchecked (&offset); - // "kern ver str" has a uint32_t version and then a - // nul terminated c-string. + // "kern ver str" has a uint32_t version and then a nul terminated + // c-string. if (strcmp ("kern ver str", data_owner) == 0) { offset = fileoff; @@ -5398,8 +5326,8 @@ std::string ObjectFileMachO::GetIdentifierString() { offset = cmd_offset + lc.cmdsize; } - // Second, make a pass over the load commands looking for an - // obsolete LC_IDENT load command. + // Second, make a pass over the load commands looking for an obsolete + // LC_IDENT load command. offset = MachHeaderSizeFromMagic(m_header.magic); for (uint32_t i = 0; i < m_header.ncmds; ++i) { const uint32_t cmd_offset = offset; @@ -5444,7 +5372,8 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo (addr_t &address, UUID &uuid) { uint64_t fileoff = m_data.GetU64_unchecked (&offset); uint64_t size = m_data.GetU64_unchecked (&offset); - // "main bin spec" (main binary specification) data payload is formatted: + // "main bin spec" (main binary specification) data payload is + // formatted: // uint32_t version [currently 1] // uint32_t type [0 == unspecified, 1 == kernel, 2 == user process] // uint64_t address [ UINT64_MAX if address not specified ] @@ -5461,12 +5390,11 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo (addr_t &address, UUID &uuid) { uuid_t raw_uuid; memset (raw_uuid, 0, sizeof (uuid_t)); - if (m_data.GetU32 (&offset, &type, 1) - && m_data.GetU64 (&offset, &address, 1) - && m_data.CopyData (offset, sizeof (uuid_t), raw_uuid) != 0 - && uuid.SetBytes (raw_uuid, sizeof (uuid_t))) - { - return true; + if (m_data.GetU32(&offset, &type, 1) && + m_data.GetU64(&offset, &address, 1) && + m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) { + uuid = UUID::fromOptionalData(raw_uuid, sizeof(uuid_t)); + return true; } } } @@ -5525,9 +5453,9 @@ ObjectFile::Type ObjectFileMachO::CalculateType() { // UUID load command. UUID uuid; if (GetUUID(&uuid)) { - // this checking for the UUID load command is not enough - // we could eventually look for the symbol named - // "OSKextGetCurrentIdentifier" as this is required of kexts + // this checking for the UUID load command is not enough we could + // eventually look for the symbol named "OSKextGetCurrentIdentifier" as + // this is required of kexts if (m_strata == eStrataInvalid) m_strata = eStrataKernel; return eTypeSharedLibrary; @@ -5569,9 +5497,9 @@ ObjectFile::Strata ObjectFileMachO::CalculateStrata() { // UUID load command. UUID uuid; if (GetUUID(&uuid)) { - // this checking for the UUID load command is not enough - // we could eventually look for the symbol named - // "OSKextGetCurrentIdentifier" as this is required of kexts + // this checking for the UUID load command is not enough we could + // eventually look for the symbol named "OSKextGetCurrentIdentifier" as + // this is required of kexts if (m_type == eTypeInvalid) m_type = eTypeSharedLibrary; @@ -5618,8 +5546,7 @@ ObjectFile::Strata ObjectFileMachO::CalculateStrata() { return eStrataUnknown; } -uint32_t ObjectFileMachO::GetVersion(uint32_t *versions, - uint32_t num_versions) { +llvm::VersionTuple ObjectFileMachO::GetVersion() { ModuleSP module_sp(GetModule()); if (module_sp) { std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); @@ -5647,23 +5574,13 @@ uint32_t ObjectFileMachO::GetVersion(uint32_t *versions, } if (version_cmd == LC_ID_DYLIB) { - if (versions != NULL && num_versions > 0) { - if (num_versions > 0) - versions[0] = (version & 0xFFFF0000ull) >> 16; - if (num_versions > 1) - versions[1] = (version & 0x0000FF00ull) >> 8; - if (num_versions > 2) - versions[2] = (version & 0x000000FFull); - // Fill in an remaining version numbers with invalid values - for (i = 3; i < num_versions; ++i) - versions[i] = UINT32_MAX; - } - // The LC_ID_DYLIB load command has a version with 3 version numbers - // in it, so always return 3 - return 3; + unsigned major = (version & 0xFFFF0000ull) >> 16; + unsigned minor = (version & 0x0000FF00ull) >> 8; + unsigned subminor = (version & 0x000000FFull); + return llvm::VersionTuple(major, minor, subminor); } } - return false; + return llvm::VersionTuple(); } bool ObjectFileMachO::GetArchitecture(ArchSpec &arch) { @@ -5676,21 +5593,40 @@ bool ObjectFileMachO::GetArchitecture(ArchSpec &arch) { return false; } -UUID ObjectFileMachO::GetProcessSharedCacheUUID(Process *process) { - UUID uuid; +void ObjectFileMachO::GetProcessSharedCacheUUID(Process *process, addr_t &base_addr, UUID &uuid) { + uuid.Clear(); + base_addr = LLDB_INVALID_ADDRESS; if (process && process->GetDynamicLoader()) { DynamicLoader *dl = process->GetDynamicLoader(); - addr_t load_address; LazyBool using_shared_cache; LazyBool private_shared_cache; - dl->GetSharedCacheInformation(load_address, uuid, using_shared_cache, + dl->GetSharedCacheInformation(base_addr, uuid, using_shared_cache, private_shared_cache); } - return uuid; + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("inferior process shared cache has a UUID of %s, base address 0x%" PRIx64 , uuid.GetAsString().c_str(), base_addr); } -UUID ObjectFileMachO::GetLLDBSharedCacheUUID() { - UUID uuid; +// From dyld SPI header dyld_process_info.h +typedef void *dyld_process_info; +struct lldb_copy__dyld_process_cache_info { + uuid_t cacheUUID; // UUID of cache used by process + uint64_t cacheBaseAddress; // load address of dyld shared cache + bool noCache; // process is running without a dyld cache + bool privateCache; // process is using a private copy of its dyld cache +}; + +// #including mach/mach.h pulls in machine.h & CPU_TYPE_ARM etc conflicts with llvm +// enum definitions llvm::MachO::CPU_TYPE_ARM turning them into compile errors. +// So we need to use the actual underlying types of task_t and kern_return_t +// below. +extern "C" unsigned int /*task_t*/ mach_task_self(); + +void ObjectFileMachO::GetLLDBSharedCacheUUID(addr_t &base_addr, UUID &uuid) { + uuid.Clear(); + base_addr = LLDB_INVALID_ADDRESS; + #if defined(__APPLE__) && \ (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) uint8_t *(*dyld_get_all_image_infos)(void); @@ -5708,25 +5644,60 @@ UUID ObjectFileMachO::GetLLDBSharedCacheUUID() { sharedCacheUUID_address = (uuid_t *)((uint8_t *)dyld_all_image_infos_address + 160); // sharedCacheUUID <mach-o/dyld_images.h> + if (*version >= 15) + base_addr = *(uint64_t *) ((uint8_t *) dyld_all_image_infos_address + + 176); // sharedCacheBaseAddress <mach-o/dyld_images.h> } else { sharedCacheUUID_address = (uuid_t *)((uint8_t *)dyld_all_image_infos_address + 84); // sharedCacheUUID <mach-o/dyld_images.h> + if (*version >= 15) { + base_addr = 0; + base_addr = *(uint32_t *) ((uint8_t *) dyld_all_image_infos_address + + 100); // sharedCacheBaseAddress <mach-o/dyld_images.h> + } + } + uuid = UUID::fromOptionalData(sharedCacheUUID_address, sizeof(uuid_t)); + } + } + } else { + // Exists in macOS 10.12 and later, iOS 10.0 and later - dyld SPI + dyld_process_info (*dyld_process_info_create)(unsigned int /* task_t */ task, uint64_t timestamp, unsigned int /*kern_return_t*/ *kernelError); + void (*dyld_process_info_get_cache)(void *info, void *cacheInfo); + void (*dyld_process_info_release)(dyld_process_info info); + + dyld_process_info_create = (void *(*)(unsigned int /* task_t */, uint64_t, unsigned int /*kern_return_t*/ *)) + dlsym (RTLD_DEFAULT, "_dyld_process_info_create"); + dyld_process_info_get_cache = (void (*)(void *, void *)) + dlsym (RTLD_DEFAULT, "_dyld_process_info_get_cache"); + dyld_process_info_release = (void (*)(void *)) + dlsym (RTLD_DEFAULT, "_dyld_process_info_release"); + + if (dyld_process_info_create && dyld_process_info_get_cache) { + unsigned int /*kern_return_t */ kern_ret; + dyld_process_info process_info = dyld_process_info_create(::mach_task_self(), 0, &kern_ret); + if (process_info) { + struct lldb_copy__dyld_process_cache_info sc_info; + memset (&sc_info, 0, sizeof (struct lldb_copy__dyld_process_cache_info)); + dyld_process_info_get_cache (process_info, &sc_info); + if (sc_info.cacheBaseAddress != 0) { + base_addr = sc_info.cacheBaseAddress; + uuid = UUID::fromOptionalData(sc_info.cacheUUID, sizeof(uuid_t)); } - uuid.SetBytes(sharedCacheUUID_address); + dyld_process_info_release (process_info); } } } + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_PROCESS)); + if (log && uuid.IsValid()) + log->Printf("lldb's in-memory shared cache has a UUID of %s base address of 0x%" PRIx64, uuid.GetAsString().c_str(), base_addr); #endif - return uuid; } -uint32_t ObjectFileMachO::GetMinimumOSVersion(uint32_t *versions, - uint32_t num_versions) { - if (m_min_os_versions.empty()) { +llvm::VersionTuple ObjectFileMachO::GetMinimumOSVersion() { + if (!m_min_os_version) { 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; i < m_header.ncmds; ++i) { const lldb::offset_t load_cmd_offset = offset; version_min_command lc; @@ -5742,35 +5713,21 @@ uint32_t ObjectFileMachO::GetMinimumOSVersion(uint32_t *versions, const uint32_t yy = (lc.version >> 8) & 0xffu; const uint32_t zz = lc.version & 0xffu; if (xxxx) { - m_min_os_versions.push_back(xxxx); - m_min_os_versions.push_back(yy); - m_min_os_versions.push_back(zz); + m_min_os_version = llvm::VersionTuple(xxxx, yy, zz); + break; } - success = true; } } offset = load_cmd_offset + lc.cmdsize; } - if (success == false) { - // Push an invalid value so we don't keep trying to - m_min_os_versions.push_back(UINT32_MAX); + if (!m_min_os_version) { + // Set version to an empty value so we don't keep trying to + m_min_os_version = llvm::VersionTuple(); } } - if (m_min_os_versions.size() > 1 || m_min_os_versions[0] != UINT32_MAX) { - if (versions != NULL && num_versions > 0) { - for (size_t i = 0; i < num_versions; ++i) { - if (i < m_min_os_versions.size()) - versions[i] = m_min_os_versions[i]; - else - versions[i] = 0; - } - } - return m_min_os_versions.size(); - } - // Call the superclasses version that will empty out the data - return ObjectFile::GetMinimumOSVersion(versions, num_versions); + return *m_min_os_version; } uint32_t ObjectFileMachO::GetSDKVersion(uint32_t *versions, @@ -5797,20 +5754,29 @@ uint32_t ObjectFileMachO::GetSDKVersion(uint32_t *versions, m_sdk_versions.push_back(xxxx); m_sdk_versions.push_back(yy); m_sdk_versions.push_back(zz); + success = true; + } else { + GetModule()->ReportWarning( + "minimum OS version load command with invalid (0) version found."); } - success = true; } } offset = load_cmd_offset + lc.cmdsize; } if (success == false) { - // Push an invalid value so we don't keep trying to + // Push an invalid value so we don't try to find + // the version # again on the next call to this + // method. m_sdk_versions.push_back(UINT32_MAX); } } - if (m_sdk_versions.size() > 1 || m_sdk_versions[0] != UINT32_MAX) { + // Legitimate version numbers will have 3 entries pushed + // on to m_sdk_versions. If we only have one value, it's + // the sentinel value indicating that this object file + // does not have a valid minimum os version #. + if (m_sdk_versions.size() > 1) { if (versions != NULL && num_versions > 0) { for (size_t i = 0; i < num_versions; ++i) { if (i < m_sdk_versions.size()) @@ -5843,9 +5809,9 @@ lldb_private::ConstString ObjectFileMachO::GetPluginName() { uint32_t ObjectFileMachO::GetPluginVersion() { return 1; } Section *ObjectFileMachO::GetMachHeaderSection() { - // Find the first address of the mach header which is the first non-zero - // file sized section whose file offset is zero. This is the base file address - // of the mach-o file which can be subtracted from the vmaddr of the other + // Find the first address of the mach header which is the first non-zero file + // sized section whose file offset is zero. This is the base file address of + // 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) { @@ -5883,8 +5849,8 @@ lldb::addr_t ObjectFileMachO::CalculateSectionLoadAddressForMemoryImage( 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. + // 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) @@ -5910,9 +5876,8 @@ bool ObjectFileMachO::SetLoadAddress(Target &target, lldb::addr_t value, if (value_is_offset) { // "value" is an offset to apply to each top level segment for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { - // Iterate through the object file sections to find all - // of the sections that size on disk (to avoid __PAGEZERO) - // and load them + // 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 && @@ -5920,8 +5885,7 @@ bool ObjectFileMachO::SetLoadAddress(Target &target, lldb::addr_t value, // 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. + // 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) @@ -6071,10 +6035,10 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, ThreadList &thread_list = process_sp->GetThreadList(); const uint32_t num_threads = thread_list.GetSize(); - // Make an array of LC_THREAD data items. Each one contains - // the contents of the LC_THREAD load command. The data doesn't - // contain the load command + load command size, we will - // add the load command and load command size as we emit the data. + // Make an array of LC_THREAD data items. Each one contains the + // contents of the LC_THREAD load command. The data doesn't contain + // the load command + load command size, we will add the load command + // and load command size as we emit the data. std::vector<StreamString> LC_THREAD_datas(num_threads); for (auto &LC_THREAD_data : LC_THREAD_datas) { LC_THREAD_data.GetFlags().Set(Stream::eBinary); @@ -6234,8 +6198,8 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, bytes_left -= bytes_read; addr += bytes_read; } else { - // Some pages within regions are not readable, those - // should be zero filled + // Some pages within regions are not readable, those should + // be zero filled memset(bytes, 0, bytes_to_read); size_t bytes_written = bytes_to_read; error = core_file.Write(bytes, bytes_written); diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index 9a42f41a4c94..be64518064b5 100644 --- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -86,7 +86,7 @@ public: uint32_t GetAddressByteSize() const override; - lldb::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; lldb_private::Symtab *GetSymtab() override; @@ -123,10 +123,9 @@ public: ObjectFile::Strata CalculateStrata() override; - uint32_t GetVersion(uint32_t *versions, uint32_t num_versions) override; + llvm::VersionTuple GetVersion() override; - uint32_t GetMinimumOSVersion(uint32_t *versions, - uint32_t num_versions) override; + llvm::VersionTuple GetMinimumOSVersion() override; uint32_t GetSDKVersion(uint32_t *versions, uint32_t num_versions) override; @@ -162,14 +161,14 @@ protected: // with an on-disk dyld_shared_cache file. The process will record // the shared cache UUID so the on-disk cache can be matched or rejected // correctly. - lldb_private::UUID GetProcessSharedCacheUUID(lldb_private::Process *); + void GetProcessSharedCacheUUID(lldb_private::Process *, lldb::addr_t &base_addr, lldb_private::UUID &uuid); // Intended for same-host arm device debugging where lldb will read // shared cache libraries out of its own memory instead of the remote // process' memory as an optimization. If lldb's shared cache UUID // does not match the process' shared cache UUID, this optimization // should not be used. - lldb_private::UUID GetLLDBSharedCacheUUID(); + void GetLLDBSharedCacheUUID(lldb::addr_t &base_addir, lldb_private::UUID &uuid); lldb_private::Section *GetMachHeaderSection(); @@ -185,6 +184,18 @@ protected: size_t ParseSymtab(); + typedef lldb_private::RangeArray<uint32_t, uint32_t, 8> EncryptedFileRanges; + EncryptedFileRanges GetEncryptedFileRanges(); + + struct SegmentParsingContext; + void ProcessDysymtabCommand(const llvm::MachO::load_command &load_cmd, + lldb::offset_t offset); + void ProcessSegmentCommand(const llvm::MachO::load_command &load_cmd, + lldb::offset_t offset, uint32_t cmd_idx, + SegmentParsingContext &context); + void SanitizeSegmentCommand(llvm::MachO::segment_command_64 &seg_cmd, + uint32_t cmd_idx); + llvm::MachO::mach_header m_header; static const lldb_private::ConstString &GetSegmentNameTEXT(); static const lldb_private::ConstString &GetSegmentNameDATA(); @@ -197,7 +208,7 @@ protected: llvm::MachO::dysymtab_command m_dysymtab; std::vector<llvm::MachO::segment_command_64> m_mach_segments; std::vector<llvm::MachO::section_64> m_mach_sections; - std::vector<uint32_t> m_min_os_versions; + llvm::Optional<llvm::VersionTuple> m_min_os_version; std::vector<uint32_t> m_sdk_versions; typedef lldb_private::RangeVector<uint32_t, uint32_t> FileRangeArray; lldb_private::Address m_entry_point_address; diff --git a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 77bfa7fe0a64..b2967f1532ab 100644 --- a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -236,8 +236,8 @@ bool ObjectFilePECOFF::SetLoadAddress(Target &target, addr_t value, size_t sect_idx = 0; for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { - // Iterate through the object file sections to find all - // of the sections that have SHF_ALLOC in their flag bits. + // 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->IsThreadSpecific()) { if (target.GetSectionLoadList().SetSectionLoadAddress( @@ -268,8 +268,8 @@ uint32_t ObjectFilePECOFF::GetAddressByteSize() const { //---------------------------------------------------------------------- // NeedsEndianSwap // -// Return true if an endian swap needs to occur when extracting data -// from this file. +// Return true if an endian swap needs to occur when extracting data from this +// file. //---------------------------------------------------------------------- bool ObjectFilePECOFF::NeedsEndianSwap() const { #if defined(__LITTLE_ENDIAN__) @@ -552,8 +552,8 @@ Symtab *ObjectFilePECOFF::GetSymtab() { // are followed by a 4-byte string table offset. Else these // 8 bytes contain the symbol name if (symtab_data.GetU32(&offset) == 0) { - // Long string that doesn't fit into the symbol table name, - // so now we must read the 4 byte string table offset + // Long string that doesn't fit into the symbol table name, so + // now we must read the 4 byte string table offset uint32_t strtab_offset = symtab_data.GetU32(&offset); symbol_name_cstr = strtab_data.PeekCStr(strtab_offset); symbol_name.assign(symbol_name_cstr); @@ -692,10 +692,12 @@ void ObjectFilePECOFF::CreateSections(SectionList &unified_section_list) { 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; @@ -736,6 +738,8 @@ void ObjectFilePECOFF::CreateSections(SectionList &unified_section_list) { 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) @@ -744,6 +748,8 @@ void ObjectFilePECOFF::CreateSections(SectionList &unified_section_list) { 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) diff --git a/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp b/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp index 75bc518f7538..3f6083931513 100644 --- a/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp +++ b/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp @@ -312,8 +312,8 @@ bool OperatingSystemGo::UpdateThreadList(ThreadList &old_thread_list, } 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. + // the lldb_private::Process subclass, no memory threads will be in this + // list. Status err; for (uint64_t i = 0; i < allglen; ++i) { @@ -402,7 +402,6 @@ lldb::ThreadSP OperatingSystemGo::CreateThread(lldb::tid_t tid, ValueObjectSP OperatingSystemGo::FindGlobal(TargetSP target, const char *name) { VariableList variable_list; - const bool append = true; Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS)); @@ -414,7 +413,7 @@ ValueObjectSP OperatingSystemGo::FindGlobal(TargetSP target, const char *name) { } uint32_t match_count = target->GetImages().FindGlobalVariables( - ConstString(name), append, 1, variable_list); + ConstString(name), 1, variable_list); if (match_count > 0) { ExecutionContextScope *exe_scope = target->GetProcessSP().get(); if (exe_scope == NULL) diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index b71f3cf04c33..d6252c473270 100644 --- a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -50,8 +50,8 @@ void OperatingSystemPython::Terminate() { OperatingSystem *OperatingSystemPython::CreateInstance(Process *process, bool force) { - // Python OperatingSystem plug-ins must be requested by name, so force must be - // true + // 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()) { std::unique_ptr<OperatingSystemPython> os_ap( @@ -156,9 +156,10 @@ bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list, Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS)); - // First thing we have to do is to try to get the API lock, and the run lock. - // We're going to change the thread content of the process, and we're going - // to use python, which requires the API lock to do it. + // First thing we have to do is to try to get the API lock, and the + // interpreter lock. We're going to change the thread content of the process, + // and we're going to use python, which requires the API lock to do it. We + // need the interpreter lock to make sure thread_info_dict stays alive. // // If someone already has the API lock, that is ok, we just want to avoid // external code from making new API calls while this call is happening. @@ -166,9 +167,10 @@ bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list, // This is a recursive lock so we can grant it to any Python code called on // the stack below us. Target &target = m_process->GetTarget(); - std::unique_lock<std::recursive_mutex> lock(target.GetAPIMutex(), - std::defer_lock); - lock.try_lock(); + std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), + std::defer_lock); + api_lock.try_lock(); + auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); if (log) log->Printf("OperatingSystemPython::UpdateThreadList() fetching thread " @@ -176,20 +178,16 @@ bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list, m_process->GetID()); // 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. - - auto interpreter_lock = - m_interpreter - ->AcquireInterpreterLock(); // to make sure threads_list stays alive + // the lldb_private::Process subclass, no memory threads will be in this + // list. StructuredData::ArraySP threads_list = m_interpreter->OSPlugin_ThreadsInfo(m_python_object_sp); const uint32_t num_cores = core_thread_list.GetSize(false); // Make a map so we can keep track of which cores were used from the - // core_thread list. Any real threads/cores that weren't used should - // later be put back into the "new_thread_list". + // core_thread list. Any real threads/cores that weren't used should later be + // put back into the "new_thread_list". std::vector<bool> core_used_map(num_cores, false); if (threads_list) { if (log) { @@ -214,8 +212,7 @@ bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list, // Any real core threads that didn't end up backing a memory thread should // still be in the main thread list, and they should be inserted at the - // beginning - // of the 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) { @@ -256,8 +253,8 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo( // plug-in generated thread. if (!IsOperatingSystemPluginThread(thread_sp)) { // We have thread ID overlap between the protocol threads and the - // operating system threads, clear the thread so we create an - // operating system thread for this. + // operating system threads, clear the thread so we create an operating + // system thread for this. thread_sp.reset(); } } @@ -301,20 +298,24 @@ OperatingSystemPython::CreateRegisterContextForThread(Thread *thread, if (!IsOperatingSystemPluginThread(thread->shared_from_this())) return reg_ctx_sp; - // First thing we have to do is get the API lock, and the run lock. We're - // going to change the thread - // content of the process, and we're going to use python, which requires the - // API lock to do it. - // So get & hold that. This is a recursive lock so we can grant it to any - // Python code called on the stack below us. + // First thing we have to do is to try to get the API lock, and the + // interpreter lock. We're going to change the thread content of the process, + // and we're going to use python, which requires the API lock to do it. We + // need the interpreter lock to make sure thread_info_dict stays alive. + // + // If someone already has the API lock, that is ok, we just want to avoid + // external code from making new API calls while this call is happening. + // + // This is a recursive lock so we can grant it to any Python code called on + // the stack below us. Target &target = m_process->GetTarget(); - std::lock_guard<std::recursive_mutex> guard(target.GetAPIMutex()); + std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), + std::defer_lock); + api_lock.try_lock(); + auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - auto lock = - m_interpreter - ->AcquireInterpreterLock(); // to make sure python objects stays alive if (reg_data_addr != LLDB_INVALID_ADDRESS) { // The registers data is in contiguous memory, just create the register // context using the address provided @@ -326,8 +327,8 @@ OperatingSystemPython::CreateRegisterContextForThread(Thread *thread, reg_ctx_sp.reset(new RegisterContextMemory( *thread, 0, *GetDynamicRegisterInfo(), reg_data_addr)); } else { - // No register data address is provided, query the python plug-in to let - // it make up the data as it sees fit + // No register data address is provided, query the python plug-in to let it + // make up the data as it sees fit if (log) log->Printf("OperatingSystemPython::CreateRegisterContextForThread (tid " "= 0x%" PRIx64 ", 0x%" PRIx64 @@ -383,18 +384,23 @@ lldb::ThreadSP OperatingSystemPython::CreateThread(lldb::tid_t tid, tid, context); if (m_interpreter && m_python_object_sp) { - // First thing we have to do is get the API lock, and the run lock. We're - // going to change the thread - // content of the process, and we're going to use python, which requires the - // API lock to do it. - // So get & hold that. This is a recursive lock so we can grant it to any - // Python code called on the stack below us. + // First thing we have to do is to try to get the API lock, and the + // interpreter lock. We're going to change the thread content of the + // process, and we're going to use python, which requires the API lock to + // do it. We need the interpreter lock to make sure thread_info_dict stays + // alive. + // + // If someone already has the API lock, that is ok, we just want to avoid + // external code from making new API calls while this call is happening. + // + // This is a recursive lock so we can grant it to any Python code called on + // the stack below us. Target &target = m_process->GetTarget(); - std::lock_guard<std::recursive_mutex> guard(target.GetAPIMutex()); + std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), + std::defer_lock); + api_lock.try_lock(); + auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); - auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure - // thread_info_dict - // stays alive StructuredData::DictionarySP thread_info_dict = m_interpreter->OSPlugin_CreateThread(m_python_object_sp, tid, context); std::vector<bool> core_used_map; diff --git a/source/Plugins/Platform/Android/AdbClient.cpp b/source/Plugins/Platform/Android/AdbClient.cpp index 6e15eb2b1dcb..4cd8c645dd76 100644 --- a/source/Plugins/Platform/Android/AdbClient.cpp +++ b/source/Plugins/Platform/Android/AdbClient.cpp @@ -165,8 +165,8 @@ Status AdbClient::GetDevices(DeviceIDList &device_list) { for (const auto device : devices) device_list.push_back(device.split('\t').first); - // Force disconnect since ADB closes connection after host:devices - // response is sent. + // Force disconnect since ADB closes connection after host:devices response + // is sent. m_conn.reset(); return error; } diff --git a/source/Plugins/Platform/Android/PlatformAndroid.cpp b/source/Plugins/Platform/Android/PlatformAndroid.cpp index 5b85bcdf7fdd..1cedcde97a92 100644 --- a/source/Plugins/Platform/Android/PlatformAndroid.cpp +++ b/source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -83,9 +83,9 @@ PlatformSP PlatformAndroid::CreateInstance(bool force, const ArchSpec *arch) { break; #if defined(__ANDROID__) - // Only accept "unknown" for the vendor if the host is android and - // it "unknown" wasn't specified (it was just returned because it - // was NOT specified_ + // Only accept "unknown" for the vendor if the host is android and it + // "unknown" wasn't specified (it was just returned because it was NOT + // specified_ case llvm::Triple::VendorType::UnknownVendor: create = !arch->TripleVendorWasSpecified(); break; @@ -100,9 +100,9 @@ PlatformSP PlatformAndroid::CreateInstance(bool force, const ArchSpec *arch) { break; #if defined(__ANDROID__) - // Only accept "unknown" for the OS if the host is android and - // it "unknown" wasn't specified (it was just returned because it - // was NOT specified) + // Only accept "unknown" for the OS if the host is android and it + // "unknown" wasn't specified (it was just returned because it was NOT + // specified) case llvm::Triple::OSType::UnknownOS: create = !arch->TripleOSWasSpecified(); break; @@ -193,8 +193,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::ePathSyntaxPosix); + FileSpec source_spec(source.GetPath(false), false, FileSpec::Style::posix); if (source_spec.IsRelative()) source_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent( source_spec.GetCString(false)); @@ -222,8 +221,8 @@ Status PlatformAndroid::GetFile(const FileSpec &source, if (strchr(source_file, '\'') != nullptr) return Status("Doesn't support single-quotes in filenames"); - // mode == 0 can signify that adbd cannot access the file - // due security constraints - try "cat ..." as a fallback. + // mode == 0 can signify that adbd cannot access the file due security + // constraints - try "cat ..." as a fallback. AdbClient adb(m_device_id); char cmd[PATH_MAX]; @@ -239,7 +238,7 @@ Status PlatformAndroid::PutFile(const FileSpec &source, return PlatformLinux::PutFile(source, destination, uid, gid); FileSpec destination_spec(destination.GetPath(false), false, - FileSpec::ePathSyntaxPosix); + FileSpec::Style::posix); if (destination_spec.IsRelative()) destination_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent( destination_spec.GetCString(false)); @@ -306,7 +305,7 @@ Status PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp, const FileSpec &dst_file_spec) { // For oat file we can try to fetch additional debug info from the device ConstString extension = module_sp->GetFileSpec().GetFileNameExtension(); - if (extension != ConstString("oat") && extension != ConstString("odex")) + if (extension != ConstString(".oat") && extension != ConstString(".odex")) return Status( "Symbol file downloading only supported for oat and odex files"); @@ -361,10 +360,8 @@ Status PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp, } bool PlatformAndroid::GetRemoteOSVersion() { - m_major_os_version = GetSdkVersion(); - m_minor_os_version = 0; - m_update_os_version = 0; - return m_major_os_version != 0; + m_os_version = llvm::VersionTuple(GetSdkVersion()); + return !m_os_version.empty(); } llvm::StringRef diff --git a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp index dbc74833e287..2415da31daf0 100644 --- a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -180,9 +180,9 @@ Status PlatformAndroidRemoteGDBServer::MakeConnectURL( static const int kAttempsNum = 5; Status error; - // There is a race possibility that somebody will occupy - // a port while we're in between FindUnusedPort and ForwardPortWithAdb - - // adding the loop to mitigate such problem. + // There is a race possibility that somebody will occupy a port while we're + // in between FindUnusedPort and ForwardPortWithAdb - adding the loop to + // mitigate such problem. for (auto i = 0; i < kAttempsNum; ++i) { uint16_t local_port = 0; error = FindUnusedPort(local_port); @@ -208,10 +208,9 @@ lldb::ProcessSP PlatformAndroidRemoteGDBServer::ConnectProcess( lldb_private::Debugger &debugger, lldb_private::Target *target, lldb_private::Status &error) { // We don't have the pid of the remote gdbserver when it isn't started by us - // but we still want - // to store the list of port forwards we set up in our port forward map. - // Generate a fake pid for - // these cases what won't collide with any other valid pid on android. + // but we still want to store the list of port forwards we set up in our port + // forward map. Generate a fake pid for these cases what won't collide with + // any other valid pid on android. static lldb::pid_t s_remote_gdbserver_fake_pid = 0xffffffffffffffffULL; int remote_port; diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index 73c7d21f0a06..bc8111d1078b 100644 --- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -32,8 +32,8 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" -// Define these constants from FreeBSD mman.h for use when targeting -// remote FreeBSD systems even when host has different values. +// Define these constants from FreeBSD mman.h for use when targeting remote +// FreeBSD systems even when host has different values. #define MAP_PRIVATE 0x0002 #define MAP_ANON 0x1000 @@ -60,9 +60,8 @@ PlatformSP PlatformFreeBSD::CreateInstance(bool force, const ArchSpec *arch) { break; #if defined(__FreeBSD__) - // Only accept "unknown" for the OS if the host is BSD and - // it "unknown" wasn't specified (it was just returned because it - // was NOT specified) + // Only accept "unknown" for the OS if the host is BSD and it "unknown" + // wasn't specified (it was just returned because it was NOT specified) case llvm::Triple::OSType::UnknownOS: create = !arch->TripleOSWasSpecified(); break; @@ -143,7 +142,8 @@ bool PlatformFreeBSD::GetSupportedArchitectureAtIndex(uint32_t idx, arch = hostArch; return arch.IsValid(); } else if (idx == 1) { - // If the default host architecture is 64-bit, look for a 32-bit variant + // If the default host architecture is 64-bit, look for a 32-bit + // variant if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit()) { arch = HostInfo::GetArchitecture(HostInfo::eArchKind32); return arch.IsValid(); @@ -187,13 +187,10 @@ bool PlatformFreeBSD::GetSupportedArchitectureAtIndex(uint32_t idx, return false; } // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the - // vendor by - // calling triple.SetVendorName("unknown") so that it is a "unspecified - // unknown". - // This means when someone calls triple.GetVendorName() it will return an - // empty string - // which indicates that the vendor can be set when two architectures are - // merged + // vendor by calling triple.SetVendorName("unknown") so that it is a + // "unspecified unknown". This means when someone calls + // triple.GetVendorName() it will return an empty string which indicates + // that the vendor can be set when two architectures are merged // Now set the triple into "arch" and return true arch.SetTriple(triple); @@ -228,16 +225,16 @@ PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode(Target &target, switch (target.GetArchitecture().GetMachine()) { case llvm::Triple::arm: { lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); - AddressClass addr_class = eAddressClassUnknown; + AddressClass addr_class = AddressClass::eUnknown; if (bp_loc_sp) { addr_class = bp_loc_sp->GetAddress().GetAddressClass(); - if (addr_class == eAddressClassUnknown && + if (addr_class == AddressClass::eUnknown && (bp_loc_sp->GetAddress().GetFileAddress() & 1)) - addr_class = eAddressClassCodeAlternateISA; + addr_class = AddressClass::eCodeAlternateISA; } - if (addr_class == eAddressClassCodeAlternateISA) { + if (addr_class == AddressClass::eCodeAlternateISA) { // TODO: Enable when FreeBSD supports thumb breakpoints. // FreeBSD kernel as of 10.x, does not support thumb breakpoints return 0; @@ -286,9 +283,9 @@ lldb::ProcessSP PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info, if (target && error.Success()) { debugger.GetTargetList().SetSelectedTarget(target); - // The freebsd always currently uses the GDB remote debugger plug-in - // so even when debugging locally we are debugging remotely! - // Just like the darwin plugin. + // The freebsd always currently uses the GDB remote debugger plug-in so + // even when debugging locally we are debugging remotely! Just like the + // darwin plugin. process_sp = target->CreateProcess( attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL); diff --git a/source/Plugins/Platform/Linux/PlatformLinux.cpp b/source/Plugins/Platform/Linux/PlatformLinux.cpp index 8186eae0e8c4..dbde91d7ab2d 100644 --- a/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ b/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -30,8 +30,8 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" -// Define these constants from Linux mman.h for use when targeting -// remote linux systems even when host has different values. +// Define these constants from Linux mman.h for use when targeting remote linux +// systems even when host has different values. #define MAP_PRIVATE 2 #define MAP_ANON 0x20 @@ -58,9 +58,8 @@ PlatformSP PlatformLinux::CreateInstance(bool force, const ArchSpec *arch) { break; #if defined(__linux__) - // Only accept "unknown" for the OS if the host is linux and - // it "unknown" wasn't specified (it was just returned because it - // was NOT specified) + // Only accept "unknown" for the OS if the host is linux and it "unknown" + // wasn't specified (it was just returned because it was NOT specified) case llvm::Triple::OSType::UnknownOS: create = !arch->TripleOSWasSpecified(); break; @@ -142,7 +141,8 @@ bool PlatformLinux::GetSupportedArchitectureAtIndex(uint32_t idx, arch = hostArch; return arch.IsValid(); } else if (idx == 1) { - // If the default host architecture is 64-bit, look for a 32-bit variant + // If the default host architecture is 64-bit, look for a 32-bit + // variant if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit()) { arch = HostInfo::GetArchitecture(HostInfo::eArchKind32); return arch.IsValid(); @@ -192,13 +192,10 @@ bool PlatformLinux::GetSupportedArchitectureAtIndex(uint32_t idx, return false; } // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the - // vendor by - // calling triple.SetVendorName("unknown") so that it is a "unspecified - // unknown". - // This means when someone calls triple.GetVendorName() it will return an - // empty string - // which indicates that the vendor can be set when two architectures are - // merged + // vendor by calling triple.SetVendorName("unknown") so that it is a + // "unspecified unknown". This means when someone calls + // triple.GetVendorName() it will return an empty string which indicates + // that the vendor can be set when two architectures are merged // Now set the triple into "arch" and return true arch.SetTriple(triple); @@ -212,8 +209,8 @@ void PlatformLinux::GetStatus(Stream &strm) { #ifndef LLDB_DISABLE_POSIX // Display local kernel information only when we are running in host mode. - // Otherwise, we would end up printing non-Linux information (when running - // on Mac OS for example). + // Otherwise, we would end up printing non-Linux information (when running on + // Mac OS for example). if (IsHost()) { struct utsname un; @@ -272,8 +269,8 @@ bool PlatformLinux::CanDebugProcess() { } // For local debugging, Linux will override the debug logic to use llgs-launch -// rather than lldb-launch, llgs-attach. This differs from current lldb-launch, -// debugserver-attach approach on MacOSX. +// rather than lldb-launch, llgs-attach. This differs from current lldb- +// launch, debugserver-attach approach on MacOSX. lldb::ProcessSP PlatformLinux::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new @@ -297,8 +294,8 @@ PlatformLinux::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, launch_info.GetFlags().Set(eLaunchFlagDebug); // We always launch the process we are going to debug in a separate process - // group, since then we can handle ^C interrupts ourselves w/o having to worry - // about the target getting them as well. + // group, since then we can handle ^C interrupts ourselves w/o having to + // worry about the target getting them as well. launch_info.SetLaunchInSeparateProcessGroup(true); // Ensure we have a target. diff --git a/source/Plugins/Platform/MacOSX/CMakeLists.txt b/source/Plugins/Platform/MacOSX/CMakeLists.txt index f8d911b321f8..f9663559069a 100644 --- a/source/Plugins/Platform/MacOSX/CMakeLists.txt +++ b/source/Plugins/Platform/MacOSX/CMakeLists.txt @@ -11,13 +11,14 @@ list(APPEND PLUGIN_PLATFORM_MACOSX_SOURCES list(APPEND PLUGIN_PLATFORM_MACOSX_DARWIN_ONLY_SOURCES PlatformAppleSimulator.cpp PlatformiOSSimulator.cpp - PlatformiOSSimulatorCoreSimulatorSupport.mm PlatformAppleTVSimulator.cpp PlatformAppleWatchSimulator.cpp ) if(CMAKE_SYSTEM_NAME MATCHES "Darwin") include_directories(${LIBXML2_INCLUDE_DIR}) + add_subdirectory(objcxx) + set(OBJC_LIBS "lldbPluginPlatformMacOSXObjCXX") list(APPEND PLUGIN_PLATFORM_MACOSX_SOURCES ${PLUGIN_PLATFORM_MACOSX_DARWIN_ONLY_SOURCES}) else() @@ -38,6 +39,7 @@ add_lldb_library(lldbPluginPlatformMacOSX PLUGIN lldbTarget lldbUtility lldbPluginPlatformPOSIX + ${OBJC_LIBS} LINK_COMPONENTS Support ) diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp index a216e3839dd9..6852097117a1 100644 --- a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp @@ -84,8 +84,8 @@ lldb_private::Status PlatformAppleSimulator::LaunchProcess( void PlatformAppleSimulator::GetStatus(Stream &strm) { #if defined(__APPLE__) - // This will get called by subclasses, so just output status on the - // current simulator + // This will get called by subclasses, so just output status on the current + // simulator PlatformAppleSimulator::LoadCoreSimulator(); CoreSimulatorSupport::DeviceSet devices = @@ -183,8 +183,8 @@ lldb::ProcessSP PlatformAppleSimulator::DebugProcess( // Make sure we stop at the entry point launch_info.GetFlags().Set(eLaunchFlagDebug); // We always launch the process we are going to debug in a separate process - // group, since then we can handle ^C interrupts ourselves w/o having to worry - // about the target getting them as well. + // group, since then we can handle ^C interrupts ourselves w/o having to + // worry about the target getting them as well. launch_info.SetLaunchInSeparateProcessGroup(true); error = LaunchProcess(launch_info); @@ -201,10 +201,10 @@ lldb::ProcessSP PlatformAppleSimulator::DebugProcess( // process if this happens. process_sp->SetShouldDetach(false); - // If we didn't have any file actions, the pseudo terminal might - // have been used where the slave side was given as the file to - // open for stdin/out/err after we have already opened the master - // so we can read/write stdin/out/err. + // If we didn't have any file actions, the pseudo terminal might have + // been used where the slave side was given as the file to open for + // stdin/out/err after we have already opened the master so we can + // read/write stdin/out/err. int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); if (pty_fd != PseudoTerminal::invalid_fd) { process_sp->SetSTDIOFileDescriptor(pty_fd); diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h index 44feb019dc73..2536854e9630 100644 --- a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h +++ b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h @@ -16,8 +16,8 @@ // Other libraries and framework includes // Project includes -#include "PlatformDarwin.h" -#include "PlatformiOSSimulatorCoreSimulatorSupport.h" +#include "Plugins/Platform/MacOSX/PlatformDarwin.h" +#include "Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h" #include "lldb/Utility/FileSpec.h" #include "llvm/ADT/Optional.h" diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp index e0558f8b200e..e55cc0f4f6a4 100644 --- a/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp @@ -90,9 +90,9 @@ PlatformSP PlatformAppleTVSimulator::CreateInstance(bool force, 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) + // 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: create = !arch->TripleVendorWasSpecified(); break; @@ -107,9 +107,9 @@ PlatformSP PlatformAppleTVSimulator::CreateInstance(bool force, break; #if defined(__APPLE__) - // Only accept "unknown" for the OS if the host is Apple and - // it "unknown" wasn't specified (it was just returned because it - // was NOT specified) + // Only accept "unknown" for the OS if the host is Apple and it + // "unknown" wasn't specified (it was just returned because it was NOT + // specified) case llvm::Triple::UnknownOS: create = !arch->TripleOSWasSpecified(); break; @@ -199,9 +199,9 @@ Status PlatformAppleTVSimulator::ResolveExecutable( return error; exe_module_sp.reset(); } - // No valid architecture was specified or the exact ARM slice wasn't - // found so ask the platform for the architectures that we should be - // using (in the correct order) and see if we can find a match that way + // No valid architecture was specified or the exact ARM slice wasn't found + // so ask the platform for the architectures that we should be using (in + // the correct order) and see if we can find a match that way StreamString arch_names; ArchSpec platform_arch; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( @@ -293,8 +293,8 @@ const char *PlatformAppleTVSimulator::GetSDKDirectoryAsCString() { m_sdk_directory.assign(1, '\0'); } - // We should have put a single NULL character into m_sdk_directory - // or it should have a valid path if the code gets here + // We should have put a single NULL character into m_sdk_directory or it + // should have a valid path if the code gets here assert(m_sdk_directory.empty() == false); if (m_sdk_directory[0]) return m_sdk_directory.c_str(); @@ -315,12 +315,12 @@ 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); + local_file.SetFile(resolved_path, true, FileSpec::Style::native); if (local_file.Exists()) return error; // Else fall back to the actual path itself - local_file.SetFile(platform_file_path, true); + local_file.SetFile(platform_file_path, true, FileSpec::Style::native); if (local_file.Exists()) return error; } @@ -337,10 +337,9 @@ Status PlatformAppleTVSimulator::GetSharedModule( const ModuleSpec &module_spec, lldb_private::Process *process, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, bool *did_create_ptr) { - // For AppleTV, the SDK files are all cached locally on the host - // system. So first we ask for the file in the cached SDK, - // then we attempt to get a shared module for the right architecture - // with the right UUID. + // For AppleTV, the SDK files are all cached locally on the host system. So + // first we ask for the file in the cached SDK, then we attempt to get a + // shared module for the right architecture with the right UUID. Status error; ModuleSpec platform_module_spec(module_spec); const FileSpec &platform_file = module_spec.GetFileSpec(); diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp index 9b2608f68625..8bbe0af0aec2 100644 --- a/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp @@ -89,9 +89,9 @@ PlatformSP PlatformAppleWatchSimulator::CreateInstance(bool force, 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) + // 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: create = !arch->TripleVendorWasSpecified(); break; @@ -106,9 +106,9 @@ PlatformSP PlatformAppleWatchSimulator::CreateInstance(bool force, break; #if defined(__APPLE__) - // Only accept "unknown" for the OS if the host is Apple and - // it "unknown" wasn't specified (it was just returned because it - // was NOT specified) + // Only accept "unknown" for the OS if the host is Apple and it + // "unknown" wasn't specified (it was just returned because it was NOT + // specified) case llvm::Triple::UnknownOS: create = !arch->TripleOSWasSpecified(); break; @@ -199,9 +199,9 @@ Status PlatformAppleWatchSimulator::ResolveExecutable( return error; exe_module_sp.reset(); } - // No valid architecture was specified or the exact ARM slice wasn't - // found so ask the platform for the architectures that we should be - // using (in the correct order) and see if we can find a match that way + // No valid architecture was specified or the exact ARM slice wasn't found + // so ask the platform for the architectures that we should be using (in + // the correct order) and see if we can find a match that way StreamString arch_names; ArchSpec platform_arch; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( @@ -293,8 +293,8 @@ const char *PlatformAppleWatchSimulator::GetSDKDirectoryAsCString() { m_sdk_directory.assign(1, '\0'); } - // We should have put a single NULL character into m_sdk_directory - // or it should have a valid path if the code gets here + // We should have put a single NULL character into m_sdk_directory or it + // should have a valid path if the code gets here assert(m_sdk_directory.empty() == false); if (m_sdk_directory[0]) return m_sdk_directory.c_str(); @@ -315,12 +315,12 @@ 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); + local_file.SetFile(resolved_path, true, FileSpec::Style::native); if (local_file.Exists()) return error; // Else fall back to the actual path itself - local_file.SetFile(platform_file_path, true); + local_file.SetFile(platform_file_path, true, FileSpec::Style::native); if (local_file.Exists()) return error; } @@ -337,10 +337,9 @@ Status PlatformAppleWatchSimulator::GetSharedModule( const ModuleSpec &module_spec, lldb_private::Process *process, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, bool *did_create_ptr) { - // For AppleWatch, the SDK files are all cached locally on the host - // system. So first we ask for the file in the cached SDK, - // then we attempt to get a shared module for the right architecture - // with the right UUID. + // For AppleWatch, the SDK files are all cached locally on the host system. + // So first we ask for the file in the cached SDK, then we attempt to get a + // shared module for the right architecture with the right UUID. Status error; ModuleSpec platform_module_spec(module_spec); const FileSpec &platform_file = module_spec.GetFileSpec(); diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index b04d72f755f6..886e3b6d9a05 100644 --- a/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -16,8 +16,6 @@ #include <algorithm> #include <mutex> -// Other libraries and framework includes -#include "clang/Basic/VersionTuple.h" // Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/BreakpointSite.h" @@ -42,6 +40,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/VersionTuple.h" #if defined(__APPLE__) #include <TargetConditionals.h> // for TARGET_OS_TV, TARGET_OS_WATCH @@ -73,10 +72,9 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( // NB some extensions might be meaningful and should not be stripped - // "this.binary.file" // should not lose ".file" but GetFileNameStrippingExtension() will do - // precisely that. - // Ideally, we should have a per-platform list of extensions (".exe", - // ".app", ".dSYM", ".framework") - // which should be stripped while leaving "this.binary.file" as-is. + // precisely that. Ideally, we should have a per-platform list of + // extensions (".exe", ".app", ".dSYM", ".framework") which should be + // stripped while leaving "this.binary.file" as-is. ScriptInterpreter *script_interpreter = target->GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); @@ -101,14 +99,11 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( // FIXME: for Python, we cannot allow certain characters in // module // filenames we import. Theoretically, different scripting - // languages may - // have different sets of forbidden tokens in filenames, and - // that should - // be dealt with by each ScriptInterpreter. For now, we just - // replace dots - // with underscores, but if we ever support anything other than - // Python - // we will need to rework this + // languages may have different sets of forbidden tokens in + // filenames, and that should be dealt with by each + // ScriptInterpreter. For now, we just replace dots with + // underscores, but if we ever support anything other than + // Python we will need to rework this std::replace(module_basename.begin(), module_basename.end(), '.', '_'); std::replace(module_basename.begin(), module_basename.end(), @@ -125,9 +120,9 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( StreamString path_string; StreamString original_path_string; // for OSX we are going to be in - // .dSYM/Contents/Resources/DWARF/<basename> - // let us go to .dSYM/Contents/Resources/Python/<basename>.py - // and see if the file exists + // .dSYM/Contents/Resources/DWARF/<basename> let us go to + // .dSYM/Contents/Resources/Python/<basename>.py and see if the + // file exists path_string.Printf("%s/../Python/%s.py", symfile_spec.GetDirectory().GetCString(), module_basename.c_str()); @@ -140,9 +135,8 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( true); // 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 + // 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()) { @@ -178,8 +172,8 @@ FileSpecList PlatformDarwin::LocateExecutableScriptingResources( break; } - // If we didn't find the python file, then keep - // stripping the extensions and try again + // If we didn't find the python file, then keep stripping the + // extensions and try again ConstString filename_no_extension( module_spec.GetFileNameStrippingExtension()); if (module_spec.GetFilename() == filename_no_extension) @@ -270,8 +264,8 @@ lldb_private::Status PlatformDarwin::GetSharedModuleWithLocalCache( FileSpec module_cache_spec(cache_path, false); // 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 connection + // efficient when files are the same on the local and remote end of the + // connection if (this->GetSupportsRSync()) { err = BringInRemoteFile(this, module_spec, module_cache_spec); if (err.Fail()) @@ -370,8 +364,8 @@ Status PlatformDarwin::GetSharedModule( module_sp.reset(); if (IsRemote()) { - // If we have a remote platform always, let it try and locate - // the shared module first. + // If we have a remote platform always, let it try and locate the shared + // module first. if (m_remote_platform_sp) { error = m_remote_platform_sp->GetSharedModule( module_spec, process, module_sp, module_search_paths_ptr, @@ -453,8 +447,8 @@ PlatformDarwin::GetSoftwareBreakpointTrapOpcode(Target &target, switch (machine) { case llvm::Triple::aarch64: { // TODO: fix this with actual darwin breakpoint opcode for arm64. - // right now debugging uses the Z packets with GDB remote so this - // is not needed, but the size needs to be correct... + // right now debugging uses the Z packets with GDB remote so this is not + // needed, but the size needs to be correct... static const uint8_t g_arm64_breakpoint_opcode[] = {0xFE, 0xDE, 0xFF, 0xE7}; trap_opcode = g_arm64_breakpoint_opcode; trap_opcode_size = sizeof(g_arm64_breakpoint_opcode); @@ -472,7 +466,7 @@ PlatformDarwin::GetSoftwareBreakpointTrapOpcode(Target &target, lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); if (bp_loc_sp) bp_is_thumb = bp_loc_sp->GetAddress().GetAddressClass() == - eAddressClassCodeAlternateISA; + AddressClass::eCodeAlternateISA; } if (bp_is_thumb) { trap_opcode = g_thumb_breakpooint_opcode; @@ -548,8 +542,8 @@ bool PlatformDarwin::x86GetSupportedArchitectureAtIndex(uint32_t idx, HostInfo::GetArchitecture(HostInfo::eArchKind64)); if (platform_arch.IsExactMatch(platform_arch64)) { // This macosx platform supports both 32 and 64 bit. Since we already - // returned the 64 bit arch for idx == 0, return the 32 bit arch - // for idx == 1 + // returned the 64 bit arch for idx == 0, return the 32 bit arch for + // idx == 1 arch = HostInfo::GetArchitecture(HostInfo::eArchKind32); return arch.IsValid(); } @@ -558,9 +552,9 @@ bool PlatformDarwin::x86GetSupportedArchitectureAtIndex(uint32_t idx, return false; } -// The architecture selection rules for arm processors -// These cpu subtypes have distinct names (e.g. armv7f) but armv7 binaries run -// fine on an armv7f processor. +// The architecture selection rules for arm processors These cpu subtypes have +// distinct names (e.g. armv7f) but armv7 binaries run fine on an armv7f +// processor. bool PlatformDarwin::ARMGetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) { @@ -1138,14 +1132,15 @@ const char *PlatformDarwin::GetDeveloperDirectory() { if (m_developer_directory.empty()) { bool developer_dir_path_valid = false; char developer_dir_path[PATH_MAX]; - FileSpec temp_file_spec; // Get the lldb framework's file path, and if it exists, truncate some // components to only the developer directory path. - if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, temp_file_spec)) { + FileSpec temp_file_spec = HostInfo::GetShlibDir(); + if (temp_file_spec) { if (temp_file_spec.GetPath(developer_dir_path, sizeof(developer_dir_path))) { - // e.g. /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework + // e.g. + // /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework char *shared_frameworks = strstr(developer_dir_path, "/SharedFrameworks/LLDB.framework"); if (shared_frameworks) { @@ -1153,7 +1148,8 @@ const char *PlatformDarwin::GetDeveloperDirectory() { strncat (developer_dir_path, "/Developer", sizeof (developer_dir_path) - 1); // add /Developer on developer_dir_path_valid = true; } else { - // e.g. /Applications/Xcode.app/Contents/Developer/Toolchains/iOS11.2.xctoolchain/System/Library/PrivateFrameworks/LLDB.framework + // e.g. + // /Applications/Xcode.app/Contents/Developer/Toolchains/iOS11.2.xctoolchain/System/Library/PrivateFrameworks/LLDB.framework char *developer_toolchains = strstr(developer_dir_path, "/Contents/Developer/Toolchains/"); if (developer_toolchains) { @@ -1171,7 +1167,7 @@ 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); + temp_file_spec.SetFile(xcode_dir_path, false, FileSpec::Style::native); auto dir_buffer = DataBufferLLVM::CreateFromPath(temp_file_spec.GetPath()); if (dir_buffer && dir_buffer->GetByteSize() > 0) { @@ -1196,7 +1192,7 @@ const char *PlatformDarwin::GetDeveloperDirectory() { Host::RunShellCommand("/usr/bin/xcode-select --print-path", NULL, // current working directory &exit_status, &signo, &command_output, - 2, // short timeout + std::chrono::seconds(2), // short timeout false); // don't run in a shell if (error.Success() && exit_status == 0 && !command_output.empty()) { const char *cmd_output_ptr = command_output.c_str(); @@ -1219,7 +1215,8 @@ const char *PlatformDarwin::GetDeveloperDirectory() { } if (developer_dir_path_valid) { - temp_file_spec.SetFile(developer_dir_path, false); + temp_file_spec.SetFile(developer_dir_path, false, + FileSpec::Style::native); if (temp_file_spec.Exists()) { m_developer_directory.assign(developer_dir_path); return m_developer_directory.c_str(); @@ -1230,8 +1227,8 @@ const char *PlatformDarwin::GetDeveloperDirectory() { m_developer_directory.assign(1, '\0'); } - // We should have put a single NULL character into m_developer_directory - // or it should have a valid path if the code gets here + // We should have put a single NULL character into m_developer_directory or + // it should have a valid path if the code gets here assert(m_developer_directory.empty() == false); if (m_developer_directory[0]) return m_developer_directory.c_str(); @@ -1279,17 +1276,11 @@ PlatformDarwin::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { shell_name++; if (strcmp(shell_name, "sh") == 0) { - // /bin/sh re-exec's itself as /bin/bash requiring another resume. - // But it only does this if the COMMAND_MODE environment variable - // is set to "legacy". - const char **envp = - launch_info.GetEnvironmentEntries().GetConstArgumentVector(); - if (envp != NULL) { - for (int i = 0; envp[i] != NULL; i++) { - if (strcmp(envp[i], "COMMAND_MODE=legacy") == 0) - return 2; - } - } + // /bin/sh re-exec's itself as /bin/bash requiring another resume. But it + // only does this if the COMMAND_MODE environment variable is set to + // "legacy". + if (launch_info.GetEnvironment().lookup("COMMAND_MODE") == "legacy") + return 2; return 1; } else if (strcmp(shell_name, "csh") == 0 || strcmp(shell_name, "tcsh") == 0 || @@ -1310,7 +1301,7 @@ static const char *const sdk_strings[] = { static FileSpec CheckPathForXcode(const FileSpec &fspec) { if (fspec.Exists()) { - const char substr[] = ".app/Contents/"; + const char substr[] = ".app/Contents"; std::string path_to_shlib = fspec.GetPath(); size_t pos = path_to_shlib.rfind(substr); @@ -1339,9 +1330,8 @@ static FileSpec GetXcodeContentsPath() { // First get the program file spec. If lldb.so or LLDB.framework is running // in a program and that program is Xcode, the path returned with be the - // path - // to Xcode.app/Contents/MacOS/Xcode, so this will be the correct Xcode to - // use. + // path to Xcode.app/Contents/MacOS/Xcode, so this will be the correct + // Xcode to use. fspec = HostInfo::GetProgramFileSpec(); if (fspec) { @@ -1375,7 +1365,7 @@ static FileSpec GetXcodeContentsPath() { &signo, // Put the signal that caused the process to exit in here &output, // Get the output from the command and place it in this // string - 3); // Timeout in seconds to wait for shell program to finish + std::chrono::seconds(3)); if (status == 0 && !output.empty()) { size_t first_non_newline = output.find_last_not_of("\r\n"); if (first_non_newline != std::string::npos) { @@ -1392,18 +1382,14 @@ static FileSpec GetXcodeContentsPath() { return g_xcode_filespec; } -bool PlatformDarwin::SDKSupportsModules(SDKType sdk_type, uint32_t major, - uint32_t minor, uint32_t micro) { +bool PlatformDarwin::SDKSupportsModules(SDKType sdk_type, + llvm::VersionTuple version) { switch (sdk_type) { case SDKType::MacOSX: - if (major > 10 || (major == 10 && minor >= 10)) - return true; - break; + return version >= llvm::VersionTuple(10, 10); case SDKType::iPhoneOS: case SDKType::iPhoneSimulator: - if (major >= 8) - return true; - break; + return version >= llvm::VersionTuple(8); } return false; @@ -1425,32 +1411,10 @@ bool PlatformDarwin::SDKSupportsModules(SDKType desired_type, return false; } - const size_t major_dot_offset = version_part.find('.'); - if (major_dot_offset == llvm::StringRef::npos) - return false; - - const llvm::StringRef major_version = - version_part.slice(0, major_dot_offset); - const llvm::StringRef minor_part = - version_part.drop_front(major_dot_offset + 1); - - const size_t minor_dot_offset = minor_part.find('.'); - if (minor_dot_offset == llvm::StringRef::npos) - return false; - - const llvm::StringRef minor_version = minor_part.slice(0, minor_dot_offset); - - unsigned int major = 0; - unsigned int minor = 0; - unsigned int micro = 0; - - if (major_version.getAsInteger(10, major)) - return false; - - if (minor_version.getAsInteger(10, minor)) + llvm::VersionTuple version; + if (version.tryParse(version_part)) return false; - - return SDKSupportsModules(desired_type, major, minor, micro); + return SDKSupportsModules(desired_type, version); } return false; @@ -1522,18 +1486,17 @@ FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { sdks_spec.AppendPathComponent("SDKs"); if (sdk_type == SDKType::MacOSX) { - uint32_t major = 0; - uint32_t minor = 0; - uint32_t micro = 0; + llvm::VersionTuple version = HostInfo::GetOSVersion(); - if (HostInfo::GetOSVersion(major, minor, micro)) { - if (SDKSupportsModules(SDKType::MacOSX, major, minor, micro)) { + if (!version.empty()) { + if (SDKSupportsModules(SDKType::MacOSX, version)) { // We slightly prefer the exact SDK for this machine. See if it is // there. FileSpec native_sdk_spec = sdks_spec; StreamString native_sdk_name; - native_sdk_name.Printf("MacOSX%u.%u.sdk", major, minor); + native_sdk_name.Printf("MacOSX%u.%u.sdk", version.getMajor(), + version.getMinor().getValueOr(0)); native_sdk_spec.AppendPathComponent(native_sdk_name.GetString()); if (native_sdk_spec.Exists()) { @@ -1546,14 +1509,14 @@ FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { return FindSDKInXcodeForModules(sdk_type, sdks_spec); } -std::tuple<uint32_t, uint32_t, uint32_t, llvm::StringRef> +std::tuple<llvm::VersionTuple, llvm::StringRef> PlatformDarwin::ParseVersionBuildDir(llvm::StringRef dir) { - uint32_t major, minor, update; llvm::StringRef build; llvm::StringRef version_str; llvm::StringRef build_str; std::tie(version_str, build_str) = dir.split(' '); - if (Args::StringToVersion(version_str, major, minor, update) || + llvm::VersionTuple version; + if (!version.tryParse(version_str) || build_str.empty()) { if (build_str.consume_front("(")) { size_t pos = build_str.find(')'); @@ -1561,7 +1524,7 @@ PlatformDarwin::ParseVersionBuildDir(llvm::StringRef dir) { } } - return std::make_tuple(major, minor, update, build); + return std::make_tuple(version, build); } void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( @@ -1573,7 +1536,6 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( options.insert(options.end(), apple_arguments.begin(), apple_arguments.end()); StreamString minimum_version_option; - uint32_t versions[3] = {0, 0, 0}; bool use_current_os_version = false; switch (sdk_type) { case SDKType::iPhoneOS: @@ -1597,9 +1559,9 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( break; } - bool versions_valid = false; + llvm::VersionTuple version; if (use_current_os_version) - versions_valid = GetOSVersion(versions[0], versions[1], versions[2]); + version = GetOSVersion(); else if (target) { // Our OS doesn't match our executable so we need to get the min OS version // from the object file @@ -1607,35 +1569,23 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( if (exe_module_sp) { ObjectFile *object_file = exe_module_sp->GetObjectFile(); if (object_file) - versions_valid = object_file->GetMinimumOSVersion(versions, 3) > 0; + version = object_file->GetMinimumOSVersion(); } } // Only add the version-min options if we got a version from somewhere - if (versions_valid && versions[0] != UINT32_MAX) { - // Make any invalid versions be zero if needed - if (versions[1] == UINT32_MAX) - versions[1] = 0; - if (versions[2] == UINT32_MAX) - versions[2] = 0; - + if (!version.empty()) { switch (sdk_type) { case SDKType::iPhoneOS: minimum_version_option.PutCString("-mios-version-min="); - minimum_version_option.PutCString( - clang::VersionTuple(versions[0], versions[1], versions[2]) - .getAsString()); + minimum_version_option.PutCString(version.getAsString()); break; case SDKType::iPhoneSimulator: minimum_version_option.PutCString("-mios-simulator-version-min="); - minimum_version_option.PutCString( - clang::VersionTuple(versions[0], versions[1], versions[2]) - .getAsString()); + minimum_version_option.PutCString(version.getAsString()); break; case SDKType::MacOSX: minimum_version_option.PutCString("-mmacosx-version-min="); - minimum_version_option.PutCString( - clang::VersionTuple(versions[0], versions[1], versions[2]) - .getAsString()); + minimum_version_option.PutCString(version.getAsString()); } options.push_back(minimum_version_option.GetString()); } @@ -1662,49 +1612,35 @@ ConstString PlatformDarwin::GetFullNameForDylib(ConstString basename) { return ConstString(stream.GetString()); } -bool PlatformDarwin::GetOSVersion(uint32_t &major, uint32_t &minor, - uint32_t &update, Process *process) { +llvm::VersionTuple PlatformDarwin::GetOSVersion(Process *process) { if (process && strstr(GetPluginName().GetCString(), "-simulator")) { lldb_private::ProcessInstanceInfo proc_info; if (Host::GetProcessInfo(process->GetID(), proc_info)) { - Args &env = proc_info.GetEnvironmentEntries(); - const size_t n = env.GetArgumentCount(); - const llvm::StringRef k_runtime_version("SIMULATOR_RUNTIME_VERSION="); - const llvm::StringRef k_dyld_root_path("DYLD_ROOT_PATH="); - std::string dyld_root_path; - - for (size_t i = 0; i < n; ++i) { - const char *env_cstr = env.GetArgumentAtIndex(i); - if (env_cstr) { - llvm::StringRef env_str(env_cstr); - if (env_str.consume_front(k_runtime_version)) { - if (Args::StringToVersion(env_str, major, minor, update)) - return true; - } else if (env_str.consume_front(k_dyld_root_path)) { - dyld_root_path = env_str; - } - } - } + const Environment &env = proc_info.GetEnvironment(); + llvm::VersionTuple result; + if (!result.tryParse(env.lookup("SIMULATOR_RUNTIME_VERSION"))) + return result; + + std::string dyld_root_path = env.lookup("DYLD_ROOT_PATH"); if (!dyld_root_path.empty()) { dyld_root_path += "/System/Library/CoreServices/SystemVersion.plist"; ApplePropertyList system_version_plist(dyld_root_path.c_str()); std::string product_version; if (system_version_plist.GetValueAsString("ProductVersion", product_version)) { - return Args::StringToVersion(product_version, major, minor, update); + if (!result.tryParse(product_version)) + return result; } } } // For simulator platforms, do NOT call back through - // Platform::GetOSVersion() - // as it might call Process::GetHostOSVersion() which we don't want as it - // will be - // incorrect - return false; + // Platform::GetOSVersion() as it might call Process::GetHostOSVersion() + // which we don't want as it will be incorrect + return llvm::VersionTuple(); } - return Platform::GetOSVersion(major, minor, update, process); + return Platform::GetOSVersion(process); } lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) { @@ -1713,8 +1649,8 @@ lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) { // any executable directories that should be searched. static std::vector<FileSpec> g_executable_dirs; - // Find the global list of directories that we will search for - // executables once so we don't keep doing the work over and over. + // Find the global list of directories that we will search for executables + // once so we don't keep doing the work over and over. static llvm::once_flag g_once_flag; llvm::call_once(g_once_flag, []() { @@ -1748,22 +1684,19 @@ lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) { lldb_private::Status PlatformDarwin::LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) { - // Starting in Fall 2016 OSes, NSLog messages only get mirrored to stderr - // if the OS_ACTIVITY_DT_MODE environment variable is set. (It doesn't - // require any specific value; rather, it just needs to exist). - // We will set it here as long as the IDE_DISABLED_OS_ACTIVITY_DT_MODE flag - // is not set. Xcode makes use of IDE_DISABLED_OS_ACTIVITY_DT_MODE to tell + // Starting in Fall 2016 OSes, NSLog messages only get mirrored to stderr if + // the OS_ACTIVITY_DT_MODE environment variable is set. (It doesn't require + // any specific value; rather, it just needs to exist). We will set it here + // as long as the IDE_DISABLED_OS_ACTIVITY_DT_MODE flag is not set. Xcode + // makes use of IDE_DISABLED_OS_ACTIVITY_DT_MODE to tell // LLDB *not* to muck with the OS_ACTIVITY_DT_MODE flag when they // specifically want it unset. const char *disable_env_var = "IDE_DISABLED_OS_ACTIVITY_DT_MODE"; - auto &env_vars = launch_info.GetEnvironmentEntries(); - if (!env_vars.ContainsEnvironmentVariable(llvm::StringRef(disable_env_var))) { - // We want to make sure that OS_ACTIVITY_DT_MODE is set so that - // we get os_log and NSLog messages mirrored to the target process - // stderr. - if (!env_vars.ContainsEnvironmentVariable( - llvm::StringRef("OS_ACTIVITY_DT_MODE"))) - env_vars.AppendArgument(llvm::StringRef("OS_ACTIVITY_DT_MODE=enable")); + auto &env_vars = launch_info.GetEnvironment(); + if (!env_vars.count(disable_env_var)) { + // We want to make sure that OS_ACTIVITY_DT_MODE is set so that we get + // os_log and NSLog messages mirrored to the target process stderr. + env_vars.try_emplace("OS_ACTIVITY_DT_MODE", "enable"); } // Let our parent class do the real launching. @@ -1777,24 +1710,23 @@ PlatformDarwin::FindBundleBinaryInExecSearchPaths (const ModuleSpec &module_spec ModuleSP *old_module_sp_ptr, bool *did_create_ptr) { const FileSpec &platform_file = module_spec.GetFileSpec(); - // See if the file is present in any of the module_search_paths_ptr directories. + // See if the file is present in any of the module_search_paths_ptr + // directories. if (!module_sp && module_search_paths_ptr && platform_file) { - // create a vector of all the file / directory names in platform_file - // e.g. this might be + // create a vector of all the file / directory names in platform_file e.g. + // this might be // /System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation // - // We'll need to look in the module_search_paths_ptr directories for - // both "UIFoundation" and "UIFoundation.framework" -- most likely the - // latter will be the one we find there. + // We'll need to look in the module_search_paths_ptr directories for both + // "UIFoundation" and "UIFoundation.framework" -- most likely the latter + // will be the one we find there. FileSpec platform_pull_apart(platform_file); std::vector<std::string> path_parts; - ConstString unix_root_dir("/"); - while (true) { + path_parts.push_back( + platform_pull_apart.GetLastPathComponent().AsCString()); + while (platform_pull_apart.RemoveLastPathComponent()) { ConstString part = platform_pull_apart.GetLastPathComponent(); - platform_pull_apart.RemoveLastPathComponent(); - if (part.IsEmpty() || part == unix_root_dir) - break; path_parts.push_back(part.AsCString()); } const size_t path_parts_size = path_parts.size(); @@ -1804,25 +1736,24 @@ PlatformDarwin::FindBundleBinaryInExecSearchPaths (const ModuleSpec &module_spec Log *log_verbose = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log_verbose) log_verbose->Printf ("PlatformRemoteDarwinDevice::GetSharedModule searching for binary in search-path %s", module_search_paths_ptr->GetFileSpecAtIndex(i).GetPath().c_str()); - // Create a new FileSpec with this module_search_paths_ptr - // plus just the filename ("UIFoundation"), then the parent - // dir plus filename ("UIFoundation.framework/UIFoundation") - // etc - up to four names (to handle "Foo.framework/Contents/MacOS/Foo") + // Create a new FileSpec with this module_search_paths_ptr plus just the + // filename ("UIFoundation"), then the parent dir plus filename + // ("UIFoundation.framework/UIFoundation") etc - up to four names (to + // handle "Foo.framework/Contents/MacOS/Foo") for (size_t j = 0; j < 4 && j < path_parts_size - 1; ++j) { FileSpec path_to_try(module_search_paths_ptr->GetFileSpecAtIndex(i)); // Add the components backwards. For - // .../PrivateFrameworks/UIFoundation.framework/UIFoundation - // path_parts is + // .../PrivateFrameworks/UIFoundation.framework/UIFoundation path_parts + // is // [0] UIFoundation // [1] UIFoundation.framework // [2] PrivateFrameworks // // and if 'j' is 2, we want to append path_parts[1] and then - // path_parts[0], aka - // 'UIFoundation.framework/UIFoundation', to the module_search_paths_ptr - // path. + // path_parts[0], aka 'UIFoundation.framework/UIFoundation', to the + // module_search_paths_ptr path. for (int k = j; k >= 0; --k) { path_to_try.AppendPathComponent(path_parts[k]); diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/source/Plugins/Platform/MacOSX/PlatformDarwin.h index c04318e98cae..3ad29ec1a0b9 100644 --- a/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -69,8 +69,8 @@ public: void CalculateTrapHandlerSymbolNames() override; - bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update, - lldb_private::Process *process = nullptr) override; + llvm::VersionTuple + GetOSVersion(lldb_private::Process *process = nullptr) override; bool SupportsModules() override { return true; } @@ -82,7 +82,7 @@ public: lldb_private::Status LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) override; - static std::tuple<uint32_t, uint32_t, uint32_t, llvm::StringRef> + static std::tuple<llvm::VersionTuple, llvm::StringRef> ParseVersionBuildDir(llvm::StringRef str); protected: @@ -101,8 +101,7 @@ protected: iPhoneOS, }; - static bool SDKSupportsModules(SDKType sdk_type, uint32_t major, - uint32_t minor, uint32_t micro); + static bool SDKSupportsModules(SDKType sdk_type, llvm::VersionTuple version); static bool SDKSupportsModules(SDKType desired_type, const lldb_private::FileSpec &sdk_path); diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp index e5d27fc28949..1e3216c0af5a 100644 --- a/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp @@ -92,11 +92,9 @@ PlatformSP PlatformDarwinKernel::CreateInstance(bool force, } // This is a special plugin that we don't want to activate just based on an - // 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. + // 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 (log) log->Printf("PlatformDarwinKernel::%s() aborting creation of platform " @@ -115,9 +113,8 @@ PlatformSP PlatformDarwinKernel::CreateInstance(bool force, create = true; break; - // 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) + // 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: create = !arch->TripleVendorWasSpecified(); break; @@ -133,9 +130,8 @@ PlatformSP PlatformDarwinKernel::CreateInstance(bool force, case llvm::Triple::WatchOS: case llvm::Triple::TvOS: 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) + // 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) case llvm::Triple::UnknownOS: create = !arch->TripleOSWasSpecified(); break; @@ -341,11 +337,9 @@ void PlatformDarwinKernel::GetStatus(Stream &strm) { void PlatformDarwinKernel::CollectKextAndKernelDirectories() { // Differentiate between "ios debug session" and "mac debug session" so we - // don't index - // kext bundles that won't be used in this debug session. If this is an ios - // kext debug - // session, looking in /System/Library/Extensions is a waste of stat()s, for - // example. + // don't index kext bundles that won't be used in this debug session. If + // this is an ios kext debug session, looking in /System/Library/Extensions + // is a waste of stat()s, for example. // DeveloperDirectory is something like // "/Applications/Xcode.app/Contents/Developer" @@ -368,9 +362,8 @@ void PlatformDarwinKernel::CollectKextAndKernelDirectories() { AddSDKSubdirsToSearchPaths("/Volumes/KernelDebugKit"); AddSDKSubdirsToSearchPaths("/AppleInternal/Developer/KDKs"); - // The KDKs distributed from Apple installed on external - // developer systems may be in directories like - // /Library/Developer/KDKs/KDK_10.10_14A298i.kdk + // The KDKs distributed from Apple installed on external developer systems + // may be in directories like /Library/Developer/KDKs/KDK_10.10_14A298i.kdk AddSDKSubdirsToSearchPaths("/Library/Developer/KDKs"); if (m_ios_debug_session != eLazyBoolNo) { @@ -438,8 +431,8 @@ void PlatformDarwinKernel::AddSDKSubdirsToSearchPaths(const std::string &dir) { FileSpec::EnumerateDirectoryResult PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory( void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec) { - static ConstString g_sdk_suffix = ConstString("sdk"); - static ConstString g_kdk_suffix = ConstString("kdk"); + static ConstString g_sdk_suffix = ConstString(".sdk"); + static ConstString g_kdk_suffix = ConstString(".kdk"); PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; if (ft == llvm::sys::fs::file_type::directory_file && @@ -450,9 +443,8 @@ PlatformDarwinKernel::FindKDKandSDKDirectoriesInDirectory( return FileSpec::eEnumerateDirectoryResultNext; } -// Recursively search trough m_search_directories looking for -// kext and kernel binaries, adding files found to the appropriate -// lists. +// Recursively search trough m_search_directories looking for kext and kernel +// binaries, adding files found to the appropriate lists. void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() { const uint32_t num_dirs = m_search_directories.size(); for (uint32_t i = 0; i < num_dirs; i++) { @@ -476,13 +468,11 @@ void PlatformDarwinKernel::SearchForKextsAndKernelsRecursively() { } } -// We're only doing a filename match here. We won't try opening the file to see -// if it's really -// a kernel or not until we need to find a kernel of a given UUID. There's no -// cheap way to find -// the UUID of a file (or if it's a Mach-O binary at all) without creating a -// whole Module for -// the file and throwing it away if it's not wanted. +// We're only doing a filename match here. We won't try opening the file to +// see if it's really a kernel or not until we need to find a kernel of a given +// UUID. There's no cheap way to find the UUID of a file (or if it's a Mach-O +// binary at all) without creating a whole Module for the file and throwing it +// away if it's not wanted. // // Recurse into any subdirectories found. @@ -502,8 +492,8 @@ FileSpec::EnumerateDirectoryResult PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( void *baton, llvm::sys::fs::file_type ft, const FileSpec &file_spec, bool recurse) { - static ConstString g_kext_suffix = ConstString("kext"); - static ConstString g_dsym_suffix = ConstString("dSYM"); + static ConstString g_kext_suffix = ConstString(".kext"); + static ConstString g_dsym_suffix = ConstString(".dSYM"); static ConstString g_bundle_suffix = ConstString("Bundle"); ConstString file_spec_extension = file_spec.GetFileNameExtension(); @@ -633,7 +623,7 @@ 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); + dsym_fspec.SetFile(deep_bundle_str, true, FileSpec::Style::native); if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { return true; } @@ -643,15 +633,15 @@ 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); + dsym_fspec.SetFile(shallow_bundle_str, true, FileSpec::Style::native); if (llvm::sys::fs::is_directory(dsym_fspec.GetPath())) { return true; } return false; } -// Given a FileSpec of /dir/dir/mach.development.t7004 -// Return true if a dSYM exists next to it: +// Given a FileSpec of /dir/dir/mach.development.t7004 Return true if a dSYM +// exists next to it: // /dir/dir/mach.development.t7004.dSYM bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) { FileSpec kernel_dsym = kernel_binary; @@ -694,8 +684,8 @@ Status PlatformDarwinKernel::GetSharedModule( } } - // Give the generic methods, including possibly calling into - // DebugSymbols framework on macOS systems, a chance. + // Give the generic methods, including possibly calling into DebugSymbols + // framework on macOS systems, a chance. error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr); @@ -749,8 +739,8 @@ Status PlatformDarwinKernel::GetSharedModule( } } - // Give the generic methods, including possibly calling into - // DebugSymbols framework on macOS systems, a chance. + // Give the generic methods, including possibly calling into DebugSymbols + // framework on macOS systems, a chance. error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr); @@ -789,37 +779,53 @@ Status PlatformDarwinKernel::GetSharedModule( return error; } +std::vector<lldb_private::FileSpec> +PlatformDarwinKernel::SearchForExecutablesRecursively(const std::string &dir) { + std::vector<FileSpec> executables; + std::error_code EC; + for (llvm::sys::fs::recursive_directory_iterator it(dir.c_str(), EC), + end; + it != end && !EC; it.increment(EC)) { + auto status = it->status(); + if (!status) + break; + if (llvm::sys::fs::is_regular_file(*status) && + llvm::sys::fs::can_execute(it->path())) + executables.emplace_back(it->path(), false); + } + return executables; +} + Status PlatformDarwinKernel::ExamineKextForMatchingUUID( const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid, const ArchSpec &arch, ModuleSP &exe_module_sp) { - Status error; - FileSpec exe_file = kext_bundle_path; - Host::ResolveExecutableInBundle(exe_file); - if (exe_file.Exists()) { - ModuleSpec exe_spec(exe_file); - exe_spec.GetUUID() = uuid; - if (!uuid.IsValid()) { - exe_spec.GetArchitecture() = arch; - } + for (const auto &exe_file : + SearchForExecutablesRecursively(kext_bundle_path.GetPath())) { + if (exe_file.Exists()) { + ModuleSpec exe_spec(exe_file); + exe_spec.GetUUID() = uuid; + if (!uuid.IsValid()) { + exe_spec.GetArchitecture() = arch; + } - // First try to create a ModuleSP with the file / arch and see if the UUID - // matches. - // If that fails (this exec file doesn't have the correct uuid), don't call - // GetSharedModule - // (which may call in to the DebugSymbols framework and therefore can be - // slow.) - ModuleSP module_sp(new Module(exe_spec)); - if (module_sp && module_sp->GetObjectFile() && - module_sp->MatchesModuleSpec(exe_spec)) { - error = ModuleList::GetSharedModule(exe_spec, exe_module_sp, NULL, NULL, - NULL); - if (exe_module_sp && exe_module_sp->GetObjectFile()) { - return error; + // First try to create a ModuleSP with the file / arch and see if the UUID + // matches. If that fails (this exec file doesn't have the correct uuid), + // don't call GetSharedModule (which may call in to the DebugSymbols + // framework and therefore can be slow.) + ModuleSP module_sp(new Module(exe_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(exe_spec)) { + Status error = ModuleList::GetSharedModule(exe_spec, exe_module_sp, + NULL, NULL, NULL); + if (exe_module_sp && exe_module_sp->GetObjectFile()) { + return error; + } } + exe_module_sp.reset(); } - exe_module_sp.reset(); } - return error; + + return {}; } bool PlatformDarwinKernel::GetSupportedArchitectureAtIndex(uint32_t idx, @@ -851,17 +857,13 @@ void PlatformDarwinKernel::CalculateTrapHandlerSymbolNames() { #else // __APPLE__ -// Since DynamicLoaderDarwinKernel is compiled in for all systems, and relies on -// PlatformDarwinKernel for the plug-in name, we compile just the plug-in name -// in -// here to avoid issues. We are tracking an internal bug to resolve this issue -// by -// either not compiling in DynamicLoaderDarwinKernel for non-apple builds, or to -// make -// PlatformDarwinKernel build on all systems. PlatformDarwinKernel is currently -// not -// compiled on other platforms due to the use of the Mac-specific -// source/Host/macosx/cfcpp utilities. +// Since DynamicLoaderDarwinKernel is compiled in for all systems, and relies +// on PlatformDarwinKernel for the plug-in name, we compile just the plug-in +// name in here to avoid issues. We are tracking an internal bug to resolve +// this issue by either not compiling in DynamicLoaderDarwinKernel for non- +// apple builds, or to make PlatformDarwinKernel build on all systems. +// PlatformDarwinKernel is currently not compiled on other platforms due to the +// use of the Mac-specific source/Host/macosx/cfcpp utilities. lldb_private::ConstString PlatformDarwinKernel::GetPluginNameStatic() { static lldb_private::ConstString g_name("darwin-kernel"); diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h index 9b3ec5e0d717..7f603cac2bec 100644 --- a/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h +++ b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h @@ -127,6 +127,9 @@ protected: const lldb_private::FileSpec &file_spec, bool recurse); + static std::vector<lldb_private::FileSpec> + SearchForExecutablesRecursively(const std::string &dir); + static void AddKextToMap(PlatformDarwinKernel *thisp, const lldb_private::FileSpec &file_spec); @@ -201,6 +204,7 @@ public: // source/Host/macosx/cfcpp utilities. class PlatformDarwinKernel { +public: static lldb_private::ConstString GetPluginNameStatic(); }; diff --git a/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp index 43f4d8bbf023..99f603b01f43 100644 --- a/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp @@ -91,9 +91,8 @@ PlatformSP PlatformMacOSX::CreateInstance(bool force, const ArchSpec *arch) { break; #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) + // 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: create = !arch->TripleVendorWasSpecified(); break; @@ -109,9 +108,8 @@ PlatformSP PlatformMacOSX::CreateInstance(bool force, const ArchSpec *arch) { case llvm::Triple::MacOSX: break; #if defined(__APPLE__) - // 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) + // 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) case llvm::Triple::UnknownOS: create = !arch->TripleOSWasSpecified(); break; @@ -175,7 +173,8 @@ ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) { FileSpec fspec; uint32_t versions[2]; if (objfile->GetSDKVersion(versions, sizeof(versions))) { - if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, fspec)) { + fspec = HostInfo::GetShlibDir(); + if (fspec) { std::string path; xcode_contents_path = fspec.GetPath(); size_t pos = xcode_contents_path.find("/Xcode.app/Contents/"); @@ -198,7 +197,7 @@ ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) { // here &output, // Get the output from the command and place it in this // string - 3); // Timeout in seconds to wait for shell program to finish + std::chrono::seconds(3)); if (status == 0 && !output.empty()) { size_t first_non_newline = output.find_last_not_of("\r\n"); if (first_non_newline != std::string::npos) @@ -219,13 +218,13 @@ 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); + fspec.SetFile(sdk_path.GetString(), false, FileSpec::Style::native); if (fspec.Exists()) return ConstString(sdk_path.GetString()); } if (!default_xcode_sdk.empty()) { - fspec.SetFile(default_xcode_sdk, false); + fspec.SetFile(default_xcode_sdk, false, FileSpec::Style::native); if (fspec.Exists()) return ConstString(default_xcode_sdk); } diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp index 1eef643d3904..be4c829a981c 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp @@ -99,8 +99,8 @@ PlatformSP PlatformRemoteAppleTV::CreateInstance(bool force, #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) + // "unknown" wasn't specified (it was just returned because it was NOT + // specified) case llvm::Triple::UnknownArch: create = !arch->TripleVendorWasSpecified(); break; diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp index 17ae67bc28de..6159511d4a18 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp @@ -94,8 +94,8 @@ PlatformSP PlatformRemoteAppleWatch::CreateInstance(bool force, #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) + // "unknown" wasn't specified (it was just returned because it was NOT + // specified) case llvm::Triple::UnknownArch: create = !arch->TripleVendorWasSpecified(); break; @@ -123,8 +123,8 @@ PlatformSP PlatformRemoteAppleWatch::CreateInstance(bool force, #if defined(__APPLE__) && \ (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) - // If lldb is running on a watch, this isn't a RemoteWatch environment; it's a - // local system environment. + // If lldb is running on a watch, this isn't a RemoteWatch environment; it's + // a local system environment. if (force == false) { create = false; } diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp index cb064aad6155..930d062fe41e 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp @@ -31,12 +31,10 @@ using namespace lldb_private; PlatformRemoteDarwinDevice::SDKDirectoryInfo::SDKDirectoryInfo( const lldb_private::FileSpec &sdk_dir) - : directory(sdk_dir), build(), version_major(0), version_minor(0), - version_update(0), user_cached(false) { + : directory(sdk_dir), build(), user_cached(false) { llvm::StringRef dirname_str = sdk_dir.GetFilename().GetStringRef(); llvm::StringRef build_str; - std::tie(version_major, version_minor, version_update, build_str) = - ParseVersionBuildDir(dirname_str); + std::tie(version, build_str) = ParseVersionBuildDir(dirname_str); build.SetString(build_str); } @@ -97,9 +95,9 @@ Status PlatformRemoteDarwinDevice::ResolveExecutable( return error; exe_module_sp.reset(); } - // No valid architecture was specified or the exact ARM slice wasn't - // found so ask the platform for the architectures that we should be - // using (in the correct order) and see if we can find a match that way + // No valid architecture was specified or the exact ARM slice wasn't found + // so ask the platform for the architectures that we should be using (in + // the correct order) and see if we can find a match that way StreamString arch_names; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( idx, resolved_module_spec.GetArchitecture()); @@ -183,8 +181,8 @@ bool PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded() { &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 us. + // contain developer disk images and no symbols, so they aren't useful to + // us. FileSpec sdk_symbols_symlink_fspec; for (const auto &sdk_directory_info : builtin_sdk_directory_infos) { sdk_symbols_symlink_fspec = sdk_directory_info.directory; @@ -244,8 +242,8 @@ PlatformRemoteDarwinDevice::GetSDKDirectoryForCurrentOSVersion() { if (UpdateSDKDirectoryInfosIfNeeded()) { const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); - // Check to see if the user specified a build string. If they did, then - // be sure to match it. + // Check to see if the user specified a build string. If they did, then be + // sure to match it. std::vector<bool> check_sdk_info(num_sdk_infos, true); ConstString build(m_sdk_build); if (build) { @@ -253,26 +251,25 @@ PlatformRemoteDarwinDevice::GetSDKDirectoryForCurrentOSVersion() { check_sdk_info[i] = m_sdk_directory_infos[i].build == build; } - // If we are connected we can find the version of the OS the platform - // us running on and select the right SDK - uint32_t major, minor, update; - if (GetOSVersion(major, minor, update)) { + // If we are connected we can find the version of the OS the platform us + // running on and select the right SDK + llvm::VersionTuple version = GetOSVersion(); + if (!version.empty()) { if (UpdateSDKDirectoryInfosIfNeeded()) { // First try for an exact match of major, minor and update for (i = 0; i < num_sdk_infos; ++i) { if (check_sdk_info[i]) { - if (m_sdk_directory_infos[i].version_major == major && - m_sdk_directory_infos[i].version_minor == minor && - m_sdk_directory_infos[i].version_update == update) { + if (m_sdk_directory_infos[i].version == version) return &m_sdk_directory_infos[i]; - } } } // First try for an exact match of major and minor for (i = 0; i < num_sdk_infos; ++i) { if (check_sdk_info[i]) { - if (m_sdk_directory_infos[i].version_major == major && - m_sdk_directory_infos[i].version_minor == minor) { + if (m_sdk_directory_infos[i].version.getMajor() == + version.getMajor() && + m_sdk_directory_infos[i].version.getMinor() == + version.getMinor()) { return &m_sdk_directory_infos[i]; } } @@ -280,7 +277,8 @@ PlatformRemoteDarwinDevice::GetSDKDirectoryForCurrentOSVersion() { // Lastly try to match of major version only.. for (i = 0; i < num_sdk_infos; ++i) { if (check_sdk_info[i]) { - if (m_sdk_directory_infos[i].version_major == major) { + if (m_sdk_directory_infos[i].version.getMajor() == + version.getMajor()) { return &m_sdk_directory_infos[i]; } } @@ -300,25 +298,13 @@ const PlatformRemoteDarwinDevice::SDKDirectoryInfo * PlatformRemoteDarwinDevice::GetSDKDirectoryForLatestOSVersion() { const PlatformRemoteDarwinDevice::SDKDirectoryInfo *result = NULL; if (UpdateSDKDirectoryInfosIfNeeded()) { - 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 = 0; i < num_sdk_infos; ++i) { - const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i]; - if (sdk_dir_info.version_major != UINT32_MAX) { - if (result == NULL || - sdk_dir_info.version_major > result->version_major) { - result = &sdk_dir_info; - } else if (sdk_dir_info.version_major == result->version_major) { - if (sdk_dir_info.version_minor > result->version_minor) { - result = &sdk_dir_info; - } else if (sdk_dir_info.version_minor == result->version_minor) { - if (sdk_dir_info.version_update > result->version_update) { - result = &sdk_dir_info; - } - } - } - } - } + auto max = std::max_element( + m_sdk_directory_infos.begin(), m_sdk_directory_infos.end(), + [](const SDKDirectoryInfo &a, const SDKDirectoryInfo &b) { + return a.version < b.version; + }); + if (max != m_sdk_directory_infos.end()) + result = &*max; } return result; } @@ -366,8 +352,8 @@ const char *PlatformRemoteDarwinDevice::GetDeviceSupportDirectoryForOSVersion() } } // We should have put a single NULL character into - // m_device_support_directory_for_os_version - // or it should have a valid path if the code gets here + // m_device_support_directory_for_os_version or it should have a valid path + // if the code gets here assert(m_device_support_directory_for_os_version.empty() == false); if (m_device_support_directory_for_os_version[0]) return m_device_support_directory_for_os_version.c_str(); @@ -409,7 +395,7 @@ 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); + local_file.SetFile(sdkroot_path, false, FileSpec::Style::native); if (paths_to_try[i][0] != '\0') local_file.AppendPathComponent(paths_to_try[i]); local_file.AppendPathComponent(platform_file_path); @@ -442,7 +428,7 @@ 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); + local_file.SetFile(resolved_path, true, FileSpec::Style::native); if (local_file.Exists()) { if (log) { log->Printf("Found a copy of %s in the DeviceSupport dir %s", @@ -454,7 +440,7 @@ 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); + local_file.SetFile(resolved_path, true, FileSpec::Style::native); if (local_file.Exists()) { if (log) { log->Printf( @@ -466,7 +452,7 @@ 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); + local_file.SetFile(resolved_path, true, FileSpec::Style::native); if (local_file.Exists()) { if (log) { log->Printf("Found a copy of %s in the DeviceSupport dir %s/Symbols", @@ -492,10 +478,9 @@ Status PlatformRemoteDarwinDevice::GetSharedModule( const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, bool *did_create_ptr) { - // For iOS, the SDK files are all cached locally on the host - // system. So first we ask for the file in the cached SDK, - // then we attempt to get a shared module for the right architecture - // with the right UUID. + // For iOS, the SDK files are all cached locally on the host system. So first + // we ask for the file in the cached SDK, then we attempt to get a shared + // module for the right architecture with the right UUID. const FileSpec &platform_file = module_spec.GetFileSpec(); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); @@ -510,8 +495,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule( const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); // If we are connected we migth be able to correctly deduce the SDK - // directory - // using the OS build. + // directory using the OS build. const uint32_t connected_sdk_idx = GetConnectedSDKIndex(); if (connected_sdk_idx < num_sdk_infos) { LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file, @@ -528,8 +512,8 @@ Status PlatformRemoteDarwinDevice::GetSharedModule( } } - // Try the last SDK index if it is set as most files from an SDK - // will tend to be valid in that same SDK. + // Try the last SDK index if it is set as most files from an SDK will tend + // to be valid in that same SDK. if (m_last_module_sdk_idx < num_sdk_infos) { LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file, m_sdk_directory_infos[m_last_module_sdk_idx].directory); @@ -544,9 +528,9 @@ Status PlatformRemoteDarwinDevice::GetSharedModule( } } - // First try for an exact match of major, minor and update: - // If a particalar SDK version was specified via --version or --build, look - // for a match on disk. + // First try for an exact match of major, minor and update: If a particalar + // SDK version was specified via --version or --build, look for a match on + // disk. const SDKDirectoryInfo *current_sdk_info = GetSDKDirectoryForCurrentOSVersion(); const uint32_t current_sdk_idx = @@ -570,8 +554,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule( // Second try all SDKs that were found. for (uint32_t sdk_idx = 0; sdk_idx < num_sdk_infos; ++sdk_idx) { if (m_last_module_sdk_idx == sdk_idx) { - // Skip the last module SDK index if we already searched - // it above + // Skip the last module SDK index if we already searched it above continue; } LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file, @@ -582,8 +565,8 @@ Status PlatformRemoteDarwinDevice::GetSharedModule( error = ResolveExecutable(platform_module_spec, module_sp, NULL); if (module_sp) { - // Remember the index of the last SDK that we found a file - // in in case the wrong SDK was selected. + // Remember the index of the last SDK that we found a file in in case + // the wrong SDK was selected. m_last_module_sdk_idx = sdk_idx; error.Clear(); return error; diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h b/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h index f159e8575d76..8ddfd51600fd 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h @@ -60,9 +60,7 @@ protected: SDKDirectoryInfo(const lldb_private::FileSpec &sdk_dir_spec); lldb_private::FileSpec directory; lldb_private::ConstString build; - uint32_t version_major; - uint32_t version_minor; - uint32_t version_update; + llvm::VersionTuple version; bool user_cached; }; diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp index 5bff792525bc..150bfdbfc118 100644 --- a/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp @@ -89,8 +89,8 @@ PlatformSP PlatformRemoteiOS::CreateInstance(bool force, const ArchSpec *arch) { #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) + // "unknown" wasn't specified (it was just returned because it was NOT + // specified) case llvm::Triple::UnknownArch: create = !arch->TripleVendorWasSpecified(); break; diff --git a/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp index ee1f90311e7e..26feec282322 100644 --- a/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp +++ b/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp @@ -91,9 +91,9 @@ PlatformSP PlatformiOSSimulator::CreateInstance(bool force, 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) + // 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: create = !arch->TripleVendorWasSpecified(); break; @@ -112,9 +112,9 @@ PlatformSP PlatformiOSSimulator::CreateInstance(bool force, break; #if defined(__APPLE__) - // Only accept "unknown" for the OS if the host is Apple and - // it "unknown" wasn't specified (it was just returned because it - // was NOT specified) + // Only accept "unknown" for the OS if the host is Apple and it + // "unknown" wasn't specified (it was just returned because it was NOT + // specified) case llvm::Triple::UnknownOS: create = !arch->TripleOSWasSpecified(); break; @@ -205,9 +205,9 @@ Status PlatformiOSSimulator::ResolveExecutable( return error; exe_module_sp.reset(); } - // No valid architecture was specified or the exact ARM slice wasn't - // found so ask the platform for the architectures that we should be - // using (in the correct order) and see if we can find a match that way + // No valid architecture was specified or the exact ARM slice wasn't found + // so ask the platform for the architectures that we should be using (in + // the correct order) and see if we can find a match that way StreamString arch_names; ArchSpec platform_arch; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( @@ -298,8 +298,8 @@ const char *PlatformiOSSimulator::GetSDKDirectoryAsCString() { m_sdk_directory.assign(1, '\0'); } - // We should have put a single NULL character into m_sdk_directory - // or it should have a valid path if the code gets here + // We should have put a single NULL character into m_sdk_directory or it + // should have a valid path if the code gets here assert(m_sdk_directory.empty() == false); if (m_sdk_directory[0]) return m_sdk_directory.c_str(); @@ -320,12 +320,12 @@ 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); + local_file.SetFile(resolved_path, true, FileSpec::Style::native); if (local_file.Exists()) return error; // Else fall back to the actual path itself - local_file.SetFile(platform_file_path, true); + local_file.SetFile(platform_file_path, true, FileSpec::Style::native); if (local_file.Exists()) return error; } @@ -342,10 +342,9 @@ Status PlatformiOSSimulator::GetSharedModule( const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, bool *did_create_ptr) { - // For iOS, the SDK files are all cached locally on the host - // system. So first we ask for the file in the cached SDK, - // then we attempt to get a shared module for the right architecture - // with the right UUID. + // For iOS, the SDK files are all cached locally on the host system. So first + // we ask for the file in the cached SDK, then we attempt to get a shared + // module for the right architecture with the right UUID. Status error; ModuleSpec platform_module_spec(module_spec); const FileSpec &platform_file = module_spec.GetFileSpec(); @@ -409,14 +408,14 @@ bool PlatformiOSSimulator::GetSupportedArchitectureAtIndex(uint32_t idx, if (arch.IsValid()) { if (idx == 2) arch.GetTriple().setOS(llvm::Triple::IOS); - // 32/64: return "i386-apple-ios" for architecture 2 - // 32/64: return "i386-apple-macosx" for architecture 3 + // 32/64: return "i386-apple-ios" for architecture 2 32/64: return + // "i386-apple-macosx" for architecture 3 return true; } } } else if (idx == 1) { - // This macosx platform supports only 32 bit, so return the *-apple-macosx - // version + // This macosx platform supports only 32 bit, so return the *-apple- + // macosx version arch = platform_arch; return true; } diff --git a/source/Plugins/Platform/MacOSX/objcxx/CMakeLists.txt b/source/Plugins/Platform/MacOSX/objcxx/CMakeLists.txt new file mode 100644 index 000000000000..946ff0a64c26 --- /dev/null +++ b/source/Plugins/Platform/MacOSX/objcxx/CMakeLists.txt @@ -0,0 +1,17 @@ +remove_module_flags() +include_directories(.) + +add_lldb_library(lldbPluginPlatformMacOSXObjCXX + PlatformiOSSimulatorCoreSimulatorSupport.mm + + LINK_LIBS + lldbCore + lldbSymbol + lldbTarget + lldbUtility + ${EXTRA_LIBS} + + LINK_COMPONENTS + Object + Support + ) diff --git a/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.h b/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h index 31e11a60e419..083e2d6c5687 100644 --- a/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.h +++ b/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h @@ -24,8 +24,8 @@ typedef void *id; #endif // Project includes -#include "lldb/Interpreter/Args.h" #include "lldb/Target/ProcessLaunchInfo.h" +#include "lldb/Utility/Args.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" diff --git a/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm b/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm index 7bd37683d2fd..4516a66ee8ca 100644 --- a/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm +++ b/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm @@ -478,26 +478,17 @@ CoreSimulatorSupport::Device::Spawn(ProcessLaunchInfo &launch_info) { [options setObject:args_array forKey:kSimDeviceSpawnArguments]; } - if (launch_info.GetEnvironmentEntries().GetArgumentCount()) { - const Args &envs(launch_info.GetEnvironmentEntries()); - NSMutableDictionary *env_dict = [[NSMutableDictionary alloc] init]; - for (size_t idx = 0; idx < envs.GetArgumentCount(); idx++) { - llvm::StringRef arg_sr(envs.GetArgumentAtIndex(idx)); - auto first_eq = arg_sr.find('='); - if (first_eq == llvm::StringRef::npos) - continue; - llvm::StringRef key = arg_sr.substr(0, first_eq); - llvm::StringRef value = arg_sr.substr(first_eq + 1); - - NSString *key_ns = [NSString stringWithUTF8String:key.str().c_str()]; - NSString *value_ns = [NSString stringWithUTF8String:value.str().c_str()]; - - [env_dict setValue:value_ns forKey:key_ns]; - } + NSMutableDictionary *env_dict = [[NSMutableDictionary alloc] init]; + + for (const auto &KV : launch_info.GetEnvironment()) { + NSString *key_ns = [NSString stringWithUTF8String:KV.first().str().c_str()]; + NSString *value_ns = [NSString stringWithUTF8String:KV.second.c_str()]; - [options setObject:env_dict forKey:kSimDeviceSpawnEnvironment]; + [env_dict setValue:value_ns forKey:key_ns]; } + [options setObject:env_dict forKey:kSimDeviceSpawnEnvironment]; + Status error; File stdin_file; File stdout_file; diff --git a/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp b/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp index 38bdf60c1ced..3aa8ecb4c228 100644 --- a/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp +++ b/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -30,8 +30,8 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" -// Define these constants from NetBSD mman.h for use when targeting -// remote netbsd systems even when host has different values. +// Define these constants from NetBSD mman.h for use when targeting remote +// netbsd systems even when host has different values. #define MAP_PRIVATE 0x0002 #define MAP_ANON 0x1000 @@ -45,19 +45,9 @@ static uint32_t g_initialize_count = 0; PlatformSP PlatformNetBSD::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("PlatformNetBSD::%s(force=%s, arch={%s,%s})", __FUNCTION__, - force ? "true" : "false", arch_name, triple_cstr); - } + LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force, + arch ? arch->GetArchitectureName() : "<null>", + arch ? arch->GetTriple().getTriple() : "<null>"); bool create = force; if (create == false && arch && arch->IsValid()) { @@ -72,18 +62,10 @@ PlatformSP PlatformNetBSD::CreateInstance(bool force, const ArchSpec *arch) { } } + LLDB_LOG(log, "create = {0}", create); if (create) { - if (log) - log->Printf("PlatformNetBSD::%s() creating remote-netbsd platform", - __FUNCTION__); return PlatformSP(new PlatformNetBSD(false)); } - - if (log) - log->Printf( - "PlatformNetBSD::%s() aborting creation of remote-netbsd platform", - __FUNCTION__); - return PlatformSP(); } @@ -152,7 +134,8 @@ bool PlatformNetBSD::GetSupportedArchitectureAtIndex(uint32_t idx, arch = hostArch; return arch.IsValid(); } else if (idx == 1) { - // If the default host architecture is 64-bit, look for a 32-bit variant + // If the default host architecture is 64-bit, look for a 32-bit + // variant if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit()) { arch = HostInfo::GetArchitecture(HostInfo::eArchKind32); return arch.IsValid(); @@ -178,13 +161,10 @@ bool PlatformNetBSD::GetSupportedArchitectureAtIndex(uint32_t idx, return false; } // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the - // vendor by - // calling triple.SetVendorName("unknown") so that it is a "unspecified - // unknown". - // This means when someone calls triple.GetVendorName() it will return an - // empty string - // which indicates that the vendor can be set when two architectures are - // merged + // vendor by calling triple.SetVendorName("unknown") so that it is a + // "unspecified unknown". This means when someone calls + // triple.GetVendorName() it will return an empty string which indicates + // that the vendor can be set when two architectures are merged // Now set the triple into "arch" and return true arch.SetTriple(triple); @@ -258,19 +238,15 @@ bool PlatformNetBSD::CanDebugProcess() { } // For local debugging, NetBSD will override the debug logic to use llgs-launch -// rather than -// lldb-launch, llgs-attach. This differs from current lldb-launch, -// debugserver-attach -// approach on MacOSX. -lldb::ProcessSP PlatformNetBSD::DebugProcess( - ProcessLaunchInfo &launch_info, Debugger &debugger, - Target *target, // Can be NULL, if NULL create a new - // target, else use existing one - Status &error) { +// rather than lldb-launch, llgs-attach. This differs from current lldb- +// launch, debugserver-attach approach on MacOSX. +lldb::ProcessSP +PlatformNetBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, + Target *target, // Can be NULL, if NULL create a new + // target, else use existing one + Status &error) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf("PlatformNetBSD::%s entered (target %p)", __FUNCTION__, - static_cast<void *>(target)); + LLDB_LOG(log, "target {0}", target); // If we're a remote host, use standard behavior from parent class. if (!IsHost()) @@ -287,67 +263,48 @@ lldb::ProcessSP PlatformNetBSD::DebugProcess( launch_info.GetFlags().Set(eLaunchFlagDebug); // We always launch the process we are going to debug in a separate process - // group, since then we can handle ^C interrupts ourselves w/o having to worry - // about the target getting them as well. + // group, since then we can handle ^C interrupts ourselves w/o having to + // worry about the target getting them as well. launch_info.SetLaunchInSeparateProcessGroup(true); // Ensure we have a target. if (target == nullptr) { - if (log) - log->Printf("PlatformNetBSD::%s creating new target", __FUNCTION__); - + LLDB_LOG(log, "creating new target"); TargetSP new_target_sp; error = debugger.GetTargetList().CreateTarget(debugger, "", "", false, nullptr, new_target_sp); if (error.Fail()) { - if (log) - log->Printf("PlatformNetBSD::%s failed to create new target: %s", - __FUNCTION__, error.AsCString()); + LLDB_LOG(log, "failed to create new target: {0}", error); return process_sp; } target = new_target_sp.get(); if (!target) { error.SetErrorString("CreateTarget() returned nullptr"); - if (log) - log->Printf("PlatformNetBSD::%s failed: %s", __FUNCTION__, - error.AsCString()); + LLDB_LOG(log, "error: {0}", error); return process_sp; } - } else { - if (log) - log->Printf("PlatformNetBSD::%s using provided target", __FUNCTION__); } // Mark target as currently selected target. debugger.GetTargetList().SetSelectedTarget(target); // Now create the gdb-remote process. - if (log) - log->Printf( - "PlatformNetBSD::%s having target create process with gdb-remote plugin", - __FUNCTION__); + LLDB_LOG(log, "having target create process with gdb-remote plugin"); process_sp = target->CreateProcess( launch_info.GetListenerForProcess(debugger), "gdb-remote", nullptr); if (!process_sp) { error.SetErrorString("CreateProcess() failed for gdb-remote process"); - if (log) - log->Printf("PlatformNetBSD::%s failed: %s", __FUNCTION__, - error.AsCString()); + LLDB_LOG(log, "error: {0}", error); return process_sp; - } else { - if (log) - log->Printf("PlatformNetBSD::%s successfully created process", - __FUNCTION__); } + LLDB_LOG(log, "successfully created process"); // Adjust launch for a hijacker. ListenerSP listener_sp; if (!launch_info.GetHijackListener()) { - if (log) - log->Printf("PlatformNetBSD::%s setting up hijacker", __FUNCTION__); - + LLDB_LOG(log, "setting up hijacker"); listener_sp = Listener::MakeListener("lldb.PlatformNetBSD.DebugProcess.hijack"); launch_info.SetHijackListener(listener_sp); @@ -356,16 +313,13 @@ lldb::ProcessSP PlatformNetBSD::DebugProcess( // Log file actions. if (log) { - log->Printf( - "PlatformNetBSD::%s launching process with the following file actions:", - __FUNCTION__); - + LLDB_LOG(log, "launching process with the following file actions:"); StreamString stream; size_t i = 0; const FileAction *file_action; while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) { file_action->Dump(stream); - log->PutCString(stream.GetData()); + LLDB_LOG(log, "{0}", stream.GetData()); stream.Clear(); } } @@ -378,16 +332,7 @@ lldb::ProcessSP PlatformNetBSD::DebugProcess( const StateType state = process_sp->WaitForProcessToStop( llvm::None, NULL, false, listener_sp); - if (state == eStateStopped) { - if (log) - log->Printf("PlatformNetBSD::%s pid %" PRIu64 " state %s\n", - __FUNCTION__, process_sp->GetID(), StateAsCString(state)); - } else { - if (log) - log->Printf("PlatformNetBSD::%s pid %" PRIu64 - " state is not stopped - %s\n", - __FUNCTION__, process_sp->GetID(), StateAsCString(state)); - } + LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state); } // Hook up process PTY if we have one (which we should for local debugging @@ -395,20 +340,11 @@ lldb::ProcessSP PlatformNetBSD::DebugProcess( int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); if (pty_fd != PseudoTerminal::invalid_fd) { process_sp->SetSTDIOFileDescriptor(pty_fd); - if (log) - log->Printf("PlatformNetBSD::%s pid %" PRIu64 - " hooked up STDIO pty to process", - __FUNCTION__, process_sp->GetID()); - } else { - if (log) - log->Printf("PlatformNetBSD::%s pid %" PRIu64 - " not using process STDIO pty", - __FUNCTION__, process_sp->GetID()); - } + LLDB_LOG(log, "hooked up STDIO pty to process"); + } else + LLDB_LOG(log, "not using process STDIO pty"); } else { - if (log) - log->Printf("PlatformNetBSD::%s process launch failed: %s", __FUNCTION__, - error.AsCString()); + LLDB_LOG(log, "process launch failed: {0}", error); // FIXME figure out appropriate cleanup here. Do we delete the target? Do // we delete the process? Does our caller do that? } diff --git a/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp b/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp index 050639aba7cc..10ca8fbfbdd7 100644 --- a/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp +++ b/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp @@ -30,8 +30,8 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" -// Define these constants from OpenBSD mman.h for use when targeting -// remote openbsd systems even when host has different values. +// Define these constants from OpenBSD mman.h for use when targeting remote +// openbsd systems even when host has different values. #define MAP_PRIVATE 0x0002 #define MAP_ANON 0x1000 @@ -58,9 +58,8 @@ PlatformSP PlatformOpenBSD::CreateInstance(bool force, const ArchSpec *arch) { break; #if defined(__OpenBSD__) - // Only accept "unknown" for the OS if the host is BSD and - // it "unknown" wasn't specified (it was just returned because it - // was NOT specified) + // Only accept "unknown" for the OS if the host is BSD and it "unknown" + // wasn't specified (it was just returned because it was NOT specified) case llvm::Triple::OSType::UnknownOS: create = !arch->TripleOSWasSpecified(); break; @@ -167,13 +166,10 @@ bool PlatformOpenBSD::GetSupportedArchitectureAtIndex(uint32_t idx, return false; } // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the - // vendor by - // calling triple.SetVendorName("unknown") so that it is a "unspecified - // unknown". - // This means when someone calls triple.GetVendorName() it will return an - // empty string - // which indicates that the vendor can be set when two architectures are - // merged + // vendor by calling triple.SetVendorName("unknown") so that it is a + // "unspecified unknown". This means when someone calls + // triple.GetVendorName() it will return an empty string which indicates + // that the vendor can be set when two architectures are merged // Now set the triple into "arch" and return true arch.SetTriple(triple); diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index d45a54ee2499..5e7ffe71918e 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -18,17 +18,22 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ValueObject.h" +#include "lldb/Expression/DiagnosticManager.h" +#include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UserExpression.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Host/File.h" #include "lldb/Host/FileCache.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/CleanUp.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" @@ -97,17 +102,14 @@ lldb_private::Status PlatformPOSIX::RunShellCommand( // process to exit std::string *command_output, // Pass NULL if you don't want the command output - uint32_t - timeout_sec) // Timeout in seconds to wait for shell program to finish -{ + const Timeout<std::micro> &timeout) { if (IsHost()) return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, - command_output, timeout_sec); + command_output, timeout); else { if (m_remote_platform_sp) - return m_remote_platform_sp->RunShellCommand(command, working_dir, - status_ptr, signo_ptr, - command_output, timeout_sec); + return m_remote_platform_sp->RunShellCommand( + command, working_dir, status_ptr, signo_ptr, command_output, timeout); else return Status("unable to run a remote command without a platform"); } @@ -124,11 +126,12 @@ PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec, ModuleSpec resolved_module_spec(module_spec); if (IsHost()) { - // If we have "ls" as the exe_file, resolve the executable location based on - // the current path variables + // If we have "ls" as the exe_file, resolve the executable location based + // on the current path variables if (!resolved_module_spec.GetFileSpec().Exists()) { 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, true, + FileSpec::Style::native); } if (!resolved_module_spec.GetFileSpec().Exists()) @@ -210,9 +213,9 @@ PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec, resolved_module_spec.GetArchitecture().GetArchitectureName()); } } else { - // No valid architecture was specified, ask the platform for - // the architectures that we should be using (in the correct order) - // and see if we can find a match that way + // No valid architecture was specified, ask the platform for the + // architectures that we should be using (in the correct order) and see + // if we can find a match that way StreamString arch_names; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( idx, resolved_module_spec.GetArchitecture()); @@ -367,7 +370,8 @@ static uint32_t chown_file(Platform *platform, const char *path, command.Printf(":%d", gid); command.Printf("%s", path); int status; - platform->RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 10); + platform->RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, + std::chrono::seconds(10)); return status; } @@ -391,7 +395,8 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source, StreamString command; command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); int status; - RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 10); + RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, + std::chrono::seconds(10)); if (status != 0) return Status("unable to perform copy"); if (uid == UINT32_MAX && gid == UINT32_MAX) @@ -421,7 +426,8 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source, if (log) log->Printf("[PutFile] Running command: %s\n", command.GetData()); int retcode; - Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 60); + Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, + std::chrono::minutes(1)); if (retcode == 0) { // Don't chown a local file for a remote system // if (chown_file(this,dst_path.c_str(),uid,gid) != 0) @@ -495,7 +501,8 @@ lldb_private::Status PlatformPOSIX::GetFile( StreamString cp_command; cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); int status; - RunShellCommand(cp_command.GetData(), NULL, &status, NULL, NULL, 10); + RunShellCommand(cp_command.GetData(), NULL, &status, NULL, NULL, + std::chrono::seconds(10)); if (status != 0) return Status("unable to perform copy"); return Status(); @@ -516,11 +523,12 @@ lldb_private::Status PlatformPOSIX::GetFile( if (log) log->Printf("[GetFile] Running command: %s\n", command.GetData()); int retcode; - Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 60); + Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, + std::chrono::minutes(1)); if (retcode == 0) return Status(); - // If we are here, rsync has failed - let's try the slow way before giving - // up + // If we are here, rsync has failed - let's try the slow way before + // giving up } // open src and dst // read/write, read/write, read/write, ... @@ -645,9 +653,10 @@ bool PlatformPOSIX::SetRemoteWorkingDirectory(const FileSpec &working_dir) { } bool PlatformPOSIX::GetRemoteOSVersion() { - if (m_remote_platform_sp) - return m_remote_platform_sp->GetOSVersion( - m_major_os_version, m_minor_os_version, m_update_os_version); + if (m_remote_platform_sp) { + m_os_version = m_remote_platform_sp->GetOSVersion(); + return !m_os_version.empty(); + } return false; } @@ -658,13 +667,13 @@ bool PlatformPOSIX::GetRemoteOSBuildString(std::string &s) { return false; } -size_t PlatformPOSIX::GetEnvironment(StringList &env) { +Environment PlatformPOSIX::GetEnvironment() { if (IsRemote()) { if (m_remote_platform_sp) - return m_remote_platform_sp->GetEnvironment(env); - return 0; + return m_remote_platform_sp->GetEnvironment(); + return Environment(); } - return Host::GetEnvironment(env); + return Host::GetEnvironment(); } bool PlatformPOSIX::GetRemoteOSKernelDescription(std::string &s) { @@ -861,12 +870,12 @@ PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, if (IsHost()) { // We are going to hand this process off to debugserver which will be in - // charge of setting the exit status. - // We still need to reap it from lldb but if we let the monitor thread also - // set the exit status, we set up a - // race between debugserver & us for who will find out about the debugged - // process's death. - launch_info.GetFlags().Set(eLaunchFlagDontSetExitStatus); + // charge of setting the exit status. However, we still need to reap it + // from lldb. So, make sure we use a exit callback which does not set exit + // status. + const bool monitor_signals = false; + launch_info.SetMonitorProcessCallback( + &ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals); process_sp = Platform::DebugProcess(launch_info, debugger, target, error); } else { if (m_remote_platform_sp) @@ -923,64 +932,380 @@ Status PlatformPOSIX::EvaluateLibdlExpression( return Status(); } +std::unique_ptr<UtilityFunction> +PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, + Status &error) { + // Remember to prepend this with the prefix from + // GetLibdlFunctionDeclarations. The returned values are all in + // __lldb_dlopen_result for consistency. The wrapper returns a void * but + // doesn't use it because UtilityFunctions don't work with void returns at + // present. + static const char *dlopen_wrapper_code = R"( + struct __lldb_dlopen_result { + void *image_ptr; + const char *error_str; + }; + + extern void *memcpy(void *, const void *, size_t size); + extern size_t strlen(const char *); + + + void * __lldb_dlopen_wrapper (const char *name, + const char *path_strings, + char *buffer, + __lldb_dlopen_result *result_ptr) + { + // This is the case where the name is the full path: + if (!path_strings) { + result_ptr->image_ptr = dlopen(name, 2); + if (result_ptr->image_ptr) + result_ptr->error_str = nullptr; + return nullptr; + } + + // This is the case where we have a list of paths: + size_t name_len = strlen(name); + while (path_strings && path_strings[0] != '\0') { + size_t path_len = strlen(path_strings); + memcpy((void *) buffer, (void *) path_strings, path_len); + buffer[path_len] = '/'; + char *target_ptr = buffer+path_len+1; + memcpy((void *) target_ptr, (void *) name, name_len + 1); + result_ptr->image_ptr = dlopen(buffer, 2); + if (result_ptr->image_ptr) { + result_ptr->error_str = nullptr; + break; + } + result_ptr->error_str = dlerror(); + path_strings = path_strings + path_len + 1; + } + return nullptr; + } + )"; + + static const char *dlopen_wrapper_name = "__lldb_dlopen_wrapper"; + Process *process = exe_ctx.GetProcessSP().get(); + // Insert the dlopen shim defines into our generic expression: + std::string expr(GetLibdlFunctionDeclarations(process)); + expr.append(dlopen_wrapper_code); + Status utility_error; + DiagnosticManager diagnostics; + + std::unique_ptr<UtilityFunction> dlopen_utility_func_up(process + ->GetTarget().GetUtilityFunctionForLanguage(expr.c_str(), + eLanguageTypeObjC, + dlopen_wrapper_name, + utility_error)); + if (utility_error.Fail()) { + error.SetErrorStringWithFormat("dlopen error: could not make utility" + "function: %s", utility_error.AsCString()); + return nullptr; + } + if (!dlopen_utility_func_up->Install(diagnostics, exe_ctx)) { + error.SetErrorStringWithFormat("dlopen error: could not install utility" + "function: %s", + diagnostics.GetString().c_str()); + return nullptr; + } + + Value value; + ValueList arguments; + FunctionCaller *do_dlopen_function = nullptr; + + // Fetch the clang types we will need: + ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); + + CompilerType clang_void_pointer_type + = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + CompilerType clang_char_pointer_type + = ast->GetBasicType(eBasicTypeChar).GetPointerType(); + + // We are passing four arguments, the basename, the list of places to look, + // a buffer big enough for all the path + name combos, and + // a pointer to the storage we've made for the result: + value.SetValueType(Value::eValueTypeScalar); + value.SetCompilerType(clang_void_pointer_type); + arguments.PushValue(value); + value.SetCompilerType(clang_char_pointer_type); + arguments.PushValue(value); + arguments.PushValue(value); + arguments.PushValue(value); + + do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller( + clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error); + if (utility_error.Fail()) { + error.SetErrorStringWithFormat("dlopen error: could not make function" + "caller: %s", utility_error.AsCString()); + return nullptr; + } + + do_dlopen_function = dlopen_utility_func_up->GetFunctionCaller(); + if (!do_dlopen_function) { + error.SetErrorString("dlopen error: could not get function caller."); + return nullptr; + } + + // We made a good utility function, so cache it in the process: + return dlopen_utility_func_up; +} + uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, const lldb_private::FileSpec &remote_file, - lldb_private::Status &error) { - char path[PATH_MAX]; - remote_file.GetPath(path, sizeof(path)); - - StreamString expr; - expr.Printf(R"( - struct __lldb_dlopen_result { void *image_ptr; const char *error_str; } the_result; - the_result.image_ptr = dlopen ("%s", 2); - if (the_result.image_ptr == (void *) 0x0) - { - the_result.error_str = dlerror(); - } - else - { - the_result.error_str = (const char *) 0x0; - } - the_result; - )", - path); - llvm::StringRef prefix = GetLibdlFunctionDeclarations(process); - lldb::ValueObjectSP result_valobj_sp; - error = EvaluateLibdlExpression(process, expr.GetData(), prefix, - result_valobj_sp); - if (error.Fail()) + const std::vector<std::string> *paths, + lldb_private::Status &error, + lldb_private::FileSpec *loaded_image) { + if (loaded_image) + loaded_image->Clear(); + + std::string path; + path = remote_file.GetPath(); + + ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); + if (!thread_sp) { + error.SetErrorString("dlopen error: no thread available to call dlopen."); return LLDB_INVALID_IMAGE_TOKEN; - - error = result_valobj_sp->GetError(); - if (error.Fail()) + } + + DiagnosticManager diagnostics; + + ExecutionContext exe_ctx; + thread_sp->CalculateExecutionContext(exe_ctx); + + Status utility_error; + UtilityFunction *dlopen_utility_func; + ValueList arguments; + FunctionCaller *do_dlopen_function = nullptr; + + // The UtilityFunction is held in the Process. Platforms don't track the + // lifespan of the Targets that use them, we can't put this in the Platform. + dlopen_utility_func = process->GetLoadImageUtilityFunction( + this, [&]() -> std::unique_ptr<UtilityFunction> { + return MakeLoadImageUtilityFunction(exe_ctx, error); + }); + // If we couldn't make it, the error will be in error, so we can exit here. + if (!dlopen_utility_func) return LLDB_INVALID_IMAGE_TOKEN; - - Scalar scalar; - ValueObjectSP image_ptr_sp = result_valobj_sp->GetChildAtIndex(0, true); - if (!image_ptr_sp || !image_ptr_sp->ResolveValue(scalar)) { - error.SetErrorStringWithFormat("unable to load '%s'", path); + + do_dlopen_function = dlopen_utility_func->GetFunctionCaller(); + if (!do_dlopen_function) { + error.SetErrorString("dlopen error: could not get function caller."); return LLDB_INVALID_IMAGE_TOKEN; } - - addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS); - if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS) - return process->AddImageToken(image_ptr); - - if (image_ptr == 0) { - ValueObjectSP error_str_sp = result_valobj_sp->GetChildAtIndex(1, true); - if (error_str_sp) { - DataBufferSP buffer_sp(new DataBufferHeap(10240, 0)); - size_t num_chars = - error_str_sp->ReadPointedString(buffer_sp, error, 10240).first; - if (error.Success() && num_chars > 0) - error.SetErrorStringWithFormat("dlopen error: %s", - buffer_sp->GetBytes()); - else - error.SetErrorStringWithFormat("dlopen failed for unknown reasons."); + arguments = do_dlopen_function->GetArgumentValues(); + + // Now insert the path we are searching for and the result structure into the + // target. + uint32_t permissions = ePermissionsReadable|ePermissionsWritable; + size_t path_len = path.size() + 1; + lldb::addr_t path_addr = process->AllocateMemory(path_len, + permissions, + utility_error); + if (path_addr == LLDB_INVALID_ADDRESS) { + error.SetErrorStringWithFormat("dlopen error: could not allocate memory" + "for path: %s", utility_error.AsCString()); + return LLDB_INVALID_IMAGE_TOKEN; + } + + // Make sure we deallocate the input string memory: + CleanUp path_cleanup([process, path_addr] { + process->DeallocateMemory(path_addr); + }); + + process->WriteMemory(path_addr, path.c_str(), path_len, utility_error); + if (utility_error.Fail()) { + error.SetErrorStringWithFormat("dlopen error: could not write path string:" + " %s", utility_error.AsCString()); + return LLDB_INVALID_IMAGE_TOKEN; + } + + // Make space for our return structure. It is two pointers big: the token + // and the error string. + const uint32_t addr_size = process->GetAddressByteSize(); + lldb::addr_t return_addr = process->CallocateMemory(2*addr_size, + permissions, + utility_error); + if (utility_error.Fail()) { + error.SetErrorStringWithFormat("dlopen error: could not allocate memory" + "for path: %s", utility_error.AsCString()); + return LLDB_INVALID_IMAGE_TOKEN; + } + + // Make sure we deallocate the result structure memory + CleanUp return_cleanup([process, return_addr] { + process->DeallocateMemory(return_addr); + }); + + // This will be the address of the storage for paths, if we are using them, + // or nullptr to signal we aren't. + lldb::addr_t path_array_addr = 0x0; + llvm::Optional<CleanUp> path_array_cleanup; + + // This is the address to a buffer large enough to hold the largest path + // conjoined with the library name we're passing in. This is a convenience + // to avoid having to call malloc in the dlopen function. + lldb::addr_t buffer_addr = 0x0; + llvm::Optional<CleanUp> buffer_cleanup; + + // Set the values into our args and write them to the target: + if (paths != nullptr) { + // First insert the paths into the target. This is expected to be a + // continuous buffer with the strings laid out null terminated and + // end to end with an empty string terminating the buffer. + // We also compute the buffer's required size as we go. + size_t buffer_size = 0; + std::string path_array; + for (auto path : *paths) { + // Don't insert empty paths, they will make us abort the path + // search prematurely. + if (path.empty()) + continue; + size_t path_size = path.size(); + path_array.append(path); + path_array.push_back('\0'); + if (path_size > buffer_size) + buffer_size = path_size; + } + path_array.push_back('\0'); + + path_array_addr = process->AllocateMemory(path_array.size(), + permissions, + utility_error); + if (path_array_addr == LLDB_INVALID_ADDRESS) { + error.SetErrorStringWithFormat("dlopen error: could not allocate memory" + "for path array: %s", + utility_error.AsCString()); + return LLDB_INVALID_IMAGE_TOKEN; + } + + // Make sure we deallocate the paths array. + path_array_cleanup.emplace([process, path_array_addr] { + process->DeallocateMemory(path_array_addr); + }); + + process->WriteMemory(path_array_addr, path_array.data(), + path_array.size(), utility_error); + + if (utility_error.Fail()) { + error.SetErrorStringWithFormat("dlopen error: could not write path array:" + " %s", utility_error.AsCString()); + return LLDB_INVALID_IMAGE_TOKEN; + } + // Now make spaces in the target for the buffer. We need to add one for + // the '/' that the utility function will insert and one for the '\0': + buffer_size += path.size() + 2; + + buffer_addr = process->AllocateMemory(buffer_size, + permissions, + utility_error); + if (buffer_addr == LLDB_INVALID_ADDRESS) { + error.SetErrorStringWithFormat("dlopen error: could not allocate memory" + "for buffer: %s", + utility_error.AsCString()); return LLDB_INVALID_IMAGE_TOKEN; } + + // Make sure we deallocate the buffer memory: + buffer_cleanup.emplace([process, buffer_addr] { + process->DeallocateMemory(buffer_addr); + }); } - error.SetErrorStringWithFormat("unable to load '%s'", path); + + arguments.GetValueAtIndex(0)->GetScalar() = path_addr; + arguments.GetValueAtIndex(1)->GetScalar() = path_array_addr; + arguments.GetValueAtIndex(2)->GetScalar() = buffer_addr; + arguments.GetValueAtIndex(3)->GetScalar() = return_addr; + + lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS; + + diagnostics.Clear(); + if (!do_dlopen_function->WriteFunctionArguments(exe_ctx, + func_args_addr, + arguments, + diagnostics)) { + error.SetErrorStringWithFormat("dlopen error: could not write function " + "arguments: %s", + diagnostics.GetString().c_str()); + return LLDB_INVALID_IMAGE_TOKEN; + } + + // Make sure we clean up the args structure. We can't reuse it because the + // Platform lives longer than the process and the Platforms don't get a + // signal to clean up cached data when a process goes away. + CleanUp args_cleanup([do_dlopen_function, &exe_ctx, func_args_addr] { + do_dlopen_function->DeallocateFunctionResults(exe_ctx, func_args_addr); + }); + + // Now run the caller: + EvaluateExpressionOptions options; + options.SetExecutionPolicy(eExecutionPolicyAlways); + options.SetLanguage(eLanguageTypeC_plus_plus); + options.SetIgnoreBreakpoints(true); + options.SetUnwindOnError(true); + options.SetTrapExceptions(false); // dlopen can't throw exceptions, so + // don't do the work to trap them. + options.SetTimeout(std::chrono::seconds(2)); + + Value return_value; + // Fetch the clang types we will need: + ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); + + CompilerType clang_void_pointer_type + = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + + return_value.SetCompilerType(clang_void_pointer_type); + + ExpressionResults results = do_dlopen_function->ExecuteFunction( + exe_ctx, &func_args_addr, options, diagnostics, return_value); + if (results != eExpressionCompleted) { + error.SetErrorStringWithFormat("dlopen error: failed executing " + "dlopen wrapper function: %s", + diagnostics.GetString().c_str()); + return LLDB_INVALID_IMAGE_TOKEN; + } + + // Read the dlopen token from the return area: + lldb::addr_t token = process->ReadPointerFromMemory(return_addr, + utility_error); + if (utility_error.Fail()) { + error.SetErrorStringWithFormat("dlopen error: could not read the return " + "struct: %s", utility_error.AsCString()); + return LLDB_INVALID_IMAGE_TOKEN; + } + + // The dlopen succeeded! + if (token != 0x0) { + if (loaded_image && buffer_addr != 0x0) + { + // Capture the image which was loaded. We leave it in the buffer on + // exit from the dlopen function, so we can just read it from there: + 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); + } + return process->AddImageToken(token); + } + + // We got an error, lets read in the error string: + std::string dlopen_error_str; + lldb::addr_t error_addr + = process->ReadPointerFromMemory(return_addr + addr_size, utility_error); + if (utility_error.Fail()) { + error.SetErrorStringWithFormat("dlopen error: could not read error string: " + "%s", utility_error.AsCString()); + return LLDB_INVALID_IMAGE_TOKEN; + } + + size_t num_chars = process->ReadCStringFromMemory(error_addr + addr_size, + dlopen_error_str, + utility_error); + if (utility_error.Success() && num_chars > 0) + error.SetErrorStringWithFormat("dlopen error: %s", + dlopen_error_str.c_str()); + else + error.SetErrorStringWithFormat("dlopen failed for unknown reasons."); + return LLDB_INVALID_IMAGE_TOKEN; } diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 93bebeb332ca..cc6f7299c194 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -85,7 +85,7 @@ public: const lldb::UnixSignalsSP &GetRemoteUnixSignals() override; - size_t GetEnvironment(lldb_private::StringList &environment) override; + lldb_private::Environment GetEnvironment() override; bool IsConnected() const override; @@ -99,8 +99,7 @@ public: // the process to exit std::string *command_output, // Pass nullptr if you don't want the command output - uint32_t timeout_sec) - override; // Timeout in seconds to wait for shell program to finish + const lldb_private::Timeout<std::micro> &timeout) override; lldb_private::Status ResolveExecutable( const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp, @@ -166,7 +165,9 @@ public: uint32_t DoLoadImage(lldb_private::Process *process, const lldb_private::FileSpec &remote_file, - lldb_private::Status &error) override; + const std::vector<std::string> *paths, + lldb_private::Status &error, + lldb_private::FileSpec *loaded_image) override; lldb_private::Status UnloadImage(lldb_private::Process *process, uint32_t image_token) override; @@ -201,6 +202,10 @@ protected: llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp); + std::unique_ptr<lldb_private::UtilityFunction> + MakeLoadImageUtilityFunction(lldb_private::ExecutionContext &exe_ctx, + lldb_private::Status &error); + virtual llvm::StringRef GetLibdlFunctionDeclarations(lldb_private::Process *process); diff --git a/source/Plugins/Platform/Windows/PlatformWindows.cpp b/source/Plugins/Platform/Windows/PlatformWindows.cpp index 3535df0c65cc..ed2bcf0cbee4 100644 --- a/source/Plugins/Platform/Windows/PlatformWindows.cpp +++ b/source/Plugins/Platform/Windows/PlatformWindows.cpp @@ -194,7 +194,8 @@ Status PlatformWindows::ResolveExecutable( // variables if (!resolved_module_spec.GetFileSpec().Exists()) { 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, true, + FileSpec::Style::native); } if (!resolved_module_spec.GetFileSpec().Exists()) @@ -237,9 +238,9 @@ Status PlatformWindows::ResolveExecutable( resolved_module_spec.GetArchitecture().GetArchitectureName()); } } else { - // No valid architecture was specified, ask the platform for - // the architectures that we should be using (in the correct order) - // and see if we can find a match that way + // No valid architecture was specified, ask the platform for the + // architectures that we should be using (in the correct order) and see + // if we can find a match that way StreamString arch_names; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( idx, resolved_module_spec.GetArchitecture()); @@ -279,9 +280,10 @@ Status PlatformWindows::ResolveExecutable( } bool PlatformWindows::GetRemoteOSVersion() { - if (m_remote_platform_sp) - return m_remote_platform_sp->GetOSVersion( - m_major_os_version, m_minor_os_version, m_update_os_version); + if (m_remote_platform_sp) { + m_os_version = m_remote_platform_sp->GetOSVersion(); + return !m_os_version.empty(); + } return false; } @@ -413,29 +415,23 @@ ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, Status &error) { // Windows has special considerations that must be followed when launching or - // attaching to a process. The - // key requirement is that when launching or attaching to a process, you must - // do it from the same the thread - // that will go into a permanent loop which will then receive debug events - // from the process. In particular, - // this means we can't use any of LLDB's generic mechanisms to do it for us, - // because it doesn't have the - // special knowledge required for setting up the background thread or passing - // the right flags. + // attaching to a process. The key requirement is that when launching or + // attaching to a process, you must do it from the same the thread that will + // go into a permanent loop which will then receive debug events from the + // process. In particular, this means we can't use any of LLDB's generic + // mechanisms to do it for us, because it doesn't have the special knowledge + // required for setting up the background thread or passing the right flags. // // Another problem is that that LLDB's standard model for debugging a process - // is to first launch it, have - // it stop at the entry point, and then attach to it. In Windows this doesn't - // quite work, you have to - // specify as an argument to CreateProcess() that you're going to debug the - // process. So we override DebugProcess - // here to handle this. Launch operations go directly to the process plugin, - // and attach operations almost go - // directly to the process plugin (but we hijack the events first). In - // essence, we encapsulate all the logic - // of Launching and Attaching in the process plugin, and - // PlatformWindows::DebugProcess is just a pass-through - // to get to the process plugin. + // is to first launch it, have it stop at the entry point, and then attach to + // it. In Windows this doesn't quite work, you have to specify as an + // argument to CreateProcess() that you're going to debug the process. So we + // override DebugProcess here to handle this. Launch operations go directly + // to the process plugin, and attach operations almost go directly to the + // process plugin (but we hijack the events first). In essence, we + // encapsulate all the logic of Launching and Attaching in the process + // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to + // the process plugin. if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { // This is a process attach. Don't need to launch anything. @@ -538,8 +534,8 @@ Status PlatformWindows::GetSharedModule( module_sp.reset(); if (IsRemote()) { - // If we have a remote platform always, let it try and locate - // the shared module first. + // If we have a remote platform always, let it try and locate the shared + // module first. if (m_remote_platform_sp) { error = m_remote_platform_sp->GetSharedModule( module_spec, process, module_sp, module_search_paths_ptr, @@ -572,29 +568,21 @@ void PlatformWindows::GetStatus(Stream &strm) { Platform::GetStatus(strm); #ifdef _WIN32 - uint32_t major; - uint32_t minor; - uint32_t update; - if (!HostInfo::GetOSVersion(major, minor, update)) { - strm << "Windows"; - return; - } - - strm << "Host: Windows " << major << '.' << minor << " Build: " << update - << '\n'; + llvm::VersionTuple version = HostInfo::GetOSVersion(); + strm << "Host: Windows " << version.getAsString() << '\n'; #endif } bool PlatformWindows::CanDebugProcess() { return true; } -size_t PlatformWindows::GetEnvironment(StringList &env) { +Environment PlatformWindows::GetEnvironment() { if (IsRemote()) { if (m_remote_platform_sp) - return m_remote_platform_sp->GetEnvironment(env); - return 0; + return m_remote_platform_sp->GetEnvironment(); + return Environment(); } - return Host::GetEnvironment(env); + return Host::GetEnvironment(); } ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) { diff --git a/source/Plugins/Platform/Windows/PlatformWindows.h b/source/Plugins/Platform/Windows/PlatformWindows.h index 9af42116680e..3a15271c5762 100644 --- a/source/Plugins/Platform/Windows/PlatformWindows.h +++ b/source/Plugins/Platform/Windows/PlatformWindows.h @@ -118,7 +118,7 @@ public: bool CanDebugProcess() override; - size_t GetEnvironment(StringList &env) override; + Environment GetEnvironment() override; // FIXME not sure what the _sigtramp equivalent would be on this platform void CalculateTrapHandlerSymbolNames() override {} diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 759ec7fd1d29..348bb825a5c5 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -118,9 +118,9 @@ Status PlatformRemoteGDBServer::ResolveExecutable( return error; exe_module_sp.reset(); } - // No valid architecture was specified or the exact arch wasn't - // found so ask the platform for the architectures that we should be - // using (in the correct order) and see if we can find a match that way + // No valid architecture was specified or the exact arch wasn't found so + // ask the platform for the architectures that we should be using (in the + // correct order) and see if we can find a match that way StreamString arch_names; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( idx, resolved_module_spec.GetArchitecture()); @@ -236,14 +236,8 @@ size_t PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode( } bool PlatformRemoteGDBServer::GetRemoteOSVersion() { - uint32_t major, minor, update; - if (m_gdb_client.GetOSVersion(major, minor, update)) { - m_major_os_version = major; - m_minor_os_version = minor; - m_update_os_version = update; - return true; - } - return false; + m_os_version = m_gdb_client.GetOSVersion(); + return !m_os_version.empty(); } bool PlatformRemoteGDBServer::GetRemoteOSBuildString(std::string &s) { @@ -277,8 +271,7 @@ bool PlatformRemoteGDBServer::SetRemoteWorkingDirectory( const FileSpec &working_dir) { if (IsConnected()) { // Clear the working directory it case it doesn't get set correctly. This - // will - // for use to re-read it + // will for use to re-read it Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); if (log) log->Printf("PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')", @@ -423,16 +416,7 @@ Status PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) { } // Send the environment and the program + arguments after we connect - const char **envp = - launch_info.GetEnvironmentEntries().GetConstArgumentVector(); - - if (envp) { - const char *env_entry; - for (int i = 0; (env_entry = envp[i]); ++i) { - if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0) - break; - } - } + m_gdb_client.SendEnvironment(launch_info.GetEnvironment()); ArchSpec arch_spec = launch_info.GetArchitecture(); const char *arch_triple = arch_spec.GetTriple().str().c_str(); @@ -549,9 +533,8 @@ bool PlatformRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid, bool launch_result = false; if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS) { - // When remote debugging to iOS, we use a USB mux that always talks - // to localhost, so we will need the remote debugserver to accept - // connections + // When remote debugging to iOS, we use a USB mux that always talks to + // localhost, so we will need the remote debugserver to accept connections // only from localhost, no matter what our current hostname is launch_result = m_gdb_client.LaunchGDBServer("127.0.0.1", pid, port, socket_name); @@ -731,11 +714,9 @@ Status PlatformRemoteGDBServer::RunShellCommand( // process to exit std::string *command_output, // Pass NULL if you don't want the command output - uint32_t - timeout_sec) // Timeout in seconds to wait for shell program to finish -{ + const Timeout<std::micro> &timeout) { return m_gdb_client.RunShellCommand(command, working_dir, status_ptr, - signo_ptr, command_output, timeout_sec); + signo_ptr, command_output, timeout); } void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() { @@ -749,8 +730,8 @@ const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() { if (m_remote_signals_sp) return m_remote_signals_sp; - // If packet not implemented or JSON failed to parse, - // we'll guess the signal set based on the remote architecture. + // If packet not implemented or JSON failed to parse, we'll guess the signal + // set based on the remote architecture. m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture()); StringExtractorGDBRemote response; diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 210544f752e6..a31933b5d9b0 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -17,7 +17,7 @@ // Other libraries and framework includes // Project includes -#include "../../Process/gdb-remote/GDBRemoteCommunicationClient.h" +#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" #include "lldb/Target/Platform.h" @@ -155,8 +155,7 @@ public: // process to exit std::string *command_output, // Pass NULL if you don't want the command output - uint32_t timeout_sec) - override; // Timeout in seconds to wait for shell program to finish + const lldb_private::Timeout<std::micro> &timeout) override; void CalculateTrapHandlerSymbolNames() override; diff --git a/source/Plugins/Process/CMakeLists.txt b/source/Plugins/Process/CMakeLists.txt index 62abd75a43b6..fdeb211fe7a2 100644 --- a/source/Plugins/Process/CMakeLists.txt +++ b/source/Plugins/Process/CMakeLists.txt @@ -11,9 +11,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") add_subdirectory(Windows/Common) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") add_subdirectory(MacOSX-Kernel) - add_subdirectory(mach-core) endif() add_subdirectory(gdb-remote) add_subdirectory(Utility) add_subdirectory(elf-core) +add_subdirectory(mach-core) add_subdirectory(minidump) diff --git a/source/Plugins/Process/Darwin/CFString.cpp b/source/Plugins/Process/Darwin/CFString.cpp index 84ad56774d7c..b87afe999181 100644 --- a/source/Plugins/Process/Darwin/CFString.cpp +++ b/source/Plugins/Process/Darwin/CFString.cpp @@ -91,9 +91,8 @@ const char *CFString::UTF8(std::string &str) { return CFString::UTF8(get(), str); } -// Static function that puts a copy of the UTF8 contents of CF_STR into STR -// and returns the C string pointer that is contained in STR when successful, -// else +// Static function that puts a copy of the UTF8 contents of CF_STR into STR and +// returns the C string pointer that is contained in STR when successful, else // NULL is returned. This allows the std::string parameter to own the extracted // string, // and also allows that string to be returned as a C string pointer that can be @@ -120,9 +119,9 @@ const char *CFString::UTF8(CFStringRef cf_str, std::string &str) { // Static function that puts a copy of the file system representation of CF_STR // into STR and returns the C string pointer that is contained in STR when -// successful, else NULL is returned. This allows the std::string parameter -// to own the extracted string, and also allows that string to be returned as -// a C string pointer that can be used. +// successful, else NULL is returned. This allows the std::string parameter to +// own the extracted string, and also allows that string to be returned as a C +// string pointer that can be used. const char *CFString::FileSystemRepresentation(CFStringRef cf_str, std::string &str) { diff --git a/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp b/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp index 6b3d5f6c117f..95659725ce2e 100644 --- a/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp +++ b/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp @@ -142,8 +142,8 @@ static Status ForkChildForPTraceDebugging(const char *path, char const *argv[], } // Use a fork that ties the child process's stdin/out/err to a pseudo - // terminal so we can read it in our MachProcess::STDIOThread - // as unbuffered io. + // terminal so we can read it in our MachProcess::STDIOThread as unbuffered + // io. PseudoTerminal pty; char fork_error[256]; memset(fork_error, 0, sizeof(fork_error)); @@ -167,12 +167,12 @@ static Status ForkChildForPTraceDebugging(const char *path, char const *argv[], // Get BSD signals as mach exceptions. ::ptrace(PT_SIGEXC, 0, 0, 0); - // If our parent is setgid, lets make sure we don't inherit those - // extra powers due to nepotism. + // If our parent is setgid, lets make sure we don't inherit those extra + // powers due to nepotism. if (::setgid(getgid()) == 0) { - // Let the child have its own process group. We need to execute - // this call in both the child and parent to avoid a race - // condition between the two processes. + // Let the child have its own process group. We need to execute this call + // in both the child and parent to avoid a race condition between the two + // processes. // Set the child process group to match its pid. ::setpgid(0, 0); @@ -183,23 +183,22 @@ static Status ForkChildForPTraceDebugging(const char *path, char const *argv[], // Turn this process into the given executable. ::execv(path, (char *const *)argv); } - // Exit with error code. Child process should have taken - // over in above exec call and if the exec fails it will - // exit the child process below. + // Exit with error code. Child process should have taken over in above exec + // call and if the exec fails it will exit the child process below. ::exit(127); } else { //-------------------------------------------------------------- // Parent process //-------------------------------------------------------------- - // Let the child have its own process group. We need to execute - // this call in both the child and parent to avoid a race condition - // between the two processes. + // Let the child have its own process group. We need to execute this call + // in both the child and parent to avoid a race condition between the two + // processes. // Set the child process group to match its pid ::setpgid(*pid, *pid); if (pty_fd) { - // Release our master pty file descriptor so the pty class doesn't - // close it and so we can continue to use it in our STDIO thread + // Release our master pty file descriptor so the pty class doesn't close + // it and so we can continue to use it in our STDIO thread *pty_fd = pty.ReleaseMasterFileDescriptor(); } } @@ -302,8 +301,7 @@ static Status PosixSpawnChildForPTraceDebugging(const char *path, return error; } - // Ensure we clean up the spawnattr structure however we exit this - // function. + // Ensure we clean up the spawnattr structure however we exit this function. std::unique_ptr<posix_spawnattr_t, int (*)(posix_spawnattr_t *)> spawnattr_up( &attr, ::posix_spawnattr_destroy); @@ -332,9 +330,9 @@ static Status PosixSpawnChildForPTraceDebugging(const char *path, #if !defined(__arm__) - // We don't need to do this for ARM, and we really shouldn't now that we - // have multiple CPU subtypes and no posix_spawnattr call that allows us - // to set which CPU subtype to launch... + // We don't need to do this for ARM, and we really shouldn't now that we have + // multiple CPU subtypes and no posix_spawnattr call that allows us to set + // which CPU subtype to launch... cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType(); if (desired_cpu_type != LLDB_INVALID_CPUTYPE) { size_t ocount = 0; @@ -374,10 +372,10 @@ static Status PosixSpawnChildForPTraceDebugging(const char *path, int (*)(posix_spawn_file_actions_t *)> file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy); - // We assume the caller has setup the file actions appropriately. We - // are not in the business of figuring out what we really need here. - // lldb-server will have already called FinalizeFileActions() as well - // to button these up properly. + // We assume the caller has setup the file actions appropriately. We are not + // in the business of figuring out what we really need here. lldb-server will + // have already called FinalizeFileActions() as well to button these up + // properly. const size_t num_actions = launch_info.GetNumFileActions(); for (size_t action_index = 0; action_index < num_actions; ++action_index) { const FileAction *const action = @@ -533,8 +531,8 @@ Status LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, if (error.Success()) { launch_info.SetProcessID(static_cast<lldb::pid_t>(pid)); } else { - // Reset any variables that might have been set during a failed - // launch attempt. + // Reset any variables that might have been set during a failed launch + // attempt. if (pty_master_fd) *pty_master_fd = -1; @@ -616,8 +614,8 @@ Status LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, if (pty_master_fd) *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); } else { - // Reset any variables that might have been set during a failed - // launch attempt. + // Reset any variables that might have been set during a failed launch + // attempt. if (pty_master_fd) *pty_master_fd = -1; @@ -636,8 +634,8 @@ Status LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, } if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) { - // If we don't have a valid process ID and no one has set the error, - // then return a generic error. + // If we don't have a valid process ID and no one has set the error, then + // return a generic error. if (error.Success()) error.SetErrorStringWithFormat("%s(): failed to launch, no reason " "specified", diff --git a/source/Plugins/Process/Darwin/MachException.cpp b/source/Plugins/Process/Darwin/MachException.cpp index 9f5920753d68..353f2df32139 100644 --- a/source/Plugins/Process/Darwin/MachException.cpp +++ b/source/Plugins/Process/Darwin/MachException.cpp @@ -92,8 +92,6 @@ extern "C" kern_return_t catch_mach_exception_raise_state_identity( (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); } - mach_port_deallocate(mach_task_self(), task_port); - mach_port_deallocate(mach_task_self(), thread_port); return KERN_FAILURE; } @@ -249,20 +247,19 @@ bool MachException::Message::CatchExceptionRaise(task_t task) { bool success = false; state.task_port = task; g_message = &state; - // The exc_server function is the MIG generated server handling function - // to handle messages from the kernel relating to the occurrence of an - // exception in a thread. Such messages are delivered to the exception port - // set via thread_set_exception_ports or task_set_exception_ports. When an - // exception occurs in a thread, the thread sends an exception message to - // its exception port, blocking in the kernel waiting for the receipt of a - // reply. The exc_server function performs all necessary argument handling - // for this kernel message and calls catch_exception_raise, - // catch_exception_raise_state or catch_exception_raise_state_identity, - // which should handle the exception. If the called routine returns - // KERN_SUCCESS, a reply message will be sent, allowing the thread to - // continue from the point of the exception; otherwise, no reply message - // is sent and the called routine must have dealt with the exception - // thread directly. + // The exc_server function is the MIG generated server handling function to + // handle messages from the kernel relating to the occurrence of an exception + // in a thread. Such messages are delivered to the exception port set via + // thread_set_exception_ports or task_set_exception_ports. When an exception + // occurs in a thread, the thread sends an exception message to its exception + // port, blocking in the kernel waiting for the receipt of a reply. The + // exc_server function performs all necessary argument handling for this + // kernel message and calls catch_exception_raise, + // catch_exception_raise_state or catch_exception_raise_state_identity, which + // should handle the exception. If the called routine returns KERN_SUCCESS, a + // reply message will be sent, allowing the thread to continue from the point + // of the exception; otherwise, no reply message is sent and the called + // routine must have dealt with the exception thread directly. if (mach_exc_server(&exc_msg.hdr, &reply_msg.hdr)) { success = true; } else { @@ -385,9 +382,9 @@ Status MachException::PortInfo::Save(task_t task) { log->Printf("MachException::PortInfo::%s(task = 0x%4.4x)", __FUNCTION__, task); - // Be careful to be able to have debugserver built on a newer OS than what - // it is currently running on by being able to start with all exceptions - // and back off to just what is supported on the current system + // Be careful to be able to have debugserver built on a newer OS than what it + // is currently running on by being able to start with all exceptions and + // back off to just what is supported on the current system mask = LLDB_EXC_MASK; count = (sizeof(ports) / sizeof(ports[0])); diff --git a/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp b/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp index 518f0d2da4f2..3505443abcb0 100644 --- a/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp +++ b/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp @@ -104,8 +104,8 @@ Status NativeProcessProtocol::Launch( return error; } - // Finalize the processing needed to debug the launched process with - // a NativeProcessDarwin instance. + // Finalize the processing needed to debug the launched process with a + // NativeProcessDarwin instance. error = np_darwin_sp->FinalizeLaunch(launch_flavor, mainloop); if (!error.Success()) { if (log) @@ -194,9 +194,9 @@ Status NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor, "mach exception port monitor thread: %s", __FUNCTION__, error.AsCString()); - // Terminate the inferior process. There's nothing meaningful we can - // do if we can't receive signals and exceptions. Since we launched - // the process, it's fair game for us to kill it. + // Terminate the inferior process. There's nothing meaningful we can do if + // we can't receive signals and exceptions. Since we launched the process, + // it's fair game for us to kill it. ::ptrace(PT_KILL, m_pid, 0, 0); SetState(eStateExited); @@ -243,9 +243,9 @@ Status NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor, } if (TaskPortForProcessID(error) == TASK_NULL) { - // We failed to get the task for our process ID which is bad. - // Kill our process; otherwise, it will be stopped at the entry - // point and get reparented to someone else and never go away. + // We failed to get the task for our process ID which is bad. Kill our + // process; otherwise, it will be stopped at the entry point and get + // reparented to someone else and never go away. if (log) log->Printf("NativeProcessDarwin::%s(): could not get task port " "for process, sending SIGKILL and exiting: %s", @@ -277,9 +277,9 @@ bool NativeProcessDarwin::ProcessUsingBackBoard() const { return false; } -// Called by the exception thread when an exception has been received from -// our process. The exception message is completely filled and the exception -// data has already been copied. +// Called by the exception thread when an exception has been received from our +// process. The exception message is completely filled and the exception data +// has already been copied. void NativeProcessDarwin::ExceptionMessageReceived( const MachException::Message &message) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); @@ -290,8 +290,8 @@ void NativeProcessDarwin::ExceptionMessageReceived( SuspendTask(); } - // Use a locker to automatically unlock our mutex in case of exceptions - // Add the exception to our internal exception stack + // Use a locker to automatically unlock our mutex in case of exceptions Add + // the exception to our internal exception stack m_exception_messages.push_back(message); if (log) @@ -324,13 +324,12 @@ void *NativeProcessDarwin::DoExceptionThread() { // Ensure we don't get CPU starved. MaybeRaiseThreadPriority(); - // We keep a count of the number of consecutive exceptions received so - // we know to grab all exceptions without a timeout. We do this to get a - // bunch of related exceptions on our exception port so we can process - // then together. When we have multiple threads, we can get an exception - // per thread and they will come in consecutively. The main loop in this - // thread can stop periodically if needed to service things related to this - // process. + // We keep a count of the number of consecutive exceptions received so we + // know to grab all exceptions without a timeout. We do this to get a bunch + // of related exceptions on our exception port so we can process then + // together. When we have multiple threads, we can get an exception per + // thread and they will come in consecutively. The main loop in this thread + // can stop periodically if needed to service things related to this process. // // [did we lose some words here?] // @@ -338,15 +337,15 @@ void *NativeProcessDarwin::DoExceptionThread() { // 0 our exception port. After we get one exception, we then will use the // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current // exceptions for our process. After we have received the last pending - // exception, we will get a timeout which enables us to then notify - // our main thread that we have an exception bundle available. We then wait - // for the main thread to tell this exception thread to start trying to get + // exception, we will get a timeout which enables us to then notify our main + // thread that we have an exception bundle available. We then wait for the + // main thread to tell this exception thread to start trying to get // exceptions messages again and we start again with a mach_msg read with // infinite timeout. // // We choose to park a thread on this, rather than polling, because the - // polling is expensive. On devices, we need to minimize overhead caused - // by the process monitor. + // polling is expensive. On devices, we need to minimize overhead caused by + // the process monitor. uint32_t num_exceptions_received = 0; Status error; task_t task = m_task; @@ -359,8 +358,7 @@ void *NativeProcessDarwin::DoExceptionThread() { CFReleaser<SBSWatchdogAssertionRef> watchdog; if (process->ProcessUsingSpringBoard()) { - // Request a renewal for every 60 seconds if we attached using - // SpringBoard. + // Request a renewal for every 60 seconds if we attached using SpringBoard. watchdog.reset(::SBSWatchdogAssertionCreateForPID(nullptr, pid, 60)); if (log) log->Printf("::SBSWatchdogAssertionCreateForPID(NULL, %4.4x, 60) " @@ -401,18 +399,18 @@ void *NativeProcessDarwin::DoExceptionThread() { } #endif // #ifdef WITH_BKS - // Do we want to use a weak pointer to the NativeProcessDarwin here, in - // which case we can guarantee we don't whack the process monitor if we - // race between this thread and the main one on shutdown? + // Do we want to use a weak pointer to the NativeProcessDarwin here, in which + // case we can guarantee we don't whack the process monitor if we race + // between this thread and the main one on shutdown? while (IsExceptionPortValid()) { ::pthread_testcancel(); MachException::Message exception_message; if (num_exceptions_received > 0) { - // We don't want a timeout here, just receive as many exceptions as - // we can since we already have one. We want to get all currently - // available exceptions for this task at once. + // We don't want a timeout here, just receive as many exceptions as we + // can since we already have one. We want to get all currently available + // exceptions for this task at once. error = exception_message.Receive( GetExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0); @@ -424,8 +422,8 @@ void *NativeProcessDarwin::DoExceptionThread() { MACH_RCV_TIMEOUT, periodic_timeout); } else { - // We don't need to parse all current exceptions or stop - // periodically, just wait for an exception forever. + // We don't need to parse all current exceptions or stop periodically, + // just wait for an exception forever. error = exception_message.Receive(GetExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0); } @@ -462,8 +460,8 @@ void *NativeProcessDarwin::DoExceptionThread() { __FUNCTION__); continue; } else { - // The inferior task is no longer valid. Time to exit as - // the process has gone away. + // The inferior task is no longer valid. Time to exit as the process + // has gone away. if (log) log->Printf("NativeProcessDarwin::%s(): the inferior task " "has exited, and so will we...", @@ -476,18 +474,17 @@ void *NativeProcessDarwin::DoExceptionThread() { // We timed out when waiting for exceptions. if (num_exceptions_received > 0) { - // We were receiving all current exceptions with a timeout of - // zero. It is time to go back to our normal looping mode. + // We were receiving all current exceptions with a timeout of zero. + // It is time to go back to our normal looping mode. num_exceptions_received = 0; - // Notify our main thread we have a complete exception message - // bundle available. Get the possibly updated task port back - // from the process in case we exec'ed and our task port - // changed. + // Notify our main thread we have a complete exception message bundle + // available. Get the possibly updated task port back from the + // process in case we exec'ed and our task port changed. task = ExceptionMessageBundleComplete(); - // In case we use a timeout value when getting exceptions, - // make sure our task is still valid. + // In case we use a timeout value when getting exceptions, make sure + // our task is still valid. if (IsTaskValid(task)) { // Task is still ok. if (log) @@ -496,8 +493,8 @@ void *NativeProcessDarwin::DoExceptionThread() { __FUNCTION__); continue; } else { - // The inferior task is no longer valid. Time to exit as - // the process has gone away. + // The inferior task is no longer valid. Time to exit as the + // process has gone away. if (log) log->Printf("NativeProcessDarwin::%s(): the inferior " "task has exited, and so will we...", @@ -534,10 +531,8 @@ void *NativeProcessDarwin::DoExceptionThread() { // TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel // when we // all are up and running on systems that support it. The SBS framework has - // a #define - // that will forward SBSWatchdogAssertionRelease to - // SBSWatchdogAssertionCancel for now - // so it should still build either way. + // a #define that will forward SBSWatchdogAssertionRelease to + // SBSWatchdogAssertionCancel for now so it should still build either way. DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionRelease(%p)", watchdog.get()); ::SBSWatchdogAssertionRelease(watchdog.get()); @@ -728,8 +723,8 @@ task_t NativeProcessDarwin::ExceptionMessageBundleComplete() { const int signo = m_exception_messages[i].state.SoftSignal(); if (signo == SIGTRAP) { // SIGTRAP could mean that we exec'ed. We need to check the - // dyld all_image_infos.infoArray to see if it is NULL and if - // so, say that we exec'ed. + // dyld all_image_infos.infoArray to see if it is NULL and if so, say + // that we exec'ed. const addr_t aii_addr = GetDYLDAllImageInfosAddress(error); if (aii_addr == LLDB_INVALID_ADDRESS) break; @@ -744,12 +739,12 @@ task_t NativeProcessDarwin::ExceptionMessageBundleComplete() { bytes_read); // #bytes read if (read_error.Success() && (bytes_read == 4)) { if (info_array_count == 0) { - // We got the all infos address, and there are zero - // entries. We think we exec'd. + // We got the all infos address, and there are zero entries. We + // think we exec'd. m_did_exec = true; - // Force the task port to update itself in case the - // task port changed after exec + // Force the task port to update itself in case the task port + // changed after exec const task_t old_task = m_task; const bool force_update = true; const task_t new_task = TaskPortForProcessID(error, force_update); @@ -810,8 +805,7 @@ task_t NativeProcessDarwin::ExceptionMessageBundleComplete() { // 4 - We might need to resume if we stopped only with the // interrupt signal that we never handled. if (m_auto_resume_signo != 0) { - // Only auto_resume if we stopped with _only_ the interrupt - // signal. + // Only auto_resume if we stopped with _only_ the interrupt signal. if (num_task_exceptions == 1) { auto_resume = true; if (log) @@ -831,8 +825,8 @@ task_t NativeProcessDarwin::ExceptionMessageBundleComplete() { } } - // Let all threads recover from stopping and do any clean up based - // on the previous thread state (if any). + // Let all threads recover from stopping and do any clean up based on the + // previous thread state (if any). m_thread_list.ProcessDidStop(*this); // Let each thread know of any exceptions @@ -863,8 +857,8 @@ task_t NativeProcessDarwin::ExceptionMessageBundleComplete() { // TODO - need to hook up event system here. !!!! #if 0 // Wait for the eEventProcessRunningStateChanged event to be reset - // before changing state to stopped to avoid race condition with - // very fast start/stops. + // before changing state to stopped to avoid race condition with very + // fast start/stops. struct timespec timeout; //DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 ms @@ -889,12 +883,12 @@ Status NativeProcessDarwin::StartWaitpidThread(MainLoop &main_loop) { Status error; Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - // Strategy: create a thread that sits on waitpid(), waiting for the - // inferior process to die, reaping it in the process. Arrange for - // the thread to have a pipe file descriptor that it can send a byte - // over when the waitpid completes. Have the main loop have a read - // object for the other side of the pipe, and have the callback for - // the read do the process termination message sending. + // Strategy: create a thread that sits on waitpid(), waiting for the inferior + // process to die, reaping it in the process. Arrange for the thread to have + // a pipe file descriptor that it can send a byte over when the waitpid + // completes. Have the main loop have a read object for the other side of + // the pipe, and have the callback for the read do the process termination + // message sending. // Create a single-direction communication channel. const bool child_inherits = false; @@ -1025,8 +1019,8 @@ void *NativeProcessDarwin::DoWaitpidThread() { } } - // We should never exit as long as our child process is alive. If we - // get here, something completely unexpected went wrong and we should exit. + // We should never exit as long as our child process is alive. If we get + // here, something completely unexpected went wrong and we should exit. if (log) log->Printf( "NativeProcessDarwin::%s(): internal error: waitpid thread " @@ -1157,8 +1151,8 @@ task_t NativeProcessDarwin::TaskPortForProcessID(Status &error, ::usleep(usec_interval); } - // We failed to get the task for the inferior process. - // Ensure that it is cleared out. + // We failed to get the task for the inferior process. Ensure that it is + // cleared out. m_task = TASK_NULL; } return m_task; @@ -1196,9 +1190,9 @@ Status NativeProcessDarwin::PrivateResume() { } // bool stepOverBreakInstruction = step; - // Let the thread prepare to resume and see if any threads want us to - // step over a breakpoint instruction (ProcessWillResume will modify - // the value of stepOverBreakInstruction). + // Let the thread prepare to resume and see if any threads want us to step + // over a breakpoint instruction (ProcessWillResume will modify the value of + // stepOverBreakInstruction). m_thread_list.ProcessWillResume(*this, m_thread_actions); // Set our state accordingly @@ -1254,8 +1248,8 @@ Status NativeProcessDarwin::ReplyToAllExceptions() { error = message.Reply(m_pid, m_task, thread_reply_signal); if (error.Fail() && log) { - // We log any error here, but we don't stop the exception - // response handling. + // We log any error here, but we don't stop the exception response + // handling. log->Printf("NativeProcessDarwin::%s(): failed to reply to " "exception: %s", __FUNCTION__, error.AsCString()); @@ -1263,8 +1257,8 @@ Status NativeProcessDarwin::ReplyToAllExceptions() { } } - // Erase all exception message as we should have used and replied - // to them all already. + // Erase all exception message as we should have used and replied to them all + // already. m_exception_messages.clear(); return error; } @@ -1292,8 +1286,8 @@ Status NativeProcessDarwin::ResumeTask() { "0x%4.4x", __FUNCTION__, m_task); - // Get the BasicInfo struct to verify that we're suspended before we try - // to resume the task. + // Get the BasicInfo struct to verify that we're suspended before we try to + // resume the task. struct task_basic_info task_info; error = GetTaskBasicInfo(m_task, &task_info); if (error.Fail()) { @@ -1304,9 +1298,8 @@ Status NativeProcessDarwin::ResumeTask() { return error; } - // task_resume isn't counted like task_suspend calls are, so if the - // task is not suspended, don't try and resume it since it is already - // running + // task_resume isn't counted like task_suspend calls are, so if the task is + // not suspended, don't try and resume it since it is already running if (task_info.suspend_count > 0) { auto mach_err = ::task_resume(m_task); error.SetError(mach_err, eErrorTypeMachKernel); diff --git a/source/Plugins/Process/Darwin/NativeProcessDarwin.h b/source/Plugins/Process/Darwin/NativeProcessDarwin.h index 649280c17a8f..0b186fd7d80c 100644 --- a/source/Plugins/Process/Darwin/NativeProcessDarwin.h +++ b/source/Plugins/Process/Darwin/NativeProcessDarwin.h @@ -43,10 +43,10 @@ class Scalar; namespace process_darwin { /// @class NativeProcessDarwin -/// @brief Manages communication with the inferior (debugee) process. +/// Manages communication with the inferior (debugee) process. /// -/// Upon construction, this class prepares and launches an inferior -/// process for debugging. +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. /// /// Changes in the inferior process state are broadcasted. class NativeProcessDarwin : public NativeProcessProtocol { @@ -205,10 +205,10 @@ private: // ----------------------------------------------------------------- /// Finalize the launch. /// - /// This method associates the NativeProcessDarwin instance with - /// the host process that was just launched. It peforms actions - /// like attaching a listener to the inferior exception port, - /// ptracing the process, and the like. + /// This method associates the NativeProcessDarwin instance with the host + /// process that was just launched. It peforms actions like attaching a + /// listener to the inferior exception port, ptracing the process, and the + /// like. /// /// @param[in] launch_flavor /// The launch flavor that was used to launch the process. @@ -263,8 +263,8 @@ private: task_t TaskPortForProcessID(Status &error, bool force = false) const; - /// Attaches to an existing process. Forms the - /// implementation of Process::DoAttach. + /// Attaches to an existing process. Forms the implementation of + /// Process::DoAttach. void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error); ::pid_t Attach(lldb::pid_t pid, Status &error); @@ -323,8 +323,8 @@ private: Status GetSignalInfo(lldb::tid_t tid, void *siginfo); /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) - /// corresponding to the given thread ID to the memory pointed to - /// by @p message. + /// corresponding to the given thread ID to the memory pointed to by @p + /// message. Status GetEventMessage(lldb::tid_t tid, unsigned long *message); void NotifyThreadDeath(lldb::tid_t tid); diff --git a/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp b/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp index 07398ab7b678..521c6d5c8fd0 100644 --- a/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp +++ b/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp @@ -30,8 +30,8 @@ uint64_t NativeThreadDarwin::GetGloballyUniqueThreadIDForMachPortID( (thread_info_t)&tident, &tident_count); if (mach_err != KERN_SUCCESS) { // When we fail to get thread info for the supposed port, assume it is - // really a globally unique thread id already, or return the best thing - // we can, which is the thread port. + // really a globally unique thread id already, or return the best thing we + // can, which is the thread port. return mach_port_id; } return tident.thread_id; @@ -47,9 +47,9 @@ NativeThreadDarwin::NativeThreadDarwin(NativeProcessDarwin *process, bool NativeThreadDarwin::GetIdentifierInfo() { // Don't try to get the thread info once and cache it for the life of the - // thread. It changes over time, for instance - // if the thread name changes, then the thread_handle also changes... So you - // have to refetch it every time. + // thread. It changes over time, for instance if the thread name changes, + // then the thread_handle also changes... So you have to refetch it every + // time. mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; kern_return_t kret = ::thread_info(m_mach_thread_port, THREAD_IDENTIFIER_INFO, (thread_info_t)&m_ident_info, &count); @@ -137,16 +137,16 @@ bool NativeThreadDarwin::NotifyException(MachException::Data &exc) { // TODO implement this. #if 0 // Allow the arch specific protocol to process (MachException::Data &)exc - // first before possible reassignment of m_stop_exception with exc. - // See also MachThread::GetStopException(). + // first before possible reassignment of m_stop_exception with exc. See + // also MachThread::GetStopException(). bool handled = m_arch_ap->NotifyException(exc); if (m_stop_exception.IsValid()) { // We may have more than one exception for a thread, but we need to - // only remember the one that we will say is the reason we stopped. - // We may have been single stepping and also gotten a signal exception, - // so just remember the most pertinent one. + // only remember the one that we will say is the reason we stopped. We + // may have been single stepping and also gotten a signal exception, so + // just remember the most pertinent one. if (m_stop_exception.IsBreakpoint()) m_stop_exception = exc; } @@ -170,8 +170,8 @@ bool NativeThreadDarwin::ShouldStop(bool &step_more) const { if (bp) { - // This thread is sitting at a breakpoint, ask the breakpoint - // if we should be stopping here. + // This thread is sitting at a breakpoint, ask the breakpoint if we + // should be stopping here. return true; } else @@ -181,11 +181,10 @@ bool NativeThreadDarwin::ShouldStop(bool &step_more) const { step_more = true; return false; } - // The thread state is used to let us know what the thread was - // trying to do. MachThread::ThreadWillResume() will set the - // thread state to various values depending if the thread was - // the current thread and if it was to be single stepped, or - // resumed. + // The thread state is used to let us know what the thread was trying + // to do. MachThread::ThreadWillResume() will set the thread state to + // various values depending if the thread was the current thread and if + // it was to be single stepped, or resumed. if (GetState() == eStateRunning) { // If our state is running, then we should continue as we are in @@ -194,8 +193,7 @@ bool NativeThreadDarwin::ShouldStop(bool &step_more) const { } else { - // Stop if we have any kind of valid exception for this - // thread. + // Stop if we have any kind of valid exception for this thread. if (GetStopException().IsValid()) return true; } @@ -209,17 +207,17 @@ bool NativeThreadDarwin::ShouldStop(bool &step_more) const { void NativeThreadDarwin::ThreadDidStop() { // TODO implement this. #if 0 - // This thread has existed prior to resuming under debug nub control, - // and has just been stopped. Do any cleanup that needs to be done - // after running. + // This thread has existed prior to resuming under debug nub control, and + // has just been stopped. Do any cleanup that needs to be done after + // running. - // The thread state and breakpoint will still have the same values - // as they had prior to resuming the thread, so it makes it easy to check - // if we were trying to step a thread, or we tried to resume while being - // at a breakpoint. + // The thread state and breakpoint will still have the same values as they + // had prior to resuming the thread, so it makes it easy to check if we + // were trying to step a thread, or we tried to resume while being at a + // breakpoint. - // When this method gets called, the process state is still in the - // state it was in while running so we can act accordingly. + // When this method gets called, the process state is still in the state it + // was in while running so we can act accordingly. m_arch_ap->ThreadDidStop(); diff --git a/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp b/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp index 7d44adeec375..4ff662e42097 100644 --- a/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp +++ b/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp @@ -308,8 +308,8 @@ uint32_t NativeThreadListDarwin::UpdateThreadList(NativeProcessDarwin &process, __FUNCTION__, process.GetID(), update, process.GetStopID()); if (process.GetStopID() == 0) { - // On our first stop, we'll record details like 32/64 bitness and - // select the proper architecture implementation. + // On our first stop, we'll record details like 32/64 bitness and select + // the proper architecture implementation. // int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)process.GetID()}; @@ -358,9 +358,9 @@ uint32_t NativeThreadListDarwin::UpdateThreadList(NativeProcessDarwin &process, if (thread_list_count > 0) { collection currThreads; size_t idx; - // Iterator through the current thread list and see which threads - // we already have in our list (keep them), which ones we don't - // (add them), and which ones are not around anymore (remove them). + // Iterator through the current thread list and see which threads we + // already have in our list (keep them), which ones we don't (add them), + // and which ones are not around anymore (remove them). for (idx = 0; idx < thread_list_count; ++idx) { // Get the Mach thread port. const ::thread_t mach_port_num = thread_list[idx]; @@ -373,18 +373,18 @@ uint32_t NativeThreadListDarwin::UpdateThreadList(NativeProcessDarwin &process, // Retrieve the thread if it exists. auto thread_sp = GetThreadByID(unique_thread_id); if (thread_sp) { - // We are already tracking it. Keep the existing native - // thread instance. + // We are already tracking it. Keep the existing native thread + // instance. currThreads.push_back(thread_sp); } else { - // We don't have a native thread instance for this thread. - // Create it now. + // We don't have a native thread instance for this thread. Create it + // now. thread_sp.reset(new NativeThreadDarwin( &process, m_is_64_bit, unique_thread_id, mach_port_num)); - // Add the new thread regardless of its is user ready state. - // Make sure the thread is ready to be displayed and shown - // to users before we add this thread to our list... + // Add the new thread regardless of its is user ready state. Make + // sure the thread is ready to be displayed and shown to users before + // we add this thread to our list... if (thread_sp->IsUserReady()) { if (new_threads) new_threads->push_back(thread_sp); @@ -417,9 +417,9 @@ NativeThreadListDarwin::CurrentThread (MachThreadSP& thread_sp) PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); if (m_current_thread.get() == NULL) { - // Figure out which thread is going to be our current thread. - // This is currently done by finding the first thread in the list - // that has a valid exception. + // Figure out which thread is going to be our current thread. This is + // currently done by finding the first thread in the list that has a + // valid exception. const size_t num_threads = m_threads.size(); for (uint32_t idx = 0; idx < num_threads; ++idx) { @@ -455,8 +455,8 @@ void NativeThreadListDarwin::ProcessWillResume( NativeProcessDarwin &process, const ResumeActionList &thread_actions) { std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - // Update our thread list, because sometimes libdispatch or the kernel - // will spawn threads while a task is suspended. + // Update our thread list, because sometimes libdispatch or the kernel will + // spawn threads while a task is suspended. NativeThreadListDarwin::collection new_threads; // TODO implement this. @@ -489,7 +489,8 @@ void NativeThreadListDarwin::ProcessWillResume( #if 0 DNBThreadResumeAction resume_new_threads = { -1U, eStateRunning, 0, INVALID_NUB_ADDRESS }; - // If we are planning to run only one thread, any new threads should be suspended. + // If we are planning to run only one thread, any new threads should be + // suspended. if (run_one_thread) resume_new_threads.state = eStateSuspended; @@ -549,11 +550,11 @@ uint32_t NativeThreadListDarwin::ProcessDidStop(NativeProcessDarwin &process) { } //---------------------------------------------------------------------- -// Check each thread in our thread list to see if we should notify our -// client of the current halt in execution. +// Check each thread in our thread list to see if we should notify our client +// of the current halt in execution. // -// Breakpoints can have callback functions associated with them than -// can return true to stop, or false to continue executing the inferior. +// Breakpoints can have callback functions associated with them than can return +// true to stop, or false to continue executing the inferior. // // RETURNS // true if we should stop and notify our clients @@ -607,8 +608,9 @@ NativeThreadListDarwin::DisableHardwareBreakpoint (const DNBBreakpoint* bp) cons return false; } -// DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> MachProcess::EnableWatchpoint() -// -> NativeThreadListDarwin::EnableHardwareWatchpoint(). +// DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> +// MachProcess::EnableWatchpoint() -> +// NativeThreadListDarwin::EnableHardwareWatchpoint(). uint32_t NativeThreadListDarwin::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const { @@ -617,14 +619,16 @@ NativeThreadListDarwin::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const { PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); const size_t num_threads = m_threads.size(); - // On Mac OS X we have to prime the control registers for new threads. We do this - // using the control register data for the first thread, for lack of a better way of choosing. + // On Mac OS X we have to prime the control registers for new threads. + // We do this using the control register data for the first thread, for + // lack of a better way of choosing. bool also_set_on_task = true; for (uint32_t idx = 0; idx < num_threads; ++idx) { if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp, also_set_on_task)) == INVALID_NUB_HW_INDEX) { - // We know that idx failed for some reason. Let's rollback the transaction for [0, idx). + // We know that idx failed for some reason. Let's rollback the + // transaction for [0, idx). for (uint32_t i = 0; i < idx; ++i) m_threads[i]->RollbackTransForHWP(); return INVALID_NUB_HW_INDEX; @@ -647,14 +651,16 @@ NativeThreadListDarwin::DisableHardwareWatchpoint (const DNBBreakpoint* wp) cons PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); const size_t num_threads = m_threads.size(); - // On Mac OS X we have to prime the control registers for new threads. We do this - // using the control register data for the first thread, for lack of a better way of choosing. + // On Mac OS X we have to prime the control registers for new threads. + // We do this using the control register data for the first thread, for + // lack of a better way of choosing. bool also_set_on_task = true; for (uint32_t idx = 0; idx < num_threads; ++idx) { if (!m_threads[idx]->DisableHardwareWatchpoint(wp, also_set_on_task)) { - // We know that idx failed for some reason. Let's rollback the transaction for [0, idx). + // We know that idx failed for some reason. Let's rollback the + // transaction for [0, idx). for (uint32_t i = 0; i < idx; ++i) m_threads[i]->RollbackTransForHWP(); return false; @@ -675,7 +681,8 @@ NativeThreadListDarwin::NumSupportedHardwareWatchpoints () const { PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); const size_t num_threads = m_threads.size(); - // Use an arbitrary thread to retrieve the number of supported hardware watchpoints. + // Use an arbitrary thread to retrieve the number of supported hardware + // watchpoints. if (num_threads) return m_threads[0]->NumSupportedHardwareWatchpoints(); return 0; diff --git a/source/Plugins/Process/FreeBSD/CMakeLists.txt b/source/Plugins/Process/FreeBSD/CMakeLists.txt index 63855992d708..c8301f350e07 100644 --- a/source/Plugins/Process/FreeBSD/CMakeLists.txt +++ b/source/Plugins/Process/FreeBSD/CMakeLists.txt @@ -1,7 +1,3 @@ -include_directories(.) -include_directories(../POSIX) -include_directories(../Utility) - add_lldb_library(lldbPluginProcessFreeBSD PLUGIN ProcessFreeBSD.cpp FreeBSDThread.cpp diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp index e6557c2d58e0..3576a7f26f86 100644 --- a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp @@ -57,7 +57,7 @@ using namespace lldb_private; FreeBSDThread::FreeBSDThread(Process &process, lldb::tid_t tid) : Thread(process, tid), m_frame_ap(), m_breakpoint(), - m_thread_name_valid(false), m_thread_name(), m_posix_thread(NULL) { + m_thread_name_valid(false), m_thread_name(), m_posix_thread(nullptr) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); LLDB_LOGV(log, "tid = {0}", tid); @@ -69,15 +69,15 @@ FreeBSDThread::FreeBSDThread(Process &process, lldb::tid_t tid) for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++) { lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx); if (wp.get() && wp->IsEnabled()) { - // This watchpoint as been enabled; obviously this "new" thread - // has been created since that watchpoint was enabled. Since - // the POSIXBreakpointProtocol has yet to be initialized, its - // m_watchpoints_initialized member will be FALSE. Attempting to - // read the debug status register to determine if a watchpoint - // has been hit would result in the zeroing of that register. - // Since the active debug registers would have been cloned when - // this thread was created, simply force the m_watchpoints_initized - // member to TRUE and avoid resetting dr6 and dr7. + // This watchpoint as been enabled; obviously this "new" thread has been + // created since that watchpoint was enabled. Since the + // POSIXBreakpointProtocol has yet to be initialized, its + // m_watchpoints_initialized member will be FALSE. Attempting to read + // the debug status register to determine if a watchpoint has been hit + // would result in the zeroing of that register. Since the active debug + // registers would have been cloned when this thread was created, simply + // force the m_watchpoints_initized member to TRUE and avoid resetting + // dr6 and dr7. GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized(); } } @@ -98,16 +98,15 @@ void FreeBSDThread::RefreshStateAfterStop() { // context by the time this function gets called. The KDPRegisterContext // class has been made smart enough to detect when it needs to invalidate // which registers are valid by putting hooks in the register read and - // register supply functions where they check the process stop ID and do - // the right thing. - // if (StateIsStoppedState(GetState()) + // register supply functions where they check the process stop ID and do the + // right thing. if (StateIsStoppedState(GetState()) { const bool force = false; GetRegisterContext()->InvalidateIfNeeded(force); } } -const char *FreeBSDThread::GetInfo() { return NULL; } +const char *FreeBSDThread::GetInfo() { return nullptr; } void FreeBSDThread::SetName(const char *name) { m_thread_name_valid = (name && name[0]); @@ -158,15 +157,15 @@ const char *FreeBSDThread::GetName() { } if (m_thread_name.empty()) - return NULL; + return nullptr; return m_thread_name.c_str(); } lldb::RegisterContextSP FreeBSDThread::GetRegisterContext() { if (!m_reg_context_sp) { - m_posix_thread = NULL; + m_posix_thread = nullptr; - RegisterInfoInterface *reg_interface = NULL; + RegisterInfoInterface *reg_interface = nullptr; const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); assert(target_arch.GetTriple().getOS() == llvm::Triple::FreeBSD); @@ -282,7 +281,7 @@ bool FreeBSDThread::CalculateStopInfo() { } Unwind *FreeBSDThread::GetUnwinder() { - if (m_unwinder_ap.get() == NULL) + if (!m_unwinder_ap) m_unwinder_ap.reset(new UnwindLLDB(*this)); return m_unwinder_ap.get(); @@ -469,22 +468,19 @@ void FreeBSDThread::BreakNotify(const ProcessMessage &message) { GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); // If the breakpoint is for this thread, then we'll report the hit, but if it - // is for another thread, - // we create a stop reason with should_stop=false. If there is no breakpoint - // location, then report - // an invalid stop reason. We don't need to worry about stepping over the - // breakpoint here, that will - // be taken care of when the thread resumes and notices that there's a + // is for another thread, we create a stop reason with should_stop=false. If + // there is no breakpoint location, then report an invalid stop reason. We + // don't need to worry about stepping over the breakpoint here, that will be + // taken care of when the thread resumes and notices that there's a // breakpoint under the pc. if (bp_site) { lldb::break_id_t bp_id = bp_site->GetID(); // If we have an operating system plug-in, we might have set a thread - // specific breakpoint using the - // operating system thread ID, so we can't make any assumptions about the - // thread ID so we must always - // report the breakpoint regardless of the thread. + // specific breakpoint using the operating system thread ID, so we can't + // make any assumptions about the thread ID so we must always report the + // breakpoint regardless of the thread. if (bp_site->ValidForThisThread(this) || - GetProcess()->GetOperatingSystem() != NULL) + GetProcess()->GetOperatingSystem() != nullptr) SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id)); else { const bool should_stop = false; @@ -541,15 +537,14 @@ void FreeBSDThread::TraceNotify(const ProcessMessage &message) { lldb::BreakpointSiteSP bp_site( GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); - // If the current pc is a breakpoint site then set the StopInfo to Breakpoint. - // Otherwise, set the StopInfo to Watchpoint or Trace. - // If we have an operating system plug-in, we might have set a thread specific - // breakpoint using the - // operating system thread ID, so we can't make any assumptions about the - // thread ID so we must always - // report the breakpoint regardless of the thread. + // If the current pc is a breakpoint site then set the StopInfo to + // Breakpoint. Otherwise, set the StopInfo to Watchpoint or Trace. If we have + // an operating system plug-in, we might have set a thread specific + // breakpoint using the operating system thread ID, so we can't make any + // assumptions about the thread ID so we must always report the breakpoint + // regardless of the thread. if (bp_site && (bp_site->ValidForThisThread(this) || - GetProcess()->GetOperatingSystem() != NULL)) + GetProcess()->GetOperatingSystem() != nullptr)) SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID( *this, bp_site->GetID())); else { diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.h b/source/Plugins/Process/FreeBSD/FreeBSDThread.h index 72e846459552..c93cc4fbfd73 100644 --- a/source/Plugins/Process/FreeBSD/FreeBSDThread.h +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.h @@ -24,7 +24,7 @@ class POSIXBreakpointProtocol; //------------------------------------------------------------------------------ // @class FreeBSDThread -// @brief Abstraction of a FreeBSD thread. +// Abstraction of a FreeBSD thread. class FreeBSDThread : public lldb_private::Thread { public: //------------------------------------------------------------------ diff --git a/source/Plugins/Process/FreeBSD/POSIXStopInfo.h b/source/Plugins/Process/FreeBSD/POSIXStopInfo.h index 96861852b38e..ff3693107170 100644 --- a/source/Plugins/Process/FreeBSD/POSIXStopInfo.h +++ b/source/Plugins/Process/FreeBSD/POSIXStopInfo.h @@ -17,7 +17,7 @@ //===----------------------------------------------------------------------===// /// @class POSIXStopInfo -/// @brief Simple base class for all POSIX-specific StopInfo objects. +/// Simple base class for all POSIX-specific StopInfo objects. /// class POSIXStopInfo : public lldb_private::StopInfo { public: @@ -27,7 +27,7 @@ public: //===----------------------------------------------------------------------===// /// @class POSIXLimboStopInfo -/// @brief Represents the stop state of a process ready to exit. +/// Represents the stop state of a process ready to exit. /// class POSIXLimboStopInfo : public POSIXStopInfo { public: @@ -46,7 +46,7 @@ public: //===----------------------------------------------------------------------===// /// @class POSIXNewThreadStopInfo -/// @brief Represents the stop state of process when a new thread is spawned. +/// Represents the stop state of process when a new thread is spawned. /// class POSIXNewThreadStopInfo : public POSIXStopInfo { diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index 7a937db49be0..fa0bcea8f6bd 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -357,10 +357,10 @@ ProcessFreeBSD::GetFileSpec(const lldb_private::FileAction *file_action, if (file_action && file_action->GetAction() == FileAction::eFileActionOpen) { file_spec = file_action->GetFileSpec(); - // By default the stdio paths passed in will be pseudo-terminal - // (/dev/pts). If so, convert to using a different default path - // instead to redirect I/O to the debugger console. This should - // also handle user overrides to /dev/null or a different file. + // By default the stdio paths passed in will be pseudo-terminal (/dev/pts). + // If so, convert to using a different default path instead to redirect I/O + // to the debugger console. This should also handle user overrides to + // /dev/null or a different file. if (!file_spec || file_spec == dbg_pts_file_spec) file_spec = default_file_spec; } @@ -407,9 +407,8 @@ Status ProcessFreeBSD::DoLaunch(Module *module, m_monitor = new ProcessMonitor( this, module, launch_info.GetArguments().GetConstArgumentVector(), - launch_info.GetEnvironmentEntries().GetConstArgumentVector(), - stdin_file_spec, stdout_file_spec, stderr_file_spec, working_dir, - launch_info, error); + launch_info.GetEnvironment(), stdin_file_spec, stdout_file_spec, + stderr_file_spec, working_dir, launch_info, error); m_module = module; @@ -656,19 +655,19 @@ ProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site) { break; case llvm::Triple::arm: { - // The ARM reference recommends the use of 0xe7fddefe and 0xdefe - // but the linux kernel does otherwise. + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the + // linux kernel does otherwise. static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde}; lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); - AddressClass addr_class = eAddressClassUnknown; + AddressClass addr_class = AddressClass::eUnknown; if (bp_loc_sp) addr_class = bp_loc_sp->GetAddress().GetAddressClass(); - if (addr_class == eAddressClassCodeAlternateISA || - (addr_class == eAddressClassUnknown && + if (addr_class == AddressClass::eCodeAlternateISA || + (addr_class == AddressClass::eUnknown && bp_loc_sp->GetAddress().GetOffset() & 1)) { opcode = g_thumb_breakpoint_opcode; opcode_size = sizeof(g_thumb_breakpoint_opcode); @@ -745,8 +744,8 @@ Status ProcessFreeBSD::EnableWatchpoint(Watchpoint *wp, bool notify) { wp->SetEnabled(true, notify); return error; } else { - // Watchpoint enabling failed on at least one - // of the threads so roll back all of them + // Watchpoint enabling failed on at least one of the threads so roll + // back all of them DisableWatchpoint(wp, false); error.SetErrorString("Setting hardware watchpoint failed"); } @@ -813,8 +812,8 @@ Status ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num) { Status ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num, bool &after) { Status error = GetWatchpointSupportInfo(num); - // Watchpoints trigger and halt the inferior after - // the corresponding instruction has been executed. + // Watchpoints trigger and halt the inferior after the corresponding + // instruction has been executed. after = true; return error; } @@ -1077,8 +1076,8 @@ Status ProcessFreeBSD::SetupSoftwareSingleStepping(lldb::tid_t tid) { "Emulation was successful but PC wasn't updated"); next_pc = pc_it->second.GetAsUInt64(); } else if (pc_it == baton.m_register_values.end()) { - // Emulate instruction failed and it haven't changed PC. Advance PC - // with the size of the current opcode because the emulation of all + // Emulate instruction failed and it haven't changed PC. Advance PC with + // the size of the current opcode because the emulation of all // PC modifying instruction should be successful. The failure most // likely caused by a not supported instruction which don't modify PC. next_pc = diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index bd06fa25f0a0..51fdf2e5ef33 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -38,15 +38,11 @@ #include "ProcessFreeBSD.h" #include "ProcessMonitor.h" -extern "C" { -extern char **environ; -} - using namespace lldb; using namespace lldb_private; -// We disable the tracing of ptrace calls for integration builds to -// avoid the additional indirection and checks. +// We disable the tracing of ptrace calls for integration builds to avoid the +// additional indirection and checks. #ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION // Wrapper for ptrace to catch errors and log calls. @@ -65,9 +61,8 @@ const char *Get_PT_IO_OP(int op) { } } -// Wrapper for ptrace to catch errors and log calls. -// Note that ptrace sets errno on error because -1 is reserved as a valid -// result. +// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets +// errno on error because -1 is reserved as a valid result. extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, const char *reqName, const char *file, int line) { long int result; @@ -134,8 +129,8 @@ extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, return result; } -// Wrapper for ptrace when logging is not required. -// Sets errno to 0 prior to calling ptrace. +// Wrapper for ptrace when logging is not required. Sets errno to 0 prior to +// calling ptrace. extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data) { long result = 0; errno = 0; @@ -163,8 +158,10 @@ static size_t DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf, pi_desc.piod_addr = buf; pi_desc.piod_len = size; - if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) + if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) { error.SetErrorToErrno(); + return 0; + } return pi_desc.piod_len; } @@ -177,8 +174,10 @@ static size_t DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr, pi_desc.piod_addr = (void *)buf; pi_desc.piod_len = size; - if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) + if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) { error.SetErrorToErrno(); + return 0; + } return pi_desc.piod_len; } @@ -202,15 +201,16 @@ static bool EnsureFDFlags(int fd, int flags, Status &error) { //------------------------------------------------------------------------------ /// @class Operation -/// @brief Represents a ProcessMonitor operation. +/// Represents a ProcessMonitor operation. /// -/// Under FreeBSD, it is not possible to ptrace() from any other thread but the -/// one that spawned or attached to the process from the start. Therefore, when -/// a ProcessMonitor is asked to deliver or change the state of an inferior -/// process the operation must be "funneled" to a specific thread to perform the -/// task. The Operation class provides an abstract base for all services the -/// ProcessMonitor must perform via the single virtual function Execute, thus -/// encapsulating the code that needs to run in the privileged context. +/// Under FreeBSD, it is not possible to ptrace() from any other thread but +/// the one that spawned or attached to the process from the start. +/// Therefore, when a ProcessMonitor is asked to deliver or change the state +/// of an inferior process the operation must be "funneled" to a specific +/// thread to perform the task. The Operation class provides an abstract base +/// for all services the ProcessMonitor must perform via the single virtual +/// function Execute, thus encapsulating the code that needs to run in the +/// privileged context. class Operation { public: virtual ~Operation() {} @@ -219,7 +219,7 @@ public: //------------------------------------------------------------------------------ /// @class ReadOperation -/// @brief Implements ProcessMonitor::ReadMemory. +/// Implements ProcessMonitor::ReadMemory. class ReadOperation : public Operation { public: ReadOperation(lldb::addr_t addr, void *buff, size_t size, Status &error, @@ -245,7 +245,7 @@ void ReadOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class WriteOperation -/// @brief Implements ProcessMonitor::WriteMemory. +/// Implements ProcessMonitor::WriteMemory. class WriteOperation : public Operation { public: WriteOperation(lldb::addr_t addr, const void *buff, size_t size, @@ -271,7 +271,7 @@ void WriteOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class ReadRegOperation -/// @brief Implements ProcessMonitor::ReadRegisterValue. +/// Implements ProcessMonitor::ReadRegisterValue. class ReadRegOperation : public Operation { public: ReadRegOperation(lldb::tid_t tid, unsigned offset, unsigned size, @@ -311,7 +311,7 @@ void ReadRegOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class WriteRegOperation -/// @brief Implements ProcessMonitor::WriteRegisterValue. +/// Implements ProcessMonitor::WriteRegisterValue. class WriteRegOperation : public Operation { public: WriteRegOperation(lldb::tid_t tid, unsigned offset, @@ -344,7 +344,7 @@ void WriteRegOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class ReadDebugRegOperation -/// @brief Implements ProcessMonitor::ReadDebugRegisterValue. +/// Implements ProcessMonitor::ReadDebugRegisterValue. class ReadDebugRegOperation : public Operation { public: ReadDebugRegOperation(lldb::tid_t tid, unsigned offset, unsigned size, @@ -379,7 +379,7 @@ void ReadDebugRegOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class WriteDebugRegOperation -/// @brief Implements ProcessMonitor::WriteDebugRegisterValue. +/// Implements ProcessMonitor::WriteDebugRegisterValue. class WriteDebugRegOperation : public Operation { public: WriteDebugRegOperation(lldb::tid_t tid, unsigned offset, @@ -412,7 +412,7 @@ void WriteDebugRegOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class ReadGPROperation -/// @brief Implements ProcessMonitor::ReadGPR. +/// Implements ProcessMonitor::ReadGPR. class ReadGPROperation : public Operation { public: ReadGPROperation(lldb::tid_t tid, void *buf, bool &result) @@ -439,7 +439,7 @@ void ReadGPROperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class ReadFPROperation -/// @brief Implements ProcessMonitor::ReadFPR. +/// Implements ProcessMonitor::ReadFPR. class ReadFPROperation : public Operation { public: ReadFPROperation(lldb::tid_t tid, void *buf, bool &result) @@ -462,7 +462,7 @@ void ReadFPROperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class WriteGPROperation -/// @brief Implements ProcessMonitor::WriteGPR. +/// Implements ProcessMonitor::WriteGPR. class WriteGPROperation : public Operation { public: WriteGPROperation(lldb::tid_t tid, void *buf, bool &result) @@ -485,7 +485,7 @@ void WriteGPROperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class WriteFPROperation -/// @brief Implements ProcessMonitor::WriteFPR. +/// Implements ProcessMonitor::WriteFPR. class WriteFPROperation : public Operation { public: WriteFPROperation(lldb::tid_t tid, void *buf, bool &result) @@ -508,7 +508,7 @@ void WriteFPROperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class ResumeOperation -/// @brief Implements ProcessMonitor::Resume. +/// Implements ProcessMonitor::Resume. class ResumeOperation : public Operation { public: ResumeOperation(uint32_t signo, bool &result) @@ -539,7 +539,7 @@ void ResumeOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class SingleStepOperation -/// @brief Implements ProcessMonitor::SingleStep. +/// Implements ProcessMonitor::SingleStep. class SingleStepOperation : public Operation { public: SingleStepOperation(uint32_t signo, bool &result) @@ -567,7 +567,7 @@ void SingleStepOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class LwpInfoOperation -/// @brief Implements ProcessMonitor::GetLwpInfo. +/// Implements ProcessMonitor::GetLwpInfo. class LwpInfoOperation : public Operation { public: LwpInfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err) @@ -596,7 +596,7 @@ void LwpInfoOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class ThreadSuspendOperation -/// @brief Implements ProcessMonitor::ThreadSuspend. +/// Implements ProcessMonitor::ThreadSuspend. class ThreadSuspendOperation : public Operation { public: ThreadSuspendOperation(lldb::tid_t tid, bool suspend, bool &result) @@ -616,7 +616,7 @@ void ThreadSuspendOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class EventMessageOperation -/// @brief Implements ProcessMonitor::GetEventMessage. +/// Implements ProcessMonitor::GetEventMessage. class EventMessageOperation : public Operation { public: EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result) @@ -646,7 +646,7 @@ void EventMessageOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class KillOperation -/// @brief Implements ProcessMonitor::Kill. +/// Implements ProcessMonitor::Kill. class KillOperation : public Operation { public: KillOperation(bool &result) : m_result(result) {} @@ -668,7 +668,7 @@ void KillOperation::Execute(ProcessMonitor *monitor) { //------------------------------------------------------------------------------ /// @class DetachOperation -/// @brief Implements ProcessMonitor::Detach. +/// Implements ProcessMonitor::Detach. class DetachOperation : public Operation { public: DetachOperation(Status &result) : m_error(result) {} @@ -695,13 +695,14 @@ ProcessMonitor::OperationArgs::~OperationArgs() { sem_destroy(&m_semaphore); } ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor, lldb_private::Module *module, - char const **argv, char const **envp, + char const **argv, Environment env, const FileSpec &stdin_file_spec, const FileSpec &stdout_file_spec, const FileSpec &stderr_file_spec, const FileSpec &working_dir) - : OperationArgs(monitor), m_module(module), m_argv(argv), m_envp(envp), - m_stdin_file_spec(stdin_file_spec), m_stdout_file_spec(stdout_file_spec), + : OperationArgs(monitor), m_module(module), m_argv(argv), + m_env(std::move(env)), m_stdin_file_spec(stdin_file_spec), + m_stdout_file_spec(stdout_file_spec), m_stderr_file_spec(stderr_file_spec), m_working_dir(working_dir) {} ProcessMonitor::LaunchArgs::~LaunchArgs() {} @@ -714,11 +715,10 @@ ProcessMonitor::AttachArgs::~AttachArgs() {} //------------------------------------------------------------------------------ /// The basic design of the ProcessMonitor is built around two threads. /// -/// One thread (@see SignalThread) simply blocks on a call to waitpid() looking -/// for changes in the debugee state. When a change is detected a +/// One thread (@see SignalThread) simply blocks on a call to waitpid() +/// looking for changes in the debugee state. When a change is detected a /// ProcessMessage is sent to the associated ProcessFreeBSD instance. This -/// thread -/// "drives" state changes in the debugger. +/// thread "drives" state changes in the debugger. /// /// The second thread (@see OperationThread) is responsible for two things 1) /// launching or attaching to the inferior process, and then 2) servicing @@ -726,7 +726,7 @@ ProcessMonitor::AttachArgs::~AttachArgs() {} /// on the Operation class for more info as to why this is needed. ProcessMonitor::ProcessMonitor( ProcessFreeBSD *process, Module *module, const char *argv[], - const char *envp[], const FileSpec &stdin_file_spec, + Environment env, const FileSpec &stdin_file_spec, const FileSpec &stdout_file_spec, const FileSpec &stderr_file_spec, const FileSpec &working_dir, const lldb_private::ProcessLaunchInfo & /* launch_info */, @@ -736,7 +736,7 @@ ProcessMonitor::ProcessMonitor( using namespace std::placeholders; std::unique_ptr<LaunchArgs> args( - new LaunchArgs(this, module, argv, envp, stdin_file_spec, + new LaunchArgs(this, module, argv, std::move(env), stdin_file_spec, stdout_file_spec, stderr_file_spec, working_dir)); sem_init(&m_operation_pending, 0, 0); @@ -837,7 +837,6 @@ bool ProcessMonitor::Launch(LaunchArgs *args) { ProcessMonitor *monitor = args->m_monitor; ProcessFreeBSD &process = monitor->GetProcess(); const char **argv = args->m_argv; - const char **envp = args->m_envp; const FileSpec &stdin_file_spec = args->m_stdin_file_spec; const FileSpec &stdout_file_spec = args->m_stdout_file_spec; const FileSpec &stderr_file_spec = args->m_stderr_file_spec; @@ -849,8 +848,8 @@ bool ProcessMonitor::Launch(LaunchArgs *args) { ::pid_t pid; // Propagate the environment if one is not supplied. - if (envp == NULL || envp[0] == NULL) - envp = const_cast<const char **>(environ); + Environment::Envp envp = + (args->m_env.empty() ? Host::GetEnvironment() : args->m_env).getEnvp(); if ((pid = terminal.Fork(err_str, err_len)) == -1) { args->m_error.SetErrorToGenericError(); @@ -875,9 +874,9 @@ bool ProcessMonitor::Launch(LaunchArgs *args) { if (PTRACE(PT_TRACE_ME, 0, NULL, 0) < 0) exit(ePtraceFailed); - // terminal has already dupped the tty descriptors to stdin/out/err. - // This closes original fd from which they were copied (and avoids - // leaking descriptors to the debugged process. + // terminal has already dupped the tty descriptors to stdin/out/err. This + // closes original fd from which they were copied (and avoids leaking + // descriptors to the debugged process. terminal.CloseSlaveFileDescriptor(); // Do not inherit setgid powers. @@ -908,8 +907,7 @@ bool ProcessMonitor::Launch(LaunchArgs *args) { exit(eChdirFailed); // Execute. We should never return. - execve(argv[0], const_cast<char *const *>(argv), - const_cast<char *const *>(envp)); + execve(argv[0], const_cast<char *const *>(argv), envp); exit(eExecFailed); } @@ -1103,9 +1101,9 @@ ProcessMessage ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, break; case (SIGTRAP /* | (PTRACE_EVENT_EXIT << 8) */): { - // The inferior process is about to exit. Maintain the process in a - // state of "limbo" until we are explicitly commanded to detach, - // destroy, resume, etc. + // The inferior process is about to exit. Maintain the process in a state + // of "limbo" until we are explicitly commanded to detach, destroy, resume, + // etc. unsigned long data = 0; if (!monitor->GetEventMessage(tid, &data)) data = -1; @@ -1160,8 +1158,8 @@ ProcessMessage ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); // POSIX says that process behaviour is undefined after it ignores a SIGFPE, - // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a - // kill(2) or raise(3). Similarly for tgkill(2) on FreeBSD. + // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a kill(2) + // or raise(3). Similarly for tgkill(2) on FreeBSD. // // IOW, user generated signals never generate what we consider to be a // "crash". @@ -1197,8 +1195,8 @@ ProcessMessage ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, } // else; Use atleast si_signo info for other si_code } - // Everything else is "normal" and does not require any special action on - // our part. + // Everything else is "normal" and does not require any special action on our + // part. return ProcessMessage::Signal(tid, signo); } @@ -1424,14 +1422,14 @@ void ProcessMonitor::StopMonitor() { } // FIXME: On Linux, when a new thread is created, we receive to notifications, -// (1) a SIGTRAP|PTRACE_EVENT_CLONE from the main process thread with the -// child thread id as additional information, and (2) a SIGSTOP|SI_USER from -// the new child thread indicating that it has is stopped because we attached. -// We have no guarantee of the order in which these arrive, but we need both -// before we are ready to proceed. We currently keep a list of threads which -// have sent the initial SIGSTOP|SI_USER event. Then when we receive the -// SIGTRAP|PTRACE_EVENT_CLONE notification, if the initial stop has not occurred -// we call ProcessMonitor::WaitForInitialTIDStop() to wait for it. +// (1) a SIGTRAP|PTRACE_EVENT_CLONE from the main process thread with the child +// thread id as additional information, and (2) a SIGSTOP|SI_USER from the new +// child thread indicating that it has is stopped because we attached. We have +// no guarantee of the order in which these arrive, but we need both before we +// are ready to proceed. We currently keep a list of threads which have sent +// the initial SIGSTOP|SI_USER event. Then when we receive the +// SIGTRAP|PTRACE_EVENT_CLONE notification, if the initial stop has not +// occurred we call ProcessMonitor::WaitForInitialTIDStop() to wait for it. // // Right now, the above logic is in ProcessPOSIX, so we need a definition of // this function in the FreeBSD ProcessMonitor implementation even if it isn't diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 0963453a31b1..1d3e2d746fa9 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -32,10 +32,10 @@ class ProcessFreeBSD; class Operation; /// @class ProcessMonitor -/// @brief Manages communication with the inferior (debugee) process. +/// Manages communication with the inferior (debugee) process. /// -/// Upon construction, this class prepares and launches an inferior process for -/// debugging. +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. /// /// Changes in the inferior process state are propagated to the associated /// ProcessFreeBSD instance by calling ProcessFreeBSD::SendMessage with the @@ -48,7 +48,7 @@ public: /// Launches an inferior process ready for debugging. Forms the /// implementation of Process::DoLaunch. ProcessMonitor(ProcessFreeBSD *process, lldb_private::Module *module, - char const *argv[], char const *envp[], + char const *argv[], lldb_private::Environment env, const lldb_private::FileSpec &stdin_file_spec, const lldb_private::FileSpec &stdout_file_spec, const lldb_private::FileSpec &stderr_file_spec, @@ -74,8 +74,7 @@ public: /// standard error of this debugee. Even if stderr and stdout were /// redirected on launch it may still happen that data is available on this /// descriptor (if the inferior process opens /dev/tty, for example). This - /// descriptor is - /// closed after a call to StopMonitor(). + /// descriptor is closed after a call to StopMonitor(). /// /// If this monitor was attached to an existing process this method returns /// -1. @@ -95,8 +94,8 @@ public: size_t WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, lldb_private::Status &error); - /// Reads the contents from the register identified by the given (architecture - /// dependent) offset. + /// Reads the contents from the register identified by the given + /// (architecture dependent) offset. /// /// This method is provided for use by RegisterContextFreeBSD derivatives. bool ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, @@ -215,11 +214,11 @@ private: /// @class LauchArgs /// - /// @brief Simple structure to pass data to the thread responsible for - /// launching a child process. + /// Simple structure to pass data to the thread responsible for launching a + /// child process. struct LaunchArgs : OperationArgs { LaunchArgs(ProcessMonitor *monitor, lldb_private::Module *module, - char const **argv, char const **envp, + char const **argv, lldb_private::Environment env, const lldb_private::FileSpec &stdin_file_spec, const lldb_private::FileSpec &stdout_file_spec, const lldb_private::FileSpec &stderr_file_spec, @@ -229,7 +228,7 @@ private: lldb_private::Module *m_module; // The executable image to launch. char const **m_argv; // Process arguments. - char const **m_envp; // Process environment. + lldb_private::Environment m_env; // Process environment. const lldb_private::FileSpec m_stdin_file_spec; // Redirect stdin or empty. const lldb_private::FileSpec m_stdout_file_spec; // Redirect stdout or empty. diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h index 4ff5121bac13..b1b44e71de46 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h @@ -13,14 +13,14 @@ // C Includes // C++ Includes // Other libraries and framework includes -#include "RegisterInfoInterface.h" +#include "Plugins/Process/Utility/RegisterInfoInterface.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/ArchSpec.h" //------------------------------------------------------------------------------ /// @class POSIXBreakpointProtocol /// -/// @brief Extends RegisterClass with a few virtual operations useful on POSIX. +/// Extends RegisterClass with a few virtual operations useful on POSIX. class POSIXBreakpointProtocol { public: POSIXBreakpointProtocol() { m_watchpoints_initialized = false; } diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp index 59d42b9ad72e..8ddc253aea5d 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp @@ -14,7 +14,7 @@ #include "ProcessFreeBSD.h" #include "ProcessMonitor.h" #include "RegisterContextPOSIXProcessMonitor_arm.h" -#include "RegisterContextPOSIX_arm.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" using namespace lldb_private; using namespace lldb; diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp index b911ee222015..734167e1fc98 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -130,14 +130,14 @@ bool RegisterContextPOSIXProcessMonitor_mips64::ReadRegister( bool success = ReadRegister(full_reg, value); if (success) { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned value - // one byte to the right. + // If our read was not aligned (for ah,bh,ch,dh), shift our returned + // value one byte to the right. if (is_subreg && (reg_info->byte_offset & 0x1)) value.SetUInt64(value.GetAsUInt64() >> 8); // If our return byte size was greater than the return value reg size, - // then - // use the type specified by reg_info rather than the uint64_t default + // then use the type specified by reg_info rather than the uint64_t + // default if (value.GetByteSize() > reg_info->byte_size) value.SetType(reg_info); } diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp index bc1d4df89fc8..5cc6cd290629 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp @@ -14,7 +14,7 @@ #include "ProcessFreeBSD.h" #include "ProcessMonitor.h" #include "RegisterContextPOSIXProcessMonitor_powerpc.h" -#include "RegisterContextPOSIX_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" using namespace lldb_private; using namespace lldb; @@ -140,8 +140,8 @@ bool RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister( if (success) { // If our return byte size was greater than the return value reg size, - // then - // use the type specified by reg_info rather than the uint64_t default + // then use the type specified by reg_info rather than the uint64_t + // default if (value.GetByteSize() > reg_info->byte_size) value.SetType(reg_info); } diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp index 4608520dba40..7db7f803b371 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -193,14 +193,14 @@ bool RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister( bool success = ReadRegister(full_reg, value); if (success) { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned value - // one byte to the right. + // If our read was not aligned (for ah,bh,ch,dh), shift our returned + // value one byte to the right. if (is_subreg && (reg_info->byte_offset & 0x1)) value.SetUInt64(value.GetAsUInt64() >> 8); // If our return byte size was greater than the return value reg size, - // then - // use the type specified by reg_info rather than the uint64_t default + // then use the type specified by reg_info rather than the uint64_t + // default if (value.GetByteSize() > reg_info->byte_size) value.SetType(reg_info); } @@ -221,7 +221,8 @@ bool RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister( value.SetBytes(m_fpr.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order); if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) { - // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes + // Concatenate ymm using the register halves in xmm.bytes and + // ymmh.bytes if (GetFPRType() == eXSAVE && CopyXSTATEtoYMM(reg, byte_order)) value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order); @@ -233,11 +234,10 @@ bool RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister( return false; } - // Get pointer to m_fpr.fxsave variable and set the data from it. - // Byte offsets of all registers are calculated wrt 'UserArea' structure. - // However, ReadFPR() reads fpu registers {using ptrace(PT_GETFPREGS,..)} - // and stores them in 'm_fpr' (of type FPR structure). To extract values of - // fpu + // Get pointer to m_fpr.fxsave variable and set the data from it. Byte + // offsets of all registers are calculated wrt 'UserArea' structure. However, + // ReadFPR() reads fpu registers {using ptrace(PT_GETFPREGS,..)} and stores + // them in 'm_fpr' (of type FPR structure). To extract values of fpu // registers, m_fpr should be read at byte offsets calculated wrt to FPR // structure. @@ -299,12 +299,12 @@ bool RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister( return false; } } else { - // Get pointer to m_fpr.fxsave variable and set the data to it. - // Byte offsets of all registers are calculated wrt 'UserArea' structure. - // However, WriteFPR() takes m_fpr (of type FPR structure) and writes only - // fpu - // registers using ptrace(PT_SETFPREGS,..) API. Hence fpu registers should - // be written in m_fpr at byte offsets calculated wrt FPR structure. + // Get pointer to m_fpr.fxsave variable and set the data to it. Byte + // offsets of all registers are calculated wrt 'UserArea' structure. + // However, WriteFPR() takes m_fpr (of type FPR structure) and writes + // only fpu registers using ptrace(PT_SETFPREGS,..) API. Hence fpu + // registers should be written in m_fpr at byte offsets calculated wrt + // FPR structure. // Since, FPR structure is also one of the member of UserArea structure. // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - diff --git a/source/Plugins/Process/Linux/CMakeLists.txt b/source/Plugins/Process/Linux/CMakeLists.txt index 390dbd9ff8bf..b4b4c401a271 100644 --- a/source/Plugins/Process/Linux/CMakeLists.txt +++ b/source/Plugins/Process/Linux/CMakeLists.txt @@ -1,7 +1,3 @@ -include_directories(.) -include_directories(../POSIX) -include_directories(../Utility) - add_lldb_library(lldbPluginProcessLinux PLUGIN NativeProcessLinux.cpp NativeRegisterContextLinux.cpp diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp index 136af361af29..3fb886e1c7a3 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -245,13 +245,15 @@ NativeProcessLinux::Factory::Launch(ProcessLaunchInfo &launch_info, } LLDB_LOG(log, "inferior started, now in stopped state"); - ArchSpec arch; - if ((status = ResolveProcessArchitecture(pid, arch)).Fail()) - return status.ToError(); + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error<StringError>("Cannot get process architecture", + llvm::inconvertibleErrorCode()); + } // Set the architecture to the exe architecture. LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, - arch.GetArchitectureName()); + Info.GetArchitecture().GetArchitectureName()); status = SetDefaultPtraceOpts(pid); if (status.Fail()) { @@ -261,7 +263,7 @@ NativeProcessLinux::Factory::Launch(ProcessLaunchInfo &launch_info, return std::unique_ptr<NativeProcessLinux>(new NativeProcessLinux( pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, - arch, mainloop, {pid})); + Info.GetArchitecture(), mainloop, {pid})); } llvm::Expected<std::unique_ptr<NativeProcessProtocol>> @@ -272,17 +274,18 @@ NativeProcessLinux::Factory::Attach( LLDB_LOG(log, "pid = {0:x}", pid); // Retrieve the architecture for the running process. - ArchSpec arch; - Status status = ResolveProcessArchitecture(pid, arch); - if (!status.Success()) - return status.ToError(); + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error<StringError>("Cannot get process architecture", + llvm::inconvertibleErrorCode()); + } auto tids_or = NativeProcessLinux::Attach(pid); if (!tids_or) return tids_or.takeError(); return std::unique_ptr<NativeProcessLinux>(new NativeProcessLinux( - pid, -1, native_delegate, arch, mainloop, *tids_or)); + pid, -1, native_delegate, Info.GetArchitecture(), mainloop, *tids_or)); } // ----------------------------------------------------------------------------- @@ -334,8 +337,8 @@ llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) { // Attach to the requested process. // An attach will cause the thread to stop with a SIGSTOP. if ((status = PtraceWrapper(PTRACE_ATTACH, tid)).Fail()) { - // No such thread. The thread may have exited. - // More error handling may be needed. + // No such thread. The thread may have exited. More error handling + // may be needed. if (status.GetError() == ESRCH) { it = tids_to_attach.erase(it); continue; @@ -345,11 +348,11 @@ llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) { int wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, nullptr, __WALL); - // Need to use __WALL otherwise we receive an error with errno=ECHLD - // At this point we should have a thread stopped if waitpid succeeds. + // Need to use __WALL otherwise we receive an error with errno=ECHLD At + // this point we should have a thread stopped if waitpid succeeds. if (wpid < 0) { - // No such thread. The thread may have exited. - // More error handling may be needed. + // No such thread. The thread may have exited. More error handling + // may be needed. if (errno == ESRCH) { it = tids_to_attach.erase(it); continue; @@ -394,8 +397,8 @@ Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) { // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK) ptrace_opts |= PTRACE_O_TRACECLONE; - // Have the tracer notify us before execve returns - // (needed to disable legacy SIGTRAP generation) + // Have the tracer notify us before execve returns (needed to disable legacy + // SIGTRAP generation) ptrace_opts |= PTRACE_O_TRACEEXEC; return PtraceWrapper(PTRACE_SETOPTIONS, pid, nullptr, (void *)ptrace_opts); @@ -435,8 +438,8 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, auto thread_sp = GetThreadByID(pid); if (!thread_sp) { - // Normally, the only situation when we cannot find the thread is if we have - // just received a new thread notification. This is indicated by + // Normally, the only situation when we cannot find the thread is if we + // have just received a new thread notification. This is indicated by // GetSignalInfo() returning si_code == SI_USER and si_pid == 0 LLDB_LOG(log, "received notification about an unknown tid {0}.", pid); @@ -468,15 +471,15 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, MonitorSignal(info, *thread_sp, exited); } else { if (info_err.GetError() == EINVAL) { - // This is a group stop reception for this tid. - // We can reach here if we reinject SIGSTOP, SIGSTP, SIGTTIN or SIGTTOU - // into the tracee, triggering the group-stop mechanism. Normally - // receiving these would stop the process, pending a SIGCONT. Simulating - // this state in a debugger is hard and is generally not needed (one use - // case is debugging background task being managed by a shell). For - // general use, it is sufficient to stop the process in a signal-delivery - // stop which happens before the group stop. This done by MonitorSignal - // and works correctly for all signals. + // This is a group stop reception for this tid. We can reach here if we + // reinject SIGSTOP, SIGSTP, SIGTTIN or SIGTTOU into the tracee, + // triggering the group-stop mechanism. Normally receiving these would + // stop the process, pending a SIGCONT. Simulating this state in a + // debugger is hard and is generally not needed (one use case is + // debugging background task being managed by a shell). For general use, + // it is sufficient to stop the process in a signal-delivery stop which + // happens before the group stop. This done by MonitorSignal and works + // correctly for all signals. LLDB_LOG(log, "received a group stop for pid {0} tid {1}. Transparent " "handling of group stops not supported, resuming the " @@ -502,8 +505,8 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, if (is_main_thread) { // Notify the delegate - our process is not available but appears to - // have been killed outside - // our control. Is eStateExited the right exit state in this case? + // have been killed outside our control. Is eStateExited the right + // exit state in this case? SetExitStatus(status, true); SetState(StateType::eStateExited, true); } else { @@ -572,19 +575,14 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, switch (info.si_code) { // TODO: these two cases are required if we want to support tracing of the - // inferiors' children. We'd need this to debug a monitor. - // case (SIGTRAP | (PTRACE_EVENT_FORK << 8)): - // case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)): + // inferiors' children. We'd need this to debug a monitor. case (SIGTRAP | + // (PTRACE_EVENT_FORK << 8)): case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)): case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)): { // This is the notification on the parent thread which informs us of new - // thread - // creation. - // We don't want to do anything with the parent thread so we just resume it. - // In case we - // want to implement "break on thread creation" functionality, we would need - // to stop - // here. + // thread creation. We don't want to do anything with the parent thread so + // we just resume it. In case we want to implement "break on thread + // creation" functionality, we would need to stop here. unsigned long event_message = 0; if (GetEventMessage(thread.GetID(), &event_message).Fail()) { @@ -634,10 +632,10 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, } case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)): { - // The inferior process or one of its threads is about to exit. - // We don't want to do anything with the thread so we just resume it. In - // case we want to implement "break on thread exit" functionality, we would - // need to stop here. + // The inferior process or one of its threads is about to exit. We don't + // want to do anything with the thread so we just resume it. In case we + // want to implement "break on thread exit" functionality, we would need to + // stop here. unsigned long data = 0; if (GetEventMessage(thread.GetID(), &data).Fail()) @@ -655,8 +653,8 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, // Due to a kernel bug, we may sometimes get this stop after the inferior // gets a SIGKILL. This confuses our state tracking logic in // ResumeThread(), since normally, we should not be receiving any ptrace - // events while the inferior is stopped. This makes sure that the inferior - // is resumed and exits normally. + // events while the inferior is stopped. This makes sure that the + // inferior is resumed and exits normally. state = eStateRunning; } ResumeThread(thread, state, LLDB_INVALID_SIGNAL_NUMBER); @@ -702,8 +700,8 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, case SI_KERNEL: #if defined __mips__ - // For mips there is no special signal for watchpoint - // So we check for watchpoint in kernel trap + // For mips there is no special signal for watchpoint So we check for + // watchpoint in kernel trap { // If a watchpoint was hit, report it uint32_t wp_index; @@ -779,8 +777,8 @@ void NativeProcessLinux::MonitorWatchpoint(NativeThreadLinux &thread, LLDB_LOG(log, "received watchpoint event, pid = {0}, wp_index = {1}", thread.GetID(), wp_index); - // Mark the thread as stopped at watchpoint. - // The address is at (lldb::addr_t)info->si_addr if we need it. + // Mark the thread as stopped at watchpoint. The address is at + // (lldb::addr_t)info->si_addr if we need it. thread.SetStoppedByWatchpoint(wp_index); // We need to tell all other running threads before we notify the delegate @@ -796,8 +794,8 @@ void NativeProcessLinux::MonitorSignal(const siginfo_t &info, Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); // POSIX says that process behaviour is undefined after it ignores a SIGFPE, - // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a - // kill(2) or raise(3). Similarly for tgkill(2) on Linux. + // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a kill(2) + // or raise(3). Similarly for tgkill(2) on Linux. // // IOW, user generated signals never generate what we consider to be a // "crash". @@ -816,22 +814,22 @@ void NativeProcessLinux::MonitorSignal(const siginfo_t &info, // This is a tgkill()-based stop. LLDB_LOG(log, "pid {0} tid {1}, thread stopped", GetID(), thread.GetID()); - // Check that we're not already marked with a stop reason. - // Note this thread really shouldn't already be marked as stopped - if we - // were, that would imply that the kernel signaled us with the thread - // stopping which we handled and marked as stopped, and that, without an - // intervening resume, we received another stop. It is more likely that we - // are missing the marking of a run state somewhere if we find that the - // thread was marked as stopped. + // Check that we're not already marked with a stop reason. Note this thread + // really shouldn't already be marked as stopped - if we were, that would + // imply that the kernel signaled us with the thread stopping which we + // handled and marked as stopped, and that, without an intervening resume, + // we received another stop. It is more likely that we are missing the + // marking of a run state somewhere if we find that the thread was marked + // as stopped. const StateType thread_state = thread.GetState(); if (!StateIsStoppedState(thread_state, false)) { // An inferior thread has stopped because of a SIGSTOP we have sent it. // Generally, these are not important stops and we don't want to report // them as they are just used to stop other threads when one thread (the // one with the *real* stop reason) hits a breakpoint (watchpoint, - // etc...). However, in the case of an asynchronous Interrupt(), this *is* - // the real stop reason, so we leave the signal intact if this is the - // thread that was chosen as the triggering thread. + // etc...). However, in the case of an asynchronous Interrupt(), this + // *is* the real stop reason, so we leave the signal intact if this is + // the thread that was chosen as the triggering thread. if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { if (m_pending_notification_tid == thread.GetID()) thread.SetStoppedBySignal(SIGSTOP, &info); @@ -860,8 +858,8 @@ void NativeProcessLinux::MonitorSignal(const siginfo_t &info, return; } - // Check if debugger should stop at this signal or just ignore it - // and resume the inferior. + // Check if debugger should stop at this signal or just ignore it and resume + // the inferior. if (m_signals_to_ignore.find(signo) != m_signals_to_ignore.end()) { ResumeThread(thread, thread.GetState(), signo); return; @@ -912,9 +910,9 @@ static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, return true; } - // The emulator only fill in the dwarf regsiter numbers (and in some case - // the generic register numbers). Get the full register info from the - // register context based on the dwarf register numbers. + // The emulator only fill in the dwarf regsiter numbers (and in some case the + // generic register numbers). Get the full register info from the register + // context based on the dwarf register numbers. const RegisterInfo *full_reg_info = emulator_baton->m_reg_context.GetRegisterInfo( eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); @@ -998,8 +996,8 @@ NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) { else next_flags = ReadFlags(register_context); } else if (pc_it == baton.m_register_values.end()) { - // Emulate instruction failed and it haven't changed PC. Advance PC - // with the size of the current opcode because the emulation of all + // Emulate instruction failed and it haven't changed PC. Advance PC with + // the size of the current opcode because the emulation of all // PC modifying instruction should be successful. The failure most // likely caused by a not supported instruction which don't modify PC. next_pc = register_context.GetPC() + emulator_ap->GetOpcode().GetByteSize(); @@ -1030,8 +1028,8 @@ NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) { error = SetSoftwareBreakpoint(next_pc, 0); } - // If setting the breakpoint fails because next_pc is out of - // the address space, ignore it and let the debugee segfault. + // If setting the breakpoint fails because next_pc is out of the address + // space, ignore it and let the debugee segfault. if (error.GetError() == EIO || error.GetError() == EFAULT) { return Status(); } else if (error.Fail()) @@ -1162,8 +1160,8 @@ Status NativeProcessLinux::Signal(int signo) { } Status NativeProcessLinux::Interrupt() { - // Pick a running thread (or if none, a not-dead stopped thread) as - // the chosen thread that will be the stop-reason thread. + // Pick a running thread (or if none, a not-dead stopped thread) as the + // chosen thread that will be the stop-reason thread. Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); NativeThreadProtocol *running_thread = nullptr; @@ -1171,15 +1169,15 @@ Status NativeProcessLinux::Interrupt() { LLDB_LOG(log, "selecting running thread for interrupt target"); for (const auto &thread : m_threads) { - // If we have a running or stepping thread, we'll call that the - // target of the interrupt. + // If we have a running or stepping thread, we'll call that the target of + // the interrupt. const auto thread_state = thread->GetState(); if (thread_state == eStateRunning || thread_state == eStateStepping) { running_thread = thread.get(); break; } else if (!stopped_thread && StateIsStoppedState(thread_state, true)) { - // Remember the first non-dead stopped thread. We'll use that as a backup - // if there are no running threads. + // Remember the first non-dead stopped thread. We'll use that as a + // backup if there are no running threads. stopped_thread = thread.get(); } } @@ -1248,9 +1246,8 @@ ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef &maps_line, 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). + // 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); @@ -1331,8 +1328,8 @@ Status NativeProcessLinux::GetMemoryRegionInfo(lldb::addr_t load_addr, // the virtual address space, // with no perms if it is not mapped. - // Use an approach that reads memory regions from /proc/{pid}/maps. - // Assume proc maps entries are in ascending order. + // Use an approach that reads memory regions from /proc/{pid}/maps. Assume + // proc maps entries are in ascending order. // FIXME assert if we find differently. if (m_supports_mem_region == LazyBool::eLazyBoolNo) { @@ -1383,10 +1380,8 @@ Status NativeProcessLinux::GetMemoryRegionInfo(lldb::addr_t load_addr, } // If we made it here, we didn't find an entry that contained the given - // address. Return the - // load_addr as start and the amount of bytes betwwen load address and the end - // of the memory as - // size. + // address. Return the load_addr as start and the amount of bytes betwwen + // load address and the end of the memory as size. range_info.GetRange().SetRangeBase(load_addr); range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); @@ -1431,8 +1426,8 @@ Status NativeProcessLinux::PopulateMemoryRegionCache() { if (m_mem_region_cache.empty()) { // No entries after attempting to read them. This shouldn't happen if - // /proc/{pid}/maps is supported. Assume we don't support map entries - // via procfs. + // /proc/{pid}/maps is supported. Assume we don't support map entries via + // procfs. m_supports_mem_region = LazyBool::eLazyBoolNo; LLDB_LOG(log, "failed to find any procfs maps entries, assuming no support " @@ -1459,8 +1454,8 @@ void NativeProcessLinux::DoStopIDBumped(uint32_t newBumpId) { Status NativeProcessLinux::AllocateMemory(size_t size, uint32_t permissions, lldb::addr_t &addr) { // FIXME implementing this requires the equivalent of -// InferiorCallPOSIX::InferiorCallMmap, which depends on -// functional ThreadPlans working with Native*Protocol. +// InferiorCallPOSIX::InferiorCallMmap, which depends on functional ThreadPlans +// working with Native*Protocol. #if 1 return Status("not implemented yet"); #else @@ -1475,8 +1470,7 @@ Status NativeProcessLinux::AllocateMemory(size_t size, uint32_t permissions, prot |= eMmapProtExec; // TODO implement this directly in NativeProcessLinux - // (and lift to NativeProcessPOSIX if/when that class is - // refactored out). + // (and lift to NativeProcessPOSIX if/when that class is refactored out). if (InferiorCallMmap(this, addr, 0, size, prot, eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { m_addr_to_mmap_size[addr] = size; @@ -1502,10 +1496,9 @@ lldb::addr_t NativeProcessLinux::GetSharedLibraryInfoAddress() { } size_t NativeProcessLinux::UpdateThreads() { - // The NativeProcessLinux monitoring threads are always up to date - // with respect to thread state and they keep the thread list - // populated properly. All this method needs to do is return the - // thread count. + // The NativeProcessLinux monitoring threads are always up to date with + // respect to thread state and they keep the thread list populated properly. + // All this method needs to do is return the thread count. return m_threads.size(); } @@ -1515,7 +1508,6 @@ Status NativeProcessLinux::GetSoftwareBreakpointPCOffset( // 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}; - static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap switch (m_arch.GetMachine()) { case llvm::Triple::x86: @@ -1527,16 +1519,13 @@ Status NativeProcessLinux::GetSoftwareBreakpointPCOffset( actual_opcode_size = static_cast<uint32_t>(sizeof(g_s390x_opcode)); return Status(); - case llvm::Triple::ppc64le: - actual_opcode_size = static_cast<uint32_t>(sizeof(g_ppc64le_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(); @@ -1633,161 +1622,11 @@ Status NativeProcessLinux::GetSoftwareBreakpointTrapOpcode( } } -#if 0 -ProcessMessage::CrashReason -NativeProcessLinux::GetCrashReasonForSIGSEGV(const siginfo_t *info) -{ - ProcessMessage::CrashReason reason; - assert(info->si_signo == SIGSEGV); - - reason = ProcessMessage::eInvalidCrashReason; - - switch (info->si_code) - { - default: - assert(false && "unexpected si_code for SIGSEGV"); - break; - case SI_KERNEL: - // Linux will occasionally send spurious SI_KERNEL codes. - // (this is poorly documented in sigaction) - // One way to get this is via unaligned SIMD loads. - reason = ProcessMessage::eInvalidAddress; // for lack of anything better - break; - case SEGV_MAPERR: - reason = ProcessMessage::eInvalidAddress; - break; - case SEGV_ACCERR: - reason = ProcessMessage::ePrivilegedAddress; - break; - } - - return reason; -} -#endif - -#if 0 -ProcessMessage::CrashReason -NativeProcessLinux::GetCrashReasonForSIGILL(const siginfo_t *info) -{ - ProcessMessage::CrashReason reason; - assert(info->si_signo == SIGILL); - - reason = ProcessMessage::eInvalidCrashReason; - - switch (info->si_code) - { - default: - assert(false && "unexpected si_code for SIGILL"); - break; - case ILL_ILLOPC: - reason = ProcessMessage::eIllegalOpcode; - break; - case ILL_ILLOPN: - reason = ProcessMessage::eIllegalOperand; - break; - case ILL_ILLADR: - reason = ProcessMessage::eIllegalAddressingMode; - break; - case ILL_ILLTRP: - reason = ProcessMessage::eIllegalTrap; - break; - case ILL_PRVOPC: - reason = ProcessMessage::ePrivilegedOpcode; - break; - case ILL_PRVREG: - reason = ProcessMessage::ePrivilegedRegister; - break; - case ILL_COPROC: - reason = ProcessMessage::eCoprocessorError; - break; - case ILL_BADSTK: - reason = ProcessMessage::eInternalStackError; - break; - } - - return reason; -} -#endif - -#if 0 -ProcessMessage::CrashReason -NativeProcessLinux::GetCrashReasonForSIGFPE(const siginfo_t *info) -{ - ProcessMessage::CrashReason reason; - assert(info->si_signo == SIGFPE); - - reason = ProcessMessage::eInvalidCrashReason; - - switch (info->si_code) - { - default: - assert(false && "unexpected si_code for SIGFPE"); - break; - case FPE_INTDIV: - reason = ProcessMessage::eIntegerDivideByZero; - break; - case FPE_INTOVF: - reason = ProcessMessage::eIntegerOverflow; - break; - case FPE_FLTDIV: - reason = ProcessMessage::eFloatDivideByZero; - break; - case FPE_FLTOVF: - reason = ProcessMessage::eFloatOverflow; - break; - case FPE_FLTUND: - reason = ProcessMessage::eFloatUnderflow; - break; - case FPE_FLTRES: - reason = ProcessMessage::eFloatInexactResult; - break; - case FPE_FLTINV: - reason = ProcessMessage::eFloatInvalidOperation; - break; - case FPE_FLTSUB: - reason = ProcessMessage::eFloatSubscriptRange; - break; - } - - return reason; -} -#endif - -#if 0 -ProcessMessage::CrashReason -NativeProcessLinux::GetCrashReasonForSIGBUS(const siginfo_t *info) -{ - ProcessMessage::CrashReason reason; - assert(info->si_signo == SIGBUS); - - reason = ProcessMessage::eInvalidCrashReason; - - switch (info->si_code) - { - default: - assert(false && "unexpected si_code for SIGBUS"); - break; - case BUS_ADRALN: - reason = ProcessMessage::eIllegalAlignment; - break; - case BUS_ADRERR: - reason = ProcessMessage::eIllegalAddress; - break; - case BUS_OBJERR: - reason = ProcessMessage::eHardwareError; - break; - } - - return reason; -} -#endif - Status NativeProcessLinux::ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) { if (ProcessVmReadvSupported()) { // The process_vm_readv path is about 50 times faster than ptrace api. We - // want to use - // this syscall if it is supported. + // want to use this syscall if it is supported. const ::pid_t pid = GetID(); @@ -2094,12 +1933,11 @@ Status NativeProcessLinux::ResumeThread(NativeThreadLinux &thread, Log *const log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD); LLDB_LOG(log, "tid: {0}", thread.GetID()); - // Before we do the resume below, first check if we have a pending - // stop notification that is currently waiting for - // all threads to stop. This is potentially a buggy situation since - // we're ostensibly waiting for threads to stop before we send out the - // pending notification, and here we are resuming one before we send - // out the pending stop notification. + // Before we do the resume below, first check if we have a pending stop + // notification that is currently waiting for all threads to stop. This is + // potentially a buggy situation since we're ostensibly waiting for threads + // to stop before we send out the pending notification, and here we are + // resuming one before we send out the pending stop notification. if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { LLDB_LOG(log, "about to resume tid {0} per explicit request but we have a " @@ -2108,8 +1946,8 @@ Status NativeProcessLinux::ResumeThread(NativeThreadLinux &thread, thread.GetID(), m_pending_notification_tid); } - // Request a resume. We expect this to be synchronous and the system - // to reflect it is running after this completes. + // Request a resume. We expect this to be synchronous and the system to + // reflect it is running after this completes. switch (state) { case eStateRunning: { const auto resume_result = thread.Resume(signo); @@ -2138,8 +1976,8 @@ void NativeProcessLinux::StopRunningThreads(const lldb::tid_t triggering_tid) { m_pending_notification_tid = triggering_tid; - // Request a stop for all the thread stops that need to be stopped - // and are not already known to be stopped. + // Request a stop for all the thread stops that need to be stopped and are + // not already known to be stopped. for (const auto &thread : m_threads) { if (StateIsRunningState(thread->GetState())) static_cast<NativeThreadLinux *>(thread.get())->RequestStop(); @@ -2185,8 +2023,7 @@ void NativeProcessLinux::ThreadWasCreated(NativeThreadLinux &thread) { if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && StateIsRunningState(thread.GetState())) { // We will need to wait for this new thread to stop as well before firing - // the - // notification. + // the notification. thread.RequestStop(); } } @@ -2222,9 +2059,8 @@ void NativeProcessLinux::SigchldHandler() { } } -// Wrapper for ptrace to catch errors and log calls. -// Note that ptrace sets errno on error because -1 can be a valid result (i.e. -// for PTRACE_PEEK*) +// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets +// errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*) Status NativeProcessLinux::PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size, long *result) { @@ -2422,8 +2258,8 @@ Status NativeProcessLinux::StopTracingForThread(lldb::tid_t thread) { } if (iter->second->GetTraceID() == m_pt_proces_trace_id) { - // traceid maps to the whole process so we have to erase it from the - // thread group. + // traceid maps to the whole process so we have to erase it from the thread + // group. LLDB_LOG(log, "traceid maps to process"); m_pt_traced_thread_group.erase(thread); } @@ -2474,8 +2310,8 @@ Status NativeProcessLinux::StopProcessorTracingOnThread(lldb::user_id_t traceid, if (thread == LLDB_INVALID_THREAD_ID) { for (auto& iter : m_processor_trace_monitor) { if (iter.second->GetTraceID() == traceid) { - // Stopping a trace instance for an individual thread - // hence there will only be one traceid that can match. + // Stopping a trace instance for an individual thread hence there will + // only be one traceid that can match. m_processor_trace_monitor.erase(iter.first); return error; } @@ -2505,8 +2341,8 @@ Status NativeProcessLinux::StopProcessorTracingOnThread(lldb::user_id_t traceid, LLDB_LOG(log, "UID - {0} , Thread -{1}", traceid, thread); if (traceid == m_pt_proces_trace_id) { - // traceid maps to the whole process so we have to erase it from the - // thread group. + // traceid maps to the whole process so we have to erase it from the thread + // group. LLDB_LOG(log, "traceid maps to process"); m_pt_traced_thread_group.erase(thread); } diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.h b/source/Plugins/Process/Linux/NativeProcessLinux.h index f078c1ac30e2..1c2f786e8d69 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -31,10 +31,10 @@ class Scalar; namespace process_linux { /// @class NativeProcessLinux -/// @brief Manages communication with the inferior (debugee) process. +/// Manages communication with the inferior (debugee) process. /// -/// Upon construction, this class prepares and launches an inferior process for -/// debugging. +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. /// /// Changes in the inferior process state are broadcasted. class NativeProcessLinux : public NativeProcessProtocol { @@ -184,20 +184,6 @@ private: Status SetupSoftwareSingleStepping(NativeThreadLinux &thread); -#if 0 - static ::ProcessMessage::CrashReason - GetCrashReasonForSIGSEGV(const siginfo_t *info); - - static ::ProcessMessage::CrashReason - GetCrashReasonForSIGILL(const siginfo_t *info); - - static ::ProcessMessage::CrashReason - GetCrashReasonForSIGFPE(const siginfo_t *info); - - static ::ProcessMessage::CrashReason - GetCrashReasonForSIGBUS(const siginfo_t *info); -#endif - bool HasThreadNoLock(lldb::tid_t thread_id); bool StopTrackingThread(lldb::tid_t thread_id); diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp index cb05416cb6c3..749291684620 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -184,14 +184,14 @@ NativeRegisterContextLinux_arm::ReadRegister(const RegisterInfo *reg_info, error = ReadRegisterRaw(full_reg, reg_value); if (error.Success()) { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned value - // one byte to the right. + // If our read was not aligned (for ah,bh,ch,dh), shift our returned + // value one byte to the right. if (is_subreg && (reg_info->byte_offset & 0x1)) reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); // If our return byte size was greater than the return value reg size, - // then - // use the type specified by reg_info rather than the uint64_t default + // then use the type specified by reg_info rather than the uint64_t + // default if (reg_value.GetByteSize() > reg_info->byte_size) reg_value.SetType(reg_info); } @@ -558,8 +558,8 @@ uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint( uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0; lldb::addr_t real_addr = addr; - // Check if we are setting watchpoint other than read/write/access - // Also update watchpoint flag to match Arm write-read bit configuration. + // Check if we are setting watchpoint other than read/write/access Also + // update watchpoint flag to match Arm write-read bit configuration. switch (watch_flags) { case 1: watch_flags = 2; @@ -579,9 +579,9 @@ uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint( if (size == 0 || size > 4) return LLDB_INVALID_INDEX32; - // Check 4-byte alignment for hardware watchpoint target address. - // Below is a hack to recalculate address and size in order to - // make sure we can watch non 4-byte alligned addresses as well. + // Check 4-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 4-byte alligned addresses as well. if (addr & 0x03) { uint8_t watch_mask = (addr & 0x03) + size; @@ -874,12 +874,10 @@ Status NativeRegisterContextLinux_arm::DoReadRegisterValue( uint32_t offset, const char *reg_name, uint32_t size, RegisterValue &value) { // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android - // devices (always return - // "Bad address"). To avoid using PTRACE_PEEKUSER we read out the full GPR - // register set instead. - // This approach is about 4 times slower but the performance overhead is - // negligible in - // comparision to processing time in lldb-server. + // devices (always return "Bad address"). To avoid using PTRACE_PEEKUSER we + // read out the full GPR register set instead. This approach is about 4 times + // slower but the performance overhead is negligible in comparision to + // processing time in lldb-server. assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) return Status("Register isn't fit into the size of the GPR area"); @@ -895,13 +893,10 @@ Status NativeRegisterContextLinux_arm::DoReadRegisterValue( Status NativeRegisterContextLinux_arm::DoWriteRegisterValue( uint32_t offset, const char *reg_name, const RegisterValue &value) { // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android - // devices (always return - // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR - // register set, modify - // the requested register and write it back. This approach is about 4 times - // slower but the - // performance overhead is negligible in comparision to processing time in - // lldb-server. + // devices (always return "Bad address"). To avoid using PTRACE_POKEUSER we + // read out the full GPR register set, modify the requested register and + // write it back. This approach is about 4 times slower but the performance + // overhead is negligible in comparision to processing time in lldb-server. assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) return Status("Register isn't fit into the size of the GPR area"); @@ -915,9 +910,8 @@ Status NativeRegisterContextLinux_arm::DoWriteRegisterValue( // will clear thumb bit of new PC if we are already in thumb mode; that is // CPSR thumb mode bit is set. if (offset / sizeof(uint32_t) == gpr_pc_arm) { - // Check if we are already in thumb mode and - // thumb bit of current PC is read out to be zero and - // thumb bit of next PC is read out to be one. + // Check if we are already in thumb mode and thumb bit of current PC is + // read out to be zero and thumb bit of next PC is read out to be one. if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) && (value.GetAsUInt32() & 0x01)) { reg_value &= (~1ull); diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h index 40e3b80eda74..d0b068550a9e 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h @@ -42,7 +42,7 @@ public: Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; //------------------------------------------------------------------ - // Hardware breakpoints/watchpoint mangement functions + // Hardware breakpoints/watchpoint management functions //------------------------------------------------------------------ uint32_t NumSupportedHardwareBreakpoints() override; @@ -140,7 +140,7 @@ private: // occurred. lldb::addr_t real_addr; // Address value that should cause target to stop. uint32_t control; // Breakpoint/watchpoint control value. - uint32_t refcount; // Serves as enable/disable and refernce counter. + uint32_t refcount; // Serves as enable/disable and reference counter. }; struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index c483260a5b2c..41fe446f728c 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -28,8 +28,7 @@ #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" // System includes - They have to be included after framework includes because -// they define some -// macros which collide with variable names in other modules +// they define some macros which collide with variable names in other modules #include <sys/socket.h> // NT_PRSTATUS and NT_FPREGSET definition #include <elf.h> @@ -207,14 +206,14 @@ NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info, error = ReadRegisterRaw(full_reg, reg_value); if (error.Success()) { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned value - // one byte to the right. + // If our read was not aligned (for ah,bh,ch,dh), shift our returned + // value one byte to the right. if (is_subreg && (reg_info->byte_offset & 0x1)) reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); // If our return byte size was greater than the return value reg size, - // then - // use the type specified by reg_info rather than the uint64_t default + // then use the type specified by reg_info rather than the uint64_t + // default if (reg_value.GetByteSize() > reg_info->byte_size) reg_value.SetType(reg_info); } @@ -562,8 +561,8 @@ uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint( uint32_t control_value = 0, wp_index = 0; lldb::addr_t real_addr = addr; - // Check if we are setting watchpoint other than read/write/access - // Also update watchpoint flag to match AArch64 write-read bit configuration. + // Check if we are setting watchpoint other than read/write/access Also + // update watchpoint flag to match AArch64 write-read bit configuration. switch (watch_flags) { case 1: watch_flags = 2; @@ -581,9 +580,9 @@ uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint( if (size != 1 && size != 2 && size != 4 && size != 8) return LLDB_INVALID_INDEX32; - // Check 8-byte alignment for hardware watchpoint target address. - // Below is a hack to recalculate address and size in order to - // make sure we can watch non 8-byte alligned addresses as well. + // Check 8-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 8-byte alligned addresses as well. if (addr & 0x07) { uint8_t watch_mask = (addr & 0x07) + size; diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h index ab3c881ead59..c859d4249d05 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h @@ -42,7 +42,7 @@ public: Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; //------------------------------------------------------------------ - // Hardware breakpoints/watchpoint mangement functions + // Hardware breakpoints/watchpoint management functions //------------------------------------------------------------------ uint32_t NumSupportedHardwareBreakpoints() override; @@ -140,7 +140,7 @@ private: // occurred. lldb::addr_t real_addr; // Address value that should cause target to stop. uint32_t control; // Breakpoint/watchpoint control value. - uint32_t refcount; // Serves as enable/disable and refernce counter. + uint32_t refcount; // Serves as enable/disable and reference counter. }; struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp index 32c04a4374e6..69194b3c0663 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -140,9 +140,9 @@ NativeRegisterContextLinux_mips64::NativeRegisterContextLinux_mips64( break; } - // Initialize m_iovec to point to the buffer and buffer size - // using the conventions of Berkeley style UIO structures, as required - // by PTRACE extensions. + // Initialize m_iovec to point to the buffer and buffer size using the + // conventions of Berkeley style UIO structures, as required by PTRACE + // extensions. m_iovec.iov_base = &m_msa; m_iovec.iov_len = sizeof(MSA_linux_mips); @@ -337,7 +337,8 @@ lldb_private::Status NativeRegisterContextLinux_mips64::WriteRegister( uint8_t byte_size = reg_info->byte_size; lldbassert(reg_info->byte_offset < sizeof(UserArea)); - // Initialise the FP and MSA buffers by reading all co-processor 1 registers + // Initialise the FP and MSA buffers by reading all co-processor 1 + // registers ReadCP1(); if (IsFPR(reg_index)) { diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp index ea854dfa1dc6..6aa4af64ab51 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp @@ -26,8 +26,7 @@ #include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" // System includes - They have to be included after framework includes because -// they define some -// macros which collide with variable names in other modules +// they define some macros which collide with variable names in other modules #include <sys/socket.h> #include <elf.h> #include <asm/ptrace.h> @@ -50,6 +49,7 @@ static const uint32_t g_gpr_regnums_ppc64le[] = { gpr_pc_ppc64le, gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le, gpr_lr_ppc64le, gpr_xer_ppc64le, gpr_cr_ppc64le, gpr_softe_ppc64le, gpr_trap_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag }; static const uint32_t g_fpr_regnums_ppc64le[] = { @@ -62,6 +62,7 @@ static const uint32_t g_fpr_regnums_ppc64le[] = { fpr_f24_ppc64le, fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le, fpr_f28_ppc64le, fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le, fpr_fpscr_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag }; static const uint32_t g_vmx_regnums_ppc64le[] = { @@ -74,6 +75,7 @@ static const uint32_t g_vmx_regnums_ppc64le[] = { vmx_vr24_ppc64le, vmx_vr25_ppc64le, vmx_vr26_ppc64le, vmx_vr27_ppc64le, vmx_vr28_ppc64le, vmx_vr29_ppc64le, vmx_vr30_ppc64le, vmx_vr31_ppc64le, vmx_vscr_ppc64le, vmx_vrsave_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag }; static const uint32_t g_vsx_regnums_ppc64le[] = { @@ -93,6 +95,7 @@ static const uint32_t g_vsx_regnums_ppc64le[] = { vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le, vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le, vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le, + LLDB_INVALID_REGNUM // register sets need to end with this flag }; namespace { @@ -565,8 +568,8 @@ uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint( lldb::addr_t real_addr = addr; uint32_t rw_mode = 0; - // Check if we are setting watchpoint other than read/write/access - // Update watchpoint flag to match ppc64le write-read bit configuration. + // Check if we are setting watchpoint other than read/write/access Update + // watchpoint flag to match ppc64le write-read bit configuration. switch (watch_flags) { case eWatchpointKindWrite: rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE; @@ -587,9 +590,9 @@ uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint( if (size != 1 && size != 2 && size != 4 && size != 8) return LLDB_INVALID_INDEX32; - // Check 8-byte alignment for hardware watchpoint target address. - // Below is a hack to recalculate address and size in order to - // make sure we can watch non 8-byte alligned addresses as well. + // Check 8-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 8-byte alligned addresses as well. if (addr & 0x07) { addr_t begin = llvm::alignDown(addr, 8); diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h index bb25af80d02c..2c4471962ad0 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h @@ -19,7 +19,7 @@ #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" #define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT -#include "RegisterInfos_ppc64le.h" +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" #undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT namespace lldb_private { @@ -49,7 +49,7 @@ public: Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; //------------------------------------------------------------------ - // Hardware watchpoint mangement functions + // Hardware watchpoint management functions //------------------------------------------------------------------ uint32_t NumSupportedHardwareWatchpoints() override; diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp index 021394ab154b..36da2b001054 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp @@ -10,7 +10,7 @@ #if defined(__s390x__) && defined(__linux__) #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" @@ -372,10 +372,10 @@ Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues( DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4); dst += 4; - // To enable inferior function calls while the process is stopped in - // an interrupted system call, we need to clear the system call flag. - // It will be restored to its original value by WriteAllRegisterValues. - // Again we ignore error if the regset is unsupported. + // To enable inferior function calls while the process is stopped in an + // interrupted system call, we need to clear the system call flag. It will be + // restored to its original value by WriteAllRegisterValues. Again we ignore + // error if the regset is unsupported. uint32_t system_call = 0; DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp index 84ffe9b6e420..87f4b8da053e 100755 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -329,9 +329,9 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64( break; } - // Initialize m_iovec to point to the buffer and buffer size - // using the conventions of Berkeley style UIO structures, as required - // by PTRACE extensions. + // Initialize m_iovec to point to the buffer and buffer size using the + // conventions of Berkeley style UIO structures, as required by PTRACE + // extensions. m_iovec.iov_base = &m_fpr; m_iovec.iov_len = sizeof(m_fpr); @@ -420,14 +420,14 @@ NativeRegisterContextLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, error = ReadRegisterRaw(full_reg, reg_value); if (error.Success()) { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned value - // one byte to the right. + // If our read was not aligned (for ah,bh,ch,dh), shift our returned + // value one byte to the right. if (is_subreg && (reg_info->byte_offset & 0x1)) reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); // If our return byte size was greater than the return value reg size, - // then - // use the type specified by reg_info rather than the uint64_t default + // then use the type specified by reg_info rather than the uint64_t + // default if (reg_value.GetByteSize() > reg_info->byte_size) reg_value.SetType(reg_info); } @@ -448,7 +448,8 @@ NativeRegisterContextLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, reg_value.SetBytes(m_fpr.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order); if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) { - // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes + // Concatenate ymm using the register halves in xmm.bytes and + // ymmh.bytes if (CopyXSTATEtoYMM(reg, byte_order)) reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order); @@ -492,8 +493,7 @@ NativeRegisterContextLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, // Byte offsets of all registers are calculated wrt 'UserArea' structure. // However, ReadFPR() reads fpu registers {using ptrace(PTRACE_GETFPREGS,..)} // and stores them in 'm_fpr' (of type FPR structure). To extract values of - // fpu - // registers, m_fpr should be read at byte offsets calculated wrt to FPR + // fpu registers, m_fpr should be read at byte offsets calculated wrt to FPR // structure. // Since, FPR structure is also one of the member of UserArea structure. @@ -599,11 +599,10 @@ Status NativeRegisterContextLinux_x86_64::WriteRegister( // Get pointer to m_fpr.fxsave variable and set the data to it. // Byte offsets of all registers are calculated wrt 'UserArea' structure. - // However, WriteFPR() takes m_fpr (of type FPR structure) and writes only - // fpu - // registers using ptrace(PTRACE_SETFPREGS,..) API. Hence fpu registers - // should - // be written in m_fpr at byte offsets calculated wrt FPR structure. + // However, WriteFPR() takes m_fpr (of type FPR structure) and writes + // only fpu registers using ptrace(PTRACE_SETFPREGS,..) API. Hence fpu + // registers should be written in m_fpr at byte offsets calculated wrt + // FPR structure. // Since, FPR structure is also one of the member of UserArea structure. // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - @@ -1093,8 +1092,7 @@ Status NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex( if (error.Fail()) return error; - // for watchpoints 0, 1, 2, or 3, respectively, - // set bits 1, 3, 5, or 7 + // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 uint64_t enable_bit = 1 << (2 * wp_index); // set bits 16-17, 20-21, 24-25, or 28-29 @@ -1132,8 +1130,8 @@ bool NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint( RegisterValue reg_value; - // for watchpoints 0, 1, 2, or 3, respectively, - // clear bits 0, 1, 2, or 3 of the debug status register (DR6) + // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of + // the debug status register (DR6) Status error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value); if (error.Fail()) return false; @@ -1143,9 +1141,9 @@ bool NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint( if (error.Fail()) return false; - // for watchpoints 0, 1, 2, or 3, respectively, - // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} - // of the debug control register (DR7) + // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, + // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register + // (DR7) error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); if (error.Fail()) return false; diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/source/Plugins/Process/Linux/NativeThreadLinux.cpp index 0db3bd56b8e4..4ab2a9ae6245 100644 --- a/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ b/source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -211,8 +211,8 @@ Status NativeThreadLinux::Resume(uint32_t signo) { m_stop_info.reason = StopReason::eStopReasonNone; m_stop_description.clear(); - // If watchpoints have been set, but none on this thread, - // then this is a new thread. So set all existing watchpoints. + // If watchpoints have been set, but none on this thread, then this is a new + // thread. So set all existing watchpoints. if (m_watchpoint_index_map.empty()) { NativeProcessLinux &process = GetProcess(); @@ -263,8 +263,8 @@ Status NativeThreadLinux::SingleStep(uint32_t signo) { data = signo; // If hardware single-stepping is not supported, we just do a continue. The - // breakpoint on the - // next instruction has been setup in NativeProcessLinux::Resume. + // breakpoint on the next instruction has been setup in + // NativeProcessLinux::Resume. return NativeProcessLinux::PtraceWrapper( GetProcess().SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT, diff --git a/source/Plugins/Process/Linux/ProcessorTrace.h b/source/Plugins/Process/Linux/ProcessorTrace.h index 6603c7d60478..6fd918c2bb58 100644 --- a/source/Plugins/Process/Linux/ProcessorTrace.h +++ b/source/Plugins/Process/Linux/ProcessorTrace.h @@ -34,7 +34,7 @@ namespace process_linux { // a key to the tracing instance and trace manipulations could be // performed using the trace id. // -// The traace id could map to trace instances for a group of threads +// The trace id could map to trace instances for a group of threads // (spanning to all the threads in the process) or a single thread. // The kernel interface for us is the perf_event_open. // --------------------------------------------------------------------- diff --git a/source/Plugins/Process/Linux/SingleStepCheck.cpp b/source/Plugins/Process/Linux/SingleStepCheck.cpp index 251cb4b2f10a..c57a2daf2275 100644 --- a/source/Plugins/Process/Linux/SingleStepCheck.cpp +++ b/source/Plugins/Process/Linux/SingleStepCheck.cpp @@ -59,9 +59,9 @@ struct ChildDeleter { bool WorkaroundNeeded() { // We shall spawn a child, and use it to verify the debug capabilities of the - // cpu. We shall iterate through the cpus, bind the child to each one in turn, - // and verify that single-stepping works on that cpu. A workaround is needed - // if we find at least one broken cpu. + // cpu. We shall iterate through the cpus, bind the child to each one in + // turn, and verify that single-stepping works on that cpu. A workaround is + // needed if we find at least one broken cpu. Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD); ::pid_t child_pid = fork(); diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp index 3d9f498b1e9a..116155d9a232 100644 --- a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp @@ -59,15 +59,6 @@ bool CommunicationKDP::SendRequestPacket( return SendRequestPacketNoLock(request_packet); } -#if 0 -typedef struct { - uint8_t request; // Either: CommandType | ePacketTypeRequest, or CommandType | ePacketTypeReply - uint8_t sequence; - uint16_t length; // Length of entire packet including this header - uint32_t key; // Session key -} kdp_hdr_t; -#endif - void CommunicationKDP::MakeRequestPacketHeader(CommandType request_type, PacketStreamType &request_packet, uint16_t request_length) { @@ -127,16 +118,14 @@ bool CommunicationKDP::SendRequestAndGetReply( } } else if (reply_sequence_id > request_sequence_id) { // Sequence ID was greater than the sequence ID of the packet we - // sent, something - // is really wrong... + // sent, something is really wrong... reply_packet.Clear(); return false; } else { - // The reply sequence ID was less than our current packet's sequence - // ID - // so we should keep trying to get a response because this was a - // response - // for a previous packet that we must have retried. + // The reply sequence ID was less than our current packet's + // sequence ID so we should keep trying to get a response because + // this was a response for a previous packet that we must have + // retried. } } else { // Break and retry sending the packet as we didn't get a response due @@ -186,7 +175,7 @@ bool CommunicationKDP::GetSequenceMutex( bool CommunicationKDP::WaitForNotRunningPrivate( const std::chrono::microseconds &timeout) { - return m_is_running.WaitForValueEqualTo(false, timeout, NULL); + return m_is_running.WaitForValueEqualTo(false, timeout); } size_t @@ -324,9 +313,9 @@ bool CommunicationKDP::CheckForPacket(const uint8_t *src, size_t src_len, offset = 2; const uint16_t length = packet.GetU16(&offset); if (length <= bytes_available) { - // We have an entire packet ready, we need to copy the data - // bytes into a buffer that will be owned by the packet and - // erase the bytes from our communcation buffer "m_bytes" + // We have an entire packet ready, we need to copy the data bytes into + // a buffer that will be owned by the packet and erase the bytes from + // our communcation buffer "m_bytes" packet.SetData(DataBufferSP(new DataBufferHeap(&m_bytes[0], length))); m_bytes.erase(0, length); @@ -341,8 +330,8 @@ bool CommunicationKDP::CheckForPacket(const uint8_t *src, size_t src_len, } break; default: - // Unrecognized reply command byte, erase this byte and try to get back on - // track + // Unrecognized reply command byte, erase this byte and try to get back + // on track if (log) log->Printf("CommunicationKDP::%s: tossing junk byte: 0x%2.2x", __FUNCTION__, (uint8_t)m_bytes[0]); @@ -436,34 +425,6 @@ bool CommunicationKDP::SendRequestVersion() { return false; } -#if 0 // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection... -const char * -CommunicationKDP::GetImagePath () -{ - if (m_image_path.empty()) - SendRequestImagePath(); - return m_image_path.c_str(); -} - -bool -CommunicationKDP::SendRequestImagePath () -{ - PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); - const CommandType command = KDP_IMAGEPATH; - const uint32_t command_length = 8; - MakeRequestPacketHeader (command, request_packet, command_length); - DataExtractor reply_packet; - if (SendRequestAndGetReply (command, request_packet, reply_packet)) - { - const char *path = reply_packet.PeekCStr(8); - if (path && path[0]) - m_kernel_version.assign (path); - return true; - } - return false; -} -#endif - uint32_t CommunicationKDP::GetCPUMask() { if (!HostInfoIsValid()) SendRequestHostInfo(); @@ -495,7 +456,7 @@ lldb_private::UUID CommunicationKDP::GetUUID() { if (uuid_str.size() < 32) return uuid; - if (uuid.SetFromCString(uuid_str.c_str()) == 0) { + if (uuid.SetFromStringRef(uuid_str) == 0) { UUID invalid_uuid; return invalid_uuid; } @@ -1245,8 +1206,8 @@ uint32_t CommunicationKDP::SendRequestReadRegisters(uint32_t cpu, if (src) { ::memcpy(dst, src, bytes_to_copy); error.Clear(); - // Return the number of bytes we could have returned regardless if - // we copied them or not, just so we know when things don't match up + // Return the number of bytes we could have returned regardless if we + // copied them or not, just so we know when things don't match up return src_len; } } diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp index f01f1ace583c..2e707ab2e363 100644 --- a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -172,10 +172,10 @@ ProcessKDP::ProcessKDP(TargetSP target_sp, ListenerSP listener_sp) //---------------------------------------------------------------------- ProcessKDP::~ProcessKDP() { Clear(); - // We need to call finalize on the process before destroying ourselves - // to make sure all of the broadcaster cleanup goes as planned. If we - // destruct this class, then Process::~Process() might have problems - // trying to fully destroy the broadcaster. + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. Finalize(); } @@ -226,9 +226,9 @@ bool ProcessKDP::GetHostArchitecture(ArchSpec &arch) { Status ProcessKDP::DoConnectRemote(Stream *strm, llvm::StringRef remote_url) { Status error; - // Don't let any JIT happen when doing KDP as we can't allocate - // memory and we don't want to be mucking with threads that might - // already be handling exceptions + // Don't let any JIT happen when doing KDP as we can't allocate memory and we + // don't want to be mucking with threads that might already be handling + // exceptions SetCanJIT(false); if (remote_url.empty()) { @@ -282,16 +282,15 @@ Status ProcessKDP::DoConnectRemote(Stream *strm, llvm::StringRef remote_url) { if (m_comm.RemoteIsEFI()) { // Select an invalid plugin name for the dynamic loader so one - // doesn't get used - // since EFI does its own manual loading via python scripting + // doesn't get used since EFI does its own manual loading via + // python scripting static ConstString g_none_dynamic_loader("none"); m_dyld_plugin_name = g_none_dynamic_loader; if (kernel_uuid.IsValid()) { - // If EFI passed in a UUID= try to lookup UUID - // The slide will not be provided. But the UUID - // lookup will be used to launch EFI debug scripts - // from the dSYM, that can load all of the symbols. + // If EFI passed in a UUID= try to lookup UUID The slide will not + // be provided. But the UUID lookup will be used to launch EFI + // debug scripts from the dSYM, that can load all of the symbols. ModuleSpec module_spec; module_spec.GetUUID() = kernel_uuid; module_spec.GetArchitecture() = target.GetArchitecture(); @@ -386,7 +385,7 @@ ProcessKDP::DoAttachToProcessWithID(lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) { Status error; error.SetErrorString( - "attach to process by ID is not suppported in kdp remote debugging"); + "attach to process by ID is not supported in kdp remote debugging"); return error; } @@ -395,7 +394,7 @@ ProcessKDP::DoAttachToProcessWithName(const char *process_name, const ProcessAttachInfo &attach_info) { Status error; error.SetErrorString( - "attach to process by name is not suppported in kdp remote debugging"); + "attach to process by name is not supported in kdp remote debugging"); return error; } @@ -443,8 +442,8 @@ Status ProcessKDP::DoResume() { StateAsCString(thread_resume_state)); switch (thread_resume_state) { case eStateSuspended: - // Nothing to do here when a thread will stay suspended - // we just leave the CPU mask bit set to zero for the thread + // Nothing to do here when a thread will stay suspended we just leave the + // CPU mask bit set to zero for the thread if (log) log->Printf("ProcessKDP::DoResume() = suspended???"); break; @@ -535,8 +534,8 @@ bool ProcessKDP::UpdateThreadList(ThreadList &old_thread_list, } void ProcessKDP::RefreshStateAfterStop() { - // Let all threads recover from stopping and do any clean up based - // on the previous thread state (if any). + // Let all threads recover from stopping and do any clean up based on the + // previous thread state (if any). m_thread_list.RefreshStateAfterStop(); } @@ -545,9 +544,9 @@ Status ProcessKDP::DoHalt(bool &caused_stop) { if (m_comm.IsRunning()) { if (m_destroy_in_process) { - // If we are attemping to destroy, we need to not return an error to - // Halt or DoDestroy won't get called. - // We are also currently running, so send a process stopped event + // If we are attempting to destroy, we need to not return an error to Halt + // or DoDestroy won't get called. We are also currently running, so send + // a process stopped event SetPrivateState(eStateStopped); } else { error.SetErrorString("KDP cannot interrupt a running kernel"); @@ -563,8 +562,8 @@ Status ProcessKDP::DoDetach(bool keep_stopped) { log->Printf("ProcessKDP::DoDetach(keep_stopped = %i)", keep_stopped); if (m_comm.IsRunning()) { - // We are running and we can't interrupt a running kernel, so we need - // to just close the connection to the kernel and hope for the best + // We are running and we can't interrupt a running kernel, so we need to + // just close the connection to the kernel and hope for the best } else { // If we are going to keep the target stopped, then don't send the // disconnect message. @@ -647,14 +646,14 @@ size_t ProcessKDP::DoWriteMemory(addr_t addr, const void *buf, size_t size, lldb::addr_t ProcessKDP::DoAllocateMemory(size_t size, uint32_t permissions, Status &error) { error.SetErrorString( - "memory allocation not suppported in kdp remote debugging"); + "memory allocation not supported in kdp remote debugging"); return LLDB_INVALID_ADDRESS; } Status ProcessKDP::DoDeallocateMemory(lldb::addr_t addr) { Status error; error.SetErrorString( - "memory deallocation not suppported in kdp remote debugging"); + "memory deallocation not supported in kdp remote debugging"); return error; } @@ -701,14 +700,14 @@ Status ProcessKDP::DisableBreakpointSite(BreakpointSite *bp_site) { Status ProcessKDP::EnableWatchpoint(Watchpoint *wp, bool notify) { Status error; error.SetErrorString( - "watchpoints are not suppported in kdp remote debugging"); + "watchpoints are not supported in kdp remote debugging"); return error; } Status ProcessKDP::DisableWatchpoint(Watchpoint *wp, bool notify) { Status error; error.SetErrorString( - "watchpoints are not suppported in kdp remote debugging"); + "watchpoints are not supported in kdp remote debugging"); return error; } @@ -717,7 +716,7 @@ void ProcessKDP::Clear() { m_thread_list.Clear(); } Status ProcessKDP::DoSignal(int signo) { Status error; error.SetErrorString( - "sending signals is not suppported in kdp remote debugging"); + "sending signals is not supported in kdp remote debugging"); return error; } diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp index 1902cc492ff4..7fca0fc24fdb 100644 --- a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp @@ -52,11 +52,11 @@ ThreadKDP::~ThreadKDP() { const char *ThreadKDP::GetName() { if (m_thread_name.empty()) - return NULL; + return nullptr; return m_thread_name.c_str(); } -const char *ThreadKDP::GetQueueName() { return NULL; } +const char *ThreadKDP::GetQueueName() { return nullptr; } void ThreadKDP::RefreshStateAfterStop() { // Invalidate all registers in our register context. We don't set "force" to @@ -65,8 +65,8 @@ void ThreadKDP::RefreshStateAfterStop() { // context by the time this function gets called. The KDPRegisterContext // class has been made smart enough to detect when it needs to invalidate // which registers are valid by putting hooks in the register read and - // register supply functions where they check the process stop ID and do - // the right thing. + // register supply functions where they check the process stop ID and do the + // right thing. const bool force = false; lldb::RegisterContextSP reg_ctx_sp(GetRegisterContext()); if (reg_ctx_sp) @@ -79,8 +79,8 @@ void ThreadKDP::Dump(Log *log, uint32_t index) {} bool ThreadKDP::ShouldStop(bool &step_more) { return true; } lldb::RegisterContextSP ThreadKDP::GetRegisterContext() { - if (m_reg_context_sp.get() == NULL) - m_reg_context_sp = CreateRegisterContextForFrame(NULL); + if (!m_reg_context_sp) + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); return m_reg_context_sp; } @@ -119,7 +119,7 @@ ThreadKDP::CreateRegisterContextForFrame(StackFrame *frame) { } } else { Unwind *unwinder = GetUnwinder(); - if (unwinder) + if (unwinder != nullptr) reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); } return reg_ctx_sp; @@ -151,8 +151,8 @@ void ThreadKDP::SetStopInfoFrom_KDP_EXCEPTION( const uint32_t exc_type = exc_reply_packet.GetU32(&offset); const uint32_t exc_code = exc_reply_packet.GetU32(&offset); const uint32_t exc_subcode = exc_reply_packet.GetU32(&offset); - // We have to make a copy of the stop info because the thread list - // will iterate through the threads and clear all stop infos.. + // We have to make a copy of the stop info because the thread list will + // iterate through the threads and clear all stop infos.. // Let the StopInfoMachException::CreateStopReasonWithMachException() // function update the PC if needed as we might hit a software breakpoint diff --git a/source/Plugins/Process/NetBSD/CMakeLists.txt b/source/Plugins/Process/NetBSD/CMakeLists.txt index 5b2cef8b847b..92a6014ced07 100644 --- a/source/Plugins/Process/NetBSD/CMakeLists.txt +++ b/source/Plugins/Process/NetBSD/CMakeLists.txt @@ -1,7 +1,3 @@ -include_directories(.) -include_directories(../POSIX) -include_directories(../Utility) - add_lldb_library(lldbPluginProcessNetBSD PLUGIN NativeProcessNetBSD.cpp NativeRegisterContextNetBSD.cpp diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index 387f04afa5b4..1a4cb21d000e 100644 --- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -24,8 +24,7 @@ #include "llvm/Support/Errno.h" // System includes - They have to be included after framework includes because -// they define some -// macros which collide with variable names in other modules +// they define some macros which collide with variable names in other modules // clang-format off #include <sys/types.h> #include <sys/ptrace.h> @@ -93,17 +92,19 @@ NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, } LLDB_LOG(log, "inferior started, now in stopped state"); - ArchSpec arch; - if ((status = ResolveProcessArchitecture(pid, arch)).Fail()) - return status.ToError(); + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error<StringError>("Cannot get process architecture", + llvm::inconvertibleErrorCode()); + } // Set the architecture to the exe architecture. LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, - arch.GetArchitectureName()); + Info.GetArchitecture().GetArchitectureName()); std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD( pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, - arch, mainloop)); + Info.GetArchitecture(), mainloop)); status = process_up->ReinitializeThreads(); if (status.Fail()) @@ -111,7 +112,7 @@ NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, for (const auto &thread : process_up->m_threads) static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP); - process_up->SetState(StateType::eStateStopped); + process_up->SetState(StateType::eStateStopped, false); return std::move(process_up); } @@ -124,15 +125,16 @@ NativeProcessNetBSD::Factory::Attach( LLDB_LOG(log, "pid = {0:x}", pid); // Retrieve the architecture for the running process. - ArchSpec arch; - Status status = ResolveProcessArchitecture(pid, arch); - if (!status.Success()) - return status.ToError(); + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error<StringError>("Cannot get process architecture", + llvm::inconvertibleErrorCode()); + } - std::unique_ptr<NativeProcessNetBSD> process_up( - new NativeProcessNetBSD(pid, -1, native_delegate, arch, mainloop)); + std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD( + pid, -1, native_delegate, Info.GetArchitecture(), mainloop)); - status = process_up->Attach(); + Status status = process_up->Attach(); if (!status.Success()) return status.ToError(); @@ -349,8 +351,8 @@ NativeProcessNetBSD::FixupBreakpointPCAsNeeded(NativeThreadNetBSD &thread) { 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. + // 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; @@ -559,8 +561,8 @@ Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr, "descending memory map entries detected, unexpected"); prev_base_address = proc_entry_info.GetRange().GetRangeBase(); UNUSED_IF_ASSERT_DISABLED(prev_base_address); - // If the target address comes before this entry, indicate distance to - // next region. + // If the target address comes before this entry, indicate distance to next + // region. if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { range_info.GetRange().SetRangeBase(load_addr); range_info.GetRange().SetByteSize( @@ -579,9 +581,8 @@ Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr, // parsed. } // If we made it here, we didn't find an entry that contained the given - // address. Return the - // load_addr as start and the amount of bytes betwwen load address and the - // end of the memory as size. + // address. Return the load_addr as start and the amount of bytes betwwen + // load address and the end of the memory as size. range_info.GetRange().SetRangeBase(load_addr); range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); @@ -641,8 +642,8 @@ Status NativeProcessNetBSD::PopulateMemoryRegionCache() { free(vm); if (m_mem_region_cache.empty()) { - // No entries after attempting to read them. This shouldn't happen. - // Assume we don't support map entries. + // No entries after attempting to read them. This shouldn't happen. Assume + // we don't support map entries. LLDB_LOG(log, "failed to find any vmmap entries, assuming no support " "for memory region metadata retrieval"); m_supports_mem_region = LazyBool::eLazyBoolNo; @@ -778,8 +779,8 @@ Status NativeProcessNetBSD::Attach() { return status; int wstatus; - // Need to use WALLSIG otherwise we receive an error with errno=ECHLD - // At this point we should have a thread stopped if waitpid succeeds. + // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this + // point we should have a thread stopped if waitpid succeeds. if ((wstatus = waitpid(m_pid, NULL, WALLSIG)) < 0) return Status(errno, eErrorTypePOSIX); @@ -871,13 +872,13 @@ NativeProcessNetBSD::GetAuxvData() const { */ size_t auxv_size = 100 * sizeof(AuxInfo); - ErrorOr<std::unique_ptr<MemoryBuffer>> buf = - llvm::MemoryBuffer::getNewMemBuffer(auxv_size); + ErrorOr<std::unique_ptr<WritableMemoryBuffer>> buf = + llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size); struct ptrace_io_desc io; io.piod_op = PIOD_READ_AUXV; io.piod_offs = 0; - io.piod_addr = const_cast<void *>(static_cast<const void *>(buf.get()->getBufferStart())); + io.piod_addr = static_cast<void *>(buf.get()->getBufferStart()); io.piod_len = auxv_size; Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io); @@ -888,7 +889,7 @@ NativeProcessNetBSD::GetAuxvData() const { if (io.piod_len < 1) return std::error_code(ECANCELED, std::generic_category()); - return buf; + return std::move(buf); } Status NativeProcessNetBSD::ReinitializeThreads() { diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h index 7090fce34fc9..142f74ecf194 100644 --- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h +++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h @@ -20,10 +20,10 @@ namespace lldb_private { namespace process_netbsd { /// @class NativeProcessNetBSD -/// @brief Manages communication with the inferior (debugee) process. +/// Manages communication with the inferior (debugee) process. /// -/// Upon construction, this class prepares and launches an inferior process for -/// debugging. +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. /// /// Changes in the inferior process state are broadcasted. class NativeProcessNetBSD : public NativeProcessProtocol { diff --git a/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp index 347c15ae5b23..16b6f2c52dd5 100644 --- a/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp +++ b/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp @@ -161,8 +161,8 @@ static RegisterInfoInterface * CreateRegisterInfoInterface(const ArchSpec &target_arch) { assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); - // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the - // x86_64 register context. + // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 + // register context. return new RegisterContextNetBSD_x86_64(target_arch); } @@ -805,8 +805,7 @@ Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( if (error.Fail()) return error; - // for watchpoints 0, 1, 2, or 3, respectively, - // set bits 1, 3, 5, or 7 + // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 uint64_t enable_bit = 1 << (2 * wp_index); // set bits 16-17, 20-21, 24-25, or 28-29 @@ -845,8 +844,8 @@ bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint( RegisterValue reg_value; - // for watchpoints 0, 1, 2, or 3, respectively, - // clear bits 0, 1, 2, or 3 of the debug status register (DR6) + // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of + // the debug status register (DR6) const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(lldb_dr6_x86_64); Status error = ReadRegister(reg_info_dr6, reg_value); @@ -858,9 +857,9 @@ bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint( if (error.Fail()) return false; - // for watchpoints 0, 1, 2, or 3, respectively, - // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} - // of the debug control register (DR7) + // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, + // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register + // (DR7) const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(lldb_dr7_x86_64); error = ReadRegister(reg_info_dr7, reg_value); diff --git a/source/Plugins/Process/POSIX/CMakeLists.txt b/source/Plugins/Process/POSIX/CMakeLists.txt index d9a4508df0a3..f058e01c7439 100644 --- a/source/Plugins/Process/POSIX/CMakeLists.txt +++ b/source/Plugins/Process/POSIX/CMakeLists.txt @@ -1,6 +1,3 @@ -include_directories(.) -include_directories(../Utility) - add_lldb_library(lldbPluginProcessPOSIX PLUGIN CrashReason.cpp ProcessMessage.cpp diff --git a/source/Plugins/Process/POSIX/CrashReason.cpp b/source/Plugins/Process/POSIX/CrashReason.cpp index 864418c90031..4b24d31226a9 100644 --- a/source/Plugins/Process/POSIX/CrashReason.cpp +++ b/source/Plugins/Process/POSIX/CrashReason.cpp @@ -47,8 +47,7 @@ CrashReason GetCrashReasonForSIGSEGV(const siginfo_t &info) { #ifdef SI_KERNEL case SI_KERNEL: // Some platforms will occasionally send nonstandard spurious SI_KERNEL - // codes. - // One way to get this is via unaligned SIMD loads. + // codes. One way to get this is via unaligned SIMD loads. return CrashReason::eInvalidAddress; // for lack of anything better #endif case SEGV_MAPERR: diff --git a/source/Plugins/Process/Utility/CMakeLists.txt b/source/Plugins/Process/Utility/CMakeLists.txt index 3780fb5e4c18..b43756acea63 100644 --- a/source/Plugins/Process/Utility/CMakeLists.txt +++ b/source/Plugins/Process/Utility/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(../../../Utility/) - add_lldb_library(lldbPluginProcessUtility PLUGIN DynamicRegisterInfo.cpp FreeBSDSignals.cpp @@ -60,7 +58,6 @@ add_lldb_library(lldbPluginProcessUtility PLUGIN lldbSymbol lldbTarget lldbUtility - lldbPluginProcessElfCore LINK_COMPONENTS Support ) diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index 61e5bf4481d6..5f34e9915ede 100644 --- a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -12,6 +12,7 @@ #include "lldb/Core/StreamFile.h" #include "lldb/DataFormatters/FormatManager.h" #include "lldb/Host/StringConvert.h" +#include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/StringExtractor.h" @@ -20,21 +21,42 @@ using namespace lldb; using namespace lldb_private; -DynamicRegisterInfo::DynamicRegisterInfo() - : m_regs(), m_sets(), m_set_reg_nums(), m_set_names(), m_value_regs_map(), - m_invalidate_regs_map(), m_dynamic_reg_size_map(), - m_reg_data_byte_size(0), m_finalized(false) {} - DynamicRegisterInfo::DynamicRegisterInfo( const lldb_private::StructuredData::Dictionary &dict, - const lldb_private::ArchSpec &arch) - : m_regs(), m_sets(), m_set_reg_nums(), m_set_names(), m_value_regs_map(), - m_invalidate_regs_map(), m_dynamic_reg_size_map(), - m_reg_data_byte_size(0), m_finalized(false) { + const lldb_private::ArchSpec &arch) { SetRegisterInfo(dict, arch); } -DynamicRegisterInfo::~DynamicRegisterInfo() {} +DynamicRegisterInfo::DynamicRegisterInfo(DynamicRegisterInfo &&info) { + MoveFrom(std::move(info)); +} + +DynamicRegisterInfo & +DynamicRegisterInfo::operator=(DynamicRegisterInfo &&info) { + MoveFrom(std::move(info)); + return *this; +} + +void DynamicRegisterInfo::MoveFrom(DynamicRegisterInfo &&info) { + m_regs = std::move(info.m_regs); + m_sets = std::move(info.m_sets); + m_set_reg_nums = std::move(info.m_set_reg_nums); + m_set_names = std::move(info.m_set_names); + m_value_regs_map = std::move(info.m_value_regs_map); + m_invalidate_regs_map = std::move(info.m_invalidate_regs_map); + m_dynamic_reg_size_map = std::move(info.m_dynamic_reg_size_map); + + m_reg_data_byte_size = info.m_reg_data_byte_size; + m_finalized = info.m_finalized; + + if (m_finalized) { + const size_t num_sets = m_sets.size(); + for (size_t set = 0; set < num_sets; ++set) + m_sets[set].registers = m_set_reg_nums[set].data(); + } + + info.Clear(); +} size_t DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, @@ -44,13 +66,9 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, if (dict.GetValueForKeyAsArray("sets", sets)) { const uint32_t num_sets = sets->GetSize(); for (uint32_t i = 0; i < num_sets; ++i) { - llvm::StringRef set_name_str; ConstString set_name; - if (sets->GetItemAtIndexAsString(i, set_name_str)) - set_name.SetString(set_name_str); - if (set_name) { - RegisterSet new_set = {set_name.AsCString(), NULL, 0, NULL}; - m_sets.push_back(new_set); + if (sets->GetItemAtIndexAsString(i, set_name) && !set_name.IsEmpty()) { + m_sets.push_back({ set_name.AsCString(), NULL, 0, NULL }); } else { Clear(); printf("error: register sets must have valid names\n"); @@ -59,6 +77,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, } m_set_reg_nums.resize(m_sets.size()); } + StructuredData::Array *regs = nullptr; if (!dict.GetValueForKeyAsArray("registers", regs)) return 0; @@ -76,8 +95,8 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, return 0; } - // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' - // , 'format':'hex' , 'set': 0, 'ehframe' : 2, + // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, + // 'encoding':'uint' , 'format':'hex' , 'set': 0, 'ehframe' : 2, // 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', }, RegisterInfo reg_info; std::vector<uint32_t> value_regs; @@ -102,14 +121,11 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, const ByteOrder byte_order = arch.GetByteOrder(); if (reg_info.byte_offset == UINT32_MAX) { - // No offset for this register, see if the register has a value expression - // which indicates this register is part of another register. Value - // expressions - // are things like "rax[31:0]" which state that the current register's - // value - // is in a concrete register "rax" in bits 31:0. If there is a value - // expression - // we can calculate the offset + // No offset for this register, see if the register has a value + // expression which indicates this register is part of another register. + // Value expressions are things like "rax[31:0]" which state that the + // current register's value is in a concrete register "rax" in bits 31:0. + // If there is a value expression we can calculate the offset bool success = false; llvm::StringRef slice_str; if (reg_info_dict->GetValueForKeyAsString("slice", slice_str, nullptr)) { @@ -141,7 +157,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, ConstString containing_reg_name(reg_name_str); - RegisterInfo *containing_reg_info = + const RegisterInfo *containing_reg_info = GetRegisterInfo(containing_reg_name); if (containing_reg_info) { const uint32_t max_bit = containing_reg_info->byte_size * 8; @@ -210,7 +226,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, ConstString composite_reg_name; if (composite_reg_list->GetItemAtIndexAsString( composite_idx, composite_reg_name, nullptr)) { - RegisterInfo *composite_reg_info = + const RegisterInfo *composite_reg_info = GetRegisterInfo(composite_reg_name); if (composite_reg_info) { composite_offset = std::min(composite_offset, @@ -286,7 +302,8 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, llvm::StringRef format_str; if (reg_info_dict->GetValueForKeyAsString("format", format_str, nullptr)) { - if (Args::StringToFormat(format_str.str().c_str(), reg_info.format, NULL) + if (OptionArgParser::ToFormat(format_str.str().c_str(), reg_info.format, + NULL) .Fail()) { Clear(); printf("error: invalid 'format' value in register dictionary\n"); @@ -349,7 +366,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, uint64_t invalidate_reg_num; if (invalidate_reg_list->GetItemAtIndexAsString( idx, invalidate_reg_name)) { - RegisterInfo *invalidate_reg_info = + const RegisterInfo *invalidate_reg_info = GetRegisterInfo(invalidate_reg_name); if (invalidate_reg_info) { m_invalidate_regs_map[i].push_back( @@ -437,7 +454,7 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { for (size_t set = 0; set < num_sets; ++set) { assert(m_sets.size() == m_set_reg_nums.size()); m_sets[set].num_registers = m_set_reg_nums[set].size(); - m_sets[set].registers = &m_set_reg_nums[set][0]; + m_sets[set].registers = m_set_reg_nums[set].data(); } // sort and unique all value registers and make sure each is terminated with @@ -492,8 +509,7 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { } // sort and unique all invalidate registers and make sure each is terminated - // with - // LLDB_INVALID_REGNUM + // with LLDB_INVALID_REGNUM for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(), end = m_invalidate_regs_map.end(); pos != end; ++pos) { @@ -517,8 +533,8 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { m_regs[i].invalidate_regs = NULL; } - // Check if we need to automatically set the generic registers in case - // they weren't set + // Check if we need to automatically set the generic registers in case they + // weren't set bool generic_regs_specified = false; for (const auto ® : m_regs) { if (reg.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) { @@ -730,11 +746,11 @@ void DynamicRegisterInfo::Dump() const { } } -lldb_private::RegisterInfo *DynamicRegisterInfo::GetRegisterInfo( - const lldb_private::ConstString ®_name) { +const lldb_private::RegisterInfo *DynamicRegisterInfo::GetRegisterInfo( + const lldb_private::ConstString ®_name) const { for (auto ®_info : m_regs) { - // We can use pointer comparison since we used a ConstString to set - // the "name" member in AddRegister() + // We can use pointer comparison since we used a ConstString to set the + // "name" member in AddRegister() if (reg_info.name == reg_name.GetCString()) { return ®_info; } diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/source/Plugins/Process/Utility/DynamicRegisterInfo.h index 228acfbed4ee..acb3e3eb8a84 100644 --- a/source/Plugins/Process/Utility/DynamicRegisterInfo.h +++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.h @@ -23,12 +23,18 @@ class DynamicRegisterInfo { public: - DynamicRegisterInfo(); + DynamicRegisterInfo() = default; DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict, const lldb_private::ArchSpec &arch); - virtual ~DynamicRegisterInfo(); + virtual ~DynamicRegisterInfo() = default; + + DynamicRegisterInfo(DynamicRegisterInfo &) = delete; + void operator=(DynamicRegisterInfo &) = delete; + + DynamicRegisterInfo(DynamicRegisterInfo &&info); + DynamicRegisterInfo &operator=(DynamicRegisterInfo &&info); size_t SetRegisterInfo(const lldb_private::StructuredData::Dictionary &dict, const lldb_private::ArchSpec &arch); @@ -75,8 +81,10 @@ protected: typedef std::vector<uint8_t> dwarf_opcode; typedef std::map<uint32_t, dwarf_opcode> dynamic_reg_size_map; - lldb_private::RegisterInfo * - GetRegisterInfo(const lldb_private::ConstString ®_name); + const lldb_private::RegisterInfo * + GetRegisterInfo(const lldb_private::ConstString ®_name) const; + + void MoveFrom(DynamicRegisterInfo &&info); reg_collection m_regs; set_collection m_sets; @@ -85,9 +93,8 @@ protected: reg_to_regs_map m_value_regs_map; reg_to_regs_map m_invalidate_regs_map; dynamic_reg_size_map m_dynamic_reg_size_map; - size_t m_reg_data_byte_size; // The number of bytes required to store all - // registers - bool m_finalized; + size_t m_reg_data_byte_size = 0u; // The number of bytes required to store + // all registers + bool m_finalized = false; }; - #endif // lldb_DynamicRegisterInfo_h_ diff --git a/source/Plugins/Process/Utility/HistoryThread.h b/source/Plugins/Process/Utility/HistoryThread.h index 363ba2669637..7675a95246a7 100644 --- a/source/Plugins/Process/Utility/HistoryThread.h +++ b/source/Plugins/Process/Utility/HistoryThread.h @@ -29,13 +29,13 @@ namespace lldb_private { //---------------------------------------------------------------------- /// @class HistoryThread HistoryThread.h "HistoryThread.h" -/// @brief A thread object representing a backtrace from a previous point in the +/// A thread object representing a backtrace from a previous point in the /// process execution /// /// This subclass of Thread is used to provide a backtrace from earlier in /// process execution. It is given a backtrace list of pc addresses and -/// optionally a stop_id of when those pc addresses were collected, and it will -/// create stack frames for them. +/// optionally a stop_id of when those pc addresses were collected, and it +/// will create stack frames for them. //---------------------------------------------------------------------- class HistoryThread : public lldb_private::Thread { diff --git a/source/Plugins/Process/Utility/InstructionUtils.h b/source/Plugins/Process/Utility/InstructionUtils.h index e422a96200c8..186d525ce499 100644 --- a/source/Plugins/Process/Utility/InstructionUtils.h +++ b/source/Plugins/Process/Utility/InstructionUtils.h @@ -10,6 +10,9 @@ #ifndef lldb_InstructionUtils_h_ #define lldb_InstructionUtils_h_ +#include <cassert> +#include <cstdint> + // Common utilities for manipulating instruction bit fields. namespace lldb_private { diff --git a/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h b/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h new file mode 100644 index 000000000000..ff57464be2de --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h @@ -0,0 +1,26 @@ +//===-- RegisterContextDarwinConstants.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_REGISTERCONTEXTDARWINCONSTANTS_H +#define LLDB_REGISTERCONTEXTDARWINCONSTANTS_H + +namespace lldb_private { + +/// Constants returned by various RegisterContextDarwin_*** functions. +#ifndef KERN_SUCCESS +#define KERN_SUCCESS 0 +#endif + +#ifndef KERN_INVALID_ARGUMENT +#define KERN_INVALID_ARGUMENT 4 +#endif + +} // namespace lldb_private + +#endif // LLDB_REGISTERCONTEXTDARWINCONSTANTS_H diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp index 64a697ff53c8..5d9ff02fafdd 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp @@ -7,13 +7,8 @@ // //===----------------------------------------------------------------------===// -#if defined(__APPLE__) - #include "RegisterContextDarwin_arm.h" - -// C Includes -#include <mach/mach_types.h> -#include <mach/thread_act.h> +#include "RegisterContextDarwinConstants.h" // C++ Includes // Other libraries and framework includes @@ -34,7 +29,7 @@ #endif // Project includes -#include "ARM_DWARF_Registers.h" +#include "Utility/ARM_DWARF_Registers.h" #include "Utility/ARM_ehframe_Registers.h" #include "llvm/ADT/STLExtras.h" @@ -968,9 +963,9 @@ const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); //---------------------------------------------------------------------- -// Register set definitions. The first definitions at register set index -// of zero is for all registers, followed by other registers sets. The -// register information for the all register set need not be filled in. +// Register set definitions. The first definitions at register set index of +// zero is for all registers, followed by other registers sets. The register +// information for the all register set need not be filled in. //---------------------------------------------------------------------- static const RegisterSet g_reg_sets[] = { { @@ -1510,7 +1505,7 @@ uint32_t RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber( } uint32_t RegisterContextDarwin_arm::NumSupportedHardwareBreakpoints() { -#if defined(__arm__) +#if defined(__APPLE__) && defined(__arm__) // Set the init value to something that will let us know that we need to // autodetect how many breakpoints are supported dynamically... static uint32_t g_num_supported_hw_breakpoints = UINT32_MAX; @@ -1642,7 +1637,7 @@ bool RegisterContextDarwin_arm::ClearHardwareBreakpoint(uint32_t hw_index) { } uint32_t RegisterContextDarwin_arm::NumSupportedHardwareWatchpoints() { -#if defined(__arm__) +#if defined(__APPLE__) && defined(__arm__) // Set the init value to something that will let us know that we need to // autodetect how many watchpoints are supported dynamically... static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX; @@ -1766,5 +1761,3 @@ bool RegisterContextDarwin_arm::ClearHardwareWatchpoint(uint32_t hw_index) { } return false; } - -#endif diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp index 344c08965fad..03ce7ef9f524 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -8,14 +8,8 @@ // //===----------------------------------------------------------------------===// -#if defined(__APPLE__) - #include "RegisterContextDarwin_arm64.h" - -// C Includes -#include <mach/mach_types.h> -#include <mach/thread_act.h> -#include <sys/sysctl.h> +#include "RegisterContextDarwinConstants.h" // C++ Includes // Other libraries and framework includes @@ -39,7 +33,7 @@ #endif // Project includes -#include "ARM64_DWARF_Registers.h" +#include "Utility/ARM64_DWARF_Registers.h" using namespace lldb; using namespace lldb_private; @@ -149,9 +143,9 @@ const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); //---------------------------------------------------------------------- -// Register set definitions. The first definitions at register set index -// of zero is for all registers, followed by other registers sets. The -// register information for the all register set need not be filled in. +// Register set definitions. The first definitions at register set index of +// zero is for all registers, followed by other registers sets. The register +// information for the all register set need not be filled in. //---------------------------------------------------------------------- static const RegisterSet g_reg_sets[] = { { @@ -299,8 +293,9 @@ int RegisterContextDarwin_arm64::WriteRegisterSet(uint32_t set) { void RegisterContextDarwin_arm64::LogDBGRegisters(Log *log, const DBG &dbg) { if (log) { for (uint32_t i = 0; i < 16; i++) - log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8llx, 0x%8.8llx } WVR%-2u/WCR%-2u " - "= { 0x%8.8llx, 0x%8.8llx }", + log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8" PRIu64 ", 0x%8.8" PRIu64 + " } WVR%-2u/WCR%-2u " + "= { 0x%8.8" PRIu64 ", 0x%8.8" PRIu64 " }", i, i, dbg.bvr[i], dbg.bcr[i], i, i, dbg.wvr[i], dbg.wcr[i]); } } @@ -921,7 +916,7 @@ uint32_t RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber( } uint32_t RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints() { -#if defined(__arm64__) || defined(__aarch64__) +#if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) // autodetect how many watchpoints are supported dynamically... static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX; if (g_num_supported_hw_watchpoints == UINT32_MAX) { @@ -1043,5 +1038,3 @@ bool RegisterContextDarwin_arm64::ClearHardwareWatchpoint(uint32_t hw_index) { } return false; } - -#endif diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp index c818fad9ac0e..24414211d9aa 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp @@ -147,9 +147,9 @@ enum { sizeof(RegisterContextDarwin_i386::FPU)) // These macros will auto define the register name, alt name, register size, -// register offset, encoding, format and native register. This ensures that -// the register state structures are defined correctly and have the correct -// sizes and offsets. +// register offset, encoding, format and native register. This ensures that the +// register state structures are defined correctly and have the correct sizes +// and offsets. #define DEFINE_GPR(reg, alt) \ #reg, alt, sizeof(((RegisterContextDarwin_i386::GPR *) NULL)->reg), \ GPR_OFFSET(reg), eEncodingUint, eFormatHex @@ -464,9 +464,9 @@ const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); //---------------------------------------------------------------------- -// Register set definitions. The first definitions at register set index -// of zero is for all registers, followed by other registers sets. The -// register information for the all register set need not be filled in. +// Register set definitions. The first definitions at register set index of +// zero is for all registers, followed by other registers sets. The register +// information for the all register set need not be filled in. //---------------------------------------------------------------------- static const RegisterSet g_reg_sets[] = { { @@ -680,8 +680,7 @@ bool RegisterContextDarwin_i386::ReadRegister(const RegisterInfo *reg_info, case fpu_stmm6: case fpu_stmm7: // These values don't fit into scalar types, - // RegisterContext::ReadRegisterBytes() must be used for these - // registers + // RegisterContext::ReadRegisterBytes() must be used for these registers //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes, //10); return false; @@ -695,8 +694,7 @@ bool RegisterContextDarwin_i386::ReadRegister(const RegisterInfo *reg_info, case fpu_xmm6: case fpu_xmm7: // These values don't fit into scalar types, - // RegisterContext::ReadRegisterBytes() - // must be used for these registers + // RegisterContext::ReadRegisterBytes() must be used for these registers //::memcpy (reg_value.value.vector.uint8, fpu.xmm[reg - fpu_xmm0].bytes, //16); return false; @@ -799,8 +797,7 @@ bool RegisterContextDarwin_i386::WriteRegister(const RegisterInfo *reg_info, case fpu_stmm6: case fpu_stmm7: // These values don't fit into scalar types, - // RegisterContext::ReadRegisterBytes() - // must be used for these registers + // RegisterContext::ReadRegisterBytes() must be used for these registers ::memcpy(fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize()); return false; @@ -814,8 +811,7 @@ bool RegisterContextDarwin_i386::WriteRegister(const RegisterInfo *reg_info, case fpu_xmm6: case fpu_xmm7: // These values don't fit into scalar types, - // RegisterContext::ReadRegisterBytes() - // must be used for these registers + // RegisterContext::ReadRegisterBytes() must be used for these registers ::memcpy(fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize()); return false; diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp index 50e7292f86b1..ecad8240b294 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp @@ -165,9 +165,9 @@ enum ehframe_dwarf_regnums { sizeof(RegisterContextDarwin_x86_64::FPU)) // These macros will auto define the register name, alt name, register size, -// register offset, encoding, format and native register. This ensures that -// the register state structures are defined correctly and have the correct -// sizes and offsets. +// register offset, encoding, format and native register. This ensures that the +// register state structures are defined correctly and have the correct sizes +// and offsets. #define DEFINE_GPR(reg, alt) \ #reg, alt, sizeof(((RegisterContextDarwin_x86_64::GPR *) NULL)->reg), \ GPR_OFFSET(reg), eEncodingUint, eFormatHex @@ -525,9 +525,9 @@ const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); //---------------------------------------------------------------------- -// Register set definitions. The first definitions at register set index -// of zero is for all registers, followed by other registers sets. The -// register information for the all register set need not be filled in. +// Register set definitions. The first definitions at register set index of +// zero is for all registers, followed by other registers sets. The register +// information for the all register set need not be filled in. //---------------------------------------------------------------------- static const RegisterSet g_reg_sets[] = { { diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 5435a02433ab..ba9a8071bcfb 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -104,8 +104,7 @@ bool RegisterContextLLDB::IsUnwindPlanValidForCurrentPC( } // Initialize a RegisterContextLLDB which is the first frame of a stack -- the -// zeroth frame or currently -// executing frame. +// zeroth frame or currently executing frame. void RegisterContextLLDB::InitializeZerothFrame() { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); @@ -131,25 +130,26 @@ void RegisterContextLLDB::InitializeZerothFrame() { // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs // this will strip bit zero in case we read a PC from memory or from the LR. // (which would be a no-op in frame 0 where we get it from the register set, - // but still a good idea to make the call here for other ABIs that may exist.) + // but still a good idea to make the call here for other ABIs that may + // exist.) ABI *abi = process->GetABI().get(); if (abi) current_pc = abi->FixCodeAddress(current_pc); - // Initialize m_current_pc, an Address object, based on current_pc, an addr_t. + // Initialize m_current_pc, an Address object, based on current_pc, an + // addr_t. m_current_pc.SetLoadAddress(current_pc, &process->GetTarget()); // If we don't have a Module for some reason, we're not going to find - // symbol/function information - just - // stick in some reasonable defaults and hope we can unwind past this frame. + // symbol/function information - just stick in some reasonable defaults and + // hope we can unwind past this frame. ModuleSP pc_module_sp(m_current_pc.GetModule()); if (!m_current_pc.IsValid() || !pc_module_sp) { UnwindLogMsg("using architectural default unwind method"); } // 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. + // successfully filled in or this context is of no use to us. const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; if (pc_module_sp.get() && (pc_module_sp->ResolveSymbolContextForAddress( m_current_pc, resolve_scope, m_sym_ctx) & @@ -180,18 +180,17 @@ void RegisterContextLLDB::InitializeZerothFrame() { } // If we were able to find a symbol/function, set addr_range to the bounds of - // that symbol/function. - // else treat the current pc value as the start_pc and record no offset. + // that symbol/function. else treat the current pc value as the start_pc and + // record no offset. if (addr_range.GetBaseAddress().IsValid()) { m_start_pc = addr_range.GetBaseAddress(); if (m_current_pc.GetSection() == m_start_pc.GetSection()) { m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset(); } else if (m_current_pc.GetModule() == m_start_pc.GetModule()) { - // This means that whatever symbol we kicked up isn't really correct - // --- we should not cross section boundaries ... We really should NULL - // out - // the function/symbol in this case unless there is a bad assumption - // here due to inlined functions? + // This means that whatever symbol we kicked up isn't really correct --- + // we should not cross section boundaries ... We really should NULL out + // the function/symbol in this case unless there is a bad assumption here + // due to inlined functions? m_current_offset = m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress(); } @@ -266,8 +265,7 @@ void RegisterContextLLDB::InitializeZerothFrame() { } // Initialize a RegisterContextLLDB for the non-zeroth frame -- rely on the -// RegisterContextLLDB "below" it -// to provide things like its current pc value. +// RegisterContextLLDB "below" it to provide things like its current pc value. void RegisterContextLLDB::InitializeNonZerothFrame() { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); @@ -333,8 +331,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { m_current_pc.SetLoadAddress(pc, &process->GetTarget(), allow_section_end); // If we don't have a Module for some reason, we're not going to find - // symbol/function information - just - // stick in some reasonable defaults and hope we can unwind past this frame. + // symbol/function information - just stick in some reasonable defaults and + // hope we can unwind past this frame. ModuleSP pc_module_sp(m_current_pc.GetModule()); if (!m_current_pc.IsValid() || !pc_module_sp) { UnwindLogMsg("using architectural default unwind method"); @@ -345,12 +343,10 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { if (process->GetLoadAddressPermissions(pc, permissions) && (permissions & ePermissionsExecutable) == 0) { // If this is the second frame off the stack, we may have unwound the - // first frame - // incorrectly. But using the architecture default unwind plan may get us - // back on - // track -- albeit possibly skipping a real frame. Give this frame a - // clearly-invalid - // pc and see if we can get any further. + // first frame incorrectly. But using the architecture default unwind + // plan may get us back on track -- albeit possibly skipping a real + // frame. Give this frame a clearly-invalid pc and see if we can get any + // further. if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsFrameZero()) { UnwindLogMsg("had a pc of 0x%" PRIx64 " which is not in executable " @@ -359,8 +355,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { (uint64_t)pc); m_frame_type = eSkipFrame; } else { - // anywhere other than the second frame, a non-executable pc means we're - // off in the weeds -- stop now. + // anywhere other than the second frame, a non-executable pc means + // we're off in the weeds -- stop now. m_frame_type = eNotAValidFrame; UnwindLogMsg("pc is in a non-executable section of memory and this " "isn't the 2nd frame in the stack walk."); @@ -399,8 +395,7 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { } // m_cfa should point into the stack memory; if we can query memory - // region permissions, - // see if the memory is allocated & readable. + // region permissions, see if the memory is allocated & readable. if (process->GetLoadAddressPermissions(m_cfa, permissions) && (permissions & ePermissionsReadable) == 0) { m_frame_type = eNotAValidFrame; @@ -435,19 +430,18 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { bool resolve_tail_call_address = false; // m_current_pc can be one past the // address range of the function... - // If the saved pc does not point to a function/symbol because it is - // beyond the bounds of the correct function and there's no symbol there, - // we do *not* want ResolveSymbolContextForAddress to back up the pc by 1, - // because 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. + // If the saved pc does not point to a function/symbol because it is beyond + // the bounds of the correct function and there's no symbol there, we do + // *not* want ResolveSymbolContextForAddress to back up the pc by 1, because + // 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; uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress( m_current_pc, resolve_scope, m_sym_ctx, resolve_tail_call_address); // 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. + // successfully filled in or this context is of no use to us. if (resolve_scope & resolved_scope) { m_sym_ctx_valid = true; } @@ -476,8 +470,7 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { decr_pc_and_recompute_addr_range = true; // Or if we're in the middle of the stack (and not "above" an asynchronous - // event like sigtramp), - // and our "current" pc is the start of a function... + // event like sigtramp), and our "current" pc is the start of a function... if (GetNextFrame()->m_frame_type != eTrapHandlerFrame && GetNextFrame()->m_frame_type != eDebuggerFrame && (!m_sym_ctx_valid || @@ -488,9 +481,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { } // We need to back up the pc by 1 byte and re-search for the Symbol to handle - // the case where the "saved pc" - // value is pointing to the next function, e.g. if a function ends with a CALL - // instruction. + // the case where the "saved pc" value is pointing to the next function, e.g. + // if a function ends with a CALL instruction. // FIXME this may need to be an architectural-dependent behavior; if so we'll // need to add a member function // to the ABI plugin and consult that. @@ -516,9 +508,9 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); } - // If we were able to find a symbol/function, set addr_range_ptr to the bounds - // of that symbol/function. - // else treat the current pc value as the start_pc and record no offset. + // If we were able to find a symbol/function, set addr_range_ptr to the + // bounds of that symbol/function. else treat the current pc value as the + // start_pc and record no offset. if (addr_range.GetBaseAddress().IsValid()) { m_start_pc = addr_range.GetBaseAddress(); m_current_offset = pc - m_start_pc.GetLoadAddress(&process->GetTarget()); @@ -553,9 +545,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { RegisterKind row_register_kind = eRegisterKindGeneric; // Try to get by with just the fast UnwindPlan if possible - the full - // UnwindPlan may be expensive to get - // (e.g. if we have to parse the entire eh_frame section of an ObjectFile for - // the first time.) + // UnwindPlan may be expensive to get (e.g. if we have to parse the entire + // eh_frame section of an ObjectFile for the first time.) if (m_fast_unwind_plan_sp && m_fast_unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { @@ -616,16 +607,14 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { bool RegisterContextLLDB::CheckIfLoopingStack() { // If we have a bad stack setup, we can get the same CFA value multiple times - // -- or even - // more devious, we can actually oscillate between two CFA values. Detect that - // here and - // break out to avoid a possible infinite loop in lldb trying to unwind the - // stack. - // To detect when we have the same CFA value multiple times, we compare the + // -- or even more devious, we can actually oscillate between two CFA values. + // Detect that here and break out to avoid a possible infinite loop in lldb + // trying to unwind the stack. To detect when we have the same CFA value + // multiple times, we compare the // CFA of the current // frame with the 2nd next frame because in some specail case (e.g. signal - // hanlders, hand - // written assembly without ABI compiance) we can have 2 frames with the same + // hanlders, hand written assembly without ABI compiance) we can have 2 + // frames with the same // CFA (in theory we // can have arbitrary number of frames with the same CFA, but more then 2 is // very very unlikely) @@ -734,15 +723,12 @@ UnwindPlanSP RegisterContextLLDB::GetFullUnwindPlanForFrame() { } // If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) - // so the pc is 0x0 - // in the zeroth frame, we need to use the "unwind at first instruction" arch - // default UnwindPlan - // Also, if this Process can report on memory region attributes, any - // non-executable region means - // we jumped through a bad function pointer - handle the same way as 0x0. - // Note, if we have a symbol context & a symbol, we don't want to follow this - // code path. This is - // for jumping to memory regions without any information available. + // so the pc is 0x0 in the zeroth frame, we need to use the "unwind at first + // instruction" arch default UnwindPlan Also, if this Process can report on + // memory region attributes, any non-executable region means we jumped + // through a bad function pointer - handle the same way as 0x0. Note, if we + // have a symbol context & a symbol, we don't want to follow this code path. + // This is for jumping to memory regions without any information available. if ((!m_sym_ctx_valid || (m_sym_ctx.function == NULL && m_sym_ctx.symbol == NULL)) && @@ -780,12 +766,10 @@ UnwindPlanSP RegisterContextLLDB::GetFullUnwindPlanForFrame() { } // No FuncUnwinders available for this pc (stripped function symbols, lldb - // could not augment its - // function table with another source, like LC_FUNCTION_STARTS or eh_frame in - // ObjectFileMachO). - // See if eh_frame or the .ARM.exidx tables have unwind information for this - // address, else fall - // back to the architectural default unwind. + // could not augment its function table with another source, like + // LC_FUNCTION_STARTS or eh_frame in ObjectFileMachO). See if eh_frame or the + // .ARM.exidx tables have unwind information for this address, else fall back + // to the architectural default unwind. if (!func_unwinders_sp) { m_frame_type = eNormalFrame; @@ -793,7 +777,8 @@ UnwindPlanSP RegisterContextLLDB::GetFullUnwindPlanForFrame() { !m_current_pc.IsValid()) return arch_default_unwind_plan_sp; - // Even with -fomit-frame-pointer, we can try eh_frame to get back on track. + // Even with -fomit-frame-pointer, we can try eh_frame to get back on + // track. DWARFCallFrameInfo *eh_frame = pc_module_sp->GetObjectFile()->GetUnwindTable().GetEHFrameInfo(); if (eh_frame) { @@ -819,11 +804,10 @@ UnwindPlanSP RegisterContextLLDB::GetFullUnwindPlanForFrame() { } // If we're in _sigtramp(), unwinding past this frame requires special - // knowledge. On Mac OS X this knowledge - // is properly encoded in the eh_frame section, so prefer that if available. - // On other platforms we may need to provide a platform-specific UnwindPlan - // which encodes the details of - // how to unwind out of sigtramp. + // knowledge. On Mac OS X this knowledge is properly encoded in the eh_frame + // section, so prefer that if available. On other platforms we may need to + // provide a platform-specific UnwindPlan which encodes the details of how to + // unwind out of sigtramp. if (m_frame_type == eTrapHandlerFrame && process) { m_fast_unwind_plan_sp.reset(); unwind_plan_sp = func_unwinders_sp->GetEHFrameUnwindPlan( @@ -835,24 +819,19 @@ UnwindPlanSP RegisterContextLLDB::GetFullUnwindPlanForFrame() { } // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame - // even when it's frame zero - // This comes up if we have hand-written functions in a Module and - // hand-written eh_frame. The assembly - // instruction inspection may fail and the eh_frame CFI were probably written - // with some care to do the - // right thing. It'd be nice if there was a way to ask the eh_frame directly - // if it is asynchronous - // (can be trusted at every instruction point) or synchronous (the normal case - // - only at call sites). + // even when it's frame zero This comes up if we have hand-written functions + // in a Module and hand-written eh_frame. The assembly instruction + // inspection may fail and the eh_frame CFI were probably written with some + // care to do the right thing. It'd be nice if there was a way to ask the + // eh_frame directly if it is asynchronous (can be trusted at every + // instruction point) or synchronous (the normal case - only at call sites). // But there is not. if (process && process->GetDynamicLoader() && process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo(m_sym_ctx)) { // We must specifically call the GetEHFrameUnwindPlan() method here -- - // normally we would - // call GetUnwindPlanAtCallSite() -- because CallSite may return an unwind - // plan sourced from - // either eh_frame (that's what we intend) or compact unwind (this won't - // work) + // normally we would call GetUnwindPlanAtCallSite() -- because CallSite may + // return an unwind plan sourced from either eh_frame (that's what we + // intend) or compact unwind (this won't work) unwind_plan_sp = func_unwinders_sp->GetEHFrameUnwindPlan( process->GetTarget(), m_current_offset_backed_up_one); if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { @@ -871,22 +850,16 @@ UnwindPlanSP RegisterContextLLDB::GetFullUnwindPlanForFrame() { if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) { // We probably have an UnwindPlan created by inspecting assembly - // instructions. The - // assembly profilers work really well with compiler-generated functions - // but hand- - // written assembly can be problematic. We set the eh_frame based unwind - // plan as our - // fallback unwind plan if instruction emulation doesn't work out even - // for non call - // sites if it is available and use the architecture default unwind plan - // if it is + // instructions. The assembly profilers work really well with compiler- + // generated functions but hand- written assembly can be problematic. + // We set the eh_frame based unwind plan as our fallback unwind plan if + // instruction emulation doesn't work out even for non call sites if it + // is available and use the architecture default unwind plan if it is // not available. The eh_frame unwind plan is more reliable even on non - // call sites - // then the architecture default plan and for hand written assembly code - // it is often - // written in a way that it valid at all location what helps in the most - // common - // cases when the instruction emulation fails. + // call sites then the architecture default plan and for hand written + // assembly code it is often written in a way that it valid at all + // location what helps in the most common cases when the instruction + // emulation fails. UnwindPlanSP call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite( process->GetTarget(), m_current_offset_backed_up_one); @@ -919,9 +892,8 @@ UnwindPlanSP RegisterContextLLDB::GetFullUnwindPlanForFrame() { } // We'd prefer to use an UnwindPlan intended for call sites when we're at a - // call site but if we've - // struck out on that, fall back to using the non-call-site assembly - // inspection UnwindPlan if possible. + // call site but if we've struck out on that, fall back to using the non- + // call-site assembly inspection UnwindPlan if possible. if (process) { unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite( process->GetTarget(), m_thread, m_current_offset_backed_up_one); @@ -929,19 +901,14 @@ UnwindPlanSP RegisterContextLLDB::GetFullUnwindPlanForFrame() { if (unwind_plan_sp && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) { // We probably have an UnwindPlan created by inspecting assembly - // instructions. The assembly - // profilers work really well with compiler-generated functions but hand- - // written assembly - // can be problematic. We set the eh_frame based unwind plan as our fallback - // unwind plan if + // instructions. The assembly profilers work really well with compiler- + // generated functions but hand- written assembly can be problematic. We + // set the eh_frame based unwind plan as our fallback unwind plan if // instruction emulation doesn't work out even for non call sites if it is - // available and use - // the architecture default unwind plan if it is not available. The eh_frame - // unwind plan is - // more reliable even on non call sites then the architecture default plan - // and for hand - // written assembly code it is often written in a way that it valid at all - // location what + // available and use the architecture default unwind plan if it is not + // available. The eh_frame unwind plan is more reliable even on non call + // sites then the architecture default plan and for hand written assembly + // code it is often written in a way that it valid at all location what // helps in the most common cases when the instruction emulation fails. UnwindPlanSP call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite( @@ -963,8 +930,8 @@ UnwindPlanSP RegisterContextLLDB::GetFullUnwindPlanForFrame() { } // If we're on the first instruction of a function, and we have an - // architectural default UnwindPlan - // for the initial instruction of a function, use that. + // architectural default UnwindPlan for the initial instruction of a + // function, use that. if (m_current_offset_backed_up_one == 0) { unwind_plan_sp = func_unwinders_sp->GetUnwindPlanArchitectureDefaultAtFunctionEntry( @@ -1115,12 +1082,10 @@ bool RegisterContextLLDB::IsValid() const { } // After the final stack frame in a stack walk we'll get one invalid -// (eNotAValidFrame) stack frame -- -// one past the end of the stack walk. But higher-level code will need to tell -// the differnece between -// "the unwind plan below this frame failed" versus "we successfully completed -// the stack walk" so -// this method helps to disambiguate that. +// (eNotAValidFrame) stack frame -- one past the end of the stack walk. But +// higher-level code will need to tell the differnece between "the unwind plan +// below this frame failed" versus "we successfully completed the stack walk" +// so this method helps to disambiguate that. bool RegisterContextLLDB::IsTrapHandlerFrame() const { return m_frame_type == eTrapHandlerFrame; @@ -1129,12 +1094,10 @@ bool RegisterContextLLDB::IsTrapHandlerFrame() const { // A skip frame is a bogus frame on the stack -- but one where we're likely to // find a real frame farther // up the stack if we keep looking. It's always the second frame in an unwind -// (i.e. the first frame after -// frame zero) where unwinding can be the trickiest. Ideally we'll mark up this -// frame in some way so the -// user knows we're displaying bad data and we may have skipped one frame of -// their real program in the -// process of getting back on track. +// (i.e. the first frame after frame zero) where unwinding can be the +// trickiest. Ideally we'll mark up this frame in some way so the user knows +// we're displaying bad data and we may have skipped one frame of their real +// program in the process of getting back on track. bool RegisterContextLLDB::IsSkipFrame() const { return m_frame_type == eSkipFrame; @@ -1231,8 +1194,8 @@ RegisterContextLLDB::SavedLocationForRegister( RegisterNumber return_address_reg; // If we're fetching the saved pc and this UnwindPlan defines a - // ReturnAddress register (e.g. lr on arm), - // look for the return address register number in the UnwindPlan's row. + // ReturnAddress register (e.g. lr on arm), look for the return address + // register number in the UnwindPlan's row. if (pc_regnum.IsValid() && pc_regnum == regnum && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM) { @@ -1272,10 +1235,8 @@ RegisterContextLLDB::SavedLocationForRegister( } // This is frame 0 and we're retrieving the PC and it's saved in a Return - // Address register and - // it hasn't been saved anywhere yet -- that is, it's still live in the - // actual register. - // Handle this specially. + // 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() && IsFrameZero()) { @@ -1298,22 +1259,18 @@ RegisterContextLLDB::SavedLocationForRegister( } // If this architecture stores the return address in a register (it - // defines a Return Address register) - // and we're on a non-zero stack frame and the Full UnwindPlan says that - // the pc is stored in the + // defines a Return Address register) and we're on a non-zero stack frame + // and the Full UnwindPlan says that the pc is stored in the // RA registers (e.g. lr on arm), then we know that the full unwindplan is // not trustworthy -- this // is an impossible situation and the instruction emulation code has - // likely been misled. - // If this stack frame meets those criteria, we need to throw away the - // Full UnwindPlan that the - // instruction emulation came up with and fall back to the architecture's - // Default UnwindPlan so - // the stack walk can get past this point. + // likely been misled. If this stack frame meets those criteria, we need + // to throw away the Full UnwindPlan that the instruction emulation came + // up with and fall back to the architecture's Default UnwindPlan so the + // stack walk can get past this point. // Special note: If the Full UnwindPlan was generated from the compiler, - // don't second-guess it - // when we're at a call site location. + // don't second-guess it when we're at a call site location. // arch_default_ra_regnum is the return address register # in the Full // UnwindPlan register numbering @@ -1376,11 +1333,10 @@ RegisterContextLLDB::SavedLocationForRegister( ExecutionContext exe_ctx(m_thread.shared_from_this()); Process *process = exe_ctx.GetProcessPtr(); if (have_unwindplan_regloc == false) { - // If the UnwindPlan failed to give us an unwind location for this register, - // we may be able to fall back - // to some ABI-defined default. For example, some ABIs allow to determine - // the caller's SP via the CFA. - // Also, the ABI may set volatile registers to the undefined state. + // If the UnwindPlan failed to give us an unwind location for this + // register, we may be able to fall back to some ABI-defined default. For + // example, some ABIs allow to determine the caller's SP via the CFA. Also, + // the ABI may set volatile registers to the undefined state. ABI *abi = process ? process->GetABI().get() : NULL; if (abi) { const RegisterInfo *reg_info = @@ -1558,24 +1514,19 @@ RegisterContextLLDB::SavedLocationForRegister( // TryFallbackUnwindPlan() -- this method is a little tricky. // // When this is called, the frame above -- the caller frame, the "previous" -// frame -- -// is invalid or bad. +// frame -- is invalid or bad. // -// Instead of stopping the stack walk here, we'll try a different UnwindPlan and -// see -// if we can get a valid frame above us. +// Instead of stopping the stack walk here, we'll try a different UnwindPlan +// and see if we can get a valid frame above us. // // This most often happens when an unwind plan based on assembly instruction -// inspection -// is not correct -- mostly with hand-written assembly functions or functions -// where the -// stack frame is set up "out of band", e.g. the kernel saved the register -// context and -// then called an asynchronous trap handler like _sigtramp. +// inspection is not correct -- mostly with hand-written assembly functions or +// functions where the stack frame is set up "out of band", e.g. the kernel +// saved the register context and then called an asynchronous trap handler like +// _sigtramp. // // Often in these cases, if we just do a dumb stack walk we'll get past this -// tricky -// frame and our usual techniques can continue to be used. +// tricky frame and our usual techniques can continue to be used. bool RegisterContextLLDB::TryFallbackUnwindPlan() { if (m_fallback_unwind_plan_sp.get() == nullptr) @@ -1591,15 +1542,13 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() { } // If a compiler generated unwind plan failed, trying the arch default - // unwindplan - // isn't going to do any better. + // unwindplan isn't going to do any better. if (m_full_unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes) return false; - // Get the caller's pc value and our own CFA value. - // Swap in the fallback unwind plan, re-fetch the caller's pc value and CFA - // value. - // If they're the same, then the fallback unwind plan provides no benefit. + // Get the caller's pc value and our own CFA value. Swap in the fallback + // unwind plan, re-fetch the caller's pc value and CFA value. If they're the + // same, then the fallback unwind plan provides no benefit. RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); @@ -1622,23 +1571,18 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() { } // This is a tricky wrinkle! If SavedLocationForRegister() detects a really - // impossible - // register location for the full unwind plan, it may call - // ForceSwitchToFallbackUnwindPlan() - // which in turn replaces the full unwindplan with the fallback... in short, - // we're done, - // we're using the fallback UnwindPlan. - // We checked if m_fallback_unwind_plan_sp was nullptr at the top -- the only - // way it - // became nullptr since then is via SavedLocationForRegister(). + // impossible register location for the full unwind plan, it may call + // ForceSwitchToFallbackUnwindPlan() which in turn replaces the full + // unwindplan with the fallback... in short, we're done, we're using the + // fallback UnwindPlan. We checked if m_fallback_unwind_plan_sp was nullptr + // at the top -- the only way it became nullptr since then is via + // SavedLocationForRegister(). if (m_fallback_unwind_plan_sp.get() == nullptr) return true; // Switch the full UnwindPlan to be the fallback UnwindPlan. If we decide - // this isn't - // working, we need to restore. - // We'll also need to save & restore the value of the m_cfa ivar. Save is - // down below a bit in 'old_cfa'. + // this isn't working, we need to restore. We'll also need to save & restore + // the value of the m_cfa ivar. Save is down below a bit in 'old_cfa'. UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp; addr_t old_cfa = m_cfa; @@ -2049,10 +1993,9 @@ bool RegisterContextLLDB::ReadPC(addr_t &pc) { // A pc value of 0 or 1 is impossible in the middle of the stack -- it // indicates the end of a stack walk. // On the currently executing frame (or such a frame interrupted - // asynchronously by sigtramp et al) this may - // occur if code has jumped through a NULL pointer -- we want to be able to - // unwind past that frame to help - // find the bug. + // asynchronously by sigtramp et al) this may occur if code has jumped + // through a NULL pointer -- we want to be able to unwind past that frame + // to help find the bug. ProcessSP process_sp (m_thread.GetProcess()); if (process_sp) diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp index 2d24bdaed2cd..77c1bea34851 100644 --- a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp @@ -19,7 +19,7 @@ #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/StreamString.h" // Project includes -#include "Utility/StringExtractorGDBRemote.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" using namespace lldb; using namespace lldb_private; @@ -139,8 +139,8 @@ bool RegisterContextMacOSXFrameBackchain::ReadRegister( bool RegisterContextMacOSXFrameBackchain::WriteRegister( const RegisterInfo *reg_info, const RegisterValue &value) { - // Not supported yet. We could easily add support for this by remembering - // the address of each entry (it would need to be part of the cursor) + // Not supported yet. We could easily add support for this by remembering the + // address of each entry (it would need to be part of the cursor) return false; } @@ -154,10 +154,10 @@ bool RegisterContextMacOSXFrameBackchain::ReadAllRegisterValues( bool RegisterContextMacOSXFrameBackchain::WriteAllRegisterValues( const lldb::DataBufferSP &data_sp) { - // Since this class doesn't respond to "ReadAllRegisterValues()", it must - // not have been the one that saved all the register values. So we just let - // the thread's register context (the register context for frame zero) do - // the writing. + // Since this class doesn't respond to "ReadAllRegisterValues()", it must not + // have been the one that saved all the register values. So we just let the + // thread's register context (the register context for frame zero) do the + // writing. return m_thread.GetRegisterContext()->WriteAllRegisterValues(data_sp); } diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/source/Plugins/Process/Utility/RegisterContextMemory.cpp index 8f0dfd2a5b50..76189ea781de 100644 --- a/source/Plugins/Process/Utility/RegisterContextMemory.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMemory.cpp @@ -32,9 +32,9 @@ RegisterContextMemory::RegisterContextMemory(Thread &thread, addr_t reg_data_addr) : RegisterContext(thread, concrete_frame_idx), m_reg_infos(reg_infos), m_reg_valid(), m_reg_data(), m_reg_data_addr(reg_data_addr) { - // Resize our vector of bools to contain one bool for every register. - // We will use these boolean values to know when a register value - // is valid in m_reg_data. + // Resize our vector of bools to contain one bool for every register. We will + // use these boolean values to know when a register value is valid in + // m_reg_data. const size_t num_regs = reg_infos.GetNumRegisters(); assert(num_regs > 0); m_reg_valid.resize(num_regs); diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp index bb3509330eec..352e251e3b64 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp @@ -13,6 +13,7 @@ #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" @@ -20,7 +21,6 @@ #include "lldb/Utility/Endian.h" #include "llvm/Support/Compiler.h" -#include "Plugins/Process/elf-core/ProcessElfCore.h" #include "RegisterContextPOSIX_arm.h" using namespace lldb; @@ -107,11 +107,6 @@ RegisterContextPOSIX_arm::RegisterContextPOSIX_arm( } ::memset(&m_fpr, 0, sizeof m_fpr); - - // elf-core yet to support ReadFPR() - lldb::ProcessSP base = CalculateProcess(); - if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) - return; } RegisterContextPOSIX_arm::~RegisterContextPOSIX_arm() {} @@ -142,8 +137,8 @@ size_t RegisterContextPOSIX_arm::GetGPRSize() { const lldb_private::RegisterInfo *RegisterContextPOSIX_arm::GetRegisterInfo() { // Commonly, this method is overridden and g_register_infos is copied and - // specialized. - // So, use GetRegisterInfo() rather than g_register_infos in this scope. + // specialized. So, use GetRegisterInfo() rather than g_register_infos in + // this scope. return m_register_info_ap->GetRegisterInfo(); } @@ -199,8 +194,8 @@ bool RegisterContextPOSIX_arm::IsRegisterSetAvailable(size_t set_index) { return set_index < k_num_register_sets; } -// Used when parsing DWARF and EH frame information and any other -// object file sections that contain register numbers in them. +// Used when parsing DWARF and EH frame information and any other object file +// sections that contain register numbers in them. uint32_t RegisterContextPOSIX_arm::ConvertRegisterKindToRegisterNumber( lldb::RegisterKind kind, uint32_t num) { const uint32_t num_regs = GetRegisterCount(); diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp index 89384c8f5190..3ff93cde2347 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -13,6 +13,7 @@ #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" @@ -20,7 +21,6 @@ #include "lldb/Utility/Endian.h" #include "llvm/Support/Compiler.h" -#include "Plugins/Process/elf-core/ProcessElfCore.h" #include "RegisterContextPOSIX_arm64.h" using namespace lldb; @@ -126,11 +126,6 @@ RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64( } ::memset(&m_fpr, 0, sizeof m_fpr); - - // elf-core yet to support ReadFPR() - lldb::ProcessSP base = CalculateProcess(); - if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) - return; } RegisterContextPOSIX_arm64::~RegisterContextPOSIX_arm64() {} @@ -162,8 +157,8 @@ size_t RegisterContextPOSIX_arm64::GetGPRSize() { const lldb_private::RegisterInfo * RegisterContextPOSIX_arm64::GetRegisterInfo() { // Commonly, this method is overridden and g_register_infos is copied and - // specialized. - // So, use GetRegisterInfo() rather than g_register_infos in this scope. + // specialized. So, use GetRegisterInfo() rather than g_register_infos in + // this scope. return m_register_info_ap->GetRegisterInfo(); } @@ -219,8 +214,8 @@ bool RegisterContextPOSIX_arm64::IsRegisterSetAvailable(size_t set_index) { return set_index < k_num_register_sets; } -// Used when parsing DWARF and EH frame information and any other -// object file sections that contain register numbers in them. +// Used when parsing DWARF and EH frame information and any other object file +// sections that contain register numbers in them. uint32_t RegisterContextPOSIX_arm64::ConvertRegisterKindToRegisterNumber( lldb::RegisterKind kind, uint32_t num) { const uint32_t num_regs = GetRegisterCount(); diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp index 6a55947ba5c2..98d1e6fa8817 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp @@ -13,6 +13,7 @@ #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" @@ -20,11 +21,10 @@ #include "lldb/Utility/Endian.h" #include "llvm/Support/Compiler.h" -#include "Plugins/Process/elf-core/ProcessElfCore.h" #include "RegisterContextPOSIX_mips64.h" #include "RegisterContextFreeBSD_mips64.h" #include "RegisterContextLinux_mips64.h" -#include "RegisterContextLinux_mips.h" +#include "RegisterContextLinux_mips.h" using namespace lldb_private; using namespace lldb; @@ -59,11 +59,6 @@ RegisterContextPOSIX_mips64::RegisterContextPOSIX_mips64( static_cast<uint32_t>(m_registers_count[gpr_registers_count] + m_registers_count[fpr_registers_count] + m_registers_count[msa_registers_count])); - - // elf-core yet to support ReadFPR() - ProcessSP base = CalculateProcess(); - if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) - return; } RegisterContextPOSIX_mips64::~RegisterContextPOSIX_mips64() {} @@ -92,8 +87,8 @@ size_t RegisterContextPOSIX_mips64::GetGPRSize() { const RegisterInfo *RegisterContextPOSIX_mips64::GetRegisterInfo() { // Commonly, this method is overridden and g_register_infos is copied and - // specialized. - // So, use GetRegisterInfo() rather than g_register_infos in this scope. + // specialized. So, use GetRegisterInfo() rather than g_register_infos in + // this scope. return m_register_info_ap->GetRegisterInfo(); } @@ -172,8 +167,8 @@ bool RegisterContextPOSIX_mips64::IsRegisterSetAvailable(size_t set_index) { return (set_index < num_sets); } -// Used when parsing DWARF and EH frame information and any other -// object file sections that contain register numbers in them. +// Used when parsing DWARF and EH frame information and any other object file +// sections that contain register numbers in them. uint32_t RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber( lldb::RegisterKind kind, uint32_t num) { const uint32_t num_regs = m_num_registers; diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp index c2b73e226165..9f0552539723 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp @@ -14,6 +14,7 @@ #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" @@ -21,7 +22,6 @@ #include "lldb/Utility/Endian.h" #include "llvm/Support/Compiler.h" -#include "Plugins/Process/elf-core/ProcessElfCore.h" #include "RegisterContextPOSIX_powerpc.h" using namespace lldb_private; @@ -95,11 +95,6 @@ RegisterContextPOSIX_powerpc::RegisterContextPOSIX_powerpc( RegisterInfoInterface *register_info) : RegisterContext(thread, concrete_frame_idx) { m_register_info_ap.reset(register_info); - - // elf-core yet to support ReadFPR() - ProcessSP base = CalculateProcess(); - if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) - return; } RegisterContextPOSIX_powerpc::~RegisterContextPOSIX_powerpc() {} @@ -129,8 +124,8 @@ size_t RegisterContextPOSIX_powerpc::GetGPRSize() { const RegisterInfo *RegisterContextPOSIX_powerpc::GetRegisterInfo() { // Commonly, this method is overridden and g_register_infos is copied and - // specialized. - // So, use GetRegisterInfo() rather than g_register_infos in this scope. + // specialized. So, use GetRegisterInfo() rather than g_register_infos in + // this scope. return m_register_info_ap->GetRegisterInfo(); } @@ -181,8 +176,8 @@ bool RegisterContextPOSIX_powerpc::IsRegisterSetAvailable(size_t set_index) { return (set_index < num_sets); } -// Used when parsing DWARF and EH frame information and any other -// object file sections that contain register numbers in them. +// Used when parsing DWARF and EH frame information and any other object file +// sections that contain register numbers in them. uint32_t RegisterContextPOSIX_powerpc::ConvertRegisterKindToRegisterNumber( lldb::RegisterKind kind, uint32_t num) { const uint32_t num_regs = GetRegisterCount(); diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp index de410f063b53..41ae5ec6b51a 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp @@ -13,6 +13,7 @@ #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" @@ -20,7 +21,6 @@ #include "lldb/Utility/Endian.h" #include "llvm/Support/Compiler.h" -#include "Plugins/Process/elf-core/ProcessElfCore.h" #include "RegisterContextPOSIX_ppc64le.h" using namespace lldb_private; @@ -117,10 +117,6 @@ RegisterContextPOSIX_ppc64le::RegisterContextPOSIX_ppc64le( RegisterInfoInterface *register_info) : RegisterContext(thread, concrete_frame_idx) { m_register_info_ap.reset(register_info); - - ProcessSP base = CalculateProcess(); - if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) - return; } void RegisterContextPOSIX_ppc64le::InvalidateAllRegisters() {} @@ -146,8 +142,8 @@ size_t RegisterContextPOSIX_ppc64le::GetGPRSize() { const RegisterInfo *RegisterContextPOSIX_ppc64le::GetRegisterInfo() { // Commonly, this method is overridden and g_register_infos is copied and - // specialized. - // So, use GetRegisterInfo() rather than g_register_infos in this scope. + // specialized. So, use GetRegisterInfo() rather than g_register_infos in + // this scope. return m_register_info_ap->GetRegisterInfo(); } @@ -198,8 +194,8 @@ bool RegisterContextPOSIX_ppc64le::IsRegisterSetAvailable(size_t set_index) { return (set_index < num_sets); } -// Used when parsing DWARF and EH frame information and any other -// object file sections that contain register numbers in them. +// Used when parsing DWARF and EH frame information and any other object file +// sections that contain register numbers in them. uint32_t RegisterContextPOSIX_ppc64le::ConvertRegisterKindToRegisterNumber( lldb::RegisterKind kind, uint32_t num) { const uint32_t num_regs = GetRegisterCount(); diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp index b3365ee2f098..662ac38405ef 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp @@ -174,8 +174,8 @@ lldb::ByteOrder RegisterContextPOSIX_s390x::GetByteOrder() { return byte_order; } -// Used when parsing DWARF and EH frame information and any other -// object file sections that contain register numbers in them. +// Used when parsing DWARF and EH frame information and any other object file +// sections that contain register numbers in them. uint32_t RegisterContextPOSIX_s390x::ConvertRegisterKindToRegisterNumber( lldb::RegisterKind kind, uint32_t num) { const uint32_t num_regs = GetRegisterCount(); diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp index 41cec8add987..d2a06e1b7897 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp @@ -414,8 +414,8 @@ size_t RegisterContextPOSIX_x86::GetFXSAVEOffset() { const RegisterInfo *RegisterContextPOSIX_x86::GetRegisterInfo() { // Commonly, this method is overridden and g_register_infos is copied and - // specialized. - // So, use GetRegisterInfo() rather than g_register_infos in this scope. + // specialized. So, use GetRegisterInfo() rather than g_register_infos in + // this scope. return m_register_info_ap->GetRegisterInfo(); } @@ -531,8 +531,8 @@ bool RegisterContextPOSIX_x86::IsRegisterSetAvailable(size_t set_index) { return (set_index < num_sets); } -// Used when parsing DWARF and EH frame information and any other -// object file sections that contain register numbers in them. +// Used when parsing DWARF and EH frame information and any other object file +// sections that contain register numbers in them. uint32_t RegisterContextPOSIX_x86::ConvertRegisterKindToRegisterNumber( lldb::RegisterKind kind, uint32_t num) { const uint32_t num_regs = GetRegisterCount(); diff --git a/source/Plugins/Process/Utility/RegisterInfoInterface.h b/source/Plugins/Process/Utility/RegisterInfoInterface.h index 1894b5368122..5d7ad89ad394 100644 --- a/source/Plugins/Process/Utility/RegisterInfoInterface.h +++ b/source/Plugins/Process/Utility/RegisterInfoInterface.h @@ -19,7 +19,7 @@ namespace lldb_private { ///------------------------------------------------------------------------------ /// @class RegisterInfoInterface /// -/// @brief RegisterInfo interface to patch RegisterInfo structure for archs. +/// RegisterInfo interface to patch RegisterInfo structure for archs. ///------------------------------------------------------------------------------ class RegisterInfoInterface { public: diff --git a/source/Plugins/Process/Utility/RegisterInfos_ppc64.h b/source/Plugins/Process/Utility/RegisterInfos_ppc64.h new file mode 100644 index 000000000000..69f00e4ba885 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterInfos_ppc64.h @@ -0,0 +1,331 @@ +//===-- RegisterInfos_ppc64.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifdef DECLARE_REGISTER_INFOS_PPC64_STRUCT + +// C Includes +#include <stddef.h> + +// Computes the offset of the given GPR_PPC64 in the user data area. +#define GPR_PPC64_OFFSET(regname) (offsetof(GPR_PPC64, regname)) +#define FPR_PPC64_OFFSET(regname) (offsetof(FPR_PPC64, regname) \ + + sizeof(GPR_PPC64)) +#define VMX_PPC64_OFFSET(regname) (offsetof(VMX_PPC64, regname) \ + + sizeof(GPR_PPC64) + sizeof(FPR_PPC64)) +#define GPR_PPC64_SIZE(regname) (sizeof(((GPR_PPC64 *)NULL)->regname)) + +#include "Utility/PPC64_DWARF_Registers.h" +#include "lldb-ppc64-register-enums.h" + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR_PPC64(reg, alt, lldb_kind) \ + { \ + #reg, alt, GPR_PPC64_SIZE(reg), GPR_PPC64_OFFSET(reg), lldb::eEncodingUint,\ + lldb::eFormatHex, \ + {ppc64_dwarf::dwarf_##reg##_ppc64, \ + ppc64_dwarf::dwarf_##reg##_ppc64, \ + lldb_kind, \ + LLDB_INVALID_REGNUM, \ + gpr_##reg##_ppc64 }, \ + NULL, NULL, NULL, 0 \ + } +#define DEFINE_FPR_PPC64(reg, alt, lldb_kind) \ + { \ +#reg, alt, 8, FPR_PPC64_OFFSET(reg), lldb::eEncodingIEEE754, \ + lldb::eFormatFloat, \ + {ppc64_dwarf::dwarf_##reg##_ppc64, \ + ppc64_dwarf::dwarf_##reg##_ppc64, lldb_kind, LLDB_INVALID_REGNUM, \ + fpr_##reg##_ppc64 }, \ + NULL, NULL, NULL, 0 \ + } +#define DEFINE_VMX_PPC64(reg, lldb_kind) \ + { \ +#reg, NULL, 16, VMX_PPC64_OFFSET(reg), lldb::eEncodingVector, \ + lldb::eFormatVectorOfUInt32, \ + {ppc64_dwarf::dwarf_##reg##_ppc64, \ + ppc64_dwarf::dwarf_##reg##_ppc64, lldb_kind, LLDB_INVALID_REGNUM, \ + vmx_##reg##_ppc64 }, \ + NULL, NULL, NULL, 0 \ + } + +// General purpose registers. +// EH_Frame, Generic, Process Plugin +#define PPC64_REGS \ + DEFINE_GPR_PPC64(r0, NULL, LLDB_INVALID_REGNUM) \ + , DEFINE_GPR_PPC64(r1, "sp", LLDB_REGNUM_GENERIC_SP), \ + DEFINE_GPR_PPC64(r2, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r3, "arg1", LLDB_REGNUM_GENERIC_ARG1), \ + DEFINE_GPR_PPC64(r4, "arg2", LLDB_REGNUM_GENERIC_ARG2), \ + DEFINE_GPR_PPC64(r5, "arg3", LLDB_REGNUM_GENERIC_ARG3), \ + DEFINE_GPR_PPC64(r6, "arg4", LLDB_REGNUM_GENERIC_ARG4), \ + DEFINE_GPR_PPC64(r7, "arg5", LLDB_REGNUM_GENERIC_ARG5), \ + DEFINE_GPR_PPC64(r8, "arg6", LLDB_REGNUM_GENERIC_ARG6), \ + DEFINE_GPR_PPC64(r9, "arg7", LLDB_REGNUM_GENERIC_ARG7), \ + DEFINE_GPR_PPC64(r10, "arg8", LLDB_REGNUM_GENERIC_ARG8), \ + DEFINE_GPR_PPC64(r11, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r12, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r13, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r14, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r15, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r16, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r17, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r18, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r19, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r20, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r21, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r22, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r23, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r24, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r25, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r26, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r27, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r28, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r29, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r30, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(r31, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(cr, "cr", LLDB_REGNUM_GENERIC_FLAGS), \ + DEFINE_GPR_PPC64(msr, "msr", LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(xer, "xer", LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(lr, "lr", LLDB_REGNUM_GENERIC_RA), \ + DEFINE_GPR_PPC64(ctr, "ctr", LLDB_INVALID_REGNUM), \ + DEFINE_GPR_PPC64(pc, "pc", LLDB_REGNUM_GENERIC_PC), \ + DEFINE_FPR_PPC64(f0, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f1, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f2, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f3, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f4, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f5, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f6, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f7, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f8, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f9, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f10, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f11, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f12, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f13, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f14, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f15, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f16, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f17, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f18, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f19, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f20, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f21, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f22, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f23, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f24, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f25, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f26, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f27, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f28, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f29, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f30, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_FPR_PPC64(f31, NULL, LLDB_INVALID_REGNUM), \ + {"fpscr", \ + NULL, \ + 8, \ + FPR_PPC64_OFFSET(fpscr), \ + lldb::eEncodingUint, \ + lldb::eFormatHex, \ + {ppc64_dwarf::dwarf_fpscr_ppc64, \ + ppc64_dwarf::dwarf_fpscr_ppc64, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, fpr_fpscr_ppc64}, \ + NULL, \ + NULL, \ + NULL, \ + 0}, \ + DEFINE_VMX_PPC64(vr0, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr1, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr2, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr3, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr4, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr5, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr6, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr7, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr8, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr9, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr10, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr11, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr12, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr13, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr14, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr15, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr16, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr17, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr18, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr19, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr20, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr21, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr22, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr23, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr24, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr25, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr26, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr27, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr28, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr29, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr30, LLDB_INVALID_REGNUM), \ + DEFINE_VMX_PPC64(vr31, LLDB_INVALID_REGNUM), \ + {"vscr", \ + NULL, \ + 4, \ + VMX_PPC64_OFFSET(vscr), \ + lldb::eEncodingUint, \ + lldb::eFormatHex, \ + {ppc64_dwarf::dwarf_vscr_ppc64, ppc64_dwarf::dwarf_vscr_ppc64, \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, vmx_vscr_ppc64}, \ + NULL, \ + NULL, \ + NULL, \ + 0}, \ + {"vrsave", \ + NULL, \ + 4, \ + VMX_PPC64_OFFSET(vrsave), \ + lldb::eEncodingUint, \ + lldb::eFormatHex, \ + {ppc64_dwarf::dwarf_vrsave_ppc64, \ + ppc64_dwarf::dwarf_vrsave_ppc64, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, vmx_vrsave_ppc64}, \ + NULL, \ + NULL, \ + NULL, \ + 0}, /* */ + +typedef struct _GPR_PPC64 { + uint64_t r0; + uint64_t r1; + uint64_t r2; + uint64_t r3; + uint64_t r4; + uint64_t r5; + uint64_t r6; + uint64_t r7; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t r16; + uint64_t r17; + uint64_t r18; + uint64_t r19; + uint64_t r20; + uint64_t r21; + uint64_t r22; + uint64_t r23; + uint64_t r24; + uint64_t r25; + uint64_t r26; + uint64_t r27; + uint64_t r28; + uint64_t r29; + uint64_t r30; + uint64_t r31; + uint64_t cr; + uint64_t msr; + uint64_t xer; + uint64_t lr; + uint64_t ctr; + uint64_t pc; + uint64_t pad[3]; +} GPR_PPC64; + +typedef struct _FPR_PPC64 { + uint64_t f0; + uint64_t f1; + uint64_t f2; + uint64_t f3; + uint64_t f4; + uint64_t f5; + uint64_t f6; + uint64_t f7; + uint64_t f8; + uint64_t f9; + uint64_t f10; + uint64_t f11; + uint64_t f12; + uint64_t f13; + uint64_t f14; + uint64_t f15; + uint64_t f16; + uint64_t f17; + uint64_t f18; + uint64_t f19; + uint64_t f20; + uint64_t f21; + uint64_t f22; + uint64_t f23; + uint64_t f24; + uint64_t f25; + uint64_t f26; + uint64_t f27; + uint64_t f28; + uint64_t f29; + uint64_t f30; + uint64_t f31; + uint64_t fpscr; +} FPR_PPC64; + +typedef struct _VMX_PPC64 { + uint32_t vr0[4]; + uint32_t vr1[4]; + uint32_t vr2[4]; + uint32_t vr3[4]; + uint32_t vr4[4]; + uint32_t vr5[4]; + uint32_t vr6[4]; + uint32_t vr7[4]; + uint32_t vr8[4]; + uint32_t vr9[4]; + uint32_t vr10[4]; + uint32_t vr11[4]; + uint32_t vr12[4]; + uint32_t vr13[4]; + uint32_t vr14[4]; + uint32_t vr15[4]; + uint32_t vr16[4]; + uint32_t vr17[4]; + uint32_t vr18[4]; + uint32_t vr19[4]; + uint32_t vr20[4]; + uint32_t vr21[4]; + uint32_t vr22[4]; + uint32_t vr23[4]; + uint32_t vr24[4]; + uint32_t vr25[4]; + uint32_t vr26[4]; + uint32_t vr27[4]; + uint32_t vr28[4]; + uint32_t vr29[4]; + uint32_t vr30[4]; + uint32_t vr31[4]; + uint32_t pad[2]; + uint32_t vscr[2]; + uint32_t vrsave; +} VMX_PPC64; + + +static lldb_private::RegisterInfo g_register_infos_ppc64[] = { + PPC64_REGS +}; + +static_assert((sizeof(g_register_infos_ppc64) / + sizeof(g_register_infos_ppc64[0])) == + k_num_registers_ppc64, + "g_register_infos_powerpc64 has wrong number of register infos"); + +#undef DEFINE_FPR_PPC64 +#undef DEFINE_GPR_PPC64 +#undef DEFINE_VMX_PPC64 + +#endif // DECLARE_REGISTER_INFOS_PPC64_STRUCT diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp index 3e860874183c..3dbfe611e713 100644 --- a/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -356,8 +356,8 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( if (exc_code == 0x10003) // EXC_SOFT_SIGNAL { if (exc_sub_code == 5) { - // On MacOSX, a SIGTRAP can signify that a process has called - // exec, so we should check with our dynamic loader to verify. + // On MacOSX, a SIGTRAP can signify that a process has called exec, + // so we should check with our dynamic loader to verify. ProcessSP process_sp(thread.GetProcess()); if (process_sp) { DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader(); @@ -403,10 +403,8 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( if (!exc_sub_code) { // This looks like a plain trap. // Have to check if there is a breakpoint here as well. When you - // single-step onto a trap, - // the single step stops you not to trap. Since we also do that - // check below, let's just use - // that logic. + // single-step onto a trap, the single step stops you not to trap. + // Since we also do that check below, let's just use that logic. is_actual_breakpoint = true; is_trace_if_actual_breakpoint_missing = true; } else { @@ -419,8 +417,8 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( (lldb::addr_t)exc_sub_code); if (wp_sp && wp_sp->IsEnabled()) { // Debugserver may piggyback the hardware index of the fired - // watchpoint in the exception data. - // Set the hardware index if that's the case. + // watchpoint in the exception data. Set the hardware index if + // that's the case. if (exc_data_count >= 3) wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); return StopInfo::CreateStopReasonWithWatchpointID(thread, @@ -450,16 +448,15 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( if (exc_code == 0x102) // EXC_ARM_DA_DEBUG { // It's a watchpoint, then, if the exc_sub_code indicates a - // known/enabled - // data break address from our watchpoint list. + // known/enabled data break address from our watchpoint list. lldb::WatchpointSP wp_sp; if (target) wp_sp = target->GetWatchpointList().FindByAddress( (lldb::addr_t)exc_sub_code); if (wp_sp && wp_sp->IsEnabled()) { // Debugserver may piggyback the hardware index of the fired - // watchpoint in the exception data. - // Set the hardware index if that's the case. + // watchpoint in the exception data. Set the hardware index if + // that's the case. if (exc_data_count >= 3) wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); return StopInfo::CreateStopReasonWithWatchpointID(thread, @@ -473,9 +470,9 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( is_actual_breakpoint = true; is_trace_if_actual_breakpoint_missing = true; } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel - // is currently returning this so accept it as - // indicating a breakpoint until the kernel is - // fixed + // is currently returning this so accept it + // as indicating a breakpoint until the + // kernel is fixed { is_actual_breakpoint = true; is_trace_if_actual_breakpoint_missing = true; @@ -493,16 +490,15 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( if (exc_code == 0x102) // EXC_ARM_DA_DEBUG { // It's a watchpoint, then, if the exc_sub_code indicates a - // known/enabled - // data break address from our watchpoint list. + // known/enabled data break address from our watchpoint list. lldb::WatchpointSP wp_sp; if (target) wp_sp = target->GetWatchpointList().FindByAddress( (lldb::addr_t)exc_sub_code); if (wp_sp && wp_sp->IsEnabled()) { // Debugserver may piggyback the hardware index of the fired - // watchpoint in the exception data. - // Set the hardware index if that's the case. + // watchpoint in the exception data. Set the hardware index if + // that's the case. if (exc_data_count >= 3) wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); return StopInfo::CreateStopReasonWithWatchpointID(thread, @@ -514,8 +510,7 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( return StopInfo::CreateStopReasonToTrace(thread); } // It looks like exc_sub_code has the 4 bytes of the instruction that - // triggered the - // exception, i.e. our breakpoint opcode + // triggered the exception, i.e. our breakpoint opcode is_actual_breakpoint = exc_code == 1; break; } @@ -534,23 +529,21 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( if (process_sp) bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc); if (bp_site_sp && bp_site_sp->IsEnabled()) { - // Update the PC if we were asked to do so, but only do - // so if we find a breakpoint that we know about cause - // this could be a trap instruction in the code + // Update the PC if we were asked to do so, but only do so if we find + // a breakpoint that we know about cause this could be a trap + // instruction in the code if (pc_decrement > 0 && adjust_pc_if_needed) reg_ctx_sp->SetPC(pc); // If the breakpoint is for this thread, then we'll report the hit, - // but if it is for another thread, - // we can just report no reason. We don't need to worry about - // stepping over the breakpoint here, that + // but if it is for another thread, we can just report no reason. We + // don't need to worry about stepping over the breakpoint here, that // will be taken care of when the thread resumes and notices that - // there's a breakpoint under the pc. - // If we have an operating system plug-in, we might have set a thread - // specific breakpoint using the + // there's a breakpoint under the pc. If we have an operating system + // plug-in, we might have set a thread specific breakpoint using the // operating system thread ID, so we can't make any assumptions about - // the thread ID so we must always - // report the breakpoint regardless of the thread. + // the thread ID so we must always report the breakpoint regardless + // of the thread. if (bp_site_sp->ValidForThisThread(&thread) || thread.GetProcess()->GetOperatingSystem() != NULL) return StopInfo::CreateStopReasonWithBreakpointSiteID( diff --git a/source/Plugins/Process/Utility/ThreadMemory.cpp b/source/Plugins/Process/Utility/ThreadMemory.cpp index 5ff928c69e59..0c7c195815a4 100644 --- a/source/Plugins/Process/Utility/ThreadMemory.cpp +++ b/source/Plugins/Process/Utility/ThreadMemory.cpp @@ -62,7 +62,7 @@ ThreadMemory::CreateRegisterContextForFrame(StackFrame *frame) { reg_ctx_sp = GetRegisterContext(); } else { Unwind *unwinder = GetUnwinder(); - if (unwinder) + if (unwinder != nullptr) reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); } return reg_ctx_sp; diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index 2b34bddd90b2..55559f07f1e5 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -132,16 +132,12 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { // We want to detect an unwind that cycles erroneously and stop backtracing. // Don't want this maximum unwind limit to be too low -- if you have a - // backtrace - // with an "infinitely recursing" bug, it will crash when the stack blows out - // and the first 35,000 frames are uninteresting - it's the top most 5 frames - // that - // you actually care about. So you can't just cap the unwind at 10,000 or - // something. - // Realistically anything over around 200,000 is going to blow out the stack - // space. - // If we're still unwinding at that point, we're probably never going to - // finish. + // backtrace with an "infinitely recursing" bug, it will crash when the stack + // blows out and the first 35,000 frames are uninteresting - it's the top + // most 5 frames that you actually care about. So you can't just cap the + // unwind at 10,000 or something. Realistically anything over around 200,000 + // is going to blow out the stack space. If we're still unwinding at that + // point, we're probably never going to finish. if (cur_idx > 300000) { if (log) log->Printf("%*sFrame %d unwound too many frames, assuming unwind has " @@ -152,13 +148,12 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { if (reg_ctx_sp.get() == NULL) { // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to - // that and return - // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + // that and return true. Subsequent calls to TryFallbackUnwindPlan() will + // return false. if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of - // prev_frame. However, cfa field of prev_frame still needs to be updated. - // Hence updating it. + // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame + // still needs to be updated. Hence updating it. if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) return nullptr; @@ -172,15 +167,13 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { } if (!reg_ctx_sp->IsValid()) { - // We failed to get a valid RegisterContext. - // See if the regctx below this on the stack has a fallback unwind plan it - // can use. - // Subsequent calls to TryFallbackUnwindPlan() will return false. + // We failed to get a valid RegisterContext. See if the regctx below this + // on the stack has a fallback unwind plan it can use. Subsequent calls to + // TryFallbackUnwindPlan() will return false. if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of - // prev_frame. However, cfa field of prev_frame still needs to be updated. - // Hence updating it. + // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame + // still needs to be updated. Hence updating it. if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) return nullptr; @@ -195,13 +188,12 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { } if (!reg_ctx_sp->GetCFA(cursor_sp->cfa)) { // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to - // that and return - // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + // that and return true. Subsequent calls to TryFallbackUnwindPlan() will + // return false. if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of - // prev_frame. However, cfa field of prev_frame still needs to be updated. - // Hence updating it. + // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame + // still needs to be updated. Hence updating it. if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) return nullptr; @@ -216,27 +208,21 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { } if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa)) { // On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not - // have - // its (constructed) CFA aligned correctly -- don't do the abi alignment - // check for - // these. + // have its (constructed) CFA aligned correctly -- don't do the abi + // alignment check for these. if (reg_ctx_sp->IsTrapHandlerFrame() == false) { // 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. + // 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 (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of - // prev_frame. However, cfa field of prev_frame still needs to be - // updated. Hence updating it. + // reg_ctx_lldb_sp field of prev_frame. However, cfa field of + // prev_frame still needs to be updated. Hence updating it. if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) return nullptr; @@ -259,13 +245,12 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { } if (!reg_ctx_sp->ReadPC(cursor_sp->start_pc)) { // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to - // that and return - // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + // that and return true. Subsequent calls to TryFallbackUnwindPlan() will + // return false. if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of - // prev_frame. However, cfa field of prev_frame still needs to be updated. - // Hence updating it. + // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame + // still needs to be updated. Hence updating it. if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) return nullptr; @@ -280,13 +265,12 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { } if (abi && !abi->CodeAddressIsValid(cursor_sp->start_pc)) { // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to - // that and return - // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + // that and return true. Subsequent calls to TryFallbackUnwindPlan() will + // return false. if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { // TryFallbackUnwindPlan for prev_frame succeeded and updated - // reg_ctx_lldb_sp field of - // prev_frame. However, cfa field of prev_frame still needs to be updated. - // Hence updating it. + // reg_ctx_lldb_sp field of prev_frame. However, cfa field of prev_frame + // still needs to be updated. Hence updating it. if (!(prev_frame->reg_ctx_lldb_sp->GetCFA(prev_frame->cfa))) return nullptr; @@ -320,13 +304,12 @@ void UnwindLLDB::UpdateUnwindPlanForFirstFrameIfInvalid(ABI *abi) { CursorSP old_m_candidate_frame = m_candidate_frame; // Try to unwind 2 more frames using the Unwinder. It uses Full UnwindPlan - // and if Full UnwindPlan fails, then uses FallBack UnwindPlan. Also - // update the cfa of Frame 0 (if required). + // and if Full UnwindPlan fails, then uses FallBack UnwindPlan. Also update + // the cfa of Frame 0 (if required). AddOneMoreFrame(abi); - // Remove all the frames added by above function as the purpose of - // using above function was just to check whether Unwinder of Frame 0 - // works or not. + // Remove all the frames added by above function as the purpose of using + // above function was just to check whether Unwinder of Frame 0 works or not. for (uint32_t i = 1; i < m_frames.size(); i++) m_frames.pop_back(); @@ -362,51 +345,44 @@ bool UnwindLLDB::AddOneMoreFrame(ABI *abi) { m_frames.push_back(new_frame); - // If we can get one more frame further then accept that we get back a correct - // frame. + // If we can get one more frame further then accept that we get back a + // correct frame. m_candidate_frame = GetOneMoreFrame(abi); if (m_candidate_frame) return true; // We can't go further from the frame returned by GetOneMore frame. Lets try - // to get a - // different frame with using the fallback unwind plan. + // to get a different frame with using the fallback unwind plan. if (!m_frames[m_frames.size() - 2] ->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { // We don't have a valid fallback unwind plan. Accept the frame as it is. - // This is a - // valid situation when we are at the bottom of the stack. + // This is a valid situation when we are at the bottom of the stack. return true; } // Remove the possibly incorrect frame from the frame list and try to add a - // different one with - // the newly selected fallback unwind plan. + // different one with the newly selected fallback unwind plan. m_frames.pop_back(); CursorSP new_frame_v2 = GetOneMoreFrame(abi); if (new_frame_v2 == nullptr) { // We haven't got a new frame from the fallback unwind plan. Accept the - // frame from the - // original unwind plan. This is a valid situation when we are at the bottom - // of the stack. + // frame from the original unwind plan. This is a valid situation when we + // are at the bottom of the stack. m_frames.push_back(new_frame); return true; } // Push the new frame to the list and try to continue from this frame. If we - // can get a new frame - // then accept it as the correct one. + // can get a new frame then accept it as the correct one. m_frames.push_back(new_frame_v2); m_candidate_frame = GetOneMoreFrame(abi); if (m_candidate_frame) { // If control reached here then TryFallbackUnwindPlan had succeeded for - // Cursor::m_frames[m_frames.size() - 2]. - // It also succeeded to Unwind next 2 frames i.e. m_frames[m_frames.size() - - // 1] and a frame after that. - // For Cursor::m_frames[m_frames.size() - 2], reg_ctx_lldb_sp field was - // already updated during TryFallbackUnwindPlan - // call above. However, cfa field still needs to be updated. Hence updating - // it here and then returning. + // Cursor::m_frames[m_frames.size() - 2]. It also succeeded to Unwind next + // 2 frames i.e. m_frames[m_frames.size() - 1] and a frame after that. For + // Cursor::m_frames[m_frames.size() - 2], reg_ctx_lldb_sp field was already + // updated during TryFallbackUnwindPlan call above. However, cfa field + // still needs to be updated. Hence updating it here and then returning. if (!(m_frames[m_frames.size() - 2]->reg_ctx_lldb_sp->GetCFA( m_frames[m_frames.size() - 2]->cfa))) return false; @@ -414,8 +390,7 @@ bool UnwindLLDB::AddOneMoreFrame(ABI *abi) { } // The new frame hasn't helped in unwinding. Fall back to the original one as - // the default unwind - // plan is usually more reliable then the fallback one. + // the default unwind plan is usually more reliable then the fallback one. m_frames.pop_back(); m_frames.push_back(new_frame); return true; @@ -486,10 +461,9 @@ bool UnwindLLDB::SearchForSavedLocationForRegister( if (static_cast<size_t>(frame_num) >= m_frames.size()) return false; - // Never interrogate more than one level while looking for the saved pc value. - // If the value - // isn't saved by frame_num, none of the frames lower on the stack will have a - // useful value. + // Never interrogate more than one level while looking for the saved pc + // value. If the value isn't saved by frame_num, none of the frames lower on + // the stack will have a useful value. if (pc_reg) { UnwindLLDB::RegisterSearchResult result; result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister( @@ -505,8 +479,7 @@ bool UnwindLLDB::SearchForSavedLocationForRegister( lldb_regnum, regloc); // We descended down to the live register context aka stack frame 0 and are - // reading the value - // out of a live register. + // reading the value out of a live register. if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound && regloc.type == UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext) { @@ -514,11 +487,9 @@ bool UnwindLLDB::SearchForSavedLocationForRegister( } // If we have unwind instructions saying that register N is saved in - // register M in the middle of - // the stack (and N can equal M here, meaning the register was not used in - // this function), then - // change the register number we're looking for to M and keep looking for a - // concrete location + // register M in the middle of the stack (and N can equal M here, meaning + // the register was not used in this function), then change the register + // number we're looking for to M and keep looking for a concrete location // down the stack, or an actual value from a live RegisterContext at frame // 0. if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound && diff --git a/source/Plugins/Process/Utility/UnwindLLDB.h b/source/Plugins/Process/Utility/UnwindLLDB.h index 3f84649aa05f..3d1f85a3dec3 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.h +++ b/source/Plugins/Process/Utility/UnwindLLDB.h @@ -17,6 +17,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Symbol/FuncUnwinders.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Unwind.h" diff --git a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp index d831011cb661..2115b4e179c0 100644 --- a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp +++ b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp @@ -133,8 +133,8 @@ size_t UnwindMacOSXFrameBackchain::GetStackFrameData_i386( if (addr_range_ptr) { if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress()) { - // We are at the first instruction, so we can recover the - // previous PC by dereferencing the SP + // We are at the first instruction, so we can recover the previous PC + // by dereferencing the SP lldb::addr_t first_frame_sp = reg_ctx->GetSP(0); // Read the real second frame return address into frame.pc if (first_frame_sp && @@ -224,8 +224,8 @@ size_t UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64( if (addr_range_ptr) { if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress()) { - // We are at the first instruction, so we can recover the - // previous PC by dereferencing the SP + // We are at the first instruction, so we can recover the previous PC + // by dereferencing the SP lldb::addr_t first_frame_sp = reg_ctx->GetSP(0); // Read the real second frame return address into frame.pc if (process->ReadMemory(first_frame_sp, &frame.pc, sizeof(frame.pc), diff --git a/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h b/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h new file mode 100644 index 000000000000..9ea81c00b666 --- /dev/null +++ b/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h @@ -0,0 +1,139 @@ +//===-- lldb-ppc64-register-enums.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_ppc64_register_enums_h +#define lldb_ppc64_register_enums_h + +// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) + +// --------------------------------------------------------------------------- +// Internal codes for all ppc64 registers. +// --------------------------------------------------------------------------- +enum { + k_first_gpr_ppc64, + gpr_r0_ppc64 = k_first_gpr_ppc64, + gpr_r1_ppc64, + gpr_r2_ppc64, + gpr_r3_ppc64, + gpr_r4_ppc64, + gpr_r5_ppc64, + gpr_r6_ppc64, + gpr_r7_ppc64, + gpr_r8_ppc64, + gpr_r9_ppc64, + gpr_r10_ppc64, + gpr_r11_ppc64, + gpr_r12_ppc64, + gpr_r13_ppc64, + gpr_r14_ppc64, + gpr_r15_ppc64, + gpr_r16_ppc64, + gpr_r17_ppc64, + gpr_r18_ppc64, + gpr_r19_ppc64, + gpr_r20_ppc64, + gpr_r21_ppc64, + gpr_r22_ppc64, + gpr_r23_ppc64, + gpr_r24_ppc64, + gpr_r25_ppc64, + gpr_r26_ppc64, + gpr_r27_ppc64, + gpr_r28_ppc64, + gpr_r29_ppc64, + gpr_r30_ppc64, + gpr_r31_ppc64, + gpr_cr_ppc64, + gpr_msr_ppc64, + gpr_xer_ppc64, + gpr_lr_ppc64, + gpr_ctr_ppc64, + gpr_pc_ppc64, + k_last_gpr_ppc64 = gpr_pc_ppc64, + + k_first_fpr_ppc64, + fpr_f0_ppc64 = k_first_fpr_ppc64, + fpr_f1_ppc64, + fpr_f2_ppc64, + fpr_f3_ppc64, + fpr_f4_ppc64, + fpr_f5_ppc64, + fpr_f6_ppc64, + fpr_f7_ppc64, + fpr_f8_ppc64, + fpr_f9_ppc64, + fpr_f10_ppc64, + fpr_f11_ppc64, + fpr_f12_ppc64, + fpr_f13_ppc64, + fpr_f14_ppc64, + fpr_f15_ppc64, + fpr_f16_ppc64, + fpr_f17_ppc64, + fpr_f18_ppc64, + fpr_f19_ppc64, + fpr_f20_ppc64, + fpr_f21_ppc64, + fpr_f22_ppc64, + fpr_f23_ppc64, + fpr_f24_ppc64, + fpr_f25_ppc64, + fpr_f26_ppc64, + fpr_f27_ppc64, + fpr_f28_ppc64, + fpr_f29_ppc64, + fpr_f30_ppc64, + fpr_f31_ppc64, + fpr_fpscr_ppc64, + k_last_fpr_ppc64 = fpr_fpscr_ppc64, + + k_first_vmx_ppc64, + vmx_vr0_ppc64 = k_first_vmx_ppc64, + vmx_vr1_ppc64, + vmx_vr2_ppc64, + vmx_vr3_ppc64, + vmx_vr4_ppc64, + vmx_vr5_ppc64, + vmx_vr6_ppc64, + vmx_vr7_ppc64, + vmx_vr8_ppc64, + vmx_vr9_ppc64, + vmx_vr10_ppc64, + vmx_vr11_ppc64, + vmx_vr12_ppc64, + vmx_vr13_ppc64, + vmx_vr14_ppc64, + vmx_vr15_ppc64, + vmx_vr16_ppc64, + vmx_vr17_ppc64, + vmx_vr18_ppc64, + vmx_vr19_ppc64, + vmx_vr20_ppc64, + vmx_vr21_ppc64, + vmx_vr22_ppc64, + vmx_vr23_ppc64, + vmx_vr24_ppc64, + vmx_vr25_ppc64, + vmx_vr26_ppc64, + vmx_vr27_ppc64, + vmx_vr28_ppc64, + vmx_vr29_ppc64, + vmx_vr30_ppc64, + vmx_vr31_ppc64, + vmx_vscr_ppc64, + vmx_vrsave_ppc64, + k_last_vmx_ppc64 = vmx_vrsave_ppc64, + + k_num_registers_ppc64, + k_num_gpr_registers_ppc64 = k_last_gpr_ppc64 - k_first_gpr_ppc64 + 1, + k_num_fpr_registers_ppc64 = k_last_fpr_ppc64 - k_first_fpr_ppc64 + 1, + k_num_vmx_registers_ppc64 = k_last_vmx_ppc64 - k_first_vmx_ppc64 + 1, +}; + +#endif // #ifndef lldb_ppc64_register_enums_h diff --git a/source/Plugins/Process/Windows/Common/CMakeLists.txt b/source/Plugins/Process/Windows/Common/CMakeLists.txt index 009a289bae39..092629086183 100644 --- a/source/Plugins/Process/Windows/Common/CMakeLists.txt +++ b/source/Plugins/Process/Windows/Common/CMakeLists.txt @@ -1,6 +1,3 @@ -include_directories(.) -include_directories(../../Utility) - set(PROC_WINDOWS_COMMON_SOURCES DebuggerThread.cpp LocalDebugDelegate.cpp diff --git a/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/source/Plugins/Process/Windows/Common/DebuggerThread.cpp index ac9e65c3c108..ad43551a4c6d 100644 --- a/source/Plugins/Process/Windows/Common/DebuggerThread.cpp +++ b/source/Plugins/Process/Windows/Common/DebuggerThread.cpp @@ -112,8 +112,7 @@ lldb::thread_result_t DebuggerThread::DebuggerThreadAttachRoutine(void *data) { lldb::thread_result_t DebuggerThread::DebuggerThreadLaunchRoutine( const ProcessLaunchInfo &launch_info) { // Grab a shared_ptr reference to this so that we know it won't get deleted - // until after the - // thread routine has exited. + // until after the thread routine has exited. std::shared_ptr<DebuggerThread> this_ref(shared_from_this()); Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); @@ -124,14 +123,11 @@ lldb::thread_result_t DebuggerThread::DebuggerThreadLaunchRoutine( ProcessLauncherWindows launcher; HostProcess process(launcher.LaunchProcess(launch_info, error)); // If we couldn't create the process, notify waiters immediately. Otherwise - // enter the debug - // loop and wait until we get the create process debug notification. Note - // that if the process - // was created successfully, we can throw away the process handle we got from - // CreateProcess - // because Windows will give us another (potentially more useful?) handle when - // it sends us the - // CREATE_PROCESS_DEBUG_EVENT. + // enter the debug loop and wait until we get the create process debug + // notification. Note that if the process was created successfully, we can + // throw away the process handle we got from CreateProcess because Windows + // will give us another (potentially more useful?) handle when it sends us + // the CREATE_PROCESS_DEBUG_EVENT. if (error.Success()) DebugLoop(); else @@ -143,8 +139,7 @@ lldb::thread_result_t DebuggerThread::DebuggerThreadLaunchRoutine( lldb::thread_result_t DebuggerThread::DebuggerThreadAttachRoutine( lldb::pid_t pid, const ProcessAttachInfo &attach_info) { // Grab a shared_ptr reference to this so that we know it won't get deleted - // until after the - // thread routine has exited. + // until after the thread routine has exited. std::shared_ptr<DebuggerThread> this_ref(shared_from_this()); Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); @@ -157,11 +152,9 @@ lldb::thread_result_t DebuggerThread::DebuggerThreadAttachRoutine( return 0; } - // The attach was successful, enter the debug loop. From here on out, this is - // no different than - // a create process operation, so all the same comments in DebugLaunch should - // apply from this - // point out. + // The attach was successful, enter the debug loop. From here on out, this + // is no different than a create process operation, so all the same comments + // in DebugLaunch should apply from this point out. DebugLoop(); return 0; @@ -188,21 +181,25 @@ Status DebuggerThread::StopDebugging(bool terminate) { lldb::process_t handle = m_process.GetNativeProcess().GetSystemHandle(); if (terminate) { - // Initiate the termination before continuing the exception, so that the - // next debug - // event we get is the exit process event, and not some other event. - BOOL terminate_suceeded = TerminateProcess(handle, 0); - LLDB_LOG(log, - "calling TerminateProcess({0}, 0) (inferior={1}), success={2}", - handle, pid, terminate_suceeded); + if (handle != nullptr && handle != LLDB_INVALID_PROCESS) { + // Initiate the termination before continuing the exception, so that the + // next debug event we get is the exit process event, and not some other + // event. + BOOL terminate_suceeded = TerminateProcess(handle, 0); + LLDB_LOG(log, + "calling TerminateProcess({0}, 0) (inferior={1}), success={2}", + handle, pid, terminate_suceeded); + } else { + LLDB_LOG(log, + "NOT calling TerminateProcess because the inferior is not valid ({0}, 0) (inferior={1})", + handle, pid); + } } // If we're stuck waiting for an exception to continue (e.g. the user is at a - // breakpoint - // messing around in the debugger), continue it now. But only AFTER calling - // TerminateProcess - // to make sure that the very next call to WaitForDebugEvent is an exit - // process event. + // breakpoint messing around in the debugger), continue it now. But only + // AFTER calling TerminateProcess to make sure that the very next call to + // WaitForDebugEvent is an exit process event. if (m_active_exception.get()) { LLDB_LOG(log, "masking active exception"); ContinueAsyncException(ExceptionResult::MaskException); @@ -355,8 +352,7 @@ DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, } // Don't perform any blocking operations while we're shutting down. That - // will - // cause TerminateProcess -> WaitForSingleObject to time out. + // will cause TerminateProcess -> WaitForSingleObject to time out. return ExceptionResult::SendToApplication; } @@ -373,8 +369,8 @@ DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, m_exception_pred.SetValue(result, eBroadcastNever); LLDB_LOG(log, "waiting for ExceptionPred != BreakInDebugger"); - m_exception_pred.WaitForValueNotEqualTo(ExceptionResult::BreakInDebugger, - result); + result = *m_exception_pred.WaitForValueNotEqualTo( + ExceptionResult::BreakInDebugger); LLDB_LOG(log, "got ExceptionPred = {0}", (int)m_exception_pred.GetValue()); return result; diff --git a/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/source/Plugins/Process/Windows/Common/ProcessWindows.cpp index a1c9cfaed41c..b14081f76617 100644 --- a/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -77,8 +77,8 @@ std::string GetProcessExecutableName(DWORD pid) { namespace lldb_private { // We store a pointer to this class in the ProcessWindows, so that we don't -// expose Windows-specific types and implementation details from a public header -// file. +// expose Windows-specific types and implementation details from a public +// header file. class ProcessWindowsData { public: ProcessWindowsData(bool stop_at_entry) : m_stop_at_entry(stop_at_entry) { @@ -186,9 +186,9 @@ Status ProcessWindows::DoDetach(bool keep_stopped) { StateType private_state; { // Acquire the lock only long enough to get the DebuggerThread. - // StopDebugging() will trigger a call back into ProcessWindows which - // will also acquire the lock. Thus we have to release the lock before - // calling StopDebugging(). + // StopDebugging() will trigger a call back into ProcessWindows which will + // also acquire the lock. Thus we have to release the lock before calling + // StopDebugging(). llvm::sys::ScopedLock lock(m_mutex); private_state = GetPrivateState(); @@ -228,14 +228,22 @@ Status ProcessWindows::DoDetach(bool keep_stopped) { Status ProcessWindows::DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) { - // Even though m_session_data is accessed here, it is before a debugger thread - // has been - // kicked off. So there's no race conditions, and it shouldn't be necessary - // to acquire - // the mutex. + // Even though m_session_data is accessed here, it is before a debugger + // thread has been kicked off. So there's no race conditions, and it + // shouldn't be necessary to acquire the mutex. Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); Status result; + + 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 (!launch_info.GetFlags().Test(eLaunchFlagDebug)) { StreamString stream; stream.Printf("ProcessWindows unable to launch '%s'. ProcessWindows can " @@ -251,7 +259,6 @@ Status ProcessWindows::DoLaunch(Module *exe_module, bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); m_session_data.reset(new ProcessWindowsData(stop_at_entry)); - SetPrivateState(eStateLaunching); DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); m_session_data->m_debugger.reset(new DebuggerThread(delegate)); DebuggerThreadSP debugger = m_session_data->m_debugger; @@ -276,12 +283,10 @@ Status ProcessWindows::DoLaunch(Module *exe_module, launch_info.GetExecutableFile().GetPath()); // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the - // private state - // should already be set to eStateStopped as a result of hitting the initial - // breakpoint. If - // it was not set, the breakpoint should have already been resumed from and - // the private state - // should already be eStateRunning. + // private state should already be set to eStateStopped as a result of + // hitting the initial breakpoint. If it was not set, the breakpoint should + // have already been resumed from and the private state should already be + // eStateRunning. launch_info.SetProcessID(process.GetProcessId()); SetID(process.GetProcessId()); @@ -322,12 +327,10 @@ ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid, LLDB_LOG(log, "successfully attached to process with pid={0}", process_id); // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the - // private state - // should already be set to eStateStopped as a result of hitting the initial - // breakpoint. If - // it was not set, the breakpoint should have already been resumed from and - // the private state - // should already be eStateRunning. + // private state should already be set to eStateStopped as a result of + // hitting the initial breakpoint. If it was not set, the breakpoint should + // have already been resumed from and the private state should already be + // eStateRunning. SetID(process.GetProcessId()); return error; } @@ -346,22 +349,35 @@ Status ProcessWindows::DoResume() { ExceptionRecordSP active_exception = m_session_data->m_debugger->GetActiveException().lock(); if (active_exception) { - // Resume the process and continue processing debug events. Mask - // the exception so that from the process's view, there is no - // indication that anything happened. + // Resume the process and continue processing debug events. Mask the + // exception so that from the process's view, there is no indication that + // anything happened. m_session_data->m_debugger->ContinueAsyncException( ExceptionResult::MaskException); } LLDB_LOG(log, "resuming {0} threads.", m_thread_list.GetSize()); + bool failed = false; for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) { auto thread = std::static_pointer_cast<TargetThreadWindows>( m_thread_list.GetThreadAtIndex(i)); - thread->DoResume(); + Status result = thread->DoResume(); + if (result.Fail()) { + failed = true; + LLDB_LOG( + log, + "Trying to resume thread at index {0}, but failed with error {1}.", + i, result); + } } - SetPrivateState(eStateRunning); + if (failed) { + error.SetErrorString("ProcessWindows::DoResume failed"); + return error; + } else { + SetPrivateState(eStateRunning); + } } else { LLDB_LOG(log, "error: process %I64u is in state %u. Returning...", m_session_data->m_debugger->GetProcess().GetProcessId(), @@ -376,10 +392,9 @@ Status ProcessWindows::DoDestroy() { StateType private_state; { // Acquire this lock inside an inner scope, only long enough to get the - // DebuggerThread. - // StopDebugging() will trigger a call back into ProcessWindows which will - // acquire the lock - // again, so we need to not deadlock. + // DebuggerThread. StopDebugging() will trigger a call back into + // ProcessWindows which will acquire the lock again, so we need to not + // deadlock. llvm::sys::ScopedLock lock(m_mutex); private_state = GetPrivateState(); @@ -461,8 +476,9 @@ void ProcessWindows::RefreshStateAfterStop() { m_session_data->m_debugger->GetActiveException(); ExceptionRecordSP active_exception = exception_record.lock(); if (!active_exception) { - LLDB_LOG(log, "there is no active exception in process {0}. Why is the " - "process stopped?", + LLDB_LOG(log, + "there is no active exception in process {0}. Why is the " + "process stopped?", m_session_data->m_debugger->GetProcess().GetProcessId()); return; } @@ -479,8 +495,9 @@ void ProcessWindows::RefreshStateAfterStop() { const uint64_t pc = register_context->GetPC(); BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); if (site && site->ValidForThisThread(stop_thread.get())) { - LLDB_LOG(log, "Single-stepped onto a breakpoint in process {0} at " - "address {1:x} with breakpoint site {2}", + LLDB_LOG(log, + "Single-stepped onto a breakpoint in process {0} at " + "address {1:x} with breakpoint site {2}", m_session_data->m_debugger->GetProcess().GetProcessId(), pc, site->GetID()); stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread, @@ -502,22 +519,25 @@ void ProcessWindows::RefreshStateAfterStop() { BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); if (site) { - LLDB_LOG(log, "detected breakpoint in process {0} at address {1:x} with " - "breakpoint site {2}", + LLDB_LOG(log, + "detected breakpoint in process {0} at address {1:x} with " + "breakpoint site {2}", m_session_data->m_debugger->GetProcess().GetProcessId(), pc, site->GetID()); if (site->ValidForThisThread(stop_thread.get())) { - LLDB_LOG(log, "Breakpoint site {0} is valid for this thread ({1:x}), " - "creating stop info.", + LLDB_LOG(log, + "Breakpoint site {0} is valid for this thread ({1:x}), " + "creating stop info.", site->GetID(), stop_thread->GetID()); stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( *stop_thread, site->GetID()); register_context->SetPC(pc); } else { - LLDB_LOG(log, "Breakpoint site {0} is not valid for this thread, " - "creating empty stop info.", + LLDB_LOG(log, + "Breakpoint site {0} is not valid for this thread, " + "creating empty stop info.", site->GetID()); } stop_thread->SetStopInfo(stop_info); @@ -558,8 +578,8 @@ bool ProcessWindows::CanDebug(lldb::TargetSP target_sp, ModuleSP exe_module_sp(target_sp->GetExecutableModule()); if (exe_module_sp.get()) return exe_module_sp->GetFileSpec().Exists(); - // However, if there is no executable module, we return true since we might be - // preparing to attach. + // However, if there is no executable module, we return true since we might + // be preparing to attach. return true; } @@ -589,8 +609,8 @@ bool ProcessWindows::UpdateThreadList(ThreadList &old_thread_list, } } - // Also add all the threads that are new since the last time we broke into the - // debugger. + // Also add all the threads that are new since the last time we broke into + // the debugger. for (const auto &thread_info : m_session_data->m_new_threads) { ThreadSP thread(new TargetThreadWindows(*this, thread_info.second)); thread->SetID(thread_info.first); @@ -639,8 +659,13 @@ size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf, SIZE_T bytes_read = 0; if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, buf, size, &bytes_read)) { + // Reading from the process can fail for a number of reasons - set the + // error code and make sure that the number of bytes read is set back to 0 + // because in some scenarios the value of bytes_read returned from the API + // is garbage. error.SetError(GetLastError(), eErrorTypeWin32); LLDB_LOG(log, "reading failed with error: {0}", error); + bytes_read = 0; } return bytes_read; } @@ -699,11 +724,9 @@ Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr, SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info)); if (result == 0) { if (::GetLastError() == ERROR_INVALID_PARAMETER) { - // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with an - // address - // past the highest accessible address. We should return a range from the - // vm_addr - // to LLDB_INVALID_ADDRESS + // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with + // an address past the highest accessible address. We should return a + // range from the vm_addr to LLDB_INVALID_ADDRESS info.GetRange().SetRangeBase(vm_addr); info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); info.SetReadable(MemoryRegionInfo::eNo); @@ -713,8 +736,9 @@ Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr, return error; } else { error.SetError(::GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "VirtualQueryEx returned error {0} while getting memory " - "region info for address {1:x}", + LLDB_LOG(log, + "VirtualQueryEx returned error {0} while getting memory " + "region info for address {1:x}", error, vm_addr); return error; } @@ -744,10 +768,8 @@ Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr, info.SetMapped(MemoryRegionInfo::eYes); } else { // In the unmapped case we need to return the distance to the next block of - // memory. - // VirtualQueryEx nearly does that except that it gives the distance from - // the start - // of the page containing vm_addr. + // memory. VirtualQueryEx nearly does that except that it gives the + // distance from the start of the page containing vm_addr. SYSTEM_INFO data; GetSystemInfo(&data); DWORD page_offset = vm_addr % data.dwPageSize; @@ -757,8 +779,9 @@ Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr, } error.SetError(::GetLastError(), eErrorTypeWin32); - LLDB_LOGV(log, "Memory region info for address {0}: readable={1}, " - "executable={2}, writable={3}", + LLDB_LOGV(log, + "Memory region info for address {0}: readable={1}, " + "executable={2}, writable={3}", vm_addr, info.GetReadable(), info.GetExecutable(), info.GetWritable()); return error; @@ -779,7 +802,7 @@ void ProcessWindows::OnExitProcess(uint32_t exit_code) { Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code); - TargetSP target = m_target_sp.lock(); + TargetSP target = CalculateTarget(); if (target) { ModuleSP executable_module = target->GetExecutableModule(); ModuleList unloaded_modules; @@ -825,10 +848,9 @@ void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { GetTarget().ModulesDidLoad(loaded_modules); // Add the main executable module to the list of pending module loads. We - // can't call - // GetTarget().ModulesDidLoad() here because we still haven't returned from - // DoLaunch() / DoAttach() yet - // so the target may not have set the process instance to `this` yet. + // can't call GetTarget().ModulesDidLoad() here because we still haven't + // returned from DoLaunch() / DoAttach() yet so the target may not have set + // the process instance to `this` yet. llvm::sys::ScopedLock lock(m_mutex); const HostThreadWindows &wmain_thread = debugger->GetMainThread().GetNativeThread(); @@ -845,15 +867,14 @@ ProcessWindows::OnDebugException(bool first_chance, // FIXME: Without this check, occasionally when running the test suite there // is // an issue where m_session_data can be null. It's not clear how this could - // happen - // but it only surfaces while running the test suite. In order to properly - // diagnose - // this, we probably need to first figure allow the test suite to print out - // full - // lldb logs, and then add logging to the process plugin. + // happen but it only surfaces while running the test suite. In order to + // properly diagnose this, we probably need to first figure allow the test + // suite to print out full lldb logs, and then add logging to the process + // plugin. if (!m_session_data) { - LLDB_LOG(log, "Debugger thread reported exception {0:x} at address {1:x}, " - "but there is no session.", + LLDB_LOG(log, + "Debugger thread reported exception {0:x} at address {1:x}, " + "but there is no session.", record.GetExceptionCode(), record.GetExceptionAddress()); return ExceptionResult::SendToApplication; } @@ -887,8 +908,9 @@ ProcessWindows::OnDebugException(bool first_chance, SetPrivateState(eStateStopped); break; default: - LLDB_LOG(log, "Debugger thread reported exception {0:x} at address {1:x} " - "(first_chance={2})", + LLDB_LOG(log, + "Debugger thread reported exception {0:x} at address {1:x} " + "(first_chance={2})", record.GetExceptionCode(), record.GetExceptionAddress(), first_chance); // For non-breakpoints, give the application a chance to handle the @@ -929,9 +951,8 @@ void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) { // Confusingly, there is no Target::AddSharedModule. Instead, calling - // GetSharedModule() with - // a new module will add it to the module list and return a corresponding - // ModuleSP. + // GetSharedModule() with a new module will add it to the module list and + // return a corresponding ModuleSP. Status error; ModuleSP module = GetTarget().GetSharedModule(module_spec, &error); bool load_addr_changed = false; @@ -961,17 +982,16 @@ void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) { Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); if (m_session_data->m_initial_stop_received) { - // This happened while debugging. Do we shutdown the debugging session, try - // to continue, or do something else? - LLDB_LOG(log, "Error {0} occurred during debugging. Unexpected behavior " - "may result. {1}", + // This happened while debugging. Do we shutdown the debugging session, + // try to continue, or do something else? + LLDB_LOG(log, + "Error {0} occurred during debugging. Unexpected behavior " + "may result. {1}", error.GetError(), error); } else { // If we haven't actually launched the process yet, this was an error - // launching the - // process. Set the internal error and signal the initial stop event so - // that the DoLaunch - // method wakes up and returns a failure. + // launching the process. Set the internal error and signal the initial + // stop event so that the DoLaunch method wakes up and returns a failure. m_session_data->m_launch_error = error; ::SetEvent(m_session_data->m_initial_stop_event); LLDB_LOG( @@ -1001,9 +1021,9 @@ Status ProcessWindows::WaitForDebuggerConnection(DebuggerThreadSP debugger, } // The Windows page protection bits are NOT independent masks that can be -// bitwise-ORed together. For example, PAGE_EXECUTE_READ is not -// (PAGE_EXECUTE | PAGE_READ). To test for an access type, it's necessary to -// test for any of the bits that provide that access type. +// bitwise-ORed together. For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE +// | PAGE_READ). To test for an access type, it's necessary to test for any of +// the bits that provide that access type. bool ProcessWindows::IsPageReadable(uint32_t protect) { return (protect & PAGE_NOACCESS) == 0; } diff --git a/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp index a4d60303877e..3903280918cc 100644 --- a/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp +++ b/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp @@ -16,10 +16,10 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/Logging.h" +#include "Plugins/Process/Utility/UnwindLLDB.h" #include "ProcessWindows.h" #include "ProcessWindowsLog.h" #include "TargetThreadWindows.h" -#include "UnwindLLDB.h" #if defined(_WIN64) #include "x64/RegisterContextWindows_x64.h" @@ -33,7 +33,7 @@ using namespace lldb_private; TargetThreadWindows::TargetThreadWindows(ProcessWindows &process, const HostThread &thread) : Thread(process, thread.GetNativeThread().GetThreadId()), - m_host_thread(thread) {} + m_thread_reg_ctx_sp(), m_host_thread(thread) {} TargetThreadWindows::~TargetThreadWindows() { DestroyThread(); } @@ -49,40 +49,53 @@ void TargetThreadWindows::DidStop() {} RegisterContextSP TargetThreadWindows::GetRegisterContext() { if (!m_reg_context_sp) - m_reg_context_sp = CreateRegisterContextForFrameIndex(0); + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); return m_reg_context_sp; } RegisterContextSP TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame) { - return CreateRegisterContextForFrameIndex(frame->GetConcreteFrameIndex()); -} - -RegisterContextSP -TargetThreadWindows::CreateRegisterContextForFrameIndex(uint32_t idx) { - if (!m_reg_context_sp) { - ArchSpec arch = HostInfo::GetArchitecture(); - switch (arch.GetMachine()) { - case llvm::Triple::x86: + RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); + + if (concrete_frame_idx == 0) { + if (!m_thread_reg_ctx_sp) { + ArchSpec arch = HostInfo::GetArchitecture(); + switch (arch.GetMachine()) { + case llvm::Triple::x86: #if defined(_WIN64) -// FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64 + // FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64 + LLDB_LOG(log, "This is a Wow64 process, we should create a " + "RegisterContextWindows_Wow64, but we don't."); #else - m_reg_context_sp.reset(new RegisterContextWindows_x86(*this, idx)); + m_thread_reg_ctx_sp.reset( + new RegisterContextWindows_x86(*this, concrete_frame_idx)); #endif - break; - case llvm::Triple::x86_64: + break; + case llvm::Triple::x86_64: #if defined(_WIN64) - m_reg_context_sp.reset(new RegisterContextWindows_x64(*this, idx)); + m_thread_reg_ctx_sp.reset( + new RegisterContextWindows_x64(*this, concrete_frame_idx)); #else -// LLDB is 32-bit, but the target process is 64-bit. We probably can't debug -// this. + LLDB_LOG(log, "LLDB is 32-bit, but the target process is 64-bit."); #endif - default: - break; + default: + break; + } } + reg_ctx_sp = m_thread_reg_ctx_sp; + } else { + Unwind *unwinder = GetUnwinder(); + if (unwinder != nullptr) + reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); } - return m_reg_context_sp; + + return reg_ctx_sp; } bool TargetThreadWindows::CalculateStopInfo() { @@ -93,16 +106,16 @@ bool TargetThreadWindows::CalculateStopInfo() { Unwind *TargetThreadWindows::GetUnwinder() { // FIXME: Implement an unwinder based on the Windows unwinder exposed through // DIA SDK. - if (m_unwinder_ap.get() == NULL) + if (!m_unwinder_ap) m_unwinder_ap.reset(new UnwindLLDB(*this)); return m_unwinder_ap.get(); } -bool TargetThreadWindows::DoResume() { +Status TargetThreadWindows::DoResume() { StateType resume_state = GetTemporaryResumeState(); StateType current_state = GetState(); if (resume_state == current_state) - return true; + return Status(); if (resume_state == eStateStepping) { uint32_t flags_index = @@ -118,8 +131,17 @@ bool TargetThreadWindows::DoResume() { DWORD previous_suspend_count = 0; HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle(); do { + // ResumeThread returns -1 on error, or the thread's *previous* suspend + // count on success. This means that the return value is 1 when the thread + // was restarted. Note that DWORD is an unsigned int, so we need to + // explicitly compare with -1. previous_suspend_count = ::ResumeThread(thread_handle); - } while (previous_suspend_count > 0); + + if (previous_suspend_count == (DWORD)-1) + return Status(::GetLastError(), eErrorTypeWin32); + + } while (previous_suspend_count > 1); } - return true; + + return Status(); } diff --git a/source/Plugins/Process/Windows/Common/TargetThreadWindows.h b/source/Plugins/Process/Windows/Common/TargetThreadWindows.h index 8b4e3dfdda4a..952c0f55b57f 100644 --- a/source/Plugins/Process/Windows/Common/TargetThreadWindows.h +++ b/source/Plugins/Process/Windows/Common/TargetThreadWindows.h @@ -37,15 +37,14 @@ public: bool CalculateStopInfo() override; Unwind *GetUnwinder() override; - bool DoResume(); + Status DoResume(); HostThread GetHostThread() const { return m_host_thread; } private: - lldb::RegisterContextSP CreateRegisterContextForFrameIndex(uint32_t idx); - + lldb::RegisterContextSP m_thread_reg_ctx_sp; HostThread m_host_thread; }; -} +} // namespace lldb_private #endif diff --git a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp index e64bade5ff90..4aa6c785f83c 100644 --- a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp +++ b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp @@ -14,9 +14,9 @@ #include "lldb/lldb-private-types.h" #include "RegisterContextWindows_x64.h" -#include "RegisterContext_x86.h" +#include "Plugins/Process/Utility/RegisterContext_x86.h" #include "TargetThreadWindows.h" -#include "lldb-x86-register-enums.h" +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" #include "llvm/ADT/STLExtras.h" @@ -29,14 +29,11 @@ using namespace lldb_private; namespace { // This enum defines the layout of the global RegisterInfo array. This is -// necessary because -// lldb register sets are defined in terms of indices into the register array. -// As such, the -// order of RegisterInfos defined in global registers array must match the order -// defined here. -// When defining the register set layouts, these values can appear in an -// arbitrary order, and that -// determines the order that register values are displayed in a dump. +// necessary because lldb register sets are defined in terms of indices into +// the register array. As such, the order of RegisterInfos defined in global +// registers array must match the order defined here. When defining the +// register set layouts, these values can appear in an arbitrary order, and +// that determines the order that register values are displayed in a dump. enum RegisterIndex { eRegisterIndexRax, eRegisterIndexRbx, @@ -44,6 +41,8 @@ enum RegisterIndex { eRegisterIndexRdx, eRegisterIndexRdi, eRegisterIndexRsi, + eRegisterIndexRbp, + eRegisterIndexRsp, eRegisterIndexR8, eRegisterIndexR9, eRegisterIndexR10, @@ -52,8 +51,6 @@ enum RegisterIndex { eRegisterIndexR13, eRegisterIndexR14, eRegisterIndexR15, - eRegisterIndexRbp, - eRegisterIndexRsp, eRegisterIndexRip, eRegisterIndexRflags }; @@ -96,6 +93,16 @@ RegisterInfo g_register_infos[] = { LLDB_INVALID_REGNUM, lldb_rsi_x86_64}, nullptr, nullptr}, + {DEFINE_GPR(rbp, "fp"), + {dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, + LLDB_INVALID_REGNUM, lldb_rbp_x86_64}, + nullptr, + nullptr}, + {DEFINE_GPR(rsp, "sp"), + {dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, + LLDB_INVALID_REGNUM, lldb_rsp_x86_64}, + nullptr, + nullptr}, {DEFINE_GPR(r8, nullptr), {dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r8_x86_64}, @@ -136,16 +143,6 @@ RegisterInfo g_register_infos[] = { LLDB_INVALID_REGNUM, lldb_r15_x86_64}, nullptr, nullptr}, - {DEFINE_GPR(rbp, "fp"), - {dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, - LLDB_INVALID_REGNUM, lldb_rbp_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rsp, "sp"), - {dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, - LLDB_INVALID_REGNUM, lldb_rsp_x86_64}, - nullptr, - nullptr}, {DEFINE_GPR(rip, "pc"), {dwarf_rip_x86_64, dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, lldb_rip_x86_64}, @@ -165,10 +162,10 @@ static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos); uint32_t g_gpr_reg_indices[] = { eRegisterIndexRax, eRegisterIndexRbx, eRegisterIndexRcx, eRegisterIndexRdx, eRegisterIndexRdi, eRegisterIndexRsi, - eRegisterIndexR8, eRegisterIndexR9, eRegisterIndexR10, - eRegisterIndexR11, eRegisterIndexR12, eRegisterIndexR13, - eRegisterIndexR14, eRegisterIndexR15, eRegisterIndexRbp, - eRegisterIndexRsp, eRegisterIndexRip, eRegisterIndexRflags}; + eRegisterIndexRbp, eRegisterIndexRsp, eRegisterIndexR8, + eRegisterIndexR9, eRegisterIndexR10, eRegisterIndexR11, + eRegisterIndexR12, eRegisterIndexR13, eRegisterIndexR14, + eRegisterIndexR15, eRegisterIndexRip, eRegisterIndexRflags}; RegisterSet g_register_sets[] = { {"General Purpose Registers", "gpr", @@ -209,6 +206,9 @@ bool RegisterContextWindows_x64::ReadRegister(const RegisterInfo *reg_info, if (!CacheAllRegisterValues()) return false; + if (reg_info == nullptr) + return false; + switch (reg_info->kinds[eRegisterKindLLDB]) { case lldb_rax_x86_64: reg_value.SetUInt64(m_context.Rax); @@ -270,11 +270,10 @@ bool RegisterContextWindows_x64::ReadRegister(const RegisterInfo *reg_info, bool RegisterContextWindows_x64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue ®_value) { - // Since we cannot only write a single register value to the inferior, we need - // to make sure - // our cached copy of the register values are fresh. Otherwise when writing - // EAX, for example, - // we may also overwrite some other register with a stale value. + // Since we cannot only write a single register value to the inferior, we + // need to make sure our cached copy of the register values are fresh. + // Otherwise when writing EAX, for example, we may also overwrite some other + // register with a stale value. if (!CacheAllRegisterValues()) return false; diff --git a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp index f56836de4a67..fd486f3d0829 100644 --- a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp +++ b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp @@ -15,9 +15,9 @@ #include "ProcessWindowsLog.h" #include "RegisterContextWindows_x86.h" -#include "RegisterContext_x86.h" +#include "Plugins/Process/Utility/RegisterContext_x86.h" #include "TargetThreadWindows.h" -#include "lldb-x86-register-enums.h" +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" #include "llvm/ADT/STLExtras.h" @@ -30,14 +30,11 @@ using namespace lldb_private; namespace { // This enum defines the layout of the global RegisterInfo array. This is -// necessary because -// lldb register sets are defined in terms of indices into the register array. -// As such, the -// order of RegisterInfos defined in global registers array must match the order -// defined here. -// When defining the register set layouts, these values can appear in an -// arbitrary order, and that -// determines the order that register values are displayed in a dump. +// necessary because lldb register sets are defined in terms of indices into +// the register array. As such, the order of RegisterInfos defined in global +// registers array must match the order defined here. When defining the +// register set layouts, these values can appear in an arbitrary order, and +// that determines the order that register values are displayed in a dump. enum RegisterIndex { eRegisterIndexEax, eRegisterIndexEbx, @@ -179,6 +176,9 @@ bool RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info, if (!CacheAllRegisterValues()) return false; + if (reg_info == nullptr) + return false; + uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; switch (reg) { case lldb_eax_i386: @@ -212,11 +212,10 @@ bool RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info, bool RegisterContextWindows_x86::WriteRegister(const RegisterInfo *reg_info, const RegisterValue ®_value) { - // Since we cannot only write a single register value to the inferior, we need - // to make sure - // our cached copy of the register values are fresh. Otherwise when writing - // EAX, for example, - // we may also overwrite some other register with a stale value. + // Since we cannot only write a single register value to the inferior, we + // need to make sure our cached copy of the register values are fresh. + // Otherwise when writing EAX, for example, we may also overwrite some other + // register with a stale value. if (!CacheAllRegisterValues()) return false; diff --git a/source/Plugins/Process/elf-core/CMakeLists.txt b/source/Plugins/Process/elf-core/CMakeLists.txt index 3082c73f6dda..9b6739824c06 100644 --- a/source/Plugins/Process/elf-core/CMakeLists.txt +++ b/source/Plugins/Process/elf-core/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(../Utility) - add_lldb_library(lldbPluginProcessElfCore PLUGIN ProcessElfCore.cpp ThreadElfCore.cpp diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 7d6a0c9ad2df..7bb7b72eaac1 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -56,9 +56,9 @@ lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp, const FileSpec *crash_file) { lldb::ProcessSP process_sp; if (crash_file) { - // Read enough data for a ELF32 header or ELF64 header - // Note: Here we care about e_type field only, so it is safe - // to ignore possible presence of the header extension. + // Read enough data for a ELF32 header or ELF64 header Note: Here we care + // about e_type field only, so it is safe to ignore possible presence of + // the header extension. const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr); auto data_sp = DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), @@ -107,10 +107,10 @@ ProcessElfCore::ProcessElfCore(lldb::TargetSP target_sp, //---------------------------------------------------------------------- ProcessElfCore::~ProcessElfCore() { Clear(); - // We need to call finalize on the process before destroying ourselves - // to make sure all of the broadcaster cleanup goes as planned. If we - // destruct this class, then Process::~Process() might have problems - // trying to fully destroy the broadcaster. + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. Finalize(); } @@ -206,8 +206,8 @@ Status ProcessElfCore::DoLoadCore() { m_core_range_infos.Sort(); } - // Even if the architecture is set in the target, we need to override - // it to match the core file which is always single arch. + // Even if the architecture is set in the target, we need to override it to + // match the core file which is always single arch. ArchSpec arch(m_core_module_sp->GetArchitecture()); ArchSpec target_arch = GetTarget().GetArchitecture(); @@ -241,8 +241,7 @@ Status ProcessElfCore::DoLoadCore() { } // Core files are useless without the main executable. See if we can locate - // the main - // executable using data we found in the core file notes. + // the main executable using data we found in the core file notes. lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); if (!exe_module_sp) { // The first entry in the NT_FILE might be our executable @@ -250,7 +249,8 @@ 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); + m_nt_file_entries[0].path.GetCString(), false, + FileSpec::Style::native); if (exe_module_spec.GetFileSpec()) { exe_module_sp = GetTarget().GetSharedModule(exe_module_spec); if (exe_module_sp) @@ -297,8 +297,8 @@ bool ProcessElfCore::IsAlive() { return true; } //------------------------------------------------------------------ size_t ProcessElfCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { - // Don't allow the caching that lldb_private::Process::ReadMemory does - // since in core files we have it all cached our our core file anyway. + // Don't allow the caching that lldb_private::Process::ReadMemory does since + // in core files we have it all cached our our core file anyway. return DoReadMemory(addr, buf, size, error); } @@ -368,17 +368,18 @@ size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb::addr_t bytes_left = 0; // Number of bytes available in the core file from the given address - // Don't proceed if core file doesn't contain the actual data for this address range. + // Don't proceed if core file doesn't contain the actual data for this + // address range. if (file_start == file_end) return 0; - // Figure out how many on-disk bytes remain in this segment - // starting at the given offset + // Figure out how many on-disk bytes remain in this segment starting at the + // given offset if (file_end > file_start + offset) bytes_left = file_end - (file_start + offset); - // Figure out how many bytes we need to zero-fill if we are - // reading more bytes than available in the on-disk segment + // Figure out how many bytes we need to zero-fill if we are reading more + // bytes than available in the on-disk segment if (bytes_to_read > bytes_left) { zero_fill_size = bytes_to_read - bytes_left; bytes_to_read = bytes_left; @@ -551,8 +552,8 @@ llvm::Error ProcessElfCore::parseFreeBSDNotes(llvm::ArrayRef<CoreNote> notes) { llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) { ThreadData thread_data; for (const auto ¬e : notes) { - // NetBSD per-thread information is stored in notes named - // "NetBSD-CORE@nnn" so match on the initial part of the string. + // NetBSD per-thread information is stored in notes named "NetBSD-CORE@nnn" + // so match on the initial part of the string. if (!llvm::StringRef(note.info.n_name).startswith("NetBSD-CORE")) continue; @@ -585,8 +586,8 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) { llvm::Error ProcessElfCore::parseOpenBSDNotes(llvm::ArrayRef<CoreNote> notes) { ThreadData thread_data; for (const auto ¬e : notes) { - // OpenBSD per-thread information is stored in notes named - // "OpenBSD@nnn" so match on the initial part of the string. + // OpenBSD per-thread information is stored in notes named "OpenBSD@nnn" so + // match on the initial part of the string. if (!llvm::StringRef(note.info.n_name).startswith("OpenBSD")) continue; @@ -665,7 +666,7 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef<CoreNote> notes) { Status status = prpsinfo.Parse(note.data, arch); if (status.Fail()) return status.ToError(); - thread_data.name = prpsinfo.pr_fname; + thread_data.name.assign (prpsinfo.pr_fname, strnlen (prpsinfo.pr_fname, sizeof (prpsinfo.pr_fname))); SetID(prpsinfo.pr_pid); break; } @@ -749,9 +750,9 @@ ArchSpec ProcessElfCore::GetArchitecture() { ArchSpec target_arch = GetTarget().GetArchitecture(); arch.MergeFrom(target_arch); - // On MIPS there is no way to differentiate betwenn 32bit and 64bit core files - // and this information can't be merged in from the target arch so we fail - // back to unconditionally returning the target arch in this config. + // On MIPS there is no way to differentiate betwenn 32bit and 64bit core + // files and this information can't be merged in from the target arch so we + // fail back to unconditionally returning the target arch in this config. if (target_arch.IsMIPS()) { return target_arch; } diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp index e252b5a35e9c..532a1f5c0831 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp @@ -56,7 +56,7 @@ bool RegisterContextCorePOSIX_mips64::ReadRegister(const RegisterInfo *reg_info, if (IsGPR(reg_info->kinds[lldb::eRegisterKindLLDB])) { if (reg_info->byte_size == 4 && !(arch.GetMachine() == llvm::Triple::mips64el)) // In case of 32bit core file, the register data are placed at 4 byte - // offset. + // offset. offset = offset / 2; v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); value = v; diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp index a5c7ffda1da5..a1f26d52444b 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp @@ -60,8 +60,8 @@ bool RegisterContextCorePOSIX_x86_64::ReadRegister(const RegisterInfo *reg_info, const uint8_t *src; size_t offset; const size_t fxsave_offset = reg_info->byte_offset - GetFXSAVEOffset(); - // make the offset relative to the beginning of the FXSAVE structure - // because this is the data that we have (not the entire UserArea) + // make the offset relative to the beginning of the FXSAVE structure because + // this is the data that we have (not the entire UserArea) if (m_gpregset && reg_info->byte_offset < GetGPRSize()) { src = m_gpregset.get(); diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 10c1ed288b2c..d9b90c8e902e 100644 --- a/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -55,16 +55,9 @@ void ThreadElfCore::RefreshStateAfterStop() { GetRegisterContext()->InvalidateIfNeeded(false); } -void ThreadElfCore::ClearStackFrames() { - Unwind *unwinder = GetUnwinder(); - if (unwinder) - unwinder->Clear(); - Thread::ClearStackFrames(); -} - RegisterContextSP ThreadElfCore::GetRegisterContext() { - if (m_reg_context_sp.get() == NULL) { - m_reg_context_sp = CreateRegisterContextForFrame(NULL); + if (!m_reg_context_sp) { + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); } return m_reg_context_sp; } @@ -84,7 +77,7 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get()); ArchSpec arch = process->GetArchitecture(); - RegisterInfoInterface *reg_interface = NULL; + RegisterInfoInterface *reg_interface = nullptr; switch (arch.GetTriple().getOS()) { case llvm::Triple::FreeBSD: { @@ -234,8 +227,10 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { } reg_ctx_sp = m_thread_reg_ctx_sp; - } else if (m_unwinder_ap.get()) { - reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame(frame); + } else { + Unwind *unwinder = GetUnwinder(); + if (unwinder != nullptr) + reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); } return reg_ctx_sp; } @@ -292,8 +287,8 @@ Status ELFLinuxPrStatus::Parse(const DataExtractor &data, return error; } - // Read field by field to correctly account for endianess - // of both the core dump and the platform running lldb. + // Read field by field to correctly account for endianess of both the core + // dump and the platform running lldb. offset_t offset = 0; si_signo = data.GetU32(&offset); si_code = data.GetU32(&offset); @@ -340,7 +335,7 @@ size_t ELFLinuxPrPsInfo::GetSize(const lldb_private::ArchSpec &arch) { return sizeof(ELFLinuxPrPsInfo); return mips_linux_pr_psinfo_size_o32_n32; } - + switch (arch.GetCore()) { case lldb_private::ArchSpec::eCore_s390x_generic: case lldb_private::ArchSpec::eCore_x86_64_x86_64: @@ -382,9 +377,9 @@ Status ELFLinuxPrPsInfo::Parse(const DataExtractor &data, pr_uid = data.GetU32(&offset); pr_gid = data.GetU32(&offset); } else { - // 16 bit on 32 bit platforms, 32 bit on 64 bit platforms - pr_uid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1); - pr_gid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1); + // 16 bit on 32 bit platforms, 32 bit on 64 bit platforms + pr_uid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1); + pr_gid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1); } pr_pid = data.GetU32(&offset); diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.h b/source/Plugins/Process/elf-core/ThreadElfCore.h index 335f698dbb24..167fd6edc4ce 100644 --- a/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -146,8 +146,6 @@ public: lldb::RegisterContextSP CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; - void ClearStackFrames() override; - static bool ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; } const char *GetName() override { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp index 4d4a4f8c5c7a..4e20b56fb111 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -109,16 +109,14 @@ StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse( const bool should_stop = ShouldStop(signals, response); response.SetFilePos(0); - // The packet we should resume with. In the future - // we should check our thread list and "do the right thing" - // for new threads that show up while we stop and run async - // packets. Setting the packet to 'c' to continue all threads - // is the right thing to do 99.99% of the time because if a - // thread was single stepping, and we sent an interrupt, we - // will notice above that we didn't stop due to an interrupt - // but stopped due to stepping and we would _not_ continue. - // This packet may get modified by the async actions (e.g. to send a - // signal). + // The packet we should resume with. In the future we should check our + // thread list and "do the right thing" for new threads that show up + // while we stop and run async packets. Setting the packet to 'c' to + // continue all threads is the right thing to do 99.99% of the time + // because if a thread was single stepping, and we sent an interrupt, we + // will notice above that we didn't stop due to an interrupt but stopped + // due to stepping and we would _not_ continue. This packet may get + // modified by the async actions (e.g. to send a signal). m_continue_packet = 'c'; cont_lock.unlock(); @@ -177,6 +175,30 @@ GDBRemoteClientBase::SendPacketAndWaitForResponse( } GDBRemoteCommunication::PacketResult +GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport( + llvm::StringRef payload, StringExtractorGDBRemote &response, + bool send_async, + llvm::function_ref<void(llvm::StringRef)> output_callback) { + Lock lock(*this, send_async); + if (!lock) { + if (Log *log = + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)) + log->Printf("GDBRemoteClientBase::%s failed to get mutex, not sending " + "packet '%.*s' (send_async=%d)", + __FUNCTION__, int(payload.size()), payload.data(), + send_async); + return PacketResult::ErrorSendFailed; + } + + PacketResult packet_result = SendPacketNoLock(payload); + if (packet_result != PacketResult::Success) + return packet_result; + + return ReadPacketWithOutputSupport(response, GetPacketTimeout(), true, + output_callback); +} + +GDBRemoteCommunication::PacketResult GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock( llvm::StringRef payload, StringExtractorGDBRemote &response) { PacketResult packet_result = SendPacketNoLock(payload); @@ -239,19 +261,16 @@ bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals, if (m_async_count == 0) return true; // We were not interrupted. The process stopped on its own. - // Older debugserver stubs (before April 2016) can return two - // stop-reply packets in response to a ^C packet. - // Additionally, all debugservers still return two stop replies if - // the inferior stops due to some other reason before the remote - // stub manages to interrupt it. We need to wait for this - // additional packet to make sure the packet sequence does not get - // skewed. + // Older debugserver stubs (before April 2016) can return two stop-reply + // packets in response to a ^C packet. Additionally, all debugservers still + // return two stop replies if the inferior stops due to some other reason + // before the remote stub manages to interrupt it. We need to wait for this + // additional packet to make sure the packet sequence does not get skewed. StringExtractorGDBRemote extra_stop_reply_packet; ReadPacket(extra_stop_reply_packet, milliseconds(100), false); - // Interrupting is typically done using SIGSTOP or SIGINT, so if - // the process stops with some other signal, we definitely want to - // stop. + // Interrupting is typically done using SIGSTOP or SIGINT, so if the process + // stops with some other signal, we definitely want to stop. const uint8_t signo = response.GetHexU8(UINT8_MAX); if (signo != signals.GetSignalNumberFromName("SIGSTOP") && signo != signals.GetSignalNumberFromName("SIGINT")) diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h b/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h index 2646405c9b91..3d84ce0ebe18 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h @@ -48,6 +48,11 @@ public: StringExtractorGDBRemote &response, bool send_async); + PacketResult SendPacketAndReceiveResponseWithOutputSupport( + llvm::StringRef payload, StringExtractorGDBRemote &response, + bool send_async, + llvm::function_ref<void(llvm::StringRef)> output_callback); + bool SendvContPacket(llvm::StringRef payload, StringExtractorGDBRemote &response); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 949cf19db658..c335b6002861 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -150,9 +150,8 @@ GDBRemoteCommunication::~GDBRemoteCommunication() { Disconnect(); } - // Stop the communications read thread which is used to parse all - // incoming packets. This function will block until the read - // thread returns. + // 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) StopReadThread(); } @@ -217,12 +216,10 @@ GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) { } } - // If logging was just enabled and we have history, then dump out what - // we have to the log so we get the historical context. The Dump() call - // that + // If logging was just enabled and we have history, then dump out what we + // have to the log so we get the historical context. The Dump() call that // logs all of the packet will set a boolean so that we don't dump this - // more - // than once + // more than once if (!m_history.DidDumpToLog()) m_history.Dump(log); @@ -275,6 +272,23 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunication::GetAck() { } GDBRemoteCommunication::PacketResult +GDBRemoteCommunication::ReadPacketWithOutputSupport( + StringExtractorGDBRemote &response, Timeout<std::micro> timeout, + bool sync_on_timeout, + llvm::function_ref<void(llvm::StringRef)> output_callback) { + auto result = ReadPacket(response, timeout, sync_on_timeout); + while (result == PacketResult::Success && response.IsNormalResponse() && + response.PeekChar() == 'O') { + response.GetChar(); + std::string output; + if (response.GetHexByteString(output)) + output_callback(output); + result = ReadPacket(response, timeout, sync_on_timeout); + } + return result; +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response, Timeout<std::micro> timeout, bool sync_on_timeout) { @@ -286,8 +300,8 @@ GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response, // This function is called when a packet is requested. // A whole packet is popped from the packet queue and returned to the caller. -// Packets are placed into this queue from the communication read thread. -// See GDBRemoteCommunication::AppendBytesToCache. +// Packets are placed into this queue from the communication read thread. See +// GDBRemoteCommunication::AppendBytesToCache. GDBRemoteCommunication::PacketResult GDBRemoteCommunication::PopPacketFromQueue(StringExtractorGDBRemote &response, Timeout<std::micro> timeout) { @@ -407,11 +421,9 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, break; } else if (successful_responses == 1) { // We got something else back as the first successful - // response, it probably is - // the response to the packet we actually wanted, so copy it - // over if this - // is the first success and continue to try to get the qEcho - // response + // response, it probably is the response to the packet we + // actually wanted, so copy it over if this is the first + // success and continue to try to get the qEcho response packet = echo_response; got_actual_response = true; } @@ -424,14 +436,13 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, } // We weren't able to sync back up with the server, we must abort - // otherwise - // all responses might not be from the right packets... + // otherwise all responses might not be from the right packets... if (sync_success) { // We timed out, but were able to recover if (got_actual_response) { // We initially timed out, but we did get a response that came in - // before the successful - // reply to our qEcho packet, so lets say everything is fine... + // before the successful reply to our qEcho packet, so lets say + // everything is fine... return PacketResult::Success; } } else { @@ -473,10 +484,9 @@ bool GDBRemoteCommunication::DecompressPacket() { size_t pkt_size = m_bytes.size(); - // Smallest possible compressed packet is $N#00 - an uncompressed empty reply, - // most commonly indicating - // an unsupported packet. Anything less than 5 characters, it's definitely - // not a compressed packet. + // Smallest possible compressed packet is $N#00 - an uncompressed empty + // reply, most commonly indicating an unsupported packet. Anything less than + // 5 characters, it's definitely not a compressed packet. if (pkt_size < 5) return true; @@ -505,17 +515,15 @@ bool GDBRemoteCommunication::DecompressPacket() { 1; // The first character of the two hex checksum characters // Normally size_of_first_packet == m_bytes.size() but m_bytes may contain - // multiple packets. - // size_of_first_packet is the size of the initial packet which we'll replace - // with the decompressed - // version of, leaving the rest of m_bytes unmodified. + // multiple packets. size_of_first_packet is the size of the initial packet + // which we'll replace with the decompressed version of, leaving the rest of + // m_bytes unmodified. size_t size_of_first_packet = hash_mark_idx + 3; // Compressed packets ("$C") start with a base10 number which is the size of - // the uncompressed payload, - // then a : and then the compressed data. e.g. $C1024:<binary>#00 - // Update content_start and content_length to only include the <binary> part - // of the packet. + // the uncompressed payload, then a : and then the compressed data. e.g. + // $C1024:<binary>#00 Update content_start and content_length to only include + // the <binary> part of the packet. uint64_t decompressed_bufsize = ULONG_MAX; if (m_bytes[1] == 'C') { @@ -564,15 +572,14 @@ bool GDBRemoteCommunication::DecompressPacket() { } if (m_bytes[1] == 'N') { - // This packet was not compressed -- delete the 'N' character at the - // start and the packet may be processed as-is. + // This packet was not compressed -- delete the 'N' character at the start + // and the packet may be processed as-is. m_bytes.erase(1, 1); return true; } - // Reverse the gdb-remote binary escaping that was done to the compressed text - // to - // guard characters like '$', '#', '}', etc. + // Reverse the gdb-remote binary escaping that was done to the compressed + // text to guard characters like '$', '#', '}', etc. std::vector<uint8_t> unescaped_content; unescaped_content.reserve(content_length); size_t i = content_start; @@ -613,12 +620,10 @@ 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 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 (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr) { decompressed_bytes = compression_decode_buffer( @@ -706,9 +711,8 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, // Parse up the packets into gdb remote packets if (!m_bytes.empty()) { - // end_idx must be one past the last valid packet byte. Start - // it off with an invalid value that is the same as the current - // index. + // end_idx must be one past the last valid packet byte. Start it off with + // an invalid value that is the same as the current index. size_t content_start = 0; size_t content_length = 0; size_t total_length = 0; @@ -743,7 +747,8 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, checksum_idx = hash_pos + 1; // Skip the dollar sign content_start = 1; - // Don't include the # in the content or the $ in the content length + // Don't include the # in the content or the $ in the content + // length content_length = hash_pos - 1; total_length = @@ -757,11 +762,10 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, break; default: { - // We have an unexpected byte and we need to flush all bad - // data that is in m_bytes, so we need to find the first - // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt), - // or '$' character (start of packet header) or of course, - // the end of the data in m_bytes... + // We have an unexpected byte and we need to flush all bad data that is + // in m_bytes, so we need to find the first byte that is a '+' (ACK), '-' + // (NACK), \x03 (CTRL+C interrupt), or '$' character (start of packet + // header) or of course, the end of the data in m_bytes... const size_t bytes_len = m_bytes.size(); bool done = false; uint32_t idx; @@ -802,16 +806,14 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, if (log) { // If logging was just enabled and we have history, then dump out what // we have to the log so we get the historical context. The Dump() call - // that - // logs all of the packet will set a boolean so that we don't dump this - // more - // than once + // that logs all of the packet will set a boolean so that we don't dump + // this more than once if (!m_history.DidDumpToLog()) m_history.Dump(log); bool binary = false; - // Only detect binary for packets that start with a '$' and have a '#CC' - // checksum + // Only detect binary for packets that start with a '$' and have a + // '#CC' checksum if (m_bytes[0] == '$' && total_length > 4) { for (size_t i = 0; !binary && i < total_length; ++i) { unsigned char c = m_bytes[i]; @@ -834,8 +836,8 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, // Remove binary escaped bytes when displaying the packet... const char ch = m_bytes[i]; if (ch == 0x7d) { - // 0x7d is the escape character. The next character is to - // be XOR'd with 0x20. + // 0x7d is the escape character. The next character is to be + // XOR'd with 0x20. const char escapee = m_bytes[++i] ^ 0x20; strm.Printf("%2.2x", escapee); } else { @@ -863,26 +865,25 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, // Clear packet_str in case there is some existing data in it. packet_str.clear(); - // Copy the packet from m_bytes to packet_str expanding the - // run-length encoding in the process. - // Reserve enough byte for the most common case (no RLE used) + // Copy the packet from m_bytes to packet_str expanding the run-length + // encoding in the process. Reserve enough byte for the most common case + // (no RLE used) packet_str.reserve(m_bytes.length()); for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_end; ++c) { if (*c == '*') { - // '*' indicates RLE. Next character will give us the - // repeat count and previous character is what is to be - // repeated. + // '*' indicates RLE. Next character will give us the repeat count + // and previous character is what is to be repeated. char char_to_repeat = packet_str.back(); // Number of time the previous character is repeated int repeat_count = *++c + 3 - ' '; - // We have the char_to_repeat and repeat_count. Now push - // it in the packet. + // We have the char_to_repeat and repeat_count. Now push it in the + // packet. for (int i = 0; i < repeat_count; ++i) packet_str.push_back(char_to_repeat); } else if (*c == 0x7d) { - // 0x7d is the escape character. The next character is to - // be XOR'd with 0x20. + // 0x7d is the escape character. The next character is to be XOR'd + // with 0x20. char escapee = *++c ^ 0x20; packet_str.push_back(escapee); } else { @@ -897,7 +898,8 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, if (GetSendAcks()) { const char *packet_checksum_cstr = &m_bytes[checksum_idx]; char packet_checksum = strtol(packet_checksum_cstr, NULL, 16); - char actual_checksum = CalculcateChecksum(packet_str); + char actual_checksum = CalculcateChecksum( + llvm::StringRef(m_bytes).slice(content_start, content_end)); success = packet_checksum == actual_checksum; if (!success) { if (log) @@ -991,11 +993,12 @@ Status GDBRemoteCommunication::StartDebugserverProcess( char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); - // Always check to see if we have an environment override for the path - // to the debugserver to use and use it if we do. + // Always check to see if we have an environment override for the path to the + // 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, false, + FileSpec::Style::native); if (log) log->Printf("GDBRemoteCommunication::%s() gdb-remote stub exe path set " "from environment variable: %s", @@ -1004,10 +1007,9 @@ Status GDBRemoteCommunication::StartDebugserverProcess( debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = debugserver_file_spec.Exists(); if (!debugserver_exists) { - // The debugserver binary is in the LLDB.framework/Resources - // directory. - if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, - debugserver_file_spec)) { + // 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(); if (debugserver_exists) { @@ -1031,8 +1033,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( __FUNCTION__, debugserver_file_spec.GetPath().c_str()); } // Don't cache the platform specific GDB server binary as it could - // change - // from platform to platform + // change from platform to platform g_debugserver_file_spec.Clear(); } } @@ -1080,14 +1081,14 @@ Status GDBRemoteCommunication::StartDebugserverProcess( // once data is written to the pipe, debug server is up and running. Pipe socket_pipe; - // port is null when debug server should listen on domain socket - - // we're not interested in port value but rather waiting for debug server - // to become available. + // port is null when debug server should listen on domain socket - we're + // not interested in port value but rather waiting for debug server to + // become available. if (pass_comm_fd == -1) { if (url) { -// Create a temporary file to get the stdout/stderr and redirect the -// output of the command into this file. We will later read this file -// if all goes well and fill the data into "command_output_ptr" +// Create a temporary file to get the stdout/stderr and redirect the output of +// the command into this file. We will later read this file if all goes well +// and fill the data into "command_output_ptr" #if defined(__APPLE__) // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... @@ -1120,8 +1121,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( #endif } else { // No host and port given, so lets listen on our end and make the - // debugserver - // connect to us.. + // debugserver connect to us.. error = StartListenThread("127.0.0.1", 0); if (error.Fail()) { if (log) @@ -1134,7 +1134,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection(); // Wait for 10 seconds to resolve the bound port - uint16_t port_ = connection->GetListeningPort(10); + uint16_t port_ = connection->GetListeningPort(std::chrono::seconds(10)); if (port_ > 0) { char port_cstr[32]; snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", port_); @@ -1206,11 +1206,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess( } // Copy the current environment to the gdbserver/debugserver instance - StringList env; - if (Host::GetEnvironment(env)) { - for (size_t i = 0; i < env.GetSize(); ++i) - launch_info.GetEnvironmentEntries().AppendArgument(env[i]); - } + launch_info.GetEnvironment() = Host::GetEnvironment(); // Close STDIN, STDOUT and STDERR. launch_info.AppendCloseFileAction(STDIN_FILENO); @@ -1327,14 +1323,11 @@ GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout() { } // This function is called via the Communications class read thread when bytes -// become available -// for this connection. This function will consume all incoming bytes and try to -// parse whole -// packets as they become available. Full packets are placed in a queue, so that -// all packet -// requests can simply pop from this queue. Async notification packets will be -// dispatched -// immediately to the ProcessGDBRemote Async thread via an event. +// become available for this connection. This function will consume all +// incoming bytes and try to parse whole packets as they become available. Full +// packets are placed in a queue, so that all packet requests can simply pop +// from this queue. Async notification packets will be dispatched immediately +// to the ProcessGDBRemote Async thread via an event. void GDBRemoteCommunication::AppendBytesToCache(const uint8_t *bytes, size_t len, bool broadcast, lldb::ConnectionStatus status) { @@ -1343,8 +1336,8 @@ void GDBRemoteCommunication::AppendBytesToCache(const uint8_t *bytes, while (true) { PacketType type = CheckForPacket(bytes, len, packet); - // scrub the data so we do not pass it back to CheckForPacket - // on future passes of the loop + // scrub the data so we do not pass it back to CheckForPacket on future + // passes of the loop bytes = nullptr; len = 0; @@ -1368,8 +1361,8 @@ void GDBRemoteCommunication::AppendBytesToCache(const uint8_t *bytes, // put this packet into an event const char *pdata = packet.GetStringRef().c_str(); - // as the communication class, we are a broadcaster and the - // async thread is tuned to listen to us + // as the communication class, we are a broadcaster and the async thread + // is tuned to listen to us BroadcastEvent(eBroadcastBitGdbReadThreadGotNotify, new EventDataBytes(pdata)); } diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index ecc9386e49c7..67796e4c61ef 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -24,10 +24,10 @@ #include "lldb/Core/Listener.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/Predicate.h" -#include "lldb/Interpreter/Args.h" +#include "lldb/Utility/Args.h" #include "lldb/lldb-public.h" -#include "Utility/StringExtractorGDBRemote.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" namespace lldb_private { namespace process_gdb_remote { @@ -232,6 +232,11 @@ protected: PacketResult ReadPacket(StringExtractorGDBRemote &response, Timeout<std::micro> timeout, bool sync_on_timeout); + PacketResult ReadPacketWithOutputSupport( + StringExtractorGDBRemote &response, Timeout<std::micro> timeout, + bool sync_on_timeout, + llvm::function_ref<void(llvm::StringRef)> output_callback); + // Pop a packet from the queue in a thread safe manner PacketResult PopPacketFromQueue(StringExtractorGDBRemote &response, Timeout<std::micro> timeout); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 867f57c475ce..c8b59d5d236b 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -21,11 +21,12 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/State.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Interpreter/Args.h" +#include "lldb/Host/XML.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/Args.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/JSON.h" #include "lldb/Utility/LLDBAssert.h" @@ -35,8 +36,8 @@ // Project includes #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" -#include "Utility/StringExtractorGDBRemote.h" #include "lldb/Host/Config.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" #include "llvm/ADT/StringSwitch.h" @@ -81,6 +82,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() m_supports_qXfer_libraries_read(eLazyBoolCalculate), m_supports_qXfer_libraries_svr4_read(eLazyBoolCalculate), m_supports_qXfer_features_read(eLazyBoolCalculate), + m_supports_qXfer_memory_map_read(eLazyBoolCalculate), m_supports_augmented_libraries_svr4_read(eLazyBoolCalculate), m_supports_jThreadExtendedInfo(eLazyBoolCalculate), m_supports_jLoadedDynamicLibrariesInfos(eLazyBoolCalculate), @@ -98,12 +100,12 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() m_curr_pid(LLDB_INVALID_PROCESS_ID), m_curr_tid(LLDB_INVALID_THREAD_ID), m_curr_tid_run(LLDB_INVALID_THREAD_ID), m_num_supported_hardware_watchpoints(0), m_host_arch(), m_process_arch(), - m_os_version_major(UINT32_MAX), m_os_version_minor(UINT32_MAX), - m_os_version_update(UINT32_MAX), m_os_build(), m_os_kernel(), - m_hostname(), m_gdb_server_name(), m_gdb_server_version(UINT32_MAX), - m_default_packet_timeout(0), m_max_packet_size(0), - m_qSupported_response(), m_supported_async_json_packets_is_valid(false), - m_supported_async_json_packets_sp() {} + m_os_build(), m_os_kernel(), m_hostname(), m_gdb_server_name(), + m_gdb_server_version(UINT32_MAX), m_default_packet_timeout(0), + m_max_packet_size(0), m_qSupported_response(), + m_supported_async_json_packets_is_valid(false), + m_supported_async_json_packets_sp(), m_qXfer_memory_map(), + m_qXfer_memory_map_loaded(false) {} //---------------------------------------------------------------------- // Destructor @@ -116,8 +118,8 @@ GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() { bool GDBRemoteCommunicationClient::HandshakeWithServer(Status *error_ptr) { ResetDiscoverableSettings(false); - // Start the read thread after we send the handshake ack since if we - // fail to send the handshake ack, there is no reason to continue... + // Start the read thread after we send the handshake ack since if we fail to + // send the handshake ack, there is no reason to continue... if (SendAck()) { // Wait for any responses that might have been queued up in the remote // GDB server and flush them all @@ -127,9 +129,9 @@ bool GDBRemoteCommunicationClient::HandshakeWithServer(Status *error_ptr) { packet_result = ReadPacket(response, milliseconds(10), false); // The return value from QueryNoAckModeSupported() is true if the packet - // was sent and _any_ response (including UNIMPLEMENTED) was received), - // or false if no response was received. This quickly tells us if we have - // a live connection to a remote GDB server... + // was sent and _any_ response (including UNIMPLEMENTED) was received), or + // false if no response was received. This quickly tells us if we have a + // live connection to a remote GDB server... if (QueryNoAckModeSupported()) { return true; } else { @@ -192,6 +194,13 @@ bool GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported() { return m_supports_qXfer_features_read == eLazyBoolYes; } +bool GDBRemoteCommunicationClient::GetQXferMemoryMapReadSupported() { + if (m_supports_qXfer_memory_map_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_memory_map_read == eLazyBoolYes; +} + uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() { if (m_max_packet_size == 0) { GetRemoteQSupported(); @@ -205,9 +214,8 @@ bool GDBRemoteCommunicationClient::QueryNoAckModeSupported() { m_supports_not_sending_acks = eLazyBoolNo; // This is the first real packet that we'll send in a debug session and it - // may take a little - // longer than normal to receive a reply. Wait at least 6 seconds for a - // reply to this packet. + // may take a little longer than normal to receive a reply. Wait at least + // 6 seconds for a reply to this packet. ScopedTimeout timeout(*this, std::max(GetPacketTimeout(), seconds(6))); @@ -296,6 +304,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { m_supports_qXfer_libraries_read = eLazyBoolCalculate; m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; m_supports_qXfer_features_read = eLazyBoolCalculate; + m_supports_qXfer_memory_map_read = eLazyBoolCalculate; m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; m_supports_qProcessInfoPID = true; m_supports_qfProcessInfo = true; @@ -313,9 +322,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { m_qSymbol_requests_done = false; m_supports_qModuleInfo = true; m_host_arch.Clear(); - m_os_version_major = UINT32_MAX; - m_os_version_minor = UINT32_MAX; - m_os_version_update = UINT32_MAX; + m_os_version = llvm::VersionTuple(); m_os_build.clear(); m_os_kernel.clear(); m_hostname.clear(); @@ -329,8 +336,8 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { m_supports_jModulesInfo = true; } - // These flags should be reset when we first connect to a GDB server - // and when our inferior process execs + // These flags should be reset when we first connect to a GDB server and when + // our inferior process execs m_qProcessInfo_is_valid = eLazyBoolCalculate; m_process_arch.Clear(); } @@ -342,6 +349,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() { m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; m_supports_augmented_libraries_svr4_read = eLazyBoolNo; m_supports_qXfer_features_read = eLazyBoolNo; + m_supports_qXfer_memory_map_read = eLazyBoolNo; m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if // not, we assume no limit @@ -361,8 +369,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() { const char *response_cstr = response.GetStringRef().c_str(); // Hang on to the qSupported packet, so that platforms can do custom - // configuration of the transport before attaching/launching the - // process. + // configuration of the transport before attaching/launching the process. m_qSupported_response = response_cstr; if (::strstr(response_cstr, "qXfer:auxv:read+")) @@ -377,9 +384,12 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() { m_supports_qXfer_libraries_read = eLazyBoolYes; if (::strstr(response_cstr, "qXfer:features:read+")) m_supports_qXfer_features_read = eLazyBoolYes; + if (::strstr(response_cstr, "qXfer:memory-map:read+")) + m_supports_qXfer_memory_map_read = eLazyBoolYes; // Look for a list of compressions in the features list e.g. - // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma + // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib- + // deflate,lzma const char *features_list = ::strstr(response_cstr, "qXfer:features:"); if (features_list) { const char *compressions = @@ -543,9 +553,8 @@ GDBRemoteCommunicationClient::SendThreadSpecificPacketAndWaitForResponse( return SendPacketAndWaitForResponseNoLock(payload.GetString(), response); } -// Check if the target supports 'p' packet. It sends out a 'p' -// packet and checks the response. A normal packet will tell us -// that support is available. +// Check if the target supports 'p' packet. It sends out a 'p' packet and +// checks the response. A normal packet will tell us that support is available. // // Takes a valid thread ID because p needs to apply to a thread. bool GDBRemoteCommunicationClient::GetpPacketSupported(lldb::tid_t tid) { @@ -600,8 +609,8 @@ bool GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported() { void GDBRemoteCommunicationClient::EnableErrorStringInPacket() { if (m_supports_error_string_reply == eLazyBoolCalculate) { StringExtractorGDBRemote response; - // We try to enable error strings in remote packets - // but if we fail, we just work in the older way. + // We try to enable error strings in remote packets but if we fail, we just + // work in the older way. m_supports_error_string_reply = eLazyBoolNo; if (SendPacketAndWaitForResponse("QEnableErrorStrings", response, false) == PacketResult::Success) { @@ -715,12 +724,10 @@ lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) { return m_curr_pid; } else { // If we don't get a response for qProcessInfo, check if $qC gives us a - // result. - // $qC only returns a real process id on older debugserver and lldb-platform - // stubs. - // The gdb remote protocol documents $qC as returning the thread id, which - // newer - // debugserver and lldb-gdbserver stubs return correctly. + // result. $qC only returns a real process id on older debugserver and + // lldb-platform stubs. The gdb remote protocol documents $qC as returning + // the thread id, which newer debugserver and lldb-gdbserver stubs return + // correctly. StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qC", response, false) == PacketResult::Success) { @@ -775,8 +782,8 @@ bool GDBRemoteCommunicationClient::GetLaunchSuccess(std::string &error_str) { int GDBRemoteCommunicationClient::SendArgumentsPacket( const ProcessLaunchInfo &launch_info) { // Since we don't get the send argv0 separate from the executable path, we - // need to - // make sure to use the actual executable path found in the launch_info... + // need to make sure to use the actual executable path found in the + // launch_info... std::vector<const char *> argv; FileSpec exe_file = launch_info.GetExecutableFile(); std::string exe_path; @@ -822,6 +829,15 @@ int GDBRemoteCommunicationClient::SendArgumentsPacket( return -1; } +int GDBRemoteCommunicationClient::SendEnvironment(const Environment &env) { + for (const auto &KV : env) { + int r = SendEnvironmentPacket(Environment::compose(KV).c_str()); + if (r != 0) + return r; + } + return 0; +} + int GDBRemoteCommunicationClient::SendEnvironmentPacket( char const *name_equal_value) { if (name_equal_value && name_equal_value[0]) { @@ -925,18 +941,9 @@ int GDBRemoteCommunicationClient::SendLaunchEventDataPacket( return -1; } -bool GDBRemoteCommunicationClient::GetOSVersion(uint32_t &major, - uint32_t &minor, - uint32_t &update) { - if (GetHostInfo()) { - if (m_os_version_major != UINT32_MAX) { - major = m_os_version_major; - minor = m_os_version_minor; - update = m_os_version_update; - return true; - } - } - return false; +llvm::VersionTuple GDBRemoteCommunicationClient::GetOSVersion() { + GetHostInfo(); + return m_os_version; } bool GDBRemoteCommunicationClient::GetOSBuildString(std::string &s) { @@ -1199,9 +1206,7 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { // "version" key instead of // "os_version"... { - Args::StringToVersion(value, m_os_version_major, m_os_version_minor, - m_os_version_update); - if (m_os_version_major != UINT32_MAX) + if (!m_os_version.tryParse(value)) ++num_keys_decoded; } else if (name.equals("watchpoint_exceptions_received")) { m_watchpoints_trigger_after_instruction = @@ -1451,7 +1456,8 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == - PacketResult::Success) { + PacketResult::Success && + response.GetResponseType() == StringExtractorGDBRemote::eResponse) { llvm::StringRef name; llvm::StringRef value; addr_t addr_value = LLDB_INVALID_ADDRESS; @@ -1527,8 +1533,134 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( if (m_supports_memory_region_info == eLazyBoolNo) { error.SetErrorString("qMemoryRegionInfo is not supported"); } - if (error.Fail()) - region_info.Clear(); + + // Try qXfer:memory-map:read to get region information not included in + // qMemoryRegionInfo + MemoryRegionInfo qXfer_region_info; + Status qXfer_error = GetQXferMemoryMapRegionInfo(addr, qXfer_region_info); + + if (error.Fail()) { + // If qMemoryRegionInfo failed, but qXfer:memory-map:read succeeded, use + // the qXfer result as a fallback + if (qXfer_error.Success()) { + region_info = qXfer_region_info; + error.Clear(); + } else { + region_info.Clear(); + } + } else if (qXfer_error.Success()) { + // If both qMemoryRegionInfo and qXfer:memory-map:read succeeded, and if + // both regions are the same range, update the result to include the flash- + // memory information that is specific to the qXfer result. + if (region_info.GetRange() == qXfer_region_info.GetRange()) { + region_info.SetFlash(qXfer_region_info.GetFlash()); + region_info.SetBlocksize(qXfer_region_info.GetBlocksize()); + } + } + return error; +} + +Status GDBRemoteCommunicationClient::GetQXferMemoryMapRegionInfo( + lldb::addr_t addr, MemoryRegionInfo ®ion) { + Status error = LoadQXferMemoryMap(); + if (!error.Success()) + return error; + for (const auto &map_region : m_qXfer_memory_map) { + if (map_region.GetRange().Contains(addr)) { + region = map_region; + return error; + } + } + error.SetErrorString("Region not found"); + return error; +} + +Status GDBRemoteCommunicationClient::LoadQXferMemoryMap() { + + Status error; + + if (m_qXfer_memory_map_loaded) + // Already loaded, return success + return error; + + if (!XMLDocument::XMLEnabled()) { + error.SetErrorString("XML is not supported"); + return error; + } + + if (!GetQXferMemoryMapReadSupported()) { + error.SetErrorString("Memory map is not supported"); + return error; + } + + std::string xml; + lldb_private::Status lldberr; + if (!ReadExtFeature(ConstString("memory-map"), ConstString(""), xml, + lldberr)) { + error.SetErrorString("Failed to read memory map"); + return error; + } + + XMLDocument xml_document; + + if (!xml_document.ParseMemory(xml.c_str(), xml.size())) { + error.SetErrorString("Failed to parse memory map xml"); + return error; + } + + XMLNode map_node = xml_document.GetRootElement("memory-map"); + if (!map_node) { + error.SetErrorString("Invalid root node in memory map xml"); + return error; + } + + m_qXfer_memory_map.clear(); + + map_node.ForEachChildElement([this](const XMLNode &memory_node) -> bool { + if (!memory_node.IsElement()) + return true; + if (memory_node.GetName() != "memory") + return true; + auto type = memory_node.GetAttributeValue("type", ""); + uint64_t start; + uint64_t length; + if (!memory_node.GetAttributeValueAsUnsigned("start", start)) + return true; + if (!memory_node.GetAttributeValueAsUnsigned("length", length)) + return true; + MemoryRegionInfo region; + region.GetRange().SetRangeBase(start); + region.GetRange().SetByteSize(length); + if (type == "rom") { + region.SetReadable(MemoryRegionInfo::eYes); + this->m_qXfer_memory_map.push_back(region); + } else if (type == "ram") { + region.SetReadable(MemoryRegionInfo::eYes); + region.SetWritable(MemoryRegionInfo::eYes); + this->m_qXfer_memory_map.push_back(region); + } else if (type == "flash") { + region.SetFlash(MemoryRegionInfo::eYes); + memory_node.ForEachChildElement( + [®ion](const XMLNode &prop_node) -> bool { + if (!prop_node.IsElement()) + return true; + if (prop_node.GetName() != "property") + return true; + auto propname = prop_node.GetAttributeValue("name", ""); + if (propname == "blocksize") { + uint64_t blocksize; + if (prop_node.GetElementTextAsUnsigned(blocksize)) + region.SetBlocksize(blocksize); + } + return true; + }); + this->m_qXfer_memory_map.push_back(region); + } + return true; + }); + + m_qXfer_memory_map_loaded = true; + return error; } @@ -1585,13 +1717,13 @@ GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction( Status error; llvm::Triple::ArchType atype = arch.GetMachine(); - // we assume watchpoints will happen after running the relevant opcode - // and we only want to override this behavior if we have explicitly - // received a qHostInfo telling us otherwise + // we assume watchpoints will happen after running the relevant opcode and we + // only want to override this behavior if we have explicitly received a + // qHostInfo telling us otherwise if (m_qHostInfo_is_valid != eLazyBoolYes) { // 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. + // 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) @@ -1789,11 +1921,12 @@ bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse( process_info.GetArchitecture().SetTriple(triple.c_str()); } else if (name.equals("name")) { StringExtractor extractor(value); - // The process name from ASCII hex bytes since we can't - // control the characters in a process name + // The process name from ASCII hex bytes since we can't control the + // characters in a process name std::string name; extractor.GetHexByteString(name); - process_info.GetExecutableFile().SetFile(name, false); + process_info.GetExecutableFile().SetFile(name, false, + FileSpec::Style::native); } else if (name.equals("cputype")) { value.getAsInteger(0, cpu); } else if (name.equals("cpusubtype")) { @@ -2046,8 +2179,8 @@ uint32_t GDBRemoteCommunicationClient::FindProcesses( } } StringExtractorGDBRemote response; - // Increase timeout as the first qfProcessInfo packet takes a long time - // on Android. The value of 1min was arrived at empirically. + // Increase timeout as the first qfProcessInfo packet takes a long time on + // Android. The value of 1min was arrived at empirically. ScopedTimeout timeout(*this, minutes(1)); if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { @@ -2081,8 +2214,8 @@ bool GDBRemoteCommunicationClient::GetUserName(uint32_t uid, PacketResult::Success) { if (response.IsNormalResponse()) { // Make sure we parsed the right number of characters. The response is - // the hex encoded user name and should make up the entire packet. - // If there are any non-hex ASCII bytes, the length won't match below.. + // the hex encoded user name and should make up the entire packet. If + // there are any non-hex ASCII bytes, the length won't match below.. if (response.GetHexByteString(name) * 2 == response.GetStringRef().size()) return true; @@ -2108,8 +2241,8 @@ bool GDBRemoteCommunicationClient::GetGroupName(uint32_t gid, PacketResult::Success) { if (response.IsNormalResponse()) { // Make sure we parsed the right number of characters. The response is - // the hex encoded group name and should make up the entire packet. - // If there are any non-hex ASCII bytes, the length won't match below.. + // the hex encoded group name and should make up the entire packet. If + // there are any non-hex ASCII bytes, the length won't match below.. if (response.GetHexByteString(name) * 2 == response.GetStringRef().size()) return true; @@ -2335,8 +2468,8 @@ bool GDBRemoteCommunicationClient::LaunchGDBServer( // Make the GDB server we launch only accept connections from this host stream.Printf("host:%s;", hostname.c_str()); } else { - // Make the GDB server we launch accept connections from any host since we - // can't figure out the hostname + // Make the GDB server we launch accept connections from any host since + // we can't figure out the hostname stream.Printf("host:*;"); } } @@ -2650,13 +2783,16 @@ lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand( // process to exit std::string *command_output, // Pass NULL if you don't want the command output - uint32_t - timeout_sec) // Timeout in seconds to wait for shell program to finish -{ + const Timeout<std::micro> &timeout) { lldb_private::StreamString stream; stream.PutCString("qPlatform_shell:"); stream.PutBytesAsRawHex8(command, strlen(command)); stream.PutChar(','); + uint32_t timeout_sec = UINT32_MAX; + if (timeout) { + // TODO: Use chrono version of std::ceil once c++17 is available. + timeout_sec = std::ceil(std::chrono::duration<double>(*timeout).count()); + } stream.PutHex32(timeout_sec); if (working_dir) { std::string path{working_dir.GetPath(false)}; @@ -3125,9 +3261,8 @@ bool GDBRemoteCommunicationClient::SaveRegisterState(lldb::tid_t tid, bool GDBRemoteCommunicationClient::RestoreRegisterState(lldb::tid_t tid, uint32_t save_id) { // We use the "m_supports_QSaveRegisterState" variable here because the - // QSaveRegisterState and QRestoreRegisterState packets must both be supported - // in - // order to be useful + // QSaveRegisterState and QRestoreRegisterState packets must both be + // supported in order to be useful if (m_supports_QSaveRegisterState == eLazyBoolNo) return false; @@ -3406,7 +3541,7 @@ bool GDBRemoteCommunicationClient::GetModuleInfo( StringExtractor extractor(value); std::string uuid; extractor.GetHexByteString(uuid); - module_spec.GetUUID().SetFromCString(uuid.c_str(), uuid.size() / 2); + module_spec.GetUUID().SetFromStringRef(uuid, uuid.size() / 2); } else if (name == "triple") { StringExtractor extractor(value); std::string triple; @@ -3523,8 +3658,8 @@ GDBRemoteCommunicationClient::GetModulesInfo( // query the target remote for extended information using the qXfer packet // -// example: object='features', annex='target.xml', out=<xml output> -// return: 'true' on success +// example: object='features', annex='target.xml', out=<xml output> return: +// 'true' on success // 'false' on failure (err set) bool GDBRemoteCommunicationClient::ReadExtFeature( const lldb_private::ConstString object, @@ -3631,10 +3766,9 @@ bool GDBRemoteCommunicationClient::ReadExtFeature( void GDBRemoteCommunicationClient::ServeSymbolLookups( lldb_private::Process *process) { - // Set to true once we've resolved a symbol to an address for the remote stub. - // If we get an 'OK' response after this, the remote stub doesn't need any - // more - // symbols and we can stop asking. + // Set to true once we've resolved a symbol to an address for the remote + // stub. If we get an 'OK' response after this, the remote stub doesn't need + // any more symbols and we can stop asking. bool symbol_response_provided = false; // Is this the initial qSymbol:: packet? @@ -3659,8 +3793,8 @@ void GDBRemoteCommunicationClient::ServeSymbolLookups( first_qsymbol_query = false; if (response.IsUnsupportedResponse()) { - // qSymbol is not supported by the current GDB server we are connected - // to + // qSymbol is not supported by the current GDB server we are + // connected to m_supports_qSymbol = false; return; } else { @@ -3725,10 +3859,8 @@ void GDBRemoteCommunicationClient::ServeSymbolLookups( } } // This is the normal path where our symbol lookup was successful - // and we want - // to send a packet with the new symbol value and see if another - // lookup needs to be - // done. + // and we want to send a packet with the new symbol value and see + // if another lookup needs to be done. // Change "packet" to contain the requested symbol value and name packet.Clear(); @@ -3763,8 +3895,7 @@ void GDBRemoteCommunicationClient::ServeSymbolLookups( StructuredData::Array * GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() { if (!m_supported_async_json_packets_is_valid) { - // Query the server for the array of supported asynchronous JSON - // packets. + // Query the server for the array of supported asynchronous JSON packets. m_supported_async_json_packets_is_valid = true; Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); @@ -3778,8 +3909,8 @@ GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() { StructuredData::ParseJSON(response.GetStringRef()); if (m_supported_async_json_packets_sp && !m_supported_async_json_packets_sp->GetAsArray()) { - // We were returned something other than a JSON array. This - // is invalid. Clear it out. + // We were returned something other than a JSON array. This is + // invalid. Clear it out. if (log) log->Printf("GDBRemoteCommunicationClient::%s(): " "QSupportedAsyncJSONPackets returned invalid " @@ -3837,8 +3968,7 @@ Status GDBRemoteCommunicationClient::ConfigureRemoteStructuredData( return error; } - // Build command: Configure{type_name}: serialized config - // data. + // Build command: Configure{type_name}: serialized config data. StreamGDBRemote stream; stream.PutCString("QConfigure"); stream.PutCString(type_name.AsCString()); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index ba67b8246398..cf1d249768d7 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -121,6 +121,7 @@ public: /// response was received. //------------------------------------------------------------------ int SendEnvironmentPacket(char const *name_equal_value); + int SendEnvironment(const Environment &env); int SendLaunchArchPacket(const char *arch); @@ -265,7 +266,7 @@ public: bool GetDefaultThreadId(lldb::tid_t &tid); - bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + llvm::VersionTuple GetOSVersion(); bool GetOSBuildString(std::string &s); @@ -354,6 +355,8 @@ public: bool GetQXferFeaturesReadSupported(); + bool GetQXferMemoryMapReadSupported(); + LazyBool SupportsAllocDeallocMemory() // const { // Uncomment this to have lldb pretend the debug server doesn't respond to @@ -401,8 +404,7 @@ public: // the process to exit std::string *command_output, // Pass nullptr if you don't want the command output - uint32_t timeout_sec); // Timeout in seconds to wait for shell program to - // finish + const Timeout<std::micro> &timeout); bool CalculateMD5(const FileSpec &file_spec, uint64_t &high, uint64_t &low); @@ -544,6 +546,7 @@ protected: LazyBool m_supports_qXfer_libraries_read; LazyBool m_supports_qXfer_libraries_svr4_read; LazyBool m_supports_qXfer_features_read; + LazyBool m_supports_qXfer_memory_map_read; LazyBool m_supports_augmented_libraries_svr4_read; LazyBool m_supports_jThreadExtendedInfo; LazyBool m_supports_jLoadedDynamicLibrariesInfos; @@ -570,9 +573,7 @@ protected: ArchSpec m_host_arch; ArchSpec m_process_arch; - uint32_t m_os_version_major; - uint32_t m_os_version_minor; - uint32_t m_os_version_update; + llvm::VersionTuple m_os_version; std::string m_os_build; std::string m_os_kernel; std::string m_hostname; @@ -587,6 +588,9 @@ protected: bool m_supported_async_json_packets_is_valid; lldb_private::StructuredData::ObjectSP m_supported_async_json_packets_sp; + std::vector<MemoryRegionInfo> m_qXfer_memory_map; + bool m_qXfer_memory_map_loaded; + bool GetCurrentProcessInfo(bool allow_lazy_pid = true); bool GetGDBServerVersion(); @@ -609,6 +613,11 @@ protected: llvm::MutableArrayRef<uint8_t> &buffer, size_t offset); + Status LoadQXferMemoryMap(); + + Status GetQXferMemoryMapRegionInfo(lldb::addr_t addr, + MemoryRegionInfo ®ion); + private: DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient); }; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 4be92b79fd1a..4fc1fc7a1964 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -19,8 +19,8 @@ // Project includes #include "ProcessGDBRemoteLog.h" -#include "Utility/StringExtractorGDBRemote.h" #include "lldb/Utility/StreamString.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" using namespace lldb; using namespace lldb_private; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index a35352480040..880caacd6414 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -57,8 +57,8 @@ protected: bool m_exit_now; // use in asynchronous handling to indicate process should // exit. - bool m_send_error_strings; // If the client enables this then - // we will send error strings as well. + bool m_send_error_strings = false; // If the client enables this then + // we will send error strings as well. PacketResult Handle_QErrorStringEnable(StringExtractorGDBRemote &packet); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 3cf6b8ac07b2..c5b478378faa 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -28,7 +28,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/FileAction.h" #include "lldb/Target/Platform.h" @@ -36,13 +36,14 @@ #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 "Utility/StringExtractorGDBRemote.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" #ifdef __ANDROID__ #include "lldb/Host/android/HostInfoAndroid.h" @@ -218,12 +219,15 @@ GDBRemoteCommunicationServerCommon::Handle_qHostInfo( if (sub != LLDB_INVALID_CPUTYPE) response.Printf("cpusubtype:%u;", sub); - if (cpu == ArchSpec::kCore_arm_any) { + if (cpu == llvm::MachO::CPU_TYPE_ARM + || cpu == llvm::MachO::CPU_TYPE_ARM64) { // Indicate the OS type. #if defined(TARGET_OS_TV) && TARGET_OS_TV == 1 response.PutCString("ostype:tvos;"); #elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 response.PutCString("ostype:watchos;"); +#elif defined(TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE == 1 + response.PutCString("ostype:bridgeos;"); #else response.PutCString("ostype:ios;"); #endif @@ -265,19 +269,10 @@ GDBRemoteCommunicationServerCommon::Handle_qHostInfo( break; } - uint32_t major = UINT32_MAX; - uint32_t minor = UINT32_MAX; - uint32_t update = UINT32_MAX; - if (HostInfo::GetOSVersion(major, minor, update)) { - if (major != UINT32_MAX) { - response.Printf("os_version:%u", major); - if (minor != UINT32_MAX) { - response.Printf(".%u", minor); - if (update != UINT32_MAX) - response.Printf(".%u", update); - } - response.PutChar(';'); - } + llvm::VersionTuple version = HostInfo::GetOSVersion(); + if (!version.empty()) { + response.Format("os_version:{0}", version.getAsString()); + response.PutChar(';'); } std::string s; @@ -295,9 +290,9 @@ GDBRemoteCommunicationServerCommon::Handle_qHostInfo( #if defined(__APPLE__) #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - // For iOS devices, we are connected through a USB Mux so we never pretend - // to actually have a hostname as far as the remote lldb that is connecting - // to this lldb-platform is concerned + // For iOS devices, we are connected through a USB Mux so we never pretend to + // actually have a hostname as far as the remote lldb that is connecting to + // this lldb-platform is concerned response.PutCString("hostname:"); response.PutCStringAsRawHex8("127.0.0.1"); response.PutChar(';'); @@ -357,7 +352,8 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( StringExtractor extractor(value); std::string file; extractor.GetHexByteString(file); - match_info.GetProcessInfo().GetExecutableFile().SetFile(file, false); + match_info.GetProcessInfo().GetExecutableFile().SetFile( + file, false, FileSpec::Style::native); } else if (key.equals("name_match")) { NameMatch name_match = llvm::StringSwitch<NameMatch>(value) .Case("equals", NameMatch::Equals) @@ -401,7 +397,7 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( match_info.GetProcessInfo().SetEffectiveGroupID(gid); } else if (key.equals("all_users")) { match_info.SetMatchAllUsers( - Args::StringToBoolean(value, false, &success)); + OptionArgParser::ToBoolean(value, false, &success)); } else if (key.equals("triple")) { match_info.GetProcessInfo().GetArchitecture() = HostInfo::GetAugmentedArchSpec(value); @@ -415,8 +411,8 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( } if (Host::FindProcesses(match_info, m_proc_infos)) { - // We found something, return the first item by calling the get - // subsequent process info packet handler... + // We found something, return the first item by calling the get subsequent + // process info packet handler... return Handle_qsProcessInfo(packet); } return SendErrorResponse(3); @@ -731,14 +727,13 @@ GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell( if (packet.GetChar() == ',') { // FIXME: add timeout to qPlatform_shell packet // uint32_t timeout = packet.GetHexMaxU32(false, 32); - uint32_t timeout = 10; if (packet.GetChar() == ',') packet.GetHexByteString(working_dir); int status, signo; std::string output; - Status err = - Host::RunShellCommand(path.c_str(), FileSpec{working_dir, true}, - &status, &signo, &output, timeout); + Status err = Host::RunShellCommand( + path.c_str(), FileSpec{working_dir, true}, &status, &signo, &output, + std::chrono::seconds(10)); StreamGDBRemote response; if (err.Fail()) { response.PutCString("F,"); @@ -945,8 +940,7 @@ GDBRemoteCommunicationServerCommon::Handle_QEnvironment( packet.SetFilePos(::strlen("QEnvironment:")); const uint32_t bytes_left = packet.GetBytesLeft(); if (bytes_left > 0) { - m_process_launch_info.GetEnvironmentEntries().AppendArgument( - llvm::StringRef::withNullAsEmpty(packet.Peek())); + m_process_launch_info.GetEnvironment().insert(packet.Peek()); return SendOKResponse(); } return SendErrorResponse(12); @@ -960,7 +954,7 @@ GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded( if (bytes_left > 0) { std::string str; packet.GetHexByteString(str); - m_process_launch_info.GetEnvironmentEntries().AppendArgument(str); + m_process_launch_info.GetEnvironment().insert(str); return SendOKResponse(); } return SendErrorResponse(12); @@ -981,11 +975,11 @@ GDBRemoteCommunicationServerCommon::Handle_QLaunchArch( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { - // The 'A' packet is the most over designed packet ever here with - // redundant argument indexes, redundant argument lengths and needed hex - // encoded argument string values. Really all that is needed is a comma - // separated hex encoded argument value list, but we will stay true to the - // documented version of the 'A' packet here... + // The 'A' packet is the most over designed packet ever here with redundant + // argument indexes, redundant argument lengths and needed hex encoded + // argument string values. Really all that is needed is a comma separated hex + // encoded argument value list, but we will stay true to the documented + // version of the 'A' packet here... Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); int actual_arg_index = 0; @@ -993,8 +987,8 @@ GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { packet.SetFilePos(1); // Skip the 'A' bool success = true; while (success && packet.GetBytesLeft() > 0) { - // Decode the decimal argument string length. This length is the - // number of hex nibbles in the argument string value. + // Decode the decimal argument string length. This length is the number of + // hex nibbles in the argument string value. const uint32_t arg_len = packet.GetU32(UINT32_MAX); if (arg_len == UINT32_MAX) success = false; @@ -1003,8 +997,8 @@ GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { if (packet.GetChar() != ',') success = false; else { - // Decode the argument index. We ignore this really because - // who would really send down the arguments in a random order??? + // Decode the argument index. We ignore this really because who would + // really send down the arguments in a random order??? const uint32_t arg_idx = packet.GetU32(UINT32_MAX); if (arg_idx == UINT32_MAX) success = false; @@ -1013,9 +1007,9 @@ GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { if (packet.GetChar() != ',') success = false; else { - // Decode the argument string value from hex bytes - // back into a UTF8 string and make sure the length - // matches the one supplied in the packet + // Decode the argument string value from hex bytes back into a UTF8 + // string and make sure the length matches the one supplied in the + // packet std::string arg; if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2)) @@ -1029,7 +1023,8 @@ GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { if (success) { if (arg_idx == 0) - m_process_launch_info.GetExecutableFile().SetFile(arg, false); + m_process_launch_info.GetExecutableFile().SetFile( + arg, false, FileSpec::Style::native); m_process_launch_info.GetArguments().AppendArgument(arg); if (log) log->Printf("LLGSPacketHandler::%s added arg %d: \"%s\"", @@ -1254,8 +1249,8 @@ void GDBRemoteCommunicationServerCommon:: // Nothing. break; } - // In case of MIPS64, pointer size is depend on ELF ABI - // For N32 the pointer size is 4 and for N64 it is 8 + // In case of MIPS64, pointer size is depend on ELF ABI For N32 the pointer + // size is 4 and for N64 it is 8 std::string abi = proc_arch.GetTargetABI(); if (!abi.empty()) response.Printf("elf_abi:%s;", abi.c_str()); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 32741c2404e2..50392fa38956 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -33,9 +33,9 @@ #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/common/NativeThreadProtocol.h" -#include "lldb/Interpreter/Args.h" #include "lldb/Target/FileAction.h" #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/Args.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/JSON.h" @@ -49,7 +49,7 @@ // Project includes #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" -#include "Utility/StringExtractorGDBRemote.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" using namespace lldb; using namespace lldb_private; @@ -236,16 +236,15 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { m_debugged_process_up = std::move(*process_or); } - // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol - // as needed. - // llgs local-process debugging may specify PTY paths, which will make these - // file actions non-null - // process launch -i/e/o will also make these file actions non-null - // nullptr means that the traffic is expected to flow over gdb-remote protocol + // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as + // needed. llgs local-process debugging may specify PTY paths, which will + // make these file actions non-null process launch -i/e/o will also make + // these file actions non-null nullptr means that the traffic is expected to + // flow over gdb-remote protocol if (should_forward_stdio) { // nullptr means it's not redirected to file or pty (in case of LLGS local) - // at least one of stdio will be transferred pty<->gdb-remote - // we need to give the pty master handle to this object to read and/or write + // at least one of stdio will be transferred pty<->gdb-remote we need to + // give the pty master handle to this object to read and/or write LLDB_LOG(log, "pid = {0}: setting up stdout/stderr redirection via $O " "gdb-remote commands", @@ -291,7 +290,7 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { // else. if (m_debugged_process_up && m_debugged_process_up->GetID() != LLDB_INVALID_PROCESS_ID) - return Status("cannot attach to a process %" PRIu64 + return Status("cannot attach to process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, m_debugged_process_up->GetID()); @@ -410,8 +409,8 @@ static JSONObject::SP GetRegistersAsJSON(NativeThreadProtocol &thread) { JSONObject::SP register_object_sp = std::make_shared<JSONObject>(); #ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET - // Expedite all registers in the first register set (i.e. should be GPRs) that - // are not contained in other registers. + // Expedite all registers in the first register set (i.e. should be GPRs) + // that are not contained in other registers. const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0); if (!reg_set_p) return nullptr; @@ -420,8 +419,7 @@ static JSONObject::SP GetRegistersAsJSON(NativeThreadProtocol &thread) { uint32_t reg_num = *reg_num_p; #else // Expedite only a couple of registers until we figure out why sending - // registers is - // expensive. + // registers is expensive. static const uint32_t k_expedited_registers[] = { LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM}; @@ -595,8 +593,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( return SendErrorResponse(52); // FIXME implement register handling for exec'd inferiors. - // if (tid_stop_info.reason == eStopReasonExec) - // { + // if (tid_stop_info.reason == eStopReasonExec) { // const bool force = true; // InitializeRegisters(force); // } @@ -633,14 +630,14 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( response.PutChar(';'); } - // If a 'QListThreadsInStopReply' was sent to enable this feature, we - // will send all thread IDs back in the "threads" key whose value is - // a list of hex thread IDs separated by commas: + // If a 'QListThreadsInStopReply' was sent to enable this feature, we will + // send all thread IDs back in the "threads" key whose value is a list of hex + // thread IDs separated by commas: // "threads:10a,10b,10c;" - // This will save the debugger from having to send a pair of qfThreadInfo - // and qsThreadInfo packets, but it also might take a lot of room in the - // stop reply packet, so it must be enabled only on systems where there - // are no limits on packet lengths. + // This will save the debugger from having to send a pair of qfThreadInfo and + // qsThreadInfo packets, but it also might take a lot of room in the stop + // reply packet, so it must be enabled only on systems where there are no + // limits on packet lengths. if (m_list_threads_in_stop_reply) { response.PutCString("threads:"); @@ -655,12 +652,11 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( } response.PutChar(';'); - // Include JSON info that describes the stop reason for any threads - // that actually have stop reasons. We use the new "jstopinfo" key - // whose values is hex ascii JSON that contains the thread IDs - // thread stop info only for threads that have stop reasons. Only send - // this if we have more than one thread otherwise this packet has all - // the info it needs. + // Include JSON info that describes the stop reason for any threads that + // actually have stop reasons. We use the new "jstopinfo" key whose values + // is hex ascii JSON that contains the thread IDs thread stop info only for + // threads that have stop reasons. Only send this if we have more than one + // thread otherwise this packet has all the info it needs. if (thread_index > 0) { const bool threads_with_valid_stop_info_only = true; JSONArray::SP threads_info_sp = GetJSONThreadsInfo( @@ -806,8 +802,8 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited( __FUNCTION__, process->GetID()); } - // Close the pipe to the inferior terminal i/o if we launched it - // and set one up. + // Close the pipe to the inferior terminal i/o if we launched it and set one + // up. MaybeCloseInferiorTerminalConnection(); // We are ready to exit the debug monitor. @@ -823,8 +819,7 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped( if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - // Send the stop reason unless this is the stop after the - // launch or attach. + // Send the stop reason unless this is the stop after the launch or attach. switch (m_inferior_prev_state) { case eStateLaunching: case eStateAttaching: @@ -859,13 +854,11 @@ void GDBRemoteCommunicationServerLLGS::ProcessStateChanged( break; case StateType::eStateStopped: - // Make sure we get all of the pending stdout/stderr from the inferior - // and send it to the lldb host before we send the state change - // notification + // Make sure we get all of the pending stdout/stderr from the inferior and + // send it to the lldb host before we send the state change notification SendProcessOutput(); // Then stop the forwarding, so that any late output (see llvm.org/pr25652) - // does not - // interfere with our protocol. + // does not interfere with our protocol. StopSTDIOForwarding(); HandleInferiorState_Stopped(process); break; @@ -1287,8 +1280,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qC(StringExtractorGDBRemote &packet) { (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); - // Make sure we set the current thread so g and p packets return - // the data the gdb will expect. + // Make sure we set the current thread so g and p packets return the data the + // gdb will expect. lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID(); SetCurrentThreadID(tid); @@ -1397,10 +1390,9 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { Status error; // We have two branches: what to do if a continue thread is specified (in - // which case we target - // sending the signal to that thread), or when we don't have a continue thread - // set (in which - // case we send a signal to the process). + // which case we target sending the signal to that thread), or when we don't + // have a continue thread set (in which case we send a signal to the + // process). // TODO discuss with Greg Clayton, make sure this makes sense. @@ -1639,8 +1631,8 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( case eStateStopped: case eStateCrashed: { lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID(); - // Make sure we set the current thread so g and p packets return - // the data the gdb will expect. + // Make sure we set the current thread so g and p packets return the data + // the gdb will expect. SetCurrentThreadID(tid); return SendStopReplyPacketForThread(tid); } @@ -2043,9 +2035,8 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { return SendErrorResponse(0x47); } - // The dwarf expression are evaluate on host site - // which may cause register size to change - // Hence the reg_size may not be same as reg_info->bytes_size + // The dwarf expression are evaluate on host site which may cause register + // size to change Hence the reg_size may not be same as reg_info->bytes_size if ((reg_size != reg_info->byte_size) && !(reg_info->dynamic_size_dwarf_expr_bytes)) { return SendIllFormedResponse(packet, "P packet register size is incorrect"); @@ -2376,10 +2367,9 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // Currently only the NativeProcessProtocol knows if it can handle a - // qMemoryRegionInfoSupported - // request, but we're not guaranteed to be attached to a process. For now - // we'll assume the - // client only asks this when a process is being debugged. + // qMemoryRegionInfoSupported request, but we're not guaranteed to be + // attached to a process. For now we'll assume the client only asks this + // when a process is being debugged. // Ensure we have a process running; otherwise, we can't figure this out // since we won't have a NativeProcessProtocol. @@ -2670,8 +2660,7 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { } // We first try to use a continue thread id. If any one or any all set, use - // the current thread. - // Bail out if we don't have a thread id. + // the current thread. Bail out if we don't have a thread id. lldb::tid_t tid = GetContinueThreadID(); if (tid == 0 || tid == LLDB_INVALID_THREAD_ID) tid = GetCurrentThreadID(); @@ -2935,7 +2924,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach( log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to attach to " "pid %" PRIu64 ": %s\n", __FUNCTION__, pid, error.AsCString()); - return SendErrorResponse(0x01); + return SendErrorResponse(error); } // Notify we attached by sending a stop packet. @@ -3093,8 +3082,8 @@ GDBRemoteCommunicationServerLLGS::Handle_QPassSignals( std::vector<int> signals; packet.SetFilePos(strlen("QPassSignals:")); - // Read sequence of hex signal numbers divided by a semicolon and - // optionally spaces. + // Read sequence of hex signal numbers divided by a semicolon and optionally + // spaces. while (packet.GetBytesLeft() > 0) { int signal = packet.GetS32(-1, 16); if (signal < 0) @@ -3154,8 +3143,7 @@ NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( return nullptr; // If the client hasn't asked for thread suffix support, there will not be a - // thread suffix. - // Use the current thread in that case. + // thread suffix. Use the current thread in that case. if (!m_thread_suffix_supported) { const lldb::tid_t current_tid = GetCurrentThreadID(); if (current_tid == LLDB_INVALID_THREAD_ID) @@ -3201,9 +3189,9 @@ NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( lldb::tid_t GDBRemoteCommunicationServerLLGS::GetCurrentThreadID() const { if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) { - // Use whatever the debug process says is the current thread id - // since the protocol either didn't specify or specified we want - // any/all threads marked as the current thread. + // Use whatever the debug process says is the current thread id since the + // protocol either didn't specify or specified we want any/all threads + // marked as the current thread. if (!m_debugged_process_up) return LLDB_INVALID_THREAD_ID; return m_debugged_process_up->GetCurrentThreadID(); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index 04ed9d704e13..26e28a900320 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -14,6 +14,7 @@ // C Includes // C++ Includes #include <chrono> +#include <csignal> #include <cstring> #include <mutex> #include <sstream> @@ -38,7 +39,7 @@ #include "lldb/Utility/UriParser.h" // Project includes -#include "Utility/StringExtractorGDBRemote.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" using namespace lldb; using namespace lldb_private; @@ -101,11 +102,11 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( if (port == UINT16_MAX) port = GetNextAvailablePort(); - // Spawn a new thread to accept the port that gets bound after - // binding to port 0 (zero). + // Spawn a new thread to accept the port that gets bound after binding to + // port 0 (zero). - // ignore the hostname send from the remote end, just use the ip address - // that we're currently communicating with as the hostname + // ignore the hostname send from the remote end, just use the ip address that + // we're currently communicating with as the hostname // Spawn a debugserver and try to get the port it listens to. ProcessLaunchInfo debugserver_launch_info; @@ -116,8 +117,8 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( if (log) log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port); - // Do not run in a new session so that it can not linger after the - // platform closes. + // Do not run in a new session so that it can not linger after the platform + // closes. debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); debugserver_launch_info.SetMonitorProcessCallback( std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, @@ -170,8 +171,8 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( #ifdef _WIN32 return SendErrorResponse(9); #else - // Spawn a local debugserver as a platform so we can then attach or launch - // a process... + // Spawn a local debugserver as a platform so we can then attach or launch a + // process... Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) @@ -259,8 +260,7 @@ GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess( lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); - // verify that we know anything about this pid. - // Scope for locker + // verify that we know anything about this pid. Scope for locker { std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { @@ -306,8 +306,8 @@ bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) { return true; } - // the launched process still lives. Now try killing it again, - // this time with an unblockable signal. + // the launched process still lives. Now try killing it again, this time + // with an unblockable signal. Host::Kill(pid, SIGKILL); for (size_t i = 0; i < 10; ++i) { @@ -321,8 +321,7 @@ bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) { usleep(10000); } - // check one more time after the final usleep - // Scope for locker + // check one more time after the final usleep Scope for locker { std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); if (m_spawned_pids.find(pid) == m_spawned_pids.end()) @@ -389,14 +388,13 @@ GDBRemoteCommunicationServerPlatform::Handle_qC( StreamString response; response.Printf("QC%" PRIx64, pid); - // If we launch a process and this GDB server is acting as a platform, - // then we need to clear the process launch state so we can start - // launching another process. In order to launch a process a bunch or - // packets need to be sent: environment packets, working directory, - // disable ASLR, and many more settings. When we launch a process we - // then need to know when to clear this information. Currently we are - // selecting the 'qC' packet as that packet which seems to make the most - // sense. + // If we launch a process and this GDB server is acting as a platform, then + // we need to clear the process launch state so we can start launching + // another process. In order to launch a process a bunch or packets need to + // be sent: environment packets, working directory, disable ASLR, and many + // more settings. When we launch a process we then need to know when to clear + // this information. Currently we are selecting the 'qC' packet as that + // packet which seems to make the most sense. if (pid != LLDB_INVALID_PROCESS_ID) { m_process_launch_info.Clear(); } @@ -445,9 +443,8 @@ Status GDBRemoteCommunicationServerPlatform::LaunchProcess() { return Status("%s: no process command line specified to launch", __FUNCTION__); - // specify the process monitor if not already set. This should - // generally be what happens since we need to reap started - // processes. + // specify the process monitor if not already set. This should generally be + // what happens since we need to reap started processes. if (!m_process_launch_info.GetMonitorProcessCallback()) m_process_launch_info.SetMonitorProcessCallback( std::bind( @@ -466,8 +463,8 @@ Status GDBRemoteCommunicationServerPlatform::LaunchProcess() { m_process_launch_info.GetArguments().GetArgumentAtIndex(0), m_process_launch_info.GetProcessID()); - // add to list of spawned processes. On an lldb-gdbserver, we - // would expect there to be only one. + // add to list of spawned processes. On an lldb-gdbserver, we would expect + // there to be only one. const auto pid = m_process_launch_info.GetProcessID(); if (pid != LLDB_INVALID_PROCESS_ID) { // add to spawned pids @@ -537,7 +534,7 @@ const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { if (domainsocket_dir_env != nullptr) g_domainsocket_dir = FileSpec(domainsocket_dir_env, false); else - HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, g_domainsocket_dir); + g_domainsocket_dir = HostInfo::GetProcessTempDir(); }); return g_domainsocket_dir; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index e418deee01f3..07dab751f4b9 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -25,7 +25,7 @@ #include "ThreadGDBRemote.h" #include "Utility/ARM_DWARF_Registers.h" #include "Utility/ARM_ehframe_Registers.h" -#include "Utility/StringExtractorGDBRemote.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" using namespace lldb; using namespace lldb_private; @@ -39,9 +39,9 @@ GDBRemoteRegisterContext::GDBRemoteRegisterContext( GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once) : RegisterContext(thread, concrete_frame_idx), m_reg_info(reg_info), m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once) { - // Resize our vector of bools to contain one bool for every register. - // We will use these boolean values to know when a register value - // is valid in m_reg_data. + // Resize our vector of bools to contain one bool for every register. We will + // use these boolean values to know when a register value is valid in + // m_reg_data. m_reg_valid.resize(reg_info.GetNumRegisters()); // Make a heap based buffer that is big enough to store all registers @@ -119,8 +119,8 @@ bool GDBRemoteRegisterContext::PrivateSetRegisterValue( if (success) { SetRegisterIsValid(reg, true); } else if (data.size() > 0) { - // Only set register is valid to false if we copied some bytes, else - // leave it as it was. + // Only set register is valid to false if we copied some bytes, else leave + // it as it was. SetRegisterIsValid(reg, false); } return success; @@ -133,11 +133,9 @@ bool GDBRemoteRegisterContext::PrivateSetRegisterValue(uint32_t reg, return false; // Early in process startup, we can get a thread that has an invalid byte - // order - // because the process hasn't been completely set up yet (see the ctor where - // the - // byte order is setfrom the process). If that's the case, we can't set the - // value here. + // order because the process hasn't been completely set up yet (see the ctor + // where the byte order is setfrom the process). If that's the case, we + // can't set the value here. if (m_reg_data.GetByteOrder() == eByteOrderInvalid) { return false; } @@ -149,8 +147,7 @@ bool GDBRemoteRegisterContext::PrivateSetRegisterValue(uint32_t reg, DataExtractor data(buffer_sp, endian::InlHostByteOrder(), sizeof(void *)); // If our register context and our register info disagree, which should never - // happen, don't - // overwrite past the end of the buffer. + // happen, don't overwrite past the end of the buffer. if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) return false; @@ -219,8 +216,7 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, } if (reg_info->value_regs) { // Process this composite register request by delegating to the - // constituent - // primordial registers. + // constituent primordial registers. // Index of the primordial register. bool success = true; @@ -228,8 +224,8 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, const uint32_t prim_reg = reg_info->value_regs[idx]; if (prim_reg == LLDB_INVALID_REGNUM) break; - // We have a valid primordial register as our constituent. - // Grab the corresponding register info. + // We have a valid primordial register as our constituent. Grab the + // corresponding register info. const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); if (prim_reg_info == NULL) success = false; @@ -242,8 +238,7 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, if (success) { // If we reach this point, all primordial register requests have - // succeeded. - // Validate this composite register. + // succeeded. Validate this composite register. SetRegisterIsValid(reg_info, true); } } else { @@ -262,16 +257,14 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, reg_info->byte_offset + reg_info->byte_size); #endif // If our register context and our register info disagree, which should - // never happen, don't - // read past the end of the buffer. + // never happen, don't read past the end of the buffer. if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) return false; - // If we aren't extracting into our own buffer (which - // only happens when this function is called from - // ReadRegisterValue(uint32_t, Scalar&)) then - // we transfer bytes from our buffer into the data - // buffer that was passed in + // If we aren't extracting into our own buffer (which only happens when + // this function is called from ReadRegisterValue(uint32_t, Scalar&)) then + // we transfer bytes from our buffer into the data buffer that was passed + // in data.SetByteOrder(m_reg_data.GetByteOrder()); data.SetData(m_reg_data, reg_info->byte_offset, reg_info->byte_size); @@ -321,8 +314,7 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, #endif // If our register context and our register info disagree, which should never - // happen, don't - // overwrite past the end of the buffer. + // happen, don't overwrite past the end of the buffer. if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) return false; @@ -358,12 +350,10 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, bool success = true; if (reg_info->value_regs) { - // This register is part of another register. In this case we read the - // actual - // register data for any "value_regs", and once all that data is read, - // we will - // have enough data in our register context bytes for the value of - // this register + // This register is part of another register. In this case we read + // the actual register data for any "value_regs", and once all that + // data is read, we will have enough data in our register context + // bytes for the value of this register // Invalidate this composite register first. @@ -371,8 +361,8 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, const uint32_t reg = reg_info->value_regs[idx]; if (reg == LLDB_INVALID_REGNUM) break; - // We have a valid primordial register as our constituent. - // Grab the corresponding register info. + // We have a valid primordial register as our constituent. Grab the + // corresponding register info. const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg); if (value_reg_info == NULL) success = false; @@ -385,8 +375,7 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, } // Check if writing this register will invalidate any other register - // values? - // If so, invalidate them + // values? If so, invalidate them if (reg_info->invalidate_regs) { for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0]; reg != LLDB_INVALID_REGNUM; @@ -548,26 +537,22 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( return true; uint32_t num_restored = 0; - // We need to manually go through all of the registers and - // restore them manually + // We need to manually go through all of the registers and restore them + // manually DataExtractor restore_data(data_sp, m_reg_data.GetByteOrder(), m_reg_data.GetAddressByteSize()); const RegisterInfo *reg_info; - // The g packet contents may either include the slice registers (registers - // defined in - // terms of other registers, e.g. eax is a subset of rax) or not. The - // slice registers - // should NOT be in the g packet, but some implementations may incorrectly - // include them. + // The g packet contents may either include the slice registers + // (registers defined in terms of other registers, e.g. eax is a subset + // of rax) or not. The slice registers should NOT be in the g packet, + // but some implementations may incorrectly include them. // // If the slice registers are included in the packet, we must step over - // the slice registers - // when parsing the packet -- relying on the RegisterInfo byte_offset - // field would be incorrect. - // If the slice registers are not included, then using the byte_offset - // values into the + // the slice registers when parsing the packet -- relying on the + // RegisterInfo byte_offset field would be incorrect. If the slice + // registers are not included, then using the byte_offset values into the // data buffer is the best way to find individual register values. uint64_t size_including_slice_registers = 0; @@ -591,21 +576,17 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( } else if (size_not_including_slice_registers == restore_data.GetByteSize()) { // The size of the packet is the same as concatenating all of the - // registers sequentially, - // skipping the slice registers + // registers sequentially, skipping the slice registers use_byte_offset_into_buffer = true; } else if (size_including_slice_registers == restore_data.GetByteSize()) { // The slice registers are present in the packet (when they shouldn't - // be). - // Don't try to use the RegisterInfo byte_offset into the restore_data, - // it will - // point to the wrong place. + // be). Don't try to use the RegisterInfo byte_offset into the + // restore_data, it will point to the wrong place. use_byte_offset_into_buffer = false; } else { // None of our expected sizes match the actual g packet data we're - // looking at. - // The most conservative approach here is to use the running total byte - // offset. + // looking at. The most conservative approach here is to use the + // running total byte offset. use_byte_offset_into_buffer = false; } @@ -664,11 +645,9 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( if (reg_info->value_regs) // skip registers that are slices of real // registers continue; - // Skip the fpsr and fpcr floating point status/control register writing - // to - // work around a bug in an older version of debugserver that would lead - // to - // register context corruption when writing fpsr/fpcr. + // Skip the fpsr and fpcr floating point status/control register + // writing to work around a bug in an older version of debugserver that + // would lead to register context corruption when writing fpsr/fpcr. if (arm64_debugserver && (strcmp(reg_info->name, "fpsr") == 0 || strcmp(reg_info->name, "fpcr") == 0)) { continue; @@ -752,8 +731,8 @@ void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) { static uint32_t g_q14_regs[] = {71, 72, LLDB_INVALID_REGNUM}; // (d28, d29) static uint32_t g_q15_regs[] = {73, 74, LLDB_INVALID_REGNUM}; // (d30, d31) - // This is our array of composite registers, with each element coming from the - // above register mappings. + // This is our array of composite registers, with each element coming from + // the above register mappings. static uint32_t *g_composites[] = { g_d0_regs, g_d1_regs, g_d2_regs, g_d3_regs, g_d4_regs, g_d5_regs, g_d6_regs, g_d7_regs, g_d8_regs, g_d9_regs, g_d10_regs, g_d11_regs, @@ -884,21 +863,17 @@ void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) { if (from_scratch) { // Calculate the offsets of the registers // Note that the layout of the "composite" registers (d0-d15 and q0-q15) - // which comes after the - // "primordial" registers is important. This enables us to calculate the - // offset of the composite - // register by using the offset of its first primordial register. For - // example, to calculate the - // offset of q0, use s0's offset. + // which comes after the "primordial" registers is important. This enables + // us to calculate the offset of the composite register by using the offset + // of its first primordial register. For example, to calculate the offset + // of q0, use s0's offset. if (g_register_infos[2].byte_offset == 0) { uint32_t byte_offset = 0; for (i = 0; i < num_registers; ++i) { // For primordial registers, increment the byte_offset by the byte_size - // to arrive at the - // byte_offset for the next register. Otherwise, we have a composite - // register whose - // offset can be calculated by consulting the offset of its first - // primordial register. + // to arrive at the byte_offset for the next register. Otherwise, we + // have a composite register whose offset can be calculated by + // consulting the offset of its first primordial register. if (!g_register_infos[i].value_regs) { g_register_infos[i].byte_offset = byte_offset; byte_offset += g_register_infos[i].byte_size; @@ -933,8 +908,8 @@ void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) { RegisterInfo *g_comp_register_infos = g_register_infos + num_common_regs; // First we need to validate that all registers that we already have match - // the non composite regs. - // If so, then we can add the registers, else we need to bail + // the non composite regs. If so, then we can add the registers, else we + // need to bail bool match = true; if (num_dynamic_regs == num_common_regs) { for (i = 0; match && i < num_dynamic_regs; ++i) { @@ -970,9 +945,8 @@ void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) { // Find a matching primordial register info entry. if (reg_info && reg_info->name && ::strcasecmp(reg_info->name, reg_name) == 0) { - // The name matches the existing primordial entry. - // Find and assign the offset, and then add this composite - // register entry. + // The name matches the existing primordial entry. Find and + // assign the offset, and then add this composite register entry. g_comp_register_infos[i].byte_offset = reg_info->byte_offset; name.SetCString(g_comp_register_infos[i].name); AddRegister(g_comp_register_infos[i], name, alt_name, diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 35d02c15ab85..b3d33b19bd66 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -24,6 +24,7 @@ // C++ Includes #include <algorithm> +#include <csignal> #include <map> #include <mutex> #include <sstream> @@ -46,11 +47,11 @@ #include "lldb/Host/Symbols.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/XML.h" -#include "lldb/Interpreter/Args.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/Interpreter/OptionGroupUInt64.h" #include "lldb/Interpreter/OptionValueProperties.h" @@ -59,10 +60,12 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" #include "lldb/Target/ThreadPlanCallFunction.h" +#include "lldb/Utility/Args.h" #include "lldb/Utility/CleanUp.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StreamString.h" @@ -77,8 +80,8 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "ThreadGDBRemote.h" -#include "Utility/StringExtractorGDBRemote.h" #include "lldb/Host/Host.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Threading.h" @@ -91,11 +94,11 @@ using namespace lldb_private::process_gdb_remote; namespace lldb { // Provide a function that can easily dump the packet history if we know a -// ProcessGDBRemote * value (which we can get from logs or from debugging). -// We need the function in the lldb namespace so it makes it into the final +// ProcessGDBRemote * value (which we can get from logs or from debugging). We +// need the function in the lldb namespace so it makes it into the final // executable since the LLDB shared library only exports stuff in the lldb -// namespace. This allows you to attach with a debugger and call this -// function and get the packet history dumped to a file. +// namespace. This allows you to attach with a debugger and call this function +// 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 | @@ -158,8 +161,8 @@ static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() { } // anonymous namespace end // 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 to debugserver. +// ephemeral port from the kernel and make sure we reserve it before passing it +// to debugserver. #if defined(__APPLE__) #define LOW_PORT (IPPORT_RESERVED) @@ -233,8 +236,8 @@ bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp, } return exe_module->GetFileSpec().Exists(); } - // However, if there is no executable module, we return true since we might be - // preparing to attach. + // However, if there is no executable module, we return true since we might + // be preparing to attach. return true; } @@ -256,7 +259,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_initial_tid(LLDB_INVALID_THREAD_ID), m_allow_flash_writes(false), + m_erased_flash_ranges() { m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, @@ -299,17 +303,16 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, ProcessGDBRemote::~ProcessGDBRemote() { // m_mach_process.UnregisterNotificationCallbacks (this); Clear(); - // We need to call finalize on the process before destroying ourselves - // to make sure all of the broadcaster cleanup goes as planned. If we - // destruct this class, then Process::~Process() might have problems - // trying to fully destroy the broadcaster. + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. Finalize(); - // The general Finalize is going to try to destroy the process and that SHOULD - // shut down the async thread. However, if we don't kill it it will get - // stranded and - // its connection will go away so when it wakes up it will crash. So kill it - // for sure here. + // The general Finalize is going to try to destroy the process and that + // SHOULD shut down the async thread. However, if we don't kill it it will + // get stranded and its connection will go away so when it wakes up it will + // crash. So kill it for sure here. StopAsyncThread(); KillDebugserverProcess(); } @@ -368,8 +371,7 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition( } // If the remote stub didn't give us eh_frame or DWARF register numbers for a -// register, -// see if the ABI can provide them. +// register, see if the ABI can provide them. // DWARF and eh_frame register numbers are defined as a part of the ABI. static void AugmentRegisterInfoViaABI(RegisterInfo ®_info, ConstString reg_name, ABISP abi_sp) { @@ -422,9 +424,9 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { m_register_info.Clear(); - // Check if qHostInfo specified a specific packet timeout for this connection. - // If so then lets update our setting so the user knows what the timeout is - // and can see it. + // Check if qHostInfo specified a specific packet timeout for this + // connection. If so then lets update our setting so the user knows what the + // timeout is and can see it. const auto host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout(); if (host_packet_timeout > std::chrono::seconds(0)) { GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout.count()); @@ -531,7 +533,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { reg_info.encoding = encoding; } else if (name.equals("format")) { Format format = eFormatInvalid; - if (Args::StringToFormat(value.str().c_str(), format, NULL) + if (OptionArgParser::ToFormat(value.str().c_str(), format, NULL) .Success()) reg_info.format = format; else { @@ -596,10 +598,8 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { } // We have to make a temporary ABI here, and not use the GetABI because - // this code - // gets called in DidAttach, when the target architecture (and - // consequently the ABI we'll get from - // the process) may be wrong. + // this code gets called in DidAttach, when the target architecture + // (and consequently the ABI we'll get from the process) may be wrong. ABISP abi_to_use = ABI::FindPlugin(shared_from_this(), arch_to_use); AugmentRegisterInfoViaABI(reg_info, reg_name, abi_to_use); @@ -620,9 +620,9 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { // We didn't get anything if the accumulated reg_num is zero. See if we are // debugging ARM and fill with a hard coded register set until we can get an - // updated debugserver down on the devices. - // On the other hand, if the accumulated reg_num is positive, see if we can - // add composite registers to the existing primordial ones. + // updated debugserver down on the devices. On the other hand, if the + // accumulated reg_num is positive, see if we can add composite registers to + // the existing primordial ones. bool from_scratch = (m_register_info.GetNumRegisters() == 0); if (!target_arch.IsValid()) { @@ -669,9 +669,8 @@ Status ProcessGDBRemote::DoConnectRemote(Stream *strm, lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); if (pid == LLDB_INVALID_PROCESS_ID) { - // We don't have a valid process ID, so note that we are connected - // and could now request to launch or attach, or get remote process - // listings... + // We don't have a valid process ID, so note that we are connected and + // could now request to launch or attach, or get remote process listings... SetPrivateState(eStateConnected); } else { // We have a valid process @@ -721,7 +720,8 @@ Status ProcessGDBRemote::DoConnectRemote(Stream *strm, if (error.Success() && !GetTarget().GetArchitecture().IsValid() && m_gdb_comm.GetHostArchitecture().IsValid()) { - // Prefer the *process'* architecture over that of the *host*, if available. + // Prefer the *process'* architecture over that of the *host*, if + // available. if (m_gdb_comm.GetProcessArchitecture().IsValid()) GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture()); else @@ -800,8 +800,8 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module, const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; if (stdin_file_spec || disable_stdio) { - // the inferior will be reading stdin from the specified file - // or stdio is completely disabled + // the inferior will be reading stdin from the specified file or stdio is + // completely disabled m_stdin_forward = false; } else { m_stdin_forward = true; @@ -824,11 +824,14 @@ 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, false, + FileSpec::Style::native); if (!stdout_file_spec) - stdout_file_spec.SetFile(FileSystem::DEV_NULL, false); + stdout_file_spec.SetFile(FileSystem::DEV_NULL, false, + FileSpec::Style::native); if (!stderr_file_spec) - stderr_file_spec.SetFile(FileSystem::DEV_NULL, false); + stderr_file_spec.SetFile(FileSystem::DEV_NULL, false, + FileSpec::Style::native); } else if (platform_sp && platform_sp->IsHost()) { // If the debugserver is local and we aren't disabling STDIO, lets use // a pseudo terminal to instead of relying on the 'O' packets for stdio @@ -888,16 +891,7 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module, } // Send the environment and the program + arguments after we connect - const Args &environment = launch_info.GetEnvironmentEntries(); - if (environment.GetArgumentCount()) { - size_t num_environment_entries = environment.GetArgumentCount(); - for (size_t i = 0; i < num_environment_entries; ++i) { - const char *env_entry = environment.GetArgumentAtIndex(i); - if (env_entry == NULL || - m_gdb_comm.SendEnvironmentPacket(env_entry) != 0) - break; - } - } + m_gdb_comm.SendEnvironment(launch_info.GetEnvironment()); { // Scope for the scoped timeout object @@ -1004,16 +998,15 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) { return error; } - // Start the communications read thread so all incoming data can be - // parsed into packets and queued as they arrive. + // Start the communications read thread so all incoming data can be parsed + // into packets and queued as they arrive. if (GetTarget().GetNonStopModeEnabled()) m_gdb_comm.StartReadThread(); - // We always seem to be able to open a connection to a local port - // so we need to make sure we can then send data to it. If we can't - // then we aren't actually connected to anything, so try and do the - // handshake with the remote GDB server and make sure that goes - // alright. + // We always seem to be able to open a connection to a local port so we need + // to make sure we can then send data to it. If we can't then we aren't + // actually connected to anything, so try and do the handshake with the + // remote GDB server and make sure that goes alright. if (!m_gdb_comm.HandshakeWithServer(&error)) { m_gdb_comm.Disconnect(); if (error.Success()) @@ -1055,9 +1048,9 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { // See if the GDB server supports the qHostInfo information - // See if the GDB server supports the qProcessInfo packet, if so - // prefer that over the Host information as it will be more specific - // to our process. + // See if the GDB server supports the qProcessInfo packet, if so prefer + // that over the Host information as it will be more specific to our + // process. const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); if (remote_process_arch.IsValid()) { @@ -1102,9 +1095,8 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { // architectures. // You can have an armv6 executable, and if the host is armv7, then the // system will load the best possible architecture for all shared - // libraries - // it has, so we really need to take the remote host architecture as our - // defacto architecture in this case. + // libraries it has, so we really need to take the remote host + // architecture as our defacto architecture in this case. if ((process_arch.GetMachine() == llvm::Triple::arm || process_arch.GetMachine() == llvm::Triple::thumb) && @@ -1150,14 +1142,14 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { ? target_arch.GetTriple().getTriple().c_str() : "<null>"); } else { - // The target doesn't have a valid architecture yet, set it from - // the architecture we got from the remote GDB server + // The target doesn't have a valid architecture yet, set it from the + // architecture we got from the remote GDB server GetTarget().SetArchitecture(process_arch); } } - // Find out which StructuredDataPlugins are supported by the - // debug monitor. These plugins transmit data over async $J packets. + // Find out which StructuredDataPlugins are supported by the debug monitor. + // These plugins transmit data over async $J packets. auto supported_packets_array = m_gdb_comm.GetSupportedStructuredDataPlugins(); if (supported_packets_array) @@ -1365,9 +1357,9 @@ Status ProcessGDBRemote::DoResume() { continue_packet_error = true; if (continue_packet_error) { - // Either no vCont support, or we tried to use part of the vCont - // packet that wasn't supported by the remote GDB server. - // We need to try and make a simple packet that can do our continue + // Either no vCont support, or we tried to use part of the vCont packet + // that wasn't supported by the remote GDB server. We need to try and + // make a simple packet that can do our continue const size_t num_continue_c_tids = m_continue_c_tids.size(); const size_t num_continue_C_tids = m_continue_C_tids.size(); const size_t num_continue_s_tids = m_continue_s_tids.size(); @@ -1394,11 +1386,10 @@ Status ProcessGDBRemote::DoResume() { const int continue_signo = m_continue_C_tids.front().second; // Only one thread is continuing if (num_continue_C_tids > 1) { - // More that one thread with a signal, yet we don't have - // vCont support and we are being asked to resume each - // thread with a signal, we need to make sure they are - // all the same signal, or we can't issue the continue - // accurately with the current support... + // More that one thread with a signal, yet we don't have vCont + // support and we are being asked to resume each thread with a + // signal, we need to make sure they are all the same signal, or we + // can't issue the continue accurately with the current support... if (num_continue_C_tids > 1) { continue_packet_error = false; for (size_t i = 1; i < m_continue_C_tids.size(); ++i) { @@ -1532,7 +1523,6 @@ void ProcessGDBRemote::ClearThreadIDList() { size_t ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue(std::string &value) { m_thread_ids.clear(); - m_thread_pcs.clear(); size_t comma_pos; lldb::tid_t tid; while ((comma_pos = value.find(',')) != std::string::npos) { @@ -1675,9 +1665,8 @@ bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list, } } - // Whatever that is left in old_thread_list_copy are not - // present in new_thread_list. Remove non-existent threads from internal id - // table. + // Whatever that is left in old_thread_list_copy are not present in + // new_thread_list. Remove non-existent threads from internal id table. size_t old_num_thread_ids = old_thread_list_copy.GetSize(false); for (size_t i = 0; i < old_num_thread_ids; i++) { ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false)); @@ -1738,12 +1727,11 @@ bool ProcessGDBRemote::CalculateThreadStopInfo(ThreadGDBRemote *thread) { return true; // See if we got thread stop info for any threads valid stop info reasons - // threads - // via the "jstopinfo" packet stop reply packet key/value pair? + // threads via the "jstopinfo" packet stop reply packet key/value pair? if (m_jstopinfo_sp) { // If we have "jstopinfo" then we have stop descriptions for all threads - // that have stop reasons, and if there is no entry for a thread, then - // it has no stop reason. + // that have stop reasons, and if there is no entry for a thread, then it + // has no stop reason. thread->GetRegisterContext()->InvalidateIfNeeded(true); if (!GetThreadStopInfoFromJSON(thread, m_jstopinfo_sp)) { thread->SetStopInfo(StopInfoSP()); @@ -1771,9 +1759,8 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( if (tid != LLDB_INVALID_THREAD_ID) { // Scope for "locker" below { - // m_thread_list_real does have its own mutex, but we need to - // hold onto the mutex between the call to - // m_thread_list_real.FindThreadByID(...) + // m_thread_list_real does have its own mutex, but we need to hold onto + // the mutex between the call to m_thread_list_real.FindThreadByID(...) // and the m_thread_list_real.AddThread(...) so it doesn't change on us std::lock_guard<std::recursive_mutex> guard( m_thread_list_real.GetMutex()); @@ -1827,10 +1814,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( if (!thread_sp->StopInfoIsUpToDate()) { thread_sp->SetStopInfo(StopInfoSP()); // If there's a memory thread backed by this thread, we need to use it - // to calcualte StopInfo. - ThreadSP memory_thread_sp = - m_thread_list.FindThreadByProtocolID(thread_sp->GetProtocolID()); - if (memory_thread_sp) + // to calculate StopInfo. + if (ThreadSP memory_thread_sp = + m_thread_list.GetBackingThread(thread_sp)) thread_sp = memory_thread_sp; if (exc_type != 0) { @@ -1852,9 +1838,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( ->GetBreakpointSiteList() .FindByAddress(pc); - // If the current pc is a breakpoint site then the StopInfo should - // be set to Breakpoint - // Otherwise, it will be set to Trace. + // If the current pc is a breakpoint site then the StopInfo + // should be set to Breakpoint Otherwise, it will be set to + // Trace. if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) { thread_sp->SetStopInfo( @@ -1871,11 +1857,10 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( .FindByAddress(pc); if (bp_site_sp) { // If the breakpoint is for this thread, then we'll report the - // hit, but if it is for another thread, - // we can just report no reason. We don't need to worry about - // stepping over the breakpoint here, that - // will be taken care of when the thread resumes and notices - // that there's a breakpoint under the pc. + // hit, but if it is for another thread, we can just report no + // reason. We don't need to worry about stepping over the + // breakpoint here, that will be taken care of when the thread + // resumes and notices that there's a breakpoint under the pc. handled = true; if (bp_site_sp->ValidForThisThread(thread_sp.get())) { thread_sp->SetStopInfo( @@ -1937,13 +1922,10 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( pc); // If the current pc is a breakpoint site then the StopInfo should - // be set to Breakpoint - // even though the remote stub did not set it as such. This can - // happen when - // the thread is involuntarily interrupted (e.g. due to stops on - // other - // threads) just as it is about to execute the breakpoint - // instruction. + // be set to Breakpoint even though the remote stub did not set it + // as such. This can happen when the thread is involuntarily + // interrupted (e.g. due to stops on other threads) just as it is + // about to execute the breakpoint instruction. if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) { thread_sp->SetStopInfo( StopInfo::CreateStopReasonWithBreakpointSiteID( @@ -1965,11 +1947,10 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( if (bp_site_sp) { // If the breakpoint is for this thread, then we'll report the - // hit, but if it is for another thread, - // we can just report no reason. We don't need to worry about - // stepping over the breakpoint here, that - // will be taken care of when the thread resumes and notices - // that there's a breakpoint under the pc. + // hit, but if it is for another thread, we can just report no + // reason. We don't need to worry about stepping over the + // breakpoint here, that will be taken care of when the thread + // resumes and notices that there's a breakpoint under the pc. if (bp_site_sp->ValidForThisThread(thread_sp.get())) { if (m_breakpoint_pc_offset != 0) thread_sp->GetRegisterContext()->SetPC(pc); @@ -1982,8 +1963,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( } } else { // If we were stepping then assume the stop was the result of - // the trace. If we were - // not stepping then report the SIGTRAP. + // the trace. If we were not stepping then report the SIGTRAP. // FIXME: We are still missing the case where we single step // over a trap instruction. if (thread_sp->GetTemporaryResumeState() == eStateStepping) @@ -2178,15 +2158,15 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { switch (stop_type) { case 'T': case 'S': { - // This is a bit of a hack, but is is required. If we did exec, we - // need to clear our thread lists and also know to rebuild our dynamic - // register info before we lookup and threads and populate the expedited - // register values so we need to know this right away so we can cleanup - // and update our registers. + // This is a bit of a hack, but is is required. If we did exec, we need to + // clear our thread lists and also know to rebuild our dynamic register + // info before we lookup and threads and populate the expedited register + // values so we need to know this right away so we can cleanup and update + // our registers. const uint32_t stop_id = GetStopID(); if (stop_id == 0) { - // Our first stop, make sure we have a process ID, and also make - // sure we know about our registers + // Our first stop, make sure we have a process ID, and also make sure we + // know about our registers if (GetID() == LLDB_INVALID_PROCESS_ID) { lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); if (pid != LLDB_INVALID_PROCESS_ID) @@ -2232,8 +2212,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { m_thread_ids.clear(); // A comma separated list of all threads in the current - // process that includes the thread for this stop reply - // packet + // process that includes the thread for this stop reply packet lldb::tid_t tid; while (!value.empty()) { llvm::StringRef tid_str; @@ -2245,8 +2224,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { } else if (key.compare("thread-pcs") == 0) { m_thread_pcs.clear(); // A comma separated list of all threads in the current - // process that includes the thread for this stop reply - // packet + // process that includes the thread for this stop reply packet lldb::addr_t pc; while (!value.empty()) { llvm::StringRef pc_str; @@ -2298,13 +2276,10 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { desc_extractor.GetHexByteString(description); } else if (key.compare("memory") == 0) { // Expedited memory. GDB servers can choose to send back expedited - // memory - // that can populate the L1 memory cache in the process so that things - // like - // the frame pointer backchain can be expedited. This will help stack - // backtracing be more efficient by not having to send as many memory - // read - // requests down the remote GDB server. + // memory that can populate the L1 memory cache in the process so that + // things like the frame pointer backchain can be expedited. This will + // help stack backtracing be more efficient by not having to send as + // many memory read requests down the remote GDB server. // Key/value pair format: memory:<addr>=<bytes>; // <addr> is a number whose base will be interpreted by the prefix: @@ -2356,7 +2331,8 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { if (tid == LLDB_INVALID_THREAD_ID) { // A thread id may be invalid if the response is old style 'S' packet // which does not provide the - // thread information. So update the thread list and choose the first one. + // thread information. So update the thread list and choose the first + // one. UpdateThreadIDList(); if (!m_thread_ids.empty()) { @@ -2389,9 +2365,9 @@ void ProcessGDBRemote::RefreshStateAfterStop() { m_thread_ids.clear(); m_thread_pcs.clear(); - // Set the thread stop info. It might have a "threads" key whose value is - // a list of all thread IDs in the current process, so m_thread_ids might - // get set. + // Set the thread stop info. It might have a "threads" key whose value is a + // list of all thread IDs in the current process, so m_thread_ids might get + // set. // Scope for the lock { @@ -2422,8 +2398,8 @@ void ProcessGDBRemote::RefreshStateAfterStop() { m_initial_tid = LLDB_INVALID_THREAD_ID; } - // Let all threads recover from stopping and do any clean up based - // on the previous thread state (if any). + // Let all threads recover from stopping and do any clean up based on the + // previous thread state (if any). m_thread_list_real.RefreshStateAfterStop(); } @@ -2431,8 +2407,8 @@ Status ProcessGDBRemote::DoHalt(bool &caused_stop) { Status error; if (m_public_state.GetValue() == eStateAttaching) { - // We are being asked to halt during an attach. We need to just close - // our file handle and debugserver will go away, and we can be done... + // We are being asked to halt during an attach. We need to just close our + // file handle and debugserver will go away, and we can be done... m_gdb_comm.Disconnect(); } else caused_stop = m_gdb_comm.Interrupt(); @@ -2475,31 +2451,24 @@ Status ProcessGDBRemote::DoDestroy() { log->Printf("ProcessGDBRemote::DoDestroy()"); // There is a bug in older iOS debugservers where they don't shut down the - // process - // they are debugging properly. If the process is sitting at a breakpoint or - // an exception, - // this can cause problems with restarting. So we check to see if any of our - // threads are stopped - // at a breakpoint, and if so we remove all the breakpoints, resume the - // process, and THEN - // destroy it again. + // process they are debugging properly. If the process is sitting at a + // breakpoint or an exception, this can cause problems with restarting. So + // we check to see if any of our threads are stopped at a breakpoint, and if + // so we remove all the breakpoints, resume the process, and THEN destroy it + // again. // // Note, we don't have a good way to test the version of debugserver, but I - // happen to know that - // the set of all the iOS debugservers which don't support - // GetThreadSuffixSupported() and that of - // the debugservers with this bug are equal. There really should be a better - // way to test this! + // happen to know that the set of all the iOS debugservers which don't + // support GetThreadSuffixSupported() and that of the debugservers with this + // bug are equal. There really should be a better way to test this! // // We also use m_destroy_tried_resuming to make sure we only do this once, if - // we resume and then halt and - // get called here to destroy again and we're still at a breakpoint or - // exception, then we should - // just do the straight-forward kill. + // we resume and then halt and get called here to destroy again and we're + // still at a breakpoint or exception, then we should just do the straight- + // forward kill. // // And of course, if we weren't able to stop the process by the time we get - // here, it isn't - // necessary (or helpful) to do any of this. + // here, it isn't necessary (or helpful) to do any of this. if (!m_gdb_comm.GetThreadSuffixSupported() && m_public_state.GetValue() != eStateRunning) { @@ -2514,9 +2483,8 @@ Status ProcessGDBRemote::DoDestroy() { "destroy once already, not doing it again."); } else { // At present, the plans are discarded and the breakpoints disabled - // Process::Destroy, - // but we really need it to happen here and it doesn't matter if we do - // it twice. + // Process::Destroy, but we really need it to happen here and it + // doesn't matter if we do it twice. m_thread_list.DiscardThreadPlans(); DisableAllBreakpointSites(); @@ -2553,12 +2521,11 @@ Status ProcessGDBRemote::DoDestroy() { m_destroy_tried_resuming = true; // If we are going to run again before killing, it would be good to - // suspend all the threads - // before resuming so they won't get into more trouble. Sadly, for - // the threads stopped with - // the breakpoint or exception, the exception doesn't get cleared if - // it is suspended, so we do - // have to run the risk of letting those threads proceed a bit. + // suspend all the threads before resuming so they won't get into + // more trouble. Sadly, for the threads stopped with the breakpoint + // or exception, the exception doesn't get cleared if it is + // suspended, so we do have to run the risk of letting those threads + // proceed a bit. { std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); @@ -2605,17 +2572,14 @@ Status ProcessGDBRemote::DoDestroy() { if (packet_cmd == 'W' || packet_cmd == 'X') { #if defined(__APPLE__) // For Native processes on Mac OS X, we launch through the Host - // Platform, then hand the process off - // to debugserver, which becomes the parent process through - // "PT_ATTACH". Then when we go to kill - // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then we - // call waitpid which returns - // with no error and the correct status. But amusingly enough that - // doesn't seem to actually reap + // Platform, then hand the process off to debugserver, which becomes + // the parent process through "PT_ATTACH". Then when we go to kill + // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then + // we call waitpid which returns with no error and the correct + // status. But amusingly enough that doesn't seem to actually reap // the process, but instead it is left around as a Zombie. Probably - // the kernel is in the process of - // switching ownership back to lldb which was the original parent, and - // gets confused in the handoff. + // the kernel is in the process of switching ownership back to lldb + // which was the original parent, and gets confused in the handoff. // Anyway, so call waitpid here to finally reap it. PlatformSP platform_sp(GetTarget().GetPlatform()); if (platform_sp && platform_sp->IsHost()) { @@ -2687,9 +2651,8 @@ void ProcessGDBRemote::SetLastStopPacket( if (GetTarget().GetNonStopModeEnabled() == false) m_stop_packet_stack.clear(); - // Add this stop packet to the stop packet stack - // This stack will get popped and examined when we switch to the - // Stopped state + // Add this stop packet to the stop packet stack This stack will get popped + // and examined when we switch to the Stopped state m_stop_packet_stack.push_back(response); } } @@ -2721,12 +2684,11 @@ addr_t ProcessGDBRemote::GetImageInfoAddress() { } void ProcessGDBRemote::WillPublicStop() { - // See if the GDB remote client supports the JSON threads info. - // If so, we gather stop info for all threads, expedited registers, - // expedited memory, runtime queue information (iOS and MacOSX only), - // and more. Expediting memory will help stack backtracing be much - // faster. Expediting registers will make sure we don't have to read - // the thread registers for GPRs. + // See if the GDB remote client supports the JSON threads info. If so, we + // gather stop info for all threads, expedited registers, expedited memory, + // runtime queue information (iOS and MacOSX only), and more. Expediting + // memory will help stack backtracing be much faster. Expediting registers + // will make sure we don't have to read the thread registers for GPRs. m_jthreadsinfo_sp = m_gdb_comm.GetThreadsInfo(); if (m_jthreadsinfo_sp) { @@ -2776,14 +2738,13 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size, error.Clear(); if (binary_memory_read) { // The lower level GDBRemoteCommunication packet receive layer has - // already de-quoted any - // 0x7d character escaping that was present in the packet + // already de-quoted any 0x7d character escaping that was present in + // the packet size_t data_received_size = response.GetBytesLeft(); if (data_received_size > size) { // Don't write past the end of BUF if the remote debug server gave us - // too - // much data for some reason. + // too much data for some reason. data_received_size = size; } memcpy(buf, response.GetStringRef().data(), data_received_size); @@ -2807,6 +2768,145 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size, return 0; } +Status ProcessGDBRemote::WriteObjectFile( + std::vector<ObjectFile::LoadableData> entries) { + Status error; + // Sort the entries by address because some writes, like those to flash + // memory, must happen in order of increasing address. + std::stable_sort( + std::begin(entries), std::end(entries), + [](const ObjectFile::LoadableData a, const ObjectFile::LoadableData b) { + return a.Dest < b.Dest; + }); + m_allow_flash_writes = true; + error = Process::WriteObjectFile(entries); + if (error.Success()) + error = FlashDone(); + else + // Even though some of the writing failed, try to send a flash done if some + // of the writing succeeded so the flash state is reset to normal, but + // don't stomp on the error status that was set in the write failure since + // that's the one we want to report back. + FlashDone(); + m_allow_flash_writes = false; + return error; +} + +bool ProcessGDBRemote::HasErased(FlashRange range) { + auto size = m_erased_flash_ranges.GetSize(); + for (size_t i = 0; i < size; ++i) + if (m_erased_flash_ranges.GetEntryAtIndex(i)->Contains(range)) + return true; + return false; +} + +Status ProcessGDBRemote::FlashErase(lldb::addr_t addr, size_t size) { + Status status; + + MemoryRegionInfo region; + status = GetMemoryRegionInfo(addr, region); + if (!status.Success()) + return status; + + // The gdb spec doesn't say if erasures are allowed across multiple regions, + // but we'll disallow it to be safe and to keep the logic simple by worring + // about only one region's block size. DoMemoryWrite is this function's + // primary user, and it can easily keep writes within a single memory region + if (addr + size > region.GetRange().GetRangeEnd()) { + status.SetErrorString("Unable to erase flash in multiple regions"); + return status; + } + + uint64_t blocksize = region.GetBlocksize(); + if (blocksize == 0) { + status.SetErrorString("Unable to erase flash because blocksize is 0"); + return status; + } + + // Erasures can only be done on block boundary adresses, so round down addr + // and round up size + lldb::addr_t block_start_addr = addr - (addr % blocksize); + size += (addr - block_start_addr); + if ((size % blocksize) != 0) + size += (blocksize - size % blocksize); + + FlashRange range(block_start_addr, size); + + if (HasErased(range)) + return status; + + // We haven't erased the entire range, but we may have erased part of it. + // (e.g., block A is already erased and range starts in A and ends in B). So, + // adjust range if necessary to exclude already erased blocks. + if (!m_erased_flash_ranges.IsEmpty()) { + // Assuming that writes and erasures are done in increasing addr order, + // because that is a requirement of the vFlashWrite command. Therefore, we + // only need to look at the last range in the list for overlap. + const auto &last_range = *m_erased_flash_ranges.Back(); + if (range.GetRangeBase() < last_range.GetRangeEnd()) { + auto overlap = last_range.GetRangeEnd() - range.GetRangeBase(); + // overlap will be less than range.GetByteSize() or else HasErased() + // would have been true + range.SetByteSize(range.GetByteSize() - overlap); + range.SetRangeBase(range.GetRangeBase() + overlap); + } + } + + StreamString packet; + packet.Printf("vFlashErase:%" PRIx64 ",%" PRIx64, range.GetRangeBase(), + (uint64_t)range.GetByteSize()); + + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, + true) == + GDBRemoteCommunication::PacketResult::Success) { + if (response.IsOKResponse()) { + m_erased_flash_ranges.Insert(range, true); + } else { + if (response.IsErrorResponse()) + status.SetErrorStringWithFormat("flash erase failed for 0x%" PRIx64, + addr); + else if (response.IsUnsupportedResponse()) + status.SetErrorStringWithFormat("GDB server does not support flashing"); + else + status.SetErrorStringWithFormat( + "unexpected response to GDB server flash erase packet '%s': '%s'", + packet.GetData(), response.GetStringRef().c_str()); + } + } else { + status.SetErrorStringWithFormat("failed to send packet: '%s'", + packet.GetData()); + } + return status; +} + +Status ProcessGDBRemote::FlashDone() { + Status status; + // If we haven't erased any blocks, then we must not have written anything + // either, so there is no need to actually send a vFlashDone command + if (m_erased_flash_ranges.IsEmpty()) + return status; + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse("vFlashDone", response, true) == + GDBRemoteCommunication::PacketResult::Success) { + if (response.IsOKResponse()) { + m_erased_flash_ranges.Clear(); + } else { + if (response.IsErrorResponse()) + status.SetErrorStringWithFormat("flash done failed"); + else if (response.IsUnsupportedResponse()) + status.SetErrorStringWithFormat("GDB server does not support flashing"); + else + status.SetErrorStringWithFormat( + "unexpected response to GDB server flash done packet: '%s'", + response.GetStringRef().c_str()); + } + } else { + status.SetErrorStringWithFormat("failed to send flash done packet"); + } + return status; +} + size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf, size_t size, Status &error) { GetMaxMemorySize(); @@ -2819,10 +2919,33 @@ size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf, size = max_memory_size; } - StreamString packet; - packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size); - packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(), - endian::InlHostByteOrder()); + StreamGDBRemote packet; + + MemoryRegionInfo region; + Status region_status = GetMemoryRegionInfo(addr, region); + + bool is_flash = + region_status.Success() && region.GetFlash() == MemoryRegionInfo::eYes; + + if (is_flash) { + if (!m_allow_flash_writes) { + error.SetErrorString("Writing to flash memory is not allowed"); + return 0; + } + // Keep the write within a flash memory region + if (addr + size > region.GetRange().GetRangeEnd()) + size = region.GetRange().GetRangeEnd() - addr; + // Flash memory must be erased before it can be written + error = FlashErase(addr, size); + if (!error.Success()) + return 0; + packet.Printf("vFlashWrite:%" PRIx64 ":", addr); + packet.PutEscapedBytes(buf, size); + } else { + packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size); + packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(), + endian::InlHostByteOrder()); + } StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, true) == @@ -2918,8 +3041,8 @@ Status ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) { switch (supported) { case eLazyBoolCalculate: - // We should never be deallocating memory without allocating memory - // first so we should never get eLazyBoolCalculate + // We should never be deallocating memory without allocating memory first + // so we should never get eLazyBoolCalculate error.SetErrorString( "tried to deallocate memory without ever allocating memory"); break; @@ -2991,18 +3114,14 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site); // SupportsGDBStoppointPacket() simply checks a boolean, indicating if this - // breakpoint type - // is supported by the remote stub. These are set to true by default, and - // later set to false - // only after we receive an unimplemented response when sending a breakpoint - // packet. This means - // initially that unless we were specifically instructed to use a hardware - // breakpoint, LLDB will - // attempt to set a software breakpoint. HardwareRequired() also queries a - // boolean variable which - // indicates if the user specifically asked for hardware breakpoints. If true - // then we will - // skip over software breakpoints. + // breakpoint type is supported by the remote stub. These are set to true by + // default, and later set to false only after we receive an unimplemented + // response when sending a breakpoint packet. This means initially that + // unless we were specifically instructed to use a hardware breakpoint, LLDB + // will attempt to set a software breakpoint. HardwareRequired() also queries + // a boolean variable which indicates if the user specifically asked for + // hardware breakpoints. If true then we will skip over software + // breakpoints. if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) && (!bp_site->HardwareRequired())) { // Try to send off a software breakpoint packet ($Z0) @@ -3015,19 +3134,14 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { return error; } - // SendGDBStoppointTypePacket() will return an error if it was unable to set - // this - // breakpoint. We need to differentiate between a error specific to placing - // this breakpoint - // or if we have learned that this breakpoint type is unsupported. To do - // this, we - // must test the support boolean for this breakpoint type to see if it now - // indicates that - // this breakpoint type is unsupported. If they are still supported then we - // should return + // SendGDBStoppointTypePacket() will return an error if it was unable to + // set this breakpoint. We need to differentiate between a error specific + // to placing this breakpoint or if we have learned that this breakpoint + // type is unsupported. To do this, we must test the support boolean for + // this breakpoint type to see if it now indicates that this breakpoint + // type is unsupported. If they are still supported then we should return // with the error code. If they are now unsupported, then we would like to - // fall through - // and try another form of breakpoint. + // fall through and try another form of breakpoint. if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) { if (error_no != UINT8_MAX) error.SetErrorStringWithFormat( @@ -3038,21 +3152,18 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { } // We reach here when software breakpoints have been found to be - // unsupported. For future - // calls to set a breakpoint, we will not attempt to set a breakpoint with a - // type that is - // known not to be supported. + // unsupported. For future calls to set a breakpoint, we will not attempt + // to set a breakpoint with a type that is known not to be supported. if (log) log->Printf("Software breakpoints are unsupported"); // So we will fall through and try a hardware breakpoint } - // The process of setting a hardware breakpoint is much the same as above. We - // check the - // supported boolean for this breakpoint type, and if it is thought to be - // supported then we - // will try to set this breakpoint with a hardware breakpoint. + // The process of setting a hardware breakpoint is much the same as above. + // We check the supported boolean for this breakpoint type, and if it is + // thought to be supported then we will try to set this breakpoint with a + // hardware breakpoint. if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) { // Try to send off a hardware breakpoint packet ($Z1) uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket( @@ -3094,8 +3205,8 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { return error; } - // As a last resort we want to place a manual breakpoint. An instruction - // is placed into the process memory using memory write packets. + // As a last resort we want to place a manual breakpoint. An instruction is + // placed into the process memory using memory write packets. return EnableSoftwareBreakpoint(bp_site); } @@ -3225,10 +3336,9 @@ Status ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) { log->Printf("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", watchID, (uint64_t)addr); - // See also 'class WatchpointSentry' within StopInfo.cpp. - // This disabling attempt might come from the user-supplied actions, we'll - // route it in order for - // the watchpoint object to intelligently process this action. + // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling + // attempt might come from the user-supplied actions, we'll route it in + // order for the watchpoint object to intelligently process this action. wp->SetEnabled(false, notify); return error; } @@ -3313,8 +3423,8 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver( static FileSpec g_debugserver_file_spec; ProcessLaunchInfo debugserver_launch_info; - // Make debugserver run in its own session so signals generated by - // special terminal key sequences (^C) don't affect debugserver. + // Make debugserver run in its own session so signals generated by special + // terminal key sequences (^C) don't affect debugserver. debugserver_launch_info.SetLaunchInSeparateProcessGroup(true); const std::weak_ptr<ProcessGDBRemote> this_wp = @@ -3325,27 +3435,22 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver( int communication_fd = -1; #ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION - // Auto close the sockets we might open up unless everything goes OK. This - // helps us not leak file descriptors when things go wrong. - lldb_utility::CleanUp<int, int> our_socket(-1, -1, close); - lldb_utility::CleanUp<int, int> gdb_socket(-1, -1, close); - // Use a socketpair on non-Windows systems for security and performance // reasons. - { - int sockets[2]; /* the pair of socket descriptors */ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) { - error.SetErrorToErrno(); - return error; - } - - our_socket.set(sockets[0]); - gdb_socket.set(sockets[1]); + int sockets[2]; /* the pair of socket descriptors */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) { + error.SetErrorToErrno(); + return error; } + int our_socket = sockets[0]; + int gdb_socket = sockets[1]; + CleanUp cleanup_our(close, our_socket); + CleanUp cleanup_gdb(close, gdb_socket); + // Don't let any child processes inherit our communication socket - SetCloexecFlag(our_socket.get()); - communication_fd = gdb_socket.get(); + SetCloexecFlag(our_socket); + communication_fd = gdb_socket; #endif error = m_gdb_comm.StartDebugserverProcess( @@ -3359,10 +3464,10 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver( if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) { #ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION - // Our process spawned correctly, we can now set our connection to use our - // end of the socket pair - m_gdb_comm.SetConnection( - new ConnectionFileDescriptor(our_socket.release(), true)); + // Our process spawned correctly, we can now set our connection to use + // our end of the socket pair + cleanup_our.disable(); + m_gdb_comm.SetConnection(new ConnectionFileDescriptor(our_socket, true)); #endif StartAsyncThread(); } @@ -3377,9 +3482,9 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver( } if (m_gdb_comm.IsConnected()) { - // Finish the connection process by doing the handshake without connecting - // (send NULL URL) - ConnectToDebugserver(""); + // Finish the connection process by doing the handshake without + // connecting (send NULL URL) + error = ConnectToDebugserver(""); } else { error.SetErrorString("connection failed"); } @@ -3393,8 +3498,8 @@ bool ProcessGDBRemote::MonitorDebugserverProcess( 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... + // "debugserver_pid" argument passed in is the process ID for debugserver + // that we are tracking... Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); const bool handled = true; @@ -3410,12 +3515,12 @@ bool ProcessGDBRemote::MonitorDebugserverProcess( if (!process_sp || process_sp->m_debugserver_pid != debugserver_pid) return handled; - // Sleep for a half a second to make sure our inferior process has - // time to set its exit status before we set it incorrectly when - // both the debugserver and the inferior process shut down. + // Sleep for a half a second to make sure our inferior process has time to + // set its exit status before we set it incorrectly when both the debugserver + // and the inferior process shut down. usleep(500000); - // If our process hasn't yet exited, debugserver might have died. - // If the process did exit, then we are reaping it. + // If our process hasn't yet exited, debugserver might have died. If the + // process did exit, then we are reaping it. const StateType state = process_sp->GetState(); if (state != eStateInvalid && state != eStateUnloaded && @@ -3438,8 +3543,8 @@ bool ProcessGDBRemote::MonitorDebugserverProcess( process_sp->SetExitStatus(-1, error_str); } - // Debugserver has exited we need to let our ProcessGDBRemote - // know that it no longer has a debugserver instance + // Debugserver has exited we need to let our ProcessGDBRemote know that it no + // longer has a debugserver instance process_sp->m_debugserver_pid = LLDB_INVALID_PROCESS_ID; return handled; } @@ -3529,10 +3634,9 @@ bool ProcessGDBRemote::HandleNotifyPacket(StringExtractorGDBRemote &packet) { // check for more stop reasons HandleStopReplySequence(); - // if the process is stopped then we need to fake a resume - // so that we can stop properly with the new break. This - // is possible due to SetPrivateState() broadcasting the - // state change as a side effect. + // if the process is stopped then we need to fake a resume so that we can + // stop properly with the new break. This is possible due to + // SetPrivateState() broadcasting the state change as a side effect. if (GetPrivateState() == lldb::StateType::eStateStopped) { SetPrivateState(lldb::StateType::eStateRunning); } @@ -3605,12 +3709,11 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { response); // We need to immediately clear the thread ID list so we are sure - // to get a valid list of threads. - // The thread ID list might be contained within the "response", or - // the stop reply packet that + // to get a valid list of threads. The thread ID list might be + // contained within the "response", or the stop reply packet that // caused the stop. So clear it now before we give the stop reply - // packet to the process - // using the process->SetLastStopPacket()... + // packet to the process using the + // process->SetLastStopPacket()... process->ClearThreadIDList(); switch (stop_state) { @@ -3647,17 +3750,14 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { // Check to see if we were trying to attach and if we got back // the "E87" error code from debugserver -- this indicates that // the process is not debuggable. Return a slightly more - // helpful - // error message about why the attach failed. + // helpful error message about why the attach failed. if (::strstr(continue_cstr, "vAttach") != NULL && response.GetError() == 0x87) { process->SetExitStatus(-1, "cannot attach to process due to " "System Integrity Protection"); - } - // E01 code from vAttach means that the attach failed - if (::strstr(continue_cstr, "vAttach") != NULL && - response.GetError() == 0x1) { - process->SetExitStatus(-1, "unable to attach"); + } else if (::strstr(continue_cstr, "vAttach") != NULL && + response.GetStatus().Fail()) { + process->SetExitStatus(-1, response.GetStatus().AsCString()); } else { process->SetExitStatus(-1, "lost connection"); } @@ -3769,8 +3869,8 @@ Status ProcessGDBRemote::UpdateAutomaticSignalFiltering() { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); LLDB_LOG(log, "Check if need to update ignored signals"); - // QPassSignals package is not supported by the server, - // there is no way we can ignore any signals on server side. + // QPassSignals package is not supported by the server, there is no way we + // can ignore any signals on server side. if (!m_gdb_comm.GetQPassSignalsSupported()) return Status(); @@ -3894,9 +3994,9 @@ ProcessGDBRemote::GetExtendedInfoForThread(lldb::tid_t tid) { // FIXME the final character of a JSON dictionary, '}', is the escape // character in gdb-remote binary mode. lldb currently doesn't escape - // these characters in its packet output -- so we add the quoted version - // of the } character here manually in case we talk to a debugserver which - // un-escapes the characters at packet read time. + // these characters in its packet output -- so we add the quoted version of + // the } character here manually in case we talk to a debugserver which un- + // escapes the characters at packet read time. packet << (char)(0x7d ^ 0x20); StringExtractorGDBRemote response; @@ -3966,9 +4066,9 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender( // FIXME the final character of a JSON dictionary, '}', is the escape // character in gdb-remote binary mode. lldb currently doesn't escape - // these characters in its packet output -- so we add the quoted version - // of the } character here manually in case we talk to a debugserver which - // un-escapes the characters at packet read time. + // these characters in its packet output -- so we add the quoted version of + // the } character here manually in case we talk to a debugserver which un- + // escapes the characters at packet read time. packet << (char)(0x7d ^ 0x20); StringExtractorGDBRemote response; @@ -3999,9 +4099,9 @@ StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() { // FIXME the final character of a JSON dictionary, '}', is the escape // character in gdb-remote binary mode. lldb currently doesn't escape - // these characters in its packet output -- so we add the quoted version - // of the } character here manually in case we talk to a debugserver which - // un-escapes the characters at packet read time. + // these characters in its packet output -- so we add the quoted version of + // the } character here manually in case we talk to a debugserver which un- + // escapes the characters at packet read time. packet << (char)(0x7d ^ 0x20); StringExtractorGDBRemote response; @@ -4026,14 +4126,14 @@ Status ProcessGDBRemote::ConfigureStructuredData( return m_gdb_comm.ConfigureRemoteStructuredData(type_name, config_sp); } -// Establish the largest memory read/write payloads we should use. -// If the remote stub has a max packet size, stay under that size. +// Establish the largest memory read/write payloads we should use. If the +// remote stub has a max packet size, stay under that size. // -// If the remote stub's max packet size is crazy large, use a -// reasonable largeish default. +// If the remote stub's max packet size is crazy large, use a reasonable +// largeish default. // -// If the remote stub doesn't advertise a max packet size, use a -// conservative default. +// If the remote stub doesn't advertise a max packet size, use a conservative +// default. void ProcessGDBRemote::GetMaxMemorySize() { const uint64_t reasonable_largeish_default = 128 * 1024; @@ -4045,15 +4145,15 @@ void ProcessGDBRemote::GetMaxMemorySize() { // Save the stub's claimed maximum packet size m_remote_stub_max_memory_size = stub_max_size; - // Even if the stub says it can support ginormous packets, - // don't exceed our reasonable largeish default packet size. + // Even if the stub says it can support ginormous packets, don't exceed + // our reasonable largeish default packet size. if (stub_max_size > reasonable_largeish_default) { stub_max_size = reasonable_largeish_default; } - // Memory packet have other overheads too like Maddr,size:#NN - // Instead of calculating the bytes taken by size and addr every - // time, we take a maximum guess here. + // Memory packet have other overheads too like Maddr,size:#NN Instead of + // calculating the bytes taken by size and addr every time, we take a + // maximum guess here. if (stub_max_size > 70) stub_max_size -= 32 + 32 + 6; else { @@ -4140,13 +4240,8 @@ void ProcessGDBRemote::PrefetchModuleSpecs( } } -bool ProcessGDBRemote::GetHostOSVersion(uint32_t &major, uint32_t &minor, - uint32_t &update) { - if (m_gdb_comm.GetOSVersion(major, minor, update)) - return true; - // We failed to get the host OS version, defer to the base - // implementation to correctly invalidate the arguments. - return Process::GetHostOSVersion(major, minor, update); +llvm::VersionTuple ProcessGDBRemote::GetHostOSVersion() { + return m_gdb_comm.GetOSVersion(); } namespace { @@ -4237,7 +4332,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, } else if (name == "format") { format_set = true; Format format = eFormatInvalid; - if (Args::StringToFormat(value.data(), format, NULL).Success()) + if (OptionArgParser::ToFormat(value.data(), format, NULL).Success()) reg_info.format = format; else if (value == "vector-sint8") reg_info.format = eFormatVectorOfSInt8; @@ -4311,8 +4406,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, } // Only update the register set name if we didn't get a "reg_set" + // attribute. "set_name" will be empty if we didn't have a "reg_set" // attribute. - // "set_name" will be empty if we didn't have a "reg_set" attribute. if (!set_name && !gdb_group.empty()) set_name.SetCString(gdb_group.c_str()); @@ -4339,8 +4434,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, } // namespace {} -// query the target of gdb-remote for extended target information -// return: 'true' on success +// query the target of gdb-remote for extended target information return: +// 'true' on success // 'false' on failure bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { // Make sure LLDB has an XML parser it can use first @@ -4409,15 +4504,27 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { return true; // Keep iterating through all children of the target_node }); + // If the target.xml includes an architecture entry like + // <architecture>i386:x86-64</architecture> (seen from VMWare ESXi) + // <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") + { + // We don't have any information about vendor or OS. + arch_to_use.SetTriple("x86_64--"); + GetTarget().MergeArchitecture(arch_to_use); + } + } + // Initialize these outside of ParseRegisters, since they should not be // reset inside each include feature uint32_t cur_reg_num = 0; uint32_t reg_offset = 0; - // Don't use Process::GetABI, this code gets called from DidAttach, and in - // that context we haven't - // set the Target's architecture yet, so the ABI is also potentially - // incorrect. + // Don't use Process::GetABI, this code gets called from DidAttach, and + // in that context we haven't set the Target's architecture yet, so the + // ABI is also potentially incorrect. ABISP abi_to_use_sp = ABI::FindPlugin(shared_from_this(), arch_to_use); for (auto &feature_node : feature_nodes) { ParseRegisters(feature_node, target_info, this->m_register_info, @@ -4758,8 +4865,8 @@ void ProcessGDBRemote::ModulesDidLoad(ModuleList &module_list) { // do anything Process::ModulesDidLoad(module_list); - // After loading shared libraries, we can ask our remote GDB server if - // it needs any symbols. + // After loading shared libraries, we can ask our remote GDB server if it + // needs any symbols. m_gdb_comm.ServeSymbolLookups(this); } @@ -4817,8 +4924,8 @@ std::string ProcessGDBRemote::HarmonizeThreadIdsForProfileData( has_used_usec = true; usec_value.getAsInteger(0, curr_used_usec); } else { - // We didn't find what we want, it is probably - // an older version. Bail out. + // We didn't find what we want, it is probably an older version. Bail + // out. profileDataExtractor.SetFilePos(input_file_pos); } } @@ -4840,8 +4947,8 @@ std::string ProcessGDBRemote::HarmonizeThreadIdsForProfileData( ((real_used_usec > 0) || (HasAssignedIndexIDToThread(thread_id))); if (good_first_time || good_subsequent_time) { - // We try to avoid doing too many index id reservation, - // resulting in fast increase of index ids. + // We try to avoid doing too many index id reservation, resulting in + // fast increase of index ids. output_stream << name << ":"; int32_t index_id = AssignIndexIDToThread(thread_id); @@ -4892,7 +4999,7 @@ ParseStructuredDataPacket(llvm::StringRef packet) { if (!packet.consume_front(s_async_json_packet_prefix)) { if (log) { log->Printf( - "GDBRemoteCommmunicationClientBase::%s() received $J packet " + "GDBRemoteCommunicationClientBase::%s() received $J packet " "but was not a StructuredData packet: packet starts with " "%s", __FUNCTION__, @@ -4901,8 +5008,7 @@ ParseStructuredDataPacket(llvm::StringRef packet) { return StructuredData::ObjectSP(); } - // This is an asynchronous JSON packet, destined for a - // StructuredDataPlugin. + // This is an asynchronous JSON packet, destined for a StructuredDataPlugin. StructuredData::ObjectSP json_sp = StructuredData::ParseJSON(packet); if (log) { if (json_sp) { @@ -5137,8 +5243,9 @@ public: ~CommandObjectProcessGDBRemotePacketMonitor() {} - bool DoExecute(const char *command, CommandReturnObject &result) override { - if (command == NULL || command[0] == '\0') { + bool DoExecute(llvm::StringRef command, + CommandReturnObject &result) override { + if (command.empty()) { result.AppendErrorWithFormat("'%s' takes a command string argument", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); @@ -5150,14 +5257,15 @@ public: if (process) { StreamString packet; packet.PutCString("qRcmd,"); - packet.PutBytesAsRawHex8(command, strlen(command)); + packet.PutBytesAsRawHex8(command.data(), command.size()); bool send_async = true; StringExtractorGDBRemote response; - process->GetGDBRemote().SendPacketAndWaitForResponse( - packet.GetString(), response, send_async); - result.SetStatus(eReturnStatusSuccessFinishResult); Stream &output_strm = result.GetOutputStream(); + process->GetGDBRemote().SendPacketAndReceiveResponseWithOutputSupport( + packet.GetString(), response, send_async, + [&output_strm](llvm::StringRef output) { output_strm << output; }); + result.SetStatus(eReturnStatusSuccessFinishResult); output_strm.Printf(" packet: %s\n", packet.GetData()); const std::string &response_str = response.GetStringRef(); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 42d1c4ecd666..45bb2d4c28e7 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -144,6 +144,9 @@ public: size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) override; + Status + WriteObjectFile(std::vector<ObjectFile::LoadableData> entries) override; + size_t DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size, Status &error) override; @@ -214,8 +217,7 @@ public: void PrefetchModuleSpecs(llvm::ArrayRef<FileSpec> module_file_specs, const llvm::Triple &triple) override; - bool GetHostOSVersion(uint32_t &major, uint32_t &minor, - uint32_t &update) override; + llvm::VersionTuple GetHostOSVersion() override; size_t LoadModules(LoadedModuleInfoList &module_list) override; @@ -302,6 +304,11 @@ protected: int64_t m_breakpoint_pc_offset; lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach + bool m_allow_flash_writes; + using FlashRangeVector = lldb_private::RangeVector<lldb::addr_t, size_t>; + using FlashRange = FlashRangeVector::Entry; + FlashRangeVector m_erased_flash_ranges; + //---------------------------------------------------------------------- // Accessors //---------------------------------------------------------------------- @@ -408,6 +415,12 @@ protected: Status UpdateAutomaticSignalFiltering() override; + Status FlashErase(lldb::addr_t addr, size_t size); + + Status FlashDone(); + + bool HasErased(FlashRange range); + private: //------------------------------------------------------------------ // For ProcessGDBRemote only diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 27dd03bfc7bc..a525c16b9f13 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -24,7 +24,7 @@ #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" -#include "Utility/StringExtractorGDBRemote.h" +#include "lldb/Utility/StringExtractorGDBRemote.h" using namespace lldb; using namespace lldb_private; @@ -55,7 +55,7 @@ ThreadGDBRemote::~ThreadGDBRemote() { const char *ThreadGDBRemote::GetName() { if (m_thread_name.empty()) - return NULL; + return nullptr; return m_thread_name.c_str(); } @@ -80,10 +80,9 @@ void ThreadGDBRemote::SetQueueInfo(std::string &&queue_name, const char *ThreadGDBRemote::GetQueueName() { // If our cached queue info is valid, then someone called - // ThreadGDBRemote::SetQueueInfo(...) - // with valid information that was gleaned from the stop reply packet. In this - // case we trust - // that the info is valid in m_dispatch_queue_name without refetching it + // ThreadGDBRemote::SetQueueInfo(...) with valid information that was gleaned + // from the stop reply packet. In this case we trust that the info is valid + // in m_dispatch_queue_name without refetching it if (CachedQueueInfoIsValid()) { if (m_dispatch_queue_name.empty()) return nullptr; @@ -110,15 +109,14 @@ const char *ThreadGDBRemote::GetQueueName() { return m_dispatch_queue_name.c_str(); } } - return NULL; + return nullptr; } QueueKind ThreadGDBRemote::GetQueueKind() { // If our cached queue info is valid, then someone called - // ThreadGDBRemote::SetQueueInfo(...) - // with valid information that was gleaned from the stop reply packet. In this - // case we trust - // that the info is valid in m_dispatch_queue_name without refetching it + // ThreadGDBRemote::SetQueueInfo(...) with valid information that was gleaned + // from the stop reply packet. In this case we trust that the info is valid + // in m_dispatch_queue_name without refetching it if (CachedQueueInfoIsValid()) { return m_queue_kind; } @@ -141,10 +139,9 @@ QueueKind ThreadGDBRemote::GetQueueKind() { queue_id_t ThreadGDBRemote::GetQueueID() { // If our cached queue info is valid, then someone called - // ThreadGDBRemote::SetQueueInfo(...) - // with valid information that was gleaned from the stop reply packet. In this - // case we trust - // that the info is valid in m_dispatch_queue_name without refetching it + // ThreadGDBRemote::SetQueueInfo(...) with valid information that was gleaned + // from the stop reply packet. In this case we trust that the info is valid + // in m_dispatch_queue_name without refetching it if (CachedQueueInfoIsValid()) return m_queue_serial_number; @@ -275,11 +272,11 @@ void ThreadGDBRemote::RefreshStateAfterStop() { // Invalidate all registers in our register context. We don't set "force" to // true because the stop reply packet might have had some register values // that were expedited and these will already be copied into the register - // context by the time this function gets called. The GDBRemoteRegisterContext - // class has been made smart enough to detect when it needs to invalidate - // which registers are valid by putting hooks in the register read and - // register supply functions where they check the process stop ID and do - // the right thing. + // context by the time this function gets called. The + // GDBRemoteRegisterContext class has been made smart enough to detect when + // it needs to invalidate which registers are valid by putting hooks in the + // register read and register supply functions where they check the process + // stop ID and do the right thing. const bool force = false; GetRegisterContext()->InvalidateIfNeeded(force); } @@ -292,8 +289,8 @@ void ThreadGDBRemote::Dump(Log *log, uint32_t index) {} bool ThreadGDBRemote::ShouldStop(bool &step_more) { return true; } lldb::RegisterContextSP ThreadGDBRemote::GetRegisterContext() { - if (m_reg_context_sp.get() == NULL) - m_reg_context_sp = CreateRegisterContextForFrame(NULL); + if (!m_reg_context_sp) + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); return m_reg_context_sp; } @@ -310,7 +307,8 @@ ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) { if (process_sp) { ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); - // read_all_registers_at_once will be true if 'p' packet is not supported. + // read_all_registers_at_once will be true if 'p' packet is not + // supported. bool read_all_registers_at_once = !gdb_process->GetGDBRemote().GetpPacketSupported(GetID()); reg_ctx_sp.reset(new GDBRemoteRegisterContext( @@ -319,7 +317,7 @@ ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) { } } else { Unwind *unwinder = GetUnwinder(); - if (unwinder) + if (unwinder != nullptr) reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); } return reg_ctx_sp; diff --git a/source/Plugins/Process/mach-core/CMakeLists.txt b/source/Plugins/Process/mach-core/CMakeLists.txt index 18f6ff581ea3..e79cd82c92a6 100644 --- a/source/Plugins/Process/mach-core/CMakeLists.txt +++ b/source/Plugins/Process/mach-core/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(../Utility) - add_lldb_library(lldbPluginProcessMachCore PLUGIN ProcessMachCore.cpp ThreadMachCore.cpp diff --git a/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/source/Plugins/Process/mach-core/ProcessMachCore.cpp index d21651b77ee0..bfa35ed506a9 100644 --- a/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ b/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -35,7 +35,7 @@ // Project includes #include "ProcessMachCore.h" -#include "StopInfoMachException.h" +#include "Plugins/Process/Utility/StopInfoMachException.h" #include "ThreadMachCore.h" // Needed for the plug-in names for the dynamic loaders. @@ -91,11 +91,10 @@ bool ProcessMachCore::CanDebug(lldb::TargetSP target_sp, // For now we are just making sure the file exists for a given module if (!m_core_module_sp && m_core_file.Exists()) { - // 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 - - // ModuleSpecList::FindMatchingModuleSpec - // enforces a strict arch mach. + // 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 - + // ModuleSpecList::FindMatchingModuleSpec enforces a strict arch mach. ModuleSpec core_module_spec(m_core_file); Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp, NULL, NULL, NULL)); @@ -125,10 +124,10 @@ ProcessMachCore::ProcessMachCore(lldb::TargetSP target_sp, //---------------------------------------------------------------------- ProcessMachCore::~ProcessMachCore() { Clear(); - // We need to call finalize on the process before destroying ourselves - // to make sure all of the broadcaster cleanup goes as planned. If we - // destruct this class, then Process::~Process() might have problems - // trying to fully destroy the broadcaster. + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. Finalize(); } @@ -162,11 +161,10 @@ bool ProcessMachCore::GetDynamicLoaderAddress(lldb::addr_t addr) { // header.magic, header.filetype); if (header.magic == llvm::MachO::MH_MAGIC || header.magic == llvm::MachO::MH_MAGIC_64) { - // Check MH_EXECUTABLE to see if we can find the mach image - // that contains the shared library list. The dynamic loader - // (dyld) is what contains the list for user applications, - // and the mach kernel contains a global that has the list - // of kexts to load + // Check MH_EXECUTABLE to see if we can find the mach image that contains + // the shared library list. The dynamic loader (dyld) is what contains the + // list for user applications, and the mach kernel contains a global that + // has the list of kexts to load switch (header.filetype) { case llvm::MachO::MH_DYLINKER: // printf("0x%16.16" PRIx64 ": file_type = MH_DYLINKER\n", vaddr); @@ -272,13 +270,10 @@ Status ProcessMachCore::DoLoadCore() { } else { m_core_aranges.Append(range_entry); } - // Some core files don't fill in the permissions correctly. If that is the - // case - // assume read + execute so clients don't think the memory is not - // readable, - // or executable. The memory isn't writable since this plug-in doesn't - // implement - // DoWriteMemory. + // Some core files don't fill in the permissions correctly. If that is + // the case assume read + execute so clients don't think the memory is + // not readable, or executable. The memory isn't writable since this + // plug-in doesn't implement DoWriteMemory. uint32_t permissions = section->GetPermissions(); if (permissions == 0) permissions = lldb::ePermissionsReadable | lldb::ePermissionsExecutable; @@ -309,8 +304,8 @@ Status ProcessMachCore::DoLoadCore() { } // This checks for the presence of an LC_IDENT string in a core file; - // 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. + // 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) { @@ -319,7 +314,7 @@ Status ProcessMachCore::DoLoadCore() { 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.SetFromCString(uuid_str.c_str()); + uuid.SetFromStringRef(uuid_str); } if (corefile_identifier.find("stext=") != std::string::npos) { size_t p = corefile_identifier.find("stext=") + strlen("stext="); @@ -342,16 +337,12 @@ Status ProcessMachCore::DoLoadCore() { if (found_main_binary_definitively == false && (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 + // 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 - // binary so - // we don't miss one or the other. Step through all memory segments - // searching for - // a kernel binary and for a user process dyld -- we'll decide which to - // prefer - // later if both are present. + // binary so we don't miss one or the other. Step through all memory + // segments searching for a kernel binary and for a user process dyld -- + // we'll decide which to prefer later if both are present. const size_t num_core_aranges = m_core_aranges.GetSize(); for (size_t i = 0; i < num_core_aranges; ++i) { @@ -369,13 +360,10 @@ Status ProcessMachCore::DoLoadCore() { if (found_main_binary_definitively == false && 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. + // 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()) { @@ -383,13 +371,11 @@ Status ProcessMachCore::DoLoadCore() { } // SearchForDarwinKernel will end up calling back into this this class in - // the GetImageInfoAddress - // method which will give it the m_mach_kernel_addr/m_dyld_addr it already - // has. Save that aside - // and set m_mach_kernel_addr/m_dyld_addr to an invalid address temporarily - // so - // DynamicLoaderDarwinKernel does a real search for the kernel using its own - // heuristics. + // the GetImageInfoAddress method which will give it the + // m_mach_kernel_addr/m_dyld_addr it already has. Save that aside and set + // m_mach_kernel_addr/m_dyld_addr to an invalid address temporarily so + // DynamicLoaderDarwinKernel does a real search for the kernel using its + // own heuristics. addr_t saved_mach_kernel_addr = m_mach_kernel_addr; addr_t saved_user_dyld_addr = m_dyld_addr; @@ -410,8 +396,8 @@ Status ProcessMachCore::DoLoadCore() { } } - // If we found both a user-process dyld and a kernel binary, we need to decide - // which to prefer. + // If we found both a user-process dyld and a kernel binary, we need to + // decide which to prefer. if (GetCorefilePreference() == eKernelCorefile) { if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { if (log) @@ -444,18 +430,13 @@ Status ProcessMachCore::DoLoadCore() { if (m_dyld_plugin_name != DynamicLoaderMacOSXDYLD::GetPluginNameStatic()) { // For non-user process core files, the permissions on the core file - // segments are usually - // meaningless, they may be just "read", because we're dealing with kernel - // coredumps or - // early startup coredumps and the dumper is grabbing pages of memory - // without knowing - // what they are. If they aren't marked as "exeuctable", that can break the - // unwinder - // which will check a pc value to see if it is in an executable segment and - // stop the + // segments are usually meaningless, they may be just "read", because we're + // dealing with kernel coredumps or early startup coredumps and the dumper + // is grabbing pages of memory without knowing what they are. If they + // aren't marked as "exeuctable", that can break the unwinder which will + // check a pc value to see if it is in an executable segment and stop the // backtrace early if it is not ("executable" and "unknown" would both be - // fine, but - // "not executable" will break the unwinder). + // fine, but "not executable" will break the unwinder). size_t core_range_infos_size = m_core_range_infos.GetSize(); for (size_t i = 0; i < core_range_infos_size; i++) { VMRangeToPermissions::Entry *ent = @@ -464,8 +445,8 @@ Status ProcessMachCore::DoLoadCore() { } } - // Even if the architecture is set in the target, we need to override - // it to match the core file which is always single arch. + // Even if the architecture is set in the target, we need to override it to + // match the core file which is always single arch. ArchSpec arch(m_core_module_sp->GetArchitecture()); if (arch.GetCore() == ArchSpec::eCore_x86_32_i486) { arch = Platform::GetAugmentedArchSpec(GetTarget().GetPlatform().get(), "i386"); @@ -488,8 +469,7 @@ bool ProcessMachCore::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) { if (old_thread_list.GetSize(false) == 0) { // Make up the thread the first time this is called so we can setup our one - // and only - // core thread state. + // and only core thread state. ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile) { @@ -508,8 +488,8 @@ bool ProcessMachCore::UpdateThreadList(ThreadList &old_thread_list, } void ProcessMachCore::RefreshStateAfterStop() { - // Let all threads recover from stopping and do any clean up based - // on the previous thread state (if any). + // Let all threads recover from stopping and do any clean up based on the + // previous thread state (if any). m_thread_list.RefreshStateAfterStop(); // SetThreadStopInfo (m_last_stop_packet); } @@ -529,8 +509,8 @@ bool ProcessMachCore::WarnBeforeDetach() const { return false; } //------------------------------------------------------------------ size_t ProcessMachCore::ReadMemory(addr_t addr, void *buf, size_t size, Status &error) { - // Don't allow the caching that lldb_private::Process::ReadMemory does - // since in core files we have it all cached our our core file anyway. + // Don't allow the caching that lldb_private::Process::ReadMemory does since + // in core files we have it all cached our our core file anyway. return DoReadMemory(addr, buf, size, error); } @@ -546,19 +526,17 @@ size_t ProcessMachCore::DoReadMemory(addr_t addr, void *buf, size_t size, // Address Size File off File size // ---------- ---------- ---------- ---------- // LC_SEGMENT 0x000f6000 0x00001000 0x1d509ee8 0x00001000 --- --- 0 - // 0x00000000 __TEXT - // LC_SEGMENT 0x0f600000 0x00100000 0x1d50aee8 0x00100000 --- --- 0 - // 0x00000000 __TEXT - // LC_SEGMENT 0x000f7000 0x00001000 0x1d60aee8 0x00001000 --- --- 0 - // 0x00000000 __TEXT + // 0x00000000 __TEXT LC_SEGMENT 0x0f600000 0x00100000 0x1d50aee8 0x00100000 + // --- --- 0 0x00000000 __TEXT LC_SEGMENT 0x000f7000 0x00001000 + // 0x1d60aee8 0x00001000 --- --- 0 0x00000000 __TEXT // // Any if the user executes the following command: // // (lldb) mem read 0xf6ff0 // - // We would attempt to read 32 bytes from 0xf6ff0 but would only - // get 16 unless we loop through consecutive memory ranges that are - // contiguous in the address space, but not in the file data. + // We would attempt to read 32 bytes from 0xf6ff0 but would only get 16 + // unless we loop through consecutive memory ranges that are contiguous in + // the address space, but not in the file data. //---------------------------------------------------------------------- while (bytes_read < size) { const addr_t curr_addr = addr + bytes_read; @@ -641,8 +619,8 @@ void ProcessMachCore::Initialize() { } addr_t ProcessMachCore::GetImageInfoAddress() { - // If we found both a user-process dyld and a kernel binary, we need to decide - // which to prefer. + // If we found both a user-process dyld and a kernel binary, we need to + // decide which to prefer. if (GetCorefilePreference() == eKernelCorefile) { if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { return m_mach_kernel_addr; diff --git a/source/Plugins/Process/mach-core/ThreadMachCore.cpp b/source/Plugins/Process/mach-core/ThreadMachCore.cpp index 2b44105c13b1..c262dd47f978 100644 --- a/source/Plugins/Process/mach-core/ThreadMachCore.cpp +++ b/source/Plugins/Process/mach-core/ThreadMachCore.cpp @@ -43,7 +43,7 @@ ThreadMachCore::~ThreadMachCore() { DestroyThread(); } const char *ThreadMachCore::GetName() { if (m_thread_name.empty()) - return NULL; + return nullptr; return m_thread_name.c_str(); } @@ -54,8 +54,8 @@ void ThreadMachCore::RefreshStateAfterStop() { // context by the time this function gets called. The KDPRegisterContext // class has been made smart enough to detect when it needs to invalidate // which registers are valid by putting hooks in the register read and - // register supply functions where they check the process stop ID and do - // the right thing. + // register supply functions where they check the process stop ID and do the + // right thing. const bool force = false; GetRegisterContext()->InvalidateIfNeeded(force); } @@ -63,8 +63,8 @@ void ThreadMachCore::RefreshStateAfterStop() { bool ThreadMachCore::ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; } lldb::RegisterContextSP ThreadMachCore::GetRegisterContext() { - if (m_reg_context_sp.get() == NULL) - m_reg_context_sp = CreateRegisterContextForFrame(NULL); + if (!m_reg_context_sp) + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); return m_reg_context_sp; } @@ -89,7 +89,7 @@ ThreadMachCore::CreateRegisterContextForFrame(StackFrame *frame) { reg_ctx_sp = m_thread_reg_ctx_sp; } else { Unwind *unwinder = GetUnwinder(); - if (unwinder) + if (unwinder != nullptr) reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); } return reg_ctx_sp; diff --git a/source/Plugins/Process/minidump/CMakeLists.txt b/source/Plugins/Process/minidump/CMakeLists.txt index 61ce16830c9b..b898ee1aa144 100644 --- a/source/Plugins/Process/minidump/CMakeLists.txt +++ b/source/Plugins/Process/minidump/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(../Utility) - add_lldb_library(lldbPluginProcessMinidump PLUGIN MinidumpTypes.cpp MinidumpParser.cpp diff --git a/source/Plugins/Process/minidump/MinidumpParser.cpp b/source/Plugins/Process/minidump/MinidumpParser.cpp index 36350fdb6398..9a979335e99e 100644 --- a/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -14,10 +14,13 @@ // Other libraries and framework includes #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/LLDBAssert.h" // C includes // C++ includes +#include <algorithm> #include <map> +#include <vector> using namespace lldb_private; using namespace minidump; @@ -27,47 +30,11 @@ MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) { if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) { return llvm::None; } - - llvm::ArrayRef<uint8_t> header_data(data_buf_sp->GetBytes(), - sizeof(MinidumpHeader)); - const MinidumpHeader *header = MinidumpHeader::Parse(header_data); - - if (header == nullptr) { - return llvm::None; - } - - lldb::offset_t directory_list_offset = header->stream_directory_rva; - // check if there is enough data for the parsing of the directory list - if ((directory_list_offset + - sizeof(MinidumpDirectory) * header->streams_count) > - data_buf_sp->GetByteSize()) { - return llvm::None; - } - - const MinidumpDirectory *directory = nullptr; - Status error; - llvm::ArrayRef<uint8_t> directory_data( - data_buf_sp->GetBytes() + directory_list_offset, - sizeof(MinidumpDirectory) * header->streams_count); - llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map; - - for (uint32_t i = 0; i < header->streams_count; ++i) { - error = consumeObject(directory_data, directory); - if (error.Fail()) { - return llvm::None; - } - directory_map[static_cast<const uint32_t>(directory->stream_type)] = - directory->location; - } - - return MinidumpParser(data_buf_sp, header, std::move(directory_map)); + return MinidumpParser(data_buf_sp); } -MinidumpParser::MinidumpParser( - const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, - llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map) - : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) { -} +MinidumpParser::MinidumpParser(const lldb::DataBufferSP &data_buf_sp) + : m_data_sp(data_buf_sp) {} llvm::ArrayRef<uint8_t> MinidumpParser::GetData() { return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(), @@ -96,6 +63,31 @@ llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) { return parseMinidumpString(arr_ref); } +UUID MinidumpParser::GetModuleUUID(const MinidumpModule *module) { + auto cv_record = + GetData().slice(module->CV_record.rva, module->CV_record.data_size); + + // Read the CV record signature + const llvm::support::ulittle32_t *signature = nullptr; + Status error = consumeObject(cv_record, signature); + if (error.Fail()) + return UUID(); + + const CvSignature cv_signature = + static_cast<CvSignature>(static_cast<const uint32_t>(*signature)); + + if (cv_signature == CvSignature::Pdb70) { + // 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)); + } else if (cv_signature == CvSignature::ElfBuildId) + return UUID::fromData(cv_record); + + return UUID(); +} + llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() { llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList); @@ -115,12 +107,12 @@ MinidumpParser::GetThreadContext(const MinidumpThread &td) { llvm::ArrayRef<uint8_t> MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) { - // On Windows, a 32-bit process can run on a 64-bit machine under - // WOW64. If the minidump was captured with a 64-bit debugger, then - // the CONTEXT we just grabbed from the mini_dump_thread is the one - // for the 64-bit "native" process rather than the 32-bit "guest" - // process we care about. In this case, we can get the 32-bit CONTEXT - // from the TEB (Thread Environment Block) of the 64-bit process. + // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If + // the minidump was captured with a 64-bit debugger, then the CONTEXT we just + // grabbed from the mini_dump_thread is the one for the 64-bit "native" + // process rather than the 32-bit "guest" process we care about. In this + // case, we can get the 32-bit CONTEXT from the TEB (Thread Environment + // Block) of the 64-bit process. auto teb_mem = GetMemory(td.teb, sizeof(TEB64)); if (teb_mem.empty()) return {}; @@ -130,9 +122,9 @@ MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) { if (error.Fail()) return {}; - // Slot 1 of the thread-local storage in the 64-bit TEB points to a - // structure that includes the 32-bit CONTEXT (after a ULONG). - // See: https://msdn.microsoft.com/en-us/library/ms681670.aspx + // Slot 1 of the thread-local storage in the 64-bit TEB points to a structure + // that includes the 32-bit CONTEXT (after a ULONG). See: + // https://msdn.microsoft.com/en-us/library/ms681670.aspx auto context = GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32)); if (context.size() < sizeof(MinidumpContext_x86_32)) @@ -334,10 +326,10 @@ MinidumpParser::FindMemoryRange(lldb::addr_t addr) { } } - // Some Minidumps have a Memory64ListStream that captures all the heap - // memory (full-memory Minidumps). We can't exactly use the same loop as - // above, because the Minidump uses slightly different data structures to - // describe those + // Some Minidumps have a Memory64ListStream that captures all the heap memory + // (full-memory Minidumps). We can't exactly use the same loop as above, + // because the Minidump uses slightly different data structures to describe + // those if (!data64.empty()) { llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list; @@ -377,8 +369,8 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr, return {}; // There's at least some overlap between the beginning of the desired range - // (addr) and the current range. Figure out where the overlap begins and - // how much overlap there is. + // (addr) and the current range. Figure out where the overlap begins and how + // much overlap there is. const size_t offset = addr - range->start; @@ -456,3 +448,109 @@ MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) { // appear truncated. return info; } + +Status MinidumpParser::Initialize() { + Status error; + + lldbassert(m_directory_map.empty()); + + llvm::ArrayRef<uint8_t> header_data(m_data_sp->GetBytes(), + sizeof(MinidumpHeader)); + const MinidumpHeader *header = MinidumpHeader::Parse(header_data); + if (header == nullptr) { + error.SetErrorString("invalid minidump: can't parse the header"); + return error; + } + + // A minidump without at least one stream is clearly ill-formed + if (header->streams_count == 0) { + error.SetErrorString("invalid minidump: no streams present"); + return error; + } + + struct FileRange { + uint32_t offset = 0; + uint32_t size = 0; + + FileRange(uint32_t offset, uint32_t size) : offset(offset), size(size) {} + uint32_t end() const { return offset + size; } + }; + + const uint32_t file_size = m_data_sp->GetByteSize(); + + // Build a global minidump file map, checking for: + // - overlapping streams/data structures + // - truncation (streams pointing past the end of file) + std::vector<FileRange> minidump_map; + + // Add the minidump header to the file map + if (sizeof(MinidumpHeader) > file_size) { + error.SetErrorString("invalid minidump: truncated header"); + return error; + } + minidump_map.emplace_back( 0, sizeof(MinidumpHeader) ); + + // Add the directory entries to the file map + FileRange directory_range(header->stream_directory_rva, + header->streams_count * + sizeof(MinidumpDirectory)); + if (directory_range.end() > file_size) { + error.SetErrorString("invalid minidump: truncated streams directory"); + return error; + } + minidump_map.push_back(directory_range); + + // Parse stream directory entries + llvm::ArrayRef<uint8_t> directory_data( + m_data_sp->GetBytes() + directory_range.offset, directory_range.size); + for (uint32_t i = 0; i < header->streams_count; ++i) { + const MinidumpDirectory *directory_entry = nullptr; + error = consumeObject(directory_data, directory_entry); + if (error.Fail()) + return error; + if (directory_entry->stream_type == 0) { + // Ignore dummy streams (technically ill-formed, but a number of + // existing minidumps seem to contain such streams) + if (directory_entry->location.data_size == 0) + continue; + error.SetErrorString("invalid minidump: bad stream type"); + return error; + } + // Update the streams map, checking for duplicate stream types + if (!m_directory_map + .insert({directory_entry->stream_type, directory_entry->location}) + .second) { + error.SetErrorString("invalid minidump: duplicate stream type"); + return error; + } + // Ignore the zero-length streams for layout checks + if (directory_entry->location.data_size != 0) { + minidump_map.emplace_back(directory_entry->location.rva, + directory_entry->location.data_size); + } + } + + // 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; + }); + + // Check for overlapping streams/data structures + for (size_t i = 1; i < minidump_map.size(); ++i) { + const auto &prev_range = minidump_map[i - 1]; + if (prev_range.end() > minidump_map[i].offset) { + error.SetErrorString("invalid minidump: overlapping streams"); + return error; + } + } + + // Check for streams past the end of file + const auto &last_range = minidump_map.back(); + if (last_range.end() > file_size) { + error.SetErrorString("invalid minidump: truncated stream"); + return error; + } + + return error; +} diff --git a/source/Plugins/Process/minidump/MinidumpParser.h b/source/Plugins/Process/minidump/MinidumpParser.h index b7329ffc0028..49b1eef14de5 100644 --- a/source/Plugins/Process/minidump/MinidumpParser.h +++ b/source/Plugins/Process/minidump/MinidumpParser.h @@ -17,6 +17,7 @@ #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/Status.h" +#include "lldb/Utility/UUID.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -54,6 +55,8 @@ public: llvm::Optional<std::string> GetMinidumpString(uint32_t rva); + UUID GetModuleUUID(const MinidumpModule* module); + llvm::ArrayRef<MinidumpThread> GetThreads(); llvm::ArrayRef<uint8_t> GetThreadContext(const MinidumpThread &td); @@ -86,14 +89,15 @@ public: llvm::Optional<MemoryRegionInfo> GetMemoryRegionInfo(lldb::addr_t); + // Perform consistency checks and initialize internal data structures + Status Initialize(); + +private: + MinidumpParser(const lldb::DataBufferSP &data_buf_sp); + private: lldb::DataBufferSP m_data_sp; - const MinidumpHeader *m_header; llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> m_directory_map; - - MinidumpParser( - const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, - llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map); }; } // end namespace minidump diff --git a/source/Plugins/Process/minidump/MinidumpTypes.cpp b/source/Plugins/Process/minidump/MinidumpTypes.cpp index 24ce3f94c094..049704ba80ca 100644 --- a/source/Plugins/Process/minidump/MinidumpTypes.cpp +++ b/source/Plugins/Process/minidump/MinidumpTypes.cpp @@ -33,9 +33,6 @@ const MinidumpHeader *MinidumpHeader::Parse(llvm::ArrayRef<uint8_t> &data) { version != MinidumpHeaderConstants::Version) return nullptr; - // TODO check for max number of streams ? - // TODO more sanity checks ? - return header; } @@ -44,19 +41,23 @@ llvm::Optional<std::string> lldb_private::minidump::parseMinidumpString(llvm::ArrayRef<uint8_t> &data) { std::string result; - const uint32_t *source_length; - Status error = consumeObject(data, source_length); - if (error.Fail() || *source_length > data.size() || *source_length % 2 != 0) + const uint32_t *source_length_ptr; + Status error = consumeObject(data, source_length_ptr); + + // Copy non-aligned source_length data into aligned memory. + uint32_t source_length; + std::memcpy(&source_length, source_length_ptr, sizeof(source_length)); + + if (error.Fail() || source_length > data.size() || source_length % 2 != 0) return llvm::None; auto source_start = reinterpret_cast<const llvm::UTF16 *>(data.data()); - // source_length is the length of the string in bytes - // we need the length of the string in UTF-16 characters/code points (16 bits - // per char) - // that's why it's divided by 2 - const auto source_end = source_start + (*source_length) / 2; + // source_length is the length of the string in bytes we need the length of + // the string in UTF-16 characters/code points (16 bits per char) that's why + // it's divided by 2 + const auto source_end = source_start + source_length / 2; // resize to worst case length - result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * (*source_length) / 2); + result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * source_length / 2); auto result_start = reinterpret_cast<llvm::UTF8 *>(&result[0]); const auto result_end = result_start + result.size(); llvm::ConvertUTF16toUTF8(&source_start, source_end, &result_start, result_end, @@ -80,11 +81,17 @@ const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef<uint8_t> &data) { llvm::ArrayRef<MinidumpThread> MinidumpThread::ParseThreadList(llvm::ArrayRef<uint8_t> &data) { + const auto orig_size = data.size(); const llvm::support::ulittle32_t *thread_count; Status error = consumeObject(data, thread_count); if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size()) return {}; + // Compilers might end up padding an extra 4 bytes depending on how the + // structure is padded by the compiler and the #pragma pack settings. + if (4 + *thread_count * sizeof(MinidumpThread) < orig_size) + data = data.drop_front(4); + return llvm::ArrayRef<MinidumpThread>( reinterpret_cast<const MinidumpThread *>(data.data()), *thread_count); } @@ -156,12 +163,17 @@ const MinidumpModule *MinidumpModule::Parse(llvm::ArrayRef<uint8_t> &data) { llvm::ArrayRef<MinidumpModule> MinidumpModule::ParseModuleList(llvm::ArrayRef<uint8_t> &data) { - + const auto orig_size = data.size(); const llvm::support::ulittle32_t *modules_count; Status error = consumeObject(data, modules_count); if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size()) return {}; - + + // Compilers might end up padding an extra 4 bytes depending on how the + // structure is padded by the compiler and the #pragma pack settings. + if (4 + *modules_count * sizeof(MinidumpModule) < orig_size) + data = data.drop_front(4); + return llvm::ArrayRef<MinidumpModule>( reinterpret_cast<const MinidumpModule *>(data.data()), *modules_count); } @@ -179,11 +191,17 @@ MinidumpExceptionStream::Parse(llvm::ArrayRef<uint8_t> &data) { llvm::ArrayRef<MinidumpMemoryDescriptor> MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) { + const auto orig_size = data.size(); const llvm::support::ulittle32_t *mem_ranges_count; Status error = consumeObject(data, mem_ranges_count); if (error.Fail() || *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size()) return {}; + + // Compilers might end up padding an extra 4 bytes depending on how the + // structure is padded by the compiler and the #pragma pack settings. + if (4 + *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) < orig_size) + data = data.drop_front(4); return llvm::makeArrayRef( reinterpret_cast<const MinidumpMemoryDescriptor *>(data.data()), diff --git a/source/Plugins/Process/minidump/MinidumpTypes.h b/source/Plugins/Process/minidump/MinidumpTypes.h index 6de4f55a769d..e83089865b9e 100644 --- a/source/Plugins/Process/minidump/MinidumpTypes.h +++ b/source/Plugins/Process/minidump/MinidumpTypes.h @@ -43,6 +43,21 @@ enum class MinidumpHeaderConstants : uint32_t { }; +enum class CvSignature : uint32_t { + Pdb70 = 0x53445352, // RSDS + ElfBuildId = 0x4270454c, // BpEL (Breakpad/Crashpad minidumps) +}; + +// Reference: +// https://crashpad.chromium.org/doxygen/structcrashpad_1_1CodeViewRecordPDB70.html +struct CvRecordPdb70 { + uint8_t Uuid[16]; + llvm::support::ulittle32_t Age; + // char PDBFileName[]; +}; +static_assert(sizeof(CvRecordPdb70) == 20, + "sizeof CvRecordPdb70 is not correct!"); + // Reference: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680394.aspx enum class MinidumpStreamType : uint32_t { diff --git a/source/Plugins/Process/minidump/ProcessMinidump.cpp b/source/Plugins/Process/minidump/ProcessMinidump.cpp index d4d65c044eab..b43f22382eac 100644 --- a/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/State.h" #include "lldb/Target/DynamicLoader.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" @@ -31,9 +32,56 @@ // C includes // C++ includes +using namespace lldb; using namespace lldb_private; using namespace minidump; +//------------------------------------------------------------------ +/// A placeholder module used for minidumps, where the original +/// object files may not be available (so we can't parse the object +/// files to extract the set of sections/segments) +/// +/// This placeholder module has a single synthetic section (.module_image) +/// which represents the module memory range covering the whole module. +//------------------------------------------------------------------ +class PlaceholderModule : public Module { +public: + PlaceholderModule(const ModuleSpec &module_spec) : + Module(module_spec.GetFileSpec(), module_spec.GetArchitecture()) { + if (module_spec.GetUUID().IsValid()) + SetUUID(module_spec.GetUUID()); + } + + // Creates a synthetic module section covering the whole module image (and + // sets the section load address as well) + void CreateImageSection(const MinidumpModule *module, Target& target) { + const ConstString section_name(".module_image"); + lldb::SectionSP section_sp(new Section( + shared_from_this(), // Module to which this section belongs. + nullptr, // ObjectFile + 0, // Section ID. + section_name, // Section name. + eSectionTypeContainer, // Section type. + module->base_of_image, // VM address. + module->size_of_image, // VM size in bytes of this section. + 0, // Offset of this section in the file. + module->size_of_image, // Size of the section as found in the file. + 12, // Alignment of the section (log2) + 0, // Flags for this section. + 1)); // Number of host bytes per target byte + section_sp->SetPermissions(ePermissionsExecutable | ePermissionsReadable); + GetSectionList()->AddSection(section_sp); + target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, module->base_of_image); + } + + ObjectFile *GetObjectFile() override { return nullptr; } + + SectionList *GetSectionList() override { + return Module::GetUnifiedSectionList(); + } +}; + ConstString ProcessMinidump::GetPluginNameStatic() { static ConstString g_name("minidump"); return g_name; @@ -57,7 +105,7 @@ lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, if (!DataPtr) return nullptr; - assert(DataPtr->GetByteSize() == header_size); + lldbassert(DataPtr->GetByteSize() == header_size); // first, only try to parse the header, beacuse we need to be fast llvm::ArrayRef<uint8_t> HeaderBytes = DataPtr->GetData(); @@ -92,10 +140,10 @@ ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp, ProcessMinidump::~ProcessMinidump() { Clear(); - // We need to call finalize on the process before destroying ourselves - // to make sure all of the broadcaster cleanup goes as planned. If we - // destruct this class, then Process::~Process() might have problems - // trying to fully destroy the broadcaster. + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. Finalize(); } @@ -116,10 +164,29 @@ void ProcessMinidump::Terminate() { Status ProcessMinidump::DoLoadCore() { Status error; + // Minidump parser initialization & consistency checks + error = m_minidump_parser.Initialize(); + if (error.Fail()) + return error; + + // Do we support the minidump's architecture? + ArchSpec arch = GetArchitecture(); + switch (arch.GetMachine()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + // supported + break; + + default: + error.SetErrorStringWithFormat("unsupported minidump architecture: %s", + arch.GetArchitectureName()); + return error; + } + m_thread_list = m_minidump_parser.GetThreads(); m_active_exception = m_minidump_parser.GetExceptionStream(); ReadModuleList(); - GetTarget().SetArchitecture(GetArchitecture()); + GetTarget().SetArchitecture(arch); llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid(); if (!pid) { @@ -185,8 +252,8 @@ bool ProcessMinidump::WarnBeforeDetach() const { return false; } size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { - // Don't allow the caching that lldb_private::Process::ReadMemory does - // since we have it all cached in our dump file anyway. + // Don't allow the caching that lldb_private::Process::ReadMemory does since + // we have it all cached in our dump file anyway. return DoReadMemory(addr, buf, size, error); } @@ -276,12 +343,25 @@ void ProcessMinidump::ReadModuleList() { m_is_wow64 = true; } - const auto file_spec = FileSpec(name.getValue(), true); - ModuleSpec module_spec = file_spec; + const auto uuid = m_minidump_parser.GetModuleUUID(module); + const auto file_spec = + FileSpec(name.getValue(), true, GetArchitecture().GetTriple()); + ModuleSpec module_spec(file_spec, uuid); Status error; lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error); if (!module_sp || error.Fail()) { - continue; + // We failed to locate a matching local object file. Fortunately, the + // minidump format encodes enough information about each module's memory + // range to allow us to create placeholder modules. + // + // 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, ...) + auto placeholder_module = + std::make_shared<PlaceholderModule>(module_spec); + placeholder_module->CreateImageSection(module, GetTarget()); + module_sp = placeholder_module; + GetTarget().GetImages().Append(module_sp); } if (log) { diff --git a/source/Plugins/Process/minidump/ProcessMinidump.h b/source/Plugins/Process/minidump/ProcessMinidump.h index 4b91d1ba396a..d65ada9009a7 100644 --- a/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/source/Plugins/Process/minidump/ProcessMinidump.h @@ -61,6 +61,8 @@ public: uint32_t GetPluginVersion() override; + SystemRuntime *GetSystemRuntime() override { return nullptr; } + Status DoDestroy() override; void RefreshStateAfterStop() override; diff --git a/source/Plugins/ScriptInterpreter/CMakeLists.txt b/source/Plugins/ScriptInterpreter/CMakeLists.txt index dc2a27d95a31..5d8642eb07e6 100644 --- a/source/Plugins/ScriptInterpreter/CMakeLists.txt +++ b/source/Plugins/ScriptInterpreter/CMakeLists.txt @@ -1,2 +1,4 @@ add_subdirectory(None) -add_subdirectory(Python) +if (NOT LLDB_DISABLE_PYTHON) + add_subdirectory(Python) +endif() diff --git a/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp b/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp index 9ec9f4344613..4bd4c6a029a0 100644 --- a/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp +++ b/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp @@ -27,7 +27,7 @@ ScriptInterpreterNone::ScriptInterpreterNone(CommandInterpreter &interpreter) ScriptInterpreterNone::~ScriptInterpreterNone() {} -bool ScriptInterpreterNone::ExecuteOneLine(const char *command, +bool ScriptInterpreterNone::ExecuteOneLine(llvm::StringRef command, CommandReturnObject *, const ExecuteScriptOptions &) { m_interpreter.GetDebugger().GetErrorFile()->PutCString( diff --git a/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h b/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h index d66b2f07310c..824579472b5e 100644 --- a/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h +++ b/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h @@ -25,7 +25,7 @@ public: ~ScriptInterpreterNone() override; bool ExecuteOneLine( - const char *command, CommandReturnObject *result, + llvm::StringRef command, CommandReturnObject *result, const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; void ExecuteInterpreterLoop() override; diff --git a/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index c337fc7b5874..56eacc941d64 100644 --- a/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -1,3 +1,16 @@ +if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows") + # Call a python script to gather the arch-specific libdir for + # modules like the lldb module. + execute_process( + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../../../../scripts/get_relative_lib_dir.py + RESULT_VARIABLE get_libdir_status + OUTPUT_VARIABLE relative_libdir + ) + if (get_libdir_status EQUAL 0) + add_definitions(-DLLDB_PYTHON_RELATIVE_LIBDIR="${relative_libdir}") + endif() +endif() + add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN PythonDataObjects.cpp PythonExceptionState.cpp diff --git a/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index 966bdff3ad95..90d8ab97fb73 100644 --- a/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -1,5 +1,4 @@ -//===-- PythonDataObjects.cpp ------------------------------------*- C++ -//-*-===// +//===-- PythonDataObjects.cpp -----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -123,21 +122,20 @@ PythonObject::ResolveNameWithDictionary(llvm::StringRef name, } PythonObject PythonObject::ResolveName(llvm::StringRef name) const { - // Resolve the name in the context of the specified object. If, - // for example, `this` refers to a PyModule, then this will look for - // `name` in this module. If `this` refers to a PyType, then it will - // resolve `name` as an attribute of that type. If `this` refers to - // an instance of an object, then it will resolve `name` as the value - // of the specified field. + // Resolve the name in the context of the specified object. If, for example, + // `this` refers to a PyModule, then this will look for `name` in this + // module. If `this` refers to a PyType, then it will resolve `name` as an + // attribute of that type. If `this` refers to an instance of an object, + // then it will resolve `name` as the value of the specified field. // // This function handles dotted names so that, for example, if `m_py_obj` - // refers to the `sys` module, and `name` == "path.append", then it - // will find the function `sys.path.append`. + // refers to the `sys` module, and `name` == "path.append", then it will find + // the function `sys.path.append`. size_t dot_pos = name.find_first_of('.'); if (dot_pos == llvm::StringRef::npos) { - // No dots in the name, we should be able to find the value immediately - // as an attribute of `m_py_obj`. + // No dots in the name, we should be able to find the value immediately as + // an attribute of `m_py_obj`. return GetAttributeValue(name); } @@ -230,8 +228,8 @@ bool PythonBytes::Check(PyObject *py_obj) { } void PythonBytes::Reset(PyRefType type, PyObject *py_obj) { - // Grab the desired reference type so that if we end up rejecting - // `py_obj` it still gets decremented if necessary. + // Grab the desired reference type so that if we end up rejecting `py_obj` it + // still gets decremented if necessary. PythonObject result(type, py_obj); if (!PythonBytes::Check(py_obj)) { @@ -240,8 +238,7 @@ void PythonBytes::Reset(PyRefType type, PyObject *py_obj) { } // Calling PythonObject::Reset(const PythonObject&) will lead to stack - // overflow since it calls - // back into the virtual implementation. + // overflow since it calls back into the virtual implementation. PythonObject::Reset(PyRefType::Borrowed, result.get()); } @@ -303,8 +300,8 @@ bool PythonByteArray::Check(PyObject *py_obj) { } void PythonByteArray::Reset(PyRefType type, PyObject *py_obj) { - // Grab the desired reference type so that if we end up rejecting - // `py_obj` it still gets decremented if necessary. + // Grab the desired reference type so that if we end up rejecting `py_obj` it + // still gets decremented if necessary. PythonObject result(type, py_obj); if (!PythonByteArray::Check(py_obj)) { @@ -313,8 +310,7 @@ void PythonByteArray::Reset(PyRefType type, PyObject *py_obj) { } // Calling PythonObject::Reset(const PythonObject&) will lead to stack - // overflow since it calls - // back into the virtual implementation. + // overflow since it calls back into the virtual implementation. PythonObject::Reset(PyRefType::Borrowed, result.get()); } @@ -378,8 +374,8 @@ bool PythonString::Check(PyObject *py_obj) { } void PythonString::Reset(PyRefType type, PyObject *py_obj) { - // Grab the desired reference type so that if we end up rejecting - // `py_obj` it still gets decremented if necessary. + // Grab the desired reference type so that if we end up rejecting `py_obj` it + // still gets decremented if necessary. PythonObject result(type, py_obj); if (!PythonString::Check(py_obj)) { @@ -394,8 +390,7 @@ void PythonString::Reset(PyRefType type, PyObject *py_obj) { result.Reset(PyRefType::Owned, PyUnicode_AsUTF8String(result.get())); #endif // Calling PythonObject::Reset(const PythonObject&) will lead to stack - // overflow since it calls - // back into the virtual implementation. + // overflow since it calls back into the virtual implementation. PythonObject::Reset(PyRefType::Borrowed, result.get()); } @@ -404,14 +399,16 @@ llvm::StringRef PythonString::GetString() const { return llvm::StringRef(); Py_ssize_t size; - char *c; + const char *data; #if PY_MAJOR_VERSION >= 3 - c = PyUnicode_AsUTF8AndSize(m_py_obj, &size); + data = PyUnicode_AsUTF8AndSize(m_py_obj, &size); #else + char *c; PyString_AsStringAndSize(m_py_obj, &c, &size); + data = c; #endif - return llvm::StringRef(c, size); + return llvm::StringRef(data, size); } size_t PythonString::GetSize() const { @@ -466,8 +463,8 @@ bool PythonInteger::Check(PyObject *py_obj) { return false; #if PY_MAJOR_VERSION >= 3 - // Python 3 does not have PyInt_Check. There is only one type of - // integral value, long. + // Python 3 does not have PyInt_Check. There is only one type of integral + // value, long. return PyLong_Check(py_obj); #else return PyLong_Check(py_obj) || PyInt_Check(py_obj); @@ -475,8 +472,8 @@ bool PythonInteger::Check(PyObject *py_obj) { } void PythonInteger::Reset(PyRefType type, PyObject *py_obj) { - // Grab the desired reference type so that if we end up rejecting - // `py_obj` it still gets decremented if necessary. + // Grab the desired reference type so that if we end up rejecting `py_obj` it + // still gets decremented if necessary. PythonObject result(type, py_obj); if (!PythonInteger::Check(py_obj)) { @@ -485,13 +482,13 @@ void PythonInteger::Reset(PyRefType type, PyObject *py_obj) { } #if PY_MAJOR_VERSION < 3 - // Always store this as a PyLong, which makes interoperability between - // Python 2.x and Python 3.x easier. This is only necessary in 2.x, - // since 3.x doesn't even have a PyInt. + // Always store this as a PyLong, which makes interoperability between Python + // 2.x and Python 3.x easier. This is only necessary in 2.x, since 3.x + // doesn't even have a PyInt. if (PyInt_Check(py_obj)) { // Since we converted the original object to a different type, the new - // object is an owned object regardless of the ownership semantics requested - // by the user. + // object is an owned object regardless of the ownership semantics + // requested by the user. result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj))); } #endif @@ -500,8 +497,7 @@ void PythonInteger::Reset(PyRefType type, PyObject *py_obj) { "Couldn't get a PyLong from this PyObject"); // Calling PythonObject::Reset(const PythonObject&) will lead to stack - // overflow since it calls - // back into the virtual implementation. + // overflow since it calls back into the virtual implementation. PythonObject::Reset(PyRefType::Borrowed, result.get()); } @@ -513,10 +509,9 @@ int64_t PythonInteger::GetInteger() const { int overflow = 0; int64_t result = PyLong_AsLongLongAndOverflow(m_py_obj, &overflow); if (overflow != 0) { - // We got an integer that overflows, like 18446744072853913392L - // we can't use PyLong_AsLongLong() as it will return - // 0xffffffffffffffff. If we use the unsigned long long - // it will work as expected. + // We got an integer that overflows, like 18446744072853913392L we can't + // use PyLong_AsLongLong() as it will return 0xffffffffffffffff. If we + // use the unsigned long long it will work as expected. const uint64_t uval = PyLong_AsUnsignedLongLong(m_py_obj); result = static_cast<int64_t>(uval); } @@ -563,8 +558,8 @@ bool PythonList::Check(PyObject *py_obj) { } void PythonList::Reset(PyRefType type, PyObject *py_obj) { - // Grab the desired reference type so that if we end up rejecting - // `py_obj` it still gets decremented if necessary. + // Grab the desired reference type so that if we end up rejecting `py_obj` it + // still gets decremented if necessary. PythonObject result(type, py_obj); if (!PythonList::Check(py_obj)) { @@ -573,8 +568,7 @@ void PythonList::Reset(PyRefType type, PyObject *py_obj) { } // Calling PythonObject::Reset(const PythonObject&) will lead to stack - // overflow since it calls - // back into the virtual implementation. + // overflow since it calls back into the virtual implementation. PythonObject::Reset(PyRefType::Borrowed, result.get()); } @@ -668,8 +662,8 @@ bool PythonTuple::Check(PyObject *py_obj) { } void PythonTuple::Reset(PyRefType type, PyObject *py_obj) { - // Grab the desired reference type so that if we end up rejecting - // `py_obj` it still gets decremented if necessary. + // Grab the desired reference type so that if we end up rejecting `py_obj` it + // still gets decremented if necessary. PythonObject result(type, py_obj); if (!PythonTuple::Check(py_obj)) { @@ -678,8 +672,7 @@ void PythonTuple::Reset(PyRefType type, PyObject *py_obj) { } // Calling PythonObject::Reset(const PythonObject&) will lead to stack - // overflow since it calls - // back into the virtual implementation. + // overflow since it calls back into the virtual implementation. PythonObject::Reset(PyRefType::Borrowed, result.get()); } @@ -741,8 +734,8 @@ bool PythonDictionary::Check(PyObject *py_obj) { } void PythonDictionary::Reset(PyRefType type, PyObject *py_obj) { - // Grab the desired reference type so that if we end up rejecting - // `py_obj` it still gets decremented if necessary. + // Grab the desired reference type so that if we end up rejecting `py_obj` it + // still gets decremented if necessary. PythonObject result(type, py_obj); if (!PythonDictionary::Check(py_obj)) { @@ -751,8 +744,7 @@ void PythonDictionary::Reset(PyRefType type, PyObject *py_obj) { } // Calling PythonObject::Reset(const PythonObject&) will lead to stack - // overflow since it calls - // back into the virtual implementation. + // overflow since it calls back into the virtual implementation. PythonObject::Reset(PyRefType::Borrowed, result.get()); } @@ -833,8 +825,8 @@ bool PythonModule::Check(PyObject *py_obj) { } void PythonModule::Reset(PyRefType type, PyObject *py_obj) { - // Grab the desired reference type so that if we end up rejecting - // `py_obj` it still gets decremented if necessary. + // Grab the desired reference type so that if we end up rejecting `py_obj` it + // still gets decremented if necessary. PythonObject result(type, py_obj); if (!PythonModule::Check(py_obj)) { @@ -843,8 +835,7 @@ void PythonModule::Reset(PyRefType type, PyObject *py_obj) { } // Calling PythonObject::Reset(const PythonObject&) will lead to stack - // overflow since it calls - // back into the virtual implementation. + // overflow since it calls back into the virtual implementation. PythonObject::Reset(PyRefType::Borrowed, result.get()); } @@ -871,8 +862,8 @@ bool PythonCallable::Check(PyObject *py_obj) { } void PythonCallable::Reset(PyRefType type, PyObject *py_obj) { - // Grab the desired reference type so that if we end up rejecting - // `py_obj` it still gets decremented if necessary. + // Grab the desired reference type so that if we end up rejecting `py_obj` it + // still gets decremented if necessary. PythonObject result(type, py_obj); if (!PythonCallable::Check(py_obj)) { @@ -881,8 +872,7 @@ void PythonCallable::Reset(PyRefType type, PyObject *py_obj) { } // Calling PythonObject::Reset(const PythonObject&) will lead to stack - // overflow since it calls - // back into the virtual implementation. + // overflow since it calls back into the virtual implementation. PythonObject::Reset(PyRefType::Borrowed, result.get()); } @@ -963,9 +953,9 @@ bool PythonFile::Check(PyObject *py_obj) { #else // In Python 3, there is no `PyFile_Check`, and in fact PyFile is not even a // first-class object type anymore. `PyFile_FromFd` is just a thin wrapper - // over `io.open()`, which returns some object derived from `io.IOBase`. - // As a result, the only way to detect a file in Python 3 is to check whether - // it inherits from `io.IOBase`. Since it is possible for non-files to also + // over `io.open()`, which returns some object derived from `io.IOBase`. As a + // result, the only way to detect a file in Python 3 is to check whether it + // inherits from `io.IOBase`. Since it is possible for non-files to also // inherit from `io.IOBase`, we additionally verify that it has the `fileno` // attribute, which should guarantee that it is backed by the file system. PythonObject io_module(PyRefType::Owned, PyImport_ImportModule("io")); @@ -985,8 +975,8 @@ bool PythonFile::Check(PyObject *py_obj) { } void PythonFile::Reset(PyRefType type, PyObject *py_obj) { - // Grab the desired reference type so that if we end up rejecting - // `py_obj` it still gets decremented if necessary. + // Grab the desired reference type so that if we end up rejecting `py_obj` it + // still gets decremented if necessary. PythonObject result(type, py_obj); if (!PythonFile::Check(py_obj)) { diff --git a/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp b/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp index 4d956d5dbe14..d28a8033820a 100644 --- a/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp +++ b/source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp @@ -30,9 +30,9 @@ PythonExceptionState::~PythonExceptionState() { } void PythonExceptionState::Acquire(bool restore_on_exit) { - // If a state is already acquired, the user needs to decide whether they - // want to discard or restore it. Don't allow the potential silent - // loss of a valid state. + // If a state is already acquired, the user needs to decide whether they want + // to discard or restore it. Don't allow the potential silent loss of a + // valid state. assert(!IsError()); if (!HasErrorOccurred()) @@ -45,8 +45,7 @@ void PythonExceptionState::Acquire(bool restore_on_exit) { // PyErr_Fetch clears the error flag. assert(!HasErrorOccurred()); - // Ownership of the objects returned by `PyErr_Fetch` is transferred - // to us. + // Ownership of the objects returned by `PyErr_Fetch` is transferred to us. m_type.Reset(PyRefType::Owned, py_type); m_value.Reset(PyRefType::Owned, py_value); m_traceback.Reset(PyRefType::Owned, py_traceback); @@ -56,14 +55,14 @@ void PythonExceptionState::Acquire(bool restore_on_exit) { void PythonExceptionState::Restore() { if (m_type.IsValid()) { // The documentation for PyErr_Restore says "Do not pass a null type and - // non-null value or traceback. So only restore if type was non-null - // to begin with. In this case we're passing ownership back to Python - // so release them all. + // non-null value or traceback. So only restore if type was non-null to + // begin with. In this case we're passing ownership back to Python so + // release them all. PyErr_Restore(m_type.release(), m_value.release(), m_traceback.release()); } - // After we restore, we should not hold onto the exception state. Demand that - // it be re-acquired. + // After we restore, we should not hold onto the exception state. Demand + // that it be re-acquired. Discard(); } @@ -100,10 +99,10 @@ std::string PythonExceptionState::Format() const { if (!IsError()) return std::string(); - // It's possible that ReadPythonBacktrace generated another exception. - // If this happens we have to clear the exception, because otherwise - // PyObject_Str() will assert below. That's why we needed to do the - // save / restore at the beginning of this function. + // It's possible that ReadPythonBacktrace generated another exception. If + // this happens we have to clear the exception, because otherwise + // PyObject_Str() will assert below. That's why we needed to do the save / + // restore at the beginning of this function. PythonExceptionState bt_error_state(false); std::string error_string; @@ -114,8 +113,8 @@ std::string PythonExceptionState::Format() const { // If we were able to read the backtrace, just append it. error_stream << backtrace << "\n"; } else { - // Otherwise, append some information about why we were unable to - // obtain the backtrace. + // Otherwise, append some information about why we were unable to obtain + // the backtrace. PythonString bt_error = bt_error_state.GetValue().Str(); error_stream << "An error occurred while retrieving the backtrace: " << bt_error.GetString() << "\n"; diff --git a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 6c39690268c6..b8eb36a2baf6 100644 --- a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -112,13 +112,12 @@ static bool g_initialized = false; namespace { -// Initializing Python is not a straightforward process. We cannot control what -// external code may have done before getting to this point in LLDB, including -// potentially having already initialized Python, so we need to do a lot of work -// to ensure that the existing state of the system is maintained across our -// initialization. We do this by using an RAII pattern where we save off -// initial -// state at the beginning, and restore it at the end +// Initializing Python is not a straightforward process. We cannot control +// what external code may have done before getting to this point in LLDB, +// including potentially having already initialized Python, so we need to do a +// lot of work to ensure that the existing state of the system is maintained +// across our initialization. We do this by using an RAII pattern where we +// save off initial state at the beginning, and restore it at the end struct InitializePythonRAII { public: InitializePythonRAII() @@ -210,12 +209,11 @@ bool ScriptInterpreterPython::Locker::DoAcquireLock() { LLDB_LOGV(log, "Ensured PyGILState. Previous state = {0}locked", m_GILState == PyGILState_UNLOCKED ? "un" : ""); - // we need to save the thread state when we first start the command - // because we might decide to interrupt it while some action is taking - // place outside of Python (e.g. printing to screen, waiting for the network, - // ...) - // in that case, _PyThreadState_Current will be NULL - and we would be unable - // to set the asynchronous exception - not a desirable situation + // we need to save the thread state when we first start the command because + // we might decide to interrupt it while some action is taking place outside + // of Python (e.g. printing to screen, waiting for the network, ...) in that + // case, _PyThreadState_Current will be NULL - and we would be unable to set + // the asynchronous exception - not a desirable situation m_python_interpreter->SetThreadState(PyThreadState_Get()); m_python_interpreter->IncrementLockCount(); return true; @@ -281,17 +279,16 @@ ScriptInterpreterPython::ScriptInterpreterPython( PyRun_SimpleString(run_string.GetData()); // Reloading modules requires a different syntax in Python 2 and Python 3. - // This provides - // a consistent syntax no matter what version of Python. + // This provides a consistent syntax no matter what version of Python. run_string.Clear(); run_string.Printf("run_one_line (%s, 'from six.moves import reload_module')", m_dictionary_name.c_str()); PyRun_SimpleString(run_string.GetData()); // WARNING: temporary code that loads Cocoa formatters - this should be done - // on a per-platform basis rather than loading the whole set - // and letting the individual formatter classes exploit APIs to check whether - // they can/cannot do their task + // on a per-platform basis rather than loading the whole set and letting the + // individual formatter classes exploit APIs to check whether they can/cannot + // do their task run_string.Clear(); run_string.Printf( "run_one_line (%s, 'import lldb.formatters, lldb.formatters.cpp, pydoc')", @@ -314,13 +311,11 @@ ScriptInterpreterPython::ScriptInterpreterPython( } ScriptInterpreterPython::~ScriptInterpreterPython() { - // the session dictionary may hold objects with complex state - // which means that they may need to be torn down with some level of smarts - // and that, in turn, requires a valid thread state - // force Python to procure itself such a thread state, nuke the session - // dictionary - // and then release it for others to use and proceed with the rest of the - // shutdown + // the session dictionary may hold objects with complex state which means + // that they may need to be torn down with some level of smarts and that, in + // turn, requires a valid thread state force Python to procure itself such a + // thread state, nuke the session dictionary and then release it for others + // to use and proceed with the rest of the shutdown auto gil_state = PyGILState_Ensure(); m_session_dict.Reset(); PyGILState_Release(gil_state); @@ -352,6 +347,71 @@ const char *ScriptInterpreterPython::GetPluginDescriptionStatic() { return "Embedded Python interpreter"; } +void ScriptInterpreterPython::ComputePythonDirForApple( + llvm::SmallVectorImpl<char> &path) { + auto style = llvm::sys::path::Style::posix; + + llvm::StringRef path_ref(path.begin(), path.size()); + auto rbegin = llvm::sys::path::rbegin(path_ref, style); + auto rend = llvm::sys::path::rend(path_ref); + auto framework = std::find(rbegin, rend, "LLDB.framework"); + if (framework == rend) { + ComputePythonDirForPosix(path); + return; + } + path.resize(framework - rend); + llvm::sys::path::append(path, style, "LLDB.framework", "Resources", "Python"); +} + +void ScriptInterpreterPython::ComputePythonDirForPosix( + llvm::SmallVectorImpl<char> &path) { + auto style = llvm::sys::path::Style::posix; +#if defined(LLDB_PYTHON_RELATIVE_LIBDIR) + // Build the path by backing out of the lib dir, then building with whatever + // the real python interpreter uses. (e.g. lib for most, lib64 on RHEL + // x86_64). + llvm::sys::path::remove_filename(path, style); + llvm::sys::path::append(path, style, LLDB_PYTHON_RELATIVE_LIBDIR); +#else + llvm::sys::path::append(path, style, + "python" + llvm::Twine(PY_MAJOR_VERSION) + "." + + llvm::Twine(PY_MINOR_VERSION), + "site-packages"); +#endif +} + +void ScriptInterpreterPython::ComputePythonDirForWindows( + llvm::SmallVectorImpl<char> &path) { + auto style = llvm::sys::path::Style::windows; + llvm::sys::path::remove_filename(path, style); + llvm::sys::path::append(path, style, "lib", "site-packages"); + + // This will be injected directly through FileSpec.GetDirectory().SetString(), + // so we need to normalize manually. + std::replace(path.begin(), path.end(), '\\', '/'); +} + +FileSpec ScriptInterpreterPython::GetPythonDir() { + static FileSpec g_spec = []() { + FileSpec spec = HostInfo::GetShlibDir(); + if (!spec) + return FileSpec(); + llvm::SmallString<64> path; + spec.GetPath(path); + +#if defined(__APPLE__) + ComputePythonDirForApple(path); +#elif defined(_WIN32) + ComputePythonDirForWindows(path); +#else + ComputePythonDirForPosix(path); +#endif + spec.GetDirectory().SetString(path); + return spec; + }(); + return g_spec; +} + lldb_private::ConstString ScriptInterpreterPython::GetPluginName() { return GetPluginNameStatic(); } @@ -452,16 +512,16 @@ void ScriptInterpreterPython::ResetOutputFileHandle(FILE *fh) {} void ScriptInterpreterPython::SaveTerminalState(int fd) { // Python mucks with the terminal state of STDIN. If we can possibly avoid // this by setting the file handles up correctly prior to entering the - // interpreter we should. For now we save and restore the terminal state - // on the input file handle. + // interpreter we should. For now we save and restore the terminal state on + // the input file handle. m_terminal_state.Save(fd, false); } void ScriptInterpreterPython::RestoreTerminalState() { // Python mucks with the terminal state of STDIN. If we can possibly avoid // this by setting the file handles up correctly prior to entering the - // interpreter we should. For now we save and restore the terminal state - // on the input file handle. + // interpreter we should. For now we save and restore the terminal state on + // the input file handle. m_terminal_state.Restore(); } @@ -470,14 +530,11 @@ void ScriptInterpreterPython::LeaveSession() { if (log) log->PutCString("ScriptInterpreterPython::LeaveSession()"); - // checking that we have a valid thread state - since we use our own threading - // and locking - // in some (rare) cases during cleanup Python may end up believing we have no - // thread state - // and PyImport_AddModule will crash if that is the case - since that seems to - // only happen - // when destroying the SBDebugger, we can make do without clearing up stdout - // and stderr + // checking that we have a valid thread state - since we use our own + // threading and locking in some (rare) cases during cleanup Python may end + // up believing we have no thread state and PyImport_AddModule will crash if + // that is the case - since that seems to only happen when destroying the + // SBDebugger, we can make do without clearing up stdout and stderr // rdar://problem/11292882 // When the current thread state is NULL, PyThreadState_Get() issues a fatal @@ -526,8 +583,7 @@ bool ScriptInterpreterPython::SetStdHandle(File &file, const char *py_name, bool ScriptInterpreterPython::EnterSession(uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err) { // If we have already entered the session, without having officially 'left' - // it, then there is no need to - // 'enter' it again. + // it, then there is no need to 'enter' it again. Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT)); if (m_session_is_active) { if (log) @@ -560,8 +616,8 @@ bool ScriptInterpreterPython::EnterSession(uint16_t on_entry_flags, FILE *in, run_string.PutCString("; lldb.frame = lldb.thread.GetSelectedFrame ()"); run_string.PutCString("')"); } else { - // If we aren't initing the globals, we should still always set the debugger - // (since that is always unique.) + // If we aren't initing the globals, we should still always set the + // debugger (since that is always unique.) run_string.Printf("run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64, m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID()); @@ -695,19 +751,20 @@ static void ReadThreadBytesReceived(void *baton, const void *src, } bool ScriptInterpreterPython::ExecuteOneLine( - const char *command, CommandReturnObject *result, + llvm::StringRef command, CommandReturnObject *result, const ExecuteScriptOptions &options) { + std::string command_str = command.str(); + if (!m_valid_session) return false; - if (command && command[0]) { + if (!command.empty()) { // We want to call run_one_line, passing in the dictionary and the command - // string. We cannot do this through - // PyRun_SimpleString here because the command string may contain escaped - // characters, and putting it inside + // string. We cannot do this through PyRun_SimpleString here because the + // command string may contain escaped characters, and putting it inside // another string to pass to PyRun_SimpleString messes up the escaping. So - // we use the following more complicated - // method to pass the command string directly down to Python. + // we use the following more complicated method to pass the command string + // directly down to Python. Debugger &debugger = m_interpreter.GetDebugger(); StreamFileSP input_file_sp; @@ -773,17 +830,14 @@ bool ScriptInterpreterPython::ExecuteOneLine( FILE *err_file = error_file_sp->GetFile().GetStream(); bool success = false; { - // WARNING! It's imperative that this RAII scope be as tight as possible. - // In particular, the - // scope must end *before* we try to join the read thread. The reason for - // this is that a - // pre-requisite for joining the read thread is that we close the write - // handle (to break the - // pipe and cause it to wake up and exit). But acquiring the GIL as below - // will redirect Python's - // stdio to use this same handle. If we close the handle while Python is - // still using it, bad - // things will happen. + // WARNING! It's imperative that this RAII scope be as tight as + // possible. In particular, the scope must end *before* we try to join + // the read thread. The reason for this is that a pre-requisite for + // joining the read thread is that we close the write handle (to break + // the pipe and cause it to wake up and exit). But acquiring the GIL as + // below will redirect Python's stdio to use this same handle. If we + // close the handle while Python is still using it, bad things will + // happen. Locker locker( this, ScriptInterpreterPython::Locker::AcquireLock | @@ -803,7 +857,7 @@ bool ScriptInterpreterPython::ExecuteOneLine( if (PyCallable_Check(m_run_one_line_function.get())) { PythonObject pargs( PyRefType::Owned, - Py_BuildValue("(Os)", session_dict.get(), command)); + Py_BuildValue("(Os)", session_dict.get(), command_str.c_str())); if (pargs.IsValid()) { PythonObject return_value( PyRefType::Owned, @@ -827,12 +881,12 @@ bool ScriptInterpreterPython::ExecuteOneLine( } if (join_read_thread) { - // Close the write end of the pipe since we are done with our - // one line script. This should cause the read thread that - // output_comm is using to exit + // Close the write end of the pipe since we are done with our one line + // script. This should cause the read thread that output_comm is using to + // exit output_file_sp->GetFile().Close(); - // The close above should cause this thread to exit when it gets - // to the end of file, so let it get all its data + // The close above should cause this thread to exit when it gets to the + // end of file, so let it get all its data output_comm.JoinReadThread(); // Now we can close the read end of the pipe output_comm.Disconnect(); @@ -842,9 +896,10 @@ bool ScriptInterpreterPython::ExecuteOneLine( return true; // The one-liner failed. Append the error message. - if (result) + if (result) { result->AppendErrorWithFormat( - "python failed attempting to evaluate '%s'\n", command); + "python failed attempting to evaluate '%s'\n", command_str.c_str()); + } return false; } @@ -889,21 +944,18 @@ public: ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); - // The following call drops into the embedded interpreter loop and stays - // there until the - // user chooses to exit from the Python interpreter. - // This embedded interpreter will, as any Python code that performs I/O, - // unlock the GIL before - // a system call that can hang, and lock it when the syscall has - // returned. + // The following call drops into the embedded interpreter loop and + // stays there until the user chooses to exit from the Python + // interpreter. This embedded interpreter will, as any Python code that + // performs I/O, unlock the GIL before a system call that can hang, and + // lock it when the syscall has returned. // We need to surround the call to the embedded interpreter with calls - // to PyGILState_Ensure and - // PyGILState_Release (using the Locker above). This is because Python - // has a global lock which must be held whenever we want - // to touch any Python objects. Otherwise, if the user calls Python - // code, the interpreter state will be off, - // and things could hang (it's happened before). + // to PyGILState_Ensure and PyGILState_Release (using the Locker + // above). This is because Python has a global lock which must be held + // whenever we want to touch any Python objects. Otherwise, if the user + // calls Python code, the interpreter state will be off, and things + // could hang (it's happened before). StreamString run_string; run_string.Printf("run_python_interpreter (%s)", @@ -934,12 +986,10 @@ void ScriptInterpreterPython::ExecuteInterpreterLoop() { Debugger &debugger = GetCommandInterpreter().GetDebugger(); // At the moment, the only time the debugger does not have an input file - // handle is when this is called - // directly from Python, in which case it is both dangerous and unnecessary - // (not to mention confusing) to - // try to embed a running interpreter loop inside the already running Python - // interpreter loop, so we won't - // do it. + // handle is when this is called directly from Python, in which case it is + // both dangerous and unnecessary (not to mention confusing) to try to embed + // a running interpreter loop inside the already running Python interpreter + // loop, so we won't do it. if (!debugger.GetInputFile()->GetFile().IsValid()) return; @@ -974,7 +1024,7 @@ bool ScriptInterpreterPython::Interrupt() { return false; } bool ScriptInterpreterPython::ExecuteOneLineWithReturn( - const char *in_string, ScriptInterpreter::ScriptReturnType return_type, + llvm::StringRef in_string, ScriptInterpreter::ScriptReturnType return_type, void *ret_value, const ExecuteScriptOptions &options) { Locker locker(this, ScriptInterpreterPython::Locker::AcquireLock | @@ -1009,116 +1059,111 @@ bool ScriptInterpreterPython::ExecuteOneLineWithReturn( if (py_error.IsValid()) PyErr_Clear(); - if (in_string != nullptr) { - { // scope for PythonInputReaderManager - // PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); - py_return.Reset( - PyRefType::Owned, - PyRun_String(in_string, Py_eval_input, globals.get(), locals.get())); - if (!py_return.IsValid()) { - py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); - if (py_error.IsValid()) - PyErr_Clear(); - - py_return.Reset(PyRefType::Owned, - PyRun_String(in_string, Py_single_input, globals.get(), - locals.get())); - } + std::string as_string = in_string.str(); + { // scope for PythonInputReaderManager + // PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); + py_return.Reset(PyRefType::Owned, + PyRun_String(as_string.c_str(), Py_eval_input, + globals.get(), locals.get())); + if (!py_return.IsValid()) { + py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); + if (py_error.IsValid()) + PyErr_Clear(); + + py_return.Reset(PyRefType::Owned, + PyRun_String(as_string.c_str(), Py_single_input, + globals.get(), locals.get())); } + } - if (py_return.IsValid()) { - switch (return_type) { - case eScriptReturnTypeCharPtr: // "char *" - { - const char format[3] = "s#"; - success = PyArg_Parse(py_return.get(), format, (char **)ret_value); - break; - } - case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == - // Py_None - { - const char format[3] = "z"; - success = PyArg_Parse(py_return.get(), format, (char **)ret_value); - break; - } - case eScriptReturnTypeBool: { - const char format[2] = "b"; - success = PyArg_Parse(py_return.get(), format, (bool *)ret_value); - break; - } - case eScriptReturnTypeShortInt: { - const char format[2] = "h"; - success = PyArg_Parse(py_return.get(), format, (short *)ret_value); - break; - } - case eScriptReturnTypeShortIntUnsigned: { - const char format[2] = "H"; - success = - PyArg_Parse(py_return.get(), format, (unsigned short *)ret_value); - break; - } - case eScriptReturnTypeInt: { - const char format[2] = "i"; - success = PyArg_Parse(py_return.get(), format, (int *)ret_value); - break; - } - case eScriptReturnTypeIntUnsigned: { - const char format[2] = "I"; - success = - PyArg_Parse(py_return.get(), format, (unsigned int *)ret_value); - break; - } - case eScriptReturnTypeLongInt: { - const char format[2] = "l"; - success = PyArg_Parse(py_return.get(), format, (long *)ret_value); - break; - } - case eScriptReturnTypeLongIntUnsigned: { - const char format[2] = "k"; - success = - PyArg_Parse(py_return.get(), format, (unsigned long *)ret_value); - break; - } - case eScriptReturnTypeLongLong: { - const char format[2] = "L"; - success = PyArg_Parse(py_return.get(), format, (long long *)ret_value); - break; - } - case eScriptReturnTypeLongLongUnsigned: { - const char format[2] = "K"; - success = PyArg_Parse(py_return.get(), format, - (unsigned long long *)ret_value); - break; - } - case eScriptReturnTypeFloat: { - const char format[2] = "f"; - success = PyArg_Parse(py_return.get(), format, (float *)ret_value); - break; - } - case eScriptReturnTypeDouble: { - const char format[2] = "d"; - success = PyArg_Parse(py_return.get(), format, (double *)ret_value); - break; - } - case eScriptReturnTypeChar: { - const char format[2] = "c"; - success = PyArg_Parse(py_return.get(), format, (char *)ret_value); - break; - } - case eScriptReturnTypeOpaqueObject: { - success = true; - PyObject *saved_value = py_return.get(); - Py_XINCREF(saved_value); - *((PyObject **)ret_value) = saved_value; - break; - } - } - - if (success) - ret_success = true; - else - ret_success = false; + if (py_return.IsValid()) { + switch (return_type) { + case eScriptReturnTypeCharPtr: // "char *" + { + const char format[3] = "s#"; + success = PyArg_Parse(py_return.get(), format, (char **)ret_value); + break; + } + case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == + // Py_None + { + const char format[3] = "z"; + success = PyArg_Parse(py_return.get(), format, (char **)ret_value); + break; } + case eScriptReturnTypeBool: { + const char format[2] = "b"; + success = PyArg_Parse(py_return.get(), format, (bool *)ret_value); + break; + } + case eScriptReturnTypeShortInt: { + const char format[2] = "h"; + success = PyArg_Parse(py_return.get(), format, (short *)ret_value); + break; + } + case eScriptReturnTypeShortIntUnsigned: { + const char format[2] = "H"; + success = + PyArg_Parse(py_return.get(), format, (unsigned short *)ret_value); + break; + } + case eScriptReturnTypeInt: { + const char format[2] = "i"; + success = PyArg_Parse(py_return.get(), format, (int *)ret_value); + break; + } + case eScriptReturnTypeIntUnsigned: { + const char format[2] = "I"; + success = PyArg_Parse(py_return.get(), format, (unsigned int *)ret_value); + break; + } + case eScriptReturnTypeLongInt: { + const char format[2] = "l"; + success = PyArg_Parse(py_return.get(), format, (long *)ret_value); + break; + } + case eScriptReturnTypeLongIntUnsigned: { + const char format[2] = "k"; + success = + PyArg_Parse(py_return.get(), format, (unsigned long *)ret_value); + break; + } + case eScriptReturnTypeLongLong: { + const char format[2] = "L"; + success = PyArg_Parse(py_return.get(), format, (long long *)ret_value); + break; + } + case eScriptReturnTypeLongLongUnsigned: { + const char format[2] = "K"; + success = + PyArg_Parse(py_return.get(), format, (unsigned long long *)ret_value); + break; + } + case eScriptReturnTypeFloat: { + const char format[2] = "f"; + success = PyArg_Parse(py_return.get(), format, (float *)ret_value); + break; + } + case eScriptReturnTypeDouble: { + const char format[2] = "d"; + success = PyArg_Parse(py_return.get(), format, (double *)ret_value); + break; + } + case eScriptReturnTypeChar: { + const char format[2] = "c"; + success = PyArg_Parse(py_return.get(), format, (char *)ret_value); + break; + } + case eScriptReturnTypeOpaqueObject: { + success = true; + PyObject *saved_value = py_return.get(); + Py_XINCREF(saved_value); + *((PyObject **)ret_value) = saved_value; + break; + } + } + + ret_success = success; } py_error.Reset(PyRefType::Borrowed, PyErr_Occurred()); @@ -1174,10 +1219,8 @@ Status ScriptInterpreterPython::ExecuteMultipleLines( if (code_object.IsValid()) { // In Python 2.x, PyEval_EvalCode takes a PyCodeObject, but in Python 3.x, it -// takes -// a PyObject. They are convertible (hence the function -// PyCode_Check(PyObject*), so -// we have to do the cast for Python 2.x +// takes a PyObject. They are convertible (hence the function +// PyCode_Check(PyObject*), so we have to do the cast for Python 2.x #if PY_MAJOR_VERSION >= 3 PyObject *py_code_obj = code_object.get(); #else @@ -1243,10 +1286,9 @@ Status ScriptInterpreterPython::SetBreakpointCommandCallback( auto data_ap = llvm::make_unique<CommandDataPython>(); // Split the command_body_text into lines, and pass that to - // GenerateBreakpointCommandCallbackData. That will - // wrap the body in an auto-generated function, and return the function name - // in script_source. That is what - // the callback will actually invoke. + // GenerateBreakpointCommandCallbackData. That will wrap the body in an + // auto-generated function, and return the function name in script_source. + // That is what the callback will actually invoke. data_ap->user_source.SplitIntoLines(command_body_text); Status error = GenerateBreakpointCommandCallbackData(data_ap->user_source, @@ -1268,9 +1310,8 @@ void ScriptInterpreterPython::SetWatchpointCommandCallback( // It's necessary to set both user_source and script_source to the oneliner. // The former is used to generate callback description (as in watchpoint - // command list) - // while the latter is used for Python to interpret during the actual - // callback. + // command list) while the latter is used for Python to interpret during the + // actual callback. data_ap->user_source.AppendString(oneliner); data_ap->script_source.assign(oneliner); @@ -1365,8 +1406,7 @@ bool ScriptInterpreterPython::GenerateTypeScriptFunction( return false; // Take what the user wrote, wrap it all up inside one big auto-generated - // Python function, passing in the - // ValueObject as parameter to the function. + // Python function, passing in the ValueObject as parameter to the function. std::string auto_generated_function_name( GenerateUniqueName("lldb_autogen_python_type_print_func", @@ -1430,8 +1470,8 @@ bool ScriptInterpreterPython::GenerateTypeSynthClass(StringList &user_input, sstr.Printf("class %s:", auto_generated_class_name.c_str()); auto_generated_class.AppendString(sstr.GetString()); - // Wrap everything up inside the class, increasing the indentation. - // we don't need to play any fancy indentation tricks here because there is no + // Wrap everything up inside the class, increasing the indentation. we don't + // need to play any fancy indentation tricks here because there is no // surrounding code whose indentation we need to honor for (int i = 0; i < num_lines; ++i) { sstr.Clear(); @@ -1439,9 +1479,8 @@ bool ScriptInterpreterPython::GenerateTypeSynthClass(StringList &user_input, auto_generated_class.AppendString(sstr.GetString()); } - // Verify that the results are valid Python. - // (even though the method is ExportFunctionDefinitionToInterpreter, a class - // will actually be exported) + // Verify that the results are valid Python. (even though the method is + // ExportFunctionDefinitionToInterpreter, a class will actually be exported) // (TODO: rename that method to ExportDefinitionToInterpreter) if (!ExportFunctionDefinitionToInterpreter(auto_generated_class).Success()) return false; @@ -1585,8 +1624,8 @@ StructuredData::ArraySP ScriptInterpreterPython::OSPlugin_ThreadsInfo( // GetPythonValueFormatString provides a system independent type safe way to // convert a variable's type into a python value format. Python value formats -// are defined in terms of builtin C types and could change from system to -// as the underlying typedef for uint* types, size_t, off_t and other values +// are defined in terms of builtin C types and could change from system to as +// the underlying typedef for uint* types, size_t, off_t and other values // change. template <typename T> const char *GetPythonValueFormatString(T t); @@ -2044,8 +2083,7 @@ void ScriptInterpreterPython::Clear() { ScriptInterpreterPython::Locker::FreeAcquiredLock); // This may be called as part of Py_Finalize. In that case the modules are - // destroyed in random - // order and we can't guarantee that we can access these. + // destroyed in random order and we can't guarantee that we can access these. if (Py_IsInitialized()) PyRun_SimpleString("lldb.debugger = None; lldb.target = None; lldb.process " "= None; lldb.thread = None; lldb.frame = None"); @@ -2615,9 +2653,9 @@ bool ScriptInterpreterPython::LoadScriptingModule( // strip .py or .pyc extension ConstString extension = target_file.GetFileNameExtension(); if (extension) { - if (::strcmp(extension.GetCString(), "py") == 0) + if (llvm::StringRef(extension.GetCString()) == ".py") basename.resize(basename.length() - 3); - else if (::strcmp(extension.GetCString(), "pyc") == 0) + else if (llvm::StringRef(extension.GetCString()) == ".pyc") basename.resize(basename.length() - 4); } } else { @@ -2629,9 +2667,8 @@ bool ScriptInterpreterPython::LoadScriptingModule( command_stream.Clear(); command_stream.Printf("sys.modules.__contains__('%s')", basename.c_str()); bool does_contain = false; - // this call will succeed if the module was ever imported in any Debugger in - // the lifetime of the process - // in which this LLDB framework is living + // this call will succeed if the module was ever imported in any Debugger + // in the lifetime of the process in which this LLDB framework is living bool was_imported_globally = (ExecuteOneLineWithReturn( command_stream.GetData(), @@ -2705,8 +2742,8 @@ bool ScriptInterpreterPython::IsReservedWord(const char *word) { llvm::StringRef word_sr(word); - // filter out a few characters that would just confuse us - // and that are clearly not keyword material anyway + // filter out a few characters that would just confuse us and that are + // clearly not keyword material anyway if (word_sr.find_first_of("'\"") != llvm::StringRef::npos) return false; @@ -2740,7 +2777,7 @@ ScriptInterpreterPython::SynchronicityHandler::~SynchronicityHandler() { } bool ScriptInterpreterPython::RunScriptBasedCommand( - const char *impl_function, const char *args, + const char *impl_function, llvm::StringRef args, ScriptedCommandSynchronicity synchronicity, lldb_private::CommandReturnObject &cmd_retobj, Status &error, const lldb_private::ExecutionContext &exe_ctx) { @@ -2774,9 +2811,10 @@ bool ScriptInterpreterPython::RunScriptBasedCommand( SynchronicityHandler synch_handler(debugger_sp, synchronicity); - ret_val = - g_swig_call_command(impl_function, m_dictionary_name.c_str(), - debugger_sp, args, cmd_retobj, exe_ctx_ref_sp); + std::string args_str = args.str(); + ret_val = g_swig_call_command(impl_function, m_dictionary_name.c_str(), + debugger_sp, args_str.c_str(), cmd_retobj, + exe_ctx_ref_sp); } if (!ret_val) @@ -2788,7 +2826,7 @@ bool ScriptInterpreterPython::RunScriptBasedCommand( } bool ScriptInterpreterPython::RunScriptBasedCommand( - StructuredData::GenericSP impl_obj_sp, const char *args, + StructuredData::GenericSP impl_obj_sp, llvm::StringRef args, ScriptedCommandSynchronicity synchronicity, lldb_private::CommandReturnObject &cmd_retobj, Status &error, const lldb_private::ExecutionContext &exe_ctx) { @@ -2822,8 +2860,10 @@ bool ScriptInterpreterPython::RunScriptBasedCommand( SynchronicityHandler synch_handler(debugger_sp, synchronicity); + std::string args_str = args.str(); ret_val = g_swig_call_command_object(impl_obj_sp->GetValue(), debugger_sp, - args, cmd_retobj, exe_ctx_ref_sp); + args_str.c_str(), cmd_retobj, + exe_ctx_ref_sp); } if (!ret_val) @@ -2834,9 +2874,9 @@ bool ScriptInterpreterPython::RunScriptBasedCommand( return ret_val; } -// in Python, a special attribute __doc__ contains the docstring -// for an object (function, method, class, ...) if any is defined -// Otherwise, the attribute's value is None +// in Python, a special attribute __doc__ contains the docstring for an object +// (function, method, class, ...) if any is defined Otherwise, the attribute's +// value is None bool ScriptInterpreterPython::GetDocumentationForItem(const char *item, std::string &dest) { dest.clear(); @@ -3106,10 +3146,9 @@ void ScriptInterpreterPython::InitializePrivate() { Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); // RAII-based initialization which correctly handles multiple-initialization, - // version- - // specific differences among Python 2 and Python 3, and saving and restoring - // various - // other pieces of state that can get mucked with during initialization. + // version- specific differences among Python 2 and Python 3, and saving and + // restoring various other pieces of state that can get mucked with during + // initialization. InitializePythonRAII initialize_guard; if (g_swig_init_callback) @@ -3121,17 +3160,13 @@ void ScriptInterpreterPython::InitializePrivate() { PyRun_SimpleString("import sys"); AddToSysPath(AddLocation::End, "."); - FileSpec file_spec; // Don't denormalize paths when calling file_spec.GetPath(). On platforms - // that use - // a backslash as the path separator, this will result in executing python - // code containing - // paths with unescaped backslashes. But Python also accepts forward slashes, - // so to make - // life easier we just use that. - if (HostInfo::GetLLDBPath(ePathTypePythonDir, file_spec)) + // that use a backslash as the path separator, this will result in executing + // python code containing paths with unescaped backslashes. But Python also + // accepts forward slashes, so to make life easier we just use that. + if (FileSpec file_spec = GetPythonDir()) AddToSysPath(AddLocation::Beginning, file_spec.GetPath(false)); - if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, file_spec)) + if (FileSpec file_spec = HostInfo::GetShlibDir()) AddToSysPath(AddLocation::Beginning, file_spec.GetPath(false)); PyRun_SimpleString("sys.dont_write_bytecode = 1; import " @@ -3157,30 +3192,20 @@ void ScriptInterpreterPython::AddToSysPath(AddLocation location, PyRun_SimpleString(statement.c_str()); } -// void -// ScriptInterpreterPython::Terminate () -//{ -// // We are intentionally NOT calling Py_Finalize here (this would be the -// logical place to call it). Calling -// // Py_Finalize here causes test suite runs to seg fault: The test suite -// runs in Python. It registers -// // SBDebugger::Terminate to be called 'at_exit'. When the test suite -// Python harness finishes up, it calls -// // Py_Finalize, which calls all the 'at_exit' registered functions. -// SBDebugger::Terminate calls Debugger::Terminate, -// // which calls lldb::Terminate, which calls ScriptInterpreter::Terminate, -// which calls -// // ScriptInterpreterPython::Terminate. So if we call Py_Finalize here, we -// end up with Py_Finalize being called from -// // within Py_Finalize, which results in a seg fault. -// // -// // Since this function only gets called when lldb is shutting down and -// going away anyway, the fact that we don't -// // actually call Py_Finalize should not cause any problems (everything -// should shut down/go away anyway when the -// // process exits). -// // -//// Py_Finalize (); -//} - -#endif // #ifdef LLDB_DISABLE_PYTHON +// We are intentionally NOT calling Py_Finalize here (this would be the logical +// place to call it). Calling Py_Finalize here causes test suite runs to seg +// fault: The test suite runs in Python. It registers SBDebugger::Terminate to +// be called 'at_exit'. When the test suite Python harness finishes up, it +// calls Py_Finalize, which calls all the 'at_exit' registered functions. +// SBDebugger::Terminate calls Debugger::Terminate, which calls lldb::Terminate, +// which calls ScriptInterpreter::Terminate, which calls +// ScriptInterpreterPython::Terminate. So if we call Py_Finalize here, we end +// up with Py_Finalize being called from within Py_Finalize, which results in a +// seg fault. Since this function only gets called when lldb is shutting down +// and going away anyway, the fact that we don't actually call Py_Finalize +// should not cause any problems (everything should shut down/go away anyway +// when the process exits). +// +// void ScriptInterpreterPython::Terminate() { Py_Finalize (); } + +#endif // LLDB_DISABLE_PYTHON diff --git a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h index a71fcea7519c..b13979dc069b 100644 --- a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -151,14 +151,14 @@ public: bool Interrupt() override; bool ExecuteOneLine( - const char *command, CommandReturnObject *result, + llvm::StringRef command, CommandReturnObject *result, const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; void ExecuteInterpreterLoop() override; bool ExecuteOneLineWithReturn( - const char *in_string, ScriptInterpreter::ScriptReturnType return_type, - void *ret_value, + llvm::StringRef in_string, + ScriptInterpreter::ScriptReturnType return_type, void *ret_value, const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; lldb_private::Status ExecuteMultipleLines( @@ -259,18 +259,17 @@ public: GetSyntheticTypeName(const StructuredData::ObjectSP &implementor) override; bool - RunScriptBasedCommand(const char *impl_function, const char *args, + RunScriptBasedCommand(const char *impl_function, llvm::StringRef args, ScriptedCommandSynchronicity synchronicity, lldb_private::CommandReturnObject &cmd_retobj, Status &error, const lldb_private::ExecutionContext &exe_ctx) override; - bool - RunScriptBasedCommand(StructuredData::GenericSP impl_obj_sp, const char *args, - ScriptedCommandSynchronicity synchronicity, - lldb_private::CommandReturnObject &cmd_retobj, - Status &error, - const lldb_private::ExecutionContext &exe_ctx) override; + bool RunScriptBasedCommand( + StructuredData::GenericSP impl_obj_sp, llvm::StringRef args, + ScriptedCommandSynchronicity synchronicity, + lldb_private::CommandReturnObject &cmd_retobj, Status &error, + const lldb_private::ExecutionContext &exe_ctx) override; Status GenerateFunction(const char *signature, const StringList &input) override; @@ -445,6 +444,8 @@ public: static const char *GetPluginDescriptionStatic(); + static FileSpec GetPythonDir(); + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -509,6 +510,10 @@ protected: static void AddToSysPath(AddLocation location, std::string path); + static void ComputePythonDirForApple(llvm::SmallVectorImpl<char> &path); + static void ComputePythonDirForPosix(llvm::SmallVectorImpl<char> &path); + static void ComputePythonDirForWindows(llvm::SmallVectorImpl<char> &path); + bool EnterSession(uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err); void LeaveSession(); diff --git a/source/Plugins/ScriptInterpreter/Python/lldb-python.h b/source/Plugins/ScriptInterpreter/Python/lldb-python.h index ee13b7a5cd1f..f929baade2e4 100644 --- a/source/Plugins/ScriptInterpreter/Python/lldb-python.h +++ b/source/Plugins/ScriptInterpreter/Python/lldb-python.h @@ -1,5 +1,4 @@ -//===-- lldb-python.h --------------------------------------------*- C++ -//-*-===// +//===-- lldb-python.h -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,7 +17,7 @@ // Python is disabled in this build #else #include "llvm/Support/Compiler.h" -#if defined(LLVM_ON_WIN32) +#if defined(_WIN32) // If anyone #includes Host/PosixApi.h later, it will try to typedef pid_t. We // need to ensure this doesn't happen. At the same time, Python.h will also try // to redefine a bunch of stuff that PosixApi.h defines. So define it all now diff --git a/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp b/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp index 8424b55ee69c..e33e26507fb1 100644 --- a/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp +++ b/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp @@ -23,6 +23,7 @@ #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Interpreter/Property.h" @@ -184,10 +185,10 @@ const char *const s_filter_attributes[] = { "message", // message contents, fully expanded "subsystem" // subsystem of the log message - // Consider impelmenting this action as it would be cheaper to filter. - // "message" requires always formatting the message, which is a waste - // of cycles if it ends up being rejected. - // "format", // format string used to format message text + // Consider implementing this action as it would be cheaper to filter. + // "message" requires always formatting the message, which is a waste of + // cycles if it ends up being rejected. "format", // format string + // used to format message text }; static const ConstString &GetDarwinLogTypeName() { @@ -238,11 +239,10 @@ public: // Indicate whether this is an accept or reject rule. dict_p->AddBooleanItem("accept", m_accept); - // Indicate which attribute of the message this filter references. - // This can drop into the rule-specific DoSerialization if we get - // to the point where not all FilterRule derived classes work on - // an attribute. (e.g. logical and/or and other compound - // operations). + // Indicate which attribute of the message this filter references. This can + // drop into the rule-specific DoSerialization if we get to the point where + // not all FilterRule derived classes work on an attribute. (e.g. logical + // and/or and other compound operations). dict_p->AddStringItem("attribute", s_filter_attributes[m_attribute_index]); // Indicate the type of the rule. @@ -403,9 +403,9 @@ static void RegisterFilterOperations() { // ------------------------------------------------------------------------- static 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. + // 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, "Specifies log messages from other related processes should be " @@ -419,10 +419,10 @@ static OptionDefinition g_enable_option_table[] = { "Specifies info-level log messages should be included."}, {LLDB_OPT_SET_ALL, false, "filter", 'f', OptionParser::eRequiredArgument, nullptr, 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 handled properly on those lines. + // 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 + // handled properly on those lines. "Appends a filter rule to the log message filter chain. Multiple " "rules may be added by specifying this option multiple times, " "once per filter rule. Filter rules are processed in the order " @@ -488,11 +488,11 @@ static OptionDefinition g_enable_option_table[] = { "a log message."}, {LLDB_OPT_SET_ALL, false, "category", 'c', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, - "Include the category in the the message header when displaying " + "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, - "Include the activity parent-child chain in the the message header " + "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}[:...]."}, @@ -544,7 +544,8 @@ public: break; case 'b': - m_broadcast_events = Args::StringToBoolean(option_arg, true, nullptr); + m_broadcast_events = + OptionArgParser::ToBoolean(option_arg, true, nullptr); break; case 'c': @@ -560,7 +561,7 @@ public: break; case 'e': - m_echo_to_stderr = Args::StringToBoolean(option_arg, false, nullptr); + m_echo_to_stderr = OptionArgParser::ToBoolean(option_arg, false, nullptr); break; case 'f': @@ -571,12 +572,12 @@ public: break; case 'l': - m_live_stream = Args::StringToBoolean(option_arg, false, nullptr); + m_live_stream = OptionArgParser::ToBoolean(option_arg, false, nullptr); break; case 'n': m_filter_fall_through_accepts = - Args::StringToBoolean(option_arg, true, nullptr); + OptionArgParser::ToBoolean(option_arg, true, nullptr); break; case 'r': @@ -614,7 +615,7 @@ public: source_flags_sp->AddBooleanItem("any-process", m_include_any_process); source_flags_sp->AddBooleanItem("debug-level", m_include_debug_level); - // The debug-level flag, if set, implies info-level. + // The debug-level flag, if set, implies info-level. source_flags_sp->AddBooleanItem("info-level", m_include_info_level || m_include_debug_level); source_flags_sp->AddBooleanItem("live-stream", m_live_stream); @@ -784,12 +785,11 @@ protected: if (!source_name) return; - // Check if we're *not* using strict sources. If not, - // then the user is going to get debug-level info - // anyways, probably not what they're expecting. - // Unfortunately we can only fix this by adding an - // env var, which would have had to have happened - // already. Thus, a warning is the best we can do here. + // Check if we're *not* using strict sources. If not, then the user is + // going to get debug-level info anyways, probably not what they're + // expecting. Unfortunately we can only fix this by adding an env var, + // which would have had to have happened already. Thus, a warning is the + // best we can do here. StreamString stream; stream.Printf("darwin-log source settings specify to exclude " "%s messages, but setting " @@ -803,24 +803,22 @@ protected: } bool DoExecute(Args &command, CommandReturnObject &result) override { - // First off, set the global sticky state of enable/disable - // based on this command execution. + // First off, set the global sticky state of enable/disable based on this + // command execution. s_is_explicitly_enabled = m_enable; - // Next, if this is an enable, save off the option data. - // We will need it later if a process hasn't been launched or - // attached yet. + // Next, if this is an enable, save off the option data. We will need it + // later if a process hasn't been launched or attached yet. if (m_enable) { - // Save off enabled configuration so we can apply these parsed - // options the next time an attach or launch occurs. + // Save off enabled configuration so we can apply these parsed options + // the next time an attach or launch occurs. DebuggerSP debugger_sp = GetCommandInterpreter().GetDebugger().shared_from_this(); SetGlobalEnableOptions(debugger_sp, m_options_sp); } - // Now check if we have a running process. If so, we should - // instruct the process monitor to enable/disable DarwinLog support - // now. + // Now check if we have a running process. If so, we should instruct the + // process monitor to enable/disable DarwinLog support now. Target *target = GetSelectedOrDummyTarget(); if (!target) { // No target, so there is nothing more to do right now. @@ -831,14 +829,13 @@ protected: // Grab the active process. auto process_sp = target->GetProcessSP(); if (!process_sp) { - // No active process, so there is nothing more to do right - // now. + // No active process, so there is nothing more to do right now. result.SetStatus(eReturnStatusSuccessFinishNoResult); return true; } - // If the process is no longer alive, we can't do this now. - // We'll catch it the next time the process is started up. + // If the process is no longer alive, we can't do this now. We'll catch it + // the next time the process is started up. if (!process_sp->IsAlive()) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return true; @@ -857,19 +854,17 @@ protected: *static_cast<StructuredDataDarwinLog *>(plugin_sp.get()); if (m_enable) { - // Hook up the breakpoint for the process that detects when - // libtrace has been sufficiently initialized to really start - // the os_log stream. This is insurance to assure us that - // logging is really enabled. Requesting that logging be - // enabled for a process before libtrace is initialized - // results in a scenario where no errors occur, but no logging - // is captured, either. This step is to eliminate that - // possibility. + // Hook up the breakpoint for the process that detects when libtrace has + // been sufficiently initialized to really start the os_log stream. This + // is insurance to assure us that logging is really enabled. Requesting + // that logging be enabled for a process before libtrace is initialized + // results in a scenario where no errors occur, but no logging is + // captured, either. This step is to eliminate that possibility. plugin.AddInitCompletionHook(*process_sp.get()); } - // Send configuration to the feature by way of the process. - // Construct the options we will use. + // Send configuration to the feature by way of the process. Construct the + // options we will use. auto config_sp = m_options_sp->BuildConfigurationData(m_enable); const Status error = process_sp->ConfigureStructuredData(GetDarwinLogTypeName(), config_sp); @@ -882,8 +877,8 @@ protected: plugin.SetEnabled(false); } else { result.SetStatus(eReturnStatusSuccessFinishNoResult); - // Our configuration succeeeded, so we're enabled/disabled - // per whichever one this command is setup to do. + // Our configuration succeeded, so we're enabled/disabled per whichever + // one this command is setup to do. plugin.SetEnabled(m_enable); } return result.Succeeded(); @@ -914,8 +909,8 @@ protected: bool DoExecute(Args &command, CommandReturnObject &result) override { auto &stream = result.GetOutputStream(); - // Figure out if we've got a process. If so, we can tell if - // DarwinLog is available for that process. + // Figure out if we've got a process. If so, we can tell if DarwinLog is + // available for that process. Target *target = GetSelectedOrDummyTarget(); auto process_sp = target ? target->GetProcessSP() : ProcessSP(); if (!target || !process_sp) { @@ -1013,13 +1008,13 @@ public: }; EnableOptionsSP ParseAutoEnableOptions(Status &error, Debugger &debugger) { - // We are abusing the options data model here so that we can parse - // options without requiring the Debugger instance. + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS); + // We are abusing the options data model here so that we can parse options + // without requiring the Debugger instance. - // We have an empty execution context at this point. We only want - // to parse options, and we don't need any context to do this here. - // In fact, we want to be able to parse the enable options before having - // any context. + // We have an empty execution context at this point. We only want to parse + // options, and we don't need any context to do this here. In fact, we want + // to be able to parse the enable options before having any context. ExecutionContext exe_ctx; EnableOptionsSP options_sp(new EnableOptions()); @@ -1044,22 +1039,23 @@ EnableOptionsSP ParseAutoEnableOptions(Status &error, Debugger &debugger) { options_property_sp->GetAsString()->GetCurrentValue(); Args args(enable_options); if (args.GetArgumentCount() > 0) { - // Eliminate the initial '--' that would be required to set the - // settings that themselves include '-' and/or '--'. + // Eliminate the initial '--' that would be required to set the settings + // that themselves include '-' and/or '--'. const char *first_arg = args.GetArgumentAtIndex(0); if (first_arg && (strcmp(first_arg, "--") == 0)) args.Shift(); } - // ParseOptions calls getopt_long_only, which always skips the zero'th item in - // the array and starts at position 1, - // so we need to push a dummy value into position zero. - args.Unshift(llvm::StringRef("dummy_string")); bool require_validation = false; - error = args.ParseOptions(*options_sp.get(), &exe_ctx, PlatformSP(), - require_validation); - if (!error.Success()) + llvm::Expected<Args> args_or = + options_sp->Parse(args, &exe_ctx, PlatformSP(), require_validation); + if (!args_or) { + LLDB_LOG_ERROR( + log, args_or.takeError(), + "Parsing plugin.structured-data.darwin-log.auto-enable-options value " + "failed: {0}"); return EnableOptionsSP(); + } if (!options_sp->VerifyOptions(result)) return EnableOptionsSP(); @@ -1168,9 +1164,9 @@ void StructuredDataDarwinLog::HandleArrivalOfStructuredData( return; } - // Broadcast the structured data event if we have that enabled. - // This is the way that the outside world (all clients) get access - // to this data. This plugin sets policy as to whether we do that. + // Broadcast the structured data event if we have that enabled. This is the + // way that the outside world (all clients) get access to this data. This + // plugin sets policy as to whether we do that. DebuggerSP debugger_sp = process.GetTarget().GetDebugger().shared_from_this(); auto options_sp = GetGlobalEnableOptions(debugger_sp); if (options_sp && options_sp->GetBroadcastEvents()) { @@ -1180,8 +1176,8 @@ void StructuredDataDarwinLog::HandleArrivalOfStructuredData( process.BroadcastStructuredData(object_sp, shared_from_this()); } - // Later, hang on to a configurable amount of these and allow commands - // to inspect, including showing backtraces. + // Later, hang on to a configurable amount of these and allow commands to + // inspect, including showing backtraces. } static void SetErrorWithJSON(Status &error, const char *message, @@ -1257,8 +1253,8 @@ Status StructuredDataDarwinLog::GetDescription( return false; } - // If we haven't already grabbed the first timestamp - // value, do that now. + // If we haven't already grabbed the first timestamp value, do that + // now. if (!m_recorded_first_timestamp) { uint64_t timestamp = 0; if (event->GetValueForKeyAsInteger("timestamp", timestamp)) { @@ -1296,8 +1292,8 @@ void StructuredDataDarwinLog::ModulesDidLoad(Process &process, // Check if we should enable the darwin log support on startup/attach. if (!GetGlobalProperties()->GetEnableOnStartup() && !s_is_explicitly_enabled) { - // We're neither auto-enabled or explicitly enabled, so we shouldn't - // try to enable here. + // We're neither auto-enabled or explicitly enabled, so we shouldn't try to + // enable here. if (log) log->Printf("StructuredDataDarwinLog::%s not applicable, we're not " "enabled (process uid %u)", @@ -1317,9 +1313,9 @@ void StructuredDataDarwinLog::ModulesDidLoad(Process &process, } } - // The logging support module name, specifies the name of - // the image name that must be loaded into the debugged process before - // we can try to enable logging. + // The logging support module name, specifies the name of the image name that + // must be loaded into the debugged process before we can try to enable + // logging. const char *logging_module_cstr = GetGlobalProperties()->GetLoggingModuleName(); if (!logging_module_cstr || (logging_module_cstr[0] == 0)) { @@ -1359,8 +1355,8 @@ void StructuredDataDarwinLog::ModulesDidLoad(Process &process, return; } - // Time to enqueue the breakpoint so we can wait for logging support - // to be initialized before we try to tap the libtrace stream. + // Time to enqueue the breakpoint so we can wait for logging support to be + // initialized before we try to tap the libtrace stream. AddInitCompletionHook(process); if (log) log->Printf("StructuredDataDarwinLog::%s post-init hook breakpoint " @@ -1368,13 +1364,13 @@ void StructuredDataDarwinLog::ModulesDidLoad(Process &process, __FUNCTION__, logging_module_name.AsCString(), process.GetUniqueID()); - // We need to try the enable here as well, which will succeed - // in the event that we're attaching to (rather than launching) the - // process and the process is already past initialization time. In that - // case, the completion breakpoint will never get hit and therefore won't - // start that way. It doesn't hurt much beyond a bit of bandwidth - // if we end up doing this twice. It hurts much more if we don't get - // the logging enabled when the user expects it. + // We need to try the enable here as well, which will succeed in the event + // that we're attaching to (rather than launching) the process and the + // process is already past initialization time. In that case, the completion + // breakpoint will never get hit and therefore won't start that way. It + // doesn't hurt much beyond a bit of bandwidth if we end up doing this twice. + // It hurts much more if we don't get the logging enabled when the user + // expects it. EnableNow(); } @@ -1411,8 +1407,7 @@ StructuredDataDarwinLog::StructuredDataDarwinLog(const ProcessWP &process_wp) StructuredDataPluginSP StructuredDataDarwinLog::CreateInstance(Process &process) { - // Currently only Apple targets support the os_log/os_activity - // protocol. + // Currently only Apple targets support the os_log/os_activity protocol. if (process.GetTarget().GetArchitecture().GetTriple().getVendor() == llvm::Triple::VendorType::Apple) { auto process_wp = ProcessWP(process.shared_from_this()); @@ -1459,20 +1454,20 @@ Status StructuredDataDarwinLog::FilterLaunchInfo(ProcessLaunchInfo &launch_info, Target *target) { Status error; - // If we're not debugging this launched process, there's nothing for us - // to do here. + // If we're not debugging this launched process, there's nothing for us to do + // here. if (!launch_info.GetFlags().AnySet(eLaunchFlagDebug)) return error; // Darwin os_log() support automatically adds debug-level and info-level // messages when a debugger is attached to a process. However, with - // integrated suppport for debugging built into the command-line LLDB, - // the user may specifically set to *not* include debug-level and info-level - // content. When the user is using the integrated log support, we want - // to put the kabosh on that automatic adding of info and debug level. - // This is done by adding an environment variable to the process on launch. - // (This also means it is not possible to suppress this behavior if - // attaching to an already-running app). + // integrated support for debugging built into the command-line LLDB, the + // user may specifically set to *not* include debug-level and info-level + // content. When the user is using the integrated log support, we want to + // put the kabosh on that automatic adding of info and debug level. This is + // done by adding an environment variable to the process on launch. (This + // also means it is not possible to suppress this behavior if attaching to an + // already-running app). // Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); // If the target architecture is not one that supports DarwinLog, we have @@ -1483,20 +1478,19 @@ Status StructuredDataDarwinLog::FilterLaunchInfo(ProcessLaunchInfo &launch_info, return error; } - // If DarwinLog is not enabled (either by explicit user command or via - // the auto-enable option), then we have nothing to do. + // If DarwinLog is not enabled (either by explicit user command or via the + // auto-enable option), then we have nothing to do. if (!GetGlobalProperties()->GetEnableOnStartup() && !s_is_explicitly_enabled) { // Nothing to do, DarwinLog is not enabled. return error; } - // If we don't have parsed configuration info, that implies we have - // enable-on-startup set up, but we haven't yet attempted to run the - // enable command. + // If we don't have parsed configuration info, that implies we have enable- + // on-startup set up, but we haven't yet attempted to run the enable command. if (!target) { - // We really can't do this without a target. We need to be able - // to get to the debugger to get the proper options to do this right. + // We really can't do this without a target. We need to be able to get to + // the debugger to get the proper options to do this right. // TODO log. error.SetErrorString("requires a target to auto-enable DarwinLog."); return error; @@ -1509,34 +1503,28 @@ Status StructuredDataDarwinLog::FilterLaunchInfo(ProcessLaunchInfo &launch_info, if (!options_sp || !error.Success()) return error; - // We already parsed the options, save them now so we don't generate - // them again until the user runs the command manually. + // We already parsed the options, save them now so we don't generate them + // again until the user runs the command manually. SetGlobalEnableOptions(debugger_sp, options_sp); } - auto &env_vars = launch_info.GetEnvironmentEntries(); if (!options_sp->GetEchoToStdErr()) { - // The user doesn't want to see os_log/NSLog messages echo to stderr. - // That mechanism is entirely separate from the DarwinLog support. - // By default we don't want to get it via stderr, because that would - // be in duplicate of the explicit log support here. + // The user doesn't want to see os_log/NSLog messages echo to stderr. That + // mechanism is entirely separate from the DarwinLog support. By default we + // don't want to get it via stderr, because that would be in duplicate of + // the explicit log support here. // Here we need to strip out any OS_ACTIVITY_DT_MODE setting to prevent // echoing of os_log()/NSLog() to stderr in the target program. - size_t argument_index; - if (env_vars.ContainsEnvironmentVariable( - llvm::StringRef("OS_ACTIVITY_DT_MODE"), &argument_index)) - env_vars.DeleteArgumentAtIndex(argument_index); + launch_info.GetEnvironment().erase("OS_ACTIVITY_DT_MODE"); - // We will also set the env var that tells any downstream launcher - // from adding OS_ACTIVITY_DT_MODE. - env_vars.AddOrReplaceEnvironmentVariable( - llvm::StringRef("IDE_DISABLED_OS_ACTIVITY_DT_MODE"), - llvm::StringRef("1")); + // We will also set the env var that tells any downstream launcher from + // adding OS_ACTIVITY_DT_MODE. + launch_info.GetEnvironment()["IDE_DISABLED_OS_ACTIVITY_DT_MODE"] = "1"; } - // Set the OS_ACTIVITY_MODE env var appropriately to enable/disable - // debug and info level messages. + // Set the OS_ACTIVITY_MODE env var appropriately to enable/disable debug and + // info level messages. const char *env_var_value; if (options_sp->GetIncludeDebugLevel()) env_var_value = "debug"; @@ -1545,10 +1533,7 @@ Status StructuredDataDarwinLog::FilterLaunchInfo(ProcessLaunchInfo &launch_info, else env_var_value = "default"; - if (env_var_value) { - launch_info.GetEnvironmentEntries().AddOrReplaceEnvironmentVariable( - llvm::StringRef("OS_ACTIVITY_MODE"), llvm::StringRef(env_var_value)); - } + launch_info.GetEnvironment()["OS_ACTIVITY_MODE"] = env_var_value; return error; } @@ -1558,8 +1543,8 @@ bool StructuredDataDarwinLog::InitCompletionHookCallback( lldb::user_id_t break_loc_id) { // We hit the init function. We now want to enqueue our new thread plan, // which will in turn enqueue a StepOut thread plan. When the StepOut - // finishes and control returns to our new thread plan, that is the time - // when we can execute our logic to enable the logging support. + // finishes and control returns to our new thread plan, that is the time when + // we can execute our logic to enable the logging support. Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) @@ -1618,8 +1603,8 @@ bool StructuredDataDarwinLog::InitCompletionHookCallback( process_uid); return; } - // Make sure we only call it once, just in case the - // thread plan hits the breakpoint twice. + // Make sure we only call it once, just in case the thread plan hits + // the breakpoint twice. if (!called_enable_method) { if (log) log->Printf("StructuredDataDarwinLog::post-init callback: " @@ -1629,8 +1614,8 @@ bool StructuredDataDarwinLog::InitCompletionHookCallback( ->EnableNow(); called_enable_method = true; } else { - // Our breakpoint was hit more than once. Unexpected but - // no harm done. Log it. + // Our breakpoint was hit more than once. Unexpected but no harm + // done. Log it. if (log) log->Printf("StructuredDataDarwinLog::post-init callback: " "skipping EnableNow(), already called by " @@ -1687,8 +1672,8 @@ void StructuredDataDarwinLog::AddInitCompletionHook(Process &process) { m_added_breakpoint = true; } - // Set a breakpoint for the process that will kick in when libtrace - // has finished its initialization. + // Set a breakpoint for the process that will kick in when libtrace has + // finished its initialization. Target &target = process.GetTarget(); // Build up the module list. @@ -1793,8 +1778,8 @@ StructuredDataDarwinLog::DumpHeader(Stream &output_stream, if (header_count > 0) stream.PutChar(','); - // Display the activity chain, from parent-most to child-most - // activity, separated by a colon (:). + // Display the activity chain, from parent-most to child-most activity, + // separated by a colon (:). stream.PutCString("activity-chain="); stream.PutCString(activity_chain); ++header_count; @@ -1836,8 +1821,8 @@ size_t StructuredDataDarwinLog::HandleDisplayOfEvent( // Check the type of the event. ConstString event_type; if (!event.GetValueForKeyAsString("type", event_type)) { - // Hmm, we expected to get events that describe - // what they are. Continue anyway. + // Hmm, we expected to get events that describe what they are. Continue + // anyway. return 0; } @@ -1885,10 +1870,10 @@ void StructuredDataDarwinLog::EnableNow() { log->Printf("StructuredDataDarwinLog::%s() call is for process uid %u", __FUNCTION__, process_sp->GetUniqueID()); - // If we have configuration data, we can directly enable it now. - // Otherwise, we need to run through the command interpreter to parse - // the auto-run options (which is the only way we get here without having - // already-parsed configuration data). + // If we have configuration data, we can directly enable it now. Otherwise, + // we need to run through the command interpreter to parse the auto-run + // options (which is the only way we get here without having already-parsed + // configuration data). DebuggerSP debugger_sp = process_sp->GetTarget().GetDebugger().shared_from_this(); if (!debugger_sp) { @@ -1901,8 +1886,8 @@ void StructuredDataDarwinLog::EnableNow() { auto options_sp = GetGlobalEnableOptions(debugger_sp); if (!options_sp) { - // We haven't run the enable command yet. Just do that now, it'll - // take care of the rest. + // We haven't run the enable command yet. Just do that now, it'll take + // care of the rest. auto &interpreter = debugger_sp->GetCommandInterpreter(); const bool success = RunEnableCommand(interpreter); if (log) { @@ -1925,8 +1910,8 @@ void StructuredDataDarwinLog::EnableNow() { return; } - // We've previously been enabled. We will re-enable now with the - // previously specified options. + // We've previously been enabled. We will re-enable now with the previously + // specified options. auto config_sp = options_sp->BuildConfigurationData(true); if (!config_sp) { if (log) diff --git a/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp b/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp new file mode 100644 index 000000000000..db75cf9c3bb3 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp @@ -0,0 +1,177 @@ +//===-- AppleDWARFIndex.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/DWARF/AppleDWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" +#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" +#include "Plugins/SymbolFile/DWARF/DWARFUnit.h" +#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" + +#include "lldb/Core/Module.h" +#include "lldb/Symbol/Function.h" + +using namespace lldb_private; +using namespace lldb; + +std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create( + Module &module, DWARFDataExtractor apple_names, + DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types, + DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) { + auto apple_names_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>( + apple_names, debug_str, ".apple_names"); + if (!apple_names_table_up->IsValid()) + apple_names_table_up.reset(); + + auto apple_namespaces_table_up = + llvm::make_unique<DWARFMappedHash::MemoryTable>( + apple_namespaces, debug_str, ".apple_namespaces"); + if (!apple_namespaces_table_up->IsValid()) + apple_namespaces_table_up.reset(); + + auto apple_types_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>( + apple_types, debug_str, ".apple_types"); + if (!apple_types_table_up->IsValid()) + apple_types_table_up.reset(); + + auto apple_objc_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>( + apple_objc, debug_str, ".apple_objc"); + if (!apple_objc_table_up->IsValid()) + apple_objc_table_up.reset(); + + if (apple_names_table_up || apple_names_table_up || apple_types_table_up || + apple_objc_table_up) + return llvm::make_unique<AppleDWARFIndex>( + module, std::move(apple_names_table_up), + std::move(apple_namespaces_table_up), std::move(apple_types_table_up), + std::move(apple_objc_table_up)); + + return nullptr; +} + +void AppleDWARFIndex::GetGlobalVariables(ConstString basename, DIEArray &offsets) { + if (m_apple_names_up) + m_apple_names_up->FindByName(basename.GetStringRef(), offsets); +} + +void AppleDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) { + if (!m_apple_names_up) + return; + + DWARFMappedHash::DIEInfoArray hash_data; + if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) + DWARFMappedHash::ExtractDIEArray(hash_data, offsets); +} + +void AppleDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, + DIEArray &offsets) { + if (!m_apple_names_up) + return; + + DWARFMappedHash::DIEInfoArray hash_data; + if (m_apple_names_up->AppendAllDIEsInRange( + cu.GetOffset(), cu.GetNextCompileUnitOffset(), hash_data)) + DWARFMappedHash::ExtractDIEArray(hash_data, offsets); +} + +void AppleDWARFIndex::GetObjCMethods(ConstString class_name, + DIEArray &offsets) { + if (m_apple_objc_up) + m_apple_objc_up->FindByName(class_name.GetStringRef(), offsets); +} + +void AppleDWARFIndex::GetCompleteObjCClass(ConstString class_name, + bool must_be_implementation, + DIEArray &offsets) { + if (m_apple_types_up) { + m_apple_types_up->FindCompleteObjCClassByName( + class_name.GetStringRef(), offsets, must_be_implementation); + } +} + +void AppleDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { + if (m_apple_types_up) + m_apple_types_up->FindByName(name.GetStringRef(), offsets); +} + +void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context, + DIEArray &offsets) { + if (!m_apple_types_up) + return; + + Log *log = LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | + DWARF_LOG_LOOKUPS); + const bool has_tag = m_apple_types_up->GetHeader().header_data.ContainsAtom( + DWARFMappedHash::eAtomTypeTag); + const bool has_qualified_name_hash = + m_apple_types_up->GetHeader().header_data.ContainsAtom( + DWARFMappedHash::eAtomTypeQualNameHash); + const ConstString type_name(context[0].name); + const dw_tag_t tag = context[0].tag; + if (has_tag && has_qualified_name_hash) { + const char *qualified_name = context.GetQualifiedName(); + const uint32_t qualified_name_hash = llvm::djbHash(qualified_name); + if (log) + m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()"); + m_apple_types_up->FindByNameAndTagAndQualifiedNameHash( + type_name.GetStringRef(), tag, qualified_name_hash, offsets); + } else if (has_tag) { + if (log) + m_module.LogMessage(log, "FindByNameAndTag()"); + m_apple_types_up->FindByNameAndTag(type_name.GetStringRef(), tag, offsets); + } else + m_apple_types_up->FindByName(type_name.GetStringRef(), offsets); +} + +void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { + if (m_apple_namespaces_up) + m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets); +} + +void AppleDWARFIndex::GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) { + DIEArray offsets; + m_apple_names_up->FindByName(name.GetStringRef(), offsets); + for (const DIERef &die_ref : offsets) { + ProcessFunctionDIE(name.GetStringRef(), die_ref, info, parent_decl_ctx, + name_type_mask, dies); + } +} + +void AppleDWARFIndex::GetFunctions(const RegularExpression ®ex, + DIEArray &offsets) { + if (!m_apple_names_up) + return; + + DWARFMappedHash::DIEInfoArray hash_data; + if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) + DWARFMappedHash::ExtractDIEArray(hash_data, offsets); +} + +void AppleDWARFIndex::ReportInvalidDIEOffset(dw_offset_t offset, + llvm::StringRef name) { + m_module.ReportErrorIfModifyDetected( + "the DWARF debug information has been modified (accelerator table had " + "bad die 0x%8.8x for '%s')\n", + offset, name.str().c_str()); +} + +void AppleDWARFIndex::Dump(Stream &s) { + if (m_apple_names_up) + s.PutCString(".apple_names index present\n"); + if (m_apple_namespaces_up) + s.PutCString(".apple_namespaces index present\n"); + if (m_apple_types_up) + s.PutCString(".apple_types index present\n"); + if (m_apple_objc_up) + s.PutCString(".apple_objc index present\n"); + // TODO: Dump index contents +} diff --git a/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h b/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h new file mode 100644 index 000000000000..ea133d0e73cf --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h @@ -0,0 +1,64 @@ +//===-- AppleDWARFIndex.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_APPLEDWARFINDEX_H +#define LLDB_APPLEDWARFINDEX_H + +#include "Plugins/SymbolFile/DWARF/DWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/HashedNameToDIE.h" + +namespace lldb_private { +class AppleDWARFIndex : public DWARFIndex { +public: + static std::unique_ptr<AppleDWARFIndex> + Create(Module &module, DWARFDataExtractor apple_names, + DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types, + DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str); + + AppleDWARFIndex( + Module &module, std::unique_ptr<DWARFMappedHash::MemoryTable> apple_names, + std::unique_ptr<DWARFMappedHash::MemoryTable> apple_namespaces, + std::unique_ptr<DWARFMappedHash::MemoryTable> apple_types, + std::unique_ptr<DWARFMappedHash::MemoryTable> apple_objc) + : DWARFIndex(module), m_apple_names_up(std::move(apple_names)), + m_apple_namespaces_up(std::move(apple_namespaces)), + m_apple_types_up(std::move(apple_types)), + m_apple_objc_up(std::move(apple_objc)) {} + + void Preload() override {} + + void GetGlobalVariables(ConstString basename, DIEArray &offsets) override; + void GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) override; + void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) override; + void GetObjCMethods(ConstString class_name, DIEArray &offsets) override; + void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, + DIEArray &offsets) override; + void GetTypes(ConstString name, DIEArray &offsets) override; + void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override; + void GetNamespaces(ConstString name, DIEArray &offsets) override; + void GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) override; + void GetFunctions(const RegularExpression ®ex, DIEArray &offsets) override; + + void ReportInvalidDIEOffset(dw_offset_t offset, + llvm::StringRef name) override; + void Dump(Stream &s) override; + +private: + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_names_up; + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_namespaces_up; + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_types_up; + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_objc_up; +}; +} // namespace lldb_private + +#endif // LLDB_APPLEDWARFINDEX_H diff --git a/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/source/Plugins/SymbolFile/DWARF/CMakeLists.txt index 05d9e6642868..f62a496f808a 100644 --- a/source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ b/source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -1,4 +1,6 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN + AppleDWARFIndex.cpp + DebugNamesDWARFIndex.cpp DIERef.cpp DWARFAbbreviationDeclaration.cpp DWARFASTParserClang.cpp @@ -6,6 +8,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN DWARFASTParserJava.cpp DWARFASTParserOCaml.cpp DWARFAttribute.cpp + DWARFBaseDIE.cpp DWARFCompileUnit.cpp DWARFDataExtractor.cpp DWARFDebugAbbrev.cpp @@ -17,16 +20,17 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN DWARFDebugMacro.cpp DWARFDebugMacinfo.cpp DWARFDebugMacinfoEntry.cpp - DWARFDebugPubnames.cpp - DWARFDebugPubnamesSet.cpp DWARFDebugRanges.cpp DWARFDeclContext.cpp DWARFDefines.cpp DWARFDIE.cpp DWARFDIECollection.cpp DWARFFormValue.cpp + DWARFIndex.cpp + DWARFUnit.cpp HashedNameToDIE.cpp LogChannelDWARF.cpp + ManualDWARFIndex.cpp NameToDIE.cpp SymbolFileDWARF.cpp SymbolFileDWARFDwo.cpp diff --git a/source/Plugins/SymbolFile/DWARF/DIERef.cpp b/source/Plugins/SymbolFile/DWARF/DIERef.cpp index c05444c031e6..0cd0f0c0272a 100644 --- a/source/Plugins/SymbolFile/DWARF/DIERef.cpp +++ b/source/Plugins/SymbolFile/DWARF/DIERef.cpp @@ -8,17 +8,12 @@ //===----------------------------------------------------------------------===// #include "DIERef.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfo.h" #include "DWARFFormValue.h" #include "SymbolFileDWARF.h" #include "SymbolFileDWARFDebugMap.h" -DIERef::DIERef() - : cu_offset(DW_INVALID_OFFSET), die_offset(DW_INVALID_OFFSET) {} - -DIERef::DIERef(dw_offset_t c, dw_offset_t d) : cu_offset(c), die_offset(d) {} - DIERef::DIERef(lldb::user_id_t uid, SymbolFileDWARF *dwarf) : cu_offset(DW_INVALID_OFFSET), die_offset(uid & 0xffffffff) { SymbolFileDWARFDebugMap *debug_map = dwarf->GetDebugMapSymfile(); @@ -28,7 +23,7 @@ DIERef::DIERef(lldb::user_id_t uid, SymbolFileDWARF *dwarf) if (actual_dwarf) { DWARFDebugInfo *debug_info = actual_dwarf->DebugInfo(); if (debug_info) { - DWARFCompileUnit *dwarf_cu = + DWARFUnit *dwarf_cu = debug_info->GetCompileUnitContainingDIEOffset(die_offset); if (dwarf_cu) { cu_offset = dwarf_cu->GetOffset(); @@ -45,7 +40,7 @@ DIERef::DIERef(lldb::user_id_t uid, SymbolFileDWARF *dwarf) DIERef::DIERef(const DWARFFormValue &form_value) : cu_offset(DW_INVALID_OFFSET), die_offset(DW_INVALID_OFFSET) { if (form_value.IsValid()) { - const DWARFCompileUnit *dwarf_cu = form_value.GetCompileUnit(); + const DWARFUnit *dwarf_cu = form_value.GetCompileUnit(); if (dwarf_cu) { if (dwarf_cu->GetBaseObjOffset() != DW_INVALID_OFFSET) cu_offset = dwarf_cu->GetBaseObjOffset(); diff --git a/source/Plugins/SymbolFile/DWARF/DIERef.h b/source/Plugins/SymbolFile/DWARF/DIERef.h index d0048d0f6d6b..cb28c890c25a 100644 --- a/source/Plugins/SymbolFile/DWARF/DIERef.h +++ b/source/Plugins/SymbolFile/DWARF/DIERef.h @@ -17,9 +17,9 @@ class DWARFFormValue; class SymbolFileDWARF; struct DIERef { - DIERef(); + DIERef() = default; - DIERef(dw_offset_t c, dw_offset_t d); + DIERef(dw_offset_t c, dw_offset_t d) : cu_offset(c), die_offset(d) {} //---------------------------------------------------------------------- // In order to properly decode a lldb::user_id_t back into a DIERef we @@ -45,8 +45,12 @@ struct DIERef { bool operator<(const DIERef &ref) { return die_offset < ref.die_offset; } - dw_offset_t cu_offset; - dw_offset_t die_offset; + explicit operator bool() const { + return cu_offset != DW_INVALID_OFFSET || die_offset != DW_INVALID_OFFSET; + } + + dw_offset_t cu_offset = DW_INVALID_OFFSET; + dw_offset_t die_offset = DW_INVALID_OFFSET; }; typedef std::vector<DIERef> DIEArray; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 54b12cfb3b8c..fe6f1be3ca48 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -10,13 +10,13 @@ #include <stdlib.h> #include "DWARFASTParserClang.h" -#include "DWARFCompileUnit.h" #include "DWARFDIE.h" #include "DWARFDIECollection.h" #include "DWARFDebugInfo.h" #include "DWARFDeclContext.h" #include "DWARFDefines.h" #include "SymbolFileDWARF.h" +#include "SymbolFileDWARFDwo.h" #include "SymbolFileDWARFDebugMap.h" #include "UniqueDWARFASTType.h" @@ -24,7 +24,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Host/Host.h" -#include "lldb/Interpreter/Args.h" #include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Symbol/ClangExternalASTSourceCommon.h" #include "lldb/Symbol/ClangUtil.h" @@ -39,8 +38,10 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include <map> #include <vector> @@ -105,9 +106,9 @@ struct BitfieldInfo { bool NextBitfieldOffsetIsValid(const uint64_t next_bit_offset) const { if (IsValid()) { - // This bitfield info is valid, so any subsequent bitfields - // must not overlap and must be at a higher bit offset than - // any previous bitfield + size. + // This bitfield info is valid, so any subsequent bitfields must not + // overlap and must be at a higher bit offset than any previous bitfield + // + size. return (bit_size + bit_offset) <= next_bit_offset; } else { // If the this BitfieldInfo is not valid, then any offset isOK @@ -123,57 +124,108 @@ ClangASTImporter &DWARFASTParserClang::GetClangASTImporter() { return *m_clang_ast_importer_ap; } +/// Detect a forward declaration that is nested in a DW_TAG_module. +static bool isClangModuleFwdDecl(const DWARFDIE &Die) { + if (!Die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0)) + return false; + auto Parent = Die.GetParent(); + while (Parent.IsValid()) { + if (Parent.Tag() == DW_TAG_module) + return true; + Parent = Parent.GetParent(); + } + return false; +} + TypeSP DWARFASTParserClang::ParseTypeFromDWO(const DWARFDIE &die, Log *log) { ModuleSP dwo_module_sp = die.GetContainingDWOModule(); - if (dwo_module_sp) { - // This type comes from an external DWO module - std::vector<CompilerContext> dwo_context; - die.GetDWOContext(dwo_context); - TypeMap dwo_types; - if (dwo_module_sp->GetSymbolVendor()->FindTypes(dwo_context, true, - dwo_types)) { - const size_t num_dwo_types = dwo_types.GetSize(); - if (num_dwo_types == 1) { - // We found a real definition for this type elsewhere - // so lets use it and cache the fact that we found - // a complete type for this die - TypeSP dwo_type_sp = dwo_types.GetTypeAtIndex(0); - if (dwo_type_sp) { - lldb_private::CompilerType dwo_type = - dwo_type_sp->GetForwardCompilerType(); - - lldb_private::CompilerType type = - GetClangASTImporter().CopyType(m_ast, dwo_type); - - // printf ("copied_qual_type: ast = %p, clang_type = %p, name = - // '%s'\n", m_ast, copied_qual_type.getAsOpaquePtr(), - // external_type->GetName().GetCString()); - if (type) { - SymbolFileDWARF *dwarf = die.GetDWARF(); - TypeSP type_sp(new Type(die.GetID(), dwarf, dwo_type_sp->GetName(), - dwo_type_sp->GetByteSize(), NULL, - LLDB_INVALID_UID, Type::eEncodingInvalid, - &dwo_type_sp->GetDeclaration(), type, - Type::eResolveStateForward)); - - dwarf->GetTypeList()->Insert(type_sp); - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - clang::TagDecl *tag_decl = ClangASTContext::GetAsTagDecl(type); - if (tag_decl) - LinkDeclContextToDIE(tag_decl, die); - else { - clang::DeclContext *defn_decl_ctx = - GetCachedClangDeclContextForDIE(die); - if (defn_decl_ctx) - LinkDeclContextToDIE(defn_decl_ctx, die); - } - return type_sp; - } - } - } + if (!dwo_module_sp) + return TypeSP(); + + // This type comes from an external DWO module. + std::vector<CompilerContext> dwo_context; + die.GetDWOContext(dwo_context); + TypeMap dwo_types; + + if (!dwo_module_sp->GetSymbolVendor()->FindTypes(dwo_context, true, + dwo_types)) { + 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) + continue; + SymbolVendor *SymVendor = NameModule.second->GetSymbolVendor(); + if (SymVendor->FindTypes(dwo_context, true, dwo_types)) + break; } } - return TypeSP(); + + const size_t num_dwo_types = dwo_types.GetSize(); + if (num_dwo_types != 1) + return TypeSP(); + + // We found a real definition for this type in the Clang module, so lets use + // it and cache the fact that we found a complete type for this die. + TypeSP dwo_type_sp = dwo_types.GetTypeAtIndex(0); + if (!dwo_type_sp) + return TypeSP(); + + lldb_private::CompilerType dwo_type = dwo_type_sp->GetForwardCompilerType(); + + lldb_private::CompilerType type = + GetClangASTImporter().CopyType(m_ast, dwo_type); + + if (!type) + return TypeSP(); + + SymbolFileDWARF *dwarf = die.GetDWARF(); + TypeSP type_sp(new Type( + die.GetID(), dwarf, dwo_type_sp->GetName(), dwo_type_sp->GetByteSize(), + NULL, LLDB_INVALID_UID, Type::eEncodingInvalid, + &dwo_type_sp->GetDeclaration(), type, Type::eResolveStateForward)); + + dwarf->GetTypeList()->Insert(type_sp); + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + clang::TagDecl *tag_decl = ClangASTContext::GetAsTagDecl(type); + if (tag_decl) + LinkDeclContextToDIE(tag_decl, die); + else { + clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE(die); + if (defn_decl_ctx) + LinkDeclContextToDIE(defn_decl_ctx, die); + } + + return type_sp; +} + +static void CompleteExternalTagDeclType(ClangASTImporter &ast_importer, + clang::DeclContext *decl_ctx, + DWARFDIE die, + const char *type_name_cstr) { + auto *tag_decl_ctx = clang::dyn_cast<clang::TagDecl>(decl_ctx); + if (!tag_decl_ctx) + return; + + // If this type was not imported from an external AST, there's nothing to do. + CompilerType type = ClangASTContext::GetTypeForDecl(tag_decl_ctx); + if (!type || !ast_importer.CanImport(type)) + return; + + auto qual_type = ClangUtil::GetQualType(type); + if (!ast_importer.RequireCompleteType(qual_type)) { + die.GetDWARF()->GetObjectFile()->GetModule()->ReportError( + "Unable to complete the Decl context for DIE '%s' at offset " + "0x%8.8x.\nPlease file a bug report.", + type_name_cstr ? type_name_cstr : "", die.GetOffset()); + // We need to make the type look complete otherwise, we might crash in + // Clang when adding children. + if (ClangASTContext::StartTagDeclarationDefinition(type)) + ClangASTContext::CompleteTagDeclarationDefinition(type); + } } TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, @@ -198,17 +250,6 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, die.GetOffset(), static_cast<void *>(context), context_die.GetOffset(), die.GetTagAsCString(), die.GetName()); } - // - // Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); - // if (log && dwarf_cu) - // { - // StreamString s; - // die->DumpLocation (this, dwarf_cu, s); - // dwarf->GetObjectFile()->GetModule()->LogMessage (log, - // "SymbolFileDwarf::%s %s", __FUNCTION__, s.GetData()); - // - // } - Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); TypeList *type_list = dwarf->GetTypeList(); if (type_ptr == NULL) { @@ -220,6 +261,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, bool is_forward_declaration = false; DWARFAttributes attributes; const char *type_name_cstr = NULL; + const char *mangled_name_cstr = NULL; ConstString type_name_const_str; Type::ResolveState resolve_state = Type::eResolveStateUnresolved; uint64_t byte_size = 0; @@ -268,8 +310,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, 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 "&"... + // reference type which doesn't include the "&"... if (tag == DW_TAG_reference_type) { if (strchr(type_name_cstr, '&') == NULL) type_name_cstr = NULL; @@ -295,32 +336,32 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } if (tag == DW_TAG_typedef && encoding_uid.IsValid()) { - // Try to parse a typedef from the DWO file first as modules - // can contain typedef'ed structures that have no names like: + // Try to parse a typedef from the DWO file first as modules can + // contain typedef'ed structures that have no names like: // // typedef struct { int a; } Foo; // - // In this case we will have a structure with no name and a - // typedef named "Foo" that points to this unnamed structure. - // The name in the typedef is the only identifier for the struct, - // so always try to get typedefs from DWO files if possible. + // In this case we will have a structure with no name and a typedef + // named "Foo" that points to this unnamed structure. The name in the + // typedef is the only identifier for the struct, so always try to + // get typedefs from DWO files if possible. // - // The type_sp returned will be empty if the typedef doesn't exist - // in a DWO file, so it is cheap to call this function just to check. + // The type_sp returned will be empty if the typedef doesn't exist in + // a DWO file, so it is cheap to call this function just to check. // - // If we don't do this we end up creating a TypeSP that says this - // is a typedef to type 0x123 (the DW_AT_type value would be 0x123 - // in the DW_TAG_typedef), and this is the unnamed structure type. - // We will have a hard time tracking down an unnammed structure - // type in the module DWO file, so we make sure we don't get into - // this situation by always resolving typedefs from the DWO file. + // If we don't do this we end up creating a TypeSP that says this is + // a typedef to type 0x123 (the DW_AT_type value would be 0x123 in + // the DW_TAG_typedef), and this is the unnamed structure type. We + // will have a hard time tracking down an unnammed structure type in + // the module DWO file, so we make sure we don't get into this + // situation by always resolving typedefs from the DWO file. const DWARFDIE encoding_die = dwarf->GetDIE(DIERef(encoding_uid)); - // First make sure that the die that this is typedef'ed to _is_ - // just a declaration (DW_AT_declaration == 1), not a full definition + // First make sure that the die that this is typedef'ed to _is_ just + // a declaration (DW_AT_declaration == 1), not a full definition // since template types can't be represented in modules since only - // concrete instances of templates are ever emitted and modules - // won't contain those + // concrete instances of templates are ever emitted and modules won't + // contain those if (encoding_die && encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) { @@ -433,7 +474,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective C 'id' built-in type.", + "is Objective-C 'id' built-in type.", die.GetOffset(), die.GetTagAsCString(), die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCID); encoding_data_type = Type::eEncodingIsUID; @@ -444,7 +485,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective C 'Class' built-in type.", + "is Objective-C 'Class' built-in type.", die.GetOffset(), die.GetTagAsCString(), die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCClass); encoding_data_type = Type::eEncodingIsUID; @@ -454,7 +495,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective C 'selector' built-in type.", + "is Objective-C 'selector' built-in type.", die.GetOffset(), die.GetTagAsCString(), die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCSel); encoding_data_type = Type::eEncodingIsUID; @@ -495,17 +536,6 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, &decl, clang_type, resolve_state)); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - - // Type* encoding_type = - // GetUniquedTypeForDIEOffset(encoding_uid, type_sp, - // NULL, 0, 0, false); - // if (encoding_type != NULL) - // { - // if (encoding_type != DIE_IS_BEING_PARSED) - // type_sp->SetEncodingType(encoding_type); - // else - // m_indirect_fixups.push_back(type_sp.get()); - // } } break; case DW_TAG_structure_type: @@ -517,7 +547,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, LanguageType class_language = eLanguageTypeUnknown; bool is_complete_objc_class = false; - // bool struct_is_class = false; + size_t calling_convention + = llvm::dwarf::CallingConvention::DW_CC_normal; + const size_t num_attributes = die.GetAttributes(attributes); if (num_attributes > 0) { uint32_t i; @@ -528,10 +560,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, 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. + // 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( @@ -572,7 +603,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, case DW_AT_APPLE_objc_complete_type: is_complete_objc_class = form_value.Signed(); break; - + case DW_AT_calling_convention: + calling_convention = form_value.Unsigned(); + break; + case DW_AT_allocated: case DW_AT_associated: case DW_AT_data_location: @@ -587,10 +621,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } } - // 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. + // 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()); @@ -601,10 +635,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, LanguageType die_language = die.GetLanguage(); if (Language::LanguageIsCPlusPlus(die_language)) { // For C++, we rely solely upon the one definition rule that says - // only - // one thing can exist at a given decl context. We ignore the file - // and - // line that things are declared on. + // only one thing can exist at a given decl context. We ignore the + // file and line that things are declared on. std::string qualified_name; if (die.GetQualifiedName(qualified_name)) unique_typename = ConstString(qualified_name); @@ -641,17 +673,16 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (byte_size_valid && byte_size == 0 && type_name_cstr && die.HasChildren() == false && sc.comp_unit->GetLanguage() == eLanguageTypeObjC) { - // Work around an issue with clang at the moment where - // forward declarations for objective C classes are emitted - // as: + // Work around an issue with clang at the moment where forward + // declarations for objective C classes are emitted as: // DW_TAG_structure_type [2] // DW_AT_name( "ForwardObjcClass" ) // DW_AT_byte_size( 0x00 ) // DW_AT_decl_file( "..." ) // DW_AT_decl_line( 1 ) // - // Note that there is no DW_AT_declaration and there are - // no children, and the byte size is zero. + // Note that there is no DW_AT_declaration and there are no children, + // and the byte size is zero. is_forward_declaration = true; } @@ -659,11 +690,11 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, class_language == eLanguageTypeObjC_plus_plus) { if (!is_complete_objc_class && die.Supports_DW_AT_APPLE_objc_complete_type()) { - // We have a valid eSymbolTypeObjCClass class symbol whose - // name matches the current objective C class that we - // are trying to find and this DIE isn't the complete - // definition (we checked is_complete_objc_class above and - // know it is false), so the real definition is in here somewhere + // We have a valid eSymbolTypeObjCClass class symbol whose name + // matches the current objective C class that we are trying to find + // and this DIE isn't the complete definition (we checked + // is_complete_objc_class above and know it is false), so the real + // definition is in here somewhere type_sp = dwarf->FindCompleteObjCDefinitionTypeForDIE( die, type_name_const_str, true); @@ -671,9 +702,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile(); if (debug_map_symfile) { - // We weren't able to find a full declaration in - // this DWARF, see if we have a declaration anywhere - // else... + // We weren't able to find a full declaration in this DWARF, + // see if we have a declaration anywhere else... type_sp = debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE( die, type_name_const_str, true); @@ -690,9 +720,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, type_sp->GetID()); } - // We found a real definition for this type elsewhere - // so lets use it and cache the fact that we found - // a complete type for this die + // We found a real definition for this type elsewhere so lets use + // it and cache the fact that we found a complete type for this + // die dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); return type_sp; } @@ -700,11 +730,11 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } if (is_forward_declaration) { - // We have a forward declaration to a type and we need - // to try and find a full declaration. We look in the - // current type index just in case we have a forward - // declaration followed by an actual declarations in the - // DWARF. If this fails, we need to look elsewhere... + // We have a forward declaration to a type and we need to try and + // find a full declaration. We look in the current type index just in + // case we have a forward declaration followed by an actual + // declarations in the DWARF. If this fails, we need to look + // elsewhere... if (log) { dwarf->GetObjectFile()->GetModule()->LogMessage( log, "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a " @@ -730,9 +760,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile(); if (debug_map_symfile) { - // We weren't able to find a full declaration in - // this DWARF, see if we have a declaration anywhere - // else... + // We weren't able to find a full declaration in this DWARF, see + // if we have a declaration anywhere else... type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext( die_decl_ctx); @@ -748,9 +777,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, DW_TAG_value_to_name(tag), type_name_cstr, type_sp->GetID()); } - // We found a real definition for this type elsewhere - // so lets use it and cache the fact that we found - // a complete type for this die + // We found a real definition for this type elsewhere so lets use + // it and cache the fact that we found a complete type for this die dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE( dwarf->DebugInfo()->GetDIE(DIERef(type_sp->GetID(), dwarf))); @@ -766,9 +794,18 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (!clang_type) { clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); + + // If your decl context is a record that was imported from another + // AST context (in the gmodules case), we need to make sure the type + // backing the Decl is complete before adding children to it. This is + // not an issue in the non-gmodules case because the debug info will + // always contain a full definition of parent types in that case. + CompleteExternalTagDeclType(GetClangASTImporter(), decl_ctx, die, + type_name_cstr); + if (accessibility == eAccessNone && decl_ctx) { - // Check the decl context that contains this class/struct/union. - // If it is a class we must give it an accessibility. + // Check the decl context that contains this class/struct/union. If + // it is a class we must give it an accessibility. const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind(); if (DeclKindIsCXXClass(containing_decl_kind)) @@ -818,10 +855,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, class_language, &metadata); } } - + // Store a forward declaration to this class type in case any - // parameters in any class methods need it for the clang - // types for function prototypes. + // parameters in any class methods need it for the clang types for + // function prototypes. LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die); type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, byte_size, NULL, LLDB_INVALID_UID, @@ -830,9 +867,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, type_sp->SetIsCompleteObjCClass(is_complete_objc_class); - // Add our type to the unique type map so we don't - // end up creating many copies of the same type over - // and over in the ASTContext for our module + // 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 = unique_decl; @@ -844,8 +881,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, // Check to see if the DIE actually has a definition, some version of // GCC will // emit DIEs with DW_AT_declaration set to true, but yet still have - // subprogram, - // members, or inheritance, so we can't trust it + // subprogram, members, or inheritance, so we can't trust it DWARFDIE child_die = die.GetFirstChild(); while (child_die) { switch (child_die.Tag()) { @@ -869,10 +905,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } 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. + // 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 if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { @@ -896,33 +932,30 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } } } else if (clang_type_was_created) { - // Start the definition if the class is not objective C since - // the underlying decls respond to isCompleteDefinition(). Objective + // Start the definition if the class is not objective C since the + // underlying decls respond to isCompleteDefinition(). Objective // C decls don't respond to isCompleteDefinition() so we can't // start the declaration definition right away. For C++ - // class/union/structs - // we want to start the definition in case the class is needed as - // the - // declaration context for a contained class or type without the - // need - // to complete that type.. + // class/union/structs we want to start the definition in case the + // class is needed as the declaration context for a contained class + // or type without the need to complete that type.. if (class_language != eLanguageTypeObjC && class_language != eLanguageTypeObjC_plus_plus) ClangASTContext::StartTagDeclarationDefinition(clang_type); - // Leave this as a forward declaration until we need - // to know the details of the type. lldb_private::Type - // will automatically call the SymbolFile virtual function - // "SymbolFileDWARF::CompleteType(Type *)" - // When the definition needs to be defined. + // 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. assert(!dwarf->GetForwardDeclClangTypeToDie().count( ClangUtil::RemoveFastQualifiers(clang_type) .GetOpaqueQualType()) && "Type already in the forward declaration map!"); - // Can't assume m_ast.GetSymbolFile() is actually a SymbolFileDWARF, - // it can be a - // SymbolFileDWARFDebugMap for Apple binaries. + // Can't assume m_ast.GetSymbolFile() is actually a + // SymbolFileDWARF, it can be a SymbolFileDWARFDebugMap for Apple + // binaries. dwarf->GetForwardDeclDieToClangType()[die.GetDIE()] = clang_type.GetOpaqueQualType(); dwarf->GetForwardDeclClangTypeToDie() @@ -931,6 +964,19 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); } } + + // If we made a clang type, set the trivial abi if applicable: We only + // do this for pass by value - which implies the Trivial ABI. There + // isn't a way to assert that something that would normally be pass by + // value is pass by reference, so we ignore that attribute if set. + if (calling_convention == llvm::dwarf::DW_CC_pass_by_value) { + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + if (record_decl) { + record_decl->setHasTrivialSpecialMemberForCall(); + } + } + } break; case DW_TAG_enumeration_type: { @@ -1008,9 +1054,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile(); if (debug_map_symfile) { - // We weren't able to find a full declaration in - // this DWARF, see if we have a declaration anywhere - // else... + // We weren't able to find a full declaration in this DWARF, + // see if we have a declaration anywhere else... type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext( die_decl_ctx); @@ -1027,9 +1072,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, type_sp->GetID()); } - // We found a real definition for this type elsewhere - // so lets use it and cache the fact that we found - // a complete type for this die + // We found a real definition for this type elsewhere so lets use + // it and cache the fact that we found a complete type for this + // die dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE(dwarf->DebugInfo()->GetDIE( @@ -1145,9 +1190,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, case DW_AT_linkage_name: case DW_AT_MIPS_linkage_name: - break; // mangled = - // form_value.AsCString(&dwarf->get_debug_str_data()); - // break; + mangled_name_cstr = form_value.AsCString(); + break; case DW_AT_type: type_die_form = form_value; break; @@ -1256,8 +1300,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, bool is_cxx_method = DeclKindIsCXXClass(containing_decl_kind); // Start off static. This will be set to false in - // ParseChildParameters(...) - // if we find a "this" parameters as the first parameter + // ParseChildParameters(...) if we find a "this" parameters as the + // first parameter if (is_cxx_method) { is_static = true; } @@ -1272,25 +1316,22 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, bool ignore_containing_context = false; // Check for templatized class member functions. If we had any - // DW_TAG_template_type_parameter - // or DW_TAG_template_value_parameter the DW_TAG_subprogram DIE, then we - // can't let this become - // a method in a class. Why? Because templatized functions are only - // emitted if one of the - // templatized methods is used in the current compile unit and we will - // end up with classes - // that may or may not include these member functions and this means one - // class won't match another - // class definition and it affects our ability to use a class in the - // clang expression parser. So - // for the greater good, we currently must not allow any template member - // functions in a class definition. + // DW_TAG_template_type_parameter or DW_TAG_template_value_parameter + // the DW_TAG_subprogram DIE, then we can't let this become a method in + // a class. Why? Because templatized functions are only emitted if one + // of the templatized methods is used in the current compile unit and + // we will end up with classes that may or may not include these member + // functions and this means one class won't match another class + // definition and it affects our ability to use a class in the clang + // expression parser. So for the greater good, we currently must not + // allow any template member functions in a class definition. if (is_cxx_method && has_template_params) { ignore_containing_context = true; is_cxx_method = false; } - // clang_type will get the function prototype clang type after this call + // clang_type will get the function prototype clang type after this + // call clang_type = m_ast.CreateFunctionType( return_clang_type, function_param_types.data(), function_param_types.size(), is_variadic, type_quals); @@ -1318,8 +1359,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (class_opaque_type) { // If accessibility isn't set to anything valid, assume public - // for - // now... + // for now... if (accessibility == eAccessNone) accessibility = eAccessPublic; @@ -1341,9 +1381,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } } } else if (is_cxx_method) { - // Look at the parent of this DIE and see if is is - // a class or struct and see if this is actually a - // C++ method + // Look at the parent of this DIE and see if is is a class or + // struct and see if this is actually a C++ method Type *class_type = dwarf->ResolveType(decl_ctx_die); if (class_type) { bool alternate_defn = false; @@ -1352,10 +1391,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, alternate_defn = true; // We uniqued the parent class of this function to another - // class - // so we now need to associate all dies under "decl_ctx_die" - // to - // DIEs in the DIE for "class_type"... + // class so we now need to associate all dies under + // "decl_ctx_die" to DIEs in the DIE for "class_type"... SymbolFileDWARF *class_symfile = NULL; DWARFDIE class_type_die; @@ -1381,10 +1418,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, // FIXME do something with these failures that's smarter // than // just dropping them on the ground. Unfortunately classes - // don't - // like having stuff added to them after their definitions - // are - // complete... + // don't like having stuff added to them after their + // definitions are complete... type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { @@ -1396,16 +1431,13 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (specification_die_form.IsValid()) { // We have a specification which we are going to base our - // function - // prototype off of, so we need this type to be completed so - // that the - // m_die_to_decl_ctx for the method in the specification has a - // valid - // clang decl context. + // function prototype off of, so we need this type to be + // completed so that the m_die_to_decl_ctx for the method in + // the specification has a valid clang decl context. class_type->GetForwardCompilerType(); // If we have a specification, then the function type should - // have been - // made with the specification and not with this die. + // have been made with the specification and not with this + // die. DWARFDIE spec_die = dwarf->DebugInfo()->GetDIE( DIERef(specification_die_form)); clang::DeclContext *spec_clang_decl_ctx = @@ -1421,12 +1453,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, type_handled = true; } else if (abstract_origin_die_form.IsValid()) { // We have a specification which we are going to base our - // function - // prototype off of, so we need this type to be completed so - // that the - // m_die_to_decl_ctx for the method in the abstract origin has - // a valid - // clang decl context. + // function prototype off of, so we need this type to be + // completed so that the m_die_to_decl_ctx for the method in + // the abstract origin has a valid clang decl context. class_type->GetForwardCompilerType(); DWARFDIE abs_die = dwarf->DebugInfo()->GetDIE( @@ -1449,17 +1478,16 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (class_opaque_type.IsBeingDefined() || alternate_defn) { if (!is_static && !die.HasChildren()) { // We have a C++ member function with no children (this - // pointer!) - // and clang will get mad if we try and make a function - // that isn't - // well formed in the DWARF, so we will just skip it... + // pointer!) and clang will get mad if we try and make + // a function that isn't well formed in the DWARF, so + // we will just skip it... type_handled = true; } else { bool add_method = true; if (alternate_defn) { // If an alternate definition for the class exists, - // then add the method only if an - // equivalent is not already present. + // then add the method only if an equivalent is not + // already present. clang::CXXRecordDecl *record_decl = m_ast.GetAsCXXRecordDecl( class_opaque_type.GetOpaqueQualType()); @@ -1499,18 +1527,18 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, const bool is_attr_used = false; // Neither GCC 4.2 nor clang++ currently set a valid - // accessibility - // in the DWARF for C++ methods... Default to public - // for now... + // accessibility in the DWARF for C++ methods... + // Default to public for now... if (accessibility == eAccessNone) accessibility = eAccessPublic; clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType( class_opaque_type.GetOpaqueQualType(), - type_name_cstr, clang_type, accessibility, - is_virtual, is_static, is_inline, is_explicit, - is_attr_used, is_artificial); + type_name_cstr, mangled_name_cstr, clang_type, + accessibility, is_virtual, is_static, + is_inline, is_explicit, is_attr_used, + is_artificial); type_handled = cxx_method_decl != NULL; @@ -1541,25 +1569,21 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } } else { // We were asked to parse the type for a method in a - // class, yet the - // class hasn't been asked to complete itself through the - // clang::ExternalASTSource protocol, so we need to just - // have the - // class complete itself and do things the right way, then - // our + // class, yet the class hasn't been asked to complete + // itself through the clang::ExternalASTSource protocol, + // so we need to just have the class complete itself and + // do things the right way, then our // DIE should then have an entry in the // dwarf->GetDIEToType() map. First // we need to modify the dwarf->GetDIEToType() so it - // doesn't think we are - // trying to parse this DIE anymore... + // doesn't think we are trying to parse this DIE + // anymore... dwarf->GetDIEToType()[die.GetDIE()] = NULL; // Now we get the full type to force our class type to - // complete itself - // using the clang::ExternalASTSource protocol which will - // parse all - // base classes and all methods (including the method for - // this DIE). + // complete itself using the clang::ExternalASTSource + // protocol which will parse all base classes and all + // methods (including the method for this DIE). class_type->GetFullCompilerType(); // The type for this DIE should have been filled in the @@ -1573,8 +1597,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, // FIXME This is fixing some even uglier behavior but we // really need to // uniq the methods of each class as well as the class - // itself. - // <rdar://problem/11240464> + // itself. <rdar://problem/11240464> type_handled = true; } } @@ -1737,8 +1760,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, array_element_type.GetCompleteType() == false) { ModuleSP module_sp = die.GetModule(); if (module_sp) { - if (die.GetCU()->GetProducer() == - DWARFCompileUnit::eProducerClang) + if (die.GetCU()->GetProducer() == eProducerClang) module_sp->ReportError( "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " "class/union/struct element type DIE 0x%8.8x that is a " @@ -1760,11 +1782,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } // We have no choice other than to pretend that the element class - // type - // is complete. If we don't do this, clang will crash when trying - // to layout the class. Since we provide layout assistance, all - // ivars in this class and other classes will be fine, this is - // the best we can do short of crashing. + // type is complete. If we don't do this, clang will crash when + // trying to layout the class. Since we provide layout + // assistance, all ivars in this class and other classes will be + // fine, this is the best we can do short of crashing. if (ClangASTContext::StartTagDeclarationDefinition( array_element_type)) { ClangASTContext::CompleteTagDeclarationDefinition( @@ -1864,7 +1885,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, dw_tag_t sc_parent_tag = sc_parent_die.Tag(); SymbolContextScope *symbol_context_scope = NULL; - if (sc_parent_tag == DW_TAG_compile_unit) { + 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 = @@ -1956,6 +1978,7 @@ bool DWARFASTParserClang::ParseTemplateDIE( const DWARFDIE &die, ClangASTContext::TemplateParameterInfos &template_param_infos) { const dw_tag_t tag = die.Tag(); + bool is_template_template_argument = false; switch (tag) { case DW_TAG_GNU_template_parameter_pack: { @@ -1971,11 +1994,15 @@ bool DWARFASTParserClang::ParseTemplateDIE( } return true; } + case DW_TAG_GNU_template_template_param: + is_template_template_argument = true; + LLVM_FALLTHROUGH; case DW_TAG_template_type_parameter: case DW_TAG_template_value_parameter: { DWARFAttributes attributes; const size_t num_attributes = die.GetAttributes(attributes); const char *name = nullptr; + const char *template_name = nullptr; CompilerType clang_type; uint64_t uval64 = 0; bool uval64_valid = false; @@ -1990,6 +2017,11 @@ bool DWARFASTParserClang::ParseTemplateDIE( name = form_value.AsCString(); break; + case DW_AT_GNU_template_name: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + template_name = form_value.AsCString(); + break; + case DW_AT_type: if (attributes.ExtractFormValueAtIndex(i, form_value)) { Type *lldb_type = die.ResolveTypeUID(DIERef(form_value)); @@ -2013,7 +2045,7 @@ bool DWARFASTParserClang::ParseTemplateDIE( if (!clang_type) clang_type = m_ast.GetBasicType(eBasicTypeVoid); - if (clang_type) { + if (!is_template_template_argument) { bool is_signed = false; if (name && name[0]) template_param_infos.names.push_back(name); @@ -2033,7 +2065,10 @@ bool DWARFASTParserClang::ParseTemplateDIE( clang::TemplateArgument(ClangUtil::GetQualType(clang_type))); } } else { - return false; + auto *tplt_type = m_ast.CreateTemplateTemplateParmDecl(template_name); + template_param_infos.names.push_back(name); + template_param_infos.args.push_back( + clang::TemplateArgument(clang::TemplateName(tplt_type))); } } } @@ -2052,7 +2087,6 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( if (!parent_die) return false; - Args template_parameter_names; for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) { const dw_tag_t tag = die.Tag(); @@ -2061,6 +2095,7 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( case DW_TAG_template_type_parameter: case DW_TAG_template_value_parameter: case DW_TAG_GNU_template_parameter_pack: + case DW_TAG_GNU_template_template_param: ParseTemplateDIE(die, template_param_infos); break; @@ -2073,6 +2108,95 @@ 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) { @@ -2090,10 +2214,10 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, #if defined LLDB_CONFIGURATION_DEBUG //---------------------------------------------------------------------- - // For debugging purposes, the LLDB_DWARF_DONT_COMPLETE_TYPENAMES - // environment variable can be set with one or more typenames separated - // by ';' characters. This will cause this function to not complete any - // types whose names match. + // For debugging purposes, the LLDB_DWARF_DONT_COMPLETE_TYPENAMES environment + // variable can be set with one or more typenames separated by ';' + // characters. This will cause this function to not complete any types whose + // names match. // // Examples of setting this environment variable: // @@ -2144,8 +2268,8 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, LanguageType class_language = eLanguageTypeUnknown; if (ClangASTContext::IsObjCObjectOrInterfaceType(clang_type)) { class_language = eLanguageTypeObjC; - // For objective C we don't start the definition when - // the class is created. + // For objective C we don't start the definition when the class is + // created. ClangASTContext::StartTagDeclarationDefinition(clang_type); } @@ -2217,29 +2341,27 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, clang::TTK_Class); } - // Since DW_TAG_structure_type gets used for both classes - // and structures, we may need to set any DW_TAG_member - // fields to have a "private" access if none was specified. - // When we parsed the child members we tracked that actual - // accessibility value for each DW_TAG_member in the - // "member_accessibilities" array. If the value for the - // member is zero, then it was set to the "default_accessibility" - // which for structs was "public". Below we correct this - // by setting any fields to "private" that weren't correctly - // set. + // Since DW_TAG_structure_type gets used for both classes and + // structures, we may need to set any DW_TAG_member fields to have a + // "private" access if none was specified. When we parsed the child + // members we tracked that actual accessibility value for each + // DW_TAG_member in the "member_accessibilities" array. If the value + // for the member is zero, then it was set to the + // "default_accessibility" which for structs was "public". Below we + // correct this by setting any fields to "private" that weren't + // correctly set. if (is_a_class && !member_accessibilities.empty()) { - // This is a class and all members that didn't have - // their access specified are private. + // This is a class and all members that didn't have their access + // specified are private. m_ast.SetDefaultAccessForRecordFields( m_ast.GetAsRecordDecl(clang_type), eAccessPrivate, &member_accessibilities.front(), member_accessibilities.size()); } if (!base_classes.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() + // 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) { clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo(); @@ -2252,19 +2374,17 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, "does not have a complete definition.", die.GetName(), base_class_type.GetTypeName().GetCString()); - if (die.GetCU()->GetProducer() == - DWARFCompileUnit::eProducerClang) + if (die.GetCU()->GetProducer() == eProducerClang) module->ReportError(":: Try compiling the source file with " "-fstandalone-debug."); // We have no choice other than to pretend that the base class // is complete. If we don't do this, clang will crash when we // call setBases() inside of - // "clang_type.SetBaseClassesForClassType()" - // 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. + // "clang_type.SetBaseClassesForClassType()" below. Since we + // provide layout assistance, all ivars in this class and other + // classes will be fine, this is the best we can do short of + // crashing. if (ClangASTContext::StartTagDeclarationDefinition( base_class_type)) { ClangASTContext::CompleteTagDeclarationDefinition( @@ -2277,14 +2397,15 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, &base_classes.front(), base_classes.size()); - // Clang will copy each CXXBaseSpecifier in "base_classes" - // so we have to free them all. + // Clang will copy each CXXBaseSpecifier in "base_classes" so we have + // to free them all. ClangASTContext::DeleteBaseClassSpecifiers(&base_classes.front(), base_classes.size()); } } } + addMethodOverrides(m_ast, clang_type); ClangASTContext::BuildIndirectFields(clang_type); ClangASTContext::CompleteTagDeclarationDefinition(clang_type); @@ -2582,14 +2703,13 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(const SymbolContext &sc, Mangled func_name; if (mangled) func_name.SetValue(ConstString(mangled), true); - else if (die.GetParent().Tag() == DW_TAG_compile_unit && + else if ((die.GetParent().Tag() == DW_TAG_compile_unit || + die.GetParent().Tag() == DW_TAG_partial_unit) && Language::LanguageIsCPlusPlus(die.GetLanguage()) && name && strcmp(name, "main") != 0) { // If the mangled name is not present in the DWARF, generate the - // demangled name - // using the decl context. We skip if the function is "main" as its name - // is - // never mangled. + // demangled name using the decl context. We skip if the function is + // "main" as its name is never mangled. bool is_static = false; bool is_variadic = false; bool has_template_params = false; @@ -2748,8 +2868,7 @@ bool DWARFASTParserClang::ParseChildMembers( if (form_value.BlockData()) { Value initialValue(0); Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = - die.GetDWARF()->get_debug_info_data(); + 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(); @@ -2763,8 +2882,8 @@ bool DWARFASTParserClang::ParseChildMembers( } } 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. + // this form value is the offset in bytes from the beginning of + // the containing entity. member_byte_offset = form_value.Unsigned(); } break; @@ -2806,8 +2925,8 @@ bool DWARFASTParserClang::ParseChildMembers( ConstString fixed_getter; ConstString fixed_setter; - // Check if the property getter/setter were provided as full - // names. We want basenames, so we extract them. + // Check if the property getter/setter were provided as full names. + // We want basenames, so we extract them. if (prop_getter_name && prop_getter_name[0] == '-') { ObjCLanguage::MethodName prop_getter_method(prop_getter_name, true); @@ -2819,8 +2938,7 @@ bool DWARFASTParserClang::ParseChildMembers( prop_setter_name = prop_setter_method.GetSelector().GetCString(); } - // If the names haven't been provided, they need to be - // filled in. + // If the names haven't been provided, they need to be filled in. if (!prop_getter_name) { prop_getter_name = prop_name; @@ -2836,19 +2954,18 @@ bool DWARFASTParserClang::ParseChildMembers( } } - // Clang has a DWARF generation bug where sometimes it - // represents fields that are references with bad byte size - // and bit size/offset information such as: + // Clang has a DWARF generation bug where sometimes it represents + // fields that are references with bad byte size and bit size/offset + // information such as: // // DW_AT_byte_size( 0x00 ) // DW_AT_bit_size( 0x40 ) // DW_AT_bit_offset( 0xffffffffffffffc0 ) // - // So check the bit offset to make sure it is sane, and if - // the values are not sane, remove them. If we don't do this - // then we will end up with a crash if we try to use this - // type in an expression when clang becomes unhappy with its - // recycled debug info. + // So check the bit offset to make sure it is sane, and if the values + // are not sane, remove them. If we don't do this then we will end up + // with a crash if we try to use this type in an expression when clang + // becomes unhappy with its recycled debug info. if (byte_size == 0 && bit_offset < 0) { bit_size = 0; @@ -2862,12 +2979,10 @@ bool DWARFASTParserClang::ParseChildMembers( 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. + // 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; } @@ -2907,15 +3022,15 @@ bool DWARFASTParserClang::ParseChildMembers( ///////////////////////////////////////////////////////////// // How to locate a field given the DWARF debug information // - // AT_byte_size indicates the size of the word in which the - // bit offset must be interpreted. + // AT_byte_size indicates the size of the word in which the bit + // offset must be interpreted. // // AT_data_member_location indicates the byte offset of the // word from the base address of the structure. // // AT_bit_offset indicates how many bits into the word - // (according to the host endianness) the low-order bit of - // the field starts. AT_bit_offset can be negative. + // (according to the host endianness) the low-order bit of the + // field starts. AT_bit_offset can be negative. // // AT_bit_size indicates the size of the field in bits. ///////////////////////////////////////////////////////////// @@ -2956,12 +3071,9 @@ bool DWARFASTParserClang::ParseChildMembers( field_bit_offset = this_field_info.bit_offset; // If the member to be emitted did not start on a character - // boundary and there is - // empty space between the last field and this one, then we need - // to emit an - // anonymous member filling up the space up to its start. There - // are three cases - // here: + // boundary and there is empty space between the last field and + // this one, then we need to emit an anonymous member filling + // up the space up to its start. There are three cases here: // // 1 If the previous member ended on a character boundary, then // we can emit an @@ -2986,10 +3098,8 @@ bool DWARFASTParserClang::ParseChildMembers( const uint64_t word_width = 32; // Objective-C has invalid DW_AT_bit_offset values in older - // versions - // of clang, so we have to be careful and only insert unnamed - // bitfields - // if we have a new enough clang. + // versions of clang, so we have to be careful and only insert + // unnamed bitfields if we have a new enough clang. bool detect_unnamed_bitfields = true; if (class_language == eLanguageTypeObjC || @@ -3052,10 +3162,10 @@ bool DWARFASTParserClang::ParseChildMembers( { // Older versions of clang emit array[0] and array[1] in the - // same way (<rdar://problem/12566646>). - // If the current field is at the end of the structure, then - // there is definitely no room for extra - // elements and we override the type to array[0]. + // same way (<rdar://problem/12566646>). If the current field + // is at the end of the structure, then there is definitely no + // room for extra elements and we override the type to + // array[0]. CompilerType member_array_element_type; uint64_t member_array_size; @@ -3089,8 +3199,7 @@ bool DWARFASTParserClang::ParseChildMembers( if (ClangASTContext::IsCXXClassType(member_clang_type) && member_clang_type.GetCompleteType() == false) { - if (die.GetCU()->GetProducer() == - DWARFCompileUnit::eProducerClang) + if (die.GetCU()->GetProducer() == eProducerClang) module_sp->ReportError( "DWARF DIE at 0x%8.8x (class %s) has a member variable " "0x%8.8x (%s) whose type is a forward declaration, not a " @@ -3108,12 +3217,11 @@ bool DWARFASTParserClang::ParseChildMembers( die.GetOffset(), name, sc.comp_unit ? sc.comp_unit->GetPath().c_str() : "the source file"); - // We have no choice other than to pretend that the member class - // is complete. If we don't do this, clang will crash when - // trying - // to layout the class. Since we provide layout assistance, all - // ivars in this class and other classes will be fine, this is - // the best we can do short of crashing. + // We have no choice other than to pretend that the member + // class is complete. If we don't do this, clang will crash + // when trying to layout the class. Since we provide layout + // assistance, all ivars in this class and other classes will + // be fine, this is the best we can do short of crashing. if (ClangASTContext::StartTagDeclarationDefinition( member_clang_type)) { ClangASTContext::CompleteTagDeclarationDefinition( @@ -3221,8 +3329,7 @@ bool DWARFASTParserClang::ParseChildMembers( if (form_value.BlockData()) { Value initialValue(0); Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = - die.GetDWARF()->get_debug_info_data(); + 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(); @@ -3235,8 +3342,8 @@ bool DWARFASTParserClang::ParseChildMembers( } } 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. + // this form value is the offset in bytes from the beginning of + // the containing entity. member_byte_offset = form_value.Unsigned(); } break; @@ -3282,18 +3389,16 @@ bool DWARFASTParserClang::ParseChildMembers( if (is_virtual) { // Do not specify any offset for virtual inheritance. The DWARF - // produced by clang doesn't - // give us a constant offset, but gives us a DWARF expressions that - // requires an actual object - // in memory. the DW_AT_data_member_location for a virtual base - // class looks like: + // produced by clang doesn't give us a constant offset, but gives + // us a DWARF expressions that requires an actual object in memory. + // the DW_AT_data_member_location for a virtual base class looks + // like: // DW_AT_data_member_location( DW_OP_dup, DW_OP_deref, // DW_OP_constu(0x00000018), DW_OP_minus, DW_OP_deref, // DW_OP_plus ) // Given this, there is really no valid response we can give to - // clang for virtual base - // class offsets, and this should eventually be removed from - // LayoutRecordType() in the external + // clang for virtual base class offsets, and this should eventually + // be removed from LayoutRecordType() in the external // AST source in clang. } else { layout_info.base_offsets.insert(std::make_pair( @@ -3365,22 +3470,6 @@ size_t DWARFASTParserClang::ParseChildParameters( is_artificial = form_value.Boolean(); 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; case DW_AT_const_value: case DW_AT_default_value: case DW_AT_description: @@ -3397,52 +3486,29 @@ size_t DWARFASTParserClang::ParseChildParameters( } bool skip = false; - if (skip_artificial) { - if (is_artificial) { - // In order to determine if a C++ member function is - // "const" we have to look at the const-ness of "this"... - // Ugly, but that - if (arg_idx == 0) { - if (DeclKindIsCXXClass(containing_decl_ctx->getDeclKind())) { - // Often times compilers omit the "this" name for the - // specification DIEs, so we can't rely upon the name - // being in the formal parameter DIE... - if (name == NULL || ::strcmp(name, "this") == 0) { - Type *this_type = - die.ResolveTypeUID(DIERef(param_type_die_form)); - if (this_type) { - uint32_t encoding_mask = this_type->GetEncodingMask(); - if (encoding_mask & Type::eEncodingIsPointerUID) { - is_static = false; - - if (encoding_mask & (1u << Type::eEncodingIsConstUID)) - type_quals |= clang::Qualifiers::Const; - if (encoding_mask & (1u << Type::eEncodingIsVolatileUID)) - type_quals |= clang::Qualifiers::Volatile; - } - } - } - } - } - skip = true; - } else { - - // HACK: Objective C formal parameters "self" and "_cmd" - // are not marked as artificial in the DWARF... - CompileUnit *comp_unit = die.GetLLDBCompileUnit(); - if (comp_unit) { - switch (comp_unit->GetLanguage()) { - case eLanguageTypeObjC: - case eLanguageTypeObjC_plus_plus: - if (name && name[0] && - (strcmp(name, "self") == 0 || strcmp(name, "_cmd") == 0)) - skip = true; - break; - default: - break; + if (skip_artificial && is_artificial) { + // In order to determine if a C++ member function is "const" we + // have to look at the const-ness of "this"... + if (arg_idx == 0 && + DeclKindIsCXXClass(containing_decl_ctx->getDeclKind()) && + // Often times compilers omit the "this" name for the + // specification DIEs, so we can't rely upon the name being in + // the formal parameter DIE... + (name == NULL || ::strcmp(name, "this") == 0)) { + Type *this_type = die.ResolveTypeUID(DIERef(param_type_die_form)); + if (this_type) { + uint32_t encoding_mask = this_type->GetEncodingMask(); + if (encoding_mask & Type::eEncodingIsPointerUID) { + is_static = false; + + if (encoding_mask & (1u << Type::eEncodingIsConstUID)) + type_quals |= clang::Qualifiers::Const; + if (encoding_mask & (1u << Type::eEncodingIsVolatileUID)) + type_quals |= clang::Qualifiers::Volatile; } } } + skip = true; } if (!skip) { @@ -3470,10 +3536,10 @@ size_t DWARFASTParserClang::ParseChildParameters( case DW_TAG_template_type_parameter: case DW_TAG_template_value_parameter: case DW_TAG_GNU_template_parameter_pack: - // The one caller of this was never using the template_param_infos, - // and the local variable was taking up a large amount of stack space - // in SymbolFileDWARF::ParseType() so this was removed. If we ever need - // the template params back, we can add them back. + // The one caller of this was never using the template_param_infos, and + // the local variable was taking up a large amount of stack space in + // SymbolFileDWARF::ParseType() so this was removed. If we ever need the + // template params back, we can add them back. // ParseTemplateDIE (dwarf_cu, die, template_param_infos); has_template_params = true; break; @@ -3692,6 +3758,7 @@ DWARFASTParserClang::GetClangDeclContextForDIE(const DWARFDIE &die) { bool try_parsing_type = true; switch (die.Tag()) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: decl_ctx = m_ast.GetTranslationUnitDecl(); try_parsing_type = false; break; @@ -4008,8 +4075,8 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( // Now do the work of linking the DeclContexts and Types. if (fast_path) { - // We can do this quickly. Just run across the tables index-for-index since - // we know each node has matching names and tags. + // We can do this quickly. Just run across the tables index-for-index + // since we know each node has matching names and tags. for (idx = 0; idx < src_size; ++idx) { src_die = src_name_to_die.GetValueAtIndexUnchecked(idx); dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx); @@ -4046,9 +4113,9 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( } } } else { - // We must do this slowly. For each member of the destination, look - // up a member in the source with the same name, check its tag, and - // unique them if everything matches up. Report failures. + // We must do this slowly. For each member of the destination, look up a + // member in the source with the same name, check its tag, and unique them + // if everything matches up. Report failures. if (!src_name_to_die.IsEmpty() && !dst_name_to_die.IsEmpty()) { src_name_to_die.Sort(); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp index e04dc76d1dbe..328212e4b684 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp @@ -10,7 +10,6 @@ #include "DWARFASTParserGo.h" #include "DWARFASTParserGo.h" -#include "DWARFCompileUnit.h" #include "DWARFDIE.h" #include "DWARFDIECollection.h" #include "DWARFDebugInfo.h" @@ -158,7 +157,8 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( 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. + // Go emits extra typedefs as a forward declaration. Ignore + // these. dwarf->m_die_to_type[die.GetDIE()] = type; return type->shared_from_this(); } @@ -213,10 +213,10 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( // 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. + // 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()); @@ -225,11 +225,10 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( 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. + // 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(); @@ -255,9 +254,9 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( 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 + // 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; @@ -266,19 +265,19 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( *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. + // 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. + // 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 @@ -432,7 +431,8 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( dw_tag_t sc_parent_tag = sc_parent_die.Tag(); SymbolContextScope *symbol_context_scope = NULL; - if (sc_parent_tag == DW_TAG_compile_unit) { + 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 = @@ -655,8 +655,7 @@ size_t DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, if (form_value.BlockData()) { Value initialValue(0); Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = - die.GetDWARF()->get_debug_info_data(); + 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(); @@ -670,8 +669,8 @@ size_t DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, } } 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. + // this form value is the offset in bytes from the beginning of + // the containing entity. member_byte_offset = form_value.Unsigned(); } break; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp index 8b5202ba265f..476394487985 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp @@ -9,7 +9,7 @@ #include "DWARFASTParserJava.h" #include "DWARFAttribute.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfoEntry.h" #include "DWARFDebugInfoEntry.h" #include "DWARFDeclContext.h" @@ -324,7 +324,8 @@ lldb::TypeSP DWARFASTParserJava::ParseTypeFromDWARF( dw_tag_t sc_parent_tag = sc_parent_die.Tag(); SymbolContextScope *symbol_context_scope = nullptr; - if (sc_parent_tag == DW_TAG_compile_unit) { + 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 = @@ -418,7 +419,7 @@ bool DWARFASTParserJava::CompleteTypeFromDWARF( void DWARFASTParserJava::ParseChildMembers(const DWARFDIE &parent_die, CompilerType &compiler_type) { - DWARFCompileUnit *dwarf_cu = parent_die.GetCU(); + DWARFUnit *dwarf_cu = parent_die.GetCU(); for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) { switch (die.Tag()) { diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp index 3b1466df21b0..3ef5c2eb8626 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp @@ -98,7 +98,8 @@ lldb::TypeSP DWARFASTParserOCaml::ParseTypeFromDWARF(const SymbolContext &sc, dw_tag_t sc_parent_tag = sc_parent_die.Tag(); SymbolContextScope *symbol_context_scope = nullptr; - if (sc_parent_tag == DW_TAG_compile_unit) { + 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 = diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h b/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h index e3b2279ca8fc..09cb5e14934f 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h @@ -4,7 +4,6 @@ #define SymbolFileDWARF_DWARFASTParserOCaml_h_ #include "DWARFASTParser.h" -#include "DWARFCompileUnit.h" #include "DWARFDIE.h" #include "DWARFDebugInfo.h" #include "DWARFDefines.h" diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp index bc49fc5de2cd..a765be0b46d0 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp @@ -10,6 +10,7 @@ #include "DWARFAbbreviationDeclaration.h" #include "lldb/Core/dwarf.h" +#include "lldb/Utility/Stream.h" #include "DWARFFormValue.h" diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h index 28e713f9beb1..b2296c455d6a 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h @@ -13,8 +13,6 @@ #include "DWARFAttribute.h" #include "SymbolFileDWARF.h" -class DWARFCompileUnit; - class DWARFAbbreviationDeclaration { public: enum { InvalidCode = 0 }; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp index d2573f3742ba..2586d1f18530 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "DWARFAttribute.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfo.h" DWARFAttributes::DWARFAttributes() : m_infos() {} @@ -26,7 +26,7 @@ uint32_t DWARFAttributes::FindAttributeIndex(dw_attr_t attr) const { return UINT32_MAX; } -void DWARFAttributes::Append(const DWARFCompileUnit *cu, +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}}; @@ -48,12 +48,11 @@ bool DWARFAttributes::RemoveAttribute(dw_attr_t attr) { bool DWARFAttributes::ExtractFormValueAtIndex( uint32_t i, DWARFFormValue &form_value) const { - const DWARFCompileUnit *cu = CompileUnitAtIndex(i); + const DWARFUnit *cu = CompileUnitAtIndex(i); form_value.SetCompileUnit(cu); form_value.SetForm(FormAtIndex(i)); lldb::offset_t offset = DIEOffsetAtIndex(i); - return form_value.ExtractValue( - cu->GetSymbolFileDWARF()->get_debug_info_data(), &offset); + return form_value.ExtractValue(cu->GetData(), &offset); } uint64_t DWARFAttributes::FormValueAsUnsigned(dw_attr_t attr, diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h index 317e710e6d94..db4324cf7725 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h @@ -14,7 +14,7 @@ #include "llvm/ADT/SmallVector.h" #include <vector> -class DWARFCompileUnit; +class DWARFUnit; class DWARFFormValue; class DWARFAttribute { @@ -50,9 +50,9 @@ public: DWARFAttributes(); ~DWARFAttributes(); - void Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, + void Append(const DWARFUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form); - const DWARFCompileUnit *CompileUnitAtIndex(uint32_t i) const { + const DWARFUnit *CompileUnitAtIndex(uint32_t i) const { return m_infos[i].cu; } dw_offset_t DIEOffsetAtIndex(uint32_t i) const { @@ -73,7 +73,7 @@ public: protected: struct AttributeValue { - const DWARFCompileUnit *cu; // Keep the compile unit with each attribute in + const DWARFUnit *cu; // Keep the compile unit with each attribute in // case we have DW_FORM_ref_addr values dw_offset_t die_offset; DWARFAttribute attr; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp b/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp new file mode 100644 index 000000000000..077de9604f1d --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp @@ -0,0 +1,193 @@ +//===-- DWARFBaseDIE.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFBaseDIE.h" + +#include "DWARFUnit.h" +#include "DWARFDebugInfoEntry.h" +#include "SymbolFileDWARF.h" + +#include "lldb/Core/Module.h" +#include "lldb/Symbol/ObjectFile.h" + +using namespace lldb_private; + +DIERef DWARFBaseDIE::GetDIERef() const { + if (!IsValid()) + return DIERef(); + + dw_offset_t cu_offset = m_cu->GetOffset(); + if (m_cu->GetBaseObjOffset() != DW_INVALID_OFFSET) + cu_offset = m_cu->GetBaseObjOffset(); + return DIERef(cu_offset, m_die->GetOffset()); +} + +dw_tag_t DWARFBaseDIE::Tag() const { + if (m_die) + return m_die->Tag(); + else + return 0; +} + +const char *DWARFBaseDIE::GetTagAsCString() const { + return lldb_private::DW_TAG_value_to_name(Tag()); +} + +const char *DWARFBaseDIE::GetAttributeValueAsString(const dw_attr_t attr, + const char *fail_value) const { + if (IsValid()) + return m_die->GetAttributeValueAsString(GetDWARF(), GetCU(), attr, + fail_value); + else + return fail_value; +} + +uint64_t DWARFBaseDIE::GetAttributeValueAsUnsigned(const dw_attr_t attr, + uint64_t fail_value) const { + if (IsValid()) + return m_die->GetAttributeValueAsUnsigned(GetDWARF(), GetCU(), attr, + fail_value); + else + return fail_value; +} + +int64_t DWARFBaseDIE::GetAttributeValueAsSigned(const dw_attr_t attr, + int64_t fail_value) const { + if (IsValid()) + return m_die->GetAttributeValueAsSigned(GetDWARF(), GetCU(), attr, + fail_value); + else + return fail_value; +} + +uint64_t DWARFBaseDIE::GetAttributeValueAsReference(const dw_attr_t attr, + uint64_t fail_value) const { + if (IsValid()) + return m_die->GetAttributeValueAsReference(GetDWARF(), GetCU(), attr, + fail_value); + else + return fail_value; +} + +uint64_t DWARFBaseDIE::GetAttributeValueAsAddress(const dw_attr_t attr, + uint64_t fail_value) const { + if (IsValid()) + return m_die->GetAttributeValueAsAddress(GetDWARF(), GetCU(), attr, + fail_value); + else + return fail_value; +} + +lldb::user_id_t DWARFBaseDIE::GetID() const { + return GetDIERef().GetUID(GetDWARF()); +} + +const char *DWARFBaseDIE::GetName() const { + if (IsValid()) + return m_die->GetName(GetDWARF(), m_cu); + else + return nullptr; +} + +lldb::LanguageType DWARFBaseDIE::GetLanguage() const { + if (IsValid()) + return m_cu->GetLanguageType(); + else + return lldb::eLanguageTypeUnknown; +} + +lldb::ModuleSP DWARFBaseDIE::GetModule() const { + SymbolFileDWARF *dwarf = GetDWARF(); + if (dwarf) + return dwarf->GetObjectFile()->GetModule(); + else + return lldb::ModuleSP(); +} + +lldb_private::CompileUnit *DWARFBaseDIE::GetLLDBCompileUnit() const { + if (IsValid()) + return GetDWARF()->GetCompUnitForDWARFCompUnit(GetCU()); + else + return nullptr; +} + +dw_offset_t DWARFBaseDIE::GetOffset() const { + if (IsValid()) + return m_die->GetOffset(); + else + return DW_INVALID_OFFSET; +} + +dw_offset_t DWARFBaseDIE::GetCompileUnitRelativeOffset() const { + if (IsValid()) + return m_die->GetOffset() - m_cu->GetOffset(); + else + return DW_INVALID_OFFSET; +} + +SymbolFileDWARF *DWARFBaseDIE::GetDWARF() const { + if (m_cu) + return m_cu->GetSymbolFileDWARF(); + else + return nullptr; +} + +lldb_private::TypeSystem *DWARFBaseDIE::GetTypeSystem() const { + if (m_cu) + return m_cu->GetTypeSystem(); + else + return nullptr; +} + +DWARFASTParser *DWARFBaseDIE::GetDWARFParser() const { + lldb_private::TypeSystem *type_system = GetTypeSystem(); + if (type_system) + return type_system->GetDWARFParser(); + else + return nullptr; +} + +bool DWARFBaseDIE::HasChildren() const { + return m_die && m_die->HasChildren(); +} + +bool DWARFBaseDIE::Supports_DW_AT_APPLE_objc_complete_type() const { + return IsValid() && GetDWARF()->Supports_DW_AT_APPLE_objc_complete_type(m_cu); +} + +size_t DWARFBaseDIE::GetAttributes(DWARFAttributes &attributes, + uint32_t depth) const { + if (IsValid()) { + return m_die->GetAttributes(m_cu, m_cu->GetFixedFormSizes(), attributes, + depth); + } + if (depth == 0) + attributes.Clear(); + return 0; +} + +void DWARFBaseDIE::Dump(lldb_private::Stream *s, + const uint32_t recurse_depth) const { + if (s && IsValid()) + m_die->Dump(GetDWARF(), GetCU(), *s, recurse_depth); +} + +bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs) { + return lhs.GetDIE() == rhs.GetDIE() && lhs.GetCU() == rhs.GetCU(); +} + +bool operator!=(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs) { + return !(lhs == rhs); +} + +const DWARFDataExtractor &DWARFBaseDIE::GetData() const { + // Clients must check if this DIE is valid before calling this function. + assert(IsValid()); + return m_cu->GetData(); +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h b/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h new file mode 100644 index 000000000000..2163a027ffbc --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h @@ -0,0 +1,157 @@ +//===-- DWARFBaseDIE.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_DWARFBaseDIE_h_ +#define SymbolFileDWARF_DWARFBaseDIE_h_ + +#include "lldb/Core/dwarf.h" +#include "lldb/lldb-types.h" + +struct DIERef; +class DWARFASTParser; +class DWARFAttributes; +class DWARFUnit; +class DWARFDebugInfoEntry; +class DWARFDeclContext; +class DWARFDIECollection; +class SymbolFileDWARF; + +class DWARFBaseDIE { +public: + DWARFBaseDIE() : m_cu(nullptr), m_die(nullptr) {} + + DWARFBaseDIE(DWARFUnit *cu, DWARFDebugInfoEntry *die) + : m_cu(cu), m_die(die) {} + + DWARFBaseDIE(const DWARFUnit *cu, DWARFDebugInfoEntry *die) + : m_cu(const_cast<DWARFUnit *>(cu)), m_die(die) {} + + DWARFBaseDIE(DWARFUnit *cu, const DWARFDebugInfoEntry *die) + : m_cu(cu), m_die(const_cast<DWARFDebugInfoEntry *>(die)) {} + + DWARFBaseDIE(const DWARFUnit *cu, const DWARFDebugInfoEntry *die) + : m_cu(const_cast<DWARFUnit *>(cu)), + m_die(const_cast<DWARFDebugInfoEntry *>(die)) {} + + //---------------------------------------------------------------------- + // Tests + //---------------------------------------------------------------------- + explicit operator bool() const { return IsValid(); } + + bool IsValid() const { return m_cu && m_die; } + + bool HasChildren() const; + + bool Supports_DW_AT_APPLE_objc_complete_type() const; + + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + SymbolFileDWARF *GetDWARF() const; + + DWARFUnit *GetCU() const { return m_cu; } + + DWARFDebugInfoEntry *GetDIE() const { return m_die; } + + DIERef GetDIERef() const; + + lldb_private::TypeSystem *GetTypeSystem() const; + + DWARFASTParser *GetDWARFParser() const; + + void Set(DWARFUnit *cu, DWARFDebugInfoEntry *die) { + if (cu && die) { + m_cu = cu; + m_die = die; + } else { + Clear(); + } + } + + void Clear() { + m_cu = nullptr; + m_die = nullptr; + } + + //---------------------------------------------------------------------- + // Get the data that contains the attribute values for this DIE. Support + // for .debug_types means that any DIE can have its data either in the + // .debug_info or the .debug_types section; this method will return the + // correct section data. + // + // Clients must validate that this object is valid before calling this. + //---------------------------------------------------------------------- + const lldb_private::DWARFDataExtractor &GetData() const; + + //---------------------------------------------------------------------- + // Accessing information about a DIE + //---------------------------------------------------------------------- + dw_tag_t Tag() const; + + const char *GetTagAsCString() const; + + dw_offset_t GetOffset() const; + + dw_offset_t GetCompileUnitRelativeOffset() const; + + //---------------------------------------------------------------------- + // Get the LLDB user ID for this DIE. This is often just the DIE offset, + // but it might have a SymbolFileDWARF::GetID() in the high 32 bits if + // we are doing Darwin DWARF in .o file, or DWARF stand alone debug + // info. + //---------------------------------------------------------------------- + lldb::user_id_t GetID() const; + + const char *GetName() const; + + lldb::LanguageType GetLanguage() const; + + lldb::ModuleSP GetModule() const; + + lldb_private::CompileUnit *GetLLDBCompileUnit() const; + + //---------------------------------------------------------------------- + // Getting attribute values from the DIE. + // + // GetAttributeValueAsXXX() functions should only be used if you are + // looking for one or two attributes on a DIE. If you are trying to + // parse all attributes, use GetAttributes (...) instead + //---------------------------------------------------------------------- + const char *GetAttributeValueAsString(const dw_attr_t attr, + const char *fail_value) const; + + uint64_t GetAttributeValueAsUnsigned(const dw_attr_t attr, + uint64_t fail_value) const; + + int64_t GetAttributeValueAsSigned(const dw_attr_t attr, + int64_t fail_value) const; + + uint64_t GetAttributeValueAsReference(const dw_attr_t attr, + uint64_t fail_value) const; + + uint64_t GetAttributeValueAsAddress(const dw_attr_t attr, + uint64_t fail_value) const; + + size_t GetAttributes(DWARFAttributes &attributes, uint32_t depth = 0) const; + + //---------------------------------------------------------------------- + // Pretty printing + //---------------------------------------------------------------------- + + void Dump(lldb_private::Stream *s, const uint32_t recurse_depth) const; + +protected: + DWARFUnit *m_cu; + DWARFDebugInfoEntry *m_die; +}; + +bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs); +bool operator!=(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs); + +#endif // SymbolFileDWARF_DWARFBaseDIE_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index 5d7b12067263..8541f1cfe1f6 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -9,48 +9,22 @@ #include "DWARFCompileUnit.h" -#include "Plugins/Language/ObjC/ObjCLanguage.h" -#include "lldb/Core/DumpDataExtractor.h" -#include "lldb/Core/Mangled.h" -#include "lldb/Core/Module.h" -#include "lldb/Host/StringConvert.h" -#include "lldb/Symbol/CompileUnit.h" -#include "lldb/Symbol/LineTable.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Utility/Stream.h" -#include "lldb/Utility/StreamString.h" -#include "lldb/Utility/Timer.h" - -#include "DWARFDIECollection.h" -#include "DWARFDebugAbbrev.h" -#include "DWARFDebugAranges.h" -#include "DWARFDebugInfo.h" -#include "DWARFFormValue.h" -#include "LogChannelDWARF.h" -#include "NameToDIE.h" #include "SymbolFileDWARF.h" -#include "SymbolFileDWARFDebugMap.h" -#include "SymbolFileDWARFDwo.h" +#include "lldb/Utility/Stream.h" using namespace lldb; using namespace lldb_private; -using namespace std; extern int g_verbose; DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF *dwarf2Data) - : m_dwarf2Data(dwarf2Data) {} + : DWARFUnit(dwarf2Data) {} -DWARFCompileUnit::~DWARFCompileUnit() {} - -DWARFCompileUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, - lldb::offset_t *offset_ptr) { - DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(dwarf2Data)); - // Out of memory? - if (cu_sp.get() == NULL) - return nullptr; - - const DWARFDataExtractor &debug_info = dwarf2Data->get_debug_info_data(); +DWARFUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, + const DWARFDataExtractor &debug_info, + lldb::offset_t *offset_ptr) { + // std::make_shared would require the ctor to be public. + std::shared_ptr<DWARFCompileUnit> cu_sp(new DWARFCompileUnit(dwarf2Data)); cu_sp->m_offset = *offset_ptr; @@ -83,259 +57,6 @@ DWARFCompileUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, return nullptr; } -void DWARFCompileUnit::ClearDIEs(bool keep_compile_unit_die) { - if (m_die_array.size() > 1) { - // std::vectors never get any smaller when resized to a smaller size, - // or when clear() or erase() are called, the size will report that it - // is smaller, but the memory allocated remains intact (call capacity() - // to see this). So we need to create a temporary vector and swap the - // contents which will cause just the internal pointers to be swapped - // so that when "tmp_array" goes out of scope, it will destroy the - // contents. - - // Save at least the compile unit DIE - DWARFDebugInfoEntry::collection tmp_array; - m_die_array.swap(tmp_array); - if (keep_compile_unit_die) - m_die_array.push_back(tmp_array.front()); - } - - if (m_dwo_symbol_file) - m_dwo_symbol_file->GetCompileUnit()->ClearDIEs(keep_compile_unit_die); -} - -//---------------------------------------------------------------------- -// ParseCompileUnitDIEsIfNeeded -// -// Parses a compile unit and indexes its DIEs if it hasn't already been -// done. -//---------------------------------------------------------------------- -size_t DWARFCompileUnit::ExtractDIEsIfNeeded(bool cu_die_only) { - const size_t initial_die_array_size = m_die_array.size(); - if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1) - return 0; // Already parsed - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, - "%8.8x: DWARFCompileUnit::ExtractDIEsIfNeeded( cu_die_only = %i )", - m_offset, cu_die_only); - - // Set the offset to that of the first DIE and calculate the start of the - // next compilation unit header. - lldb::offset_t offset = GetFirstDIEOffset(); - lldb::offset_t next_cu_offset = GetNextCompileUnitOffset(); - - DWARFDebugInfoEntry die; - // Keep a flat array of the DIE for binary lookup by DIE offset - if (!cu_die_only) { - Log *log( - LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS)); - if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( - log, "DWARFCompileUnit::ExtractDIEsIfNeeded () for compile unit at " - ".debug_info[0x%8.8x]", - GetOffset()); - } - } - - uint32_t depth = 0; - // We are in our compile unit, parse starting at the offset - // we were told to parse - const DWARFDataExtractor &debug_info_data = - m_dwarf2Data->get_debug_info_data(); - std::vector<uint32_t> die_index_stack; - die_index_stack.reserve(32); - die_index_stack.push_back(0); - bool prev_die_had_children = false; - DWARFFormValue::FixedFormSizes fixed_form_sizes = - DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), - m_is_dwarf64); - while (offset < next_cu_offset && - die.FastExtract(debug_info_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) { - if (initial_die_array_size == 0) - AddCompileUnitDIE(die); - uint64_t base_addr = die.GetAttributeValueAsAddress( - m_dwarf2Data, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); - if (base_addr == LLDB_INVALID_ADDRESS) - base_addr = die.GetAttributeValueAsAddress(m_dwarf2Data, this, - DW_AT_entry_pc, 0); - SetBaseAddress(base_addr); - if (cu_die_only) - return 1; - } else { - if (null_die) { - if (prev_die_had_children) { - // This will only happen if a DIE says is has children - // but all it contains is a NULL tag. Since we are removing - // the NULL DIEs from 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); - } - } else { - die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]); - - if (die_index_stack.back()) - m_die_array[die_index_stack.back()].SetSiblingIndex( - m_die_array.size() - die_index_stack.back()); - - // Only push the DIE if it isn't a NULL DIE - m_die_array.push_back(die); - } - } - - if (null_die) { - // NULL DIE. - if (!die_index_stack.empty()) - die_index_stack.pop_back(); - - 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; - // Normal DIE - const bool die_has_children = die.HasChildren(); - if (die_has_children) { - die_index_stack.push_back(0); - ++depth; - } - prev_die_had_children = die_has_children; - } - } - - // Give a little bit of info if we encounter corrupt DWARF (our offset - // should always terminate at or before the start of the next compilation - // unit header). - if (offset > next_cu_offset) { - m_dwarf2Data->GetObjectFile()->GetModule()->ReportWarning( - "DWARF compile unit extends beyond its bounds cu 0x%8.8x at " - "0x%8.8" PRIx64 "\n", - GetOffset(), offset); - } - - // Since std::vector objects will double their size, we really need to - // make a new array with the perfect size so we don't end up wasting - // space. So here we copy and swap to make sure we don't have any extra - // memory taken up. - - if (m_die_array.size() < m_die_array.capacity()) { - DWARFDebugInfoEntry::collection exact_size_die_array(m_die_array.begin(), - m_die_array.end()); - exact_size_die_array.swap(m_die_array); - } - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); - if (log && log->GetVerbose()) { - StreamString strm; - Dump(&strm); - if (m_die_array.empty()) - strm.Printf("error: no DIE for compile unit"); - else - m_die_array[0].Dump(m_dwarf2Data, this, strm, UINT32_MAX); - log->PutString(strm.GetString()); - } - - if (!m_dwo_symbol_file) - return m_die_array.size(); - - DWARFCompileUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); - size_t dwo_die_count = dwo_cu->ExtractDIEsIfNeeded(cu_die_only); - return m_die_array.size() + dwo_die_count - - 1; // We have 2 CU die, but we want to count it only as one -} - -void DWARFCompileUnit::AddCompileUnitDIE(DWARFDebugInfoEntry &die) { - assert(m_die_array.empty() && "Compile unit DIE already added"); - AddDIE(die); - - const DWARFDebugInfoEntry &cu_die = m_die_array.front(); - std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file = - m_dwarf2Data->GetDwoSymbolFileForCompileUnit(*this, cu_die); - if (!dwo_symbol_file) - return; - - DWARFCompileUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); - if (!dwo_cu) - return; // Can't fetch the compile unit from the dwo file. - - DWARFDIE dwo_cu_die = dwo_cu->GetCompileUnitDIEOnly(); - if (!dwo_cu_die.IsValid()) - return; // Can't fetch the compile unit DIE from the dwo file. - - uint64_t main_dwo_id = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_dwo_id, 0); - uint64_t sub_dwo_id = - dwo_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0); - if (main_dwo_id != sub_dwo_id) - return; // The 2 dwo ID isn't match. Don't use the dwo file as it belongs to - // a differectn compilation. - - m_dwo_symbol_file = std::move(dwo_symbol_file); - - dw_addr_t addr_base = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_addr_base, 0); - dw_addr_t ranges_base = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_ranges_base, 0); - dwo_cu->SetAddrBase(addr_base, ranges_base, m_offset); -} - -dw_offset_t DWARFCompileUnit::GetAbbrevOffset() const { - return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET; -} - -bool DWARFCompileUnit::Verify(Stream *s) const { - const DWARFDataExtractor &debug_info = m_dwarf2Data->get_debug_info_data(); - bool valid_offset = debug_info.ValidOffset(m_offset); - bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset() - 1); - bool version_OK = SymbolFileDWARF::SupportedVersion(m_version); - bool abbr_offset_OK = - m_dwarf2Data->get_debug_abbrev_data().ValidOffset(GetAbbrevOffset()); - bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8)); - if (valid_offset && length_OK && version_OK && addr_size_OK && - abbr_offset_OK) { - return true; - } else { - s->Printf(" 0x%8.8x: ", m_offset); - DumpDataExtractor(m_dwarf2Data->get_debug_info_data(), s, m_offset, - lldb::eFormatHex, 1, Size(), 32, LLDB_INVALID_ADDRESS, 0, - 0); - s->EOL(); - if (valid_offset) { - if (!length_OK) - s->Printf(" The length (0x%8.8x) for this compile unit is too " - "large for the .debug_info provided.\n", - m_length); - if (!version_OK) - s->Printf(" The 16 bit compile unit header version is not " - "supported.\n"); - if (!abbr_offset_OK) - s->Printf(" The offset into the .debug_abbrev section (0x%8.8x) " - "is not valid.\n", - GetAbbrevOffset()); - if (!addr_size_OK) - s->Printf(" The address size is unsupported: 0x%2.2x\n", - m_addr_size); - } else - s->Printf(" The start offset of the compile unit header in the " - ".debug_info is invalid.\n"); - } - return false; -} - void DWARFCompileUnit::Dump(Stream *s) const { s->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, " "abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at " @@ -344,768 +65,7 @@ void DWARFCompileUnit::Dump(Stream *s) const { GetNextCompileUnitOffset()); } -static uint8_t g_default_addr_size = 4; - -uint8_t DWARFCompileUnit::GetAddressByteSize(const DWARFCompileUnit *cu) { - if (cu) - return cu->GetAddressByteSize(); - return DWARFCompileUnit::GetDefaultAddressSize(); -} - -bool DWARFCompileUnit::IsDWARF64(const DWARFCompileUnit *cu) { - if (cu) - return cu->IsDWARF64(); - return false; -} - -uint8_t DWARFCompileUnit::GetDefaultAddressSize() { - return g_default_addr_size; -} - -void DWARFCompileUnit::SetDefaultAddressSize(uint8_t addr_size) { - g_default_addr_size = addr_size; -} - -lldb::user_id_t DWARFCompileUnit::GetID() const { - dw_offset_t local_id = - m_base_obj_offset != DW_INVALID_OFFSET ? m_base_obj_offset : m_offset; - if (m_dwarf2Data) - return DIERef(local_id, local_id).GetUID(m_dwarf2Data); - else - return local_id; -} - -void DWARFCompileUnit::BuildAddressRangeTable( - SymbolFileDWARF *dwarf2Data, DWARFDebugAranges *debug_aranges) { - // This function is usually called if there in no .debug_aranges section - // in order to produce a compile unit level set of address ranges that - // is accurate. - - size_t num_debug_aranges = debug_aranges->GetNumRanges(); - - // First get the compile unit DIE only and check if it has a DW_AT_ranges - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - - const dw_offset_t cu_offset = GetOffset(); - if (die) { - DWARFRangeList ranges; - const size_t num_ranges = - die->GetAttributeAddressRanges(dwarf2Data, this, ranges, false); - if (num_ranges > 0) { - // This compile unit has DW_AT_ranges, assume this is correct if it - // is present since clang no longer makes .debug_aranges by default - // and it emits DW_AT_ranges for DW_TAG_compile_units. GCC also does - // this with recent GCC builds. - for (size_t i = 0; i < num_ranges; ++i) { - const DWARFRangeList::Entry &range = ranges.GetEntryRef(i); - debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), - range.GetRangeEnd()); - } - - return; // We got all of our ranges from the DW_AT_ranges attribute - } - } - // We don't have a DW_AT_ranges attribute, so we need to parse the DWARF - - // If the DIEs weren't parsed, then we don't want all dies for all compile - // units - // to stay loaded when they weren't needed. So we can end up parsing the DWARF - // and then throwing them all away to keep memory usage down. - const bool clear_dies = ExtractDIEsIfNeeded(false) > 1; - - die = DIEPtr(); - if (die) - die->BuildAddressRangeTable(dwarf2Data, this, debug_aranges); - - if (debug_aranges->GetNumRanges() == num_debug_aranges) { - // We got nothing from the functions, maybe we have a line tables only - // situation. Check the line tables and build the arange table from this. - SymbolContext sc; - sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this); - if (sc.comp_unit) { - SymbolFileDWARFDebugMap *debug_map_sym_file = - m_dwarf2Data->GetDebugMapSymfile(); - if (debug_map_sym_file == NULL) { - LineTable *line_table = sc.comp_unit->GetLineTable(); - - if (line_table) { - LineTable::FileAddressRanges file_ranges; - const bool append = true; - const size_t num_ranges = - line_table->GetContiguousFileAddressRanges(file_ranges, append); - for (uint32_t idx = 0; idx < num_ranges; ++idx) { - const LineTable::FileAddressRanges::Entry &range = - file_ranges.GetEntryRef(idx); - debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), - range.GetRangeEnd()); - } - } - } else - debug_map_sym_file->AddOSOARanges(dwarf2Data, debug_aranges); - } - } - - if (debug_aranges->GetNumRanges() == num_debug_aranges) { - // We got nothing from the functions, maybe we have a line tables only - // situation. Check the line tables and build the arange table from this. - SymbolContext sc; - sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this); - if (sc.comp_unit) { - LineTable *line_table = sc.comp_unit->GetLineTable(); - - if (line_table) { - LineTable::FileAddressRanges file_ranges; - const bool append = true; - const size_t num_ranges = - line_table->GetContiguousFileAddressRanges(file_ranges, append); - for (uint32_t idx = 0; idx < num_ranges; ++idx) { - const LineTable::FileAddressRanges::Entry &range = - file_ranges.GetEntryRef(idx); - debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), - range.GetRangeEnd()); - } - } - } - } - - // Keep memory down by clearing DIEs if this generate function - // caused them to be parsed - if (clear_dies) - ClearDIEs(true); -} - -const DWARFDebugAranges &DWARFCompileUnit::GetFunctionAranges() { - if (m_func_aranges_ap.get() == NULL) { - m_func_aranges_ap.reset(new DWARFDebugAranges()); - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); - - if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage( - log, "DWARFCompileUnit::GetFunctionAranges() for compile unit at " - ".debug_info[0x%8.8x]", - GetOffset()); - } - const DWARFDebugInfoEntry *die = DIEPtr(); - if (die) - die->BuildFunctionAddressRangeTable(m_dwarf2Data, this, - m_func_aranges_ap.get()); - - if (m_dwo_symbol_file) { - DWARFCompileUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); - const DWARFDebugInfoEntry *dwo_die = dwo_cu->DIEPtr(); - if (dwo_die) - dwo_die->BuildFunctionAddressRangeTable(m_dwo_symbol_file.get(), dwo_cu, - m_func_aranges_ap.get()); - } - - const bool minimize = false; - m_func_aranges_ap->Sort(minimize); - } - return *m_func_aranges_ap.get(); -} - -DWARFDIE -DWARFCompileUnit::LookupAddress(const dw_addr_t address) { - if (DIE()) { - const DWARFDebugAranges &func_aranges = GetFunctionAranges(); - - // Re-check the aranges auto pointer contents in case it was created above - if (!func_aranges.IsEmpty()) - return GetDIE(func_aranges.FindAddress(address)); - } - return DWARFDIE(); -} - -//---------------------------------------------------------------------- -// Compare function DWARFDebugAranges::Range structures -//---------------------------------------------------------------------- -static bool CompareDIEOffset(const DWARFDebugInfoEntry &die, - const dw_offset_t die_offset) { - return die.GetOffset() < die_offset; -} - -//---------------------------------------------------------------------- -// GetDIE() -// -// Get the DIE (Debug Information Entry) with the specified offset by -// first checking if the DIE is contained within this compile unit and -// grabbing the DIE from this compile unit. Otherwise we grab the DIE -// from the DWARF file. -//---------------------------------------------------------------------- -DWARFDIE -DWARFCompileUnit::GetDIE(dw_offset_t die_offset) { - if (die_offset != DW_INVALID_OFFSET) { - if (m_dwo_symbol_file) - return m_dwo_symbol_file->GetCompileUnit()->GetDIE(die_offset); - - if (ContainsDIEOffset(die_offset)) { - ExtractDIEsIfNeeded(false); - DWARFDebugInfoEntry::iterator end = m_die_array.end(); - DWARFDebugInfoEntry::iterator pos = - lower_bound(m_die_array.begin(), end, die_offset, CompareDIEOffset); - if (pos != end) { - if (die_offset == (*pos).GetOffset()) - return DWARFDIE(this, &(*pos)); - } - } else { - // Don't specify the compile unit offset as we don't know it because the - // DIE belongs to - // a different compile unit in the same symbol file. - return m_dwarf2Data->DebugInfo()->GetDIEForDIEOffset(die_offset); - } - } - return DWARFDIE(); // Not found -} - -size_t DWARFCompileUnit::AppendDIEsWithTag(const dw_tag_t tag, - DWARFDIECollection &dies, - uint32_t depth) const { - size_t old_size = dies.Size(); - DWARFDebugInfoEntry::const_iterator pos; - DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); - for (pos = m_die_array.begin(); pos != end; ++pos) { - if (pos->Tag() == tag) - dies.Append(DWARFDIE(this, &(*pos))); - } - - // Return the number of DIEs added to the collection - return dies.Size() - old_size; -} - -// void -// DWARFCompileUnit::AddGlobalDIEByIndex (uint32_t die_idx) -//{ -// m_global_die_indexes.push_back (die_idx); -//} -// -// -// void -// DWARFCompileUnit::AddGlobal (const DWARFDebugInfoEntry* die) -//{ -// // Indexes to all file level global and static variables -// m_global_die_indexes; -// -// if (m_die_array.empty()) -// return; -// -// const DWARFDebugInfoEntry* first_die = &m_die_array[0]; -// const DWARFDebugInfoEntry* end = first_die + m_die_array.size(); -// if (first_die <= die && die < end) -// m_global_die_indexes.push_back (die - first_die); -//} - -void DWARFCompileUnit::Index(NameToDIE &func_basenames, - NameToDIE &func_fullnames, NameToDIE &func_methods, - NameToDIE &func_selectors, - NameToDIE &objc_class_selectors, - NameToDIE &globals, NameToDIE &types, - NameToDIE &namespaces) { - assert(!m_dwarf2Data->GetBaseCompileUnit() && - "DWARFCompileUnit associated with .dwo or .dwp " - "should not be indexed directly"); - - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); - - if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage( - log, - "DWARFCompileUnit::Index() for compile unit at .debug_info[0x%8.8x]", - GetOffset()); - } - - const LanguageType cu_language = GetLanguageType(); - DWARFFormValue::FixedFormSizes fixed_form_sizes = - DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), - m_is_dwarf64); - - IndexPrivate(this, cu_language, fixed_form_sizes, GetOffset(), func_basenames, - func_fullnames, func_methods, func_selectors, - objc_class_selectors, globals, types, namespaces); - - SymbolFileDWARFDwo *dwo_symbol_file = GetDwoSymbolFile(); - if (dwo_symbol_file) { - IndexPrivate(dwo_symbol_file->GetCompileUnit(), cu_language, - fixed_form_sizes, GetOffset(), func_basenames, func_fullnames, - func_methods, func_selectors, objc_class_selectors, globals, - types, namespaces); - } -} - -void DWARFCompileUnit::IndexPrivate( - DWARFCompileUnit *dwarf_cu, const LanguageType cu_language, - const DWARFFormValue::FixedFormSizes &fixed_form_sizes, - const dw_offset_t cu_offset, NameToDIE &func_basenames, - NameToDIE &func_fullnames, NameToDIE &func_methods, - NameToDIE &func_selectors, NameToDIE &objc_class_selectors, - NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces) { - DWARFDebugInfoEntry::const_iterator pos; - DWARFDebugInfoEntry::const_iterator begin = dwarf_cu->m_die_array.begin(); - DWARFDebugInfoEntry::const_iterator end = dwarf_cu->m_die_array.end(); - for (pos = begin; pos != end; ++pos) { - const DWARFDebugInfoEntry &die = *pos; - - const dw_tag_t tag = die.Tag(); - - switch (tag) { - case DW_TAG_array_type: - case DW_TAG_base_type: - case DW_TAG_class_type: - case DW_TAG_constant: - case DW_TAG_enumeration_type: - case DW_TAG_inlined_subroutine: - case DW_TAG_namespace: - case DW_TAG_string_type: - case DW_TAG_structure_type: - case DW_TAG_subprogram: - case DW_TAG_subroutine_type: - case DW_TAG_typedef: - case DW_TAG_union_type: - case DW_TAG_unspecified_type: - case DW_TAG_variable: - break; - - default: - continue; - } - - DWARFAttributes attributes; - const char *name = NULL; - const char *mangled_cstr = NULL; - bool is_declaration = false; - // bool is_artificial = false; - bool has_address = false; - bool has_location_or_const_value = false; - bool is_global_or_static_variable = false; - - DWARFFormValue specification_die_form; - const size_t num_attributes = - die.GetAttributes(dwarf_cu, fixed_form_sizes, attributes); - if (num_attributes > 0) { - for (uint32_t i = 0; i < num_attributes; ++i) { - dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - switch (attr) { - case DW_AT_name: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - name = form_value.AsCString(); - break; - - case DW_AT_declaration: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - is_declaration = form_value.Unsigned() != 0; - break; - - // case DW_AT_artificial: - // if (attributes.ExtractFormValueAtIndex(i, - // form_value)) - // is_artificial = form_value.Unsigned() != 0; - // break; - - case DW_AT_MIPS_linkage_name: - case DW_AT_linkage_name: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - mangled_cstr = form_value.AsCString(); - break; - - case DW_AT_low_pc: - case DW_AT_high_pc: - case DW_AT_ranges: - has_address = true; - break; - - case DW_AT_entry_pc: - has_address = true; - break; - - case DW_AT_location: - case DW_AT_const_value: - has_location_or_const_value = true; - if (tag == DW_TAG_variable) { - const DWARFDebugInfoEntry *parent_die = die.GetParent(); - while (parent_die != NULL) { - switch (parent_die->Tag()) { - case DW_TAG_subprogram: - case DW_TAG_lexical_block: - case DW_TAG_inlined_subroutine: - // Even if this is a function level static, we don't add it. We - // could theoretically - // add these if we wanted to by introspecting into the - // DW_AT_location and seeing - // if the location describes a hard coded address, but we dont - // want the performance - // penalty of that right now. - is_global_or_static_variable = false; - // if - // (attributes.ExtractFormValueAtIndex(dwarf2Data, - // i, form_value)) - // { - // // If we have valid block - // data, then we have location - // expression bytes - // // that are fixed (not a - // location list). - // const uint8_t *block_data = - // form_value.BlockData(); - // if (block_data) - // { - // uint32_t block_length = - // form_value.Unsigned(); - // if (block_length == 1 + - // attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) - // { - // if (block_data[0] == - // DW_OP_addr) - // add_die = true; - // } - // } - // } - parent_die = NULL; // Terminate the while loop. - break; - - case DW_TAG_compile_unit: - is_global_or_static_variable = true; - parent_die = NULL; // Terminate the while loop. - break; - - default: - parent_die = - parent_die->GetParent(); // Keep going in the while loop. - break; - } - } - } - break; - - case DW_AT_specification: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - specification_die_form = form_value; - break; - } - } - } - - switch (tag) { - case DW_TAG_subprogram: - if (has_address) { - if (name) { - ObjCLanguage::MethodName objc_method(name, true); - if (objc_method.IsValid(true)) { - ConstString objc_class_name_with_category( - objc_method.GetClassNameWithCategory()); - ConstString objc_selector_name(objc_method.GetSelector()); - ConstString objc_fullname_no_category_name( - objc_method.GetFullNameWithoutCategory(true)); - ConstString objc_class_name_no_category(objc_method.GetClassName()); - func_fullnames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - if (objc_class_name_with_category) - objc_class_selectors.Insert(objc_class_name_with_category, - DIERef(cu_offset, die.GetOffset())); - if (objc_class_name_no_category && - objc_class_name_no_category != objc_class_name_with_category) - objc_class_selectors.Insert(objc_class_name_no_category, - DIERef(cu_offset, die.GetOffset())); - if (objc_selector_name) - func_selectors.Insert(objc_selector_name, - DIERef(cu_offset, die.GetOffset())); - if (objc_fullname_no_category_name) - func_fullnames.Insert(objc_fullname_no_category_name, - DIERef(cu_offset, die.GetOffset())); - } - // If we have a mangled name, then the DW_AT_name attribute - // is usually the method name without the class or any parameters - const DWARFDebugInfoEntry *parent = die.GetParent(); - bool is_method = false; - if (parent) { - dw_tag_t parent_tag = parent->Tag(); - if (parent_tag == DW_TAG_class_type || - parent_tag == DW_TAG_structure_type) { - is_method = true; - } else { - if (specification_die_form.IsValid()) { - DWARFDIE specification_die = - dwarf_cu->GetSymbolFileDWARF()->DebugInfo()->GetDIE( - DIERef(specification_die_form)); - if (specification_die.GetParent().IsStructOrClass()) - is_method = true; - } - } - } - - if (is_method) - func_methods.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - else - func_basenames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - - if (!is_method && !mangled_cstr && !objc_method.IsValid(true)) - func_fullnames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - } - if (mangled_cstr) { - // Make sure our mangled name isn't the same string table entry - // as our name. If it starts with '_', then it is ok, else compare - // the string to make sure it isn't the same and we don't end up - // with duplicate entries - if (name && name != mangled_cstr && - ((mangled_cstr[0] == '_') || - (::strcmp(name, mangled_cstr) != 0))) { - Mangled mangled(ConstString(mangled_cstr), true); - func_fullnames.Insert(mangled.GetMangledName(), - DIERef(cu_offset, die.GetOffset())); - ConstString demangled = mangled.GetDemangledName(cu_language); - if (demangled) - func_fullnames.Insert(demangled, - DIERef(cu_offset, die.GetOffset())); - } - } - } - break; - - case DW_TAG_inlined_subroutine: - if (has_address) { - if (name) - func_basenames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - if (mangled_cstr) { - // Make sure our mangled name isn't the same string table entry - // as our name. If it starts with '_', then it is ok, else compare - // the string to make sure it isn't the same and we don't end up - // with duplicate entries - if (name && name != mangled_cstr && - ((mangled_cstr[0] == '_') || - (::strcmp(name, mangled_cstr) != 0))) { - Mangled mangled(ConstString(mangled_cstr), true); - func_fullnames.Insert(mangled.GetMangledName(), - DIERef(cu_offset, die.GetOffset())); - ConstString demangled = mangled.GetDemangledName(cu_language); - if (demangled) - func_fullnames.Insert(demangled, - DIERef(cu_offset, die.GetOffset())); - } - } else - func_fullnames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - } - break; - - case DW_TAG_array_type: - case DW_TAG_base_type: - case DW_TAG_class_type: - case DW_TAG_constant: - case DW_TAG_enumeration_type: - case DW_TAG_string_type: - case DW_TAG_structure_type: - case DW_TAG_subroutine_type: - case DW_TAG_typedef: - case DW_TAG_union_type: - case DW_TAG_unspecified_type: - if (name && !is_declaration) - types.Insert(ConstString(name), DIERef(cu_offset, die.GetOffset())); - if (mangled_cstr && !is_declaration) - types.Insert(ConstString(mangled_cstr), - DIERef(cu_offset, die.GetOffset())); - break; - - case DW_TAG_namespace: - if (name) - namespaces.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - break; - - case DW_TAG_variable: - if (name && has_location_or_const_value && is_global_or_static_variable) { - globals.Insert(ConstString(name), DIERef(cu_offset, die.GetOffset())); - // Be sure to include variables by their mangled and demangled - // names if they have any since a variable can have a basename - // "i", a mangled named "_ZN12_GLOBAL__N_11iE" and a demangled - // mangled name "(anonymous namespace)::i"... - - // Make sure our mangled name isn't the same string table entry - // as our name. If it starts with '_', then it is ok, else compare - // the string to make sure it isn't the same and we don't end up - // with duplicate entries - if (mangled_cstr && name != mangled_cstr && - ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { - Mangled mangled(ConstString(mangled_cstr), true); - globals.Insert(mangled.GetMangledName(), - DIERef(cu_offset, die.GetOffset())); - ConstString demangled = mangled.GetDemangledName(cu_language); - if (demangled) - globals.Insert(demangled, DIERef(cu_offset, die.GetOffset())); - } - } - break; - - default: - continue; - } - } -} - -bool DWARFCompileUnit::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 true; // Assume all other compilers didn't have incorrect ObjC bitfield - // info -} - -bool DWARFCompileUnit::Supports_DW_AT_APPLE_objc_complete_type() { - if (GetProducer() == eProducerLLVMGCC) - return false; - return true; -} - -bool DWARFCompileUnit::DW_AT_decl_file_attributes_are_invalid() { - // llvm-gcc makes completely invalid decl file attributes and won't ever - // be fixed, so we need to know to ignore these. - return GetProducer() == eProducerLLVMGCC; -} - -void DWARFCompileUnit::ParseProducerInfo() { - m_producer_version_major = UINT32_MAX; - m_producer_version_minor = UINT32_MAX; - m_producer_version_update = UINT32_MAX; - - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - if (die) { - - const char *producer_cstr = die->GetAttributeValueAsString( - m_dwarf2Data, this, DW_AT_producer, NULL); - if (producer_cstr) { - RegularExpression llvm_gcc_regex( - llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " - "Inc\\. build [0-9]+\\) \\(LLVM build " - "[\\.0-9]+\\)$")); - if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) { - m_producer = eProducerLLVMGCC; - } else if (strstr(producer_cstr, "clang")) { - static RegularExpression g_clang_version_regex( - llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)")); - RegularExpression::Match regex_match(3); - if (g_clang_version_regex.Execute(llvm::StringRef(producer_cstr), - ®ex_match)) { - std::string str; - if (regex_match.GetMatchAtIndex(producer_cstr, 1, str)) - m_producer_version_major = - StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); - if (regex_match.GetMatchAtIndex(producer_cstr, 2, str)) - m_producer_version_minor = - StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); - if (regex_match.GetMatchAtIndex(producer_cstr, 3, str)) - m_producer_version_update = - StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); - } - m_producer = eProducerClang; - } else if (strstr(producer_cstr, "GNU")) - m_producer = eProducerGCC; - } - } - if (m_producer == eProducerInvalid) - m_producer = eProcucerOther; -} - -DWARFCompileUnit::Producer DWARFCompileUnit::GetProducer() { - if (m_producer == eProducerInvalid) - ParseProducerInfo(); - return m_producer; -} - -uint32_t DWARFCompileUnit::GetProducerVersionMajor() { - if (m_producer_version_major == 0) - ParseProducerInfo(); - return m_producer_version_major; -} - -uint32_t DWARFCompileUnit::GetProducerVersionMinor() { - if (m_producer_version_minor == 0) - ParseProducerInfo(); - return m_producer_version_minor; -} - -uint32_t DWARFCompileUnit::GetProducerVersionUpdate() { - if (m_producer_version_update == 0) - ParseProducerInfo(); - return m_producer_version_update; -} - -LanguageType DWARFCompileUnit::LanguageTypeFromDWARF(uint64_t val) { - // Note: user languages between lo_user and hi_user - // must be handled explicitly here. - switch (val) { - case DW_LANG_Mips_Assembler: - return eLanguageTypeMipsAssembler; - case DW_LANG_GOOGLE_RenderScript: - return eLanguageTypeExtRenderScript; - default: - return static_cast<LanguageType>(val); - } -} - -LanguageType DWARFCompileUnit::GetLanguageType() { - if (m_language_type != eLanguageTypeUnknown) - return m_language_type; - - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - if (die) - m_language_type = LanguageTypeFromDWARF(die->GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_language, 0)); - return m_language_type; -} - -bool DWARFCompileUnit::IsDWARF64() const { return m_is_dwarf64; } - -bool DWARFCompileUnit::GetIsOptimized() { - if (m_is_optimized == eLazyBoolCalculate) { - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - if (die) { - m_is_optimized = eLazyBoolNo; - if (die->GetAttributeValueAsUnsigned(m_dwarf2Data, this, - DW_AT_APPLE_optimized, 0) == 1) { - m_is_optimized = eLazyBoolYes; - } - } - } - if (m_is_optimized == eLazyBoolYes) { - return true; - } else { - return false; - } -} - -DWARFFormValue::FixedFormSizes DWARFCompileUnit::GetFixedFormSizes() { - return DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), - IsDWARF64()); -} - -TypeSystem *DWARFCompileUnit::GetTypeSystem() { - if (m_dwarf2Data) - return m_dwarf2Data->GetTypeSystemForLanguage(GetLanguageType()); - else - return nullptr; -} - -void DWARFCompileUnit::SetUserData(void *d) { - m_user_data = d; - if (m_dwo_symbol_file) - m_dwo_symbol_file->GetCompileUnit()->SetUserData(d); -} - -void DWARFCompileUnit::SetAddrBase(dw_addr_t addr_base, - dw_addr_t ranges_base, - dw_offset_t base_obj_offset) { - m_addr_base = addr_base; - m_ranges_base = ranges_base; - m_base_obj_offset = base_obj_offset; -} -lldb::ByteOrder DWARFCompileUnit::GetByteOrder() const { - return m_dwarf2Data->GetObjectFile()->GetByteOrder(); +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 8ea0d6465adf..9c1fc82f58b7 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -10,214 +10,39 @@ #ifndef SymbolFileDWARF_DWARFCompileUnit_h_ #define SymbolFileDWARF_DWARFCompileUnit_h_ -#include "DWARFDIE.h" -#include "DWARFDebugInfoEntry.h" -#include "lldb/lldb-enumerations.h" +#include "DWARFUnit.h" -class NameToDIE; -class SymbolFileDWARF; -class SymbolFileDWARFDwo; +class DWARFCompileUnit : public DWARFUnit { + friend class DWARFUnit; -typedef std::shared_ptr<DWARFCompileUnit> DWARFCompileUnitSP; - -class DWARFCompileUnit { public: - enum Producer { - eProducerInvalid = 0, - eProducerClang, - eProducerGCC, - eProducerLLVMGCC, - eProcucerOther - }; - - static DWARFCompileUnitSP Extract(SymbolFileDWARF *dwarf2Data, - lldb::offset_t *offset_ptr); - ~DWARFCompileUnit(); - - size_t ExtractDIEsIfNeeded(bool cu_die_only); - DWARFDIE LookupAddress(const dw_addr_t address); - size_t AppendDIEsWithTag(const dw_tag_t tag, - DWARFDIECollection &matching_dies, - uint32_t depth = UINT32_MAX) const; - bool Verify(lldb_private::Stream *s) const; - void Dump(lldb_private::Stream *s) const; - // Offset of the initial length field. - dw_offset_t GetOffset() const { return m_offset; } - lldb::user_id_t GetID() const; - // Size in bytes of the initial length + compile unit header. - uint32_t Size() const { return m_is_dwarf64 ? 23 : 11; } - bool ContainsDIEOffset(dw_offset_t die_offset) const { - return die_offset >= GetFirstDIEOffset() && - die_offset < GetNextCompileUnitOffset(); - } - dw_offset_t GetFirstDIEOffset() const { return m_offset + Size(); } - dw_offset_t GetNextCompileUnitOffset() const { - return m_offset + (m_is_dwarf64 ? 12 : 4) + m_length; + static DWARFUnitSP Extract(SymbolFileDWARF *dwarf2Data, + const lldb_private::DWARFDataExtractor &debug_info, + lldb::offset_t *offset_ptr); + void Dump(lldb_private::Stream *s) const override; + + //------------------------------------------------------------------ + /// Get the data that contains the DIE information for this unit. + /// + /// @return + /// The correct data (.debug_types for DWARF 4 and earlier, and + /// .debug_info for DWARF 5 and later) for the DIE information in + /// this unit. + //------------------------------------------------------------------ + const lldb_private::DWARFDataExtractor &GetData() const override; + + //------------------------------------------------------------------ + /// Get the size in bytes of the header. + /// + /// @return + /// Byte size of the compile unit header + //------------------------------------------------------------------ + uint32_t GetHeaderByteSize() const override { + return m_is_dwarf64 ? 23 : 11; } - // Size of the CU data (without initial length and without header). - size_t GetDebugInfoSize() const { - return (m_is_dwarf64 ? 12 : 4) + m_length - Size(); - } - // Size of the CU data incl. header but without initial length. - uint32_t GetLength() const { return m_length; } - uint16_t GetVersion() const { return m_version; } - const DWARFAbbreviationDeclarationSet *GetAbbreviations() const { - return m_abbrevs; - } - dw_offset_t GetAbbrevOffset() const; - uint8_t GetAddressByteSize() const { return m_addr_size; } - 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); - void ClearDIEs(bool keep_compile_unit_die); - void BuildAddressRangeTable(SymbolFileDWARF *dwarf2Data, - DWARFDebugAranges *debug_aranges); - - lldb::ByteOrder GetByteOrder() const; - - lldb_private::TypeSystem *GetTypeSystem(); - - DWARFFormValue::FixedFormSizes GetFixedFormSizes(); - - void SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; } - - DWARFDIE - GetCompileUnitDIEOnly() { return DWARFDIE(this, GetCompileUnitDIEPtrOnly()); } - - DWARFDIE - DIE() { return DWARFDIE(this, DIEPtr()); } - - void AddDIE(DWARFDebugInfoEntry &die) { - // The average bytes per DIE entry has been seen to be - // around 14-20 so lets pre-reserve half of that since - // we are now stripping the NULL tags. - - // Only reserve the memory if we are adding children of - // the main compile unit DIE. The compile unit DIE is always - // the first entry, so if our size is 1, then we are adding - // the first compile unit child DIE and should reserve - // the memory. - if (m_die_array.empty()) - m_die_array.reserve(GetDebugInfoSize() / 24); - m_die_array.push_back(die); - } - - void AddCompileUnitDIE(DWARFDebugInfoEntry &die); - - bool HasDIEsParsed() const { return m_die_array.size() > 1; } - - DWARFDIE - GetDIE(dw_offset_t die_offset); - - static uint8_t GetAddressByteSize(const DWARFCompileUnit *cu); - - static bool IsDWARF64(const DWARFCompileUnit *cu); - - static uint8_t GetDefaultAddressSize(); - - static void SetDefaultAddressSize(uint8_t addr_size); - - void *GetUserData() const { return m_user_data; } - - void SetUserData(void *d); - - bool Supports_DW_AT_APPLE_objc_complete_type(); - - bool DW_AT_decl_file_attributes_are_invalid(); - - bool Supports_unnamed_objc_bitfields(); - - void Index(NameToDIE &func_basenames, NameToDIE &func_fullnames, - NameToDIE &func_methods, NameToDIE &func_selectors, - NameToDIE &objc_class_selectors, NameToDIE &globals, - NameToDIE &types, NameToDIE &namespaces); - - const DWARFDebugAranges &GetFunctionAranges(); - - SymbolFileDWARF *GetSymbolFileDWARF() const { return m_dwarf2Data; } - - Producer GetProducer(); - - uint32_t GetProducerVersionMajor(); - - uint32_t GetProducerVersionMinor(); - - uint32_t GetProducerVersionUpdate(); - - static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val); - - lldb::LanguageType GetLanguageType(); - - bool IsDWARF64() const; - - bool GetIsOptimized(); - - SymbolFileDWARFDwo *GetDwoSymbolFile() const { - return m_dwo_symbol_file.get(); - } - - dw_offset_t GetBaseObjOffset() const { return m_base_obj_offset; } - -protected: - SymbolFileDWARF *m_dwarf2Data; - std::unique_ptr<SymbolFileDWARFDwo> m_dwo_symbol_file; - const DWARFAbbreviationDeclarationSet *m_abbrevs; - void *m_user_data = nullptr; - DWARFDebugInfoEntry::collection - m_die_array; // The compile unit debug information entry item - std::unique_ptr<DWARFDebugAranges> m_func_aranges_ap; // A table similar to - // the .debug_aranges - // table, but this one - // points to the exact - // DW_TAG_subprogram - // DIEs - dw_addr_t m_base_addr = 0; - // Offset of the initial length field. - dw_offset_t m_offset; - dw_offset_t m_length; - uint16_t m_version; - uint8_t m_addr_size; - Producer m_producer = eProducerInvalid; - uint32_t m_producer_version_major = 0; - uint32_t m_producer_version_minor = 0; - uint32_t m_producer_version_update = 0; - lldb::LanguageType m_language_type = lldb::eLanguageTypeUnknown; - bool m_is_dwarf64; - lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; - dw_addr_t m_addr_base = 0; // Value of DW_AT_addr_base - dw_addr_t m_ranges_base = 0; // Value of DW_AT_ranges_base - // 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; - - void ParseProducerInfo(); - - static void - IndexPrivate(DWARFCompileUnit *dwarf_cu, const lldb::LanguageType cu_language, - const DWARFFormValue::FixedFormSizes &fixed_form_sizes, - const dw_offset_t cu_offset, NameToDIE &func_basenames, - NameToDIE &func_fullnames, NameToDIE &func_methods, - NameToDIE &func_selectors, NameToDIE &objc_class_selectors, - NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces); private: DWARFCompileUnit(SymbolFileDWARF *dwarf2Data); - - const DWARFDebugInfoEntry *GetCompileUnitDIEPtrOnly() { - ExtractDIEsIfNeeded(true); - if (m_die_array.empty()) - return NULL; - return &m_die_array[0]; - } - - const DWARFDebugInfoEntry *DIEPtr() { - ExtractDIEsIfNeeded(false); - if (m_die_array.empty()) - return NULL; - return &m_die_array[0]; - } - DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit); }; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index 4ef2e772ea5d..d9754e911017 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -10,43 +10,27 @@ #include "DWARFDIE.h" #include "DWARFASTParser.h" -#include "DWARFCompileUnit.h" #include "DWARFDIECollection.h" -#include "DWARFDebugAbbrev.h" -#include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" #include "DWARFDebugInfoEntry.h" -#include "DWARFDebugRanges.h" #include "DWARFDeclContext.h" -#include "DWARFFormValue.h" -#include "SymbolFileDWARF.h" - -#include "lldb/Core/Module.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/Type.h" -#include "lldb/Symbol/TypeSystem.h" +#include "DWARFUnit.h" using namespace lldb_private; -DIERef DWARFDIE::GetDIERef() const { - if (!IsValid()) - return DIERef(); - - dw_offset_t cu_offset = m_cu->GetOffset(); - if (m_cu->GetBaseObjOffset() != DW_INVALID_OFFSET) - cu_offset = m_cu->GetBaseObjOffset(); - return DIERef(cu_offset, m_die->GetOffset()); -} +void DWARFDIE::ElaboratingDIEIterator::Next() { + assert(!m_worklist.empty() && "Incrementing end iterator?"); -dw_tag_t DWARFDIE::Tag() const { - if (m_die) - return m_die->Tag(); - else - return 0; -} + // Pop the current item from the list. + DWARFDIE die = m_worklist.back(); + m_worklist.pop_back(); -const char *DWARFDIE::GetTagAsCString() const { - return lldb_private::DW_TAG_value_to_name(Tag()); + // And add back any items that elaborate it. + for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) { + if (DWARFDIE d = die.GetReferencedDIE(attr)) + if (m_seen.insert(die.GetID()).second) + m_worklist.push_back(d); + } } DWARFDIE @@ -91,37 +75,10 @@ DWARFDIE::GetDIE(dw_offset_t die_offset) const { return DWARFDIE(); } -const char *DWARFDIE::GetAttributeValueAsString(const dw_attr_t attr, - const char *fail_value) const { - if (IsValid()) - return m_die->GetAttributeValueAsString(GetDWARF(), GetCU(), attr, - fail_value); - else - return fail_value; -} - -uint64_t DWARFDIE::GetAttributeValueAsUnsigned(const dw_attr_t attr, - uint64_t fail_value) const { - if (IsValid()) - return m_die->GetAttributeValueAsUnsigned(GetDWARF(), GetCU(), attr, - fail_value); - else - return fail_value; -} - -int64_t DWARFDIE::GetAttributeValueAsSigned(const dw_attr_t attr, - int64_t fail_value) const { - if (IsValid()) - return m_die->GetAttributeValueAsSigned(GetDWARF(), GetCU(), attr, - fail_value); - else - return fail_value; -} - DWARFDIE DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const { if (IsValid()) { - DWARFCompileUnit *cu = GetCU(); + DWARFUnit *cu = GetCU(); SymbolFileDWARF *dwarf = cu->GetSymbolFileDWARF(); const bool check_specification_or_abstract_origin = true; DWARFFormValue form_value; @@ -132,29 +89,11 @@ DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const { return DWARFDIE(); } -uint64_t DWARFDIE::GetAttributeValueAsReference(const dw_attr_t attr, - uint64_t fail_value) const { - if (IsValid()) - return m_die->GetAttributeValueAsReference(GetDWARF(), GetCU(), attr, - fail_value); - else - return fail_value; -} - -uint64_t DWARFDIE::GetAttributeValueAsAddress(const dw_attr_t attr, - uint64_t fail_value) const { - if (IsValid()) - return m_die->GetAttributeValueAsAddress(GetDWARF(), GetCU(), attr, - fail_value); - else - return fail_value; -} - DWARFDIE DWARFDIE::LookupDeepestBlock(lldb::addr_t file_addr) const { if (IsValid()) { SymbolFileDWARF *dwarf = GetDWARF(); - DWARFCompileUnit *cu = GetCU(); + DWARFUnit *cu = GetCU(); DWARFDebugInfoEntry *function_die = nullptr; DWARFDebugInfoEntry *block_die = nullptr; if (m_die->LookupAddress(file_addr, dwarf, cu, &function_die, &block_die)) { @@ -171,17 +110,6 @@ DWARFDIE::LookupDeepestBlock(lldb::addr_t file_addr) const { return DWARFDIE(); } -lldb::user_id_t DWARFDIE::GetID() const { - return GetDIERef().GetUID(GetDWARF()); -} - -const char *DWARFDIE::GetName() const { - if (IsValid()) - return m_die->GetName(GetDWARF(), m_cu); - else - return nullptr; -} - const char *DWARFDIE::GetMangledName() const { if (IsValid()) return m_die->GetMangledName(GetDWARF(), m_cu); @@ -203,28 +131,6 @@ const char *DWARFDIE::GetQualifiedName(std::string &storage) const { return nullptr; } -lldb::LanguageType DWARFDIE::GetLanguage() const { - if (IsValid()) - return m_cu->GetLanguageType(); - else - return lldb::eLanguageTypeUnknown; -} - -lldb::ModuleSP DWARFDIE::GetModule() const { - SymbolFileDWARF *dwarf = GetDWARF(); - if (dwarf) - return dwarf->GetObjectFile()->GetModule(); - else - return lldb::ModuleSP(); -} - -lldb_private::CompileUnit *DWARFDIE::GetLLDBCompileUnit() const { - if (IsValid()) - return GetDWARF()->GetCompUnitForDWARFCompUnit(GetCU()); - else - return nullptr; -} - lldb_private::Type *DWARFDIE::ResolveType() const { if (IsValid()) return GetDWARF()->ResolveType(*this, true); @@ -262,7 +168,7 @@ void DWARFDIE::GetDWARFDeclContext(DWARFDeclContext &dwarf_decl_ctx) const { void DWARFDIE::GetDWOContext(std::vector<CompilerContext> &context) const { const dw_tag_t tag = Tag(); - if (tag == DW_TAG_compile_unit) + if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) return; DWARFDIE parent = GetParent(); if (parent) @@ -317,45 +223,17 @@ DWARFDIE::GetParentDeclContextDIE() const { return DWARFDIE(); } -dw_offset_t DWARFDIE::GetOffset() const { - if (IsValid()) - return m_die->GetOffset(); - else - return DW_INVALID_OFFSET; -} - -dw_offset_t DWARFDIE::GetCompileUnitRelativeOffset() const { - if (IsValid()) - return m_die->GetOffset() - m_cu->GetOffset(); - else - return DW_INVALID_OFFSET; -} - -SymbolFileDWARF *DWARFDIE::GetDWARF() const { - if (m_cu) - return m_cu->GetSymbolFileDWARF(); - else - return nullptr; -} - -lldb_private::TypeSystem *DWARFDIE::GetTypeSystem() const { - if (m_cu) - return m_cu->GetTypeSystem(); - else - return nullptr; -} - -DWARFASTParser *DWARFDIE::GetDWARFParser() const { - lldb_private::TypeSystem *type_system = GetTypeSystem(); - if (type_system) - return type_system->GetDWARFParser(); - else - return nullptr; +bool DWARFDIE::IsStructUnionOrClass() const { + const dw_tag_t tag = Tag(); + return tag == DW_TAG_class_type || tag == DW_TAG_structure_type || + tag == DW_TAG_union_type; } -bool DWARFDIE::IsStructOrClass() const { - const dw_tag_t tag = Tag(); - return tag == DW_TAG_class_type || tag == DW_TAG_structure_type; +bool DWARFDIE::IsMethod() const { + for (DWARFDIE d: elaborating_dies()) + if (d.GetParent().IsStructUnionOrClass()) + return true; + return false; } DWARFDIE @@ -369,7 +247,7 @@ DWARFDIE::GetContainingDWOModuleDIE() const { const dw_tag_t tag = parent.Tag(); if (tag == DW_TAG_module) top_module_die = parent; - else if (tag == DW_TAG_compile_unit) + else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) break; } @@ -391,25 +269,6 @@ lldb::ModuleSP DWARFDIE::GetContainingDWOModule() const { return lldb::ModuleSP(); } -bool DWARFDIE::HasChildren() const { - return m_die && m_die->HasChildren(); -} - -bool DWARFDIE::Supports_DW_AT_APPLE_objc_complete_type() const { - return IsValid() && GetDWARF()->Supports_DW_AT_APPLE_objc_complete_type(m_cu); -} - -size_t DWARFDIE::GetAttributes(DWARFAttributes &attributes, - uint32_t depth) const { - if (IsValid()) { - return m_die->GetAttributes(m_cu, m_cu->GetFixedFormSizes(), attributes, - depth); - } - if (depth == 0) - attributes.Clear(); - return 0; -} - bool DWARFDIE::GetDIENamesAndRanges( const char *&name, const char *&mangled, DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column, int &call_file, @@ -423,12 +282,6 @@ bool DWARFDIE::GetDIENamesAndRanges( return false; } -void DWARFDIE::Dump(lldb_private::Stream *s, - const uint32_t recurse_depth) const { - if (s && IsValid()) - m_die->Dump(GetDWARF(), GetCU(), *s, recurse_depth); -} - CompilerDecl DWARFDIE::GetDecl() const { DWARFASTParser *dwarf_ast = GetDWARFParser(); if (dwarf_ast) @@ -452,11 +305,3 @@ CompilerDeclContext DWARFDIE::GetContainingDeclContext() const { else return CompilerDeclContext(); } - -bool operator==(const DWARFDIE &lhs, const DWARFDIE &rhs) { - return lhs.GetDIE() == rhs.GetDIE() && lhs.GetCU() == rhs.GetCU(); -} - -bool operator!=(const DWARFDIE &lhs, const DWARFDIE &rhs) { - return !(lhs == rhs); -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index 8af3015b9d76..ecbf4912634e 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -10,115 +10,41 @@ #ifndef SymbolFileDWARF_DWARFDIE_h_ #define SymbolFileDWARF_DWARFDIE_h_ -#include "lldb/Core/dwarf.h" -#include "lldb/lldb-types.h" - -struct DIERef; -class DWARFASTParser; -class DWARFAttributes; -class DWARFCompileUnit; -class DWARFDebugInfoEntry; -class DWARFDeclContext; -class DWARFDIECollection; -class SymbolFileDWARF; - -class DWARFDIE { -public: - DWARFDIE() : m_cu(nullptr), m_die(nullptr) {} - - DWARFDIE(DWARFCompileUnit *cu, DWARFDebugInfoEntry *die) - : m_cu(cu), m_die(die) {} - - DWARFDIE(const DWARFCompileUnit *cu, DWARFDebugInfoEntry *die) - : m_cu(const_cast<DWARFCompileUnit *>(cu)), m_die(die) {} +#include "DWARFBaseDIE.h" +#include "llvm/ADT/SmallSet.h" - DWARFDIE(DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) - : m_cu(cu), m_die(const_cast<DWARFDebugInfoEntry *>(die)) {} +class DWARFDIE : public DWARFBaseDIE { +public: + class ElaboratingDIEIterator; - DWARFDIE(const DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) - : m_cu(const_cast<DWARFCompileUnit *>(cu)), - m_die(const_cast<DWARFDebugInfoEntry *>(die)) {} + using DWARFBaseDIE::DWARFBaseDIE; //---------------------------------------------------------------------- // Tests //---------------------------------------------------------------------- - explicit operator bool() const { return IsValid(); } - - bool IsValid() const { return m_cu && m_die; } - - bool IsStructOrClass() const; + bool IsStructUnionOrClass() const; - bool HasChildren() const; - - bool Supports_DW_AT_APPLE_objc_complete_type() const; + bool IsMethod() const; //---------------------------------------------------------------------- // Accessors //---------------------------------------------------------------------- - SymbolFileDWARF *GetDWARF() const; - - DWARFCompileUnit *GetCU() const { return m_cu; } - - DWARFDebugInfoEntry *GetDIE() const { return m_die; } - - DIERef GetDIERef() const; - - lldb_private::TypeSystem *GetTypeSystem() const; - - DWARFASTParser *GetDWARFParser() const; - - void Set(DWARFCompileUnit *cu, DWARFDebugInfoEntry *die) { - if (cu && die) { - m_cu = cu; - m_die = die; - } else { - Clear(); - } - } - - void Clear() { - m_cu = nullptr; - m_die = nullptr; - } - lldb::ModuleSP GetContainingDWOModule() const; DWARFDIE GetContainingDWOModuleDIE() const; - //---------------------------------------------------------------------- - // Accessing information about a DIE - //---------------------------------------------------------------------- - dw_tag_t Tag() const; - - const char *GetTagAsCString() const; - - dw_offset_t GetOffset() const; - - dw_offset_t GetCompileUnitRelativeOffset() const; + inline llvm::iterator_range<ElaboratingDIEIterator> elaborating_dies() const; //---------------------------------------------------------------------- - // Get the LLDB user ID for this DIE. This is often just the DIE offset, - // but it might have a SymbolFileDWARF::GetID() in the high 32 bits if - // we are doing Darwin DWARF in .o file, or DWARF stand alone debug - // info. + // Accessing information about a DIE //---------------------------------------------------------------------- - lldb::user_id_t GetID() const; - - const char *GetName() const; - const char *GetMangledName() const; const char *GetPubname() const; const char *GetQualifiedName(std::string &storage) const; - lldb::LanguageType GetLanguage() const; - - lldb::ModuleSP GetModule() const; - - lldb_private::CompileUnit *GetLLDBCompileUnit() const; - lldb_private::Type *ResolveType() const; //---------------------------------------------------------------------- @@ -149,6 +75,7 @@ public: //---------------------------------------------------------------------- DWARFDIE GetDIE(dw_offset_t die_offset) const; + using DWARFBaseDIE::GetDIE; DWARFDIE LookupDeepestBlock(lldb::addr_t file_addr) const; @@ -172,26 +99,9 @@ public: // looking for one or two attributes on a DIE. If you are trying to // parse all attributes, use GetAttributes (...) instead //---------------------------------------------------------------------- - const char *GetAttributeValueAsString(const dw_attr_t attr, - const char *fail_value) const; - - uint64_t GetAttributeValueAsUnsigned(const dw_attr_t attr, - uint64_t fail_value) const; - - int64_t GetAttributeValueAsSigned(const dw_attr_t attr, - int64_t fail_value) const; - - uint64_t GetAttributeValueAsReference(const dw_attr_t attr, - uint64_t fail_value) const; - DWARFDIE GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const; - uint64_t GetAttributeValueAsAddress(const dw_attr_t attr, - uint64_t fail_value) const; - - size_t GetAttributes(DWARFAttributes &attributes, uint32_t depth = 0) const; - bool GetDIENamesAndRanges(const char *&name, const char *&mangled, DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column, int &call_file, @@ -199,23 +109,68 @@ public: lldb_private::DWARFExpression *frame_base) const; //---------------------------------------------------------------------- - // Pretty printing + // CompilerDecl related functions //---------------------------------------------------------------------- - void Dump(lldb_private::Stream *s, const uint32_t recurse_depth) const; - lldb_private::CompilerDecl GetDecl() const; lldb_private::CompilerDeclContext GetDeclContext() const; lldb_private::CompilerDeclContext GetContainingDeclContext() const; +}; + +/// Iterate through all DIEs elaborating (i.e. reachable by a chain of +/// DW_AT_specification and DW_AT_abstract_origin attributes) a given DIE. For +/// convenience, the starting die is included in the sequence as the first +/// item. +class DWARFDIE::ElaboratingDIEIterator + : public std::iterator<std::input_iterator_tag, DWARFDIE> { + + // The operating invariant is: top of m_worklist contains the "current" item + // and the rest of the list are items yet to be visited. An empty worklist + // means we've reached the end. + // Infinite recursion is prevented by maintaining a list of seen DIEs. + // Container sizes are optimized for the case of following DW_AT_specification + // and DW_AT_abstract_origin just once. + llvm::SmallVector<DWARFDIE, 2> m_worklist; + llvm::SmallSet<lldb::user_id_t, 3> m_seen; + + void Next(); + +public: + /// An iterator starting at die d. + explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {} -protected: - DWARFCompileUnit *m_cu; - DWARFDebugInfoEntry *m_die; + /// End marker + ElaboratingDIEIterator() {} + + const DWARFDIE &operator*() const { return m_worklist.back(); } + ElaboratingDIEIterator &operator++() { + Next(); + return *this; + } + ElaboratingDIEIterator operator++(int) { + ElaboratingDIEIterator I = *this; + Next(); + return I; + } + + friend bool operator==(const ElaboratingDIEIterator &a, + const ElaboratingDIEIterator &b) { + if (a.m_worklist.empty() || b.m_worklist.empty()) + return a.m_worklist.empty() == b.m_worklist.empty(); + return a.m_worklist.back() == b.m_worklist.back(); + } + friend bool operator!=(const ElaboratingDIEIterator &a, + const ElaboratingDIEIterator &b) { + return !(a == b); + } }; -bool operator==(const DWARFDIE &lhs, const DWARFDIE &rhs); -bool operator!=(const DWARFDIE &lhs, const DWARFDIE &rhs); +llvm::iterator_range<DWARFDIE::ElaboratingDIEIterator> +DWARFDIE::elaborating_dies() const { + return llvm::make_range(ElaboratingDIEIterator(*this), + ElaboratingDIEIterator()); +} #endif // SymbolFileDWARF_DWARFDIE_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp index 0c807d7d604b..2fcdd34d532f 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp @@ -22,6 +22,6 @@ DWARFDataExtractor::GetDWARFInitialLength(lldb::offset_t *offset_ptr) const { dw_offset_t DWARFDataExtractor::GetDWARFOffset(lldb::offset_t *offset_ptr) const { - return GetMaxU64(offset_ptr, m_is_dwarf64 ? 8 : 4); + return GetMaxU64(offset_ptr, GetDWARFSizeOfOffset()); } } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h index 46d09f1ca237..ce0bfb3931d5 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h @@ -29,7 +29,7 @@ public: dw_offset_t GetDWARFOffset(lldb::offset_t *offset_ptr) const; size_t GetDWARFSizeofInitialLength() const { return m_is_dwarf64 ? 12 : 4; } - + size_t GetDWARFSizeOfOffset() const { return m_is_dwarf64 ? 8 : 4; } bool IsDWARF64() const { return m_is_dwarf64; } protected: diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp index 1cf0e7eeeb60..affe4b85bdab 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp @@ -80,8 +80,8 @@ DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration( //---------------------------------------------------------------------- // DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential() // -// Append an abbreviation declaration with a sequential code for O(n) -// lookups. Handy when creating an DWARFAbbreviationDeclarationSet. +// Append an abbreviation declaration with a sequential code for O(n) lookups. +// Handy when creating an DWARFAbbreviationDeclarationSet. //---------------------------------------------------------------------- dw_uleb128_t DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential( const DWARFAbbreviationDeclaration &abbrevDecl) { @@ -115,9 +115,9 @@ void DWARFAbbreviationDeclarationSet::GetUnsupportedForms( //---------------------------------------------------------------------- // Encode // -// Encode the abbreviation table onto the end of the buffer provided -// into a byte representation as would be found in a ".debug_abbrev" -// debug information section. +// Encode the abbreviation table onto the end of the buffer provided into a +// byte representation as would be found in a ".debug_abbrev" debug information +// section. //---------------------------------------------------------------------- // void // DWARFAbbreviationDeclarationSet::Encode(BinaryStreamBuf& debug_abbrev_buf) diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp index cecb69c8fb46..00265361f865 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp @@ -46,19 +46,17 @@ void DWARFDebugArangeSet::Compact() { if (m_arange_descriptors.empty()) return; - // Iterate through all arange descriptors and combine any ranges that - // overlap or have matching boundaries. The m_arange_descriptors are assumed - // to be in ascending order after being built by adding descriptors - // using the AddDescriptor method. + // Iterate through all arange descriptors and combine any ranges that overlap + // or have matching boundaries. The m_arange_descriptors are assumed to be in + // ascending order after being built by adding descriptors using the + // AddDescriptor method. uint32_t i = 0; while (i + 1 < m_arange_descriptors.size()) { if (m_arange_descriptors[i].end_address() >= m_arange_descriptors[i + 1].address) { // The current range ends at or exceeds the start of the next address - // range. - // Compute the max end address between the two and use that to make the - // new - // length. + // range. Compute the max end address between the two and use that to + // make the new length. const dw_addr_t max_end_addr = std::max(m_arange_descriptors[i].end_address(), m_arange_descriptors[i + 1].end_address()); @@ -82,8 +80,8 @@ static bool DescriptorLessThan(const DWARFDebugArangeSet::Descriptor &range1, } //---------------------------------------------------------------------- -// Add a range descriptor and keep things sorted so we can easily -// compact the ranges before being saved or used. +// Add a range descriptor and keep things sorted so we can easily compact the +// ranges before being saved or used. //---------------------------------------------------------------------- void DWARFDebugArangeSet::AddDescriptor( const DWARFDebugArangeSet::Descriptor &range) { @@ -103,15 +101,14 @@ void DWARFDebugArangeSet::AddDescriptor( // Non-contiguous entries, add this one before the found entry m_arange_descriptors.insert(pos, range); } else if (range_end_addr == pos->address) { - // The top end of 'range' is the lower end of the entry - // pointed to by 'pos'. We can combine range with the - // entry we found by setting the starting address and - // increasing the length since they don't overlap. + // The top end of 'range' is the lower end of the entry pointed to by + // 'pos'. We can combine range with the entry we found by setting the + // starting address and increasing the length since they don't overlap. pos->address = range.address; pos->length += range.length; } else { - // We can combine these two and make sure the largest end - // address is used to make end address. + // We can combine these two and make sure the largest end address is + // used to make end address. pos->address = range.address; pos->length = std::max(found_end_addr, range_end_addr) - pos->address; } @@ -142,18 +139,18 @@ bool DWARFDebugArangeSet::Extract(const DWARFDataExtractor &data, // 7.20 Address Range Table // - // Each set of entries in the table of address ranges contained in - // the .debug_aranges section begins with a header consisting of: a - // 4-byte length containing the length of the set of entries for this - // compilation unit, not including the length field itself; a 2-byte - // version identifier containing the value 2 for DWARF Version 2; a - // 4-byte offset into the.debug_infosection; a 1-byte unsigned integer - // containing the size in bytes of an address (or the offset portion of - // an address for segmented addressing) on the target system; and a - // 1-byte unsigned integer containing the size in bytes of a segment - // descriptor on the target system. This header is followed by a series - // of tuples. Each tuple consists of an address and a length, each in - // the size appropriate for an address on the target architecture. + // Each set of entries in the table of address ranges contained in the + // .debug_aranges section begins with a header consisting of: a 4-byte + // length containing the length of the set of entries for this compilation + // unit, not including the length field itself; a 2-byte version identifier + // containing the value 2 for DWARF Version 2; a 4-byte offset into + // the.debug_infosection; a 1-byte unsigned integer containing the size in + // bytes of an address (or the offset portion of an address for segmented + // addressing) on the target system; and a 1-byte unsigned integer + // containing the size in bytes of a segment descriptor on the target + // system. This header is followed by a series of tuples. Each tuple + // consists of an address and a length, each in the size appropriate for an + // address on the target architecture. m_header.length = data.GetDWARFInitialLength(offset_ptr); m_header.version = data.GetU16(offset_ptr); m_header.cu_offset = data.GetDWARFOffset(offset_ptr); @@ -195,8 +192,8 @@ bool DWARFDebugArangeSet::Extract(const DWARFDataExtractor &data, arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size); - // Each set of tuples is terminated by a 0 for the address and 0 - // for the length. + // Each set of tuples is terminated by a 0 for the address and 0 for + // the length. if (arangeDescriptor.address || arangeDescriptor.length) m_arange_descriptors.push_back(arangeDescriptor); else diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp index 13c2d8726821..02f528d571b0 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -18,7 +18,7 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfo.h" #include "LogChannelDWARF.h" #include "SymbolFileDWARF.h" @@ -82,7 +82,7 @@ bool DWARFDebugAranges::Generate(SymbolFileDWARF *dwarf2Data) { uint32_t cu_idx = 0; const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFCompileUnit *cu = debug_info->GetCompileUnitAtIndex(cu_idx); + DWARFUnit *cu = debug_info->GetCompileUnitAtIndex(cu_idx); if (cu) cu->BuildAddressRangeTable(dwarf2Data, this); } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index 9c0f1d3c8905..dadc30dc918a 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -72,7 +72,7 @@ DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() { bool printed = false; const size_t num_compile_units = GetNumCompileUnits(); for (size_t idx = 0; idx < num_compile_units; ++idx) { - DWARFCompileUnit *cu = GetCompileUnitAtIndex(idx); + DWARFUnit *cu = GetCompileUnitAtIndex(idx); dw_offset_t offset = cu->GetOffset(); if (cus_with_data.find(offset) == cus_with_data.end()) { @@ -97,8 +97,10 @@ void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() { if (m_compile_units.empty()) { if (m_dwarf2Data != NULL) { lldb::offset_t offset = 0; - DWARFCompileUnitSP cu_sp; - while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, &offset))) { + DWARFUnitSP cu_sp; + const auto &debug_info_data = m_dwarf2Data->get_debug_info_data(); + while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, debug_info_data, + &offset))) { m_compile_units.push_back(cu_sp); offset = cu_sp->GetNextCompileUnitOffset(); @@ -112,16 +114,16 @@ size_t DWARFDebugInfo::GetNumCompileUnits() { return m_compile_units.size(); } -DWARFCompileUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) { - DWARFCompileUnit *cu = NULL; +DWARFUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) { + DWARFUnit *cu = NULL; if (idx < GetNumCompileUnits()) cu = m_compile_units[idx].get(); return cu; } -bool DWARFDebugInfo::ContainsCompileUnit(const DWARFCompileUnit *cu) const { - // Not a verify efficient function, but it is handy for use in assertions - // to make sure that a compile unit comes from a debug information file. +bool DWARFDebugInfo::ContainsCompileUnit(const DWARFUnit *cu) const { + // Not a verify efficient function, but it is handy for use in assertions to + // make sure that a compile unit comes from a debug information file. CompileUnitColl::const_iterator end_pos = m_compile_units.end(); CompileUnitColl::const_iterator pos; @@ -133,13 +135,13 @@ bool DWARFDebugInfo::ContainsCompileUnit(const DWARFCompileUnit *cu) const { } bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset( - dw_offset_t offset, const DWARFCompileUnitSP &cu_sp) { + dw_offset_t offset, const DWARFUnitSP &cu_sp) { return offset < cu_sp->GetOffset(); } -DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, +DWARFUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t *idx_ptr) { - DWARFCompileUnitSP cu_sp; + DWARFUnitSP cu_sp; uint32_t cu_idx = DW_INVALID_INDEX; if (cu_offset != DW_INVALID_OFFSET) { ParseCompileUnitHeadersIfNeeded(); @@ -170,18 +172,18 @@ DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, return cu_sp.get(); } -DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) { +DWARFUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) { if (die_ref.cu_offset == DW_INVALID_OFFSET) return GetCompileUnitContainingDIEOffset(die_ref.die_offset); else return GetCompileUnit(die_ref.cu_offset); } -DWARFCompileUnit * +DWARFUnit * DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) { ParseCompileUnitHeadersIfNeeded(); - DWARFCompileUnitSP cu_sp; + DWARFUnitSP cu_sp; // Watch out for single compile unit executable as they are pretty common const size_t num_cus = m_compile_units.size(); @@ -205,7 +207,7 @@ DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) { DWARFDIE DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) { - DWARFCompileUnit *cu = GetCompileUnitContainingDIEOffset(die_offset); + DWARFUnit *cu = GetCompileUnitContainingDIEOffset(die_offset); if (cu) return cu->GetDIE(die_offset); return DWARFDIE(); @@ -218,275 +220,9 @@ DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) { //---------------------------------------------------------------------- DWARFDIE DWARFDebugInfo::GetDIE(const DIERef &die_ref) { - DWARFCompileUnit *cu = GetCompileUnit(die_ref); + DWARFUnit *cu = GetCompileUnit(die_ref); if (cu) return cu->GetDIE(die_ref.die_offset); return DWARFDIE(); // Not found } -//---------------------------------------------------------------------- -// Parse -// -// Parses the .debug_info section and uses the .debug_abbrev section -// and various other sections in the SymbolFileDWARF class and calls the -// supplied callback function each time a compile unit header, or debug -// information entry is successfully parsed. This function can be used -// for different tasks such as parsing the file contents into a -// structured data, dumping, verifying and much more. -//---------------------------------------------------------------------- -void DWARFDebugInfo::Parse(SymbolFileDWARF *dwarf2Data, Callback callback, - void *userData) { - if (dwarf2Data) { - lldb::offset_t offset = 0; - uint32_t depth = 0; - DWARFDebugInfoEntry die; - - DWARFCompileUnitSP cu; - while ((cu = DWARFCompileUnit::Extract(dwarf2Data, &offset))) { - const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset(); - - depth = 0; - // Call the callback function with no DIE pointer for the compile unit - // and get the offset that we are to continue to parse from - offset = callback(dwarf2Data, cu.get(), NULL, offset, depth, userData); - - // Make sure we are within our compile unit - if (offset < next_cu_offset) { - // We are in our compile unit, parse starting at the offset - // we were told to parse - bool done = false; - while (!done && die.Extract(dwarf2Data, cu.get(), &offset)) { - // Call the callback function with DIE pointer that falls within the - // compile unit - offset = - callback(dwarf2Data, cu.get(), &die, offset, depth, userData); - - if (die.IsNULL()) { - if (depth) - --depth; - else - done = true; // We are done with this compile unit! - } else if (die.HasChildren()) - ++depth; - } - } - - // Make sure the offset returned is valid, and if not stop parsing. - // Returning DW_INVALID_OFFSET from this callback is a good way to end - // all parsing - if (!dwarf2Data->get_debug_info_data().ValidOffset(offset)) - break; - - // Make sure we start on a proper - offset = next_cu_offset; - } - } -} - -typedef struct DumpInfo { - DumpInfo(Stream *init_strm, uint32_t off, uint32_t depth) - : strm(init_strm), die_offset(off), recurse_depth(depth), - found_depth(UINT32_MAX), found_die(false), ancestors() {} - Stream *strm; - const uint32_t die_offset; - const uint32_t recurse_depth; - uint32_t found_depth; - bool found_die; - std::vector<DWARFDebugInfoEntry> ancestors; - - DISALLOW_COPY_AND_ASSIGN(DumpInfo); -} DumpInfo; - -//---------------------------------------------------------------------- -// DumpCallback -// -// A callback function for the static DWARFDebugInfo::Parse() function -// that gets called each time a compile unit header or debug information -// entry is successfully parsed. -// -// This function dump DWARF information and obey recurse depth and -// whether a single DIE is to be dumped (or all of the data). -//---------------------------------------------------------------------- -static dw_offset_t DumpCallback(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, DWARFDebugInfoEntry *die, - const dw_offset_t next_offset, - const uint32_t curr_depth, void *userData) { - DumpInfo *dumpInfo = (DumpInfo *)userData; - Stream *s = dumpInfo->strm; - bool show_parents = - s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors); - - if (die) { - // Are we dumping everything? - if (dumpInfo->die_offset == DW_INVALID_OFFSET) { - // Yes we are dumping everything. Obey our recurse level though - if (curr_depth < dumpInfo->recurse_depth) - die->Dump(dwarf2Data, cu, *s, 0); - } else { - // We are dumping a specific DIE entry by offset - if (dumpInfo->die_offset == die->GetOffset()) { - // We found the DIE we were looking for, dump it! - if (show_parents) { - s->SetIndentLevel(0); - const uint32_t num_ancestors = dumpInfo->ancestors.size(); - if (num_ancestors > 0) { - for (uint32_t i = 0; i < num_ancestors - 1; ++i) { - dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0); - s->IndentMore(); - } - } - } - - dumpInfo->found_depth = curr_depth; - - die->Dump(dwarf2Data, cu, *s, 0); - - // Note that we found the DIE we were looking for - dumpInfo->found_die = true; - - // Since we are dumping a single DIE, if there are no children we are - // done! - if (!die->HasChildren() || dumpInfo->recurse_depth == 0) - return DW_INVALID_OFFSET; // Return an invalid address to end parsing - } else if (dumpInfo->found_die) { - // Are we done with all the children? - if (curr_depth <= dumpInfo->found_depth) - return DW_INVALID_OFFSET; - - // We have already found our DIE and are printing it's children. Obey - // our recurse depth and return an invalid offset if we get done - // dumping all of the children - if (dumpInfo->recurse_depth == UINT32_MAX || - curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth) - die->Dump(dwarf2Data, cu, *s, 0); - } else if (dumpInfo->die_offset > die->GetOffset()) { - if (show_parents) - dumpInfo->ancestors.back() = *die; - } - } - - // Keep up with our indent level - if (die->IsNULL()) { - if (show_parents) - dumpInfo->ancestors.pop_back(); - - if (curr_depth <= 1) - return cu->GetNextCompileUnitOffset(); - else - s->IndentLess(); - } else if (die->HasChildren()) { - if (show_parents) { - DWARFDebugInfoEntry null_die; - dumpInfo->ancestors.push_back(null_die); - } - s->IndentMore(); - } - } else { - if (cu == NULL) - s->PutCString("NULL - cu"); - // We have a compile unit, reset our indent level to zero just in case - s->SetIndentLevel(0); - - // See if we are dumping everything? - if (dumpInfo->die_offset == DW_INVALID_OFFSET) { - // We are dumping everything - if (cu) { - cu->Dump(s); - return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this - // Compile Unit - } else { - return DW_INVALID_OFFSET; - } - } else { - if (show_parents) { - dumpInfo->ancestors.clear(); - dumpInfo->ancestors.resize(1); - } - - // We are dumping only a single DIE possibly with it's children and - // we must find it's compile unit before we can dump it properly - if (cu && dumpInfo->die_offset < cu->GetFirstDIEOffset()) { - // Not found, maybe the DIE offset provided wasn't correct? - // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " - // was not found." << endl; - return DW_INVALID_OFFSET; - } else { - // See if the DIE is in this compile unit? - if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) { - return next_offset; - // // We found our compile unit that contains our DIE, just skip to - // dumping the requested DIE... - // return dumpInfo->die_offset; - } else { - // Skip to the next compile unit as the DIE isn't in the current one! - if (cu) { - return cu->GetNextCompileUnitOffset(); - } else { - return DW_INVALID_OFFSET; - } - } - } - } - } - - // Just return the current offset to parse the next CU or DIE entry - return next_offset; -} - -//---------------------------------------------------------------------- -// Dump -// -// Dump the information in the .debug_info section to the specified -// ostream. If die_offset is valid, a single DIE will be dumped. If the -// die_offset is invalid, all the DWARF information will be dumped. Both -// cases will obey a "recurse_depth" or how deep to traverse into the -// children of each DIE entry. A recurse_depth of zero will dump all -// compile unit headers. A recurse_depth of 1 will dump all compile unit -// headers and the DW_TAG_compile unit tags. A depth of 2 will also -// dump all types and functions. -//---------------------------------------------------------------------- -void DWARFDebugInfo::Dump(Stream *s, SymbolFileDWARF *dwarf2Data, - const uint32_t die_offset, - const uint32_t recurse_depth) { - DumpInfo dumpInfo(s, die_offset, recurse_depth); - s->PutCString(".debug_info contents"); - if (dwarf2Data->get_debug_info_data().GetByteSize() > 0) { - if (die_offset == DW_INVALID_OFFSET) - s->PutCString(":\n"); - else { - s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset); - if (recurse_depth != UINT32_MAX) - s->Printf(" recursing %u levels deep.", recurse_depth); - s->EOL(); - } - } else { - s->PutCString(": < EMPTY >\n"); - return; - } - DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo); -} - -//---------------------------------------------------------------------- -// Dump -// -// Dump the contents of this DWARFDebugInfo object as has been parsed -// and/or modified after it has been parsed. -//---------------------------------------------------------------------- -void DWARFDebugInfo::Dump(Stream *s, const uint32_t die_offset, - const uint32_t recurse_depth) { - DumpInfo dumpInfo(s, die_offset, recurse_depth); - - s->PutCString("Dumping .debug_info section from internal representation\n"); - - CompileUnitColl::const_iterator pos; - uint32_t curr_depth = 0; - ParseCompileUnitHeadersIfNeeded(); - for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos) { - DWARFCompileUnit *cu = pos->get(); - DumpCallback(m_dwarf2Data, cu, NULL, 0, curr_depth, &dumpInfo); - - const DWARFDIE die = cu->DIE(); - if (die) - die.Dump(s, recurse_depth); - } -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index 14c7d767d05b..fc6085f99a21 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -13,6 +13,7 @@ #include <map> #include <vector> +#include "DWARFUnit.h" #include "DWARFDIE.h" #include "SymbolFileDWARF.h" #include "lldb/Core/STLUtils.h" @@ -26,7 +27,7 @@ typedef CStringToDIEMap::const_iterator CStringToDIEMapConstIter; class DWARFDebugInfo { public: typedef dw_offset_t (*Callback)(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, DWARFDebugInfoEntry *die, const dw_offset_t next_offset, const uint32_t depth, void *userData); @@ -35,22 +36,14 @@ public: void SetDwarfData(SymbolFileDWARF *dwarf2Data); size_t GetNumCompileUnits(); - bool ContainsCompileUnit(const DWARFCompileUnit *cu) const; - DWARFCompileUnit *GetCompileUnitAtIndex(uint32_t idx); - DWARFCompileUnit *GetCompileUnit(dw_offset_t cu_offset, - uint32_t *idx_ptr = NULL); - DWARFCompileUnit *GetCompileUnitContainingDIEOffset(dw_offset_t die_offset); - DWARFCompileUnit *GetCompileUnit(const DIERef &die_ref); + bool ContainsCompileUnit(const DWARFUnit *cu) const; + DWARFUnit *GetCompileUnitAtIndex(uint32_t idx); + DWARFUnit *GetCompileUnit(dw_offset_t cu_offset, uint32_t *idx_ptr = NULL); + DWARFUnit *GetCompileUnitContainingDIEOffset(dw_offset_t die_offset); + DWARFUnit *GetCompileUnit(const DIERef &die_ref); DWARFDIE GetDIEForDIEOffset(dw_offset_t die_offset); DWARFDIE GetDIE(const DIERef &die_ref); - void Dump(lldb_private::Stream *s, const uint32_t die_offset, - const uint32_t recurse_depth); - static void Parse(SymbolFileDWARF *parser, Callback callback, void *userData); - static void Verify(lldb_private::Stream *s, SymbolFileDWARF *dwarf2Data); - static void Dump(lldb_private::Stream *s, SymbolFileDWARF *dwarf2Data, - const uint32_t die_offset, const uint32_t recurse_depth); - enum { eDumpFlag_Verbose = (1 << 0), // Verbose dumping eDumpFlag_ShowForm = (1 << 1), // Show the DW_form type @@ -62,9 +55,9 @@ public: protected: static bool OffsetLessThanCompileUnitOffset(dw_offset_t offset, - const DWARFCompileUnitSP &cu_sp); + const DWARFUnitSP &cu_sp); - typedef std::vector<DWARFCompileUnitSP> CompileUnitColl; + typedef std::vector<DWARFUnitSP> CompileUnitColl; //---------------------------------------------------------------------- // Member variables diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index f595bd83d846..d32aef6e162c 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -18,7 +18,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/Stream.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDIECollection.h" #include "DWARFDebugAbbrev.h" #include "DWARFDebugAranges.h" @@ -34,7 +34,7 @@ using namespace std; extern int g_verbose; bool DWARFDebugInfoEntry::FastExtract( - const DWARFDataExtractor &debug_info_data, const DWARFCompileUnit *cu, + const DWARFDataExtractor &debug_info_data, const DWARFUnit *cu, const DWARFFormValue::FixedFormSizes &fixed_form_sizes, lldb::offset_t *offset_ptr) { m_offset = *offset_ptr; @@ -189,14 +189,14 @@ bool DWARFDebugInfoEntry::FastExtract( //---------------------------------------------------------------------- // Extract // -// Extract a debug info entry for a given compile unit from the -// .debug_info and .debug_abbrev data within the SymbolFileDWARF class -// starting at the given offset +// Extract a debug info entry for a given compile unit from the .debug_info and +// .debug_abbrev data within the SymbolFileDWARF class starting at the given +// offset //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, lldb::offset_t *offset_ptr) { - const DWARFDataExtractor &debug_info_data = dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); // const DWARFDataExtractor& debug_str_data = // dwarf2Data->get_debug_str_data(); const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset(); @@ -218,9 +218,10 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, m_tag = abbrevDecl->Tag(); m_has_children = abbrevDecl->HasChildren(); - bool isCompileUnitTag = m_tag == DW_TAG_compile_unit; + bool isCompileUnitTag = (m_tag == DW_TAG_compile_unit || + m_tag == DW_TAG_partial_unit); if (cu && isCompileUnitTag) - const_cast<DWARFCompileUnit *>(cu)->SetBaseAddress(0); + const_cast<DWARFUnit *>(cu)->SetBaseAddress(0); // Skip all data in the .debug_info for the attributes const uint32_t numAttributes = abbrevDecl->NumAttributes(); @@ -235,7 +236,7 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, 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<DWARFCompileUnit *>(cu)->SetBaseAddress( + const_cast<DWARFUnit *>(cu)->SetBaseAddress( form_value.Address()); } } else { @@ -245,8 +246,7 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, uint32_t form_size = 0; switch (form) { // Blocks if inlined data that have a length field and the data - // bytes - // inlined in the .debug_info + // bytes inlined in the .debug_info case DW_FORM_exprloc: case DW_FORM_block: form_size = debug_info_data.GetULEB128(&offset); @@ -356,11 +356,11 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, //---------------------------------------------------------------------- // DumpAncestry // -// Dumps all of a debug information entries parents up until oldest and -// all of it's attributes to the specified stream. +// Dumps all of a debug information entries parents up until oldest and all of +// it's attributes to the specified stream. //---------------------------------------------------------------------- void DWARFDebugInfoEntry::DumpAncestry(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, const DWARFDebugInfoEntry *oldest, Stream &s, uint32_t recurse_depth) const { @@ -374,11 +374,10 @@ void DWARFDebugInfoEntry::DumpAncestry(SymbolFileDWARF *dwarf2Data, // GetDIENamesAndRanges // // Gets the valid address ranges for a given DIE by looking for a -// DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges -// attributes. +// DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges attributes. //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::GetDIENamesAndRanges( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, const char *&name, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const char *&name, const char *&mangled, DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column, int &call_file, int &call_line, int &call_column, DWARFExpression *frame_base) const { @@ -404,8 +403,7 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( lldb::ModuleSP module = dwarf2Data->GetObjectFile()->GetModule(); if (abbrevDecl) { - const DWARFDataExtractor &debug_info_data = - dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); if (!debug_info_data.ValidOffset(offset)) return false; @@ -451,9 +449,9 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( 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. + // 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 { cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()->ReportError( @@ -582,13 +580,13 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( //---------------------------------------------------------------------- // Dump // -// Dumps a debug information entry and all of it's attributes to the -// specified stream. +// Dumps a debug information entry and all of it's attributes to the specified +// stream. //---------------------------------------------------------------------- void DWARFDebugInfoEntry::Dump(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, Stream &s, + const DWARFUnit *cu, Stream &s, uint32_t recurse_depth) const { - const DWARFDataExtractor &debug_info_data = dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); lldb::offset_t offset = m_offset; if (debug_info_data.ValidOffset(offset)) { @@ -639,8 +637,8 @@ void DWARFDebugInfoEntry::Dump(SymbolFileDWARF *dwarf2Data, } void DWARFDebugInfoEntry::DumpLocation(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, Stream &s) const { - const DWARFDIE cu_die = cu->GetCompileUnitDIEOnly(); + DWARFUnit *cu, Stream &s) const { + const DWARFBaseDIE cu_die = cu->GetUnitDIEOnly(); const char *cu_name = NULL; if (cu_die) cu_name = cu_die.GetName(); @@ -658,12 +656,12 @@ void DWARFDebugInfoEntry::DumpLocation(SymbolFileDWARF *dwarf2Data, //---------------------------------------------------------------------- // DumpAttribute // -// Dumps a debug information entry attribute along with it's form. Any -// special display of attributes is done (disassemble location lists, -// show enumeration values for attributes, etc). +// Dumps a debug information entry attribute along with it's form. Any special +// display of attributes is done (disassemble location lists, show enumeration +// values for attributes, etc). //---------------------------------------------------------------------- void DWARFDebugInfoEntry::DumpAttribute( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + 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) { bool show_form = s.GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowForm); @@ -714,11 +712,10 @@ void DWARFDebugInfoEntry::DumpAttribute( (*offset_ptr) - form_value.Unsigned(), form_value.Unsigned()); DWARFExpression::PrintDWARFExpression( - s, locationData, DWARFCompileUnit::GetAddressByteSize(cu), 4, false); + s, locationData, DWARFUnit::GetAddressByteSize(cu), 4, false); } else { - // We have a location list offset as the value that is - // the offset into the .debug_loc section that describes - // the value over it's lifetime + // We have a location list offset as the value that is the offset into + // the .debug_loc section that describes the value over it's lifetime uint64_t debug_loc_offset = form_value.Unsigned(); if (dwarf2Data) { DWARFExpression::PrintDWARFLocationList( @@ -759,18 +756,18 @@ void DWARFDebugInfoEntry::DumpAttribute( //---------------------------------------------------------------------- // Get all attribute values for a given DIE, including following any -// specification or abstract origin attributes and including those in -// the results. Any duplicate attributes will have the first instance -// take precedence (this can happen for declaration attributes). +// specification or abstract origin attributes and including those in the +// results. Any duplicate attributes will have the first instance take +// precedence (this can happen for declaration attributes). //---------------------------------------------------------------------- size_t DWARFDebugInfoEntry::GetAttributes( - const DWARFCompileUnit *cu, DWARFFormValue::FixedFormSizes fixed_form_sizes, + const DWARFUnit *cu, DWARFFormValue::FixedFormSizes fixed_form_sizes, DWARFAttributes &attributes, uint32_t curr_depth) const { SymbolFileDWARF *dwarf2Data = nullptr; const DWARFAbbreviationDeclaration *abbrevDecl = nullptr; lldb::offset_t offset = 0; if (cu) { - if (m_tag != DW_TAG_compile_unit) { + if (m_tag != DW_TAG_compile_unit && m_tag != DW_TAG_partial_unit) { SymbolFileDWARFDwo *dwo_symbol_file = cu->GetDwoSymbolFile(); if (dwo_symbol_file) return GetAttributes(dwo_symbol_file->GetCompileUnit(), @@ -782,8 +779,7 @@ size_t DWARFDebugInfoEntry::GetAttributes( } if (abbrevDecl) { - const DWARFDataExtractor &debug_info_data = - dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); if (fixed_form_sizes.Empty()) fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize( @@ -803,9 +799,9 @@ size_t DWARFDebugInfoEntry::GetAttributes( case DW_AT_sibling: case DW_AT_declaration: if (curr_depth > 0) { - // This attribute doesn't make sense when combined with - // the DIE that references this DIE. We know a DIE is - // referencing this DIE because curr_depth is not zero + // This attribute doesn't make sense when combined with the DIE that + // references this DIE. We know a DIE is referencing this DIE because + // curr_depth is not zero break; } LLVM_FALLTHROUGH; @@ -819,7 +815,7 @@ size_t DWARFDebugInfoEntry::GetAttributes( if (form_value.ExtractValue(debug_info_data, &offset)) { dw_offset_t die_offset = form_value.Reference(); DWARFDIE spec_die = - const_cast<DWARFCompileUnit *>(cu)->GetDIE(die_offset); + const_cast<DWARFUnit *>(cu)->GetDIE(die_offset); if (spec_die) spec_die.GetAttributes(attributes, curr_depth + 1); } @@ -841,17 +837,18 @@ size_t DWARFDebugInfoEntry::GetAttributes( // GetAttributeValue // // Get the value of an attribute and return the .debug_info offset of the -// attribute if it was properly extracted into form_value, or zero -// if we fail since an offset of zero is invalid for an attribute (it -// would be a compile unit header). +// attribute if it was properly extracted into form_value, or zero if we fail +// since an offset of zero is invalid for an attribute (it would be a compile +// unit header). //---------------------------------------------------------------------- dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, DWARFFormValue &form_value, dw_offset_t *end_attr_offset_ptr, bool check_specification_or_abstract_origin) const { SymbolFileDWARFDwo *dwo_symbol_file = cu->GetDwoSymbolFile(); - if (dwo_symbol_file && m_tag != DW_TAG_compile_unit) + if (dwo_symbol_file && m_tag != DW_TAG_compile_unit && + m_tag != DW_TAG_partial_unit) return GetAttributeValue(dwo_symbol_file, dwo_symbol_file->GetCompileUnit(), attr, form_value, end_attr_offset_ptr, check_specification_or_abstract_origin); @@ -864,8 +861,7 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( uint32_t attr_idx = abbrevDecl->FindAttributeIndex(attr); if (attr_idx != DW_INVALID_INDEX) { - const DWARFDataExtractor &debug_info_data = - dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); uint32_t idx = 0; while (idx < attr_idx) @@ -886,7 +882,7 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( if (check_specification_or_abstract_origin) { if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value)) { DWARFDIE die = - const_cast<DWARFCompileUnit *>(cu)->GetDIE(form_value.Reference()); + const_cast<DWARFUnit *>(cu)->GetDIE(form_value.Reference()); if (die) { dw_offset_t die_offset = die.GetDIE()->GetAttributeValue( die.GetDWARF(), die.GetCU(), attr, form_value, end_attr_offset_ptr, @@ -898,7 +894,7 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( if (GetAttributeValue(dwarf2Data, cu, DW_AT_abstract_origin, form_value)) { DWARFDIE die = - const_cast<DWARFCompileUnit *>(cu)->GetDIE(form_value.Reference()); + const_cast<DWARFUnit *>(cu)->GetDIE(form_value.Reference()); if (die) { dw_offset_t die_offset = die.GetDIE()->GetAttributeValue( die.GetDWARF(), die.GetCU(), attr, form_value, end_attr_offset_ptr, @@ -912,11 +908,11 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( if (!dwo_symbol_file) return 0; - DWARFCompileUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); + DWARFUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); if (!dwo_cu) return 0; - DWARFDIE dwo_cu_die = dwo_cu->GetCompileUnitDIEOnly(); + DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); if (!dwo_cu_die.IsValid()) return 0; @@ -928,13 +924,13 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( //---------------------------------------------------------------------- // GetAttributeValueAsString // -// Get the value of an attribute as a string return it. The resulting -// pointer to the string data exists within the supplied SymbolFileDWARF -// and will only be available as long as the SymbolFileDWARF is still around -// and it's content doesn't change. +// Get the value of an attribute as a string return it. The resulting pointer +// to the string data exists within the supplied SymbolFileDWARF and will only +// be available as long as the SymbolFileDWARF is still around and it's content +// doesn't change. //---------------------------------------------------------------------- const char *DWARFDebugInfoEntry::GetAttributeValueAsString( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; @@ -950,7 +946,7 @@ const char *DWARFDebugInfoEntry::GetAttributeValueAsString( // Get the value of an attribute as unsigned and return it. //---------------------------------------------------------------------- uint64_t DWARFDebugInfoEntry::GetAttributeValueAsUnsigned( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; @@ -966,7 +962,7 @@ uint64_t DWARFDebugInfoEntry::GetAttributeValueAsUnsigned( // Get the value of an attribute a signed value and return it. //---------------------------------------------------------------------- int64_t DWARFDebugInfoEntry::GetAttributeValueAsSigned( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, int64_t fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; @@ -979,11 +975,11 @@ int64_t DWARFDebugInfoEntry::GetAttributeValueAsSigned( //---------------------------------------------------------------------- // GetAttributeValueAsReference // -// Get the value of an attribute as reference and fix up and compile -// unit relative offsets as needed. +// Get the value of an attribute as reference and fix up and compile unit +// relative offsets as needed. //---------------------------------------------------------------------- uint64_t DWARFDebugInfoEntry::GetAttributeValueAsReference( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; @@ -994,7 +990,7 @@ uint64_t DWARFDebugInfoEntry::GetAttributeValueAsReference( } uint64_t DWARFDebugInfoEntry::GetAttributeValueAsAddress( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; @@ -1007,13 +1003,13 @@ uint64_t DWARFDebugInfoEntry::GetAttributeValueAsAddress( //---------------------------------------------------------------------- // GetAttributeHighPC // -// Get the hi_pc, adding hi_pc to lo_pc when specified -// as an <offset-from-low-pc>. +// Get the hi_pc, adding hi_pc to lo_pc when specified as an <offset-from-low- +// pc>. // // Returns the hi_pc or fail_value. //---------------------------------------------------------------------- dw_addr_t DWARFDebugInfoEntry::GetAttributeHighPC( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, dw_addr_t lo_pc, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; if (GetAttributeValue(dwarf2Data, cu, DW_AT_high_pc, form_value, nullptr, @@ -1031,13 +1027,13 @@ dw_addr_t DWARFDebugInfoEntry::GetAttributeHighPC( //---------------------------------------------------------------------- // GetAttributeAddressRange // -// Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified -// as an <offset-from-low-pc>. +// Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified as an <offset- +// from-low-pc>. // // Returns true or sets lo_pc and hi_pc to fail_value. //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::GetAttributeAddressRange( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, dw_addr_t &lo_pc, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc, uint64_t fail_value, bool check_specification_or_abstract_origin) const { lo_pc = GetAttributeValueAsAddress(dwarf2Data, cu, DW_AT_low_pc, fail_value, @@ -1054,7 +1050,7 @@ bool DWARFDebugInfoEntry::GetAttributeAddressRange( } size_t DWARFDebugInfoEntry::GetAttributeAddressRanges( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, bool check_specification_or_abstract_origin) const { ranges.Clear(); @@ -1083,23 +1079,23 @@ size_t DWARFDebugInfoEntry::GetAttributeAddressRanges( //---------------------------------------------------------------------- // GetName // -// Get value of the DW_AT_name attribute and return it if one exists, -// else return NULL. +// Get value of the DW_AT_name attribute and return it if one exists, else +// return NULL. //---------------------------------------------------------------------- const char *DWARFDebugInfoEntry::GetName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu) const { + const DWARFUnit *cu) const { return GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, nullptr, true); } //---------------------------------------------------------------------- // GetMangledName // -// Get value of the DW_AT_MIPS_linkage_name attribute and return it if -// one exists, else return the value of the DW_AT_name attribute +// Get value of the DW_AT_MIPS_linkage_name attribute and return it if one +// exists, else return the value of the DW_AT_name attribute //---------------------------------------------------------------------- const char * DWARFDebugInfoEntry::GetMangledName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, bool substitute_name_allowed) const { const char *name = nullptr; @@ -1123,11 +1119,11 @@ DWARFDebugInfoEntry::GetMangledName(SymbolFileDWARF *dwarf2Data, //---------------------------------------------------------------------- // GetPubname // -// Get value the name for a DIE as it should appear for a -// .debug_pubnames or .debug_pubtypes section. +// Get value the name for a DIE as it should appear for a .debug_pubnames or +// .debug_pubtypes section. //---------------------------------------------------------------------- const char *DWARFDebugInfoEntry::GetPubname(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu) const { + const DWARFUnit *cu) const { const char *name = nullptr; if (!dwarf2Data) return name; @@ -1149,14 +1145,13 @@ const char *DWARFDebugInfoEntry::GetPubname(SymbolFileDWARF *dwarf2Data, //---------------------------------------------------------------------- // GetName // -// Get value of the DW_AT_name attribute for a debug information entry -// that exists at offset "die_offset" and place that value into the -// supplied stream object. If the DIE is a NULL object "NULL" is placed -// into the stream, and if no DW_AT_name attribute exists for the DIE -// then nothing is printed. +// Get value of the DW_AT_name attribute for a debug information entry that +// exists at offset "die_offset" and place that value into the supplied stream +// object. If the DIE is a NULL object "NULL" is placed into the stream, and if +// no DW_AT_name attribute exists for the DIE then nothing is printed. //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::GetName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, const dw_offset_t die_offset, Stream &s) { if (dwarf2Data == NULL) { s.PutCString("NULL"); @@ -1184,13 +1179,12 @@ bool DWARFDebugInfoEntry::GetName(SymbolFileDWARF *dwarf2Data, //---------------------------------------------------------------------- // AppendTypeName // -// Follows the type name definition down through all needed tags to -// end up with a fully qualified type name and dump the results to -// the supplied stream. This is used to show the name of types given -// a type identifier. +// Follows the type name definition down through all needed tags to end up with +// a fully qualified type name and dump the results to the supplied stream. +// This is used to show the name of types given a type identifier. //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::AppendTypeName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, const dw_offset_t die_offset, Stream &s) { if (dwarf2Data == NULL) { @@ -1318,7 +1312,7 @@ bool DWARFDebugInfoEntry::AppendTypeName(SymbolFileDWARF *dwarf2Data, // BuildAddressRangeTable //---------------------------------------------------------------------- void DWARFDebugInfoEntry::BuildAddressRangeTable( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { if (m_tag) { if (m_tag == DW_TAG_subprogram) { @@ -1343,13 +1337,13 @@ void DWARFDebugInfoEntry::BuildAddressRangeTable( //---------------------------------------------------------------------- // BuildFunctionAddressRangeTable // -// This function is very similar to the BuildAddressRangeTable function -// except that the actual DIE offset for the function is placed in the -// table instead of the compile unit offset (which is the way the -// standard .debug_aranges section does it). +// This function is very similar to the BuildAddressRangeTable function except +// that the actual DIE offset for the function is placed in the table instead +// of the compile unit offset (which is the way the standard .debug_aranges +// section does it). //---------------------------------------------------------------------- void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { if (m_tag) { if (m_tag == DW_TAG_subprogram) { @@ -1372,21 +1366,22 @@ void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( } void DWARFDebugInfoEntry::GetDeclContextDIEs( - DWARFCompileUnit *cu, DWARFDIECollection &decl_context_dies) const { + DWARFUnit *cu, DWARFDIECollection &decl_context_dies) const { DWARFDIE die(cu, const_cast<DWARFDebugInfoEntry *>(this)); die.GetDeclContextDIEs(decl_context_dies); } void DWARFDebugInfoEntry::GetDWARFDeclContext( - SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, DWARFDeclContext &dwarf_decl_ctx) const { const dw_tag_t tag = Tag(); - if (tag != DW_TAG_compile_unit) { + if (tag != DW_TAG_compile_unit && tag != DW_TAG_partial_unit) { dwarf_decl_ctx.AppendDeclContext(tag, GetName(dwarf2Data, cu)); DWARFDIE parent_decl_ctx_die = GetParentDeclContextDIE(dwarf2Data, cu); if (parent_decl_ctx_die && parent_decl_ctx_die.GetDIE() != this) { - if (parent_decl_ctx_die.Tag() != DW_TAG_compile_unit) + if (parent_decl_ctx_die.Tag() != DW_TAG_compile_unit && + parent_decl_ctx_die.Tag() != DW_TAG_partial_unit) parent_decl_ctx_die.GetDIE()->GetDWARFDeclContext( parent_decl_ctx_die.GetDWARF(), parent_decl_ctx_die.GetCU(), dwarf_decl_ctx); @@ -1395,7 +1390,7 @@ void DWARFDebugInfoEntry::GetDWARFDeclContext( } bool DWARFDebugInfoEntry::MatchesDWARFDeclContext( - SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, const DWARFDeclContext &dwarf_decl_ctx) const { DWARFDeclContext this_dwarf_decl_ctx; @@ -1405,7 +1400,7 @@ bool DWARFDebugInfoEntry::MatchesDWARFDeclContext( DWARFDIE DWARFDebugInfoEntry::GetParentDeclContextDIE(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu) const { + DWARFUnit *cu) const { DWARFAttributes attributes; GetAttributes(cu, DWARFFormValue::FixedFormSizes(), attributes); return GetParentDeclContextDIE(dwarf2Data, cu, attributes); @@ -1413,17 +1408,18 @@ DWARFDebugInfoEntry::GetParentDeclContextDIE(SymbolFileDWARF *dwarf2Data, DWARFDIE DWARFDebugInfoEntry::GetParentDeclContextDIE( - SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, const DWARFAttributes &attributes) const { DWARFDIE die(cu, const_cast<DWARFDebugInfoEntry *>(this)); while (die) { - // If this is the original DIE that we are searching for a declaration - // for, then don't look in the cache as we don't want our own decl - // context to be our decl context... + // If this is the original DIE that we are searching for a declaration for, + // then don't look in the cache as we don't want our own decl context to be + // our decl context... if (die.GetDIE() != this) { switch (die.Tag()) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: case DW_TAG_namespace: case DW_TAG_structure_type: case DW_TAG_union_type: @@ -1465,7 +1461,7 @@ DWARFDebugInfoEntry::GetParentDeclContextDIE( } const char *DWARFDebugInfoEntry::GetQualifiedName(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, std::string &storage) const { DWARFAttributes attributes; GetAttributes(cu, DWARFFormValue::FixedFormSizes(), attributes); @@ -1473,7 +1469,7 @@ const char *DWARFDebugInfoEntry::GetQualifiedName(SymbolFileDWARF *dwarf2Data, } const char *DWARFDebugInfoEntry::GetQualifiedName( - SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, const DWARFAttributes &attributes, std::string &storage) const { const char *name = GetName(dwarf2Data, cu); @@ -1529,7 +1525,7 @@ const char *DWARFDebugInfoEntry::GetQualifiedName( //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die) { bool found_address = false; @@ -1661,6 +1657,7 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, case DW_TAG_unspecified_type: break; case DW_TAG_partial_unit: + match_addr_range = true; break; case DW_TAG_imported_unit: break; @@ -1684,6 +1681,7 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, // puts("***MATCH***"); switch (m_tag) { case DW_TAG_compile_unit: // File + case DW_TAG_partial_unit: // File check_children = ((function_die != NULL) || (block_die != NULL)); break; @@ -1706,10 +1704,12 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, break; } } - } else { // compile units may not have a valid high/low pc when there + } else { + // Compile units may not have a valid high/low pc when there // are address gaps in subroutines so we must always search - // if there is no valid high and low PC - check_children = (m_tag == DW_TAG_compile_unit) && + // if there is no valid high and low PC. + check_children = (m_tag == DW_TAG_compile_unit || + m_tag == DW_TAG_partial_unit) && ((function_die != NULL) || (block_die != NULL)); } } else { @@ -1719,15 +1719,16 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, 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. + // 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()); if (ranges.FindEntryThatContains(address)) { found_address = true; // puts("***MATCH***"); switch (m_tag) { case DW_TAG_compile_unit: // File + case DW_TAG_partial_unit: // File check_children = ((function_die != NULL) || (block_die != NULL)); break; @@ -1772,7 +1773,7 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, const DWARFAbbreviationDeclaration * DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, lldb::offset_t &offset) const { if (dwarf2Data) { offset = GetOffset(); @@ -1782,11 +1783,10 @@ DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr( const DWARFAbbreviationDeclaration *abbrev_decl = abbrev_set->GetAbbreviationDeclaration(m_abbr_idx); if (abbrev_decl) { - // Make sure the abbreviation code still matches. If it doesn't and - // the DWARF data was mmap'ed, the backing file might have been modified + // Make sure the abbreviation code still matches. If it doesn't and the + // DWARF data was mmap'ed, the backing file might have been modified // which is bad news. - const uint64_t abbrev_code = - dwarf2Data->get_debug_info_data().GetULEB128(&offset); + const uint64_t abbrev_code = cu->GetData().GetULEB128(&offset); if (abbrev_decl->Code() == abbrev_code) return abbrev_decl; @@ -1825,3 +1825,15 @@ void DWARFDebugInfoEntry::DumpDIECollection( die_ref.HasChildren() ? " *" : ""); } } + +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; +} + +bool DWARFDebugInfoEntry::operator!=(const DWARFDebugInfoEntry &rhs) const { + return !(*this == rhs); +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 89450d327adf..97cb3046eb3e 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -60,128 +60,132 @@ public: m_empty_children(false), m_abbr_idx(0), m_has_children(false), m_tag(0) {} + explicit operator bool() const { return m_offset != DW_INVALID_OFFSET; } + bool operator==(const DWARFDebugInfoEntry &rhs) const; + bool operator!=(const DWARFDebugInfoEntry &rhs) const; + void BuildAddressRangeTable(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const; void BuildFunctionAddressRangeTable(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const; bool FastExtract(const lldb_private::DWARFDataExtractor &debug_info_data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, const DWARFFormValue::FixedFormSizes &fixed_form_sizes, lldb::offset_t *offset_ptr); - bool Extract(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + bool Extract(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, lldb::offset_t *offset_ptr); bool LookupAddress(const dw_addr_t address, SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die); - size_t GetAttributes(const DWARFCompileUnit *cu, + size_t GetAttributes(const DWARFUnit *cu, DWARFFormValue::FixedFormSizes fixed_form_sizes, DWARFAttributes &attrs, uint32_t curr_depth = 0) const; // "curr_depth" for internal use only, don't set this yourself!!! dw_offset_t - GetAttributeValue(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + GetAttributeValue(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, DWARFFormValue &formValue, dw_offset_t *end_attr_offset_ptr = nullptr, bool check_specification_or_abstract_origin = false) const; const char *GetAttributeValueAsString( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value, bool check_specification_or_abstract_origin = false) const; uint64_t GetAttributeValueAsUnsigned( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; uint64_t GetAttributeValueAsReference( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; int64_t GetAttributeValueAsSigned( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, int64_t fail_value, bool check_specification_or_abstract_origin = false) const; uint64_t GetAttributeValueAsAddress( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; dw_addr_t - GetAttributeHighPC(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + GetAttributeHighPC(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; bool GetAttributeAddressRange( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, dw_addr_t &lo_pc, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; size_t GetAttributeAddressRanges( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, bool check_specification_or_abstract_origin = false) const; const char *GetName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu) const; + const DWARFUnit *cu) const; const char *GetMangledName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, bool substitute_name_allowed = true) const; const char *GetPubname(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu) const; + const DWARFUnit *cu) const; - static bool GetName(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + static bool GetName(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_offset_t die_offset, lldb_private::Stream &s); static bool AppendTypeName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, const dw_offset_t die_offset, lldb_private::Stream &s); const char *GetQualifiedName(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, std::string &storage) const; const char *GetQualifiedName(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, const DWARFAttributes &attributes, std::string &storage) const; static bool OffsetLessThan(const DWARFDebugInfoEntry &a, const DWARFDebugInfoEntry &b); - void Dump(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + void Dump(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, lldb_private::Stream &s, uint32_t recurse_depth) const; - void DumpAncestry(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + void DumpAncestry(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const DWARFDebugInfoEntry *oldest, lldb_private::Stream &s, uint32_t recurse_depth) const; static void - DumpAttribute(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + 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); // This one dumps the comp unit name, objfile name and die offset for this die // so the stream S. - void DumpLocation(SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + void DumpLocation(SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, lldb_private::Stream &s) const; bool - GetDIENamesAndRanges(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + GetDIENamesAndRanges(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const char *&name, const char *&mangled, DWARFRangeList &rangeList, int &decl_file, int &decl_line, int &decl_column, int &call_file, @@ -190,7 +194,7 @@ public: const DWARFAbbreviationDeclaration * GetAbbreviationDeclarationPtr(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, lldb::offset_t &offset) const; dw_tag_t Tag() const { return m_tag; } @@ -229,20 +233,20 @@ public: return (HasChildren() && !m_empty_children) ? this + 1 : NULL; } - void GetDeclContextDIEs(DWARFCompileUnit *cu, + void GetDeclContextDIEs(DWARFUnit *cu, DWARFDIECollection &decl_context_dies) const; - void GetDWARFDeclContext(SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + void GetDWARFDeclContext(SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, DWARFDeclContext &dwarf_decl_ctx) const; bool MatchesDWARFDeclContext(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, const DWARFDeclContext &dwarf_decl_ctx) const; DWARFDIE GetParentDeclContextDIE(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu) const; + DWARFUnit *cu) const; DWARFDIE GetParentDeclContextDIE(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, const DWARFAttributes &attributes) const; void SetParent(DWARFDebugInfoEntry *parent) { diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp index 694d34fc211c..317ea4c22c66 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp @@ -242,8 +242,8 @@ dw_offset_t DWARFDebugLine::DumpStatementOpcodes( log->Printf("0x%8.8x: DW_LNE_??? (%2.2x) - Skipping unknown upcode", op_offset, opcode); // Length doesn't include the zero opcode byte or the length itself, - // but - // it does include the sub_opcode, so we have to adjust for that below + // but it does include the sub_opcode, so we have to adjust for that + // below offset += arg_size; break; } @@ -324,9 +324,9 @@ dw_offset_t DWARFDebugLine::DumpStatementOpcodes( // Special Opcodes default: if (opcode < prologue.opcode_base) { - // We have an opcode that this parser doesn't know about, skip - // the number of ULEB128 numbers that is says to skip in the - // prologue's standard_opcode_lengths array + // We have an opcode that this parser doesn't know about, skip the + // number of ULEB128 numbers that is says to skip in the prologue's + // standard_opcode_lengths array uint8_t n = prologue.standard_opcode_lengths[opcode - 1]; log->Printf("0x%8.8x: Special : Unknown skipping %u ULEB128 values.", op_offset, n); @@ -357,9 +357,9 @@ dw_offset_t DWARFDebugLine::DumpStatementOpcodes( //---------------------------------------------------------------------- // Parse // -// Parse the entire line table contents calling callback each time a -// new prologue is parsed and every time a new row is to be added to -// the line table. +// Parse the entire line table contents calling callback each time a new +// prologue is parsed and every time a new row is to be added to the line +// table. //---------------------------------------------------------------------- void DWARFDebugLine::Parse(const DWARFDataExtractor &debug_line_data, DWARFDebugLine::State::Callback callback, @@ -444,7 +444,7 @@ bool DWARFDebugLine::ParsePrologue(const DWARFDataExtractor &debug_line_data, bool DWARFDebugLine::ParseSupportFiles( const lldb::ModuleSP &module_sp, const DWARFDataExtractor &debug_line_data, - const char *cu_comp_dir, dw_offset_t stmt_list, + const lldb_private::FileSpec &cu_comp_dir, dw_offset_t stmt_list, FileSpecList &support_files) { lldb::offset_t offset = stmt_list; @@ -463,7 +463,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); + file_spec.SetFile(remapped_file, false, FileSpec::Style::native); support_files.Append(file_spec); } return true; @@ -472,9 +472,9 @@ bool DWARFDebugLine::ParseSupportFiles( //---------------------------------------------------------------------- // ParseStatementTable // -// Parse a single line table (prologue and all rows) and call the -// callback function once for the prologue (row in state will be zero) -// and each time a row is to be added to the line table. +// Parse a single line table (prologue and all rows) and call the callback +// function once for the prologue (row in state will be zero) and each time a +// row is to be added to the line table. //---------------------------------------------------------------------- bool DWARFDebugLine::ParseStatementTable( const DWARFDataExtractor &debug_line_data, lldb::offset_t *offset_ptr, @@ -511,8 +511,8 @@ bool DWARFDebugLine::ParseStatementTable( uint8_t opcode = debug_line_data.GetU8(offset_ptr); if (opcode == 0) { - // Extended Opcodes always start with a zero opcode followed by - // a uleb128 length so you can skip ones you don't know about + // Extended Opcodes always start with a zero opcode followed by a uleb128 + // length so you can skip ones you don't know about lldb::offset_t ext_offset = *offset_ptr; dw_uleb128_t len = debug_line_data.GetULEB128(offset_ptr); dw_offset_t arg_size = len - (*offset_ptr - ext_offset); @@ -522,12 +522,12 @@ bool DWARFDebugLine::ParseStatementTable( switch (sub_opcode) { case DW_LNE_end_sequence: // Set the end_sequence register of the state machine to true and - // append a row to the matrix using the current values of the - // state-machine registers. Then reset the registers to the initial - // values specified above. Every statement program sequence must end - // with a DW_LNE_end_sequence instruction which creates a row whose - // address is that of the byte after the last target machine instruction - // of the sequence. + // append a row to the matrix using the current values of the state- + // machine registers. Then reset the registers to the initial values + // specified above. Every statement program sequence must end with a + // DW_LNE_end_sequence instruction which creates a row whose address is + // that of the byte after the last target machine instruction of the + // sequence. state.end_sequence = true; state.AppendRowToMatrix(*offset_ptr); state.Reset(); @@ -537,8 +537,8 @@ bool DWARFDebugLine::ParseStatementTable( // Takes a single relocatable address as an operand. The size of the // operand is the size appropriate to hold an address on the target // machine. Set the address register to the value given by the - // relocatable address. All of the other statement program opcodes - // that affect the address register add a delta to it. This instruction + // relocatable address. All of the other statement program opcodes that + // affect the address register add a delta to it. This instruction // stores a relocatable value into it instead. if (arg_size == 4) state.address = debug_line_data.GetU32(offset_ptr); @@ -549,24 +549,24 @@ bool DWARFDebugLine::ParseStatementTable( case DW_LNE_define_file: // Takes 4 arguments. The first is a null terminated string containing // a source file name. The second is an unsigned LEB128 number - // representing - // the directory index of the directory in which the file was found. The - // third is an unsigned LEB128 number representing the time of last - // modification of the file. The fourth is an unsigned LEB128 number - // representing the length in bytes of the file. The time and length - // fields may contain LEB128(0) if the information is not available. + // representing the directory index of the directory in which the file + // was found. The third is an unsigned LEB128 number representing the + // time of last modification of the file. The fourth is an unsigned + // LEB128 number representing the length in bytes of the file. The time + // and length fields may contain LEB128(0) if the information is not + // available. // // The directory index represents an entry in the include_directories - // section of the statement program prologue. The index is LEB128(0) - // if the file was found in the current directory of the compilation, + // section of the statement program prologue. The index is LEB128(0) if + // the file was found in the current directory of the compilation, // LEB128(1) if it was found in the first directory in the // include_directories section, and so on. The directory index is // ignored for file names that represent full path names. // // The files are numbered, starting at 1, in the order in which they - // appear; the names in the prologue come before names defined by - // the DW_LNE_define_file instruction. These numbers are used in the - // file register of the state machine. + // appear; the names in the prologue come before names defined by the + // DW_LNE_define_file instruction. These numbers are used in the file + // register of the state machine. { FileNameEntry fileEntry; fileEntry.name = debug_line_data.GetCStr(offset_ptr); @@ -578,8 +578,9 @@ bool DWARFDebugLine::ParseStatementTable( break; default: - // Length doesn't include the zero opcode byte or the length itself, but - // it does include the sub_opcode, so we have to adjust for that below + // Length doesn't include the zero opcode byte or the length itself, + // but it does include the sub_opcode, so we have to adjust for that + // below (*offset_ptr) += arg_size; break; } @@ -587,23 +588,23 @@ bool DWARFDebugLine::ParseStatementTable( switch (opcode) { // Standard Opcodes case DW_LNS_copy: - // Takes no arguments. Append a row to the matrix using the - // current values of the state-machine registers. Then set - // the basic_block register to false. + // Takes no arguments. Append a row to the matrix using the current + // values of the state-machine registers. Then set the basic_block + // register to false. state.AppendRowToMatrix(*offset_ptr); break; case DW_LNS_advance_pc: // Takes a single unsigned LEB128 operand, multiplies it by the - // min_inst_length field of the prologue, and adds the - // result to the address register of the state machine. + // min_inst_length field of the prologue, and adds the result to the + // address register of the state machine. state.address += debug_line_data.GetULEB128(offset_ptr) * prologue->min_inst_length; break; case DW_LNS_advance_line: - // Takes a single signed LEB128 operand and adds that value to - // the line register of the state machine. + // Takes a single signed LEB128 operand and adds that value to the line + // register of the state machine. state.line += debug_line_data.GetSLEB128(offset_ptr); break; @@ -614,35 +615,35 @@ bool DWARFDebugLine::ParseStatementTable( break; case DW_LNS_set_column: - // Takes a single unsigned LEB128 operand and stores it in the - // column register of the state machine. + // Takes a single unsigned LEB128 operand and stores it in the column + // register of the state machine. state.column = debug_line_data.GetULEB128(offset_ptr); break; case DW_LNS_negate_stmt: - // Takes no arguments. Set the is_stmt register of the state - // machine to the logical negation of its current value. + // Takes no arguments. Set the is_stmt register of the state machine to + // the logical negation of its current value. state.is_stmt = !state.is_stmt; break; case DW_LNS_set_basic_block: - // Takes no arguments. Set the basic_block register of the - // state machine to true + // Takes no arguments. Set the basic_block register of the state + // machine to true state.basic_block = true; break; case DW_LNS_const_add_pc: - // Takes no arguments. Add to the address register of the state - // machine the address increment value corresponding to special - // opcode 255. The motivation for DW_LNS_const_add_pc is this: - // when the statement program needs to advance the address by a - // small amount, it can use a single special opcode, which occupies - // a single byte. When it needs to advance the address by up to - // twice the range of the last special opcode, it can use - // DW_LNS_const_add_pc followed by a special opcode, for a total - // of two bytes. Only if it needs to advance the address by more - // than twice that range will it need to use both DW_LNS_advance_pc - // and a special opcode, requiring three or more bytes. + // Takes no arguments. Add to the address register of the state machine + // the address increment value corresponding to special opcode 255. The + // motivation for DW_LNS_const_add_pc is this: when the statement + // program needs to advance the address by a small amount, it can use a + // single special opcode, which occupies a single byte. When it needs + // to advance the address by up to twice the range of the last special + // opcode, it can use DW_LNS_const_add_pc followed by a special opcode, + // for a total of two bytes. Only if it needs to advance the address by + // more than twice that range will it need to use both + // DW_LNS_advance_pc and a special opcode, requiring three or more + // bytes. { uint8_t adjust_opcode = 255 - prologue->opcode_base; dw_addr_t addr_offset = (adjust_opcode / prologue->line_range) * @@ -652,40 +653,40 @@ bool DWARFDebugLine::ParseStatementTable( break; case DW_LNS_fixed_advance_pc: - // Takes a single uhalf operand. Add to the address register of - // the state machine the value of the (unencoded) operand. This - // is the only extended opcode that takes an argument that is not - // a variable length number. The motivation for DW_LNS_fixed_advance_pc - // is this: existing assemblers cannot emit DW_LNS_advance_pc or - // special opcodes because they cannot encode LEB128 numbers or - // judge when the computation of a special opcode overflows and - // requires the use of DW_LNS_advance_pc. Such assemblers, however, - // can use DW_LNS_fixed_advance_pc instead, sacrificing compression. + // Takes a single uhalf operand. Add to the address register of the + // state machine the value of the (unencoded) operand. This is the only + // extended opcode that takes an argument that is not a variable length + // number. The motivation for DW_LNS_fixed_advance_pc is this: existing + // assemblers cannot emit DW_LNS_advance_pc or special opcodes because + // they cannot encode LEB128 numbers or judge when the computation of a + // special opcode overflows and requires the use of DW_LNS_advance_pc. + // Such assemblers, however, can use DW_LNS_fixed_advance_pc instead, + // sacrificing compression. state.address += debug_line_data.GetU16(offset_ptr); break; case DW_LNS_set_prologue_end: - // Takes no arguments. Set the prologue_end register of the - // state machine to true + // Takes no arguments. Set the prologue_end register of the state + // machine to true state.prologue_end = true; break; case DW_LNS_set_epilogue_begin: - // Takes no arguments. Set the basic_block register of the - // state machine to true + // Takes no arguments. Set the basic_block register of the state + // machine to true state.epilogue_begin = true; break; case DW_LNS_set_isa: - // Takes a single unsigned LEB128 operand and stores it in the - // column register of the state machine. + // Takes a single unsigned LEB128 operand and stores it in the column + // register of the state machine. state.isa = debug_line_data.GetULEB128(offset_ptr); break; default: - // Handle any unknown standard opcodes here. We know the lengths - // of such opcodes because they are specified in the prologue - // as a multiple of LEB128 operands for each opcode. + // Handle any unknown standard opcodes here. We know the lengths of + // such opcodes because they are specified in the prologue as a + // multiple of LEB128 operands for each opcode. { uint8_t i; assert(static_cast<size_t>(opcode - 1) < @@ -702,32 +703,32 @@ bool DWARFDebugLine::ParseStatementTable( // A special opcode value is chosen based on the amount that needs // to be added to the line and address registers. The maximum line - // increment for a special opcode is the value of the line_base - // field in the header, plus the value of the line_range field, - // minus 1 (line base + line range - 1). If the desired line - // increment is greater than the maximum line increment, a standard - // opcode must be used instead of a special opcode. The "address - // advance" is calculated by dividing the desired address increment - // by the minimum_instruction_length field from the header. The - // special opcode is then calculated using the following formula: + // increment for a special opcode is the value of the line_base field in + // the header, plus the value of the line_range field, minus 1 (line base + // + line range - 1). If the desired line increment is greater than the + // maximum line increment, a standard opcode must be used instead of a + // special opcode. The "address advance" is calculated by dividing the + // desired address increment by the minimum_instruction_length field from + // the header. The special opcode is then calculated using the following + // formula: // // opcode = (desired line increment - line_base) + (line_range * address // advance) + opcode_base // - // If the resulting opcode is greater than 255, a standard opcode - // must be used instead. + // If the resulting opcode is greater than 255, a standard opcode must be + // used instead. // - // To decode a special opcode, subtract the opcode_base from the - // opcode itself to give the adjusted opcode. The amount to - // increment the address register is the result of the adjusted - // opcode divided by the line_range multiplied by the - // minimum_instruction_length field from the header. That is: + // To decode a special opcode, subtract the opcode_base from the opcode + // itself to give the adjusted opcode. The amount to increment the + // address register is the result of the adjusted opcode divided by the + // line_range multiplied by the minimum_instruction_length field from the + // header. That is: // // address increment = (adjusted opcode / line_range) * // minimum_instruction_length // - // The amount to increment the line register is the line_base plus - // the result of the adjusted opcode modulo the line_range. That is: + // The amount to increment the line register is the line_base plus the + // result of the adjusted opcode modulo the line_range. That is: // // line increment = line_base + (adjusted opcode % line_range) @@ -755,8 +756,8 @@ static void ParseStatementTableCallback(dw_offset_t offset, void *userData) { DWARFDebugLine::LineTable *line_table = (DWARFDebugLine::LineTable *)userData; if (state.row == DWARFDebugLine::State::StartParsingLineTable) { - // Just started parsing the line table, so lets keep a reference to - // the prologue using the supplied shared pointer + // Just started parsing the line table, so lets keep a reference to the + // prologue using the supplied shared pointer line_table->prologue = state.prologue; } else if (state.row == DWARFDebugLine::State::DoneParsingLineTable) { // Done parsing line table, nothing to do for the cleanup @@ -769,8 +770,8 @@ static void ParseStatementTableCallback(dw_offset_t offset, //---------------------------------------------------------------------- // ParseStatementTable // -// Parse a line table at offset and populate the LineTable class with -// the prologue and all rows. +// Parse a line table at offset and populate the LineTable class with the +// prologue and all rows. //---------------------------------------------------------------------- bool DWARFDebugLine::ParseStatementTable( const DWARFDataExtractor &debug_line_data, lldb::offset_t *offset_ptr, @@ -861,11 +862,11 @@ void DWARFDebugLine::Prologue::Dump(Log *log) { // buff.Append8(0); // Terminate the file names section with empty string //} -bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, const char *comp_dir, - FileSpec &file) const { +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); + file.SetFile(file_names[idx].name, false, FileSpec::Style::native); if (file.IsRelative()) { if (file_names[idx].dir_idx > 0) { const uint32_t dir_idx = file_names[idx].dir_idx - 1; @@ -876,7 +877,7 @@ bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, const char *comp_dir, } } - if (comp_dir && comp_dir[0]) + if (comp_dir) file.PrependPathComponent(comp_dir); } return true; @@ -936,11 +937,10 @@ uint32_t DWARFDebugLine::LineTable::LookupAddress(dw_addr_t address, if (address < cu_high_pc) return rows.size() - 1; } else { - // Rely on fact that we are using a std::vector and we can do - // pointer arithmetic to find the row index (which will be one less - // that what we found since it will find the first position after - // the current address) since std::vector iterators are just - // pointers to the container type. + // Rely on fact that we are using a std::vector and we can do pointer + // arithmetic to find the row index (which will be one less that what we + // found since it will find the first position after the current address) + // since std::vector iterators are just pointers to the container type. index = pos - begin_pos; if (pos->address > address) { if (index > 0) @@ -1005,9 +1005,9 @@ static bool AddressLessThan(const DWARFDebugLine::Row &a, return a.address < b.address; } -// Insert a row at the correct address if the addresses can be out of -// order which can only happen when we are linking a line table that -// may have had it's contents rearranged. +// Insert a row at the correct address if the addresses can be out of order +// which can only happen when we are linking a line table that may have had +// it's contents rearranged. void DWARFDebugLine::Row::Insert(Row::collection &state_coll, const Row &state) { // If we don't have anything yet, or if the address of the last state in our @@ -1020,12 +1020,12 @@ void DWARFDebugLine::Row::Insert(Row::collection &state_coll, state_coll.begin(), state_coll.end(), state, AddressLessThan)); // If the addresses are equal, we can safely replace the previous entry - // with the current one if the one it is replacing is an end_sequence entry. - // We currently always place an extra end sequence when ever we exit a valid - // address range for a function in case the functions get rearranged by - // optimizations or by order specifications. These extra end sequences will - // disappear by getting replaced with valid consecutive entries within a - // compile unit if there are no gaps. + // with the current one if the one it is replacing is an end_sequence + // entry. We currently always place an extra end sequence when ever we exit + // a valid address range for a function in case the functions get + // rearranged by optimizations or by order specifications. These extra end + // sequences will disappear by getting replaced with valid consecutive + // entries within a compile unit if there are no gaps. if (range.first == range.second) { state_coll.insert(range.first, state); } else { @@ -1065,10 +1065,9 @@ void DWARFDebugLine::State::Reset() { Row::Reset(prologue->default_is_stmt); } // DWARFDebugLine::State::AppendRowToMatrix //---------------------------------------------------------------------- void DWARFDebugLine::State::AppendRowToMatrix(dw_offset_t offset) { - // Each time we are to add an entry into the line table matrix - // call the callback function so that someone can do something with - // the current state of the state machine (like build a line table - // or dump the line table!) + // Each time we are to add an entry into the line table matrix call the + // callback function so that someone can do something with the current state + // of the state machine (like build a line table or dump the line table!) if (log) { if (row == 0) { log->PutCString("Address Line Column File ISA Flags"); @@ -1088,8 +1087,8 @@ void DWARFDebugLine::State::AppendRowToMatrix(dw_offset_t offset) { // DWARFDebugLine::State::Finalize //---------------------------------------------------------------------- void DWARFDebugLine::State::Finalize(dw_offset_t offset) { - // Call the callback with a special row state when we are done parsing a - // line table + // Call the callback with a special row state when we are done parsing a line + // table row = DoneParsingLineTable; if (callback) callback(offset, *this, callbackUserData); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h index ea02cfed6e01..3ab15ac59028 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h @@ -90,7 +90,7 @@ public: include_directories.clear(); file_names.clear(); } - bool GetFile(uint32_t file_idx, const char *comp_dir, + bool GetFile(uint32_t file_idx, const lldb_private::FileSpec &cu_comp_dir, lldb_private::FileSpec &file) const; }; @@ -199,7 +199,8 @@ public: static bool ParseSupportFiles(const lldb::ModuleSP &module_sp, const lldb_private::DWARFDataExtractor &debug_line_data, - const char *cu_comp_dir, dw_offset_t stmt_list, + const lldb_private::FileSpec &cu_comp_dir, + dw_offset_t stmt_list, lldb_private::FileSpecList &support_files); static bool ParsePrologue(const lldb_private::DWARFDataExtractor &debug_line_data, diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp deleted file mode 100644 index 766899c497b0..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp +++ /dev/null @@ -1,255 +0,0 @@ -//===-- DWARFDebugPubnames.cpp ----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DWARFDebugPubnames.h" - -#include "lldb/Utility/Stream.h" -#include "lldb/Utility/Timer.h" - -#include "DWARFCompileUnit.h" -#include "DWARFDIECollection.h" -#include "DWARFDebugInfo.h" -#include "DWARFFormValue.h" -#include "LogChannelDWARF.h" -#include "SymbolFileDWARF.h" - -using namespace lldb; -using namespace lldb_private; - -DWARFDebugPubnames::DWARFDebugPubnames() : m_sets() {} - -bool DWARFDebugPubnames::Extract(const DWARFDataExtractor &data) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", - (uint64_t)data.GetByteSize()); - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES)); - if (log) - log->Printf("DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", - (uint64_t)data.GetByteSize()); - - if (data.ValidOffset(0)) { - lldb::offset_t offset = 0; - - DWARFDebugPubnamesSet set; - while (data.ValidOffset(offset)) { - if (set.Extract(data, &offset)) { - m_sets.push_back(set); - offset = set.GetOffsetOfNextEntry(); - } else - break; - } - if (log) - Dump(log); - return true; - } - return false; -} - -bool DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF *dwarf2Data) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "DWARFDebugPubnames::GeneratePubnames (data = %p)", - static_cast<void *>(dwarf2Data)); - - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES)); - if (log) - log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", - static_cast<void *>(dwarf2Data)); - - m_sets.clear(); - DWARFDebugInfo *debug_info = dwarf2Data->DebugInfo(); - if (debug_info) { - uint32_t cu_idx = 0; - const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); - for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - - DWARFCompileUnit *cu = debug_info->GetCompileUnitAtIndex(cu_idx); - - DWARFFormValue::FixedFormSizes fixed_form_sizes = - DWARFFormValue::GetFixedFormSizesForAddressSize( - cu->GetAddressByteSize(), cu->IsDWARF64()); - - bool clear_dies = cu->ExtractDIEsIfNeeded(false) > 1; - - DWARFDIECollection dies; - const size_t die_count = cu->AppendDIEsWithTag(DW_TAG_subprogram, dies) + - cu->AppendDIEsWithTag(DW_TAG_variable, dies); - - dw_offset_t cu_offset = cu->GetOffset(); - DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, - cu->GetNextCompileUnitOffset() - - cu_offset); - - size_t die_idx; - for (die_idx = 0; die_idx < die_count; ++die_idx) { - DWARFDIE die = dies.GetDIEAtIndex(die_idx); - DWARFAttributes attributes; - const char *name = NULL; - const char *mangled = NULL; - bool add_die = false; - const size_t num_attributes = die.GetDIE()->GetAttributes( - die.GetCU(), fixed_form_sizes, attributes); - if (num_attributes > 0) { - uint32_t i; - - dw_tag_t tag = die.Tag(); - - for (i = 0; i < num_attributes; ++i) { - dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - switch (attr) { - case DW_AT_name: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - name = form_value.AsCString(); - break; - - case DW_AT_MIPS_linkage_name: - case DW_AT_linkage_name: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - mangled = form_value.AsCString(); - break; - - case DW_AT_low_pc: - case DW_AT_ranges: - case DW_AT_entry_pc: - if (tag == DW_TAG_subprogram) - add_die = true; - break; - - case DW_AT_location: - if (tag == DW_TAG_variable) { - DWARFDIE parent_die = die.GetParent(); - while (parent_die) { - switch (parent_die.Tag()) { - case DW_TAG_subprogram: - case DW_TAG_lexical_block: - case DW_TAG_inlined_subroutine: - // Even if this is a function level static, we don't add it. - // We could theoretically - // add these if we wanted to by introspecting into the - // DW_AT_location and seeing - // if the location describes a hard coded address, but we - // don't want the performance - // penalty of that right now. - add_die = false; - parent_die.Clear(); // Terminate the while loop. - break; - - case DW_TAG_compile_unit: - add_die = true; - parent_die.Clear(); // Terminate the while loop. - break; - - default: - parent_die = - parent_die.GetParent(); // Keep going in the while loop. - break; - } - } - } - break; - } - } - } - - if (add_die && (name || mangled)) { - pubnames_set.AddDescriptor(die.GetCompileUnitRelativeOffset(), - mangled ? mangled : name); - } - } - - if (pubnames_set.NumDescriptors() > 0) { - m_sets.push_back(pubnames_set); - } - - // Keep memory down by clearing DIEs if this generate function - // caused them to be parsed - if (clear_dies) - cu->ClearDIEs(true); - } - } - if (m_sets.empty()) - return false; - if (log) - Dump(log); - return true; -} - -bool DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF *dwarf2Data) { - m_sets.clear(); - DWARFDebugInfo *debug_info = dwarf2Data->DebugInfo(); - if (debug_info) { - uint32_t cu_idx = 0; - const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); - for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFCompileUnit *cu = debug_info->GetCompileUnitAtIndex(cu_idx); - DWARFDIECollection dies; - const size_t die_count = cu->AppendDIEsWithTag(DW_TAG_base_type, dies); - dw_offset_t cu_offset = cu->GetOffset(); - DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, - cu->GetNextCompileUnitOffset() - - cu_offset); - - size_t die_idx; - for (die_idx = 0; die_idx < die_count; ++die_idx) { - DWARFDIE die = dies.GetDIEAtIndex(die_idx); - const char *name = die.GetName(); - - if (name) - pubnames_set.AddDescriptor(die.GetCompileUnitRelativeOffset(), name); - } - - if (pubnames_set.NumDescriptors() > 0) { - m_sets.push_back(pubnames_set); - } - } - } - return !m_sets.empty(); -} - -void DWARFDebugPubnames::Dump(Log *s) const { - if (m_sets.empty()) - s->PutCString("< EMPTY >\n"); - else { - const_iterator pos; - const_iterator end = m_sets.end(); - - for (pos = m_sets.begin(); pos != end; ++pos) - (*pos).Dump(s); - } -} - -bool DWARFDebugPubnames::Find(const char *name, bool ignore_case, - std::vector<dw_offset_t> &die_offsets) const { - const_iterator pos; - const_iterator end = m_sets.end(); - - die_offsets.clear(); - - for (pos = m_sets.begin(); pos != end; ++pos) { - (*pos).Find(name, ignore_case, die_offsets); - } - - return !die_offsets.empty(); -} - -bool DWARFDebugPubnames::Find(const RegularExpression ®ex, - std::vector<dw_offset_t> &die_offsets) const { - const_iterator pos; - const_iterator end = m_sets.end(); - - die_offsets.clear(); - - for (pos = m_sets.begin(); pos != end; ++pos) { - (*pos).Find(regex, die_offsets); - } - - return !die_offsets.empty(); -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h deleted file mode 100644 index 57dabade012c..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- DWARFDebugPubnames.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_DWARFDebugPubnames_h_ -#define SymbolFileDWARF_DWARFDebugPubnames_h_ - -#include "SymbolFileDWARF.h" - -#include <list> - -#include "DWARFDebugPubnamesSet.h" - -class DWARFDebugPubnames { -public: - DWARFDebugPubnames(); - bool Extract(const lldb_private::DWARFDataExtractor &data); - bool GeneratePubnames(SymbolFileDWARF *dwarf2Data); - bool GeneratePubBaseTypes(SymbolFileDWARF *dwarf2Data); - - void Dump(lldb_private::Log *s) const; - bool Find(const char *name, bool ignore_case, - std::vector<dw_offset_t> &die_offset_coll) const; - bool Find(const lldb_private::RegularExpression ®ex, - std::vector<dw_offset_t> &die_offsets) const; - -protected: - typedef std::list<DWARFDebugPubnamesSet> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - - collection m_sets; -}; - -#endif // SymbolFileDWARF_DWARFDebugPubnames_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp deleted file mode 100644 index 21e2482783a1..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp +++ /dev/null @@ -1,146 +0,0 @@ -//===-- DWARFDebugPubnamesSet.cpp -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DWARFDebugPubnamesSet.h" - -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegularExpression.h" - -#include "SymbolFileDWARF.h" - -using namespace lldb_private; - -DWARFDebugPubnamesSet::DWARFDebugPubnamesSet() - : m_offset(DW_INVALID_OFFSET), m_header(), m_descriptors(), - m_name_to_descriptor_index() {} - -DWARFDebugPubnamesSet::DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, - dw_offset_t cu_die_offset, - dw_offset_t cu_die_length) - : m_offset(debug_aranges_offset), m_header(), m_descriptors(), - m_name_to_descriptor_index() { - m_header.length = - 10; // set the length to only include the header right for now - m_header.version = 2; // The DWARF version number - m_header.die_offset = cu_die_offset; // compile unit .debug_info offset - m_header.die_length = cu_die_length; // compile unit .debug_info length -} - -void DWARFDebugPubnamesSet::AddDescriptor(dw_offset_t cu_rel_offset, - const char *name) { - if (name && name[0]) { - // Adjust our header length - m_header.length += strlen(name) + 1 + sizeof(dw_offset_t); - Descriptor pubnameDesc(cu_rel_offset, name); - m_descriptors.push_back(pubnameDesc); - } -} - -void DWARFDebugPubnamesSet::Clear() { - m_offset = DW_INVALID_OFFSET; - m_header.length = 10; - m_header.version = 2; - m_header.die_offset = DW_INVALID_OFFSET; - m_header.die_length = 0; - m_descriptors.clear(); -} - -//---------------------------------------------------------------------- -// InitNameIndexes -//---------------------------------------------------------------------- -void DWARFDebugPubnamesSet::InitNameIndexes() const { - // Create the name index vector to be able to quickly search by name - const size_t count = m_descriptors.size(); - for (uint32_t idx = 0; idx < count; ++idx) { - const char *name = m_descriptors[idx].name.c_str(); - if (name && name[0]) - m_name_to_descriptor_index.insert( - cstr_to_index_mmap::value_type(name, idx)); - } -} - -bool DWARFDebugPubnamesSet::Extract(const DWARFDataExtractor &data, - lldb::offset_t *offset_ptr) { - if (data.ValidOffset(*offset_ptr)) { - m_descriptors.clear(); - m_offset = *offset_ptr; - m_header.length = data.GetDWARFInitialLength(offset_ptr); - m_header.version = data.GetU16(offset_ptr); - m_header.die_offset = data.GetDWARFOffset(offset_ptr); - m_header.die_length = data.GetDWARFOffset(offset_ptr); - - Descriptor pubnameDesc; - while (data.ValidOffset(*offset_ptr)) { - pubnameDesc.offset = data.GetDWARFOffset(offset_ptr); - - if (pubnameDesc.offset) { - const char *name = data.GetCStr(offset_ptr); - if (name && name[0]) { - pubnameDesc.name = name; - m_descriptors.push_back(pubnameDesc); - } - } else - break; // We are done if we get a zero 4 byte offset - } - - return !m_descriptors.empty(); - } - return false; -} - -dw_offset_t DWARFDebugPubnamesSet::GetOffsetOfNextEntry() const { - return m_offset + m_header.length + 4; -} - -void DWARFDebugPubnamesSet::Dump(Log *log) const { - log->Printf("Pubnames Header: length = 0x%8.8x, version = 0x%4.4x, " - "die_offset = 0x%8.8x, die_length = 0x%8.8x", - m_header.length, m_header.version, m_header.die_offset, - m_header.die_length); - - bool verbose = log->GetVerbose(); - - DescriptorConstIter pos; - DescriptorConstIter end = m_descriptors.end(); - for (pos = m_descriptors.begin(); pos != end; ++pos) { - if (verbose) - log->Printf("0x%8.8x + 0x%8.8x = 0x%8.8x: %s", pos->offset, - m_header.die_offset, pos->offset + m_header.die_offset, - pos->name.c_str()); - else - log->Printf("0x%8.8x: %s", pos->offset + m_header.die_offset, - pos->name.c_str()); - } -} - -void DWARFDebugPubnamesSet::Find( - const char *name, bool ignore_case, - std::vector<dw_offset_t> &die_offset_coll) const { - if (!m_descriptors.empty() && m_name_to_descriptor_index.empty()) - InitNameIndexes(); - - std::pair<cstr_to_index_mmap::const_iterator, - cstr_to_index_mmap::const_iterator> - range(m_name_to_descriptor_index.equal_range(name)); - for (cstr_to_index_mmap::const_iterator pos = range.first; - pos != range.second; ++pos) - die_offset_coll.push_back(m_header.die_offset + - m_descriptors[(*pos).second].offset); -} - -void DWARFDebugPubnamesSet::Find( - const RegularExpression ®ex, - std::vector<dw_offset_t> &die_offset_coll) const { - DescriptorConstIter pos; - DescriptorConstIter end = m_descriptors.end(); - for (pos = m_descriptors.begin(); pos != end; ++pos) { - if (regex.Execute(pos->name)) - die_offset_coll.push_back(m_header.die_offset + pos->offset); - } -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h deleted file mode 100644 index 6e7d3f38aa85..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h +++ /dev/null @@ -1,95 +0,0 @@ -//===-- DWARFDebugPubnamesSet.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_DWARFDebugPubnamesSet_h_ -#define SymbolFileDWARF_DWARFDebugPubnamesSet_h_ - -#include "SymbolFileDWARF.h" -#include <map> -#include <string> -#include <vector> -#if __cplusplus >= 201103L || defined(_MSC_VER) -#include <unordered_map> -#else -#include <ext/hash_map> -#endif - -#include "lldb/Core/STLUtils.h" - -class DWARFDebugPubnamesSet { -public: - struct Header { - uint32_t length; // length of the set of entries for this compilation unit, - // not including the length field itself - uint16_t version; // The DWARF version number - uint32_t die_offset; // compile unit .debug_info offset - uint32_t die_length; // compile unit .debug_info length - Header() - : length(10), version(2), die_offset(DW_INVALID_OFFSET), die_length(0) { - } - }; - - struct Descriptor { - Descriptor() : offset(), name() {} - - Descriptor(dw_offset_t the_offset, const char *the_name) - : offset(the_offset), name(the_name ? the_name : "") {} - - dw_offset_t offset; - std::string name; - }; - - DWARFDebugPubnamesSet(); - DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, - dw_offset_t cu_die_offset, dw_offset_t die_length); - dw_offset_t GetOffset() const { return m_offset; } - void SetOffset(dw_offset_t offset) { m_offset = offset; } - DWARFDebugPubnamesSet::Header &GetHeader() { return m_header; } - const DWARFDebugPubnamesSet::Header &GetHeader() const { return m_header; } - const DWARFDebugPubnamesSet::Descriptor *GetDescriptor(uint32_t i) const { - if (i < m_descriptors.size()) - return &m_descriptors[i]; - return NULL; - } - uint32_t NumDescriptors() const { return m_descriptors.size(); } - void AddDescriptor(dw_offset_t cu_rel_offset, const char *name); - void Clear(); - bool Extract(const lldb_private::DWARFDataExtractor &debug_pubnames_data, - lldb::offset_t *offset_ptr); - void Dump(lldb_private::Log *s) const; - void InitNameIndexes() const; - void Find(const char *name, bool ignore_case, - std::vector<dw_offset_t> &die_offset_coll) const; - void Find(const lldb_private::RegularExpression ®ex, - std::vector<dw_offset_t> &die_offsets) const; - dw_offset_t GetOffsetOfNextEntry() const; - -protected: - typedef std::vector<Descriptor> DescriptorColl; - typedef DescriptorColl::iterator DescriptorIter; - typedef DescriptorColl::const_iterator DescriptorConstIter; - - dw_offset_t m_offset; - Header m_header; -#if __cplusplus >= 201103L || defined(_MSC_VER) - typedef std::unordered_multimap<const char *, uint32_t, - std::hash<const char *>, - CStringEqualBinaryPredicate> - cstr_to_index_mmap; -#else - typedef __gnu_cxx::hash_multimap<const char *, uint32_t, - __gnu_cxx::hash<const char *>, - CStringEqualBinaryPredicate> - cstr_to_index_mmap; -#endif - DescriptorColl m_descriptors; - mutable cstr_to_index_mmap m_name_to_descriptor_index; -}; - -#endif // SymbolFileDWARF_DWARFDebugPubnamesSet_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp index a8c48b7f2f84..89e27efb3cc2 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -89,8 +89,8 @@ void DWARFDebugRanges::Dump(Stream &s, debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) { dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); - // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits - // of ones + // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits of + // ones if (begin == 0xFFFFFFFFull && addr_size == 4) begin = LLDB_INVALID_ADDRESS; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp index 79f2f221696b..dbaf0b0ed127 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp @@ -67,8 +67,8 @@ bool DWARFDeclContext::operator==(const DWARFDeclContext &rhs) const { // First compare the tags before we do expensive name compares for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos) { if (pos->tag != rhs_pos->tag) { - // Check for DW_TAG_structure_type and DW_TAG_class_type as they are often - // used interchangeably in GCC + // Check for DW_TAG_structure_type and DW_TAG_class_type as they are + // often used interchangeably in GCC if (pos->tag == DW_TAG_structure_type && rhs_pos->tag == DW_TAG_class_type) continue; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp index 2ff0fe3aac41..1d927ba3bca3 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp @@ -473,16 +473,6 @@ const char *DW_ORD_value_to_name(uint32_t val) { return llvmstr.data(); } -const char *DW_DSC_value_to_name(uint32_t val) { - static char invalid[100]; - llvm::StringRef llvmstr = llvm::dwarf::DiscriminantString(val); - if (llvmstr.empty()) { - snprintf(invalid, sizeof(invalid), "Unknown DW_DSC constant: 0x%x", val); - return invalid; - } - return llvmstr.data(); -} - const char *DW_LNS_value_to_name(uint32_t val) { static char invalid[100]; llvm::StringRef llvmstr = llvm::dwarf::LNStandardString(val); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h index 038f5706c060..926f83b3564a 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDefines.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h @@ -58,8 +58,6 @@ const char *DW_INL_value_to_name(uint32_t val); const char *DW_ORD_value_to_name(uint32_t val); -const char *DW_DSC_value_to_name(uint32_t val); - const char *DW_LNS_value_to_name(uint32_t val); const char *DW_LNE_value_to_name(uint32_t val); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index a21e313c2f81..4fde5748d3f3 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -12,10 +12,10 @@ #include "lldb/Core/dwarf.h" #include "lldb/Utility/Stream.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFFormValue.h" -class DWARFCompileUnit; +class DWARFUnit; using namespace lldb_private; @@ -154,7 +154,7 @@ DWARFFormValue::GetFixedFormSizesForAddressSize(uint8_t addr_size, DWARFFormValue::DWARFFormValue() : m_cu(NULL), m_form(0), m_value() {} -DWARFFormValue::DWARFFormValue(const DWARFCompileUnit *cu, dw_form_t form) +DWARFFormValue::DWARFFormValue(const DWARFUnit *cu, dw_form_t form) : m_cu(cu), m_form(form), m_value() {} void DWARFFormValue::Clear() { @@ -177,7 +177,7 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, case DW_FORM_addr: assert(m_cu); m_value.value.uval = data.GetMaxU64( - offset_ptr, DWARFCompileUnit::GetAddressByteSize(m_cu)); + offset_ptr, DWARFUnit::GetAddressByteSize(m_cu)); break; case DW_FORM_block2: m_value.value.uval = data.GetU16(offset_ptr); @@ -220,7 +220,7 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, case DW_FORM_strp: assert(m_cu); m_value.value.uval = - data.GetMaxU64(offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); + data.GetMaxU64(offset_ptr, DWARFUnit::IsDWARF64(m_cu) ? 8 : 4); break; // case DW_FORM_APPLE_db_str: case DW_FORM_udata: @@ -258,7 +258,7 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, case DW_FORM_sec_offset: assert(m_cu); m_value.value.uval = - data.GetMaxU64(offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); + data.GetMaxU64(offset_ptr, DWARFUnit::IsDWARF64(m_cu) ? 8 : 4); break; case DW_FORM_flag_present: m_value.value.uval = 1; @@ -296,11 +296,11 @@ bool DWARFFormValue::SkipValue(const DWARFDataExtractor &debug_info_data, bool DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor &debug_info_data, lldb::offset_t *offset_ptr, - const DWARFCompileUnit *cu) { + const DWARFUnit *cu) { uint8_t ref_addr_size; switch (form) { - // Blocks if inlined data that have a length field and the data bytes - // inlined in the .debug_info + // Blocks if inlined data that have a length field and the data bytes inlined + // in the .debug_info case DW_FORM_exprloc: case DW_FORM_block: { dw_uleb128_t size = debug_info_data.GetULEB128(offset_ptr); @@ -330,7 +330,7 @@ bool DWARFFormValue::SkipValue(dw_form_t form, // Compile unit address sized values case DW_FORM_addr: - *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu); + *offset_ptr += DWARFUnit::GetAddressByteSize(cu); return true; case DW_FORM_ref_addr: diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index 2aa7460c4910..ef1a693b37c9 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -13,7 +13,7 @@ #include "DWARFDataExtractor.h" #include <stddef.h> // for NULL -class DWARFCompileUnit; +class DWARFUnit; class DWARFFormValue { public: @@ -55,9 +55,9 @@ public: }; DWARFFormValue(); - DWARFFormValue(const DWARFCompileUnit *cu, dw_form_t form); - const DWARFCompileUnit *GetCompileUnit() const { return m_cu; } - void SetCompileUnit(const DWARFCompileUnit *cu) { m_cu = 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; } void SetForm(dw_form_t form) { m_form = form; } const ValueType &Value() const { return m_value; } @@ -79,7 +79,7 @@ public: lldb::offset_t *offset_ptr) const; static bool SkipValue(const dw_form_t form, const lldb_private::DWARFDataExtractor &debug_info_data, - lldb::offset_t *offset_ptr, const DWARFCompileUnit *cu); + lldb::offset_t *offset_ptr, const DWARFUnit *cu); static bool IsBlockForm(const dw_form_t form); static bool IsDataForm(const dw_form_t form); static FixedFormSizes GetFixedFormSizesForAddressSize(uint8_t addr_size, @@ -89,7 +89,7 @@ public: static bool FormIsSupported(dw_form_t form); protected: - const DWARFCompileUnit *m_cu; // Compile unit for this form + const DWARFUnit *m_cu; // Compile unit for this form dw_form_t m_form; // Form for this value ValueType m_value; // Contains all data for the form }; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp new file mode 100644 index 000000000000..4577f0557a1d --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp @@ -0,0 +1,68 @@ +//===-- DWARFIndex.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/DWARF/DWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/DWARFDIE.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" + +#include "Plugins/Language/ObjC/ObjCLanguage.h" + +using namespace lldb_private; +using namespace lldb; + +DWARFIndex::~DWARFIndex() = default; + +void DWARFIndex::ProcessFunctionDIE(llvm::StringRef name, DIERef ref, + DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) { + DWARFDIE die = info.GetDIE(ref); + if (!die) { + ReportInvalidDIEOffset(ref.die_offset, name); + return; + } + + // Exit early if we're searching exclusively for methods or selectors and + // we have a context specified (no methods in namespaces). + uint32_t looking_for_nonmethods = + name_type_mask & ~(eFunctionNameTypeMethod | eFunctionNameTypeSelector); + if (!looking_for_nonmethods && parent_decl_ctx.IsValid()) + return; + + // Otherwise, we need to also check that the context matches. If it does not + // match, we do nothing. + if (!SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) + return; + + // In case of a full match, we just insert everything we find. + if (name_type_mask & eFunctionNameTypeFull) { + dies.push_back(die); + return; + } + + // If looking for ObjC selectors, we need to also check if the name is a + // possible selector. + if (name_type_mask & eFunctionNameTypeSelector && + ObjCLanguage::IsPossibleObjCMethodName(die.GetName())) { + dies.push_back(die); + return; + } + + bool looking_for_methods = name_type_mask & lldb::eFunctionNameTypeMethod; + bool looking_for_functions = name_type_mask & lldb::eFunctionNameTypeBase; + if (looking_for_methods || looking_for_functions) { + // If we're looking for either methods or functions, we definitely want this + // die. Otherwise, only keep it if the die type matches what we are + // searching for. + if ((looking_for_methods && looking_for_functions) || + looking_for_methods == die.IsMethod()) + dies.push_back(die); + } +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/source/Plugins/SymbolFile/DWARF/DWARFIndex.h new file mode 100644 index 000000000000..77af67b8e60f --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFIndex.h @@ -0,0 +1,69 @@ +//===-- DWARFIndex.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_DWARFINDEX_H +#define LLDB_DWARFINDEX_H + +#include "Plugins/SymbolFile/DWARF/DIERef.h" +#include "Plugins/SymbolFile/DWARF/DWARFDIE.h" +#include "Plugins/SymbolFile/DWARF/DWARFFormValue.h" + +class DWARFDebugInfo; +class DWARFDeclContext; +class DWARFDIE; + +namespace lldb_private { +class DWARFIndex { +public: + DWARFIndex(Module &module) : m_module(module) {} + virtual ~DWARFIndex(); + + virtual void Preload() = 0; + + /// Finds global variables with the given base name. Any additional filtering + /// (e.g., to only retrieve variables from a given context) should be done by + /// the consumer. + virtual void GetGlobalVariables(ConstString basename, DIEArray &offsets) = 0; + + virtual void GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) = 0; + virtual void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) = 0; + virtual void GetObjCMethods(ConstString class_name, DIEArray &offsets) = 0; + virtual void GetCompleteObjCClass(ConstString class_name, + bool must_be_implementation, + DIEArray &offsets) = 0; + virtual void GetTypes(ConstString name, DIEArray &offsets) = 0; + virtual void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) = 0; + virtual void GetNamespaces(ConstString name, DIEArray &offsets) = 0; + virtual void GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) = 0; + virtual void GetFunctions(const RegularExpression ®ex, + DIEArray &offsets) = 0; + + virtual void ReportInvalidDIEOffset(dw_offset_t offset, + llvm::StringRef name) = 0; + virtual void Dump(Stream &s) = 0; + +protected: + Module &m_module; + + /// Helper function implementing common logic for processing function dies. If + /// the function given by "ref" matches search criteria given by + /// "parent_decl_ctx" and "name_type_mask", it is inserted into the "dies" + /// vector. + void ProcessFunctionDIE(llvm::StringRef name, DIERef ref, + DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, std::vector<DWARFDIE> &dies); +}; +} // namespace lldb_private + +#endif // LLDB_DWARFINDEX_H diff --git a/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp new file mode 100644 index 000000000000..f44b2bb97b2b --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -0,0 +1,755 @@ +//===-- DWARFUnit.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFUnit.h" + +#include "lldb/Core/Module.h" +#include "lldb/Host/StringConvert.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/Timer.h" + +#include "DWARFDIECollection.h" +#include "DWARFDebugAranges.h" +#include "DWARFDebugInfo.h" +#include "LogChannelDWARF.h" +#include "SymbolFileDWARFDebugMap.h" +#include "SymbolFileDWARFDwo.h" + +using namespace lldb; +using namespace lldb_private; +using namespace std; + +extern int g_verbose; + +DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf) + : m_dwarf(dwarf), m_cancel_scopes(false) {} + +DWARFUnit::~DWARFUnit() {} + +//---------------------------------------------------------------------- +// Parses first DIE of a compile unit. +//---------------------------------------------------------------------- +void DWARFUnit::ExtractUnitDIEIfNeeded() { + { + llvm::sys::ScopedReader lock(m_first_die_mutex); + if (m_first_die) + return; // Already parsed + } + llvm::sys::ScopedWriter lock(m_first_die_mutex); + if (m_first_die) + return; // Already parsed + + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer( + func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", m_offset); + + // Set the offset to that of the first DIE and calculate the start of the + // next compilation unit header. + lldb::offset_t offset = GetFirstDIEOffset(); + + // We are in our compile unit, parse starting at the offset we were told to + // parse + const DWARFDataExtractor &data = GetData(); + DWARFFormValue::FixedFormSizes fixed_form_sizes = + DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), + IsDWARF64()); + if (offset < GetNextCompileUnitOffset() && + m_first_die.FastExtract(data, this, fixed_form_sizes, &offset)) { + AddUnitDIE(m_first_die); + return; + } + + ExtractDIEsEndCheck(offset); +} + +//---------------------------------------------------------------------- +// Parses a compile unit and indexes its DIEs if it hasn't already been done. +// It will leave this compile unit extracted forever. +//---------------------------------------------------------------------- +void DWARFUnit::ExtractDIEsIfNeeded() { + m_cancel_scopes = true; + + { + llvm::sys::ScopedReader lock(m_die_array_mutex); + if (!m_die_array.empty()) + return; // Already parsed + } + llvm::sys::ScopedWriter lock(m_die_array_mutex); + if (!m_die_array.empty()) + return; // Already parsed + + ExtractDIEsRWLocked(); +} + +//---------------------------------------------------------------------- +// Parses a compile unit and indexes its DIEs if it hasn't already been done. +// It will clear this compile unit after returned instance gets out of scope, +// no other ScopedExtractDIEs instance is running for this compile unit +// and no ExtractDIEsIfNeeded() has been executed during this ScopedExtractDIEs +// lifetime. +//---------------------------------------------------------------------- +DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() { + ScopedExtractDIEs scoped(this); + + { + llvm::sys::ScopedReader lock(m_die_array_mutex); + if (!m_die_array.empty()) + return scoped; // Already parsed + } + llvm::sys::ScopedWriter lock(m_die_array_mutex); + if (!m_die_array.empty()) + return scoped; // Already parsed + + // Otherwise m_die_array would be already populated. + lldbassert(!m_cancel_scopes); + + ExtractDIEsRWLocked(); + scoped.m_clear_dies = true; + return scoped; +} + +DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit *cu) : m_cu(cu) { + lldbassert(m_cu); + m_cu->m_die_array_scoped_mutex.lock_shared(); +} + +DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() { + if (!m_cu) + return; + m_cu->m_die_array_scoped_mutex.unlock_shared(); + if (!m_clear_dies || m_cu->m_cancel_scopes) + return; + // Be sure no other ScopedExtractDIEs is running anymore. + llvm::sys::ScopedWriter lock_scoped(m_cu->m_die_array_scoped_mutex); + llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex); + if (m_cu->m_cancel_scopes) + return; + m_cu->ClearDIEsRWLocked(); +} + +DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs) + : m_cu(rhs.m_cu), m_clear_dies(rhs.m_clear_dies) { + rhs.m_cu = nullptr; +} + +DWARFUnit::ScopedExtractDIEs &DWARFUnit::ScopedExtractDIEs::operator=( + DWARFUnit::ScopedExtractDIEs &&rhs) { + m_cu = rhs.m_cu; + rhs.m_cu = nullptr; + m_clear_dies = rhs.m_clear_dies; + return *this; +} + +//---------------------------------------------------------------------- +// Parses a compile unit and indexes its DIEs, m_die_array_mutex must be +// held R/W and m_die_array must be empty. +//---------------------------------------------------------------------- +void DWARFUnit::ExtractDIEsRWLocked() { + llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex); + + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer( + func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", m_offset); + + // Set the offset to that of the first DIE and calculate the start of the + // next compilation unit header. + lldb::offset_t offset = GetFirstDIEOffset(); + lldb::offset_t next_cu_offset = GetNextCompileUnitOffset(); + + DWARFDebugInfoEntry die; + // Keep a flat array of the DIE for binary lookup by DIE offset + Log *log( + LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS)); + if (log) { + m_dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( + log, + "DWARFUnit::ExtractDIEsIfNeeded () for compile unit at " + ".debug_info[0x%8.8x]", + GetOffset()); + } + + uint32_t depth = 0; + // We are in our compile unit, parse starting at the offset we were told to + // parse + const DWARFDataExtractor &data = GetData(); + std::vector<uint32_t> die_index_stack; + die_index_stack.reserve(32); + die_index_stack.push_back(0); + bool prev_die_had_children = false; + DWARFFormValue::FixedFormSizes fixed_form_sizes = + DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), + 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"); + + // The average bytes per DIE entry has been seen to be around 14-20 so + // lets pre-reserve half of that since we are now stripping the NULL + // tags. + + // Only reserve the memory if we are adding children of the main + // compile unit DIE. The compile unit DIE is always the first entry, so + // if our size is 1, then we are adding the first compile unit child + // DIE and should reserve the memory. + m_die_array.reserve(GetDebugInfoSize() / 24); + m_die_array.push_back(die); + + if (!m_first_die) + AddUnitDIE(m_die_array.front()); + } else { + if (null_die) { + if (prev_die_had_children) { + // This will only happen if a DIE says is has children but all it + // contains is a NULL tag. Since we are removing the NULL DIEs from + // 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); + } + } else { + die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]); + + if (die_index_stack.back()) + m_die_array[die_index_stack.back()].SetSiblingIndex( + m_die_array.size() - die_index_stack.back()); + + // Only push the DIE if it isn't a NULL DIE + m_die_array.push_back(die); + } + } + + if (null_die) { + // NULL DIE. + if (!die_index_stack.empty()) + die_index_stack.pop_back(); + + 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; + // Normal DIE + const bool die_has_children = die.HasChildren(); + if (die_has_children) { + die_index_stack.push_back(0); + ++depth; + } + prev_die_had_children = die_has_children; + } + } + + if (!m_die_array.empty()) { + lldbassert(!m_first_die || m_first_die == m_die_array.front()); + m_first_die = m_die_array.front(); + } + + m_die_array.shrink_to_fit(); + + ExtractDIEsEndCheck(offset); + + if (m_dwo_symbol_file) { + DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); + dwo_cu->ExtractDIEsIfNeeded(); + } +} + +//-------------------------------------------------------------------------- +// Final checks for both ExtractUnitDIEIfNeeded() and ExtractDIEsIfNeeded(). +//-------------------------------------------------------------------------- +void DWARFUnit::ExtractDIEsEndCheck(lldb::offset_t offset) const { + // Give a little bit of info if we encounter corrupt DWARF (our offset should + // always terminate at or before the start of the next compilation unit + // header). + if (offset > GetNextCompileUnitOffset()) { + m_dwarf->GetObjectFile()->GetModule()->ReportWarning( + "DWARF compile unit extends beyond its bounds cu 0x%8.8x at " + "0x%8.8" PRIx64 "\n", + GetOffset(), offset); + } + + Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); + if (log && log->GetVerbose()) { + StreamString strm; + Dump(&strm); + if (m_die_array.empty()) + strm.Printf("error: no DIE for compile unit"); + else + m_die_array[0].Dump(m_dwarf, this, strm, UINT32_MAX); + log->PutString(strm.GetString()); + } +} + +// m_die_array_mutex must be already held as read/write. +void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { + uint64_t base_addr = cu_die.GetAttributeValueAsAddress( + m_dwarf, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); + if (base_addr == LLDB_INVALID_ADDRESS) + base_addr = cu_die.GetAttributeValueAsAddress( + m_dwarf, this, DW_AT_entry_pc, 0); + SetBaseAddress(base_addr); + + std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file = + m_dwarf->GetDwoSymbolFileForCompileUnit(*this, cu_die); + if (!dwo_symbol_file) + return; + + DWARFUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); + if (!dwo_cu) + return; // Can't fetch the compile unit from the dwo file. + + DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); + if (!dwo_cu_die.IsValid()) + return; // Can't fetch the compile unit DIE from the dwo file. + + uint64_t main_dwo_id = + cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_GNU_dwo_id, 0); + uint64_t sub_dwo_id = + dwo_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0); + if (main_dwo_id != sub_dwo_id) + return; // The 2 dwo ID isn't match. Don't use the dwo file as it belongs to + // a differectn compilation. + + m_dwo_symbol_file = std::move(dwo_symbol_file); + + 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); +} + +DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) { + if (DIE()) { + const DWARFDebugAranges &func_aranges = GetFunctionAranges(); + + // Re-check the aranges auto pointer contents in case it was created above + if (!func_aranges.IsEmpty()) + return GetDIE(func_aranges.FindAddress(address)); + } + return DWARFDIE(); +} + +size_t DWARFUnit::AppendDIEsWithTag(const dw_tag_t tag, + DWARFDIECollection &dies, + uint32_t depth) const { + size_t old_size = dies.Size(); + { + llvm::sys::ScopedReader lock(m_die_array_mutex); + DWARFDebugInfoEntry::const_iterator pos; + DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); + for (pos = m_die_array.begin(); pos != end; ++pos) { + if (pos->Tag() == tag) + dies.Append(DWARFDIE(this, &(*pos))); + } + } + + // Return the number of DIEs added to the collection + return dies.Size() - old_size; +} + + +lldb::user_id_t DWARFUnit::GetID() const { + dw_offset_t local_id = + m_base_obj_offset != DW_INVALID_OFFSET ? m_base_obj_offset : m_offset; + if (m_dwarf) + return DIERef(local_id, local_id).GetUID(m_dwarf); + else + return local_id; +} + +dw_offset_t DWARFUnit::GetNextCompileUnitOffset() const { + return m_offset + GetLengthByteSize() + GetLength(); +} + +size_t DWARFUnit::GetDebugInfoSize() const { + return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); +} + +const DWARFAbbreviationDeclarationSet *DWARFUnit::GetAbbreviations() const { + return m_abbrevs; +} + +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; + m_ranges_base = ranges_base; + m_base_obj_offset = base_obj_offset; +} + +// It may be called only with m_die_array_mutex held R/W. +void DWARFUnit::ClearDIEsRWLocked() { + m_die_array.clear(); + m_die_array.shrink_to_fit(); + + if (m_dwo_symbol_file) + m_dwo_symbol_file->GetCompileUnit()->ClearDIEsRWLocked(); +} + +void DWARFUnit::BuildAddressRangeTable(SymbolFileDWARF *dwarf, + DWARFDebugAranges *debug_aranges) { + // This function is usually called if there in no .debug_aranges section in + // order to produce a compile unit level set of address ranges that is + // accurate. + + size_t num_debug_aranges = debug_aranges->GetNumRanges(); + + // First get the compile unit DIE only and check if it has a DW_AT_ranges + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + + const dw_offset_t cu_offset = GetOffset(); + if (die) { + DWARFRangeList ranges; + const size_t num_ranges = + die->GetAttributeAddressRanges(dwarf, this, ranges, false); + if (num_ranges > 0) { + // This compile unit has DW_AT_ranges, assume this is correct if it is + // present since clang no longer makes .debug_aranges by default and it + // emits DW_AT_ranges for DW_TAG_compile_units. GCC also does this with + // recent GCC builds. + for (size_t i = 0; i < num_ranges; ++i) { + const DWARFRangeList::Entry &range = ranges.GetEntryRef(i); + debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), + range.GetRangeEnd()); + } + + return; // We got all of our ranges from the DW_AT_ranges attribute + } + } + // We don't have a DW_AT_ranges attribute, so we need to parse the DWARF + + // If the DIEs weren't parsed, then we don't want all dies for all compile + // units to stay loaded when they weren't needed. So we can end up parsing + // the DWARF and then throwing them all away to keep memory usage down. + ScopedExtractDIEs clear_dies(ExtractDIEsScoped()); + + die = DIEPtr(); + if (die) + die->BuildAddressRangeTable(dwarf, this, debug_aranges); + + if (debug_aranges->GetNumRanges() == num_debug_aranges) { + // We got nothing from the functions, maybe we have a line tables only + // situation. Check the line tables and build the arange table from this. + SymbolContext sc; + sc.comp_unit = dwarf->GetCompUnitForDWARFCompUnit(this); + if (sc.comp_unit) { + SymbolFileDWARFDebugMap *debug_map_sym_file = + m_dwarf->GetDebugMapSymfile(); + if (debug_map_sym_file == NULL) { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table) { + LineTable::FileAddressRanges file_ranges; + const bool append = true; + const size_t num_ranges = + line_table->GetContiguousFileAddressRanges(file_ranges, append); + for (uint32_t idx = 0; idx < num_ranges; ++idx) { + const LineTable::FileAddressRanges::Entry &range = + file_ranges.GetEntryRef(idx); + debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), + range.GetRangeEnd()); + } + } + } else + debug_map_sym_file->AddOSOARanges(dwarf, debug_aranges); + } + } + + if (debug_aranges->GetNumRanges() == num_debug_aranges) { + // We got nothing from the functions, maybe we have a line tables only + // situation. Check the line tables and build the arange table from this. + SymbolContext sc; + sc.comp_unit = dwarf->GetCompUnitForDWARFCompUnit(this); + if (sc.comp_unit) { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table) { + LineTable::FileAddressRanges file_ranges; + const bool append = true; + const size_t num_ranges = + line_table->GetContiguousFileAddressRanges(file_ranges, append); + for (uint32_t idx = 0; idx < num_ranges; ++idx) { + const LineTable::FileAddressRanges::Entry &range = + file_ranges.GetEntryRef(idx); + debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), + range.GetRangeEnd()); + } + } + } + } +} + +lldb::ByteOrder DWARFUnit::GetByteOrder() const { + return m_dwarf->GetObjectFile()->GetByteOrder(); +} + +TypeSystem *DWARFUnit::GetTypeSystem() { + if (m_dwarf) + return m_dwarf->GetTypeSystemForLanguage(GetLanguageType()); + else + return nullptr; +} + +DWARFFormValue::FixedFormSizes DWARFUnit::GetFixedFormSizes() { + return DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), + IsDWARF64()); +} + +void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; } + +//---------------------------------------------------------------------- +// Compare function DWARFDebugAranges::Range structures +//---------------------------------------------------------------------- +static bool CompareDIEOffset(const DWARFDebugInfoEntry &die, + const dw_offset_t die_offset) { + return die.GetOffset() < die_offset; +} + +//---------------------------------------------------------------------- +// GetDIE() +// +// Get the DIE (Debug Information Entry) with the specified offset by first +// checking if the DIE is contained within this compile unit and grabbing the +// DIE from this compile unit. Otherwise we grab the DIE from the DWARF file. +//---------------------------------------------------------------------- +DWARFDIE +DWARFUnit::GetDIE(dw_offset_t die_offset) { + if (die_offset != DW_INVALID_OFFSET) { + if (GetDwoSymbolFile()) + return GetDwoSymbolFile()->GetCompileUnit()->GetDIE(die_offset); + + if (ContainsDIEOffset(die_offset)) { + ExtractDIEsIfNeeded(); + DWARFDebugInfoEntry::const_iterator end = m_die_array.cend(); + DWARFDebugInfoEntry::const_iterator pos = + lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset); + if (pos != end) { + if (die_offset == (*pos).GetOffset()) + return DWARFDIE(this, &(*pos)); + } + } else { + // Don't specify the compile unit offset as we don't know it because the + // DIE belongs to + // a different compile unit in the same symbol file. + return m_dwarf->DebugInfo()->GetDIEForDIEOffset(die_offset); + } + } + return DWARFDIE(); // Not found +} + +uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) { + if (cu) + return cu->GetAddressByteSize(); + return DWARFUnit::GetDefaultAddressSize(); +} + +bool DWARFUnit::IsDWARF64(const DWARFUnit *cu) { + if (cu) + return cu->IsDWARF64(); + return false; +} + +uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; } + +void *DWARFUnit::GetUserData() const { return m_user_data; } + +void DWARFUnit::SetUserData(void *d) { + m_user_data = d; + if (m_dwo_symbol_file) + m_dwo_symbol_file->GetCompileUnit()->SetUserData(d); +} + +bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() { + if (GetProducer() == eProducerLLVMGCC) + return false; + return true; +} + +bool DWARFUnit::DW_AT_decl_file_attributes_are_invalid() { + // llvm-gcc makes completely invalid decl file attributes and won't ever be + // fixed, so we need to know to ignore these. + return GetProducer() == eProducerLLVMGCC; +} + +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 true; // Assume all other compilers didn't have incorrect ObjC bitfield + // info +} + +SymbolFileDWARF *DWARFUnit::GetSymbolFileDWARF() const { return m_dwarf; } + +void DWARFUnit::ParseProducerInfo() { + m_producer_version_major = UINT32_MAX; + m_producer_version_minor = UINT32_MAX; + m_producer_version_update = UINT32_MAX; + + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + if (die) { + + const char *producer_cstr = + die->GetAttributeValueAsString(m_dwarf, this, DW_AT_producer, NULL); + if (producer_cstr) { + RegularExpression llvm_gcc_regex( + llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " + "Inc\\. build [0-9]+\\) \\(LLVM build " + "[\\.0-9]+\\)$")); + if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) { + m_producer = eProducerLLVMGCC; + } else if (strstr(producer_cstr, "clang")) { + static RegularExpression g_clang_version_regex( + llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)")); + RegularExpression::Match regex_match(3); + if (g_clang_version_regex.Execute(llvm::StringRef(producer_cstr), + ®ex_match)) { + std::string str; + if (regex_match.GetMatchAtIndex(producer_cstr, 1, str)) + m_producer_version_major = + StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); + if (regex_match.GetMatchAtIndex(producer_cstr, 2, str)) + m_producer_version_minor = + StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); + if (regex_match.GetMatchAtIndex(producer_cstr, 3, str)) + m_producer_version_update = + StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); + } + m_producer = eProducerClang; + } else if (strstr(producer_cstr, "GNU")) + m_producer = eProducerGCC; + } + } + if (m_producer == eProducerInvalid) + m_producer = eProcucerOther; +} + +DWARFProducer DWARFUnit::GetProducer() { + if (m_producer == eProducerInvalid) + ParseProducerInfo(); + return m_producer; +} + +uint32_t DWARFUnit::GetProducerVersionMajor() { + if (m_producer_version_major == 0) + ParseProducerInfo(); + return m_producer_version_major; +} + +uint32_t DWARFUnit::GetProducerVersionMinor() { + if (m_producer_version_minor == 0) + ParseProducerInfo(); + return m_producer_version_minor; +} + +uint32_t DWARFUnit::GetProducerVersionUpdate() { + if (m_producer_version_update == 0) + ParseProducerInfo(); + return m_producer_version_update; +} +LanguageType DWARFUnit::LanguageTypeFromDWARF(uint64_t val) { + // Note: user languages between lo_user and hi_user must be handled + // explicitly here. + switch (val) { + case DW_LANG_Mips_Assembler: + return eLanguageTypeMipsAssembler; + case DW_LANG_GOOGLE_RenderScript: + return eLanguageTypeExtRenderScript; + default: + return static_cast<LanguageType>(val); + } +} + +LanguageType DWARFUnit::GetLanguageType() { + if (m_language_type != eLanguageTypeUnknown) + return m_language_type; + + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + if (die) + m_language_type = LanguageTypeFromDWARF( + die->GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_language, 0)); + return m_language_type; +} + +bool DWARFUnit::GetIsOptimized() { + if (m_is_optimized == eLazyBoolCalculate) { + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + if (die) { + m_is_optimized = eLazyBoolNo; + if (die->GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_APPLE_optimized, + 0) == 1) { + m_is_optimized = eLazyBoolYes; + } + } + } + return m_is_optimized == eLazyBoolYes; +} + +SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() const { + return m_dwo_symbol_file.get(); +} + +dw_offset_t DWARFUnit::GetBaseObjOffset() const { return m_base_obj_offset; } + +const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { + if (m_func_aranges_ap.get() == NULL) { + m_func_aranges_ap.reset(new DWARFDebugAranges()); + Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); + + if (log) { + m_dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "DWARFUnit::GetFunctionAranges() for compile unit at " + ".debug_info[0x%8.8x]", + GetOffset()); + } + const DWARFDebugInfoEntry *die = DIEPtr(); + if (die) + die->BuildFunctionAddressRangeTable(m_dwarf, this, + m_func_aranges_ap.get()); + + if (m_dwo_symbol_file) { + DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); + const DWARFDebugInfoEntry *dwo_die = dwo_cu->DIEPtr(); + if (dwo_die) + dwo_die->BuildFunctionAddressRangeTable(m_dwo_symbol_file.get(), dwo_cu, + m_func_aranges_ap.get()); + } + + const bool minimize = false; + m_func_aranges_ap->Sort(minimize); + } + return *m_func_aranges_ap.get(); +} + diff --git a/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFUnit.h new file mode 100644 index 000000000000..c9e48c538bc1 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -0,0 +1,252 @@ +//===-- DWARFUnit.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_DWARFUnit_h_ +#define SymbolFileDWARF_DWARFUnit_h_ + +#include "DWARFDIE.h" +#include "DWARFDebugInfoEntry.h" +#include "lldb/lldb-enumerations.h" +#include "llvm/Support/RWMutex.h" +#include <atomic> + +class DWARFUnit; +class DWARFCompileUnit; +class NameToDIE; +class SymbolFileDWARF; +class SymbolFileDWARFDwo; + +typedef std::shared_ptr<DWARFUnit> DWARFUnitSP; + +enum DWARFProducer { + eProducerInvalid = 0, + eProducerClang, + eProducerGCC, + eProducerLLVMGCC, + eProcucerOther +}; + +class DWARFUnit { + friend class DWARFCompileUnit; + + using die_iterator_range = + llvm::iterator_range<DWARFDebugInfoEntry::collection::iterator>; + +public: + virtual ~DWARFUnit(); + + void ExtractUnitDIEIfNeeded(); + void ExtractDIEsIfNeeded(); + + class ScopedExtractDIEs { + DWARFUnit *m_cu; + public: + bool m_clear_dies = false; + ScopedExtractDIEs(DWARFUnit *cu); + ~ScopedExtractDIEs(); + DISALLOW_COPY_AND_ASSIGN(ScopedExtractDIEs); + ScopedExtractDIEs(ScopedExtractDIEs &&rhs); + ScopedExtractDIEs &operator=(ScopedExtractDIEs &&rhs); + }; + ScopedExtractDIEs ExtractDIEsScoped(); + + DWARFDIE LookupAddress(const dw_addr_t address); + size_t AppendDIEsWithTag(const dw_tag_t tag, + DWARFDIECollection &matching_dies, + uint32_t depth = UINT32_MAX) const; + bool Verify(lldb_private::Stream *s) const; + virtual void Dump(lldb_private::Stream *s) const = 0; + //------------------------------------------------------------------ + /// Get the data that contains the DIE information for this unit. + /// + /// This will return the correct bytes that contain the data for + /// this DWARFUnit. It could be .debug_info or .debug_types + /// depending on where the data for this unit originates. + /// + /// @return + /// The correct data for the DIE information in this unit. + //------------------------------------------------------------------ + virtual const lldb_private::DWARFDataExtractor &GetData() const = 0; + //------------------------------------------------------------------ + /// Get the size in bytes of the compile unit header. + /// + /// @return + /// Byte size of the compile unit header + //------------------------------------------------------------------ + virtual uint32_t GetHeaderByteSize() const = 0; + // Offset of the initial length field. + dw_offset_t GetOffset() const { return m_offset; } + lldb::user_id_t GetID() const; + //------------------------------------------------------------------ + /// Get the size in bytes of the length field in the header. + /// + /// In DWARF32 this is just 4 bytes, and DWARF64 it is 12 where 4 + /// are 0xFFFFFFFF followed by the actual 64 bit length. + /// + /// @return + /// Byte size of the compile unit header length field + //------------------------------------------------------------------ + size_t GetLengthByteSize() const { return IsDWARF64() ? 12 : 4; } + + bool ContainsDIEOffset(dw_offset_t die_offset) const { + return die_offset >= GetFirstDIEOffset() && + die_offset < GetNextCompileUnitOffset(); + } + dw_offset_t GetFirstDIEOffset() const { + return m_offset + GetHeaderByteSize(); + } + dw_offset_t GetNextCompileUnitOffset() const; + // Size of the CU data (without initial length and without header). + size_t GetDebugInfoSize() const; + // Size of the CU data incl. header but without initial length. + uint32_t GetLength() const { return m_length; } + uint16_t GetVersion() const { return m_version; } + const DWARFAbbreviationDeclarationSet *GetAbbreviations() const; + dw_offset_t GetAbbrevOffset() const; + uint8_t GetAddressByteSize() const { return m_addr_size; } + 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); + void BuildAddressRangeTable(SymbolFileDWARF *dwarf, + DWARFDebugAranges *debug_aranges); + + lldb::ByteOrder GetByteOrder() const; + + lldb_private::TypeSystem *GetTypeSystem(); + + const DWARFDebugAranges &GetFunctionAranges(); + + DWARFFormValue::FixedFormSizes GetFixedFormSizes(); + + void SetBaseAddress(dw_addr_t base_addr); + + DWARFBaseDIE GetUnitDIEOnly() { return DWARFDIE(this, GetUnitDIEPtrOnly()); } + + DWARFDIE DIE() { return DWARFDIE(this, DIEPtr()); } + + DWARFDIE GetDIE(dw_offset_t die_offset); + + static uint8_t GetAddressByteSize(const DWARFUnit *cu); + + static bool IsDWARF64(const DWARFUnit *cu); + + static uint8_t GetDefaultAddressSize(); + + void *GetUserData() const; + + void SetUserData(void *d); + + bool Supports_DW_AT_APPLE_objc_complete_type(); + + bool DW_AT_decl_file_attributes_are_invalid(); + + bool Supports_unnamed_objc_bitfields(); + + SymbolFileDWARF *GetSymbolFileDWARF() const; + + DWARFProducer GetProducer(); + + uint32_t GetProducerVersionMajor(); + + uint32_t GetProducerVersionMinor(); + + uint32_t GetProducerVersionUpdate(); + + static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val); + + lldb::LanguageType GetLanguageType(); + + bool IsDWARF64() const { return m_is_dwarf64; } + + bool GetIsOptimized(); + + SymbolFileDWARFDwo *GetDwoSymbolFile() const; + + dw_offset_t GetBaseObjOffset() const; + + die_iterator_range dies() { + ExtractDIEsIfNeeded(); + return die_iterator_range(m_die_array.begin(), m_die_array.end()); + } + +protected: + DWARFUnit(SymbolFileDWARF *dwarf); + + SymbolFileDWARF *m_dwarf = nullptr; + std::unique_ptr<SymbolFileDWARFDwo> m_dwo_symbol_file; + const DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr; + void *m_user_data = nullptr; + // The compile unit debug information entry item + DWARFDebugInfoEntry::collection m_die_array; + mutable llvm::sys::RWMutex m_die_array_mutex; + // It is used for tracking of ScopedExtractDIEs instances. + mutable llvm::sys::RWMutex m_die_array_scoped_mutex; + // ScopedExtractDIEs instances should not call ClearDIEsRWLocked() + // as someone called ExtractDIEsIfNeeded(). + std::atomic<bool> m_cancel_scopes; + // GetUnitDIEPtrOnly() needs to return pointer to the first DIE. + // But the first element of m_die_array after ExtractUnitDIEIfNeeded() + // would possibly move in memory after later ExtractDIEsIfNeeded(). + DWARFDebugInfoEntry m_first_die; + llvm::sys::RWMutex m_first_die_mutex; + // A table similar to the .debug_aranges table, but this one points to the + // exact DW_TAG_subprogram DIEs + std::unique_ptr<DWARFDebugAranges> m_func_aranges_ap; + dw_addr_t m_base_addr = 0; + dw_offset_t m_length = 0; + uint16_t m_version = 0; + uint8_t m_addr_size = 0; + DWARFProducer m_producer = eProducerInvalid; + uint32_t m_producer_version_major = 0; + uint32_t m_producer_version_minor = 0; + uint32_t m_producer_version_update = 0; + lldb::LanguageType m_language_type = lldb::eLanguageTypeUnknown; + bool m_is_dwarf64 = false; + lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; + dw_addr_t m_addr_base = 0; // Value of DW_AT_addr_base + dw_addr_t m_ranges_base = 0; // Value of DW_AT_ranges_base + // 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; + + // Offset of the initial length field. + dw_offset_t m_offset; + +private: + void ParseProducerInfo(); + void ExtractDIEsRWLocked(); + void ClearDIEsRWLocked(); + + // Get the DWARF unit DWARF debug informration entry. Parse the single DIE + // if needed. + const DWARFDebugInfoEntry *GetUnitDIEPtrOnly() { + ExtractUnitDIEIfNeeded(); + // m_first_die_mutex is not required as m_first_die is never cleared. + if (!m_first_die) + return NULL; + return &m_first_die; + } + + // Get all DWARF debug informration entries. Parse all DIEs if needed. + const DWARFDebugInfoEntry *DIEPtr() { + ExtractDIEsIfNeeded(); + if (m_die_array.empty()) + return NULL; + return &m_die_array[0]; + } + + void AddUnitDIE(const DWARFDebugInfoEntry &cu_die); + void ExtractDIEsEndCheck(lldb::offset_t offset) const; + + DISALLOW_COPY_AND_ASSIGN(DWARFUnit); +}; + +#endif // SymbolFileDWARF_DWARFUnit_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp new file mode 100644 index 000000000000..614ff470d161 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -0,0 +1,272 @@ +//===-- DebugNamesDWARFIndex.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/DWARF/DebugNamesDWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" +#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" +#include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb_private; +using namespace lldb; + +static llvm::DWARFDataExtractor ToLLVM(const DWARFDataExtractor &data) { + return llvm::DWARFDataExtractor( + llvm::StringRef(reinterpret_cast<const char *>(data.GetDataStart()), + data.GetByteSize()), + data.GetByteOrder() == eByteOrderLittle, data.GetAddressByteSize()); +} + +llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> +DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names, + DWARFDataExtractor debug_str, + DWARFDebugInfo *debug_info) { + if (!debug_info) { + return llvm::make_error<llvm::StringError>("debug info null", + llvm::inconvertibleErrorCode()); + } + auto index_up = + llvm::make_unique<DebugNames>(ToLLVM(debug_names), ToLLVM(debug_str)); + if (llvm::Error E = index_up->extract()) + return std::move(E); + + return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex( + module, std::move(index_up), debug_names, debug_str, *debug_info)); +} + +llvm::DenseSet<dw_offset_t> +DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { + llvm::DenseSet<dw_offset_t> result; + for (const DebugNames::NameIndex &ni : debug_names) { + for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu) + result.insert(ni.getCUOffset(cu)); + } + return result; +} + +DIERef DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) { + llvm::Optional<uint64_t> cu_offset = entry.getCUOffset(); + if (!cu_offset) + return DIERef(); + + DWARFUnit *cu = m_debug_info.GetCompileUnit(*cu_offset); + if (!cu) + return DIERef(); + + // This initializes the DWO symbol file. It's not possible for + // GetDwoSymbolFile to call this automatically because of mutual recursion + // between this and DWARFDebugInfoEntry::GetAttributeValue. + cu->ExtractUnitDIEIfNeeded(); + uint64_t die_bias = cu->GetDwoSymbolFile() ? 0 : *cu_offset; + + if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset()) + return DIERef(*cu_offset, die_bias + *die_offset); + + return DIERef(); +} + +void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry, + DIEArray &offsets) { + if (DIERef ref = ToDIERef(entry)) + offsets.push_back(ref); +} + +void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error, + const DebugNames::NameIndex &ni, + llvm::StringRef name) { + // Ignore SentinelErrors, log everything else. + LLDB_LOG_ERROR( + LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS), + handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}), + "Failed to parse index entries for index at {1:x}, name {2}: {0}", + ni.getUnitOffset(), name); +} + +void DebugNamesDWARFIndex::GetGlobalVariables(ConstString basename, + DIEArray &offsets) { + m_fallback.GetGlobalVariables(basename, offsets); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(basename.GetStringRef())) { + if (entry.tag() != DW_TAG_variable) + continue; + + Append(entry, offsets); + } +} + +void DebugNamesDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) { + m_fallback.GetGlobalVariables(regex, offsets); + + for (const DebugNames::NameIndex &ni: *m_debug_names_up) { + for (DebugNames::NameTableEntry nte: ni) { + if (!regex.Execute(nte.getString())) + continue; + + uint32_t entry_offset = nte.getEntryOffset(); + llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); + for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { + if (entry_or->tag() != DW_TAG_variable) + continue; + + Append(*entry_or, offsets); + } + MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); + } + } +} + +void DebugNamesDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, + DIEArray &offsets) { + m_fallback.GetGlobalVariables(cu, offsets); + + uint64_t cu_offset = cu.GetOffset(); + for (const DebugNames::NameIndex &ni: *m_debug_names_up) { + for (DebugNames::NameTableEntry nte: ni) { + uint32_t entry_offset = nte.getEntryOffset(); + llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); + for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { + if (entry_or->tag() != DW_TAG_variable) + continue; + if (entry_or->getCUOffset() != cu_offset) + continue; + + Append(*entry_or, offsets); + } + MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); + } + } +} + +void DebugNamesDWARFIndex::GetCompleteObjCClass(ConstString class_name, + bool must_be_implementation, + DIEArray &offsets) { + m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, offsets); + + // Keep a list of incomplete types as fallback for when we don't find the + // complete type. + DIEArray incomplete_types; + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(class_name.GetStringRef())) { + if (entry.tag() != DW_TAG_structure_type && + entry.tag() != DW_TAG_class_type) + continue; + + DIERef ref = ToDIERef(entry); + if (!ref) + continue; + + DWARFUnit *cu = m_debug_info.GetCompileUnit(ref.cu_offset); + if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) { + incomplete_types.push_back(ref); + continue; + } + + // FIXME: We should return DWARFDIEs so we don't have to resolve it twice. + DWARFDIE die = m_debug_info.GetDIE(ref); + if (!die) + continue; + + if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) { + // If we find the complete version we're done. + offsets.push_back(ref); + return; + } else { + incomplete_types.push_back(ref); + } + } + + offsets.insert(offsets.end(), incomplete_types.begin(), + incomplete_types.end()); +} + +void DebugNamesDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { + m_fallback.GetTypes(name, offsets); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(name.GetStringRef())) { + if (isType(entry.tag())) + Append(entry, offsets); + } +} + +void DebugNamesDWARFIndex::GetTypes(const DWARFDeclContext &context, + DIEArray &offsets) { + m_fallback.GetTypes(context, offsets); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(context[0].name)) { + if (entry.tag() == context[0].tag) + Append(entry, offsets); + } +} + +void DebugNamesDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { + m_fallback.GetNamespaces(name, offsets); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(name.GetStringRef())) { + if (entry.tag() == DW_TAG_namespace) + Append(entry, offsets); + } +} + +void DebugNamesDWARFIndex::GetFunctions( + ConstString name, DWARFDebugInfo &info, + 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); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(name.GetStringRef())) { + Tag tag = entry.tag(); + if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) + continue; + + if (DIERef ref = ToDIERef(entry)) + ProcessFunctionDIE(name.GetStringRef(), ref, info, parent_decl_ctx, + name_type_mask, dies); + } +} + +void DebugNamesDWARFIndex::GetFunctions(const RegularExpression ®ex, + DIEArray &offsets) { + m_fallback.GetFunctions(regex, offsets); + + for (const DebugNames::NameIndex &ni: *m_debug_names_up) { + for (DebugNames::NameTableEntry nte: ni) { + if (!regex.Execute(nte.getString())) + continue; + + uint32_t entry_offset = nte.getEntryOffset(); + llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); + for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { + Tag tag = entry_or->tag(); + if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) + continue; + + Append(*entry_or, offsets); + } + MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); + } + } +} + +void DebugNamesDWARFIndex::Dump(Stream &s) { + m_fallback.Dump(s); + + std::string data; + llvm::raw_string_ostream os(data); + m_debug_names_up->dump(os); + s.PutCString(os.str()); +} diff --git a/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h new file mode 100644 index 000000000000..30423c7ca2a2 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -0,0 +1,83 @@ +//===-- DebugNamesDWARFIndex.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_DEBUGNAMESDWARFINDEX_H +#define LLDB_DEBUGNAMESDWARFINDEX_H + +#include "Plugins/SymbolFile/DWARF/DWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" +#include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h" +#include "lldb/Utility/ConstString.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" + +namespace lldb_private { +class DebugNamesDWARFIndex : public DWARFIndex { +public: + static llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> + Create(Module &module, DWARFDataExtractor debug_names, + DWARFDataExtractor debug_str, DWARFDebugInfo *debug_info); + + void Preload() override { m_fallback.Preload(); } + + void GetGlobalVariables(ConstString basename, DIEArray &offsets) override; + void GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) override; + void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) override; + void GetObjCMethods(ConstString class_name, DIEArray &offsets) override {} + void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, + DIEArray &offsets) override; + void GetTypes(ConstString name, DIEArray &offsets) override; + void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override; + void GetNamespaces(ConstString name, DIEArray &offsets) override; + void GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) override; + void GetFunctions(const RegularExpression ®ex, + DIEArray &offsets) override; + + void ReportInvalidDIEOffset(dw_offset_t offset, + llvm::StringRef name) override {} + void Dump(Stream &s) override; + +private: + DebugNamesDWARFIndex(Module &module, + std::unique_ptr<llvm::DWARFDebugNames> debug_names_up, + DWARFDataExtractor debug_names_data, + DWARFDataExtractor debug_str_data, + DWARFDebugInfo &debug_info) + : DWARFIndex(module), m_debug_info(debug_info), + m_debug_names_data(debug_names_data), m_debug_str_data(debug_str_data), + m_debug_names_up(std::move(debug_names_up)), + m_fallback(module, &debug_info, GetUnits(*m_debug_names_up)) {} + + DWARFDebugInfo &m_debug_info; + + // LLVM DWARFDebugNames will hold a non-owning reference to this data, so keep + // track of the ownership here. + DWARFDataExtractor m_debug_names_data; + DWARFDataExtractor m_debug_str_data; + + using DebugNames = llvm::DWARFDebugNames; + std::unique_ptr<DebugNames> m_debug_names_up; + ManualDWARFIndex m_fallback; + + DIERef ToDIERef(const DebugNames::Entry &entry); + void Append(const DebugNames::Entry &entry, DIEArray &offsets); + + static void MaybeLogLookupError(llvm::Error error, + const DebugNames::NameIndex &ni, + llvm::StringRef name); + + static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names); +}; + +} // namespace lldb_private + +#endif // LLDB_DEBUGNAMESDWARFINDEX_H diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp index cb1e5c185613..36211a08557e 100644 --- a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp +++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp @@ -75,15 +75,14 @@ void DWARFMappedHash::ExtractClassOrStructDIEArray( die_tag == DW_TAG_structure_type) { if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) { if (return_implementation_only_if_available) { - // We found the one true definition for this class, so - // only return that + // We found the one true definition for this class, so only return + // that die_offsets.clear(); die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset); return; } else { - // Put the one true definition as the first entry so it - // matches first + // Put the one true definition as the first entry so it matches first die_offsets.emplace(die_offsets.begin(), die_info_array[i].cu_offset, die_info_array[i].offset); } @@ -137,9 +136,8 @@ DWARFMappedHash::DIEInfo::DIEInfo(dw_offset_t c, dw_offset_t o, dw_tag_t t, DWARFMappedHash::Prologue::Prologue(dw_offset_t _die_base_offset) : die_base_offset(_die_base_offset), atoms(), atom_mask(0), min_hash_data_byte_size(0), hash_data_has_fixed_byte_size(true) { - // Define an array of DIE offsets by first defining an array, - // and then define the atom type for the array, in this case - // we have an array of DIE offsets + // Define an array of DIE offsets by first defining an array, and then define + // the atom type for the array, in this case we have an array of DIE offsets AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4); } @@ -239,8 +237,7 @@ DWARFMappedHash::Prologue::Read(const lldb_private::DataExtractor &data, size_t DWARFMappedHash::Prologue::GetByteSize() const { // Add an extra count to the atoms size for the zero termination Atom that - // gets - // written to disk + // gets written to disk return sizeof(die_base_offset) + sizeof(uint32_t) + atoms.size() * sizeof(Atom); } @@ -379,17 +376,18 @@ bool DWARFMappedHash::MemoryTable::ReadHashData(uint32_t hash_data_offset, DWARFMappedHash::MemoryTable::Result DWARFMappedHash::MemoryTable::GetHashDataForName( - const char *name, lldb::offset_t *hash_data_offset_ptr, Pair &pair) const { + llvm::StringRef name, lldb::offset_t *hash_data_offset_ptr, + Pair &pair) const { pair.key = m_data.GetU32(hash_data_offset_ptr); pair.value.clear(); - // If the key is zero, this terminates our chain of HashData objects - // for this hash value. + // If the key is zero, this terminates our chain of HashData objects for this + // hash value. if (pair.key == 0) return eResultEndOfHashData; - // There definitely should be a string for this string offset, if - // there isn't, there is something wrong, return and error + // There definitely should be a string for this string offset, if there + // isn't, there is something wrong, return and error const char *strp_cstr = m_string_table.PeekCStr(pair.key); if (strp_cstr == NULL) { *hash_data_offset_ptr = UINT32_MAX; @@ -402,22 +400,21 @@ DWARFMappedHash::MemoryTable::GetHashDataForName( if (count > 0 && m_data.ValidOffsetForDataOfSize(*hash_data_offset_ptr, min_total_hash_data_size)) { - // We have at least one HashData entry, and we have enough - // data to parse at least "count" HashData entries. + // We have at least one HashData entry, and we have enough data to parse at + // least "count" HashData entries. // First make sure the entire C string matches... - const bool match = strcmp(name, strp_cstr) == 0; + const bool match = name == strp_cstr; if (!match && m_header.header_data.HashDataHasFixedByteSize()) { - // If the string doesn't match and we have fixed size data, - // we can just add the total byte size of all HashData objects - // to the hash data offset and be done... + // If the string doesn't match and we have fixed size data, we can just + // add the total byte size of all HashData objects to the hash data + // offset and be done... *hash_data_offset_ptr += min_total_hash_data_size; } else { - // If the string does match, or we don't have fixed size data - // then we need to read the hash data as a stream. If the - // string matches we also append all HashData objects to the - // value array. + // If the string does match, or we don't have fixed size data then we + // need to read the hash data as a stream. If the string matches we also + // append all HashData objects to the value array. for (uint32_t i = 0; i < count; ++i) { DIEInfo die_info; if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) { @@ -431,16 +428,15 @@ DWARFMappedHash::MemoryTable::GetHashDataForName( } } } - // Return the correct response depending on if the string matched - // or not... + // Return the correct response depending on if the string matched or not... if (match) return eResultKeyMatch; // The key (cstring) matches and we have lookup // results! else return eResultKeyMismatch; // The key doesn't match, this function will // get called - // again for the next key/value or the key terminator - // which in our case is a zero .debug_str offset. + // again for the next key/value or the key terminator which in our case is + // a zero .debug_str offset. } else { *hash_data_offset_ptr = UINT32_MAX; return eResultError; @@ -452,13 +448,13 @@ DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression( const lldb_private::RegularExpression ®ex, lldb::offset_t *hash_data_offset_ptr, Pair &pair) const { pair.key = m_data.GetU32(hash_data_offset_ptr); - // If the key is zero, this terminates our chain of HashData objects - // for this hash value. + // If the key is zero, this terminates our chain of HashData objects for this + // hash value. if (pair.key == 0) return eResultEndOfHashData; - // There definitely should be a string for this string offset, if - // there isn't, there is something wrong, return and error + // There definitely should be a string for this string offset, if there + // isn't, there is something wrong, return and error const char *strp_cstr = m_string_table.PeekCStr(pair.key); if (strp_cstr == NULL) return eResultError; @@ -472,15 +468,14 @@ DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression( const bool match = regex.Execute(llvm::StringRef(strp_cstr)); if (!match && m_header.header_data.HashDataHasFixedByteSize()) { - // If the regex doesn't match and we have fixed size data, - // we can just add the total byte size of all HashData objects - // to the hash data offset and be done... + // If the regex doesn't match and we have fixed size data, we can just + // add the total byte size of all HashData objects to the hash data + // offset and be done... *hash_data_offset_ptr += min_total_hash_data_size; } else { - // If the string does match, or we don't have fixed size data - // then we need to read the hash data as a stream. If the - // string matches we also append all HashData objects to the - // value array. + // If the string does match, or we don't have fixed size data then we + // need to read the hash data as a stream. If the string matches we also + // append all HashData objects to the value array. for (uint32_t i = 0; i < count; ++i) { DIEInfo die_info; if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) { @@ -494,16 +489,15 @@ DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression( } } } - // Return the correct response depending on if the string matched - // or not... + // Return the correct response depending on if the string matched or not... if (match) return eResultKeyMatch; // The key (cstring) matches and we have lookup // results! else return eResultKeyMismatch; // The key doesn't match, this function will // get called - // again for the next key/value or the key terminator - // which in our case is a zero .debug_str offset. + // again for the next key/value or the key terminator which in our case is + // a zero .debug_str offset. } else { *hash_data_offset_ptr = UINT32_MAX; return eResultError; @@ -528,8 +522,7 @@ size_t DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex( switch (hash_result) { case eResultKeyMatch: case eResultKeyMismatch: - // Whether we matches or not, it doesn't matter, we - // keep looking. + // Whether we matches or not, it doesn't matter, we keep looking. break; case eResultEndOfHashData: @@ -552,8 +545,8 @@ size_t DWARFMappedHash::MemoryTable::AppendAllDIEsInRange( lldb::offset_t hash_data_offset = GetHashDataOffset(offset_idx); while (!done && hash_data_offset != UINT32_MAX) { KeyType key = m_data.GetU32(&hash_data_offset); - // If the key is zero, this terminates our chain of HashData objects - // for this hash value. + // If the key is zero, this terminates our chain of HashData objects for + // this hash value. if (key == 0) break; @@ -573,9 +566,9 @@ size_t DWARFMappedHash::MemoryTable::AppendAllDIEsInRange( return die_info_array.size(); } -size_t DWARFMappedHash::MemoryTable::FindByName(const char *name, +size_t DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name, DIEArray &die_offsets) { - if (!name || !name[0]) + if (name.empty()) return 0; DIEInfoArray die_info_array; @@ -584,7 +577,7 @@ size_t DWARFMappedHash::MemoryTable::FindByName(const char *name, return die_info_array.size(); } -size_t DWARFMappedHash::MemoryTable::FindByNameAndTag(const char *name, +size_t DWARFMappedHash::MemoryTable::FindByNameAndTag(llvm::StringRef name, const dw_tag_t tag, DIEArray &die_offsets) { DIEInfoArray die_info_array; @@ -594,8 +587,8 @@ size_t DWARFMappedHash::MemoryTable::FindByNameAndTag(const char *name, } size_t DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash( - const char *name, const dw_tag_t tag, const uint32_t qualified_name_hash, - DIEArray &die_offsets) { + llvm::StringRef name, const dw_tag_t tag, + const uint32_t qualified_name_hash, DIEArray &die_offsets) { DIEInfoArray die_info_array; if (FindByName(name, die_info_array)) DWARFMappedHash::ExtractDIEArray(die_info_array, tag, qualified_name_hash, @@ -604,22 +597,21 @@ size_t DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash( } size_t DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName( - const char *name, DIEArray &die_offsets, bool must_be_implementation) { + llvm::StringRef name, DIEArray &die_offsets, bool must_be_implementation) { DIEInfoArray die_info_array; if (FindByName(name, die_info_array)) { if (must_be_implementation && GetHeader().header_data.ContainsAtom(eAtomTypeTypeFlags)) { - // If we have two atoms, then we have the DIE offset and - // the type flags so we can find the objective C class - // efficiently. + // If we have two atoms, then we have the DIE offset and the type flags + // so we can find the objective C class efficiently. DWARFMappedHash::ExtractTypesFromDIEArray(die_info_array, UINT32_MAX, eTypeFlagClassIsImplementation, die_offsets); } else { - // We don't only want the one true definition, so try and see - // what we can find, and only return class or struct DIEs. - // If we do have the full implementation, then return it alone, - // else return all possible matches. + // We don't only want the one true definition, so try and see what we can + // find, and only return class or struct DIEs. If we do have the full + // implementation, then return it alone, else return all possible + // matches. const bool return_implementation_only_if_available = true; DWARFMappedHash::ExtractClassOrStructDIEArray( die_info_array, return_implementation_only_if_available, die_offsets); @@ -628,9 +620,9 @@ size_t DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName( return die_offsets.size(); } -size_t DWARFMappedHash::MemoryTable::FindByName(const char *name, +size_t DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name, DIEInfoArray &die_info_array) { - if (!name || !name[0]) + if (name.empty()) return 0; Pair kv_pair; diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h index 959517529e52..17600df2edd4 100644 --- a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h +++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h @@ -21,10 +21,6 @@ #include "DWARFFormValue.h" #include "NameToDIE.h" -class SymbolFileDWARF; -class DWARFCompileUnit; -class DWARFDebugInfoEntry; - class DWARFMappedHash { public: enum AtomType : uint16_t { @@ -136,17 +132,17 @@ public: const uint32_t die_offset_end, DIEInfoArray &die_info_array) const; - size_t FindByName(const char *name, DIEArray &die_offsets); + size_t FindByName(llvm::StringRef name, DIEArray &die_offsets); - size_t FindByNameAndTag(const char *name, const dw_tag_t tag, + size_t FindByNameAndTag(llvm::StringRef name, const dw_tag_t tag, DIEArray &die_offsets); - size_t - FindByNameAndTagAndQualifiedNameHash(const char *name, const dw_tag_t tag, - const uint32_t qualified_name_hash, - DIEArray &die_offsets); + size_t FindByNameAndTagAndQualifiedNameHash( + llvm::StringRef name, const dw_tag_t tag, + const uint32_t qualified_name_hash, DIEArray &die_offsets); - size_t FindCompleteObjCClassByName(const char *name, DIEArray &die_offsets, + size_t FindCompleteObjCClassByName(llvm::StringRef name, + DIEArray &die_offsets, bool must_be_implementation); protected: @@ -154,14 +150,14 @@ public: const lldb_private::RegularExpression ®ex, lldb::offset_t *hash_data_offset_ptr, Pair &pair) const; - size_t FindByName(const char *name, DIEInfoArray &die_info_array); + size_t FindByName(llvm::StringRef name, DIEInfoArray &die_info_array); - Result GetHashDataForName(const char *name, + Result GetHashDataForName(llvm::StringRef name, lldb::offset_t *hash_data_offset_ptr, Pair &pair) const override; - const lldb_private::DWARFDataExtractor &m_data; - const lldb_private::DWARFDataExtractor &m_string_table; + lldb_private::DWARFDataExtractor m_data; + lldb_private::DWARFDataExtractor m_string_table; std::string m_name; }; diff --git a/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp new file mode 100644 index 000000000000..6438f02fe8ec --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -0,0 +1,488 @@ +//===-- ManualDWARFIndex.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/DWARF/ManualDWARFIndex.h" +#include "Plugins/Language/ObjC/ObjCLanguage.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" +#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" +#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" +#include "lldb/Core/Module.h" +#include "lldb/Host/TaskPool.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" + +using namespace lldb_private; +using namespace lldb; + +void ManualDWARFIndex::Index() { + if (!m_debug_info) + return; + + DWARFDebugInfo &debug_info = *m_debug_info; + m_debug_info = nullptr; + + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer(func_cat, "%p", static_cast<void *>(&debug_info)); + + std::vector<DWARFUnit *> units_to_index; + units_to_index.reserve(debug_info.GetNumCompileUnits()); + for (size_t U = 0; U < debug_info.GetNumCompileUnits(); ++U) { + DWARFUnit *unit = debug_info.GetCompileUnitAtIndex(U); + if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0) + units_to_index.push_back(unit); + } + if (units_to_index.empty()) + return; + + std::vector<IndexSet> sets(units_to_index.size()); + + //---------------------------------------------------------------------- + // Keep memory down by clearing DIEs for any compile units if indexing + // caused us to load the compile unit's DIEs. + //---------------------------------------------------------------------- + std::vector<llvm::Optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies( + units_to_index.size()); + auto parser_fn = [&](size_t cu_idx) { + IndexUnit(*units_to_index[cu_idx], sets[cu_idx]); + }; + + auto extract_fn = [&units_to_index, &clear_cu_dies](size_t cu_idx) { + clear_cu_dies[cu_idx] = units_to_index[cu_idx]->ExtractDIEsScoped(); + }; + + // Create a task runner that extracts dies for each DWARF compile unit in a + // separate thread + //---------------------------------------------------------------------- + // First figure out which compile units didn't have their DIEs already + // parsed and remember this. If no DIEs were parsed prior to this index + // function call, we are going to want to clear the CU dies after we are + // done indexing to make sure we don't pull in all DWARF dies, but we need + // to wait until all compile units have been indexed in case a DIE in one + // compile unit refers to another and the indexes accesses those DIEs. + //---------------------------------------------------------------------- + TaskMapOverInt(0, units_to_index.size(), extract_fn); + + // Now create a task runner that can index each DWARF compile unit in a + // separate thread so we can index quickly. + + TaskMapOverInt(0, units_to_index.size(), parser_fn); + + auto finalize_fn = [this, &sets](NameToDIE(IndexSet::*index)) { + NameToDIE &result = m_set.*index; + for (auto &set : sets) + result.Append(set.*index); + result.Finalize(); + }; + + TaskPool::RunTasks([&]() { finalize_fn(&IndexSet::function_basenames); }, + [&]() { finalize_fn(&IndexSet::function_fullnames); }, + [&]() { finalize_fn(&IndexSet::function_methods); }, + [&]() { finalize_fn(&IndexSet::function_selectors); }, + [&]() { finalize_fn(&IndexSet::objc_class_selectors); }, + [&]() { finalize_fn(&IndexSet::globals); }, + [&]() { finalize_fn(&IndexSet::types); }, + [&]() { finalize_fn(&IndexSet::namespaces); }); +} + +void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, IndexSet &set) { + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS); + + if (log) { + m_module.LogMessage( + log, "ManualDWARFIndex::IndexUnit for compile unit at .debug_info[0x%8.8x]", + unit.GetOffset()); + } + + const LanguageType cu_language = unit.GetLanguageType(); + DWARFFormValue::FixedFormSizes fixed_form_sizes = unit.GetFixedFormSizes(); + + IndexUnitImpl(unit, cu_language, fixed_form_sizes, unit.GetOffset(), set); + + SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile(); + if (dwo_symbol_file && dwo_symbol_file->GetCompileUnit()) { + IndexUnitImpl(*dwo_symbol_file->GetCompileUnit(), cu_language, + fixed_form_sizes, unit.GetOffset(), set); + } +} + +void ManualDWARFIndex::IndexUnitImpl( + DWARFUnit &unit, const LanguageType cu_language, + const DWARFFormValue::FixedFormSizes &fixed_form_sizes, + const dw_offset_t cu_offset, IndexSet &set) { + for (const DWARFDebugInfoEntry &die : unit.dies()) { + const dw_tag_t tag = die.Tag(); + + switch (tag) { + case DW_TAG_array_type: + case DW_TAG_base_type: + case DW_TAG_class_type: + case DW_TAG_constant: + case DW_TAG_enumeration_type: + case DW_TAG_inlined_subroutine: + case DW_TAG_namespace: + case DW_TAG_string_type: + case DW_TAG_structure_type: + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: + case DW_TAG_typedef: + case DW_TAG_union_type: + case DW_TAG_unspecified_type: + case DW_TAG_variable: + break; + + default: + continue; + } + + DWARFAttributes attributes; + const char *name = NULL; + const char *mangled_cstr = NULL; + bool is_declaration = false; + // bool is_artificial = false; + bool has_address = false; + bool has_location_or_const_value = false; + bool is_global_or_static_variable = false; + + DWARFFormValue specification_die_form; + const size_t num_attributes = + die.GetAttributes(&unit, fixed_form_sizes, attributes); + if (num_attributes > 0) { + for (uint32_t i = 0; i < num_attributes; ++i) { + dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + switch (attr) { + case DW_AT_name: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + name = form_value.AsCString(); + break; + + case DW_AT_declaration: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + is_declaration = form_value.Unsigned() != 0; + break; + + // case DW_AT_artificial: + // if (attributes.ExtractFormValueAtIndex(i, + // form_value)) + // is_artificial = form_value.Unsigned() != 0; + // break; + + case DW_AT_MIPS_linkage_name: + case DW_AT_linkage_name: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + mangled_cstr = form_value.AsCString(); + break; + + case DW_AT_low_pc: + case DW_AT_high_pc: + case DW_AT_ranges: + has_address = true; + break; + + case DW_AT_entry_pc: + has_address = true; + break; + + case DW_AT_location: + case DW_AT_const_value: + has_location_or_const_value = true; + if (tag == DW_TAG_variable) { + const DWARFDebugInfoEntry *parent_die = die.GetParent(); + while (parent_die != NULL) { + switch (parent_die->Tag()) { + case DW_TAG_subprogram: + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + // Even if this is a function level static, we don't add it. We + // could theoretically add these if we wanted to by + // introspecting into the DW_AT_location and seeing if the + // location describes a hard coded address, but we don't want + // the performance penalty of that right now. + is_global_or_static_variable = false; + // if (attributes.ExtractFormValueAtIndex(dwarf, i, + // form_value)) { + // // If we have valid block data, then we have location + // // expression bytesthat are fixed (not a location list). + // const uint8_t *block_data = form_value.BlockData(); + // if (block_data) { + // uint32_t block_length = form_value.Unsigned(); + // if (block_length == 1 + + // attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) { + // if (block_data[0] == DW_OP_addr) + // add_die = true; + // } + // } + // } + parent_die = NULL; // Terminate the while loop. + break; + + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + is_global_or_static_variable = true; + parent_die = NULL; // Terminate the while loop. + break; + + default: + parent_die = + parent_die->GetParent(); // Keep going in the while loop. + break; + } + } + } + break; + + case DW_AT_specification: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + specification_die_form = form_value; + break; + } + } + } + + switch (tag) { + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + if (has_address) { + if (name) { + ObjCLanguage::MethodName objc_method(name, true); + if (objc_method.IsValid(true)) { + ConstString objc_class_name_with_category( + objc_method.GetClassNameWithCategory()); + ConstString objc_selector_name(objc_method.GetSelector()); + ConstString objc_fullname_no_category_name( + objc_method.GetFullNameWithoutCategory(true)); + ConstString objc_class_name_no_category(objc_method.GetClassName()); + set.function_fullnames.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + if (objc_class_name_with_category) + set.objc_class_selectors.Insert( + objc_class_name_with_category, + DIERef(cu_offset, die.GetOffset())); + if (objc_class_name_no_category && + objc_class_name_no_category != objc_class_name_with_category) + set.objc_class_selectors.Insert( + objc_class_name_no_category, + DIERef(cu_offset, die.GetOffset())); + if (objc_selector_name) + set.function_selectors.Insert(objc_selector_name, + DIERef(cu_offset, die.GetOffset())); + if (objc_fullname_no_category_name) + set.function_fullnames.Insert(objc_fullname_no_category_name, + DIERef(cu_offset, die.GetOffset())); + } + // If we have a mangled name, then the DW_AT_name attribute is + // usually the method name without the class or any parameters + bool is_method = DWARFDIE(&unit, &die).IsMethod(); + + if (is_method) + set.function_methods.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + else + set.function_basenames.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + + if (!is_method && !mangled_cstr && !objc_method.IsValid(true)) + set.function_fullnames.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + } + if (mangled_cstr) { + // Make sure our mangled name isn't the same string table entry as + // our name. If it starts with '_', then it is ok, else compare the + // string to make sure it isn't the same and we don't end up with + // duplicate entries + if (name && name != mangled_cstr && + ((mangled_cstr[0] == '_') || + (::strcmp(name, mangled_cstr) != 0))) { + set.function_fullnames.Insert(ConstString(mangled_cstr), + DIERef(cu_offset, die.GetOffset())); + } + } + } + break; + + case DW_TAG_array_type: + case DW_TAG_base_type: + case DW_TAG_class_type: + case DW_TAG_constant: + case DW_TAG_enumeration_type: + case DW_TAG_string_type: + case DW_TAG_structure_type: + case DW_TAG_subroutine_type: + case DW_TAG_typedef: + case DW_TAG_union_type: + case DW_TAG_unspecified_type: + if (name && !is_declaration) + set.types.Insert(ConstString(name), DIERef(cu_offset, die.GetOffset())); + if (mangled_cstr && !is_declaration) + set.types.Insert(ConstString(mangled_cstr), + DIERef(cu_offset, die.GetOffset())); + break; + + case DW_TAG_namespace: + if (name) + set.namespaces.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + break; + + case DW_TAG_variable: + if (name && has_location_or_const_value && is_global_or_static_variable) { + set.globals.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + // Be sure to include variables by their mangled and demangled names if + // they have any since a variable can have a basename "i", a mangled + // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name + // "(anonymous namespace)::i"... + + // Make sure our mangled name isn't the same string table entry as our + // name. If it starts with '_', then it is ok, else compare the string + // to make sure it isn't the same and we don't end up with duplicate + // entries + if (mangled_cstr && name != mangled_cstr && + ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { + set.globals.Insert(ConstString(mangled_cstr), + DIERef(cu_offset, die.GetOffset())); + } + } + break; + + default: + continue; + } + } +} + +void ManualDWARFIndex::GetGlobalVariables(ConstString basename, DIEArray &offsets) { + Index(); + m_set.globals.Find(basename, offsets); +} + +void ManualDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) { + Index(); + m_set.globals.Find(regex, offsets); +} + +void ManualDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, + DIEArray &offsets) { + Index(); + m_set.globals.FindAllEntriesForCompileUnit(cu.GetOffset(), offsets); +} + +void ManualDWARFIndex::GetObjCMethods(ConstString class_name, + DIEArray &offsets) { + Index(); + m_set.objc_class_selectors.Find(class_name, offsets); +} + +void ManualDWARFIndex::GetCompleteObjCClass(ConstString class_name, + bool must_be_implementation, + DIEArray &offsets) { + Index(); + m_set.types.Find(class_name, offsets); +} + +void ManualDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { + Index(); + m_set.types.Find(name, offsets); +} + +void ManualDWARFIndex::GetTypes(const DWARFDeclContext &context, + DIEArray &offsets) { + Index(); + m_set.types.Find(ConstString(context[0].name), offsets); +} + +void ManualDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { + Index(); + m_set.namespaces.Find(name, offsets); +} + +void ManualDWARFIndex::GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) { + Index(); + + if (name_type_mask & eFunctionNameTypeFull) { + DIEArray offsets; + m_set.function_basenames.Find(name, offsets); + m_set.function_methods.Find(name, offsets); + m_set.function_fullnames.Find(name, offsets); + for (const DIERef &die_ref: offsets) { + DWARFDIE die = info.GetDIE(die_ref); + if (!die) + continue; + if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) + dies.push_back(die); + } + } + if (name_type_mask & eFunctionNameTypeBase) { + DIEArray offsets; + m_set.function_basenames.Find(name, offsets); + for (const DIERef &die_ref: offsets) { + DWARFDIE die = info.GetDIE(die_ref); + if (!die) + continue; + if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) + dies.push_back(die); + } + offsets.clear(); + } + + if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) { + DIEArray offsets; + m_set.function_methods.Find(name, offsets); + for (const DIERef &die_ref: offsets) { + if (DWARFDIE die = info.GetDIE(die_ref)) + dies.push_back(die); + } + } + + if (name_type_mask & eFunctionNameTypeSelector && + !parent_decl_ctx.IsValid()) { + DIEArray offsets; + m_set.function_selectors.Find(name, offsets); + for (const DIERef &die_ref: offsets) { + if (DWARFDIE die = info.GetDIE(die_ref)) + dies.push_back(die); + } + } +} + +void ManualDWARFIndex::GetFunctions(const RegularExpression ®ex, + DIEArray &offsets) { + Index(); + + m_set.function_basenames.Find(regex, offsets); + m_set.function_fullnames.Find(regex, offsets); +} + +void ManualDWARFIndex::Dump(Stream &s) { + s.Format("Manual DWARF index for ({0}) '{1:F}':", + m_module.GetArchitecture().GetArchitectureName(), + m_module.GetObjectFile()->GetFileSpec()); + s.Printf("\nFunction basenames:\n"); + m_set.function_basenames.Dump(&s); + s.Printf("\nFunction fullnames:\n"); + m_set.function_fullnames.Dump(&s); + s.Printf("\nFunction methods:\n"); + m_set.function_methods.Dump(&s); + s.Printf("\nFunction selectors:\n"); + m_set.function_selectors.Dump(&s); + s.Printf("\nObjective-C class selectors:\n"); + m_set.objc_class_selectors.Dump(&s); + s.Printf("\nGlobals and statics:\n"); + m_set.globals.Dump(&s); + s.Printf("\nTypes:\n"); + m_set.types.Dump(&s); + s.Printf("\nNamespaces:\n"); + m_set.namespaces.Dump(&s); +} diff --git a/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h new file mode 100644 index 000000000000..79ab1d95b380 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h @@ -0,0 +1,75 @@ +//===-- ManulaDWARFIndex.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_MANUALDWARFINDEX_H +#define LLDB_MANUALDWARFINDEX_H + +#include "Plugins/SymbolFile/DWARF/DWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/NameToDIE.h" +#include "llvm/ADT/DenseSet.h" + +namespace lldb_private { +class ManualDWARFIndex : public DWARFIndex { +public: + ManualDWARFIndex(Module &module, DWARFDebugInfo *debug_info, + llvm::DenseSet<dw_offset_t> units_to_avoid = {}) + : DWARFIndex(module), m_debug_info(debug_info), + m_units_to_avoid(std::move(units_to_avoid)) {} + + void Preload() override { Index(); } + + void GetGlobalVariables(ConstString basename, DIEArray &offsets) override; + void GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) override; + void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) override; + void GetObjCMethods(ConstString class_name, DIEArray &offsets) override; + void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, + DIEArray &offsets) override; + void GetTypes(ConstString name, DIEArray &offsets) override; + void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override; + void GetNamespaces(ConstString name, DIEArray &offsets) override; + void GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) override; + void GetFunctions(const RegularExpression ®ex, DIEArray &offsets) override; + + void ReportInvalidDIEOffset(dw_offset_t offset, + llvm::StringRef name) override {} + void Dump(Stream &s) override; + +private: + struct IndexSet { + NameToDIE function_basenames; + NameToDIE function_fullnames; + NameToDIE function_methods; + NameToDIE function_selectors; + NameToDIE objc_class_selectors; + NameToDIE globals; + NameToDIE types; + NameToDIE namespaces; + }; + void Index(); + void IndexUnit(DWARFUnit &unit, IndexSet &set); + + static void + IndexUnitImpl(DWARFUnit &unit, const lldb::LanguageType cu_language, + const DWARFFormValue::FixedFormSizes &fixed_form_sizes, + const dw_offset_t cu_offset, IndexSet &set); + + /// Non-null value means we haven't built the index yet. + DWARFDebugInfo *m_debug_info; + /// Which dwarf units should we skip while building the index. + llvm::DenseSet<dw_offset_t> m_units_to_avoid; + + IndexSet m_set; +}; +} // namespace lldb_private + +#endif // LLDB_MANUALDWARFINDEX_H diff --git a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp index c97680eda0fe..c8d6bba16976 100644 --- a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp +++ b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp @@ -14,7 +14,6 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" -#include "DWARFCompileUnit.h" #include "DWARFDebugInfo.h" #include "DWARFDebugInfoEntry.h" #include "SymbolFileDWARF.h" diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index f149ec354f08..ac320ac52b08 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -27,6 +27,7 @@ #include "lldb/Utility/Timer.h" #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" +#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" @@ -49,27 +50,24 @@ #include "lldb/Symbol/TypeSystem.h" #include "lldb/Symbol/VariableList.h" -#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" -#include "Plugins/Language/ObjC/ObjCLanguage.h" - #include "lldb/Target/Language.h" -#include "lldb/Host/TaskPool.h" - +#include "AppleDWARFIndex.h" #include "DWARFASTParser.h" #include "DWARFASTParserClang.h" -#include "DWARFCompileUnit.h" #include "DWARFDIECollection.h" #include "DWARFDebugAbbrev.h" #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" #include "DWARFDebugLine.h" #include "DWARFDebugMacro.h" -#include "DWARFDebugPubnames.h" #include "DWARFDebugRanges.h" #include "DWARFDeclContext.h" #include "DWARFFormValue.h" +#include "DWARFUnit.h" +#include "DebugNamesDWARFIndex.h" #include "LogChannelDWARF.h" +#include "ManualDWARFIndex.h" #include "SymbolFileDWARFDebugMap.h" #include "SymbolFileDWARFDwo.h" #include "SymbolFileDWARFDwp.h" @@ -115,11 +113,20 @@ namespace { 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."}, - {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, 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 indexes present in the object files and always index DWARF " + "manually."}, + {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}, +}; -enum { ePropertySymLinkPaths }; +enum { + ePropertySymLinkPaths, + ePropertyIgnoreIndexes, +}; class PluginProperties : public Properties { public: @@ -139,6 +146,11 @@ public: assert(option_value); return option_value->GetCurrentValue(); } + + bool IgnoreFileIndexes() const { + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, ePropertyIgnoreIndexes, false); + } }; typedef std::shared_ptr<PluginProperties> SymbolFileDWARFPropertiesSP; @@ -165,8 +177,8 @@ static const char *removeHostnameFromPathname(const char *path_from_dwarf) { return path_from_dwarf; } - // check whether we have a windows path, and so the first character - // is a drive-letter not a hostname. + // check whether we have a windows path, and so the first character is a + // drive-letter not a hostname. if (colon_pos == path_from_dwarf + 1 && isalpha(*path_from_dwarf) && strlen(path_from_dwarf) > 2 && '\\' == path_from_dwarf[2]) { return path_from_dwarf; @@ -175,41 +187,42 @@ static const char *removeHostnameFromPathname(const char *path_from_dwarf) { return colon_pos + 1; } -static const char *resolveCompDir(const char *path_from_dwarf) { +static FileSpec resolveCompDir(const char *path_from_dwarf) { if (!path_from_dwarf) - return nullptr; + return FileSpec(); // DWARF2/3 suggests the form hostname:pathname for compilation directory. // Remove the host part if present. const char *local_path = removeHostnameFromPathname(path_from_dwarf); if (!local_path) - return nullptr; + return FileSpec(); bool is_symlink = false; - FileSpec local_path_spec(local_path, 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); 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), - local_path_spec, true); + local_spec, true); if (!is_symlink) - return local_path; + return local_spec; namespace fs = llvm::sys::fs; - if (fs::get_file_type(local_path_spec.GetPath(), false) != + if (fs::get_file_type(local_spec.GetPath(), false) != fs::file_type::symlink_file) - return local_path; + return local_spec; - FileSpec resolved_local_path_spec; - const auto error = - FileSystem::Readlink(local_path_spec, resolved_local_path_spec); + FileSpec resolved_symlink; + const auto error = FileSystem::Readlink(local_spec, resolved_symlink); if (error.Success()) - return resolved_local_path_spec.GetCString(); + return resolved_symlink; - return nullptr; + return local_spec; } -DWARFCompileUnit *SymbolFileDWARF::GetBaseCompileUnit() { +DWARFUnit *SymbolFileDWARF::GetBaseCompileUnit() { return nullptr; } @@ -334,7 +347,7 @@ size_t SymbolFileDWARF::GetTypes(SymbolContextScope *sc_scope, TypeSet type_set; CompileUnit *comp_unit = NULL; - DWARFCompileUnit *dwarf_cu = NULL; + DWARFUnit *dwarf_cu = NULL; if (sc_scope) comp_unit = sc_scope->CalculateSymbolContextCompileUnit(); @@ -382,6 +395,7 @@ SymbolFileDWARF::GetParentSymbolContextDIE(const DWARFDIE &child_die) { switch (tag) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: case DW_TAG_subprogram: case DW_TAG_inlined_subroutine: case DW_TAG_lexical_block: @@ -392,20 +406,16 @@ SymbolFileDWARF::GetParentSymbolContextDIE(const DWARFDIE &child_die) { } SymbolFileDWARF::SymbolFileDWARF(ObjectFile *objfile) - : SymbolFile(objfile), UserID(0), // Used by SymbolFileDWARFDebugMap to when - // this class parses .o files to contain - // the .o file index/ID + : SymbolFile(objfile), UserID(uint64_t(DW_INVALID_OFFSET) + << 32), // Used by SymbolFileDWARFDebugMap to + // when this class parses .o files to + // contain the .o file index/ID 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_apple_names_ap(), m_apple_types_ap(), m_apple_namespaces_ap(), - m_apple_objc_ap(), m_function_basename_index(), - m_function_fullname_index(), m_function_method_index(), - m_function_selector_index(), m_objc_class_selectors_index(), - m_global_index(), m_type_index(), m_namespace_index(), m_indexed(false), - m_using_apple_tables(false), m_fetched_external_modules(false), + m_line(), m_fetched_external_modules(false), m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate), m_ranges(), m_unique_ast_type_map() {} @@ -438,6 +448,7 @@ TypeSystem *SymbolFileDWARF::GetTypeSystemForLanguage(LanguageType language) { } void SymbolFileDWARF::InitializeObject() { + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); ModuleSP module_sp(m_obj_file->GetModule()); if (module_sp) { const SectionList *section_list = module_sp->GetSectionList(); @@ -448,45 +459,38 @@ void SymbolFileDWARF::InitializeObject() { m_obj_file->ReadSectionData(section, m_dwarf_data); } - get_apple_names_data(); - if (m_data_apple_names.m_data.GetByteSize() > 0) { - m_apple_names_ap.reset(new DWARFMappedHash::MemoryTable( - m_data_apple_names.m_data, get_debug_str_data(), ".apple_names")); - if (m_apple_names_ap->IsValid()) - m_using_apple_tables = true; - else - m_apple_names_ap.reset(); - } - get_apple_types_data(); - if (m_data_apple_types.m_data.GetByteSize() > 0) { - m_apple_types_ap.reset(new DWARFMappedHash::MemoryTable( - m_data_apple_types.m_data, get_debug_str_data(), ".apple_types")); - if (m_apple_types_ap->IsValid()) - m_using_apple_tables = true; - else - m_apple_types_ap.reset(); - } + if (!GetGlobalPluginProperties()->IgnoreFileIndexes()) { + DWARFDataExtractor apple_names, apple_namespaces, apple_types, apple_objc; + LoadSectionData(eSectionTypeDWARFAppleNames, apple_names); + LoadSectionData(eSectionTypeDWARFAppleNamespaces, apple_namespaces); + LoadSectionData(eSectionTypeDWARFAppleTypes, apple_types); + LoadSectionData(eSectionTypeDWARFAppleObjC, apple_objc); - get_apple_namespaces_data(); - if (m_data_apple_namespaces.m_data.GetByteSize() > 0) { - m_apple_namespaces_ap.reset(new DWARFMappedHash::MemoryTable( - m_data_apple_namespaces.m_data, get_debug_str_data(), - ".apple_namespaces")); - if (m_apple_namespaces_ap->IsValid()) - m_using_apple_tables = true; - else - m_apple_namespaces_ap.reset(); - } + m_index = AppleDWARFIndex::Create( + *GetObjectFile()->GetModule(), apple_names, apple_namespaces, + apple_types, apple_objc, get_debug_str_data()); - get_apple_objc_data(); - if (m_data_apple_objc.m_data.GetByteSize() > 0) { - m_apple_objc_ap.reset(new DWARFMappedHash::MemoryTable( - m_data_apple_objc.m_data, get_debug_str_data(), ".apple_objc")); - if (m_apple_objc_ap->IsValid()) - m_using_apple_tables = true; - else - m_apple_objc_ap.reset(); + if (m_index) + return; + + DWARFDataExtractor debug_names; + LoadSectionData(eSectionTypeDWARFDebugNames, debug_names); + if (debug_names.GetByteSize() > 0) { + llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> index_or = + DebugNamesDWARFIndex::Create(*GetObjectFile()->GetModule(), + debug_names, get_debug_str_data(), + DebugInfo()); + if (index_or) { + m_index = std::move(*index_or); + return; + } + LLDB_LOG_ERROR(log, index_or.takeError(), + "Unable to read .debug_names data: {0}"); + } } + + m_index = llvm::make_unique<ManualDWARFIndex>(*GetObjectFile()->GetModule(), + DebugInfo()); } bool SymbolFileDWARF::SupportedVersion(uint16_t version) { @@ -501,15 +505,14 @@ uint32_t SymbolFileDWARF::CalculateAbilities() { if (section_list == NULL) return 0; - // On non Apple platforms we might have .debug_types debug info that - // is created by using "-fdebug-types-section". LLDB currently will try - // to load this debug info, but it causes crashes during debugging when - // types are missing since it doesn't know how to parse the info in - // the .debug_types type units. This causes all complex debug info - // types to be unresolved. Because this causes LLDB to crash and since - // it really doesn't provide a solid debuggiung experience, we should - // disable trying to debug this kind of DWARF until support gets - // added or deprecated. + // On non Apple platforms we might have .debug_types debug info that is + // created by using "-fdebug-types-section". LLDB currently will try to + // load this debug info, but it causes crashes during debugging when types + // are missing since it doesn't know how to parse the info in the + // .debug_types type units. This causes all complex debug info types to be + // unresolved. Because this causes LLDB to crash and since it really + // doesn't provide a solid debuggiung experience, we should disable trying + // to debug this kind of DWARF until support gets added or deprecated. if (section_list->FindSectionByName(ConstString(".debug_types"))) { m_obj_file->GetModule()->ReportWarning( "lldb doesn’t support .debug_types debug info"); @@ -561,10 +564,10 @@ uint32_t SymbolFileDWARF::CalculateAbilities() { if (symfile_dir_cstr) { if (strcasestr(symfile_dir_cstr, ".dsym")) { if (m_obj_file->GetType() == ObjectFile::eTypeDebugInfo) { - // We have a dSYM file that didn't have a any debug info. - // If the string table has a size of 1, then it was made from - // an executable with no debug info, or from an executable that - // was stripped. + // We have a dSYM file that didn't have a any debug info. If the + // string table has a size of 1, then it was made from an + // executable with no debug info, or from an executable that was + // stripped. section = section_list->FindSectionByType(eSectionTypeDWARFDebugStr, true) .get(); @@ -664,6 +667,10 @@ const DWARFDataExtractor &SymbolFileDWARF::get_debug_str_offsets_data() { m_data_debug_str_offsets); } +const DWARFDataExtractor &SymbolFileDWARF::get_debug_types_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugTypes, m_data_debug_types); +} + const DWARFDataExtractor &SymbolFileDWARF::get_apple_names_data() { return GetCachedSectionData(eSectionTypeDWARFAppleNames, m_data_apple_names); } @@ -681,6 +688,11 @@ const DWARFDataExtractor &SymbolFileDWARF::get_apple_objc_data() { return GetCachedSectionData(eSectionTypeDWARFAppleObjC, m_data_apple_objc); } +const DWARFDataExtractor &SymbolFileDWARF::get_gnu_debugaltlink() { + return GetCachedSectionData(eSectionTypeDWARFGNUDebugAltLink, + m_data_gnu_debugaltlink); +} + DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (m_abbr.get() == NULL) { const DWARFDataExtractor &debug_abbrev_data = get_debug_abbrev_data(); @@ -716,17 +728,17 @@ const DWARFDebugInfo *SymbolFileDWARF::DebugInfo() const { return m_info.get(); } -DWARFCompileUnit * +DWARFUnit * SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { if (!comp_unit) return nullptr; DWARFDebugInfo *info = DebugInfo(); if (info) { - // Just a normal DWARF file whose user ID for the compile unit is - // the DWARF offset itself + // Just a normal DWARF file whose user ID for the compile unit is the DWARF + // offset itself - DWARFCompileUnit *dwarf_cu = + DWARFUnit *dwarf_cu = info->GetCompileUnit((dw_offset_t)comp_unit->GetID()); if (dwarf_cu && dwarf_cu->GetUserData() == NULL) dwarf_cu->SetUserData(comp_unit); @@ -753,7 +765,7 @@ const DWARFDebugRanges *SymbolFileDWARF::DebugRanges() const { return m_ranges.get(); } -lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, +lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx) { CompUnitSP cu_sp; if (dwarf_cu) { @@ -772,13 +784,13 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, } else { ModuleSP module_sp(m_obj_file->GetModule()); if (module_sp) { - const DWARFDIE cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFDIE cu_die = dwarf_cu->DIE(); if (cu_die) { FileSpec cu_file_spec{cu_die.GetName(), false}; if (cu_file_spec) { // If we have a full path to the compile unit, we don't need to - // resolve - // the file. This can be expensive e.g. when the source files are + // resolve the file. This can be expensive e.g. when the source + // files are // NFS mounted. if (cu_file_spec.IsRelative()) { const char *cu_comp_dir{ @@ -789,10 +801,11 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, std::string remapped_file; if (module_sp->RemapSourceFile(cu_file_spec.GetPath(), remapped_file)) - cu_file_spec.SetFile(remapped_file, false); + cu_file_spec.SetFile(remapped_file, false, + FileSpec::Style::native); } - LanguageType cu_language = DWARFCompileUnit::LanguageTypeFromDWARF( + LanguageType cu_language = DWARFUnit::LanguageTypeFromDWARF( cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); bool is_optimized = dwarf_cu->GetIsOptimized(); @@ -801,10 +814,8 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, cu_language, is_optimized ? eLazyBoolYes : eLazyBoolNo)); if (cu_sp) { // If we just created a compile unit with an invalid file spec, - // try and get the - // first entry in the supports files from the line table as that - // should be the - // compile unit. + // try and get the first entry in the supports files from the + // line table as that should be the compile unit. if (!cu_file_spec) { cu_file_spec = cu_sp->GetSupportFiles().GetFileSpecAtIndex(1); if (cu_file_spec) { @@ -843,7 +854,7 @@ CompUnitSP SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) { CompUnitSP cu_sp; DWARFDebugInfo *info = DebugInfo(); if (info) { - DWARFCompileUnit *dwarf_cu = info->GetCompileUnitAtIndex(cu_idx); + DWARFUnit *dwarf_cu = info->GetCompileUnitAtIndex(cu_idx); if (dwarf_cu) cu_sp = ParseCompileUnit(dwarf_cu, cu_idx); } @@ -876,7 +887,7 @@ bool SymbolFileDWARF::FixupAddress(Address &addr) { lldb::LanguageType SymbolFileDWARF::ParseCompileUnitLanguage(const SymbolContext &sc) { assert(sc.comp_unit); - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) return dwarf_cu->GetLanguageType(); else @@ -886,7 +897,7 @@ SymbolFileDWARF::ParseCompileUnitLanguage(const SymbolContext &sc) { size_t SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) { assert(sc.comp_unit); size_t functions_added = 0; - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { DWARFDIECollection function_dies; const size_t num_functions = @@ -907,12 +918,12 @@ size_t SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) { bool SymbolFileDWARF::ParseCompileUnitSupportFiles( const SymbolContext &sc, FileSpecList &support_files) { assert(sc.comp_unit); - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { - const DWARFDIE cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFBaseDIE cu_die = dwarf_cu->GetUnitDIEOnly(); if (cu_die) { - const char *cu_comp_dir = resolveCompDir( + FileSpec cu_comp_dir = resolveCompDir( cu_die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr)); const dw_offset_t stmt_list = cu_die.GetAttributeValueAsUnsigned( DW_AT_stmt_list, DW_INVALID_OFFSET); @@ -931,7 +942,7 @@ bool SymbolFileDWARF::ParseCompileUnitSupportFiles( bool SymbolFileDWARF::ParseCompileUnitIsOptimized( const lldb_private::SymbolContext &sc) { - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) return dwarf_cu->GetIsOptimized(); return false; @@ -941,14 +952,14 @@ bool SymbolFileDWARF::ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules) { assert(sc.comp_unit); - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { if (ClangModulesDeclVendor::LanguageSupportsClangModules( sc.comp_unit->GetLanguage())) { UpdateExternalModuleListIfNeeded(); if (sc.comp_unit) { - const DWARFDIE die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFDIE die = dwarf_cu->DIE(); if (die) { for (DWARFDIE child_die = die.GetFirstChild(); child_die; @@ -998,8 +1009,7 @@ static void ParseDWARFLineTableCallback(dw_offset_t offset, (ParseDWARFLineTableCallbackInfo *)userData; LineTable *line_table = info->line_table; - // If this is our first time here, we need to create a - // sequence container. + // If this is our first time here, we need to create a sequence container. if (!info->sequence_ap.get()) { info->sequence_ap.reset(line_table->CreateLineSequenceContainer()); assert(info->sequence_ap.get()); @@ -1022,9 +1032,9 @@ bool SymbolFileDWARF::ParseCompileUnitLineTable(const SymbolContext &sc) { if (sc.comp_unit->GetLineTable() != NULL) return true; - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { - const DWARFDIE dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFBaseDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly(); if (dwarf_cu_die) { const dw_offset_t cu_line_offset = dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_stmt_list, @@ -1063,10 +1073,10 @@ bool SymbolFileDWARF::ParseCompileUnitLineTable(const SymbolContext &sc) { &info); 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. + // 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( debug_map_symfile->LinkOSOLineTable(this, line_table_ap.get())); } else { @@ -1105,11 +1115,11 @@ SymbolFileDWARF::ParseDebugMacros(lldb::offset_t *offset) { bool SymbolFileDWARF::ParseCompileUnitDebugMacros(const SymbolContext &sc) { assert(sc.comp_unit); - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu == nullptr) return false; - const DWARFDIE dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFBaseDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly(); if (!dwarf_cu_die) return false; @@ -1142,9 +1152,9 @@ size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc, case DW_TAG_lexical_block: { Block *block = NULL; if (tag == DW_TAG_subprogram) { - // Skip any DW_TAG_subprogram DIEs that are inside - // of a normal or inlined functions. These will be - // parsed on their own as separate entities. + // Skip any DW_TAG_subprogram DIEs that are inside of a normal or + // inlined functions. These will be parsed on their own as separate + // entities. if (depth > 0) break; @@ -1172,18 +1182,14 @@ size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc, assert(subprogram_low_pc == LLDB_INVALID_ADDRESS); subprogram_low_pc = ranges.GetMinRangeBase(0); } else if (tag == DW_TAG_inlined_subroutine) { - // We get called here for inlined subroutines in two ways. - // The first time is when we are making the Function object - // for this inlined concrete instance. Since we're creating a top - // level block at + // We get called here for inlined subroutines in two ways. The first + // time is when we are making the Function object for this inlined + // concrete instance. Since we're creating a top level block at // here, the subprogram_low_pc will be LLDB_INVALID_ADDRESS. So we - // need to - // adjust the containing address. - // The second time is when we are parsing the blocks inside the - // function that contains - // the inlined concrete instance. Since these will be blocks inside - // the containing "real" - // function the offset will be for that function. + // need to adjust the containing address. The second time is when we + // are parsing the blocks inside the function that contains the + // inlined concrete instance. Since these will be blocks inside the + // containing "real" function the offset will be for that function. if (subprogram_low_pc == LLDB_INVALID_ADDRESS) { subprogram_low_pc = ranges.GetMinRangeBase(0); } @@ -1238,9 +1244,9 @@ size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc, break; } - // Only parse siblings of the block if we are not at depth zero. A depth - // of zero indicates we are currently parsing the top level - // DW_TAG_subprogram DIE + // Only parse siblings of the block if we are not at depth zero. A depth of + // zero indicates we are currently parsing the top level DW_TAG_subprogram + // DIE if (depth == 0) die.Clear(); @@ -1286,12 +1292,12 @@ void SymbolFileDWARF::ParseDeclsForContext(CompilerDeclContext decl_ctx) { } SymbolFileDWARF *SymbolFileDWARF::GetDWARFForUID(lldb::user_id_t uid) { - // 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 - // SymbolFileDWARF classes, one for each .o file. We can often end up - // with references to other DWARF objects and we must be ready to receive - // a "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF + // 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 + // SymbolFileDWARF classes, one for each .o file. We can often end up with + // references to other DWARF objects and we must be ready to receive a + // "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF // instance. SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile(); if (debug_map) @@ -1302,12 +1308,12 @@ SymbolFileDWARF *SymbolFileDWARF::GetDWARFForUID(lldb::user_id_t uid) { DWARFDIE SymbolFileDWARF::GetDIEFromUID(lldb::user_id_t uid) { - // 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 - // SymbolFileDWARF classes, one for each .o file. We can often end up - // with references to other DWARF objects and we must be ready to receive - // a "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF + // 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 + // SymbolFileDWARF classes, one for each .o file. We can often end up with + // references to other DWARF objects and we must be ready to receive a + // "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF // instance. SymbolFileDWARF *dwarf = GetDWARFForUID(uid); if (dwarf) @@ -1316,9 +1322,9 @@ SymbolFileDWARF::GetDIEFromUID(lldb::user_id_t uid) { } CompilerDecl SymbolFileDWARF::GetDeclForUID(lldb::user_id_t type_uid) { - // 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. + // 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. DWARFDIE die = GetDIEFromUID(type_uid); if (die) return die.GetDecl(); @@ -1327,9 +1333,9 @@ CompilerDecl SymbolFileDWARF::GetDeclForUID(lldb::user_id_t type_uid) { CompilerDeclContext SymbolFileDWARF::GetDeclContextForUID(lldb::user_id_t type_uid) { - // 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. + // 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. DWARFDIE die = GetDIEFromUID(type_uid); if (die) return die.GetDeclContext(); @@ -1338,9 +1344,9 @@ SymbolFileDWARF::GetDeclContextForUID(lldb::user_id_t type_uid) { CompilerDeclContext SymbolFileDWARF::GetDeclContextContainingUID(lldb::user_id_t type_uid) { - // 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. + // 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. DWARFDIE die = GetDIEFromUID(type_uid); if (die) return die.GetContainingDeclContext(); @@ -1348,9 +1354,9 @@ SymbolFileDWARF::GetDeclContextContainingUID(lldb::user_id_t type_uid) { } Type *SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid) { - // 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. + // 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. DWARFDIE type_die = GetDIEFromUID(type_uid); if (type_die) return type_die.ResolveType(); @@ -1371,9 +1377,9 @@ Type *SymbolFileDWARF::ResolveTypeUID(const DWARFDIE &die, log, "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s'", die.GetOffset(), die.GetTagAsCString(), die.GetName()); - // We might be coming in in the middle of a type tree (a class - // within a class, an enum within a class), so parse any needed - // parent DIEs before we get to this one... + // We might be coming in in the middle of a type tree (a class within a + // class, an enum within a class), so parse any needed parent DIEs before + // we get to this one... DWARFDIE decl_ctx_die = GetDeclContextDIEContainingDIE(die); if (decl_ctx_die) { if (log) { @@ -1401,8 +1407,8 @@ Type *SymbolFileDWARF::ResolveTypeUID(const DWARFDIE &die, } // This function is used when SymbolFileDWARFDebugMap owns a bunch of -// SymbolFileDWARF objects to detect if this DWARF file is the one that -// can resolve a compiler_type. +// SymbolFileDWARF objects to detect if this DWARF file is the one that can +// resolve a compiler_type. bool SymbolFileDWARF::HasForwardDeclForClangType( const CompilerType &compiler_type) { CompilerType compiler_type_no_qualifiers = @@ -1448,12 +1454,10 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) { DWARFDIE dwarf_die = GetDIE(die_it->getSecond()); if (dwarf_die) { - // Once we start resolving this type, remove it from the forward declaration - // map in case anyone child members or other types require this type to get - // resolved. - // The type will get resolved when all of the calls to - // SymbolFileDWARF::ResolveClangOpaqueTypeDefinition - // are done. + // Once we start resolving this type, remove it from the forward + // declaration map in case anyone child members or other types require this + // type to get resolved. The type will get resolved when all of the calls + // to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition are done. GetForwardDeclClangTypeToDie().erase(die_it); Type *type = GetDIEToType().lookup(dwarf_die.GetDIE()); @@ -1494,12 +1498,12 @@ Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die, } CompileUnit * -SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit *dwarf_cu, +SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx) { // Check if the symbol vendor already knows about this compile unit? if (dwarf_cu->GetUserData() == NULL) { - // The symbol vendor doesn't know about this compile unit, we - // need to parse and add it to the symbol vendor object. + // The symbol vendor doesn't know about this compile unit, we need to parse + // and add it to the symbol vendor object. return ParseCompileUnit(dwarf_cu, cu_idx).get(); } return (CompileUnit *)dwarf_cu->GetUserData(); @@ -1508,15 +1512,7 @@ SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit *dwarf_cu, size_t SymbolFileDWARF::GetObjCMethodDIEOffsets(ConstString class_name, DIEArray &method_die_offsets) { method_die_offsets.clear(); - if (m_using_apple_tables) { - if (m_apple_objc_ap.get()) - m_apple_objc_ap->FindByName(class_name.GetCString(), method_die_offsets); - } else { - if (!m_indexed) - Index(); - - m_objc_class_selectors_index.Find(class_name, method_die_offsets); - } + m_index->GetObjCMethods(class_name, method_die_offsets); return method_die_offsets.size(); } @@ -1560,9 +1556,9 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { std::unique_ptr<SymbolFileDWARFDwo> SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( - DWARFCompileUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) { + DWARFUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) { // If we are using a dSYM file, we never want the standard DWO files since - // the -gmodule support uses the same DWO machanism to specify full debug + // the -gmodules support uses the same DWO machanism to specify full debug // info files for modules. if (GetDebugMapSymfile()) return nullptr; @@ -1589,7 +1585,7 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( if (!comp_dir) return nullptr; - dwo_file.SetFile(comp_dir, true); + dwo_file.SetFile(comp_dir, true, FileSpec::Style::native); dwo_file.AppendPathComponent(dwo_name); } @@ -1617,9 +1613,9 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { const uint32_t num_compile_units = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); + DWARFUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); - const DWARFDIE die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly(); if (die && die.HasChildren() == false) { const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr); @@ -1632,35 +1628,35 @@ 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, false, + 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, true, + FileSpec::Style::native); dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path); } } dwo_module_spec.GetArchitecture() = m_obj_file->GetModule()->GetArchitecture(); - // When LLDB loads "external" modules it looks at the - // presence of DW_AT_GNU_dwo_name. - // However, when the already created module - // (corresponding to .dwo itself) is being processed, - // it will see the presence of DW_AT_GNU_dwo_name - // (which contains the name of dwo file) and - // will try to call ModuleList::GetSharedModule again. - // In some cases (i.e. for empty files) Clang 4.0 - // generates a *.dwo file which has DW_AT_GNU_dwo_name, - // but no DW_AT_comp_dir. In this case the method - // ModuleList::GetSharedModule will fail and - // the warning will be printed. However, as one can notice - // in this case we don't actually need to try to load the already - // loaded module (corresponding to .dwo) so we simply skip it. + // When LLDB loads "external" modules it looks at the presence of + // DW_AT_GNU_dwo_name. However, when the already created module + // (corresponding to .dwo itself) is being processed, it will see + // the presence of DW_AT_GNU_dwo_name (which contains the name of + // dwo file) and will try to call ModuleList::GetSharedModule + // again. In some cases (i.e. for empty files) Clang 4.0 generates + // a *.dwo file which has DW_AT_GNU_dwo_name, but no + // DW_AT_comp_dir. In this case the method + // ModuleList::GetSharedModule will fail and the warning will be + // printed. However, as one can notice in this case we don't + // actually need to try to load the already loaded module + // (corresponding to .dwo) so we simply skip it. if (m_obj_file->GetFileSpec() .GetFileNameExtension() - .GetStringRef() == "dwo" && + .GetStringRef() == ".dwo" && llvm::StringRef(m_obj_file->GetFileSpec().GetPath()) .endswith(dwo_module_spec.GetFileSpec().GetPath())) { continue; @@ -1751,13 +1747,11 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, const dw_offset_t cu_offset = debug_info->GetCompileUnitAranges().FindAddress(file_vm_addr); if (cu_offset == DW_INVALID_OFFSET) { - // Global variables are not in the compile unit address ranges. The only - // way to - // currently find global variables is to iterate over the - // .debug_pubnames or the - // __apple_names table and find all items in there that point to - // DW_TAG_variable - // DIEs and then find the address that matches. + // Global variables are not in the compile unit address ranges. The + // only way to currently find global variables is to iterate over the + // .debug_pubnames or the __apple_names table and find all items in + // there that point to DW_TAG_variable DIEs and then find the address + // that matches. if (resolve_scope & eSymbolContextVariable) { GlobalVariableMap &map = GetGlobalAranges(); const GlobalVariableMap::Entry *entry = @@ -1774,7 +1768,7 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, } } else { uint32_t cu_idx = DW_INVALID_INDEX; - DWARFCompileUnit *dwarf_cu = + DWARFUnit *dwarf_cu = debug_info->GetCompileUnit(cu_offset, &cu_idx); if (dwarf_cu) { sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx); @@ -1825,13 +1819,10 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, LineTable *line_table = sc.comp_unit->GetLineTable(); if (line_table != NULL) { // And address that makes it into this function should be in - // terms - // of this debug file if there is no debug map, or it will be an - // address in the .o file which needs to be fixed up to be in - // terms - // of the debug map executable. Either way, calling - // FixupAddress() - // will work for us. + // terms of this debug file if there is no debug map, or it + // will be an address in the .o file which needs to be fixed up + // to be in terms of the debug map executable. Either way, + // calling FixupAddress() will work for us. Address exe_so_addr(so_addr); if (FixupAddress(exe_so_addr)) { if (line_table->FindLineEntryByAddress(exe_so_addr, @@ -1845,11 +1836,11 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, if (force_check_line_table && !(resolved & eSymbolContextLineEntry)) { // We might have had a compile unit that had discontiguous - // address ranges where the gaps are symbols that don't have - // any debug info. Discontiguous compile unit address ranges - // should only happen when there aren't other functions from - // other compile units in these gaps. This helps keep the size - // of the aranges down. + // address ranges where the gaps are symbols that don't have any + // debug info. Discontiguous compile unit address ranges should + // only happen when there aren't other functions from other + // compile units in these gaps. This helps keep the size of the + // aranges down. sc.comp_unit = NULL; resolved &= ~eSymbolContextCompUnit; } @@ -1876,7 +1867,7 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, DWARFDebugInfo *debug_info = DebugInfo(); if (debug_info) { uint32_t cu_idx; - DWARFCompileUnit *dwarf_cu = NULL; + DWARFUnit *dwarf_cu = NULL; for (cu_idx = 0; (dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx)) != NULL; @@ -1891,8 +1882,8 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, if (sc.comp_unit) { uint32_t file_idx = UINT32_MAX; - // If we are looking for inline functions only and we don't - // find it in the support files, we are done. + // If we are looking for inline functions only and we don't find it + // in the support files, we are done. if (check_inlines) { file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex( 1, file_spec, true); @@ -1904,8 +1895,8 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, LineTable *line_table = sc.comp_unit->GetLineTable(); if (line_table != NULL && line != 0) { - // We will have already looked up the file index if - // we are searching for inline entries. + // We will have already looked up the file index if we are + // searching for inline entries. if (!check_inlines) file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex( 1, file_spec, true); @@ -1962,16 +1953,14 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, } } else if (file_spec_matches_cu_file_spec && !check_inlines) { // only append the context if we aren't looking for inline call - // sites - // by file and line and if the file spec matches that of the - // compile unit + // sites by file and line and if the file spec matches that of + // the compile unit sc_list.Append(sc); } } else if (file_spec_matches_cu_file_spec && !check_inlines) { // only append the context if we aren't looking for inline call - // sites - // by file and line and if the file spec matches that of the - // compile unit + // sites by file and line and if the file spec matches that of + // the compile unit sc_list.Append(sc); } @@ -1988,143 +1977,15 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, void SymbolFileDWARF::PreloadSymbols() { std::lock_guard<std::recursive_mutex> guard( GetObjectFile()->GetModule()->GetMutex()); - Index(); -} - -void SymbolFileDWARF::Index() { - if (m_indexed) - return; - m_indexed = true; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "SymbolFileDWARF::Index (%s)", - GetObjectFile()->GetFileSpec().GetFilename().AsCString("<Unknown>")); - - DWARFDebugInfo *debug_info = DebugInfo(); - if (debug_info) { - const uint32_t num_compile_units = GetNumCompileUnits(); - if (num_compile_units == 0) - return; - - std::vector<NameToDIE> function_basename_index(num_compile_units); - std::vector<NameToDIE> function_fullname_index(num_compile_units); - std::vector<NameToDIE> function_method_index(num_compile_units); - std::vector<NameToDIE> function_selector_index(num_compile_units); - std::vector<NameToDIE> objc_class_selectors_index(num_compile_units); - std::vector<NameToDIE> global_index(num_compile_units); - std::vector<NameToDIE> type_index(num_compile_units); - std::vector<NameToDIE> namespace_index(num_compile_units); - - // std::vector<bool> might be implemented using bit test-and-set, so use - // uint8_t instead. - std::vector<uint8_t> clear_cu_dies(num_compile_units, false); - auto parser_fn = [debug_info, &function_basename_index, - &function_fullname_index, &function_method_index, - &function_selector_index, &objc_class_selectors_index, - &global_index, &type_index, - &namespace_index](size_t cu_idx) { - DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); - if (dwarf_cu) { - dwarf_cu->Index( - function_basename_index[cu_idx], function_fullname_index[cu_idx], - function_method_index[cu_idx], function_selector_index[cu_idx], - objc_class_selectors_index[cu_idx], global_index[cu_idx], - type_index[cu_idx], namespace_index[cu_idx]); - } - }; - - auto extract_fn = [debug_info, &clear_cu_dies](size_t cu_idx) { - DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); - if (dwarf_cu) { - // dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the - // DIEs for a compile unit have already been parsed. - if (dwarf_cu->ExtractDIEsIfNeeded(false) > 1) - clear_cu_dies[cu_idx] = true; - } - }; - - // Create a task runner that extracts dies for each DWARF compile unit in a - // separate thread - //---------------------------------------------------------------------- - // First figure out which compile units didn't have their DIEs already - // parsed and remember this. If no DIEs were parsed prior to this index - // function call, we are going to want to clear the CU dies after we - // are done indexing to make sure we don't pull in all DWARF dies, but - // we need to wait until all compile units have been indexed in case - // a DIE in one compile unit refers to another and the indexes accesses - // those DIEs. - //---------------------------------------------------------------------- - TaskMapOverInt(0, num_compile_units, extract_fn); - - // Now create a task runner that can index each DWARF compile unit in a - // separate - // thread so we can index quickly. - - TaskMapOverInt(0, num_compile_units, parser_fn); - - auto finalize_fn = [](NameToDIE &index, std::vector<NameToDIE> &srcs) { - for (auto &src : srcs) - index.Append(src); - index.Finalize(); - }; - - TaskPool::RunTasks( - [&]() { - finalize_fn(m_function_basename_index, function_basename_index); - }, - [&]() { - finalize_fn(m_function_fullname_index, function_fullname_index); - }, - [&]() { finalize_fn(m_function_method_index, function_method_index); }, - [&]() { - finalize_fn(m_function_selector_index, function_selector_index); - }, - [&]() { - finalize_fn(m_objc_class_selectors_index, objc_class_selectors_index); - }, - [&]() { finalize_fn(m_global_index, global_index); }, - [&]() { finalize_fn(m_type_index, type_index); }, - [&]() { finalize_fn(m_namespace_index, namespace_index); }); - - //---------------------------------------------------------------------- - // Keep memory down by clearing DIEs for any compile units if indexing - // caused us to load the compile unit's DIEs. - //---------------------------------------------------------------------- - for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - if (clear_cu_dies[cu_idx]) - debug_info->GetCompileUnitAtIndex(cu_idx)->ClearDIEs(true); - } - -#if defined(ENABLE_DEBUG_PRINTF) - StreamFile s(stdout, false); - s.Printf("DWARF index for '%s':", - GetObjectFile()->GetFileSpec().GetPath().c_str()); - s.Printf("\nFunction basenames:\n"); - m_function_basename_index.Dump(&s); - s.Printf("\nFunction fullnames:\n"); - m_function_fullname_index.Dump(&s); - s.Printf("\nFunction methods:\n"); - m_function_method_index.Dump(&s); - s.Printf("\nFunction selectors:\n"); - m_function_selector_index.Dump(&s); - s.Printf("\nObjective C class selectors:\n"); - m_objc_class_selectors_index.Dump(&s); - s.Printf("\nGlobals and statics:\n"); - m_global_index.Dump(&s); - s.Printf("\nTypes:\n"); - m_type_index.Dump(&s); - s.Printf("\nNamespaces:\n"); - m_namespace_index.Dump(&s); -#endif - } + m_index->Preload(); } bool SymbolFileDWARF::DeclContextMatchesThisSymbolFile( const lldb_private::CompilerDeclContext *decl_ctx) { if (decl_ctx == nullptr || !decl_ctx->IsValid()) { - // Invalid namespace decl which means we aren't matching only things - // in this symbol file, so return true to indicate it matches this - // symbol file. + // Invalid namespace decl which means we aren't matching only things in + // this symbol file, so return true to indicate it matches this symbol + // file. return true; } @@ -2146,14 +2007,15 @@ bool SymbolFileDWARF::DeclContextMatchesThisSymbolFile( uint32_t SymbolFileDWARF::FindGlobalVariables( const ConstString &name, const CompilerDeclContext *parent_decl_ctx, - bool append, uint32_t max_matches, VariableList &variables) { + uint32_t max_matches, VariableList &variables) { Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); if (log) GetObjectFile()->GetModule()->LogMessage( - log, "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", " - "parent_decl_ctx=%p, append=%u, max_matches=%u, variables)", - name.GetCString(), static_cast<const void *>(parent_decl_ctx), append, + log, + "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", " + "parent_decl_ctx=%p, max_matches=%u, variables)", + name.GetCString(), static_cast<const void *>(parent_decl_ctx), max_matches); if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) @@ -2163,42 +2025,28 @@ uint32_t SymbolFileDWARF::FindGlobalVariables( if (info == NULL) return 0; - // If we aren't appending the results to this list, then clear the list - if (!append) - variables.Clear(); - - // Remember how many variables are in the list before we search in case - // we are appending the results to a variable list. + // Remember how many variables are in the list before we search. const uint32_t original_size = variables.GetSize(); - DIEArray die_offsets; - - if (m_using_apple_tables) { - if (m_apple_names_ap.get()) { - const char *name_cstr = name.GetCString(); - llvm::StringRef basename; - llvm::StringRef context; - - if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context, - basename)) - basename = name_cstr; + llvm::StringRef basename; + llvm::StringRef context; - m_apple_names_ap->FindByName(basename.data(), die_offsets); - } - } else { - // Index the DWARF if we haven't already - if (!m_indexed) - Index(); - - m_global_index.Find(name, die_offsets); - } + if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name.GetCString(), + context, basename)) + basename = name.GetStringRef(); + DIEArray die_offsets; + m_index->GetGlobalVariables(ConstString(basename), die_offsets); const size_t num_die_matches = die_offsets.size(); if (num_die_matches) { SymbolContext sc; sc.module_sp = m_obj_file->GetModule(); assert(sc.module_sp); + // Loop invariant: Variables up to this index have been checked for context + // matches. + uint32_t pruned_idx = original_size; + bool done = false; for (size_t i = 0; i < num_die_matches && !done; ++i) { const DIERef &die_ref = die_offsets[i]; @@ -2229,18 +2077,21 @@ uint32_t SymbolFileDWARF::FindGlobalVariables( ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables); + while (pruned_idx < variables.GetSize()) { + VariableSP var_sp = variables.GetVariableAtIndex(pruned_idx); + if (var_sp->GetName().GetStringRef().contains(name.GetStringRef())) + ++pruned_idx; + else + variables.RemoveVariableAtIndex(pruned_idx); + } if (variables.GetSize() - original_size >= max_matches) done = true; } break; } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_names " - "accelerator table had bad die 0x%8.8x for '%s')\n", - die_ref.die_offset, name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + name.GetStringRef()); } } } @@ -2249,54 +2100,37 @@ uint32_t SymbolFileDWARF::FindGlobalVariables( const uint32_t num_matches = variables.GetSize() - original_size; if (log && num_matches > 0) { GetObjectFile()->GetModule()->LogMessage( - log, "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", " - "parent_decl_ctx=%p, append=%u, max_matches=%u, variables) => %u", - name.GetCString(), static_cast<const void *>(parent_decl_ctx), append, + log, + "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", " + "parent_decl_ctx=%p, max_matches=%u, variables) => %u", + name.GetCString(), static_cast<const void *>(parent_decl_ctx), max_matches, num_matches); } return num_matches; } uint32_t SymbolFileDWARF::FindGlobalVariables(const RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, VariableList &variables) { Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); if (log) { GetObjectFile()->GetModule()->LogMessage( - log, "SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", append=%u, " - "max_matches=%u, variables)", - regex.GetText().str().c_str(), append, max_matches); + log, + "SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", " + "max_matches=%u, variables)", + regex.GetText().str().c_str(), max_matches); } DWARFDebugInfo *info = DebugInfo(); if (info == NULL) return 0; - // If we aren't appending the results to this list, then clear the list - if (!append) - variables.Clear(); - - // Remember how many variables are in the list before we search in case - // we are appending the results to a variable list. + // Remember how many variables are in the list before we search. const uint32_t original_size = variables.GetSize(); DIEArray die_offsets; - - if (m_using_apple_tables) { - if (m_apple_names_ap.get()) { - DWARFMappedHash::DIEInfoArray hash_data_array; - if (m_apple_names_ap->AppendAllDIEsThatMatchingRegex(regex, - hash_data_array)) - DWARFMappedHash::ExtractDIEArray(hash_data_array, die_offsets); - } - } else { - // Index the DWARF if we haven't already - if (!m_indexed) - Index(); - - m_global_index.Find(regex, die_offsets); - } + m_index->GetGlobalVariables(regex, die_offsets); SymbolContext sc; sc.module_sp = m_obj_file->GetModule(); @@ -2315,14 +2149,8 @@ uint32_t SymbolFileDWARF::FindGlobalVariables(const RegularExpression ®ex, if (variables.GetSize() - original_size >= max_matches) break; - } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_names " - "accelerator table had bad die 0x%8.8x for regex '%s')\n", - die_ref.die_offset, regex.GetText().str().c_str()); - } - } + } else + m_index->ReportInvalidDIEOffset(die_ref.die_offset, regex.GetText()); } } @@ -2330,13 +2158,6 @@ uint32_t SymbolFileDWARF::FindGlobalVariables(const RegularExpression ®ex, return variables.GetSize() - original_size; } -bool SymbolFileDWARF::ResolveFunction(const DIERef &die_ref, - bool include_inlines, - SymbolContextList &sc_list) { - DWARFDIE die = DebugInfo()->GetDIE(die_ref); - return ResolveFunction(die, include_inlines, sc_list); -} - bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, bool include_inlines, SymbolContextList &sc_list) { @@ -2390,54 +2211,11 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, return false; } -void SymbolFileDWARF::FindFunctions(const ConstString &name, - const NameToDIE &name_to_die, - bool include_inlines, - SymbolContextList &sc_list) { - DIEArray die_offsets; - if (name_to_die.Find(name, die_offsets)) { - ParseFunctions(die_offsets, include_inlines, sc_list); - } -} - -void SymbolFileDWARF::FindFunctions(const RegularExpression ®ex, - const NameToDIE &name_to_die, - bool include_inlines, - SymbolContextList &sc_list) { - DIEArray die_offsets; - if (name_to_die.Find(regex, die_offsets)) { - ParseFunctions(die_offsets, include_inlines, sc_list); - } -} - -void SymbolFileDWARF::FindFunctions( - const RegularExpression ®ex, - const DWARFMappedHash::MemoryTable &memory_table, bool include_inlines, - SymbolContextList &sc_list) { - DIEArray die_offsets; - DWARFMappedHash::DIEInfoArray hash_data_array; - if (memory_table.AppendAllDIEsThatMatchingRegex(regex, hash_data_array)) { - DWARFMappedHash::ExtractDIEArray(hash_data_array, die_offsets); - ParseFunctions(die_offsets, include_inlines, sc_list); - } -} - -void SymbolFileDWARF::ParseFunctions(const DIEArray &die_offsets, - bool include_inlines, - SymbolContextList &sc_list) { - const size_t num_matches = die_offsets.size(); - if (num_matches) { - for (size_t i = 0; i < num_matches; ++i) - ResolveFunction(die_offsets[i], include_inlines, sc_list); - } -} - bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext *decl_ctx, const DWARFDIE &die) { // If we have no parent decl context to match this DIE matches, and if the - // parent - // decl context isn't valid, we aren't trying to look for any particular decl - // context so any die matches. + // parent decl context isn't valid, we aren't trying to look for any + // particular decl context so any die matches. if (decl_ctx == nullptr || !decl_ctx->IsValid()) return true; @@ -2486,10 +2264,8 @@ SymbolFileDWARF::FindFunctions(const ConstString &name, if (name.IsEmpty()) return 0; - // Remember how many sc_list are in the list before we search in case - // we are appending the results to a variable list. - - const char *name_cstr = name.GetCString(); + // Remember how many sc_list are in the list before we search in case we are + // appending the results to a variable list. const uint32_t original_size = sc_list.GetSize(); @@ -2497,228 +2273,17 @@ SymbolFileDWARF::FindFunctions(const ConstString &name, if (info == NULL) return 0; - std::set<const DWARFDebugInfoEntry *> resolved_dies; - if (m_using_apple_tables) { - if (m_apple_names_ap.get()) { - - DIEArray die_offsets; - - uint32_t num_matches = 0; - - if (name_type_mask & eFunctionNameTypeFull) { - // If they asked for the full name, match what they typed. At some - // point we may - // want to canonicalize this (strip double spaces, etc. For now, we - // just add all the - // dies that we find by exact match. - num_matches = m_apple_names_ap->FindByName(name_cstr, die_offsets); - for (uint32_t i = 0; i < num_matches; i++) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = info->GetDIE(die_ref); - if (die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (ResolveFunction(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } else { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_names " - "accelerator table had bad die 0x%8.8x for '%s')", - die_ref.die_offset, name_cstr); - } - } - } - - if (name_type_mask & eFunctionNameTypeSelector) { - if (parent_decl_ctx && parent_decl_ctx->IsValid()) - return 0; // no selectors in namespaces - - num_matches = m_apple_names_ap->FindByName(name_cstr, die_offsets); - // Now make sure these are actually ObjC methods. In this case we can - // simply look up the name, - // and if it is an ObjC method name, we're good. + llvm::DenseSet<const DWARFDebugInfoEntry *> resolved_dies; + DIEArray offsets; + CompilerDeclContext empty_decl_ctx; + if (!parent_decl_ctx) + parent_decl_ctx = &empty_decl_ctx; - for (uint32_t i = 0; i < num_matches; i++) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = info->GetDIE(die_ref); - if (die) { - const char *die_name = die.GetName(); - if (ObjCLanguage::IsPossibleObjCMethodName(die_name)) { - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (ResolveFunction(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } else { - GetObjectFile()->GetModule()->ReportError( - "the DWARF debug information has been modified (.apple_names " - "accelerator table had bad die 0x%8.8x for '%s')", - die_ref.die_offset, name_cstr); - } - } - die_offsets.clear(); - } - - if (((name_type_mask & eFunctionNameTypeMethod) && !parent_decl_ctx) || - name_type_mask & eFunctionNameTypeBase) { - // The apple_names table stores just the "base name" of C++ methods in - // the table. So we have to - // extract the base name, look that up, and if there is any other - // information in the name we were - // passed in we have to post-filter based on that. - - // FIXME: Arrange the logic above so that we don't calculate the base - // name twice: - num_matches = m_apple_names_ap->FindByName(name_cstr, die_offsets); - - for (uint32_t i = 0; i < num_matches; i++) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = info->GetDIE(die_ref); - if (die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - // If we get to here, the die is good, and we should add it: - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end() && - ResolveFunction(die, include_inlines, sc_list)) { - bool keep_die = true; - if ((name_type_mask & - (eFunctionNameTypeBase | eFunctionNameTypeMethod)) != - (eFunctionNameTypeBase | eFunctionNameTypeMethod)) { - // We are looking for either basenames or methods, so we need to - // trim out the ones we won't want by looking at the type - SymbolContext sc; - if (sc_list.GetLastContext(sc)) { - if (sc.block) { - // We have an inlined function - } else if (sc.function) { - Type *type = sc.function->GetType(); - - if (type) { - CompilerDeclContext decl_ctx = - GetDeclContextContainingUID(type->GetID()); - if (decl_ctx.IsStructUnionOrClass()) { - if (name_type_mask & eFunctionNameTypeBase) { - sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); - keep_die = false; - } - } else { - if (name_type_mask & eFunctionNameTypeMethod) { - sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); - keep_die = false; - } - } - } else { - GetObjectFile()->GetModule()->ReportWarning( - "function at die offset 0x%8.8x had no function type", - die_ref.die_offset); - } - } - } - } - if (keep_die) - resolved_dies.insert(die.GetDIE()); - } - } else { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_names " - "accelerator table had bad die 0x%8.8x for '%s')", - die_ref.die_offset, name_cstr); - } - } - die_offsets.clear(); - } - } - } else { - - // Index the DWARF if we haven't already - if (!m_indexed) - Index(); - - if (name_type_mask & eFunctionNameTypeFull) { - FindFunctions(name, m_function_fullname_index, include_inlines, sc_list); - - // FIXME Temporary workaround for global/anonymous namespace - // functions debugging FreeBSD and Linux binaries. - // If we didn't find any functions in the global namespace try - // looking in the basename index but ignore any returned - // functions that have a namespace but keep functions which - // have an anonymous namespace - // TODO: The arch in the object file isn't correct for MSVC - // binaries on windows, we should find a way to make it - // correct and handle those symbols as well. - if (sc_list.GetSize() == original_size) { - ArchSpec arch; - if (!parent_decl_ctx && GetObjectFile()->GetArchitecture(arch) && - arch.GetTriple().isOSBinFormatELF()) { - SymbolContextList temp_sc_list; - FindFunctions(name, m_function_basename_index, include_inlines, - temp_sc_list); - SymbolContext sc; - for (uint32_t i = 0; i < temp_sc_list.GetSize(); i++) { - if (temp_sc_list.GetContextAtIndex(i, sc)) { - ConstString mangled_name = - sc.GetFunctionName(Mangled::ePreferMangled); - ConstString demangled_name = - sc.GetFunctionName(Mangled::ePreferDemangled); - // Mangled names on Linux and FreeBSD are of the form: - // _ZN18function_namespace13function_nameEv. - if (strncmp(mangled_name.GetCString(), "_ZN", 3) || - !strncmp(demangled_name.GetCString(), "(anonymous namespace)", - 21)) { - sc_list.Append(sc); - } - } - } - } - } - } - DIEArray die_offsets; - if (name_type_mask & eFunctionNameTypeBase) { - uint32_t num_base = m_function_basename_index.Find(name, die_offsets); - for (uint32_t i = 0; i < num_base; i++) { - DWARFDIE die = info->GetDIE(die_offsets[i]); - if (die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - // If we get to here, the die is good, and we should add it: - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (ResolveFunction(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } - die_offsets.clear(); - } - - if (name_type_mask & eFunctionNameTypeMethod) { - if (parent_decl_ctx && parent_decl_ctx->IsValid()) - return 0; // no methods in namespaces - - uint32_t num_base = m_function_method_index.Find(name, die_offsets); - { - for (uint32_t i = 0; i < num_base; i++) { - DWARFDIE die = info->GetDIE(die_offsets[i]); - if (die) { - // If we get to here, the die is good, and we should add it: - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (ResolveFunction(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } - } - die_offsets.clear(); - } - - if ((name_type_mask & eFunctionNameTypeSelector) && - (!parent_decl_ctx || !parent_decl_ctx->IsValid())) { - FindFunctions(name, m_function_selector_index, include_inlines, sc_list); - } + std::vector<DWARFDIE> dies; + m_index->GetFunctions(name, *info, *parent_decl_ctx, name_type_mask, dies); + for (const DWARFDIE &die: dies) { + if (resolved_dies.insert(die.GetDIE()).second) + ResolveFunction(die, include_inlines, sc_list); } // Return the number of variable that were appended to the list @@ -2755,21 +2320,26 @@ uint32_t SymbolFileDWARF::FindFunctions(const RegularExpression ®ex, if (!append) sc_list.Clear(); - // Remember how many sc_list are in the list before we search in case - // we are appending the results to a variable list. - uint32_t original_size = sc_list.GetSize(); + DWARFDebugInfo *info = DebugInfo(); + if (!info) + return 0; - if (m_using_apple_tables) { - if (m_apple_names_ap.get()) - FindFunctions(regex, *m_apple_names_ap, include_inlines, sc_list); - } else { - // Index the DWARF if we haven't already - if (!m_indexed) - Index(); + // Remember how many sc_list are in the list before we search in case we are + // appending the results to a variable list. + uint32_t original_size = sc_list.GetSize(); - FindFunctions(regex, m_function_basename_index, include_inlines, sc_list); + DIEArray offsets; + m_index->GetFunctions(regex, offsets); - FindFunctions(regex, m_function_fullname_index, include_inlines, sc_list); + llvm::DenseSet<const DWARFDebugInfoEntry *> resolved_dies; + for (DIERef ref : offsets) { + DWARFDIE die = info->GetDIE(ref); + if (!die) { + m_index->ReportInvalidDIEOffset(ref.die_offset, regex.GetText()); + continue; + } + if (resolved_dies.insert(die.GetDIE()).second) + ResolveFunction(die, include_inlines, sc_list); } // Return the number of variable that were appended to the list @@ -2785,7 +2355,7 @@ void SymbolFileDWARF::GetMangledNamesForFunction( num_comp_units = info->GetNumCompileUnits(); for (uint32_t i = 0; i < num_comp_units; i++) { - DWARFCompileUnit *cu = info->GetCompileUnitAtIndex(i); + DWARFUnit *cu = info->GetCompileUnitAtIndex(i); if (cu == nullptr) continue; @@ -2847,19 +2417,7 @@ uint32_t SymbolFileDWARF::FindTypes( return 0; DIEArray die_offsets; - - if (m_using_apple_tables) { - if (m_apple_types_ap.get()) { - const char *name_cstr = name.GetCString(); - m_apple_types_ap->FindByName(name_cstr, die_offsets); - } - } else { - if (!m_indexed) - Index(); - - m_type_index.Find(name, die_offsets); - } - + m_index->GetTypes(name, die_offsets); const size_t num_die_matches = die_offsets.size(); if (num_die_matches) { @@ -2881,12 +2439,8 @@ uint32_t SymbolFileDWARF::FindTypes( break; } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_types " - "accelerator table had bad die 0x%8.8x for '%s')\n", - die_ref.die_offset, name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + name.GetStringRef()); } } const uint32_t num_matches = types.GetSize() - initial_types_size; @@ -2935,25 +2489,13 @@ size_t SymbolFileDWARF::FindTypes(const std::vector<CompilerContext> &context, if (context.empty()) return 0; - DIEArray die_offsets; - ConstString name = context.back().name; if (!name) return 0; - if (m_using_apple_tables) { - if (m_apple_types_ap.get()) { - const char *name_cstr = name.GetCString(); - m_apple_types_ap->FindByName(name_cstr, die_offsets); - } - } else { - if (!m_indexed) - Index(); - - m_type_index.Find(name, die_offsets); - } - + DIEArray die_offsets; + m_index->GetTypes(name, die_offsets); const size_t num_die_matches = die_offsets.size(); if (num_die_matches) { @@ -2976,12 +2518,8 @@ size_t SymbolFileDWARF::FindTypes(const std::vector<CompilerContext> &context, ++num_matches; } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_types " - "accelerator table had bad die 0x%8.8x for '%s')\n", - die_ref.die_offset, name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + name.GetStringRef()); } } return num_matches; @@ -3008,21 +2546,7 @@ SymbolFileDWARF::FindNamespace(const SymbolContext &sc, const ConstString &name, DWARFDebugInfo *info = DebugInfo(); if (info) { DIEArray die_offsets; - - // Index if we already haven't to make sure the compile units - // get indexed and make their global DIE index list - if (m_using_apple_tables) { - if (m_apple_namespaces_ap.get()) { - const char *name_cstr = name.GetCString(); - m_apple_namespaces_ap->FindByName(name_cstr, die_offsets); - } - } else { - if (!m_indexed) - Index(); - - m_namespace_index.Find(name, die_offsets); - } - + m_index->GetNamespaces(name, die_offsets); const size_t num_matches = die_offsets.size(); if (num_matches) { for (size_t i = 0; i < num_matches; ++i) { @@ -3040,13 +2564,8 @@ SymbolFileDWARF::FindNamespace(const SymbolContext &sc, const ConstString &name, break; } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified " - "(.apple_namespaces accelerator table had bad die 0x%8.8x for " - "'%s')\n", - die_ref.die_offset, name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + name.GetStringRef()); } } } @@ -3105,6 +2624,7 @@ SymbolFileDWARF::GetDeclContextDIEContainingDIE(const DWARFDIE &orig_die) { if (orig_die != die) { switch (die.Tag()) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: case DW_TAG_namespace: case DW_TAG_structure_type: case DW_TAG_union_type: @@ -3159,16 +2679,14 @@ SymbolFileDWARF::GetObjCClassSymbol(const ConstString &objc_class_name) { } // Some compilers don't emit the DW_AT_APPLE_objc_complete_type attribute. If -// they don't -// then we can end up looking through all class types for a complete type and -// never find -// the full definition. We need to know if this attribute is supported, so we -// determine -// this here and cache th result. We also need to worry about the debug map +// they don't then we can end up looking through all class types for a complete +// type and never find the full definition. We need to know if this attribute +// is supported, so we determine this here and cache th result. We also need to +// worry about the debug map // DWARF file // if we are doing darwin DWARF in .o file debugging. bool SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type( - DWARFCompileUnit *cu) { + DWARFUnit *cu) { if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate) { m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo; if (cu && cu->Supports_DW_AT_APPLE_objc_complete_type()) @@ -3177,7 +2695,7 @@ bool SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type( DWARFDebugInfo *debug_info = DebugInfo(); const uint32_t num_compile_units = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); + DWARFUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); if (dwarf_cu != cu && dwarf_cu->Supports_DW_AT_APPLE_objc_complete_type()) { m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes; @@ -3204,19 +2722,7 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( return type_sp; DIEArray die_offsets; - - if (m_using_apple_tables) { - if (m_apple_types_ap.get()) { - const char *name_cstr = type_name.GetCString(); - m_apple_types_ap->FindCompleteObjCClassByName(name_cstr, die_offsets, - must_be_implementation); - } - } else { - if (!m_indexed) - Index(); - - m_type_index.Find(type_name, die_offsets); - } + m_index->GetCompleteObjCClass(type_name, must_be_implementation, die_offsets); const size_t num_matches = die_offsets.size(); @@ -3228,7 +2734,8 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( if (type_die) { bool try_resolving_type = false; - // Don't try and resolve the DIE we are looking for with the DIE itself! + // Don't try and resolve the DIE we are looking for with the DIE + // itself! if (type_die != die) { switch (type_die.Tag()) { case DW_TAG_class_type: @@ -3264,12 +2771,8 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( } } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_types " - "accelerator table had bad die 0x%8.8x for '%s')\n", - die_ref.die_offset, type_name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + type_name.GetStringRef()); } } } @@ -3277,16 +2780,15 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( } //---------------------------------------------------------------------- -// This function helps to ensure that the declaration contexts match for -// two different DIEs. Often times debug information will refer to a -// forward declaration of a type (the equivalent of "struct my_struct;". -// There will often be a declaration of that type elsewhere that has the -// full definition. When we go looking for the full type "my_struct", we -// will find one or more matches in the accelerator tables and we will -// then need to make sure the type was in the same declaration context -// as the original DIE. This function can efficiently compare two DIEs -// and will return true when the declaration context matches, and false -// when they don't. +// This function helps to ensure that the declaration contexts match for two +// different DIEs. Often times debug information will refer to a forward +// declaration of a type (the equivalent of "struct my_struct;". There will +// often be a declaration of that type elsewhere that has the full definition. +// When we go looking for the full type "my_struct", we will find one or more +// matches in the accelerator tables and we will then need to make sure the +// type was in the same declaration context as the original DIE. This function +// can efficiently compare two DIEs and will return true when the declaration +// context matches, and false when they don't. //---------------------------------------------------------------------- bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1, const DWARFDIE &die2) { @@ -3295,32 +2797,31 @@ bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1, DWARFDIECollection decl_ctx_1; DWARFDIECollection decl_ctx_2; - // The declaration DIE stack is a stack of the declaration context - // DIEs all the way back to the compile unit. If a type "T" is - // declared inside a class "B", and class "B" is declared inside - // a class "A" and class "A" is in a namespace "lldb", and the - // namespace is in a compile unit, there will be a stack of DIEs: + // The declaration DIE stack is a stack of the declaration context DIEs all + // the way back to the compile unit. If a type "T" is declared inside a class + // "B", and class "B" is declared inside a class "A" and class "A" is in a + // namespace "lldb", and the namespace is in a compile unit, there will be a + // stack of DIEs: // // [0] DW_TAG_class_type for "B" // [1] DW_TAG_class_type for "A" // [2] DW_TAG_namespace for "lldb" - // [3] DW_TAG_compile_unit for the source file. + // [3] DW_TAG_compile_unit or DW_TAG_partial_unit for the source file. // - // We grab both contexts and make sure that everything matches - // all the way back to the compiler unit. + // We grab both contexts and make sure that everything matches all the way + // back to the compiler unit. // First lets grab the decl contexts for both DIEs die1.GetDeclContextDIEs(decl_ctx_1); die2.GetDeclContextDIEs(decl_ctx_2); - // Make sure the context arrays have the same size, otherwise - // we are done + // Make sure the context arrays have the same size, otherwise we are done const size_t count1 = decl_ctx_1.Size(); const size_t count2 = decl_ctx_2.Size(); if (count1 != count2) return false; - // Make sure the DW_TAG values match all the way back up the - // compile unit. If they don't, then we are done. + // Make sure the DW_TAG values match all the way back up the compile unit. If + // they don't, then we are done. DWARFDIE decl_ctx_die1; DWARFDIE decl_ctx_die2; size_t i; @@ -3333,25 +2834,28 @@ bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1, #if defined LLDB_CONFIGURATION_DEBUG // Make sure the top item in the decl context die array is always - // DW_TAG_compile_unit. If it isn't then something went wrong in - // the DWARFDIE::GetDeclContextDIEs() function... - assert(decl_ctx_1.GetDIEAtIndex(count1 - 1).Tag() == DW_TAG_compile_unit); + // DW_TAG_compile_unit or DW_TAG_partial_unit. If it isn't then + // something went wrong in the DWARFDIE::GetDeclContextDIEs() + // function. + dw_tag_t cu_tag = decl_ctx_1.GetDIEAtIndex(count1 - 1).Tag(); + UNUSED_IF_ASSERT_DISABLED(cu_tag); + assert(cu_tag == DW_TAG_compile_unit || cu_tag == DW_TAG_partial_unit); #endif - // Always skip the compile unit when comparing by only iterating up to - // "count - 1". Here we compare the names as we go. + // Always skip the compile unit when comparing by only iterating up to "count + // - 1". Here we compare the names as we go. for (i = 0; i < count1 - 1; i++) { decl_ctx_die1 = decl_ctx_1.GetDIEAtIndex(i); decl_ctx_die2 = decl_ctx_2.GetDIEAtIndex(i); const char *name1 = decl_ctx_die1.GetName(); const char *name2 = decl_ctx_die2.GetName(); - // If the string was from a DW_FORM_strp, then the pointer will often - // be the same! + // If the string was from a DW_FORM_strp, then the pointer will often be + // the same! if (name1 == name2) continue; - // Name pointers are not equal, so only compare the strings - // if both are not NULL. + // Name pointers are not equal, so only compare the strings if both are not + // NULL. if (name1 && name2) { // If the strings don't compare, we are done... if (strcmp(name1, name2) != 0) @@ -3361,8 +2865,8 @@ bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1, return false; } } - // We made it through all of the checks and the declaration contexts - // are equal. + // We made it through all of the checks and the declaration contexts are + // equal. return true; } @@ -3387,47 +2891,12 @@ TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext( } DIEArray die_offsets; - - if (m_using_apple_tables) { - if (m_apple_types_ap.get()) { - const bool has_tag = - m_apple_types_ap->GetHeader().header_data.ContainsAtom( - DWARFMappedHash::eAtomTypeTag); - const bool has_qualified_name_hash = - m_apple_types_ap->GetHeader().header_data.ContainsAtom( - DWARFMappedHash::eAtomTypeQualNameHash); - if (has_tag && has_qualified_name_hash) { - const char *qualified_name = dwarf_decl_ctx.GetQualifiedName(); - const uint32_t qualified_name_hash = - MappedHash::HashStringUsingDJB(qualified_name); - if (log) - GetObjectFile()->GetModule()->LogMessage( - log, "FindByNameAndTagAndQualifiedNameHash()"); - m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash( - type_name.GetCString(), tag, qualified_name_hash, die_offsets); - } else if (has_tag) { - if (log) - GetObjectFile()->GetModule()->LogMessage(log, - "FindByNameAndTag()"); - m_apple_types_ap->FindByNameAndTag(type_name.GetCString(), tag, - die_offsets); - } else { - m_apple_types_ap->FindByName(type_name.GetCString(), die_offsets); - } - } - } else { - if (!m_indexed) - Index(); - - m_type_index.Find(type_name, die_offsets); - } - + m_index->GetTypes(dwarf_decl_ctx, die_offsets); const size_t num_matches = die_offsets.size(); - // Get the type system that we are looking to find a type for. We will use - // this - // to ensure any matches we find are in a language that this type system - // supports + // Get the type system that we are looking to find a type for. We will + // use this to ensure any matches we find are in a language that this + // type system supports const LanguageType language = dwarf_decl_ctx.GetLanguage(); TypeSystem *type_system = (language == eLanguageTypeUnknown) ? nullptr @@ -3440,10 +2909,8 @@ TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext( if (type_die) { // Make sure type_die's langauge matches the type system we are - // looking for. - // We don't want to find a "Foo" type from Java if we are looking - // for a "Foo" - // type for C, C++, ObjC, or ObjC++. + // looking for. We don't want to find a "Foo" type from Java if we + // are looking for a "Foo" type for C, C++, ObjC, or ObjC++. if (type_system && !type_system->SupportsLanguage(type_die.GetLanguage())) continue; @@ -3457,24 +2924,23 @@ TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext( // The tags match, lets try resolving this type try_resolving_type = true; } else { - // The tags don't match, but we need to watch our for a - // forward declaration for a struct and ("struct foo") - // ends up being a class ("class foo { ... };") or - // vice versa. + // The tags don't match, but we need to watch our for a forward + // declaration for a struct and ("struct foo") ends up being a + // class ("class foo { ... };") or vice versa. switch (type_tag) { case DW_TAG_class_type: - // We had a "class foo", see if we ended up with a "struct foo { - // ... };" + // We had a "class foo", see if we ended up with a "struct foo + // { ... };" try_resolving_type = (tag == DW_TAG_structure_type); break; case DW_TAG_structure_type: - // We had a "struct foo", see if we ended up with a "class foo { - // ... };" + // We had a "struct foo", see if we ended up with a "class foo + // { ... };" try_resolving_type = (tag == DW_TAG_class_type); break; default: - // Tags don't match, don't event try to resolve - // using this type whose name matches.... + // Tags don't match, don't event try to resolve using this type + // whose name matches.... break; } } @@ -3515,12 +2981,8 @@ TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext( } } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_types " - "accelerator table had bad die 0x%8.8x for '%s')\n", - die_ref.die_offset, type_name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + type_name.GetStringRef()); } } } @@ -3606,7 +3068,7 @@ size_t SymbolFileDWARF::ParseTypes(const SymbolContext &sc, size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc) { assert(sc.comp_unit && sc.function); size_t functions_added = 0; - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + 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); @@ -3623,7 +3085,7 @@ size_t SymbolFileDWARF::ParseTypes(const SymbolContext &sc) { // At least a compile unit must be valid assert(sc.comp_unit); size_t types_added = 0; - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { if (sc.function) { dw_offset_t function_die_offset = sc.function->GetID(); @@ -3662,7 +3124,7 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { return num_variables; } } else if (sc.comp_unit) { - DWARFCompileUnit *dwarf_cu = info->GetCompileUnit(sc.comp_unit->GetID()); + DWARFUnit *dwarf_cu = info->GetCompileUnit(sc.comp_unit->GetID()); if (dwarf_cu == NULL) return 0; @@ -3675,25 +3137,7 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { sc.comp_unit->SetVariableList(variables); DIEArray die_offsets; - if (m_using_apple_tables) { - if (m_apple_names_ap.get()) { - DWARFMappedHash::DIEInfoArray hash_data_array; - if (m_apple_names_ap->AppendAllDIEsInRange( - dwarf_cu->GetOffset(), dwarf_cu->GetNextCompileUnitOffset(), - hash_data_array)) { - DWARFMappedHash::ExtractDIEArray(hash_data_array, die_offsets); - } - } - } else { - // Index if we already haven't to make sure the compile units - // get indexed and make their global DIE index list - if (!m_indexed) - Index(); - - m_global_index.FindAllEntriesForCompileUnit(dwarf_cu->GetOffset(), - die_offsets); - } - + m_index->GetGlobalVariables(*dwarf_cu, die_offsets); const size_t num_matches = die_offsets.size(); if (num_matches) { for (size_t i = 0; i < num_matches; ++i) { @@ -3706,14 +3150,8 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { variables->AddVariableIfUnique(var_sp); ++vars_added; } - } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified " - "(.apple_names accelerator table had bad die 0x%8.8x)\n", - die_ref.die_offset); - } - } + } else + m_index->ReportInvalidDIEOffset(die_ref.die_offset, ""); } } } @@ -3796,7 +3234,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, location_is_const_value_data = true; // The constant value will be either a block, a data value or a // string. - const DWARFDataExtractor &debug_info_data = get_debug_info_data(); + auto debug_info_data = die.GetData(); if (DWARFFormValue::IsBlockForm(form_value.Form())) { // Retrieve the value as a block expression. uint32_t block_offset = @@ -3853,13 +3291,12 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, location_is_const_value_data = false; has_explicit_location = true; if (DWARFFormValue::IsBlockForm(form_value.Form())) { - const DWARFDataExtractor &debug_info_data = get_debug_info_data(); + auto data = die.GetData(); uint32_t block_offset = - form_value.BlockData() - debug_info_data.GetDataStart(); + form_value.BlockData() - data.GetDataStart(); uint32_t block_length = form_value.Unsigned(); - location.CopyOpcodeData(module, get_debug_info_data(), - block_offset, block_length); + location.CopyOpcodeData(module, data, block_offset, block_length); } else { const DWARFDataExtractor &debug_loc_data = get_debug_loc_data(); const dw_offset_t debug_loc_offset = form_value.Unsigned(); @@ -3902,10 +3339,9 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, // TODO: Handle the case when DW_AT_start_scope have form // constant. The // dwarf spec is a bit ambiguous about what is the expected - // behavior in - // case the enclosing block have a non coninious address range and - // the - // DW_AT_start_scope entry have a form constant. + // behavior in case the enclosing block have a non coninious + // address range and the DW_AT_start_scope entry have a form + // constant. GetObjectFile()->GetModule()->ReportWarning( "0x%8.8" PRIx64 ": DW_AT_start_scope has unsupported form type (0x%x)\n", @@ -3937,7 +3373,8 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die); const dw_tag_t parent_tag = die.GetParent().Tag(); bool is_static_member = - parent_tag == DW_TAG_compile_unit && + (parent_tag == DW_TAG_compile_unit || + parent_tag == DW_TAG_partial_unit) && (parent_context_die.Tag() == DW_TAG_class_type || parent_context_die.Tag() == DW_TAG_structure_type); @@ -3949,17 +3386,17 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, bool has_explicit_mangled = mangled != nullptr; if (!mangled) { // LLDB relies on the mangled name (DW_TAG_linkage_name or - // DW_AT_MIPS_linkage_name) to - // generate fully qualified names of global variables with commands like - // "frame var j". - // For example, if j were an int variable holding a value 4 and declared - // in a namespace - // B which in turn is contained in a namespace A, the command "frame var - // j" returns - // "(int) A::B::j = 4". If the compiler does not emit a linkage name, we - // should be able - // to generate a fully qualified name from the declaration context. - if (parent_tag == DW_TAG_compile_unit && + // DW_AT_MIPS_linkage_name) to generate fully qualified names + // of global variables with commands like "frame var j". For + // example, if j were an int variable holding a value 4 and + // declared in a namespace B which in turn is contained in a + // namespace A, the command "frame var j" returns + // "(int) A::B::j = 4". + // If the compiler does not emit a linkage name, we should be + // able to generate a fully qualified name from the + // declaration context. + if ((parent_tag == DW_TAG_compile_unit || + parent_tag == DW_TAG_partial_unit) && Language::LanguageIsCPlusPlus(die.GetLanguage())) { DWARFDeclContext decl_ctx; @@ -4007,24 +3444,21 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, scope = eValueTypeVariableStatic; if (debug_map_symfile) { - // When leaving the DWARF in the .o files on darwin, - // when we have a global variable that wasn't initialized, - // the .o file might not have allocated a virtual - // address for the global variable. In this case it will - // have created a symbol for the global variable - // that is undefined/data and external and the value will - // be the byte size of the variable. When we do the - // address map in SymbolFileDWARFDebugMap we rely on - // having an address, we need to do some magic here - // so we can get the correct address for our global - // variable. The address for all of these entries - // will be zero, and there will be an undefined symbol - // in this object file, and the executable will have - // a matching symbol with a good address. So here we - // dig up the correct address and replace it in the - // location for the variable, and set the variable's - // symbol context scope to be that of the main executable - // so the file address will resolve correctly. + // When leaving the DWARF in the .o files on darwin, when we have a + // global variable that wasn't initialized, the .o file might not + // have allocated a virtual address for the global variable. In + // this case it will have created a symbol for the global variable + // that is undefined/data and external and the value will be the + // byte size of the variable. When we do the address map in + // SymbolFileDWARFDebugMap we rely on having an address, we need to + // do some magic here so we can get the correct address for our + // global variable. The address for all of these entries will be + // zero, and there will be an undefined symbol in this object file, + // and the executable will have a matching symbol with a good + // address. So here we dig up the correct address and replace it in + // the location for the variable, and set the variable's symbol + // context scope to be that of the main executable so the file + // address will resolve correctly. bool linked_oso_file_addr = false; if (is_external && location_DW_OP_addr == 0) { // we have a possible uninitialized extern global @@ -4056,8 +3490,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, if (!linked_oso_file_addr) { // The DW_OP_addr is not zero, but it contains a .o file address - // which - // needs to be linked up correctly. + // which needs to be linked up correctly. const lldb::addr_t exe_file_addr = debug_map_symfile->LinkOSOFileAddress(this, location_DW_OP_addr); @@ -4127,16 +3560,16 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, var_sp->SetLocationIsConstantValueData(location_is_const_value_data); } else { - // Not ready to parse this variable yet. It might be a global - // or static variable that is in a function scope and the function - // in the symbol context wasn't filled in yet + // Not ready to parse this variable yet. It might be a global or static + // variable that is in a function scope and the function in the symbol + // context wasn't filled in yet return var_sp; } } - // Cache var_sp even if NULL (the variable was just a specification or - // was missing vital information to be able to be displayed in the debugger - // (missing location due to optimization, etc)) so we don't re-parse - // this DIE over and over later... + // Cache var_sp even if NULL (the variable was just a specification or was + // missing vital information to be able to be displayed in the debugger + // (missing location due to optimization, etc)) so we don't re-parse this + // DIE over and over later... GetDIEToVariable()[die.GetDIE()] = var_sp; if (spec_die) GetDIEToVariable()[spec_die.GetDIE()] = var_sp; @@ -4217,11 +3650,11 @@ size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc, dw_tag_t parent_tag = sc_parent_die.Tag(); switch (parent_tag) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: if (sc.comp_unit != NULL) { variable_list_sp = sc.comp_unit->GetVariableList(false); if (variable_list_sp.get() == NULL) { variable_list_sp.reset(new VariableList()); - sc.comp_unit->SetVariableList(variable_list_sp); } } else { GetObjectFile()->GetModule()->ReportError( @@ -4243,8 +3676,8 @@ size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc, Block *block = sc.function->GetBlock(true).FindBlockByID( sc_parent_die.GetID()); if (block == NULL) { - // This must be a specification or abstract origin with - // a concrete block counterpart in the current function. We need + // This must be a specification or abstract origin with a + // concrete block counterpart in the current function. We need // to find the concrete block so we can correctly add the // variable to it const DWARFDIE concrete_block_die = @@ -4310,30 +3743,7 @@ ConstString SymbolFileDWARF::GetPluginName() { return GetPluginNameStatic(); } uint32_t SymbolFileDWARF::GetPluginVersion() { return 1; } -void SymbolFileDWARF::DumpIndexes() { - StreamFile s(stdout, false); - - s.Printf( - "DWARF index for (%s) '%s':", - GetObjectFile()->GetModule()->GetArchitecture().GetArchitectureName(), - GetObjectFile()->GetFileSpec().GetPath().c_str()); - s.Printf("\nFunction basenames:\n"); - m_function_basename_index.Dump(&s); - s.Printf("\nFunction fullnames:\n"); - m_function_fullname_index.Dump(&s); - s.Printf("\nFunction methods:\n"); - m_function_method_index.Dump(&s); - s.Printf("\nFunction selectors:\n"); - m_function_selector_index.Dump(&s); - s.Printf("\nObjective C class selectors:\n"); - m_objc_class_selectors_index.Dump(&s); - s.Printf("\nGlobals and statics:\n"); - m_global_index.Dump(&s); - s.Printf("\nTypes:\n"); - m_type_index.Dump(&s); - s.Printf("\nNamespaces:\n"); - m_namespace_index.Dump(&s); -} +void SymbolFileDWARF::Dump(lldb_private::Stream &s) { m_index->Dump(s); } SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { if (m_debug_map_symfile == NULL && !m_debug_map_module_wp.expired()) { diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 6902dc0333d2..a5f2ac8f3e7d 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -38,8 +38,7 @@ // Project includes #include "DWARFDataExtractor.h" #include "DWARFDefines.h" -#include "HashedNameToDIE.h" -#include "NameToDIE.h" +#include "DWARFIndex.h" #include "UniqueDWARFASTType.h" //---------------------------------------------------------------------- @@ -54,7 +53,6 @@ class DWARFDebugAranges; class DWARFDebugInfo; class DWARFDebugInfoEntry; class DWARFDebugLine; -class DWARFDebugPubnames; class DWARFDebugRanges; class DWARFDeclContext; class DWARFDIECollection; @@ -72,7 +70,7 @@ public: friend class SymbolFileDWARFDwo; friend class DebugMapModule; friend struct DIERef; - friend class DWARFCompileUnit; + friend class DWARFUnit; friend class DWARFDIE; friend class DWARFASTParserClang; friend class DWARFASTParserGo; @@ -181,11 +179,11 @@ public: uint32_t FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t FindGlobalVariables(const lldb_private::RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t @@ -247,10 +245,12 @@ public: 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_types_data(); const lldb_private::DWARFDataExtractor &get_apple_names_data(); const lldb_private::DWARFDataExtractor &get_apple_types_data(); const lldb_private::DWARFDataExtractor &get_apple_namespaces_data(); const lldb_private::DWARFDataExtractor &get_apple_objc_data(); + const lldb_private::DWARFDataExtractor &get_gnu_debugaltlink(); DWARFDebugAbbrev *DebugAbbrev(); @@ -273,19 +273,19 @@ public: HasForwardDeclForClangType(const lldb_private::CompilerType &compiler_type); lldb_private::CompileUnit * - GetCompUnitForDWARFCompUnit(DWARFCompileUnit *dwarf_cu, + GetCompUnitForDWARFCompUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx = UINT32_MAX); virtual size_t GetObjCMethodDIEOffsets(lldb_private::ConstString class_name, DIEArray &method_die_offsets); - bool Supports_DW_AT_APPLE_objc_complete_type(DWARFCompileUnit *cu); + bool Supports_DW_AT_APPLE_objc_complete_type(DWARFUnit *cu); lldb_private::DebugMacrosSP ParseDebugMacros(lldb::offset_t *offset); static DWARFDIE GetParentSymbolContextDIE(const DWARFDIE &die); - virtual lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit *dwarf_cu, + virtual lldb::CompUnitSP ParseCompileUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx); virtual lldb_private::DWARFExpression::LocationListFormat @@ -293,16 +293,30 @@ public: lldb::ModuleSP GetDWOModule(lldb_private::ConstString name); + typedef std::map<lldb_private::ConstString, lldb::ModuleSP> + ExternalTypeModuleMap; + + /// Return the list of Clang modules imported by this SymbolFile. + const ExternalTypeModuleMap& getExternalTypeModules() const { + return m_external_type_modules; + } + virtual DWARFDIE GetDIE(const DIERef &die_ref); virtual std::unique_ptr<SymbolFileDWARFDwo> - GetDwoSymbolFileForCompileUnit(DWARFCompileUnit &dwarf_cu, + GetDwoSymbolFileForCompileUnit(DWARFUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die); // For regular SymbolFileDWARF instances the method returns nullptr, // for the instances of the subclass SymbolFileDWARFDwo // the method returns a pointer to the base compile unit. - virtual DWARFCompileUnit *GetBaseCompileUnit(); + virtual DWARFUnit *GetBaseCompileUnit(); + + static bool + DIEInDeclContext(const lldb_private::CompilerDeclContext *parent_decl_ctx, + const DWARFDIE &die); + + void Dump(lldb_private::Stream &s) override; protected: typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *> @@ -331,14 +345,10 @@ protected: bool DeclContextMatchesThisSymbolFile( const lldb_private::CompilerDeclContext *decl_ctx); - bool - DIEInDeclContext(const lldb_private::CompilerDeclContext *parent_decl_ctx, - const DWARFDIE &die); - - virtual DWARFCompileUnit * + virtual DWARFUnit * GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit); - DWARFCompileUnit *GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit *prev_cu); + DWARFUnit *GetNextUnparsedDWARFCompileUnit(DWARFUnit *prev_cu); bool GetFunction(const DWARFDIE &die, lldb_private::SymbolContext &sc); @@ -375,25 +385,9 @@ protected: bool ClassOrStructIsVirtual(const DWARFDIE &die); // Given a die_offset, figure out the symbol context representing that die. - bool ResolveFunction(const DIERef &die_ref, bool include_inlines, - lldb_private::SymbolContextList &sc_list); - bool ResolveFunction(const DWARFDIE &die, bool include_inlines, lldb_private::SymbolContextList &sc_list); - void FindFunctions(const lldb_private::ConstString &name, - const NameToDIE &name_to_die, bool include_inlines, - lldb_private::SymbolContextList &sc_list); - - void FindFunctions(const lldb_private::RegularExpression ®ex, - const NameToDIE &name_to_die, bool include_inlines, - lldb_private::SymbolContextList &sc_list); - - void FindFunctions(const lldb_private::RegularExpression ®ex, - const DWARFMappedHash::MemoryTable &memory_table, - bool include_inlines, - lldb_private::SymbolContextList &sc_list); - virtual lldb::TypeSP FindDefinitionTypeForDWARFDeclContext(const DWARFDeclContext &die_decl_ctx); @@ -404,16 +398,9 @@ protected: lldb_private::Symbol * GetObjCClassSymbol(const lldb_private::ConstString &objc_class_name); - void ParseFunctions(const DIEArray &die_offsets, bool include_inlines, - lldb_private::SymbolContextList &sc_list); - lldb::TypeSP GetTypeForDIE(const DWARFDIE &die, bool resolve_function_context = false); - void Index(); - - void DumpIndexes(); - void SetDebugMapModule(const lldb::ModuleSP &module_sp) { m_debug_map_module_wp = module_sp; } @@ -439,9 +426,6 @@ protected: typedef std::set<lldb_private::Type *> TypeSet; - typedef std::map<lldb_private::ConstString, lldb::ModuleSP> - ExternalTypeModuleMap; - void GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset, dw_offset_t max_die_offset, uint32_t type_mask, TypeSet &type_set); @@ -487,10 +471,12 @@ protected: DWARFDataSegment m_data_debug_ranges; DWARFDataSegment m_data_debug_str; DWARFDataSegment m_data_debug_str_offsets; + DWARFDataSegment m_data_debug_types; DWARFDataSegment m_data_apple_names; DWARFDataSegment m_data_apple_types; DWARFDataSegment m_data_apple_namespaces; DWARFDataSegment m_data_apple_objc; + DWARFDataSegment m_data_gnu_debugaltlink; // The unique pointer items below are generated on demand if and when someone // accesses @@ -498,10 +484,6 @@ protected: std::unique_ptr<DWARFDebugAbbrev> m_abbr; std::unique_ptr<DWARFDebugInfo> m_info; std::unique_ptr<DWARFDebugLine> m_line; - std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_names_ap; - std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_types_ap; - std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_namespaces_ap; - std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_objc_ap; std::unique_ptr<GlobalVariableMap> m_global_aranges_ap; typedef std::unordered_map<lldb::offset_t, lldb_private::DebugMacrosSP> @@ -509,17 +491,8 @@ protected: DebugMacrosMap m_debug_macros_map; ExternalTypeModuleMap m_external_type_modules; - NameToDIE m_function_basename_index; // All concrete functions - NameToDIE m_function_fullname_index; // All concrete functions - NameToDIE m_function_method_index; // All inlined functions - NameToDIE - m_function_selector_index; // All method names for functions of classes - NameToDIE m_objc_class_selectors_index; // Given a class name, find all - // selectors for the class - NameToDIE m_global_index; // Global and static variables - NameToDIE m_type_index; // All type DIE offsets - NameToDIE m_namespace_index; // All type DIE offsets - bool m_indexed : 1, m_using_apple_tables : 1, m_fetched_external_modules : 1; + std::unique_ptr<lldb_private::DWARFIndex> m_index; + bool m_fetched_external_modules : 1; lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; typedef std::shared_ptr<std::set<DIERef>> DIERefSetSP; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index eabff86a5428..39c70d146524 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -44,10 +44,8 @@ using namespace lldb; using namespace lldb_private; // Subclass lldb_private::Module so we can intercept the -// "Module::GetObjectFile()" -// (so we can fixup the object file sections) and also for -// "Module::GetSymbolVendor()" -// (so we can fixup the symbol file id. +// "Module::GetObjectFile()" (so we can fixup the object file sections) and +// also for "Module::GetSymbolVendor()" (so we can fixup the symbol file id. const SymbolFileDWARFDebugMap::FileRangeMap & SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( @@ -84,8 +82,8 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( /// const uint32_t fun_resolve_flags = SymbolContext::Module | /// eSymbolContextCompUnit | eSymbolContextFunction; // SectionList *oso_sections = oso_objfile->Sections(); - // Now we need to make sections that map from zero based object - // file addresses to where things ended up in the main executable. + // Now we need to make sections that map from zero based object file + // addresses to where things ended up in the main executable. assert(comp_unit_info->first_symbol_index != UINT32_MAX); // End index is one past the last valid symbol index @@ -104,9 +102,9 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( break; case eSymbolTypeCode: { - // For each N_FUN, or function that we run into in the debug map - // we make a new section that we add to the sections found in the - // .o file. This new section has the file address set to what the + // For each N_FUN, or function that we run into in the debug map we + // make a new section that we add to the sections found in the .o + // file. This new section has the file address set to what the // addresses are in the .o file, and the load address is adjusted // to match where it ended up in the final executable! We do this // before we parse any dwarf info so that when it goes get parsed @@ -129,21 +127,21 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( } break; case eSymbolTypeData: { - // For each N_GSYM we remap the address for the global by making - // a new section that we add to the sections found in the .o file. - // This new section has the file address set to what the - // addresses are in the .o file, and the load address is adjusted - // to match where it ended up in the final executable! We do this - // before we parse any dwarf info so that when it goes get parsed - // all section/offset addresses that get registered will resolve + // For each N_GSYM we remap the address for the global by making a + // new section that we add to the sections found in the .o file. + // This new section has the file address set to what the addresses + // are in the .o file, and the load address is adjusted to match + // where it ended up in the final executable! We do this before we + // parse any dwarf info so that when it goes get parsed all + // section/offset addresses that get registered will resolve // correctly to the new addresses in the main executable. We // initially set the section size to be 1 byte, but will need to // fix up these addresses further after all globals have been // parsed to span the gaps, or we can find the global variable // sizes from the DWARF info as we are parsing. - // Next we find the non-stab entry that corresponds to the N_GSYM in - // the .o file + // Next we find the non-stab entry that corresponds to the N_GSYM + // in the .o file Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType( exe_symbol->GetMangled().GetName(lldb::eLanguageTypeUnknown, @@ -198,9 +196,9 @@ public: SymbolVendor *symbol_vendor = Module::GetSymbolVendor(can_create, feedback_strm); if (symbol_vendor) { - // Set a pointer to this class to set our OSO DWARF file know - // that the DWARF is being used along with a debug map and that - // it will have the remapped sections that we do below. + // Set a pointer to this class to set our OSO DWARF file know that + // the DWARF is being used along with a debug map and that it will + // have the remapped sections that we do below. SymbolFileDWARF *oso_symfile = SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF( symbol_vendor->GetSymbolFile()); @@ -292,8 +290,8 @@ void SymbolFileDWARFDebugMap::InitOSO() { // In order to get the abilities of this plug-in, we look at the list of // N_OSO entries (object files) from the symbol table and make sure that - // these files exist and also contain valid DWARF. If we get any of that - // then we return the abilities of the first N_OSO's DWARF. + // these files exist and also contain valid DWARF. If we get any of that then + // we return the abilities of the first N_OSO's DWARF. Symtab *symtab = m_obj_file->GetSymtab(); if (symtab) { @@ -303,10 +301,10 @@ void SymbolFileDWARFDebugMap::InitOSO() { // When a mach-o symbol is encoded, the n_type field is encoded in bits // 23:16, and the n_desc field is encoded in bits 15:0. // - // To find all N_OSO entries that are part of the DWARF + debug map - // we find only object file symbols with the flags value as follows: - // bits 23:16 == 0x66 (N_OSO) - // bits 15: 0 == 0x0001 (specifies this is a debug map object file) + // To find all N_OSO entries that are part of the DWARF + debug map we find + // only object file symbols with the flags value as follows: bits 23:16 == + // 0x66 (N_OSO) bits 15: 0 == 0x0001 (specifies this is a debug map object + // file) const uint32_t k_oso_symbol_flags_value = 0x660001u; const uint32_t oso_index_count = @@ -353,7 +351,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); + so_symbol->GetName().AsCString(), false, 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)); @@ -413,13 +411,15 @@ Module *SymbolFileDWARFDebugMap::GetModuleByOSOIndex(uint32_t oso_idx) { Module *SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo( CompileUnitInfo *comp_unit_info) { if (!comp_unit_info->oso_sp) { - auto pos = m_oso_map.find(comp_unit_info->oso_path); + auto pos = m_oso_map.find( + {comp_unit_info->oso_path, comp_unit_info->oso_mod_time}); if (pos != m_oso_map.end()) { comp_unit_info->oso_sp = pos->second; } else { ObjectFile *obj_file = GetObjectFile(); comp_unit_info->oso_sp.reset(new OSOInfo()); - m_oso_map[comp_unit_info->oso_path] = comp_unit_info->oso_sp; + 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); ConstString oso_object; @@ -443,16 +443,15 @@ Module *SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo( return NULL; } } - // Always create a new module for .o files. Why? Because we - // use the debug map, to add new sections to each .o file and - // even though a .o file might not have changed, the sections - // that get added to the .o file can change. + // Always create a new module for .o files. Why? Because we use the debug + // map, to add new sections to each .o file and even though a .o file + // might not have changed, the sections that get added to the .o file can + // change. ArchSpec oso_arch; // Only adopt the architecture from the module (not the vendor or OS) - // since .o files for "i386-apple-ios" will historically show up as - // "i386-apple-macosx" - // due to the lack of a LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS - // load command... + // since .o files for "i386-apple-ios" will historically show up as "i386 + // -apple-macosx" due to the lack of a LC_VERSION_MIN_MACOSX or + // LC_VERSION_MIN_IPHONEOS load command... oso_arch.SetTriple(m_obj_file->GetModule() ->GetArchitecture() .GetTriple() @@ -546,8 +545,8 @@ SymbolFileDWARF *SymbolFileDWARFDebugMap::GetSymbolFileByCompUnitInfo( uint32_t SymbolFileDWARFDebugMap::CalculateAbilities() { // In order to get the abilities of this plug-in, we look at the list of // N_OSO entries (object files) from the symbol table and make sure that - // these files exist and also contain valid DWARF. If we get any of that - // then we return the abilities of the first N_OSO's DWARF. + // these files exist and also contain valid DWARF. If we get any of that then + // we return the abilities of the first N_OSO's DWARF. const uint32_t oso_index_count = GetNumCompileUnits(); if (oso_index_count > 0) { @@ -576,9 +575,8 @@ CompUnitSP SymbolFileDWARFDebugMap::ParseCompileUnitAtIndex(uint32_t cu_idx) { if (oso_module) { FileSpec so_file_spec; if (GetFileSpecForSO(cu_idx, so_file_spec)) { - // User zero as the ID to match the compile unit at offset - // zero in each .o file since each .o file can only have - // one compile unit for now. + // User zero as the ID to match the compile unit at offset zero in each + // .o file since each .o file can only have one compile unit for now. lldb::user_id_t cu_id = 0; m_compile_unit_infos[cu_idx].compile_unit_sp.reset( new CompileUnit(m_obj_file->GetModule(), NULL, so_file_spec, cu_id, @@ -767,8 +765,8 @@ uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext( const uint32_t cu_count = GetNumCompileUnits(); for (uint32_t i = 0; i < cu_count; ++i) { - // If we are checking for inlines, then we need to look through all - // compile units no matter if "file_spec" matches. + // If we are checking for inlines, then we need to look through all compile + // units no matter if "file_spec" matches. bool resolve = check_inlines; if (!resolve) { @@ -805,8 +803,8 @@ uint32_t SymbolFileDWARFDebugMap::PrivateFindGlobalVariables( if (comp_unit_info) { SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx); if (oso_dwarf) { - if (oso_dwarf->FindGlobalVariables(name, parent_decl_ctx, true, - max_matches, variables)) + if (oso_dwarf->FindGlobalVariables(name, parent_decl_ctx, max_matches, + variables)) if (variables.GetSize() > max_matches) break; } @@ -817,21 +815,16 @@ uint32_t SymbolFileDWARFDebugMap::PrivateFindGlobalVariables( uint32_t SymbolFileDWARFDebugMap::FindGlobalVariables( const ConstString &name, const CompilerDeclContext *parent_decl_ctx, - bool append, uint32_t max_matches, VariableList &variables) { + uint32_t max_matches, VariableList &variables) { - // If we aren't appending the results to this list, then clear the list - if (!append) - variables.Clear(); - - // Remember how many variables are in the list before we search in case - // we are appending the results to a variable list. + // Remember how many variables are in the list before we search. const uint32_t original_size = variables.GetSize(); uint32_t total_matches = 0; ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { const uint32_t oso_matches = oso_dwarf->FindGlobalVariables( - name, parent_decl_ctx, true, max_matches, variables); + name, parent_decl_ctx, max_matches, variables); if (oso_matches > 0) { total_matches += oso_matches; @@ -843,8 +836,8 @@ uint32_t SymbolFileDWARFDebugMap::FindGlobalVariables( if (max_matches >= total_matches) return true; - // Update the max matches for any subsequent calls to find globals - // in any other object files with DWARF + // Update the max matches for any subsequent calls to find globals in any + // other object files with DWARF max_matches -= oso_matches; } @@ -857,20 +850,15 @@ uint32_t SymbolFileDWARFDebugMap::FindGlobalVariables( uint32_t SymbolFileDWARFDebugMap::FindGlobalVariables(const RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, VariableList &variables) { - // If we aren't appending the results to this list, then clear the list - if (!append) - variables.Clear(); - - // Remember how many variables are in the list before we search in case - // we are appending the results to a variable list. + // Remember how many variables are in the list before we search. const uint32_t original_size = variables.GetSize(); uint32_t total_matches = 0; ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { const uint32_t oso_matches = - oso_dwarf->FindGlobalVariables(regex, true, max_matches, variables); + oso_dwarf->FindGlobalVariables(regex, max_matches, variables); if (oso_matches > 0) { total_matches += oso_matches; @@ -882,8 +870,8 @@ SymbolFileDWARFDebugMap::FindGlobalVariables(const RegularExpression ®ex, if (max_matches >= total_matches) return true; - // Update the max matches for any subsequent calls to find globals - // in any other object files with DWARF + // Update the max matches for any subsequent calls to find globals in any + // other object files with DWARF max_matches -= oso_matches; } @@ -965,12 +953,12 @@ SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithID( static void RemoveFunctionsWithModuleNotEqualTo(const ModuleSP &module_sp, SymbolContextList &sc_list, uint32_t start_idx) { - // We found functions in .o files. Not all functions in the .o files - // will have made it into the final output file. The ones that did - // make it into the final output file will have a section whose module - // matches the module from the ObjectFile for this SymbolFile. When - // the modules don't match, then we have something that was in a - // .o file, but doesn't map to anything in the final executable. + // We found functions in .o files. Not all functions in the .o files will + // have made it into the final output file. The ones that did make it into + // the final output file will have a section whose module matches the module + // from the ObjectFile for this SymbolFile. When the modules don't match, + // then we have something that was in a .o file, but doesn't map to anything + // in the final executable. uint32_t i = start_idx; while (i < sc_list.GetSize()) { SymbolContext sc; @@ -1101,12 +1089,12 @@ bool SymbolFileDWARFDebugMap::Supports_DW_AT_APPLE_objc_complete_type( TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( const DWARFDIE &die, const ConstString &type_name, bool must_be_implementation) { - // If we have a debug map, we will have an Objective C symbol whose name is + // If we have a debug map, we will have an Objective-C symbol whose name is // the type name and whose type is eSymbolTypeObjCClass. If we can find that // symbol and find its containing parent, we can locate the .o file that will // contain the implementation definition since it will be scoped inside the - // N_SO - // and we can then locate the SymbolFileDWARF that corresponds to that N_SO. + // N_SO and we can then locate the SymbolFileDWARF that corresponds to that + // N_SO. SymbolFileDWARF *oso_dwarf = NULL; TypeSP type_sp; ObjectFile *module_objfile = m_obj_file->GetModule()->GetObjectFile(); @@ -1118,8 +1106,7 @@ TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( Symtab::eVisibilityAny); if (objc_class_symbol) { // Get the N_SO symbol that contains the objective C class symbol as - // this - // should be the .o file that contains the real definition... + // this should be the .o file that contains the real definition... const Symbol *source_file_symbol = symtab->GetParent(objc_class_symbol); if (source_file_symbol && @@ -1147,10 +1134,8 @@ 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. + // 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) { TypeSP type_sp; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index dcca4268b6eb..550f74a203ea 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -95,10 +95,10 @@ public: uint32_t FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t FindGlobalVariables(const lldb_private::RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t FindFunctions(const lldb_private::ConstString &name, @@ -136,7 +136,7 @@ protected: friend class DebugMapModule; friend struct DIERef; friend class DWARFASTParserClang; - friend class DWARFCompileUnit; + friend class DWARFUnit; friend class SymbolFileDWARF; struct OSOInfo { lldb::ModuleSP module_sp; @@ -300,7 +300,9 @@ protected: std::vector<CompileUnitInfo> m_compile_unit_infos; std::vector<uint32_t> m_func_indexes; // Sorted by address std::vector<uint32_t> m_glob_indexes; - std::map<lldb_private::ConstString, OSOInfoSP> m_oso_map; + std::map<std::pair<lldb_private::ConstString, llvm::sys::TimePoint<>>, + OSOInfoSP> + m_oso_map; UniqueDWARFASTTypeMap m_unique_ast_type_map; lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; DebugMap m_debug_map; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index 17c188a41a77..15fe362fa117 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -14,14 +14,14 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/LLDBAssert.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfo.h" using namespace lldb; using namespace lldb_private; SymbolFileDWARFDwo::SymbolFileDWARFDwo(ObjectFileSP objfile, - DWARFCompileUnit *dwarf_cu) + DWARFUnit *dwarf_cu) : SymbolFileDWARF(objfile.get()), m_obj_file_sp(objfile), m_base_dwarf_cu(dwarf_cu) { SetID(((lldb::user_id_t)dwarf_cu->GetOffset()) << 32); @@ -52,7 +52,7 @@ void SymbolFileDWARFDwo::LoadSectionData(lldb::SectionType sect_type, } lldb::CompUnitSP -SymbolFileDWARFDwo::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, +SymbolFileDWARFDwo::ParseCompileUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx) { assert(GetCompileUnit() == dwarf_cu && "SymbolFileDWARFDwo::ParseCompileUnit " "called with incompatible compile " @@ -60,7 +60,7 @@ SymbolFileDWARFDwo::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, return GetBaseSymbolFile()->ParseCompileUnit(m_base_dwarf_cu, UINT32_MAX); } -DWARFCompileUnit *SymbolFileDWARFDwo::GetCompileUnit() { +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)) @@ -76,7 +76,7 @@ DWARFCompileUnit *SymbolFileDWARFDwo::GetCompileUnit() { return nullptr; } -DWARFCompileUnit * +DWARFUnit * SymbolFileDWARFDwo::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { return GetCompileUnit(); } @@ -122,7 +122,7 @@ lldb::TypeSP SymbolFileDWARFDwo::FindCompleteObjCDefinitionTypeForDIE( die, type_name, must_be_implementation); } -DWARFCompileUnit *SymbolFileDWARFDwo::GetBaseCompileUnit() { +DWARFUnit *SymbolFileDWARFDwo::GetBaseCompileUnit() { return m_base_dwarf_cu; } diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index b67967aafab2..483a19512a36 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -18,16 +18,16 @@ class SymbolFileDWARFDwo : public SymbolFileDWARF { public: - SymbolFileDWARFDwo(lldb::ObjectFileSP objfile, DWARFCompileUnit *dwarf_cu); + SymbolFileDWARFDwo(lldb::ObjectFileSP objfile, DWARFUnit *dwarf_cu); ~SymbolFileDWARFDwo() override = default; - lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit *dwarf_cu, + lldb::CompUnitSP ParseCompileUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx) override; - DWARFCompileUnit *GetCompileUnit(); + DWARFUnit *GetCompileUnit(); - DWARFCompileUnit * + DWARFUnit * GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) override; lldb_private::DWARFExpression::LocationListFormat @@ -43,12 +43,12 @@ public: GetDIE(const DIERef &die_ref) override; std::unique_ptr<SymbolFileDWARFDwo> - GetDwoSymbolFileForCompileUnit(DWARFCompileUnit &dwarf_cu, + GetDwoSymbolFileForCompileUnit(DWARFUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) override { return nullptr; } - DWARFCompileUnit *GetBaseCompileUnit() override; + DWARFUnit *GetBaseCompileUnit() override; protected: void LoadSectionData(lldb::SectionType sect_type, @@ -74,7 +74,7 @@ protected: SymbolFileDWARF *GetBaseSymbolFile(); lldb::ObjectFileSP m_obj_file_sp; - DWARFCompileUnit *m_base_dwarf_cu; + DWARFUnit *m_base_dwarf_cu; }; #endif // SymbolFileDWARFDwo_SymbolFileDWARFDwo_h_ diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp index f6de1818eae0..403c10fe65ea 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp @@ -14,7 +14,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/LLDBAssert.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfo.h" using namespace lldb; @@ -22,7 +22,7 @@ using namespace lldb_private; SymbolFileDWARFDwoDwp::SymbolFileDWARFDwoDwp(SymbolFileDWARFDwp *dwp_symfile, ObjectFileSP objfile, - DWARFCompileUnit *dwarf_cu, + DWARFUnit *dwarf_cu, uint64_t dwo_id) : SymbolFileDWARFDwo(objfile, dwarf_cu), m_dwp_symfile(dwp_symfile), m_dwo_id(dwo_id) {} diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h index 00ad7aafd96b..b1b505b5899f 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h @@ -20,7 +20,7 @@ class SymbolFileDWARFDwoDwp : public SymbolFileDWARFDwo { public: SymbolFileDWARFDwoDwp(SymbolFileDWARFDwp *dwp_symfile, - lldb::ObjectFileSP objfile, DWARFCompileUnit *dwarf_cu, + lldb::ObjectFileSP objfile, DWARFUnit *dwarf_cu, uint64_t dwo_id); protected: diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp index 1dc1dab34a5c..ae10e7179e33 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp @@ -85,7 +85,7 @@ SymbolFileDWARFDwp::SymbolFileDWARFDwp(lldb::ModuleSP module_sp, {} std::unique_ptr<SymbolFileDWARFDwo> -SymbolFileDWARFDwp::GetSymbolFileForDwoId(DWARFCompileUnit *dwarf_cu, +SymbolFileDWARFDwp::GetSymbolFileForDwoId(DWARFUnit *dwarf_cu, uint64_t dwo_id) { return std::unique_ptr<SymbolFileDWARFDwo>( new SymbolFileDWARFDwoDwp(this, m_obj_file, dwarf_cu, dwo_id)); diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h index a7372b9358b1..470d1c5b1c48 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h @@ -29,7 +29,7 @@ public: Create(lldb::ModuleSP module_sp, const lldb_private::FileSpec &file_spec); std::unique_ptr<SymbolFileDWARFDwo> - GetSymbolFileForDwoId(DWARFCompileUnit *dwarf_cu, uint64_t dwo_id); + GetSymbolFileForDwoId(DWARFUnit *dwarf_cu, uint64_t dwo_id); bool LoadSectionData(uint64_t dwo_id, lldb::SectionType sect_type, lldb_private::DWARFDataExtractor &data); diff --git a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp index 8697e08dbf86..8273d975e57d 100644 --- a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp +++ b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp @@ -27,8 +27,8 @@ bool UniqueDWARFASTTypeList::Find(const DWARFDIE &die, udt.m_byte_size == byte_size) { // Make sure the file and line match if (udt.m_declaration == decl) { - // The type has the same name, and was defined on the same - // file and line. Now verify all of the parent DIEs match. + // The type has the same name, and was defined on the same file and + // line. Now verify all of the parent DIEs match. DWARFDIE parent_arg_die = die.GetParent(); DWARFDIE parent_pos_die = udt.m_die.GetParent(); bool match = true; @@ -57,6 +57,7 @@ bool UniqueDWARFASTTypeList::Find(const DWARFDIE &die, } break; case DW_TAG_compile_unit: + case DW_TAG_partial_unit: done = true; break; } diff --git a/source/Plugins/SymbolFile/PDB/CMakeLists.txt b/source/Plugins/SymbolFile/PDB/CMakeLists.txt index 871f382298d6..1c176c32224d 100644 --- a/source/Plugins/SymbolFile/PDB/CMakeLists.txt +++ b/source/Plugins/SymbolFile/PDB/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbPluginSymbolFilePDB PLUGIN PDBASTParser.cpp + PDBLocationToDWARFExpression.cpp SymbolFilePDB.cpp LINK_LIBS diff --git a/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index 7802d6f0d859..8bea994aae5d 100644 --- a/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -19,19 +19,22 @@ #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeSystem.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" #include "llvm/DebugInfo/PDB/PDBSymbol.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" using namespace lldb; using namespace lldb_private; -using namespace llvm; using namespace llvm::pdb; namespace { @@ -46,7 +49,7 @@ int TranslateUdtKind(PDB_UdtType pdb_kind) { case PDB_UdtType::Interface: return clang::TTK_Interface; } - return clang::TTK_Class; + return -1; } lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) { @@ -58,16 +61,146 @@ lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) { case PDB_BuiltinType::Char: return lldb::eEncodingSint; case PDB_BuiltinType::Bool: + case PDB_BuiltinType::Char16: + case PDB_BuiltinType::Char32: case PDB_BuiltinType::UInt: case PDB_BuiltinType::ULong: case PDB_BuiltinType::HResult: + case PDB_BuiltinType::WCharT: return lldb::eEncodingUint; default: return lldb::eEncodingInvalid; } } + +lldb::Encoding TranslateEnumEncoding(PDB_VariantType type) { + switch (type) { + case PDB_VariantType::Int8: + case PDB_VariantType::Int16: + case PDB_VariantType::Int32: + case PDB_VariantType::Int64: + return lldb::eEncodingSint; + + case PDB_VariantType::UInt8: + case PDB_VariantType::UInt16: + case PDB_VariantType::UInt32: + case PDB_VariantType::UInt64: + return lldb::eEncodingUint; + + default: + break; + } + + return lldb::eEncodingSint; } +CompilerType +GetBuiltinTypeForPDBEncodingAndBitSize(ClangASTContext &clang_ast, + const PDBSymbolTypeBuiltin &pdb_type, + Encoding encoding, uint32_t width) { + auto *ast = clang_ast.getASTContext(); + if (!ast) + return CompilerType(); + + switch (pdb_type.getBuiltinType()) { + default: + break; + case PDB_BuiltinType::None: + return CompilerType(); + case PDB_BuiltinType::Void: + return clang_ast.GetBasicType(eBasicTypeVoid); + case PDB_BuiltinType::Bool: + return clang_ast.GetBasicType(eBasicTypeBool); + case PDB_BuiltinType::Long: + if (width == ast->getTypeSize(ast->LongTy)) + return CompilerType(ast, ast->LongTy); + if (width == ast->getTypeSize(ast->LongLongTy)) + return CompilerType(ast, ast->LongLongTy); + break; + case PDB_BuiltinType::ULong: + if (width == ast->getTypeSize(ast->UnsignedLongTy)) + return CompilerType(ast, ast->UnsignedLongTy); + if (width == ast->getTypeSize(ast->UnsignedLongLongTy)) + return CompilerType(ast, ast->UnsignedLongLongTy); + break; + case PDB_BuiltinType::WCharT: + if (width == ast->getTypeSize(ast->WCharTy)) + return CompilerType(ast, ast->WCharTy); + break; + case PDB_BuiltinType::Char16: + return CompilerType(ast, ast->Char16Ty); + case PDB_BuiltinType::Char32: + return CompilerType(ast, ast->Char32Ty); + case PDB_BuiltinType::Float: + // Note: types `long double` and `double` have same bit size in MSVC and + // there is no information in the PDB to distinguish them. So when falling + // back to default search, the compiler type of `long double` will be + // represented by the one generated for `double`. + break; + } + // If there is no match on PDB_BuiltinType, fall back to default search by + // encoding and width only + return clang_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, width); +} + +ConstString GetPDBBuiltinTypeName(const PDBSymbolTypeBuiltin &pdb_type, + CompilerType &compiler_type) { + PDB_BuiltinType kind = pdb_type.getBuiltinType(); + switch (kind) { + default: + break; + case PDB_BuiltinType::Currency: + return ConstString("CURRENCY"); + case PDB_BuiltinType::Date: + return ConstString("DATE"); + case PDB_BuiltinType::Variant: + return ConstString("VARIANT"); + case PDB_BuiltinType::Complex: + return ConstString("complex"); + case PDB_BuiltinType::Bitfield: + return ConstString("bitfield"); + case PDB_BuiltinType::BSTR: + return ConstString("BSTR"); + case PDB_BuiltinType::HResult: + return ConstString("HRESULT"); + case PDB_BuiltinType::BCD: + return ConstString("BCD"); + case PDB_BuiltinType::Char16: + return ConstString("char16_t"); + case PDB_BuiltinType::Char32: + return ConstString("char32_t"); + case PDB_BuiltinType::None: + return ConstString("..."); + } + return compiler_type.GetTypeName(); +} + +bool GetDeclarationForSymbol(const PDBSymbol &symbol, Declaration &decl) { + auto &raw_sym = symbol.getRawSymbol(); + auto first_line_up = raw_sym.getSrcLineOnTypeDefn(); + + if (!first_line_up) { + auto lines_up = symbol.getSession().findLineNumbersByAddress( + raw_sym.getVirtualAddress(), raw_sym.getLength()); + if (!lines_up) + return false; + first_line_up = lines_up->getNext(); + if (!first_line_up) + return false; + } + uint32_t src_file_id = first_line_up->getSourceFileId(); + auto src_file_up = symbol.getSession().getSourceFileById(src_file_id); + if (!src_file_up) + return false; + + FileSpec spec(src_file_up->getFileName(), /*resolve_path*/ false); + decl.SetFile(spec); + decl.SetColumn(first_line_up->getColumnNumber()); + decl.SetLine(first_line_up->getLineNumber()); + return true; +} +} // namespace + PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) {} PDBASTParser::~PDBASTParser() {} @@ -76,21 +209,27 @@ PDBASTParser::~PDBASTParser() {} 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. + // 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; - if (auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&type)) { + switch (type.getSymTag()) { + 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) + return nullptr; if (udt_kind == PDB_UdtType::Class) access = lldb::eAccessPrivate; CompilerType clang_type = m_ast.CreateRecordType( - tu_decl_ctx, access, udt->getName().c_str(), TranslateUdtKind(udt_kind), + tu_decl_ctx, access, udt->getName().c_str(), tag_type_kind, lldb::eLanguageTypeC_plus_plus, nullptr); m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); @@ -100,51 +239,107 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { ConstString(udt->getName()), udt->getLength(), nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type, lldb_private::Type::eResolveStateForward); - } else if (auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type)) { - std::string name = enum_type->getName(); + } 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(enum_type->getBuiltinType()); + 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(); uint64_t bytes = enum_type->getLength(); - CompilerType builtin_type = - m_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, bytes * 8); + 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, false); + name.c_str(), tu_decl_ctx, decl, builtin_type, isScoped); auto enum_values = enum_type->findAllChildren<PDBSymbolData>(); - while (auto enum_value = enum_values->getNext()) { - if (enum_value->getDataKind() != PDB_DataKind::Constant) - continue; - AddEnumValue(ast_enum, *enum_value); + 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); + GetDeclarationForSymbol(type, decl); return std::make_shared<lldb_private::Type>( type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ast_enum, lldb_private::Type::eResolveStateFull); - } else if (auto type_def = llvm::dyn_cast<PDBSymbolTypeTypedef>(&type)) { + } break; + 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(); - if (!target_type) - return nullptr; CompilerType target_ast_type = target_type->GetFullCompilerType(); CompilerDeclContext target_decl_ctx = m_ast.GetSymbolFile()->GetDeclContextForUID(target_type->GetID()); CompilerType ast_typedef = m_ast.CreateTypedefType(target_ast_type, name.c_str(), target_decl_ctx); + if (!ast_typedef) + return nullptr; + return std::make_shared<lldb_private::Type>( type_def->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes, nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID, decl, ast_typedef, lldb_private::Type::eResolveStateFull); - } else if (auto func_sig = llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) { + } break; + case PDB_SymType::Function: + case PDB_SymType::FunctionSig: { + std::string name; + PDBSymbolTypeFunctionSig *func_sig = nullptr; + if (auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(&type)) { + if (pdb_func->isCompilerGenerated()) + return nullptr; + + auto sig = pdb_func->getSignature(); + if (!sig) + return nullptr; + func_sig = sig.release(); + // Function type is named. + name = pdb_func->getName(); + } else if (auto pdb_func_sig = + llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) { + func_sig = const_cast<PDBSymbolTypeFunctionSig *>(pdb_func_sig); + } else + llvm_unreachable("Unexpected PDB symbol!"); + auto arg_enum = func_sig->getArguments(); uint32_t num_args = arg_enum->getChildCount(); - std::vector<CompilerType> arg_list(num_args); - while (auto arg = arg_enum->getNext()) { + std::vector<CompilerType> arg_list; + + bool is_variadic = func_sig->isCVarArgs(); + // Drop last variadic argument. + if (is_variadic) + --num_args; + for (uint32_t arg_idx = 0; arg_idx < num_args; arg_idx++) { + auto arg = arg_enum->getChildAtIndex(arg_idx); + if (!arg) + break; lldb_private::Type *arg_type = m_ast.GetSymbolFile()->ResolveTypeUID(arg->getSymIndexId()); // If there's some error looking up one of the dependent types of this @@ -154,6 +349,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { CompilerType arg_ast_type = arg_type->GetFullCompilerType(); arg_list.push_back(arg_ast_type); } + lldbassert(arg_list.size() <= num_args); + auto pdb_return_type = func_sig->getReturnType(); lldb_private::Type *return_type = m_ast.GetSymbolFile()->ResolveTypeUID(pdb_return_type->getSymIndexId()); @@ -167,29 +364,109 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { type_quals |= clang::Qualifiers::Const; if (func_sig->isVolatileType()) type_quals |= clang::Qualifiers::Volatile; - CompilerType func_sig_ast_type = m_ast.CreateFunctionType( - return_ast_type, &arg_list[0], num_args, false, type_quals); + CompilerType func_sig_ast_type = + m_ast.CreateFunctionType(return_ast_type, arg_list.data(), + arg_list.size(), is_variadic, type_quals); + GetDeclarationForSymbol(type, decl); return std::make_shared<lldb_private::Type>( - func_sig->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), 0, + type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), 0, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, func_sig_ast_type, lldb_private::Type::eResolveStateFull); - } else if (auto array_type = llvm::dyn_cast<PDBSymbolTypeArray>(&type)) { + } break; + case PDB_SymType::ArrayType: { + auto array_type = llvm::dyn_cast<PDBSymbolTypeArray>(&type); + assert(array_type); uint32_t num_elements = array_type->getCount(); - uint32_t element_uid = array_type->getElementType()->getSymIndexId(); + uint32_t element_uid = array_type->getElementTypeId(); uint32_t bytes = array_type->getLength(); + // If array rank > 0, PDB gives the element type at N=0. So element type + // will parsed in the order N=0, N=1,..., N=rank sequentially. lldb_private::Type *element_type = m_ast.GetSymbolFile()->ResolveTypeUID(element_uid); if (!element_type) return nullptr; - CompilerType element_ast_type = element_type->GetFullCompilerType(); - CompilerType array_ast_type = - m_ast.CreateArrayType(element_ast_type, num_elements, false); - return std::make_shared<lldb_private::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) { + if (ClangASTContext::StartTagDeclarationDefinition(element_ast_type)) { + ClangASTContext::CompleteTagDeclarationDefinition(element_ast_type); + } else { + // We are not able to start defintion. + return nullptr; + } + } + CompilerType array_ast_type = m_ast.CreateArrayType( + element_ast_type, num_elements, /*is_gnu_vector*/ false); + TypeSP type_sp = std::make_shared<lldb_private::Type>( array_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), bytes, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, array_ast_type, lldb_private::Type::eResolveStateFull); + type_sp->SetEncodingType(element_type); + return type_sp; + } break; + case PDB_SymType::BuiltinType: { + auto *builtin_type = llvm::dyn_cast<PDBSymbolTypeBuiltin>(&type); + assert(builtin_type); + PDB_BuiltinType builtin_kind = builtin_type->getBuiltinType(); + if (builtin_kind == PDB_BuiltinType::None) + return nullptr; + + uint64_t bytes = builtin_type->getLength(); + Encoding encoding = TranslateBuiltinEncoding(builtin_kind); + CompilerType builtin_ast_type = GetBuiltinTypeForPDBEncodingAndBitSize( + m_ast, *builtin_type, encoding, bytes * 8); + + if (builtin_type->isConstType()) + builtin_ast_type = builtin_ast_type.AddConstModifier(); + + if (builtin_type->isVolatileType()) + builtin_ast_type = builtin_ast_type.AddVolatileModifier(); + + auto type_name = GetPDBBuiltinTypeName(*builtin_type, builtin_ast_type); + + return std::make_shared<lldb_private::Type>( + builtin_type->getSymIndexId(), m_ast.GetSymbolFile(), type_name, bytes, + nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, + builtin_ast_type, lldb_private::Type::eResolveStateFull); + } break; + case PDB_SymType::PointerType: { + auto *pointer_type = llvm::dyn_cast<PDBSymbolTypePointer>(&type); + assert(pointer_type); + Type *pointee_type = m_ast.GetSymbolFile()->ResolveTypeUID( + pointer_type->getPointeeType()->getSymIndexId()); + if (!pointee_type) + return nullptr; + + CompilerType pointer_ast_type; + pointer_ast_type = pointee_type->GetFullCompilerType(); + if (pointer_type->isReference()) + pointer_ast_type = pointer_ast_type.GetLValueReferenceType(); + else if (pointer_type->isRValueReference()) + pointer_ast_type = pointer_ast_type.GetRValueReferenceType(); + else + pointer_ast_type = pointer_ast_type.GetPointerType(); + + if (pointer_type->isConstType()) + pointer_ast_type = pointer_ast_type.AddConstModifier(); + + if (pointer_type->isVolatileType()) + pointer_ast_type = pointer_ast_type.AddVolatileModifier(); + + if (pointer_type->isRestrictedType()) + pointer_ast_type = pointer_ast_type.AddRestrictModifier(); + + 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::eResolveStateFull); + } break; + default: + break; } return nullptr; } diff --git a/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/source/Plugins/SymbolFile/PDB/PDBASTParser.h index e9ff02c0a77e..d1ac138b8115 100644 --- a/source/Plugins/SymbolFile/PDB/PDBASTParser.h +++ b/source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -19,20 +19,20 @@ class CharUnits; class CXXRecordDecl; class FieldDecl; class RecordDecl; -} +} // namespace clang namespace lldb_private { class ClangASTContext; class CompilerType; -} +} // namespace lldb_private namespace llvm { namespace pdb { class PDBSymbol; class PDBSymbolData; class PDBSymbolTypeBuiltin; -} -} +} // namespace pdb +} // namespace llvm class PDBASTParser { public: @@ -49,4 +49,4 @@ private: lldb_private::ClangASTImporter m_ast_importer; }; -#endif // SymbolFileDWARF_DWARFASTParserClang_h_ +#endif // LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H diff --git a/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp b/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp new file mode 100644 index 000000000000..69ef70cc508c --- /dev/null +++ b/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp @@ -0,0 +1,585 @@ +//===-- PDBLocationToDWARFExpression.cpp ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PDBLocationToDWARFExpression.h" + +#include "lldb/Core/Section.h" +#include "lldb/Core/StreamBuffer.h" +#include "lldb/Core/dwarf.h" +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Utility/DataBufferHeap.h" + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" + +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" + +using namespace lldb; +using namespace lldb_private; +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, 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, 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, // CVRegCR0 + LLDB_INVALID_REGNUM, // CVRegCR1 + LLDB_INVALID_REGNUM, // CVRegCR2 + LLDB_INVALID_REGNUM, // CVRegCR3 + LLDB_INVALID_REGNUM, // CVRegCR4 + 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 +}; + +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, 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, 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, // CVRegCR0 + LLDB_INVALID_REGNUM, // CVRegCR1 + LLDB_INVALID_REGNUM, // CVRegCR2 + LLDB_INVALID_REGNUM, // CVRegCR3 + LLDB_INVALID_REGNUM, // CVRegCR4 + 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_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_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_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, // CVRegMXCSR + LLDB_INVALID_REGNUM, // CVRegEDXEAX + 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, 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, // 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 +}; + +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::CVRegMXCSR: + return lldb_mxcsr_i386; + case llvm::codeview::RegisterId::CVRegBND0: + return lldb_bnd0_i386; + case llvm::codeview::RegisterId::CVRegBND1: + return lldb_bnd1_i386; + case llvm::codeview::RegisterId::CVRegBND2: + 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::CVRegVFRAME) + return LLDB_REGNUM_GENERIC_FP; + + return LLDB_INVALID_REGNUM; +} + +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); +} +} // namespace + +DWARFExpression ConvertPDBLocationToDWARFExpression(ModuleSP module, + const PDBSymbolData &symbol, + bool &is_constant) { + is_constant = true; + + if (!module) + return DWARFExpression(nullptr); + + const ArchSpec &architecture = module->GetArchitecture(); + llvm::Triple::ArchType arch_type = architecture.GetMachine(); + 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); + switch (symbol.getLocationType()) { + case PDB_LocType::Static: + case PDB_LocType::TLS: { + stream.PutHex8(DW_OP_addr); + + SectionList *section_list = module->GetSectionList(); + if (!section_list) + return DWARFExpression(nullptr); + + uint32_t section_idx = symbol.getAddressSection() - 1; + if (section_idx >= section_list->GetSize()) + return DWARFExpression(nullptr); + + auto section = section_list->GetSectionAtIndex(section_idx); + if (!section) + return DWARFExpression(nullptr); + + uint32_t offset = symbol.getAddressOffset(); + stream.PutMaxHex64(section->GetFileAddress() + offset, address_size, + byte_order); + + is_constant = false; + + break; + } + case PDB_LocType::RegRel: { + uint32_t reg_num = + GetRegisterNumber(arch_type, symbol.getRegisterId(), register_kind); + if (reg_num == LLDB_INVALID_REGNUM) + return DWARFExpression(nullptr); + + if (reg_num > 31) { + stream.PutHex8(DW_OP_bregx); + stream.PutULEB128(reg_num); + } else + stream.PutHex8(DW_OP_breg0 + reg_num); + + int32_t offset = symbol.getOffset(); + stream.PutSLEB128(offset); + + is_constant = false; + + break; + } + case PDB_LocType::Enregistered: { + uint32_t reg_num = + GetRegisterNumber(arch_type, symbol.getRegisterId(), register_kind); + if (reg_num == LLDB_INVALID_REGNUM) + return DWARFExpression(nullptr); + + if (reg_num > 31) { + stream.PutHex8(DW_OP_regx); + stream.PutULEB128(reg_num); + } else + stream.PutHex8(DW_OP_reg0 + reg_num); + + is_constant = false; + + break; + } + case PDB_LocType::Constant: { + Variant value = symbol.getValue(); + stream.PutRawBytes(&value.Value, sizeof(value.Value), + endian::InlHostByteOrder()); + break; + } + default: + 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; +} diff --git a/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h b/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h new file mode 100644 index 000000000000..37b80dfccb84 --- /dev/null +++ b/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h @@ -0,0 +1,45 @@ +//===-- PDBLocationToDWARFExpression.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_PDB_PDBLocationToDWARFExpression_h_ +#define lldb_Plugins_SymbolFile_PDB_PDBLocationToDWARFExpression_h_ + +#include "lldb/Core/Module.h" + +namespace lldb_private { +class DWARFExpression; +} + +namespace llvm { +namespace pdb { +class PDBSymbolData; +} +} // namespace llvm + +//------------------------------------------------------------------------------ +/// Converts a location information from a PDB symbol to a DWARF expression +/// +/// @param[in] module +/// The module \a symbol belongs to. +/// +/// @param[in] symbol +/// The symbol with a location information to convert. +/// +/// @param[out] is_constant +/// Set to \b true if the result expression is a constant value data, +/// and \b false if it is a DWARF bytecode. +/// +/// @return +/// The DWARF expression corresponding to the location data of \a symbol. +//------------------------------------------------------------------------------ +lldb_private::DWARFExpression +ConvertPDBLocationToDWARFExpression(lldb::ModuleSP module, + const llvm::pdb::PDBSymbolData &symbol, + bool &is_constant); +#endif diff --git a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index de9b9f024fc7..05f3017819fa 100644 --- a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -18,16 +18,21 @@ #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/TypeMap.h" +#include "lldb/Symbol/Variable.h" #include "lldb/Utility/RegularExpression.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBDataStream.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" #include "llvm/DebugInfo/PDB/IPDBTable.h" #include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" @@ -35,14 +40,18 @@ #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #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 <regex> +using namespace lldb; using namespace lldb_private; using namespace llvm::pdb; @@ -63,7 +72,7 @@ bool ShouldAddLine(uint32_t requested_line, uint32_t actual_line, return ((requested_line == 0 || actual_line == requested_line) && addr_length > 0); } -} +} // namespace void SymbolFilePDB::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), @@ -92,7 +101,8 @@ SymbolFilePDB::CreateInstance(lldb_private::ObjectFile *obj_file) { } SymbolFilePDB::SymbolFilePDB(lldb_private::ObjectFile *object_file) - : SymbolFile(object_file), m_cached_compile_unit_count(0) {} + : SymbolFile(object_file), m_session_up(), m_global_scope_up(), + m_cached_compile_unit_count(0), m_tu_decl_ctx_up() {} SymbolFilePDB::~SymbolFilePDB() {} @@ -116,15 +126,14 @@ uint32_t SymbolFilePDB::CalculateAbilities() { if (!symfile) return 0; error = loadDataForPDB(PDB_ReaderType::DIA, - llvm::StringRef(symfile.GetPath()), - m_session_up); + llvm::StringRef(symfile.GetPath()), m_session_up); if (error) { llvm::consumeError(std::move(error)); return 0; } } } - if (!m_session_up.get()) + if (!m_session_up) return 0; auto enum_tables_up = m_session_up->getEnumTables(); @@ -138,13 +147,14 @@ uint32_t SymbolFilePDB::CalculateAbilities() { case PDB_TableType::Symbols: // This table represents a store of symbols with types listed in // PDBSym_Type - abilities |= (CompileUnits | Functions | Blocks | - GlobalVariables | LocalVariables | VariableTypes); + abilities |= (CompileUnits | Functions | Blocks | GlobalVariables | + LocalVariables | VariableTypes); break; case PDB_TableType::LineNumbers: abilities |= LineTables; break; - default: break; + default: + break; } } return abilities; @@ -152,41 +162,88 @@ uint32_t SymbolFilePDB::CalculateAbilities() { void SymbolFilePDB::InitializeObject() { lldb::addr_t obj_load_address = m_obj_file->GetFileOffset(); + lldbassert(obj_load_address && obj_load_address != LLDB_INVALID_ADDRESS); m_session_up->setLoadAddress(obj_load_address); + if (!m_global_scope_up) + m_global_scope_up = m_session_up->getGlobalScope(); + lldbassert(m_global_scope_up.get()); TypeSystem *type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system); + lldbassert(clang_type_system); m_tu_decl_ctx_up = llvm::make_unique<CompilerDeclContext>( type_system, clang_type_system->GetTranslationUnitDecl()); } uint32_t SymbolFilePDB::GetNumCompileUnits() { if (m_cached_compile_unit_count == 0) { - auto global = m_session_up->getGlobalScope(); - auto compilands = global->findAllChildren<PDBSymbolCompiland>(); + auto compilands = m_global_scope_up->findAllChildren<PDBSymbolCompiland>(); + if (!compilands) + return 0; + + // The linker could link *.dll (compiland language = LINK), or import + // *.dll. For example, a compiland with name `Import:KERNEL32.dll` could be + // found as a child of the global scope (PDB executable). Usually, such + // compilands contain `thunk` symbols in which we are not interested for + // now. However we still count them in the compiland list. If we perform + // any compiland related activity, like finding symbols through + // llvm::pdb::IPDBSession methods, such compilands will all be searched + // automatically no matter whether we include them or not. m_cached_compile_unit_count = compilands->getChildCount(); // 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. - auto last_cu = compilands->getChildAtIndex(m_cached_compile_unit_count - 1); - std::string name = last_cu->getName(); + auto last_compiland_up = + compilands->getChildAtIndex(m_cached_compile_unit_count - 1); + lldbassert(last_compiland_up.get()); + std::string name = last_compiland_up->getName(); if (name == "* Linker *") --m_cached_compile_unit_count; } return m_cached_compile_unit_count; } -lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitAtIndex(uint32_t index) { - auto global = m_session_up->getGlobalScope(); - auto compilands = global->findAllChildren<PDBSymbolCompiland>(); - auto cu = compilands->getChildAtIndex(index); +void SymbolFilePDB::GetCompileUnitIndex( + const llvm::pdb::PDBSymbolCompiland &pdb_compiland, uint32_t &index) { + auto results_up = m_global_scope_up->findAllChildren<PDBSymbolCompiland>(); + if (!results_up) + return; + auto uid = pdb_compiland.getSymIndexId(); + for (uint32_t cu_idx = 0; cu_idx < GetNumCompileUnits(); ++cu_idx) { + auto compiland_up = results_up->getChildAtIndex(cu_idx); + if (!compiland_up) + continue; + if (compiland_up->getSymIndexId() == uid) { + index = cu_idx; + return; + } + } + index = UINT32_MAX; + return; +} - uint32_t id = cu->getSymIndexId(); +std::unique_ptr<llvm::pdb::PDBSymbolCompiland> +SymbolFilePDB::GetPDBCompilandByUID(uint32_t uid) { + return m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(uid); +} - return ParseCompileUnitForSymIndex(id); +lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitAtIndex(uint32_t index) { + if (index >= GetNumCompileUnits()) + return CompUnitSP(); + + // Assuming we always retrieve same compilands listed in same order through + // `PDBSymbolExe::findAllChildren` method, otherwise using `index` to get a + // compile unit makes no sense. + auto results = m_global_scope_up->findAllChildren<PDBSymbolCompiland>(); + if (!results) + return CompUnitSP(); + auto compiland_up = results->getChildAtIndex(index); + if (!compiland_up) + return CompUnitSP(); + return ParseCompileUnitForUID(compiland_up->getSymIndexId(), index); } lldb::LanguageType @@ -196,24 +253,71 @@ SymbolFilePDB::ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) { if (!sc.comp_unit) return lldb::eLanguageTypeUnknown; - auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>( - sc.comp_unit->GetID()); - if (!cu) + auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland_up) return lldb::eLanguageTypeUnknown; - auto details = cu->findOneChild<PDBSymbolCompilandDetails>(); + auto details = compiland_up->findOneChild<PDBSymbolCompilandDetails>(); if (!details) return lldb::eLanguageTypeUnknown; 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()); + + auto file_vm_addr = pdb_func.getVirtualAddress(); + if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0) + return nullptr; + + auto func_length = pdb_func.getLength(); + AddressRange func_range = + AddressRange(file_vm_addr, func_length, sc.module_sp->GetSectionList()); + if (!func_range.GetBaseAddress().IsValid()) + return nullptr; + + lldb_private::Type *func_type = ResolveTypeUID(pdb_func.getSymIndexId()); + if (!func_type) + return nullptr; + + user_id_t func_type_uid = pdb_func.getSignatureId(); + + Mangled mangled = GetMangledForPDBFunc(pdb_func); + + FunctionSP func_sp = + std::make_shared<Function>(sc.comp_unit, pdb_func.getSymIndexId(), + func_type_uid, mangled, func_type, func_range); + + sc.comp_unit->AddFunction(func_sp); + return func_sp.get(); +} + size_t SymbolFilePDB::ParseCompileUnitFunctions( const lldb_private::SymbolContext &sc) { - // TODO: Implement this - return size_t(); + lldbassert(sc.comp_unit); + size_t func_added = 0; + auto compiland_up = GetPDBCompilandByUID(sc.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()); + if (!func_sp) { + if (ParseCompileUnitFunctionForPDBFunc(*pdb_func_up, sc)) + ++func_added; + } + } + return func_added; } bool SymbolFilePDB::ParseCompileUnitLineTable( const lldb_private::SymbolContext &sc) { + lldbassert(sc.comp_unit); + if (sc.comp_unit->GetLineTable()) + return true; return ParseCompileUnitLineTable(sc, 0); } @@ -226,26 +330,29 @@ bool SymbolFilePDB::ParseCompileUnitDebugMacros( bool SymbolFilePDB::ParseCompileUnitSupportFiles( const lldb_private::SymbolContext &sc, lldb_private::FileSpecList &support_files) { - if (!sc.comp_unit) - return false; + lldbassert(sc.comp_unit); // 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 cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>( - sc.comp_unit->GetID()); - if (!cu) + auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland_up) return false; - auto files = m_session_up->getSourceFilesForCompiland(*cu); + auto files = m_session_up->getSourceFilesForCompiland(*compiland_up); if (!files || files->getChildCount() == 0) return false; while (auto file = files->getNext()) { - FileSpec spec(file->getFileName(), false); - support_files.Append(spec); + FileSpec spec(file->getFileName(), false, 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); + return true; } @@ -256,21 +363,178 @@ bool SymbolFilePDB::ParseImportedModules( return false; } +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) { + assert(pdb_symbol && parent_block); + + size_t num_added = 0; + switch (pdb_symbol->getSymTag()) { + case PDB_SymType::Block: + case PDB_SymType::Function: { + Block *block = nullptr; + auto &raw_sym = pdb_symbol->getRawSymbol(); + if (auto *pdb_func = llvm::dyn_cast<PDBSymbolFunc>(pdb_symbol)) { + if (pdb_func->hasNoInlineAttribute()) + break; + if (is_top_parent) + block = parent_block; + else + break; + } else if (llvm::dyn_cast<PDBSymbolBlock>(pdb_symbol)) { + auto uid = pdb_symbol->getSymIndexId(); + if (parent_block->FindBlockByID(uid)) + break; + if (raw_sym.getVirtualAddress() < func_file_vm_addr) + break; + + auto block_sp = std::make_shared<Block>(pdb_symbol->getSymIndexId()); + parent_block->AddChild(block_sp); + block = block_sp.get(); + } else + llvm_unreachable("Unexpected PDB symbol!"); + + block->AddRange(Block::Range( + raw_sym.getVirtualAddress() - func_file_vm_addr, raw_sym.getLength())); + block->FinalizeRanges(); + ++num_added; + + auto results_up = pdb_symbol->findAllChildren(); + if (!results_up) + break; + while (auto symbol_up = results_up->getNext()) { + num_added += ParseFunctionBlocksForPDBSymbol( + sc, func_file_vm_addr, symbol_up.get(), block, false); + } + } break; + default: + break; + } + return num_added; +} + size_t SymbolFilePDB::ParseFunctionBlocks(const lldb_private::SymbolContext &sc) { - // TODO: Implement this - return size_t(); + lldbassert(sc.comp_unit && sc.function); + size_t num_added = 0; + auto uid = sc.function->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); + return num_added; } size_t SymbolFilePDB::ParseTypes(const lldb_private::SymbolContext &sc) { - // TODO: Implement this - return size_t(); + lldbassert(sc.module_sp.get()); + if (!sc.comp_unit) + return 0; + + size_t num_added = 0; + auto compiland = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland) + return 0; + + auto ParseTypesByTagFn = [&num_added, this](const PDBSymbol &raw_sym) { + std::unique_ptr<IPDBEnumSymbols> results; + PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef, + PDB_SymType::UDT}; + for (auto tag : tags_to_search) { + results = raw_sym.findAllChildren(tag); + if (!results || results->getChildCount() == 0) + continue; + while (auto symbol = results->getNext()) { + switch (symbol->getSymTag()) { + case PDB_SymType::Enum: + case PDB_SymType::UDT: + case PDB_SymType::Typedef: + break; + default: + continue; + } + + // This should cause the type to get cached and stored in the `m_types` + // lookup. + if (!ResolveTypeUID(symbol->getSymIndexId())) + continue; + + ++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; + } + } + return num_added; } size_t SymbolFilePDB::ParseVariablesForContext(const lldb_private::SymbolContext &sc) { - // TODO: Implement this - return size_t(); + if (!sc.comp_unit) + return 0; + + size_t num_added = 0; + if (sc.function) { + auto pdb_func = m_session_up->getConcreteSymbolById<PDBSymbolFunc>( + sc.function->GetID()); + if (!pdb_func) + return 0; + + num_added += ParseVariables(sc, *pdb_func); + sc.function->GetBlock(false).SetDidParseVariables(true, true); + } else if (sc.comp_unit) { + auto compiland = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland) + return 0; + + if (sc.comp_unit->GetVariableList(false)) + return 0; + + auto results = m_global_scope_up->findAllChildren<PDBSymbolData>(); + if (results && results->getChildCount()) { + while (auto result = results->getNext()) { + auto cu_id = result->getCompilandId(); + // FIXME: We are not able to determine variable's compile unit. + if (cu_id == 0) + continue; + + if (cu_id == sc.comp_unit->GetID()) + num_added += ParseVariables(sc, *result); + } + } + + // FIXME: A `file static` or `global constant` variable appears both in + // compiland's children and global scope's children with unexpectedly + // different symbol's Id making it ambiguous. + + // FIXME: 'local constant', for example, const char var[] = "abc", declared + // in a function scope, can't be found in PDB. + + // Parse variables in this compiland. + num_added += ParseVariables(sc, *compiland); + } + + return num_added; } lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) { @@ -294,8 +558,12 @@ lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) { return nullptr; lldb::TypeSP result = pdb->CreateLLDBTypeFromPDBType(*pdb_type); - if (result.get()) + if (result) { m_types.insert(std::make_pair(type_uid, result)); + auto type_list = GetTypeList(); + if (type_list) + type_list->Insert(result); + } return result.get(); } @@ -328,12 +596,62 @@ uint32_t SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr, uint32_t resolve_scope, lldb_private::SymbolContext &sc) { - return uint32_t(); + uint32_t resolved_flags = 0; + if (resolve_scope & eSymbolContextCompUnit || + resolve_scope & eSymbolContextVariable || + resolve_scope & eSymbolContextFunction || + resolve_scope & eSymbolContextBlock || + resolve_scope & eSymbolContextLineEntry) { + auto cu_sp = GetCompileUnitContainsAddress(so_addr); + if (!cu_sp) { + if (resolved_flags | eSymbolContextVariable) { + // TODO: Resolve variables + } + return 0; + } + sc.comp_unit = cu_sp.get(); + resolved_flags |= eSymbolContextCompUnit; + lldbassert(sc.module_sp == cu_sp->GetModule()); + } + + if (resolve_scope & eSymbolContextFunction) { + addr_t file_vm_addr = so_addr.GetFileAddress(); + auto symbol_up = + m_session_up->findSymbolByAddress(file_vm_addr, PDB_SymType::Function); + if (symbol_up) { + auto *pdb_func = llvm::dyn_cast<PDBSymbolFunc>(symbol_up.get()); + assert(pdb_func); + 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); + if (sc.function) { + resolved_flags |= eSymbolContextFunction; + if (resolve_scope & eSymbolContextBlock) { + Block &block = sc.function->GetBlock(true); + sc.block = block.FindBlockByID(sc.function->GetID()); + if (sc.block) + resolved_flags |= eSymbolContextBlock; + } + } + } + } + + if (resolve_scope & eSymbolContextLineEntry) { + if (auto *line_table = sc.comp_unit->GetLineTable()) { + Address addr(so_addr); + if (line_table->FindLineEntryByAddress(addr, sc.line_entry)) + resolved_flags |= eSymbolContextLineEntry; + } + } + + return resolved_flags; } 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) { + const size_t old_size = sc_list.GetSize(); if (resolve_scope & lldb::eSymbolContextCompUnit) { // Locate all compilation units with line numbers referencing the specified // file. For example, if `file_spec` is <vector>, then this should return @@ -342,56 +660,498 @@ uint32_t SymbolFilePDB::ResolveSymbolContext( auto compilands = m_session_up->findCompilandsForSourceFile( file_spec.GetPath(), PDB_NameSearchFlags::NS_CaseInsensitive); + if (!compilands) + return 0; + // For each one, either find its previously parsed data or parse it afresh // and add it to the symbol context list. while (auto compiland = compilands->getNext()) { - // If we're not checking inlines, then don't add line information for this - // file unless the FileSpec matches. + // If we're not checking inlines, then don't add line information for + // this file unless the FileSpec matches. For inline functions, we don't + // have to match the FileSpec since they could be defined in headers + // other than file specified in FileSpec. if (!check_inlines) { - // `getSourceFileName` returns the basename of the original source file - // used to generate this compiland. It does not return the full path. - // Currently the only way to get that is to do a basename lookup to get - // the IPDBSourceFile, but this is ambiguous in the case of two source - // files with the same name contributing to the same compiland. This is - // a moderately extreme edge case, so we consider this OK for now, - // although we need to find a long-term solution. - std::string source_file = compiland->getSourceFileName(); - auto pdb_file = m_session_up->findOneSourceFile( - compiland.get(), source_file, - PDB_NameSearchFlags::NS_CaseInsensitive); - source_file = pdb_file->getFileName(); - FileSpec this_spec(source_file, false, FileSpec::ePathSyntaxWindows); - if (!file_spec.FileEquals(this_spec)) + std::string source_file = compiland->getSourceFileFullPath(); + if (source_file.empty()) + continue; + FileSpec this_spec(source_file, false, FileSpec::Style::windows); + bool need_full_match = !file_spec.GetDirectory().IsEmpty(); + if (FileSpec::Compare(file_spec, this_spec, need_full_match) != 0) continue; } SymbolContext sc; - auto cu = ParseCompileUnitForSymIndex(compiland->getSymIndexId()); + auto cu = ParseCompileUnitForUID(compiland->getSymIndexId()); + if (!cu) + continue; sc.comp_unit = cu.get(); sc.module_sp = cu->GetModule(); - sc_list.Append(sc); // If we were asked to resolve line entries, add all entries to the line // table that match the requested line (or all lines if `line` == 0). - if (resolve_scope & lldb::eSymbolContextLineEntry) - ParseCompileUnitLineTable(sc, line); + if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock | + eSymbolContextLineEntry)) { + bool has_line_table = ParseCompileUnitLineTable(sc, line); + + if ((resolve_scope & eSymbolContextLineEntry) && !has_line_table) { + // The query asks for line entries, but we can't get them for the + // compile unit. This is not normal for `line` = 0. So just assert + // it. + assert(line && "Couldn't get all line entries!\n"); + + // Current compiland does not have the requested line. Search next. + continue; + } + + if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) { + if (!has_line_table) + continue; + + auto *line_table = sc.comp_unit->GetLineTable(); + lldbassert(line_table); + + uint32_t num_line_entries = line_table->GetSize(); + // Skip the terminal line entry. + --num_line_entries; + + // If `line `!= 0, see if we can resolve function for each line entry + // in the line table. + for (uint32_t line_idx = 0; line && line_idx < num_line_entries; + ++line_idx) { + if (!line_table->GetLineEntryAtIndex(line_idx, sc.line_entry)) + continue; + + auto file_vm_addr = + sc.line_entry.range.GetBaseAddress().GetFileAddress(); + if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0) + continue; + + auto symbol_up = m_session_up->findSymbolByAddress( + file_vm_addr, PDB_SymType::Function); + if (symbol_up) { + auto func_uid = symbol_up->getSymIndexId(); + sc.function = sc.comp_unit->FindFunctionByUID(func_uid).get(); + if (sc.function == nullptr) { + auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(symbol_up.get()); + assert(pdb_func); + sc.function = ParseCompileUnitFunctionForPDBFunc(*pdb_func, sc); + } + if (sc.function && (resolve_scope & eSymbolContextBlock)) { + Block &block = sc.function->GetBlock(true); + sc.block = block.FindBlockByID(sc.function->GetID()); + } + } + sc_list.Append(sc); + } + } else if (has_line_table) { + // We can parse line table for the compile unit. But no query to + // resolve function or block. We append `sc` to the list anyway. + sc_list.Append(sc); + } + } else { + // No query for line entry, function or block. But we have a valid + // compile unit, append `sc` to the list. + sc_list.Append(sc); + } } } - return sc_list.GetSize(); + return sc_list.GetSize() - old_size; +} + +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(); +} + +VariableSP SymbolFilePDB::ParseVariableForPDBData( + const lldb_private::SymbolContext &sc, + const llvm::pdb::PDBSymbolData &pdb_data) { + VariableSP var_sp; + uint32_t var_uid = pdb_data.getSymIndexId(); + auto result = m_variables.find(var_uid); + if (result != m_variables.end()) + return result->second; + + ValueType scope = eValueTypeInvalid; + bool is_static_member = false; + bool is_external = false; + bool is_artificial = false; + + switch (pdb_data.getDataKind()) { + case PDB_DataKind::Global: + scope = eValueTypeVariableGlobal; + is_external = true; + break; + case PDB_DataKind::Local: + scope = eValueTypeVariableLocal; + break; + case PDB_DataKind::FileStatic: + scope = eValueTypeVariableStatic; + break; + case PDB_DataKind::StaticMember: + is_static_member = true; + scope = eValueTypeVariableStatic; + break; + case PDB_DataKind::Member: + scope = eValueTypeVariableStatic; + break; + case PDB_DataKind::Param: + scope = eValueTypeVariableArgument; + break; + case PDB_DataKind::Constant: + scope = eValueTypeConstResult; + break; + default: + break; + } + + switch (pdb_data.getLocationType()) { + case PDB_LocType::TLS: + scope = eValueTypeVariableThreadLocal; + break; + case PDB_LocType::RegRel: { + // It is a `this` pointer. + if (pdb_data.getDataKind() == PDB_DataKind::ObjectPtr) { + scope = eValueTypeVariableArgument; + is_artificial = true; + } + } break; + default: + break; + } + + Declaration decl; + if (!is_artificial && !pdb_data.isCompilerGenerated()) { + if (auto lines = pdb_data.getLineNumbers()) { + if (auto first_line = lines->getNext()) { + 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); + decl.SetFile(spec); + decl.SetColumn(first_line->getColumnNumber()); + decl.SetLine(first_line->getLineNumber()); + } + } + } + } + + Variable::RangeList ranges; + SymbolContextScope *context_scope = sc.comp_unit; + if (scope == eValueTypeVariableLocal) { + if (sc.function) { + context_scope = sc.function->GetBlock(true).FindBlockByID( + pdb_data.getClassParentId()); + if (context_scope == nullptr) + context_scope = sc.function; + } + } + + SymbolFileTypeSP type_sp = + std::make_shared<SymbolFileType>(*this, pdb_data.getTypeId()); + + auto var_name = pdb_data.getName(); + auto mangled = GetMangledForPDBData(pdb_data); + auto mangled_cstr = mangled.empty() ? nullptr : mangled.c_str(); + + bool is_constant; + DWARFExpression location = ConvertPDBLocationToDWARFExpression( + GetObjectFile()->GetModule(), pdb_data, is_constant); + + var_sp = std::make_shared<Variable>( + var_uid, var_name.c_str(), mangled_cstr, type_sp, scope, context_scope, + ranges, &decl, location, is_external, is_artificial, is_static_member); + var_sp->SetLocationIsConstantValueData(is_constant); + + m_variables.insert(std::make_pair(var_uid, var_sp)); + return var_sp; +} + +size_t +SymbolFilePDB::ParseVariables(const lldb_private::SymbolContext &sc, + const llvm::pdb::PDBSymbol &pdb_symbol, + lldb_private::VariableList *variable_list) { + size_t num_added = 0; + + if (auto pdb_data = llvm::dyn_cast<PDBSymbolData>(&pdb_symbol)) { + VariableListSP local_variable_list_sp; + + auto result = m_variables.find(pdb_data->getSymIndexId()); + if (result != m_variables.end()) { + if (variable_list) + variable_list->AddVariableIfUnique(result->second); + } else { + // Prepare right VariableList for this variable. + if (auto lexical_parent = pdb_data->getLexicalParent()) { + switch (lexical_parent->getSymTag()) { + case PDB_SymType::Exe: + assert(sc.comp_unit); + LLVM_FALLTHROUGH; + case PDB_SymType::Compiland: { + if (sc.comp_unit) { + local_variable_list_sp = sc.comp_unit->GetVariableList(false); + if (!local_variable_list_sp) { + local_variable_list_sp = std::make_shared<VariableList>(); + sc.comp_unit->SetVariableList(local_variable_list_sp); + } + } + } break; + case PDB_SymType::Block: + case PDB_SymType::Function: { + if (sc.function) { + Block *block = sc.function->GetBlock(true).FindBlockByID( + lexical_parent->getSymIndexId()); + if (block) { + local_variable_list_sp = block->GetBlockVariableList(false); + if (!local_variable_list_sp) { + local_variable_list_sp = std::make_shared<VariableList>(); + block->SetVariableList(local_variable_list_sp); + } + } + } + } break; + default: + break; + } + } + + if (local_variable_list_sp) { + if (auto var_sp = ParseVariableForPDBData(sc, *pdb_data)) { + local_variable_list_sp->AddVariableIfUnique(var_sp); + if (variable_list) + variable_list->AddVariableIfUnique(var_sp); + ++num_added; + } + } + } + } + + if (auto results = pdb_symbol.findAllChildren()) { + while (auto result = results->getNext()) + num_added += ParseVariables(sc, *result, variable_list); + } + + return num_added; } uint32_t SymbolFilePDB::FindGlobalVariables( const lldb_private::ConstString &name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, + const lldb_private::CompilerDeclContext *parent_decl_ctx, uint32_t max_matches, lldb_private::VariableList &variables) { - return uint32_t(); + if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) + return 0; + if (name.IsEmpty()) + return 0; + + auto results = + m_global_scope_up->findChildren(PDB_SymType::Data, name.GetStringRef(), + PDB_NameSearchFlags::NS_CaseSensitive); + if (!results) + return 0; + + uint32_t matches = 0; + size_t old_size = variables.GetSize(); + while (auto result = results->getNext()) { + auto pdb_data = llvm::dyn_cast<PDBSymbolData>(result.get()); + if (max_matches > 0 && matches >= max_matches) + break; + + SymbolContext sc; + sc.module_sp = m_obj_file->GetModule(); + lldbassert(sc.module_sp.get()); + + sc.comp_unit = ParseCompileUnitForUID(pdb_data->getCompilandId()).get(); + // FIXME: We are not able to determine the compile unit. + if (sc.comp_unit == nullptr) + continue; + + ParseVariables(sc, *pdb_data, &variables); + matches = variables.GetSize() - old_size; + } + + return matches; } uint32_t SymbolFilePDB::FindGlobalVariables(const lldb_private::RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) { - return uint32_t(); + if (!regex.IsValid()) + return 0; + auto results = m_global_scope_up->findAllChildren<PDBSymbolData>(); + if (!results) + return 0; + + uint32_t matches = 0; + size_t old_size = variables.GetSize(); + while (auto pdb_data = results->getNext()) { + if (max_matches > 0 && matches >= max_matches) + break; + + auto var_name = pdb_data->getName(); + if (var_name.empty()) + continue; + if (!regex.Execute(var_name)) + continue; + SymbolContext sc; + sc.module_sp = m_obj_file->GetModule(); + lldbassert(sc.module_sp.get()); + + sc.comp_unit = ParseCompileUnitForUID(pdb_data->getCompilandId()).get(); + // FIXME: We are not able to determine the compile unit. + if (sc.comp_unit == nullptr) + continue; + + ParseVariables(sc, *pdb_data, &variables); + matches = variables.GetSize() - old_size; + } + + return matches; +} + +bool SymbolFilePDB::ResolveFunction(const llvm::pdb::PDBSymbolFunc &pdb_func, + bool include_inlines, + lldb_private::SymbolContextList &sc_list) { + lldb_private::SymbolContext sc; + sc.comp_unit = ParseCompileUnitForUID(pdb_func.getCompilandId()).get(); + if (!sc.comp_unit) + return false; + sc.module_sp = sc.comp_unit->GetModule(); + sc.function = ParseCompileUnitFunctionForPDBFunc(pdb_func, sc); + if (!sc.function) + return false; + + sc_list.Append(sc); + return true; +} + +bool SymbolFilePDB::ResolveFunction(uint32_t uid, bool include_inlines, + lldb_private::SymbolContextList &sc_list) { + auto pdb_func_up = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(uid); + if (!pdb_func_up && !(include_inlines && pdb_func_up->hasInlineAttribute())) + return false; + return ResolveFunction(*pdb_func_up, include_inlines, sc_list); +} + +void SymbolFilePDB::CacheFunctionNames() { + if (!m_func_full_names.IsEmpty()) + return; + + std::map<uint64_t, uint32_t> addr_ids; + + if (auto results_up = m_global_scope_up->findAllChildren<PDBSymbolFunc>()) { + while (auto pdb_func_up = results_up->getNext()) { + if (pdb_func_up->isCompilerGenerated()) + continue; + + auto name = pdb_func_up->getName(); + auto demangled_name = pdb_func_up->getUndecoratedName(); + if (name.empty() && demangled_name.empty()) + continue; + + auto uid = pdb_func_up->getSymIndexId(); + if (!demangled_name.empty() && pdb_func_up->getVirtualAddress()) + addr_ids.insert(std::make_pair(pdb_func_up->getVirtualAddress(), uid)); + + if (auto parent = pdb_func_up->getClassParent()) { + + // PDB have symbols for class/struct methods or static methods in Enum + // 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); + } + + if (!basename.empty()) + m_func_base_names.Append(ConstString(basename), uid); + else { + m_func_base_names.Append(ConstString(name), uid); + } + + if (!demangled_name.empty()) + m_func_full_names.Append(ConstString(demangled_name), uid); + + } 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); + + if (name == "main") { + m_func_full_names.Append(ConstString(name), uid); + + if (!demangled_name.empty() && name != demangled_name) { + m_func_full_names.Append(ConstString(demangled_name), uid); + m_func_base_names.Append(ConstString(demangled_name), uid); + } + } else if (!demangled_name.empty()) { + m_func_full_names.Append(ConstString(demangled_name), uid); + } else { + m_func_full_names.Append(ConstString(name), uid); + } + } + } + } + + if (auto results_up = + m_global_scope_up->findAllChildren<PDBSymbolPublicSymbol>()) { + while (auto pub_sym_up = results_up->getNext()) { + if (!pub_sym_up->isFunction()) + continue; + auto name = pub_sym_up->getName(); + if (name.empty()) + continue; + + if (CPlusPlusLanguage::IsCPPMangledName(name.c_str())) { + auto vm_addr = pub_sym_up->getVirtualAddress(); + + // PDB public symbol has mangled name for its associated function. + if (vm_addr && addr_ids.find(vm_addr) != addr_ids.end()) { + // Cache mangled name. + m_func_full_names.Append(ConstString(name), addr_ids[vm_addr]); + } + } + } + } + // Sort them before value searching is working properly + m_func_full_names.Sort(); + m_func_full_names.SizeToFit(); + m_func_method_names.Sort(); + m_func_method_names.SizeToFit(); + m_func_base_names.Sort(); + m_func_base_names.SizeToFit(); } uint32_t SymbolFilePDB::FindFunctions( @@ -399,14 +1159,77 @@ uint32_t SymbolFilePDB::FindFunctions( const lldb_private::CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList &sc_list) { - return uint32_t(); + if (!append) + sc_list.Clear(); + lldbassert((name_type_mask & eFunctionNameTypeAuto) == 0); + + if (name_type_mask == eFunctionNameTypeNone) + return 0; + if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) + return 0; + if (name.IsEmpty()) + return 0; + + auto old_size = sc_list.GetSize(); + if (name_type_mask & eFunctionNameTypeFull || + name_type_mask & eFunctionNameTypeBase || + name_type_mask & eFunctionNameTypeMethod) { + CacheFunctionNames(); + + std::set<uint32_t> resolved_ids; + auto ResolveFn = [include_inlines, &name, &sc_list, &resolved_ids, + this](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 (name_type_mask & eFunctionNameTypeFull) { + ResolveFn(m_func_full_names); + } + if (name_type_mask & eFunctionNameTypeBase) { + ResolveFn(m_func_base_names); + } + if (name_type_mask & eFunctionNameTypeMethod) { + ResolveFn(m_func_method_names); + } + } + return sc_list.GetSize() - old_size; } uint32_t SymbolFilePDB::FindFunctions(const lldb_private::RegularExpression ®ex, bool include_inlines, bool append, lldb_private::SymbolContextList &sc_list) { - return uint32_t(); + if (!append) + sc_list.Clear(); + if (!regex.IsValid()) + return 0; + + auto old_size = sc_list.GetSize(); + CacheFunctionNames(); + + std::set<uint32_t> resolved_ids; + auto ResolveFn = [®ex, include_inlines, &sc_list, &resolved_ids, + this](UniqueCStringMap<uint32_t> &Names) { + std::vector<uint32_t> ids; + if (Names.GetValues(regex, ids)) { + for (auto id : ids) { + if (resolved_ids.find(id) == resolved_ids.end()) + if (ResolveFunction(id, include_inlines, sc_list)) + resolved_ids.insert(id); + } + } + }; + ResolveFn(m_func_full_names); + ResolveFn(m_func_base_names); + + return sc_list.GetSize() - old_size; } void SymbolFilePDB::GetMangledNamesForFunction( @@ -424,6 +1247,8 @@ uint32_t SymbolFilePDB::FindTypes( types.Clear(); if (!name) return 0; + if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) + return 0; searched_symbol_files.clear(); searched_symbol_files.insert(this); @@ -432,14 +1257,13 @@ uint32_t SymbolFilePDB::FindTypes( // There is an assumption 'name' is not a regex FindTypesByName(name_str, max_matches, types); - + return types.GetSize(); } -void -SymbolFilePDB::FindTypesByRegex(const lldb_private::RegularExpression ®ex, - uint32_t max_matches, - lldb_private::TypeMap &types) { +void SymbolFilePDB::FindTypesByRegex( + const lldb_private::RegularExpression ®ex, uint32_t max_matches, + lldb_private::TypeMap &types) { // When searching by regex, we need to go out of our way to limit the search // space as much as possible since this searches EVERYTHING in the PDB, // manually doing regex comparisons. PDB library isn't optimized for regex @@ -448,13 +1272,15 @@ SymbolFilePDB::FindTypesByRegex(const lldb_private::RegularExpression ®ex, // and do a regex comparison against each of them. PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef, PDB_SymType::UDT}; - auto global = m_session_up->getGlobalScope(); std::unique_ptr<IPDBEnumSymbols> results; uint32_t matches = 0; for (auto tag : tags_to_search) { - results = global->findAllChildren(tag); + results = m_global_scope_up->findAllChildren(tag); + if (!results) + continue; + while (auto result = results->getNext()) { if (max_matches > 0 && matches >= max_matches) break; @@ -493,10 +1319,13 @@ SymbolFilePDB::FindTypesByRegex(const lldb_private::RegularExpression ®ex, void SymbolFilePDB::FindTypesByName(const std::string &name, uint32_t max_matches, lldb_private::TypeMap &types) { - auto global = m_session_up->getGlobalScope(); std::unique_ptr<IPDBEnumSymbols> results; - results = global->findChildren(PDB_SymType::None, name, - PDB_NameSearchFlags::NS_Default); + if (name.empty()) + return; + results = m_global_scope_up->findChildren(PDB_SymType::None, name, + PDB_NameSearchFlags::NS_Default); + if (!results) + return; uint32_t matches = 0; @@ -509,8 +1338,8 @@ void SymbolFilePDB::FindTypesByName(const std::string &name, case PDB_SymType::Typedef: break; default: - // We're looking only for types that have names. Skip symbols, as well as - // unnamed types such as arrays, pointers, etc. + // We're looking only for types that have names. Skip symbols, as well + // as unnamed types such as arrays, pointers, etc. continue; } @@ -533,12 +1362,87 @@ size_t SymbolFilePDB::FindTypes( return 0; } -lldb_private::TypeList *SymbolFilePDB::GetTypeList() { return nullptr; } +lldb_private::TypeList *SymbolFilePDB::GetTypeList() { + return m_obj_file->GetModule()->GetTypeList(); +} + +void SymbolFilePDB::GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol, + uint32_t type_mask, + TypeCollection &type_collection) { + bool can_parse = false; + switch (pdb_symbol.getSymTag()) { + case PDB_SymType::ArrayType: + can_parse = ((type_mask & eTypeClassArray) != 0); + break; + case PDB_SymType::BuiltinType: + can_parse = ((type_mask & eTypeClassBuiltin) != 0); + break; + case PDB_SymType::Enum: + can_parse = ((type_mask & eTypeClassEnumeration) != 0); + break; + case PDB_SymType::Function: + case PDB_SymType::FunctionSig: + can_parse = ((type_mask & eTypeClassFunction) != 0); + break; + case PDB_SymType::PointerType: + can_parse = ((type_mask & (eTypeClassPointer | eTypeClassBlockPointer | + eTypeClassMemberPointer)) != 0); + break; + case PDB_SymType::Typedef: + can_parse = ((type_mask & eTypeClassTypedef) != 0); + break; + case PDB_SymType::UDT: { + auto *udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&pdb_symbol); + assert(udt); + can_parse = (udt->getUdtKind() != PDB_UdtType::Interface && + ((type_mask & (eTypeClassClass | eTypeClassStruct | + eTypeClassUnion)) != 0)); + } break; + default: + break; + } + + if (can_parse) { + if (auto *type = ResolveTypeUID(pdb_symbol.getSymIndexId())) { + auto result = + std::find(type_collection.begin(), type_collection.end(), type); + if (result == type_collection.end()) + type_collection.push_back(type); + } + } + + auto results_up = pdb_symbol.findAllChildren(); + while (auto symbol_up = results_up->getNext()) + GetTypesForPDBSymbol(*symbol_up, type_mask, type_collection); +} size_t SymbolFilePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope, uint32_t type_mask, lldb_private::TypeList &type_list) { - return size_t(); + TypeCollection type_collection; + uint32_t old_size = type_list.GetSize(); + CompileUnit *cu = + sc_scope ? sc_scope->CalculateSymbolContextCompileUnit() : nullptr; + if (cu) { + auto compiland_up = GetPDBCompilandByUID(cu->GetID()); + if (!compiland_up) + return 0; + GetTypesForPDBSymbol(*compiland_up, type_mask, type_collection); + } else { + for (uint32_t cu_idx = 0; cu_idx < GetNumCompileUnits(); ++cu_idx) { + auto cu_sp = ParseCompileUnitAtIndex(cu_idx); + if (cu_sp) { + if (auto compiland_up = GetPDBCompilandByUID(cu_sp->GetID())) + GetTypesForPDBSymbol(*compiland_up, type_mask, type_collection); + } + } + } + + for (auto type : type_collection) { + type->GetForwardCompilerType(); + type_list.Insert(type->shared_from_this()); + } + return type_list.GetSize() - old_size; } lldb_private::TypeSystem * @@ -570,65 +1474,78 @@ const IPDBSession &SymbolFilePDB::GetPDBSession() const { return *m_session_up; } -lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitForSymIndex(uint32_t id) { +lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitForUID(uint32_t id, + uint32_t index) { auto found_cu = m_comp_units.find(id); if (found_cu != m_comp_units.end()) return found_cu->second; - auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(id); - - // `getSourceFileName` returns the basename of the original source file used - // to generate this compiland. It does not return the full path. Currently - // the only way to get that is to do a basename lookup to get the - // IPDBSourceFile, but this is ambiguous in the case of two source files with - // the same name contributing to the same compiland. This is a moderately - // extreme edge case, so we consider this OK for now, although we need to find - // a long-term solution. - auto file = - m_session_up->findOneSourceFile(cu.get(), cu->getSourceFileName(), - PDB_NameSearchFlags::NS_CaseInsensitive); - std::string path = file->getFileName(); + auto compiland_up = GetPDBCompilandByUID(id); + if (!compiland_up) + return CompUnitSP(); lldb::LanguageType lang; - auto details = cu->findOneChild<PDBSymbolCompilandDetails>(); + auto details = compiland_up->findOneChild<PDBSymbolCompilandDetails>(); if (!details) lang = lldb::eLanguageTypeC_plus_plus; else lang = TranslateLanguage(details->getLanguage()); + if (lang == lldb::LanguageType::eLanguageTypeUnknown) + return CompUnitSP(); + + std::string path = compiland_up->getSourceFileFullPath(); + if (path.empty()) + return CompUnitSP(); + // Don't support optimized code for now, DebugInfoPDB does not return this // information. LazyBool optimized = eLazyBoolNo; - auto result = std::make_shared<CompileUnit>( - m_obj_file->GetModule(), nullptr, path.c_str(), id, lang, optimized); - m_comp_units.insert(std::make_pair(id, result)); - return result; + auto cu_sp = std::make_shared<CompileUnit>(m_obj_file->GetModule(), nullptr, + path.c_str(), id, lang, optimized); + + if (!cu_sp) + return CompUnitSP(); + + m_comp_units.insert(std::make_pair(id, cu_sp)); + if (index == UINT32_MAX) + GetCompileUnitIndex(*compiland_up, index); + lldbassert(index != UINT32_MAX); + m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(index, + cu_sp); + return cu_sp; } bool SymbolFilePDB::ParseCompileUnitLineTable( const lldb_private::SymbolContext &sc, uint32_t match_line) { - auto global = m_session_up->getGlobalScope(); - auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>( - sc.comp_unit->GetID()); + lldbassert(sc.comp_unit); + + auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland_up) + return false; // LineEntry needs the *index* of the file into the list of support files // returned by ParseCompileUnitSupportFiles. But the underlying SDK gives us - // a globally unique idenfitifier in the namespace of the PDB. So, we have to - // do a mapping so that we can hand out indices. + // a globally unique idenfitifier in the namespace of the PDB. So, we have + // to do a mapping so that we can hand out indices. llvm::DenseMap<uint32_t, uint32_t> index_map; - BuildSupportFileIdToSupportFileIndexMap(*cu, index_map); + BuildSupportFileIdToSupportFileIndexMap(*compiland_up, index_map); auto line_table = llvm::make_unique<LineTable>(sc.comp_unit); - // Find contributions to `cu` from all source and header files. + // Find contributions to `compiland` from all source and header files. std::string path = sc.comp_unit->GetPath(); - auto files = m_session_up->getSourceFilesForCompiland(*cu); + auto files = m_session_up->getSourceFilesForCompiland(*compiland_up); + if (!files) + return false; - // For each source and header file, create a LineSequence for contributions to - // the cu from that file, and add the sequence. + // For each source and header file, create a LineSequence for contributions + // to the compiland from that file, and add the sequence. while (auto file = files->getNext()) { std::unique_ptr<LineSequence> sequence( line_table->CreateLineSequenceContainer()); - auto lines = m_session_up->findLineNumbers(*cu, *file); + auto lines = m_session_up->findLineNumbers(*compiland_up, *file); + if (!lines) + continue; int entry_count = lines->getChildCount(); uint64_t prev_addr; @@ -646,8 +1563,8 @@ bool SymbolFilePDB::ParseCompileUnitLineTable( uint32_t col = line->getColumnNumber(); uint32_t source_idx = index_map[source_id]; - // There was a gap between the current entry and the previous entry if the - // addresses don't perfectly line up. + // There was a gap between the current entry and the previous entry if + // the addresses don't perfectly line up. bool is_gap = (i > 0) && (prev_addr + prev_length < addr); // Before inserting the current entry, insert a terminal entry at the end @@ -657,6 +1574,9 @@ bool SymbolFilePDB::ParseCompileUnitLineTable( line_table->AppendLineEntryToSequence( sequence.get(), prev_addr + prev_length, prev_line, 0, prev_source_idx, false, false, false, false, true); + + line_table->InsertSequence(sequence.release()); + sequence.reset(line_table->CreateLineSequenceContainer()); } if (ShouldAddLine(match_line, lno, length)) { @@ -667,10 +1587,12 @@ bool SymbolFilePDB::ParseCompileUnitLineTable( m_session_up->findSymbolByAddress(addr, PDB_SymType::Function); if (func) { auto prologue = func->findOneChild<PDBSymbolFuncDebugStart>(); - is_prologue = (addr == prologue->getVirtualAddress()); + if (prologue) + is_prologue = (addr == prologue->getVirtualAddress()); auto epilogue = func->findOneChild<PDBSymbolFuncDebugEnd>(); - is_epilogue = (addr == epilogue->getVirtualAddress()); + if (epilogue) + is_epilogue = (addr == epilogue->getVirtualAddress()); } line_table->AppendLineEntryToSequence(sequence.get(), addr, lno, col, @@ -694,23 +1616,134 @@ bool SymbolFilePDB::ParseCompileUnitLineTable( line_table->InsertSequence(sequence.release()); } - sc.comp_unit->SetLineTable(line_table.release()); - return true; + if (line_table->GetSize()) { + sc.comp_unit->SetLineTable(line_table.release()); + return true; + } + return false; } void SymbolFilePDB::BuildSupportFileIdToSupportFileIndexMap( - const PDBSymbolCompiland &cu, + const PDBSymbolCompiland &compiland, llvm::DenseMap<uint32_t, uint32_t> &index_map) const { - // This is a hack, but we need to convert the source id into an index into the - // support files array. We don't want to do path comparisons to avoid + // This is a hack, but we need to convert the source id into an index into + // the support files array. We don't want to do path comparisons to avoid // basename / full path issues that may or may not even be a problem, so we // use the globally unique source file identifiers. Ideally we could use the // global identifiers everywhere, but LineEntry currently assumes indices. - auto source_files = m_session_up->getSourceFilesForCompiland(cu); - int index = 0; + auto source_files = m_session_up->getSourceFilesForCompiland(compiland); + if (!source_files) + return; + + // LLDB uses the DWARF-like file numeration (one based) + int index = 1; while (auto file = source_files->getNext()) { uint32_t source_id = file->getUniqueId(); index_map[source_id] = index++; } } + +lldb::CompUnitSP SymbolFilePDB::GetCompileUnitContainsAddress( + const lldb_private::Address &so_addr) { + lldb::addr_t file_vm_addr = so_addr.GetFileAddress(); + if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0) + return nullptr; + + // If it is a PDB function's vm addr, this is the first sure bet. + if (auto lines = + m_session_up->findLineNumbersByAddress(file_vm_addr, /*Length=*/1)) { + if (auto first_line = lines->getNext()) + return ParseCompileUnitForUID(first_line->getCompilandId()); + } + + // Otherwise we resort to section contributions. + if (auto sec_contribs = m_session_up->getSectionContribs()) { + while (auto section = sec_contribs->getNext()) { + auto va = section->getVirtualAddress(); + if (file_vm_addr >= va && file_vm_addr < va + section->getLength()) + return ParseCompileUnitForUID(section->getCompilandId()); + } + } + return nullptr; +} + +Mangled +SymbolFilePDB::GetMangledForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func) { + Mangled mangled; + auto func_name = pdb_func.getName(); + auto func_undecorated_name = pdb_func.getUndecoratedName(); + std::string func_decorated_name; + + // Seek from public symbols for non-static function's decorated name if any. + // For static functions, they don't have undecorated names and aren't exposed + // in Public Symbols either. + if (!func_undecorated_name.empty()) { + auto result_up = m_global_scope_up->findChildren( + PDB_SymType::PublicSymbol, func_undecorated_name, + PDB_NameSearchFlags::NS_UndecoratedName); + if (result_up) { + while (auto symbol_up = result_up->getNext()) { + // For a public symbol, it is unique. + lldbassert(result_up->getChildCount() == 1); + if (auto *pdb_public_sym = + llvm::dyn_cast_or_null<PDBSymbolPublicSymbol>( + symbol_up.get())) { + if (pdb_public_sym->isFunction()) { + func_decorated_name = pdb_public_sym->getName(); + break; + } + } + } + } + } + if (!func_decorated_name.empty()) { + mangled.SetMangledName(ConstString(func_decorated_name)); + + // For MSVC, format of C funciton's decorated name depends on calling + // conventon. Unfortunately none of the format is recognized by current + // LLDB. For example, `_purecall` is a __cdecl C function. From PDB, + // `__purecall` is retrieved as both its decorated and undecorated name + // (using PDBSymbolFunc::getUndecoratedName method). However `__purecall` + // string is not treated as mangled in LLDB (neither `?` nor `_Z` prefix). + // Mangled::GetDemangledName method will fail internally and caches an + // empty string as its undecorated name. So we will face a contradition + // here for the same symbol: + // non-empty undecorated name from PDB + // empty undecorated name from LLDB + if (!func_undecorated_name.empty() && + mangled.GetDemangledName(mangled.GuessLanguage()).IsEmpty()) + mangled.SetDemangledName(ConstString(func_undecorated_name)); + + // LLDB uses several flags to control how a C++ decorated name is + // undecorated for MSVC. See `safeUndecorateName` in Class Mangled. So the + // yielded name could be different from what we retrieve from + // PDB source unless we also apply same flags in getting undecorated + // name through PDBSymbolFunc::getUndecoratedNameEx method. + if (!func_undecorated_name.empty() && + mangled.GetDemangledName(mangled.GuessLanguage()) != + ConstString(func_undecorated_name)) + mangled.SetDemangledName(ConstString(func_undecorated_name)); + } else if (!func_undecorated_name.empty()) { + mangled.SetDemangledName(ConstString(func_undecorated_name)); + } else if (!func_name.empty()) + mangled.SetValue(ConstString(func_name), false); + + return mangled; +} + +bool SymbolFilePDB::DeclContextMatchesThisSymbolFile( + const lldb_private::CompilerDeclContext *decl_ctx) { + if (decl_ctx == nullptr || !decl_ctx->IsValid()) + return true; + + TypeSystem *decl_ctx_type_system = decl_ctx->GetTypeSystem(); + if (!decl_ctx_type_system) + return false; + TypeSystem *type_system = GetTypeSystemForLanguage( + decl_ctx_type_system->GetMinimumLanguage(nullptr)); + if (decl_ctx_type_system == type_system) + return true; // The type systems match, return true + + return false; +} diff --git a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h index eef96be8d1fe..96b62d68a6c2 100644 --- a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -10,12 +10,15 @@ #ifndef lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ #define lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ +#include "lldb/Core/UniqueCStringMap.h" #include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/VariableList.h" #include "lldb/Utility/UserID.h" #include "llvm/ADT/DenseMap.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" class SymbolFilePDB : public lldb_private::SymbolFile { public: @@ -108,11 +111,11 @@ public: uint32_t FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t FindGlobalVariables(const lldb_private::RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t @@ -141,8 +144,7 @@ public: bool append, lldb_private::TypeMap &types) override; void FindTypesByRegex(const lldb_private::RegularExpression ®ex, - uint32_t max_matches, - lldb_private::TypeMap &types); + uint32_t max_matches, lldb_private::TypeMap &types); lldb_private::TypeList *GetTypeList() override; @@ -167,25 +169,76 @@ public: const llvm::pdb::IPDBSession &GetPDBSession() const; private: - lldb::CompUnitSP ParseCompileUnitForSymIndex(uint32_t id); + lldb::CompUnitSP ParseCompileUnitForUID(uint32_t id, + uint32_t index = UINT32_MAX); bool ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc, uint32_t match_line); void BuildSupportFileIdToSupportFileIndexMap( - const llvm::pdb::PDBSymbolCompiland &cu, + 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); + std::string GetMangledForPDBData(const llvm::pdb::PDBSymbolData &pdb_data); + + lldb::VariableSP + ParseVariableForPDBData(const lldb_private::SymbolContext &sc, + const llvm::pdb::PDBSymbolData &pdb_data); + + size_t ParseVariables(const lldb_private::SymbolContext &sc, + const llvm::pdb::PDBSymbol &pdb_data, + lldb_private::VariableList *variable_list = nullptr); + + lldb::CompUnitSP + GetCompileUnitContainsAddress(const lldb_private::Address &so_addr); + + typedef std::vector<lldb_private::Type *> TypeCollection; + + void GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol, + uint32_t type_mask, + TypeCollection &type_collection); + + lldb_private::Function * + ParseCompileUnitFunctionForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func, + const lldb_private::SymbolContext &sc); + + void GetCompileUnitIndex(const llvm::pdb::PDBSymbolCompiland &pdb_compiland, + uint32_t &index); + + std::unique_ptr<llvm::pdb::PDBSymbolCompiland> + GetPDBCompilandByUID(uint32_t uid); + + lldb_private::Mangled + GetMangledForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func); + + bool ResolveFunction(const llvm::pdb::PDBSymbolFunc &pdb_func, + bool include_inlines, + lldb_private::SymbolContextList &sc_list); + + bool ResolveFunction(uint32_t uid, bool include_inlines, + lldb_private::SymbolContextList &sc_list); + + void CacheFunctionNames(); + + bool DeclContextMatchesThisSymbolFile( + const lldb_private::CompilerDeclContext *decl_ctx); + 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; std::vector<lldb::TypeSP> m_builtin_types; std::unique_ptr<llvm::pdb::IPDBSession> m_session_up; + std::unique_ptr<llvm::pdb::PDBSymbolExe> m_global_scope_up; uint32_t m_cached_compile_unit_count; std::unique_ptr<lldb_private::CompilerDeclContext> m_tu_decl_ctx_up; + + lldb_private::UniqueCStringMap<uint32_t> m_func_full_names; + lldb_private::UniqueCStringMap<uint32_t> m_func_base_names; + lldb_private::UniqueCStringMap<uint32_t> m_func_method_names; }; #endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index dbc1b9ee5470..64e2daf60ee5 100644 --- a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -63,9 +63,9 @@ uint32_t SymbolFileSymtab::CalculateAbilities() { const Symtab *symtab = m_obj_file->GetSymtab(); if (symtab) { //---------------------------------------------------------------------- - // The snippet of code below will get the indexes the module symbol - // table entries that are code, data, or function related (debug info), - // sort them by value (address) and dump the sorted symbols. + // The snippet of code below will get the indexes the module symbol table + // entries that are code, data, or function related (debug info), sort + // them by value (address) and dump the sorted symbols. //---------------------------------------------------------------------- if (symtab->AppendSymbolIndexesWithType(eSymbolTypeSourceFile, m_source_indexes)) { @@ -105,24 +105,21 @@ uint32_t SymbolFileSymtab::CalculateAbilities() { } uint32_t SymbolFileSymtab::GetNumCompileUnits() { - // If we don't have any source file symbols we will just have one compile unit - // for - // the entire object file + // If we don't have any source file symbols we will just have one compile + // unit for the entire object file if (m_source_indexes.empty()) return 0; // If we have any source file symbols we will logically organize the object - // symbols - // using these. + // symbols using these. return m_source_indexes.size(); } CompUnitSP SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx) { CompUnitSP cu_sp; - // If we don't have any source file symbols we will just have one compile unit - // for - // the entire object file + // If we don't have any source file symbols we will just have one compile + // unit for the entire object file if (idx < m_source_indexes.size()) { const Symbol *cu_symbol = m_obj_file->GetSymtab()->SymbolAtIndex(m_source_indexes[idx]); @@ -152,13 +149,12 @@ size_t SymbolFileSymtab::ParseCompileUnitFunctions(const SymbolContext &sc) { // // const uint32_t prefix_len = strlen(prefix); - // If we don't have any source file symbols we will just have one compile unit - // for - // the entire object file + // If we don't have any source file symbols we will just have one compile + // unit for the entire object file if (m_source_indexes.empty()) { - // The only time we will have a user ID of zero is when we don't have - // and source file symbols and we declare one compile unit for the - // entire object file + // The only time we will have a user ID of zero is when we don't have and + // source file symbols and we declare one compile unit for the entire + // object file if (!m_func_indexes.empty()) { } diff --git a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp index a25119684c28..d24510966878 100644 --- a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -57,9 +57,9 @@ const char *SymbolVendorELF::GetPluginDescriptionStatic() { //---------------------------------------------------------------------- // CreateInstance // -// Platforms can register a callback to use when creating symbol -// vendors to allow for complex debug information file setups, and to -// also allow for finding separate debug information files. +// Platforms can register a callback to use when creating symbol vendors to +// allow for complex debug information file setups, and to also allow for +// finding separate debug information files. //---------------------------------------------------------------------- SymbolVendor * SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp, @@ -112,11 +112,9 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp, module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), 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 have - // stripped the - // code sections, etc. + // This objfile is for debugging purposes. Sadly, ObjectFileELF won't + // be able to figure this out consistently as the symbol file may not + // have stripped the code sections, etc. dsym_objfile_sp->SetType(ObjectFile::eTypeDebugInfo); SymbolVendorELF *symbol_vendor = new SymbolVendorELF(module_sp); @@ -134,7 +132,7 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp, eSectionTypeDWARFDebugMacInfo, eSectionTypeDWARFDebugPubNames, eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges, eSectionTypeDWARFDebugStr, eSectionTypeDWARFDebugStrOffsets, - eSectionTypeELFSymbolTable, + eSectionTypeELFSymbolTable, eSectionTypeDWARFGNUDebugAltLink, }; for (size_t idx = 0; idx < sizeof(g_sections) / sizeof(g_sections[0]); ++idx) { diff --git a/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp index b3fb05e652d9..c69eb7fd51c7 100644 --- a/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp +++ b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp @@ -94,9 +94,9 @@ const char *SymbolVendorMacOSX::GetPluginDescriptionStatic() { //---------------------------------------------------------------------- // CreateInstance // -// Platforms can register a callback to use when creating symbol -// vendors to allow for complex debug information file setups, and to -// also allow for finding separate debug information files. +// Platforms can register a callback to use when creating symbol vendors to +// allow for complex debug information file setups, and to also allow for +// finding separate debug information files. //---------------------------------------------------------------------- SymbolVendor * SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, @@ -130,14 +130,14 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, "SymbolVendorMacOSX::CreateInstance (module = %s) locate dSYM", module_sp->GetFileSpec().GetPath().c_str()); - // First check to see if the module has a symbol file in mind already. - // If it does, then we MUST use that. + // First check to see if the module has a symbol file in mind already. If + // it does, then we MUST use that. FileSpec dsym_fspec(module_sp->GetSymbolFileFileSpec()); ObjectFileSP dsym_objfile_sp; if (!dsym_fspec) { - // No symbol file was specified in the module, lets try and find - // one ourselves. + // No symbol file was specified in the module, lets try and find one + // ourselves. FileSpec file_spec = obj_file->GetFileSpec(); if (!file_spec) file_spec = module_sp->GetFileSpec(); @@ -179,24 +179,8 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, std::string DBGBuildSourcePath; std::string DBGSourcePath; - plist.GetValueAsString("DBGBuildSourcePath", - DBGBuildSourcePath); - plist.GetValueAsString("DBGSourcePath", DBGSourcePath); - if (!DBGBuildSourcePath.empty() && - !DBGSourcePath.empty()) { - if (DBGSourcePath[0] == '~') { - FileSpec resolved_source_path(DBGSourcePath.c_str(), - true); - DBGSourcePath = resolved_source_path.GetPath(); - } - module_sp->GetSourceMappingList().Append( - ConstString(DBGBuildSourcePath), - ConstString(DBGSourcePath), true); - } - // DBGSourcePathRemapping is a dictionary in the plist - // with - // keys which are DBGBuildSourcePath file paths and + // with keys which are DBGBuildSourcePath file paths and // values which are DBGSourcePath file paths StructuredData::ObjectSP plist_sp = @@ -208,17 +192,14 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, ->GetValueForKey("DBGSourcePathRemapping") ->GetAsDictionary()) { - // In an early version of DBGSourcePathRemapping, the - // DBGSourcePath - // values were incorrect. If we have a newer style - // DBGSourcePathRemapping, there will be a DBGVersion - // key in the plist with version 2 or higher. + // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping. + // If DBGVersion 2, strip last two components of path remappings from + // entries to fix an issue with a specific set of + // DBGSourcePathRemapping entries that lldb worked + // with. + // If DBGVersion 3, trust & use the source path remappings as-is. // - // If this is an old style DBGSourcePathRemapping, - // ignore the - // value half of the key-value remappings and use reuse - // the original - // gloal DBGSourcePath string. + bool new_style_source_remapping_dictionary = false; bool do_truncate_remapping_names = false; std::string original_DBGSourcePath_value = @@ -268,10 +249,12 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, } module_sp->GetSourceMappingList().Append( key, ConstString(DBGSourcePath), true); - // With version 2 of DBGSourcePathRemapping, we can chop off the - // last two filename parts from the source remapping and get a - // more general source remapping that still works. Add this as - // another option in addition to the full source path remap. + // With version 2 of DBGSourcePathRemapping, we + // can chop off the last two filename parts + // from the source remapping and get a more + // general source remapping that still works. + // Add this as another option in addition to + // the full source path remap. if (do_truncate_remapping_names) { FileSpec build_path(key.AsCString(), false); FileSpec source_path(DBGSourcePath.c_str(), false); @@ -287,6 +270,24 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, return true; }); } + + // If we have a DBGBuildSourcePath + DBGSourcePath pair, + // append those to the source path remappings. + + plist.GetValueAsString("DBGBuildSourcePath", + DBGBuildSourcePath); + plist.GetValueAsString("DBGSourcePath", DBGSourcePath); + if (!DBGBuildSourcePath.empty() && + !DBGSourcePath.empty()) { + if (DBGSourcePath[0] == '~') { + FileSpec resolved_source_path(DBGSourcePath.c_str(), + true); + DBGSourcePath = resolved_source_path.GetPath(); + } + module_sp->GetSourceMappingList().Append( + ConstString(DBGBuildSourcePath), + ConstString(DBGSourcePath), true); + } } } } @@ -300,9 +301,9 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, } } - // Just create our symbol vendor using the current objfile as this is either - // an executable with no dSYM (that we could locate), an executable with - // a dSYM that has a UUID that doesn't match. + // Just create our symbol vendor using the current objfile as this is + // either an executable with no dSYM (that we could locate), an executable + // with a dSYM that has a UUID that doesn't match. symbol_vendor->AddSymbolFileRepresentation(obj_file->shared_from_this()); } return symbol_vendor; diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp index 3f0c7db676f3..007a59378fc5 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp @@ -119,20 +119,18 @@ void AppleGetItemInfoHandler::Detach() { } // Compile our __lldb_backtrace_recording_get_item_info() function (from the -// source above in g_get_item_info_function_code) if we don't find that function -// in the inferior -// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for -// testing.) +// source above in g_get_item_info_function_code) if we don't find that +// function in the inferior already with USE_BUILTIN_FUNCTION defined. (e.g. +// this would be the case for testing.) // -// Insert the __lldb_backtrace_recording_get_item_info into the inferior process -// if needed. +// Insert the __lldb_backtrace_recording_get_item_info into the inferior +// process if needed. // // Write the get_item_info_arglist into the inferior's memory space to prepare // for the call. // // Returns the address of the arguments written down in the inferior process, -// which can be used to -// make the function call. +// which can be used to make the function call. lldb::addr_t AppleGetItemInfoHandler::SetupGetItemInfoFunction( Thread &thread, ValueList &get_item_info_arglist) { @@ -146,7 +144,8 @@ lldb::addr_t AppleGetItemInfoHandler::SetupGetItemInfoFunction( { std::lock_guard<std::mutex> guard(m_get_item_info_function_mutex); - // First stage is to make the UtilityFunction to hold our injected function: + // First stage is to make the UtilityFunction to hold our injected + // function: if (!m_get_item_info_impl_code.get()) { if (g_get_item_info_function_code != NULL) { @@ -209,10 +208,9 @@ lldb::addr_t AppleGetItemInfoHandler::SetupGetItemInfoFunction( diagnostics.Clear(); // Now write down the argument values for this particular call. This looks - // like it might be a race condition - // if other threads were calling into here, but actually it isn't because we - // allocate a new args structure for - // this call by passing args_addr = LLDB_INVALID_ADDRESS... + // like it might be a race condition if other threads were calling into here, + // but actually it isn't because we allocate a new args structure for this + // call by passing args_addr = LLDB_INVALID_ADDRESS... if (!get_item_info_caller->WriteFunctionArguments( exe_ctx, args_addr, get_item_info_arglist, diagnostics)) { @@ -272,8 +270,7 @@ AppleGetItemInfoHandler::GetItemInfo(Thread &thread, uint64_t item, // uint64_t page_to_free_size) // Where the return_buffer argument points to a 24 byte region of memory - // already allocated by lldb in - // the inferior process. + // already allocated by lldb in the inferior process. CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp index e3d03a6f9484..0de32bf11416 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp @@ -121,11 +121,10 @@ void AppleGetPendingItemsHandler::Detach() { } } -// Compile our __lldb_backtrace_recording_get_pending_items() function (from the -// source above in g_get_pending_items_function_code) if we don't find that -// function in the inferior -// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for -// testing.) +// Compile our __lldb_backtrace_recording_get_pending_items() function (from +// the source above in g_get_pending_items_function_code) if we don't find that +// function in the inferior already with USE_BUILTIN_FUNCTION defined. (e.g. +// this would be the case for testing.) // // Insert the __lldb_backtrace_recording_get_pending_items into the inferior // process if needed. @@ -134,8 +133,7 @@ void AppleGetPendingItemsHandler::Detach() { // prepare for the call. // // Returns the address of the arguments written down in the inferior process, -// which can be used to -// make the function call. +// which can be used to make the function call. lldb::addr_t AppleGetPendingItemsHandler::SetupGetPendingItemsFunction( Thread &thread, ValueList &get_pending_items_arglist) { @@ -212,10 +210,9 @@ lldb::addr_t AppleGetPendingItemsHandler::SetupGetPendingItemsFunction( } // Now write down the argument values for this particular call. This looks - // like it might be a race condition - // if other threads were calling into here, but actually it isn't because we - // allocate a new args structure for - // this call by passing args_addr = LLDB_INVALID_ADDRESS... + // like it might be a race condition if other threads were calling into here, + // but actually it isn't because we allocate a new args structure for this + // call by passing args_addr = LLDB_INVALID_ADDRESS... if (!get_pending_items_caller->WriteFunctionArguments( exe_ctx, args_addr, get_pending_items_arglist, diagnostics)) { @@ -279,8 +276,7 @@ AppleGetPendingItemsHandler::GetPendingItems(Thread &thread, addr_t queue, // uint64_t page_to_free_size) // Where the return_buffer argument points to a 24 byte region of memory - // already allocated by lldb in - // the inferior process. + // already allocated by lldb in the inferior process. CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp index c1654eb62ccc..7855b3603a3a 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp @@ -118,9 +118,9 @@ void AppleGetQueuesHandler::Detach() { } // Construct a CompilerType for the structure that -// g_get_current_queues_function_code will return by value -// so we can extract the fields after performing the function call. -// i.e. we are getting this struct returned to us: +// g_get_current_queues_function_code will return by value so we can extract +// the fields after performing the function call. i.e. we are getting this +// struct returned to us: // // struct get_current_queues_return_values // { @@ -130,11 +130,9 @@ void AppleGetQueuesHandler::Detach() { // }; // Compile our __lldb_backtrace_recording_get_current_queues() function (from -// the -// source above in g_get_current_queues_function_code) if we don't find that -// function in the inferior -// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for -// testing.) +// the source above in g_get_current_queues_function_code) if we don't find +// that function in the inferior already with USE_BUILTIN_FUNCTION defined. +// (e.g. this would be the case for testing.) // // Insert the __lldb_backtrace_recording_get_current_queues into the inferior // process if needed. @@ -143,8 +141,7 @@ void AppleGetQueuesHandler::Detach() { // the call. // // Returns the address of the arguments written down in the inferior process, -// which can be used to -// make the function call. +// which can be used to make the function call. lldb::addr_t AppleGetQueuesHandler::SetupGetQueuesFunction(Thread &thread, @@ -217,10 +214,9 @@ AppleGetQueuesHandler::SetupGetQueuesFunction(Thread &thread, diagnostics.Clear(); // Now write down the argument values for this particular call. This looks - // like it might be a race condition - // if other threads were calling into here, but actually it isn't because we - // allocate a new args structure for - // this call by passing args_addr = LLDB_INVALID_ADDRESS... + // like it might be a race condition if other threads were calling into here, + // but actually it isn't because we allocate a new args structure for this + // call by passing args_addr = LLDB_INVALID_ADDRESS... if (!get_queues_caller->WriteFunctionArguments( exe_ctx, args_addr, get_queues_arglist, diagnostics)) { @@ -280,8 +276,7 @@ AppleGetQueuesHandler::GetCurrentQueues(Thread &thread, addr_t page_to_free, // uint64_t page_to_free_size); // Where the return_buffer argument points to a 24 byte region of memory - // already allocated by lldb in - // the inferior process. + // already allocated by lldb in the inferior process. CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index 8d83922af1e7..09ab6600a9f0 100644 --- a/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -128,11 +128,9 @@ void AppleGetThreadItemInfoHandler::Detach() { } // Compile our __lldb_backtrace_recording_get_thread_item_info() function (from -// the -// source above in g_get_thread_item_info_function_code) if we don't find that -// function in the inferior -// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for -// testing.) +// the source above in g_get_thread_item_info_function_code) if we don't find +// that function in the inferior already with USE_BUILTIN_FUNCTION defined. +// (e.g. this would be the case for testing.) // // Insert the __lldb_backtrace_recording_get_thread_item_info into the inferior // process if needed. @@ -141,8 +139,7 @@ void AppleGetThreadItemInfoHandler::Detach() { // prepare for the call. // // Returns the address of the arguments written down in the inferior process, -// which can be used to -// make the function call. +// which can be used to make the function call. lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction( Thread &thread, ValueList &get_thread_item_info_arglist) { @@ -221,10 +218,9 @@ lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction( diagnostics.Clear(); // Now write down the argument values for this particular call. This looks - // like it might be a race condition - // if other threads were calling into here, but actually it isn't because we - // allocate a new args structure for - // this call by passing args_addr = LLDB_INVALID_ADDRESS... + // like it might be a race condition if other threads were calling into here, + // but actually it isn't because we allocate a new args structure for this + // call by passing args_addr = LLDB_INVALID_ADDRESS... if (!get_thread_item_info_caller->WriteFunctionArguments( exe_ctx, args_addr, get_thread_item_info_arglist, diagnostics)) { @@ -266,8 +262,7 @@ AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, // Set up the arguments for a call to - // struct get_thread_item_info_return_values - // { + // struct get_thread_item_info_return_values { // uint64_t item_info_buffer_ptr; /* the address of the items buffer // from libBacktraceRecording */ // uint64_t item_info_buffer_size; /* the size of the items buffer from @@ -283,8 +278,7 @@ AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, // uint64_t page_to_free_size) // Where the return_buffer argument points to a 24 byte region of memory - // already allocated by lldb in - // the inferior process. + // already allocated by lldb in the inferior process. CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); diff --git a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index 1a538b236c15..4748d5e8622e 100644 --- a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -34,9 +34,9 @@ using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- -// Create an instance of this class. This function is filled into -// the plugin info class that gets handed out by the plugin factory and -// allows the lldb to instantiate an instance of this class. +// Create an instance of this class. This function is filled into the plugin +// info class that gets handed out by the plugin factory and allows the lldb to +// instantiate an instance of this class. //---------------------------------------------------------------------- SystemRuntime *SystemRuntimeMacOSX::CreateInstance(Process *process) { bool create = false; @@ -125,17 +125,15 @@ SystemRuntimeMacOSX::GetQueueNameFromThreadQAddress(addr_t dispatch_qaddr) { ReadLibdispatchOffsets(); if (m_libdispatch_offsets.IsValid()) { // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a - // thread - - // deref it to get the address of the dispatch_queue_t structure for this - // thread's - // queue. + // thread - deref it to get the address of the dispatch_queue_t structure + // for this thread's queue. Status error; addr_t dispatch_queue_addr = m_process->ReadPointerFromMemory(dispatch_qaddr, error); if (error.Success()) { if (m_libdispatch_offsets.dqo_version >= 4) { - // libdispatch versions 4+, pointer to dispatch name is in the - // queue structure. + // libdispatch versions 4+, pointer to dispatch name is in the queue + // structure. addr_t pointer_to_label_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_label; addr_t label_addr = @@ -248,10 +246,8 @@ SystemRuntimeMacOSX::GetQueueIDFromThreadQAddress(lldb::addr_t dispatch_qaddr) { ReadLibdispatchOffsets(); if (m_libdispatch_offsets.IsValid()) { // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a - // thread - - // deref it to get the address of the dispatch_queue_t structure for this - // thread's - // queue. + // thread - deref it to get the address of the dispatch_queue_t structure + // for this thread's queue. Status error; uint64_t dispatch_queue_addr = m_process->ReadPointerFromMemory(dispatch_qaddr, error); @@ -287,8 +283,8 @@ void SystemRuntimeMacOSX::ReadLibdispatchOffsetsAddress() { dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType( g_dispatch_queue_offsets_symbol_name, eSymbolTypeData); - // libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") and - // later + // 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)); module_sp = m_process->GetTarget().GetImages().FindFirstModule( @@ -320,8 +316,7 @@ void SystemRuntimeMacOSX::ReadLibdispatchOffsets() { lldb::offset_t data_offset = 0; // The struct LibdispatchOffsets is a series of uint16_t's - extract them - // all - // in one big go. + // all in one big go. data.GetU16(&data_offset, &m_libdispatch_offsets.dqo_version, sizeof(struct LibdispatchOffsets) / sizeof(uint16_t)); } @@ -368,8 +363,7 @@ void SystemRuntimeMacOSX::ReadLibpthreadOffsets() { lldb::offset_t data_offset = 0; // The struct LibpthreadOffsets is a series of uint16_t's - extract them - // all - // in one big go. + // all in one big go. data.GetU16(&data_offset, &m_libpthread_offsets.plo_version, sizeof(struct LibpthreadOffsets) / sizeof(uint16_t)); } @@ -407,10 +401,8 @@ void SystemRuntimeMacOSX::ReadLibdispatchTSDIndexes() { if (m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS) { // We don't need to check the version number right now, it will be at least 2, -// but -// keep this code around to fetch just the version # for the future where we -// need -// to fetch alternate versions of the struct. +// but keep this code around to fetch just the version # for the future where +// we need to fetch alternate versions of the struct. #if 0 uint16_t dti_version = 2; Address dti_struct_addr; @@ -473,12 +465,9 @@ ThreadSP SystemRuntimeMacOSX::GetExtendedBacktraceThread(ThreadSP real_thread, Status error; // real_thread is either an actual, live thread (in which case we need to - // call into - // libBacktraceRecording to find its originator) or it is an extended - // backtrace itself, - // in which case we get the token from it and call into - // libBacktraceRecording to find - // the originator of that token. + // call into libBacktraceRecording to find its originator) or it is an + // extended backtrace itself, in which case we get the token from it and + // call into libBacktraceRecording to find the originator of that token. if (real_thread->GetExtendedBacktraceToken() != LLDB_INVALID_ADDRESS) { originating_thread_sp = GetExtendedBacktraceFromItemRef( @@ -735,13 +724,11 @@ void SystemRuntimeMacOSX::PopulateQueueList( } // We either didn't have libBacktraceRecording (and need to create the queues - // list based on threads) - // or we did get the queues list from libBacktraceRecording but some special - // queues may not be - // included in its information. This is needed because libBacktraceRecording - // will only list queues with pending or running items by default - but the - // magic com.apple.main-thread - // queue on thread 1 is always around. + // list based on threads) or we did get the queues list from + // libBacktraceRecording but some special queues may not be included in its + // information. This is needed because libBacktraceRecording will only list + // queues with pending or running items by default - but the magic com.apple + // .main-thread queue on thread 1 is always around. for (ThreadSP thread_sp : m_process->Threads()) { if (thread_sp->GetAssociatedWithLibdispatchQueue() != eLazyBoolNo) { @@ -769,12 +756,10 @@ void SystemRuntimeMacOSX::PopulateQueueList( } // Returns either an array of introspection_dispatch_item_info_ref's for the -// pending items on -// a queue or an array introspection_dispatch_item_info_ref's and code addresses -// for the -// pending items on a queue. The information about each of these pending items -// then needs to -// be fetched individually by passing the ref to libBacktraceRecording. +// pending items on a queue or an array introspection_dispatch_item_info_ref's +// and code addresses for the pending items on a queue. The information about +// each of these pending items then needs to be fetched individually by passing +// the ref to libBacktraceRecording. SystemRuntimeMacOSX::PendingItemsForQueue SystemRuntimeMacOSX::GetPendingItemRefsForQueue(lldb::addr_t queue) { @@ -927,8 +912,8 @@ void SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR( offset_t offset = 0; uint64_t queues_read = 0; - // The information about the queues is stored in this format (v1): - // typedef struct introspection_dispatch_queue_info_s { + // The information about the queues is stored in this format (v1): typedef + // struct introspection_dispatch_queue_info_s { // uint32_t offset_to_next; // dispatch_queue_t queue; // uint64_t serialnum; // queue's serialnum in the process, as diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index f8aca4d1283b..54e182b30b6f 100644 --- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -12,6 +12,7 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/DumpDataExtractor.h" +#include "lldb/Core/DumpRegisterValue.h" #include "lldb/Core/FormatEntity.h" #include "lldb/Core/PluginManager.h" #include "lldb/Target/ExecutionContext.h" @@ -58,8 +59,8 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid() && m_inst_emulator_ap.get()) { - // The instruction emulation subclass setup the unwind plan for the - // first instruction. + // The instruction emulation subclass setup the unwind plan for the first + // instruction. m_inst_emulator_ap->CreateFunctionEntryUnwind(unwind_plan); // CreateFunctionEntryUnwind should have created the first row. If it @@ -90,9 +91,9 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( m_register_values.clear(); m_pushed_regs.clear(); - // Initialize the CFA with a known value. In the 32 bit case - // it will be 0x80000000, and in the 64 bit case 0x8000000000000000. - // We use the address byte size to be safe for any future address sizes + // Initialize the CFA with a known value. In the 32 bit case it will be + // 0x80000000, and in the 64 bit case 0x8000000000000000. We use the + // address byte size to be safe for any future address sizes m_initial_sp = (1ull << ((addr_byte_size * 8) - 1)); RegisterValue cfa_reg_value; cfa_reg_value.SetUInt(m_initial_sp, m_cfa_reg_info.byte_size); @@ -105,14 +106,12 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( Instruction *inst = inst_list.GetInstructionAtIndex(0).get(); const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress(); - // Map for storing the unwind plan row and the value of the registers at - // a given offset. - // When we see a forward branch we add a new entry to this map with the - // actual unwind plan - // row and register context for the target address of the branch as the - // current data have - // to be valid for the target address of the branch too if we are in the - // same function. + // Map for storing the unwind plan row and the value of the registers + // at a given offset. When we see a forward branch we add a new entry + // to this map with the actual unwind plan row and register context for + // the target address of the branch as the current data have to be + // valid for the target address of the branch too if we are in the same + // function. std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>> saved_unwind_states; @@ -128,15 +127,14 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( saved_unwind_states.insert({0, {last_row, m_register_values}}); // cache the pc register number (in whatever register numbering this - // UnwindPlan uses) for - // quick reference during instruction parsing. + // UnwindPlan uses) for quick reference during instruction parsing. RegisterInfo pc_reg_info; m_inst_emulator_ap->GetRegisterInfo( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info); // cache the return address register number (in whatever register - // numbering this UnwindPlan uses) for - // quick reference during instruction parsing. + // numbering this UnwindPlan uses) for quick reference during + // instruction parsing. RegisterInfo ra_reg_info; m_inst_emulator_ap->GetRegisterInfo( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info); @@ -160,12 +158,11 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( "Unwind row for the function entry missing"); --it; // Move it to the row corresponding to the current offset - // If the offset of m_curr_row don't match with the offset we see in - // saved_unwind_states - // then we have to update m_curr_row and m_register_values based on - // the saved values. It - // is happenning after we processed an epilogue and a return to - // caller instruction. + // If the offset of m_curr_row don't match with the offset we see + // in saved_unwind_states then we have to update m_curr_row and + // m_register_values based on the saved values. It is happening + // after we processed an epilogue and a return to caller + // instruction. if (it->second.first->GetOffset() != m_curr_row->GetOffset()) { UnwindPlan::Row *newrow = new UnwindPlan::Row; *newrow = *it->second.first; @@ -181,10 +178,9 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( if (m_inst_emulator_ap->GetInstructionCondition() != EmulateInstruction::UnconditionalCondition && saved_unwind_states.count(current_offset) == 0) { - // If we don't have a saved row for the current offset then save - // our - // current state because we will have to restore it after the - // conditional block. + // If we don't have a saved row for the current offset then + // save our current state because we will have to restore it + // after the conditional block. auto new_row = std::make_shared<UnwindPlan::Row>(*m_curr_row.get()); saved_unwind_states.insert( @@ -192,8 +188,8 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( } // If the last instruction was conditional with a different - // condition - // then the then current condition then restore the condition. + // condition then the then current condition then restore the + // condition. if (last_condition != EmulateInstruction::UnconditionalCondition) { const auto &saved_state = @@ -211,7 +207,7 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( replace_existing); } - // We are starting a new conditional block at the catual offset + // We are starting a new conditional block at the actual offset condition_block_start_offset = current_offset; } @@ -230,8 +226,7 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( eEmulateInstructionOptionIgnoreConditions); // If the current instruction is a branch forward then save the - // current CFI information - // for the offset where we are branching. + // current CFI information for the offset where we are branching. if (m_forward_branch_offset != 0 && range.ContainsFileAddress(inst->GetAddress().GetFileAddress() + m_forward_branch_offset)) { @@ -247,8 +242,8 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( // Were there any changes to the CFI while evaluating this // instruction? if (m_curr_row_modified) { - // Save the modified row if we don't already have a CFI row in the - // currennt address + // Save the modified row if we don't already have a CFI row in + // the current address if (saved_unwind_states.count( current_offset + inst->GetOpcode().GetByteSize()) == 0) { m_curr_row->SetOffset(current_offset + @@ -492,7 +487,7 @@ bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction, strm.Printf("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => " "synthetic_value = %i, value = ", reg_info->name, synthetic); - reg_value.Dump(&strm, reg_info, false, false, eFormatDefault); + DumpRegisterValue(reg_value, &strm, reg_info, false, false, eFormatDefault); log->PutString(strm.GetString()); } return true; @@ -518,7 +513,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister( strm.Printf( "UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", reg_info->name); - reg_value.Dump(&strm, reg_info, false, false, eFormatDefault); + DumpRegisterValue(reg_value, &strm, reg_info, false, false, eFormatDefault); strm.PutCString(", context = "); context.Dump(strm, instruction); log->PutString(strm.GetString()); diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp index b8dcd99a53e7..327d0b0e4f71 100644 --- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp +++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp @@ -86,12 +86,10 @@ bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite( LLDB_REGNUM_GENERIC_PC); // Does this UnwindPlan describe the prologue? I want to see that the CFA is - // set - // in terms of the stack pointer plus an offset, and I want to see that rip is - // retrieved at the CFA-wordsize. - // If there is no description of the prologue, don't try to augment this - // eh_frame - // unwinder code, fall back to assembly parsing instead. + // set in terms of the stack pointer plus an offset, and I want to see that + // rip is retrieved at the CFA-wordsize. If there is no description of the + // prologue, don't try to augment this eh_frame unwinder code, fall back to + // assembly parsing instead. if (first_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::isRegisterPlusOffset || @@ -110,14 +108,13 @@ bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite( return false; } - // It looks like the prologue is described. - // Is the epilogue described? If it is, no need to do any augmentation. + // It looks like the prologue is described. Is the epilogue described? If it + // is, no need to do any augmentation. if (first_row != last_row && first_row->GetOffset() != last_row->GetOffset()) { - // The first & last row have the same CFA register - // and the same CFA offset value - // and the CFA register is esp/rsp (the stack pointer). + // The first & last row have the same CFA register and the same CFA offset + // value and the CFA register is esp/rsp (the stack pointer). // We're checking that both of them have an unwind rule like "CFA=esp+4" or // CFA+rsp+8". @@ -128,8 +125,8 @@ bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite( last_row->GetCFAValue().GetRegisterNumber() && first_row->GetCFAValue().GetOffset() == last_row->GetCFAValue().GetOffset()) { - // Get the register locations for eip/rip from the first & last rows. - // Are they both CFA plus an offset? Is it the same offset? + // Get the register locations for eip/rip from the first & last rows. Are + // they both CFA plus an offset? Is it the same offset? UnwindPlan::Row::RegisterLocation last_row_pc_loc; if (last_row->GetRegisterInfo( @@ -139,12 +136,10 @@ bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite( first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset()) { // One last sanity check: Is the unwind rule for getting the caller - // pc value - // "deref the CFA-4" or "deref the CFA-8"? + // pc value "deref the CFA-4" or "deref the CFA-8"? // If so, we have an UnwindPlan that already describes the epilogue - // and we don't need - // to modify it at all. + // and we don't need to modify it at all. if (first_row_pc_loc.GetOffset() == -wordsize) { do_augment_unwindplan = false; diff --git a/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp index aa15063ac0dc..10a56980594f 100644 --- a/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp +++ b/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp @@ -246,8 +246,7 @@ void x86AssemblyInspectionEngine::Initialize( } // This function expects an x86 native register number (i.e. the bits stripped -// out of the -// actual instruction), not an lldb register number. +// out of the actual instruction), not an lldb register number. // // FIXME: This is ABI dependent, it shouldn't be hardcoded here. @@ -321,15 +320,14 @@ bool x86AssemblyInspectionEngine::push_imm_pattern_p() { // pushl imm8(%esp) // -// e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)' -// (same byte pattern for 'pushq 0x20(%rsp)' in an x86_64 program) +// e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)' (same byte pattern for 'pushq +// 0x20(%rsp)' in an x86_64 program) // -// 0xff (with opcode bits '6' in next byte, PUSH r/m32) -// 0x74 (ModR/M byte with three bits used to specify the opcode) +// 0xff (with opcode bits '6' in next byte, PUSH r/m32) 0x74 (ModR/M byte with +// three bits used to specify the opcode) // mod == b01, opcode == b110, R/M == b100 // "+disp8" -// 0x24 (SIB byte - scaled index = 0, r32 == esp) -// 0x20 imm8 value +// 0x24 (SIB byte - scaled index = 0, r32 == esp) 0x20 imm8 value bool x86AssemblyInspectionEngine::push_extended_pattern_p() { if (*m_cur_insn == 0xff) { @@ -337,9 +335,8 @@ bool x86AssemblyInspectionEngine::push_extended_pattern_p() { uint8_t opcode = (*(m_cur_insn + 1) >> 3) & 7; if (opcode == 6) { // I'm only looking for 0xff /6 here - I - // don't really care what value is being pushed, - // just that we're pushing a 32/64 bit value on - // to the stack is enough. + // don't really care what value is being pushed, just that we're pushing + // a 32/64 bit value on to the stack is enough. return true; } } @@ -377,8 +374,8 @@ bool x86AssemblyInspectionEngine::push_reg_p(int ®no) { return false; } -// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] -// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5] +// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] movl %esp, %ebp [0x8b +// 0xec] or [0x89 0xe5] bool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() { uint8_t *p = m_cur_insn; if (m_wordsize == 8 && *p == 0x48) @@ -529,16 +526,16 @@ bool x86AssemblyInspectionEngine::call_next_insn_pattern_p() { (*(p + 3) == 0x0) && (*(p + 4) == 0x0); } -// Look for an instruction sequence storing a nonvolatile register -// on to the stack frame. +// Look for an instruction sequence storing a nonvolatile register on to the +// stack frame. // movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0] // movl %eax, -0xc(%ebp) [0x89 0x45 0xf4] -// The offset value returned in rbp_offset will be positive -- -// but it must be subtraced from the frame base register to get -// the actual location. The positive value returned for the offset -// is a convention used elsewhere for CFA offsets et al. +// The offset value returned in rbp_offset will be positive -- but it must be +// subtraced from the frame base register to get the actual location. The +// positive value returned for the offset is a convention used elsewhere for +// CFA offsets et al. bool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p( int ®no, int &rbp_offset) { @@ -550,8 +547,8 @@ bool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p( src_reg_prefix_bit = REX_W_SRCREG(*p) << 3; target_reg_prefix_bit = REX_W_DSTREG(*p) << 3; if (target_reg_prefix_bit == 1) { - // rbp/ebp don't need a prefix bit - we know this isn't the - // reg we care about. + // rbp/ebp don't need a prefix bit - we know this isn't the reg we care + // about. return false; } p++; @@ -671,18 +668,16 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( *newrow = *row.get(); row.reset(newrow); - // Track which registers have been saved so far in the prologue. - // If we see another push of that register, it's not part of the prologue. - // The register numbers used here are the machine register #'s - // (i386_register_numbers, x86_64_register_numbers). + // Track which registers have been saved so far in the prologue. If we see + // another push of that register, it's not part of the prologue. The register + // numbers used here are the machine register #'s (i386_register_numbers, + // x86_64_register_numbers). std::vector<bool> saved_registers(32, false); // Once the prologue has completed we'll save a copy of the unwind - // instructions - // If there is an epilogue in the middle of the function, after that epilogue - // we'll reinstate - // the unwind setup -- we assume that some code path jumps over the - // mid-function epilogue + // instructions If there is an epilogue in the middle of the function, after + // that epilogue we'll reinstate the unwind setup -- we assume that some code + // path jumps over the mid-function epilogue UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the @@ -723,9 +718,8 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( } // 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 -- + // 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 -- // normally the saved pc value is already on the stack by the time the // function starts executing. else if (push_0_pattern_p()) { @@ -733,9 +727,9 @@ 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 in - // terms of the stack pointer, - // we need to add a new row of instructions. + // the PUSH instruction has moved the stack pointer - if the CFA 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); row_updated = true; @@ -772,8 +766,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( } // the POP instruction has moved the stack pointer - if the CFA is set in - // terms of the stack pointer, - // we need to add a new row of instructions. + // 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); @@ -790,13 +783,13 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( } } - // The LEAVE instruction moves the value from rbp into rsp and pops - // a value off the stack into rbp (restoring the caller's rbp value). - // It is the opposite of ENTER, or 'push rbp, mov rsp rbp'. + // The LEAVE instruction moves the value from rbp into rsp and pops a value + // 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. + // 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); @@ -822,12 +815,11 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( 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 - 96. + // 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 - + // 96. regloc.SetAtCFAPlusOffset( -(stack_offset + row->GetCFAValue().GetOffset())); @@ -879,8 +871,8 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( } else if (ret_pattern_p() && prologue_completed_row.get()) { - // Reinstate the saved prologue setup for any instructions - // that come after the ret instruction + // Reinstate the saved prologue setup for any instructions that come + // after the ret instruction UnwindPlan::Row *newrow = new UnwindPlan::Row; *newrow = *prologue_completed_row.get(); @@ -960,16 +952,15 @@ bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite( if (!addr_start.IsValid()) return false; - // We either need a live RegisterContext, or we need the UnwindPlan to already - // be in the lldb register numbering scheme. + // We either need a live RegisterContext, or we need the UnwindPlan to + // already be in the lldb register numbering scheme. if (reg_ctx.get() == nullptr && unwind_plan.GetRegisterKind() != eRegisterKindLLDB) return false; // Is original unwind_plan valid? - // unwind_plan should have at least one row which is ABI-default (CFA register - // is sp), - // and another row in mid-function. + // unwind_plan should have at least one row which is ABI-default (CFA + // register is sp), and another row in mid-function. if (unwind_plan.GetRowCount() < 2) return false; @@ -994,11 +985,9 @@ bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite( UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row)); m_cur_insn = data + offset; - // After a mid-function epilogue we will need to re-insert the original unwind - // rules - // so unwinds work for the remainder of the function. These aren't common - // with clang/gcc - // on x86 but it is possible. + // After a mid-function epilogue we will need to re-insert the original + // unwind rules so unwinds work for the remainder of the function. These + // aren't common with clang/gcc on x86 but it is possible. bool reinstate_unwind_state = false; while (offset < size) { @@ -1015,8 +1004,7 @@ bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite( offset += insn_len; m_cur_insn = data + offset; - // offset is pointing beyond the bounds of the - // function; stop looping. + // offset is pointing beyond the bounds of the function; stop looping. if (offset >= size) continue; @@ -1044,9 +1032,8 @@ bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite( } if (row_id == 0) { - // If we are here, compiler didn't generate CFI for prologue. - // This won't happen to GCC or clang. - // In this case, bail out directly. + // If we are here, compiler didn't generate CFI for prologue. This won't + // happen to GCC or clang. In this case, bail out directly. return false; } @@ -1086,10 +1073,9 @@ bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite( } if (pop_reg_p(regno)) { // Technically, this might be a nonvolatile register recover in - // epilogue. - // We should reset RegisterInfo for the register. - // But in practice, previous rule for the register is still valid... - // So we ignore this case. + // epilogue. We should reset RegisterInfo for the register. But in + // practice, previous rule for the register is still valid... So we + // ignore this case. row->SetOffset(offset); row->GetCFAValue().IncOffset(-m_wordsize); |