diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h --- a/lldb/include/lldb/Expression/DWARFExpression.h +++ b/lldb/include/lldb/Expression/DWARFExpression.h @@ -85,8 +85,8 @@ /// Search for a load address in the location list /// - /// \param[in] process - /// The process to use when resolving the load address + /// \param[in] func_load_addr + /// The actual address of the function containing this location list. /// /// \param[in] addr /// The address to resolve @@ -98,7 +98,7 @@ // LocationListContainsLoadAddress (Process* process, const Address &addr) // const; // - bool LocationListContainsAddress(lldb::addr_t loclist_base_addr, + bool LocationListContainsAddress(lldb::addr_t func_load_addr, lldb::addr_t addr) const; /// If a location is not a location list, return true if the location @@ -138,13 +138,15 @@ /// Tells the expression that it refers to a location list. /// - /// \param[in] slide - /// This value should be a slide that is applied to any values - /// in the location list data so the values become zero based - /// offsets into the object that owns the location list. We need - /// to make location lists relative to the objects that own them - /// so we can relink addresses on the fly. - void SetLocationListSlide(lldb::addr_t slide); + /// \param[in] cu_file_addr + /// The base address to use for interpreting relative location list + /// entries. + /// \param[in] func_file_addr + /// The file address of the function containing this location list. This + /// address will be used to relocate the location list on the fly (in + /// conjuction with the func_load_addr arguments). + void SetLocationListAddresses(lldb::addr_t cu_file_addr, + lldb::addr_t func_file_addr); /// Return the call-frame-info style register kind int GetRegisterKind(); @@ -158,8 +160,7 @@ /// Wrapper for the static evaluate function that accepts an /// ExecutionContextScope instead of an ExecutionContext and uses member /// variables to populate many operands - bool Evaluate(ExecutionContextScope *exe_scope, - lldb::addr_t loclist_base_load_addr, + bool Evaluate(ExecutionContextScope *exe_scope, lldb::addr_t func_load_addr, const Value *initial_value_ptr, const Value *object_address_ptr, Value &result, Status *error_ptr) const; @@ -222,8 +223,8 @@ } bool DumpLocationForAddress(Stream *s, lldb::DescriptionLevel level, - lldb::addr_t loclist_base_load_addr, - lldb::addr_t address, ABI *abi); + lldb::addr_t func_load_addr, lldb::addr_t address, + ABI *abi); static bool PrintDWARFExpression(Stream &s, const DataExtractor &data, int address_size, int dwarf_ref_size, @@ -256,7 +257,7 @@ void DumpLocation(Stream *s, lldb::offset_t offset, lldb::offset_t length, lldb::DescriptionLevel level, ABI *abi) const; - bool GetLocation(lldb::addr_t base_addr, lldb::addr_t pc, + bool GetLocation(lldb::addr_t func_load_addr, lldb::addr_t pc, lldb::offset_t &offset, lldb::offset_t &len); static bool AddressRangeForLocationListEntry( @@ -266,6 +267,9 @@ bool GetOpAndEndOffsets(StackFrame &frame, lldb::offset_t &op_offset, lldb::offset_t &end_offset); + void RelocateLowHighPC(lldb::addr_t base_address, lldb::addr_t func_load_addr, + lldb::addr_t &low_pc, lldb::addr_t &high_pc) const; + /// Module which defined this expression. lldb::ModuleWP m_module_wp; @@ -280,10 +284,11 @@ /// One of the defines that starts with LLDB_REGKIND_ lldb::RegisterKind m_reg_kind; - /// A value used to slide the location list offsets so that m_c they are - /// relative to the object that owns the location list (the function for - /// frame base and variable location lists) - lldb::addr_t m_loclist_slide; + struct LoclistAddresses { + lldb::addr_t cu_file_addr; + lldb::addr_t func_file_addr; + }; + llvm::Optional m_loclist_addresses; }; } // namespace lldb_private diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -56,13 +56,13 @@ // DWARFExpression constructor DWARFExpression::DWARFExpression() : m_module_wp(), m_data(), m_dwarf_cu(nullptr), - m_reg_kind(eRegisterKindDWARF), m_loclist_slide(LLDB_INVALID_ADDRESS) {} + m_reg_kind(eRegisterKindDWARF) {} DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp, const DataExtractor &data, const DWARFUnit *dwarf_cu) : m_module_wp(), m_data(data), m_dwarf_cu(dwarf_cu), - m_reg_kind(eRegisterKindDWARF), m_loclist_slide(LLDB_INVALID_ADDRESS) { + m_reg_kind(eRegisterKindDWARF) { if (module_sp) m_module_wp = module_sp; } @@ -94,8 +94,9 @@ nullptr); } -void DWARFExpression::SetLocationListSlide(addr_t slide) { - m_loclist_slide = slide; +void DWARFExpression::SetLocationListAddresses(addr_t cu_file_addr, + addr_t func_file_addr) { + m_loclist_addresses = LoclistAddresses{cu_file_addr, func_file_addr}; } int DWARFExpression::GetRegisterKind() { return m_reg_kind; } @@ -105,7 +106,7 @@ } bool DWARFExpression::IsLocationList() const { - return m_loclist_slide != LLDB_INVALID_ADDRESS; + return bool(m_loclist_addresses); } void DWARFExpression::GetDescription(Stream *s, lldb::DescriptionLevel level, @@ -614,46 +615,43 @@ return true; } -bool DWARFExpression::LocationListContainsAddress( - lldb::addr_t loclist_base_addr, lldb::addr_t addr) const { - if (addr == LLDB_INVALID_ADDRESS) +bool DWARFExpression::LocationListContainsAddress(addr_t func_load_addr, + lldb::addr_t addr) const { + if (func_load_addr == LLDB_INVALID_ADDRESS || addr == LLDB_INVALID_ADDRESS) return false; - if (IsLocationList()) { - lldb::offset_t offset = 0; - - if (loclist_base_addr == LLDB_INVALID_ADDRESS) - return false; + if (!IsLocationList()) + return false; - while (m_data.ValidOffset(offset)) { - // We need to figure out what the value is for the location. - addr_t lo_pc = LLDB_INVALID_ADDRESS; - addr_t hi_pc = LLDB_INVALID_ADDRESS; - if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, lo_pc, - hi_pc)) - break; + lldb::offset_t offset = 0; + lldb::addr_t base_address = m_loclist_addresses->cu_file_addr; + while (m_data.ValidOffset(offset)) { + // We need to figure out what the value is for the location. + addr_t lo_pc = LLDB_INVALID_ADDRESS; + addr_t hi_pc = LLDB_INVALID_ADDRESS; + if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, lo_pc, + hi_pc)) + break; - if (lo_pc == 0 && hi_pc == 0) - break; + if (lo_pc == 0 && hi_pc == 0) + break; - if ((m_data.GetAddressByteSize() == 4 && (lo_pc == UINT32_MAX)) || - (m_data.GetAddressByteSize() == 8 && (lo_pc == UINT64_MAX))) { - loclist_base_addr = hi_pc + m_loclist_slide; - continue; - } - lo_pc += loclist_base_addr - m_loclist_slide; - hi_pc += loclist_base_addr - m_loclist_slide; + if ((m_data.GetAddressByteSize() == 4 && (lo_pc == UINT32_MAX)) || + (m_data.GetAddressByteSize() == 8 && (lo_pc == UINT64_MAX))) { + base_address = hi_pc; + continue; + } + RelocateLowHighPC(base_address, func_load_addr, lo_pc, hi_pc); - if (lo_pc <= addr && addr < hi_pc) - return true; + if (lo_pc <= addr && addr < hi_pc) + return true; - offset += m_data.GetU16(&offset); - } + offset += m_data.GetU16(&offset); } return false; } -bool DWARFExpression::GetLocation(addr_t base_addr, addr_t pc, +bool DWARFExpression::GetLocation(addr_t func_load_addr, addr_t pc, lldb::offset_t &offset, lldb::offset_t &length) { offset = 0; @@ -662,9 +660,8 @@ return true; } - if (base_addr != LLDB_INVALID_ADDRESS && pc != LLDB_INVALID_ADDRESS) { - addr_t curr_base_addr = base_addr; - + if (func_load_addr != LLDB_INVALID_ADDRESS && pc != LLDB_INVALID_ADDRESS) { + addr_t base_address = m_loclist_addresses->cu_file_addr; while (m_data.ValidOffset(offset)) { // We need to figure out what the value is for the location. addr_t lo_pc = LLDB_INVALID_ADDRESS; @@ -678,13 +675,11 @@ if ((m_data.GetAddressByteSize() == 4 && (lo_pc == UINT32_MAX)) || (m_data.GetAddressByteSize() == 8 && (lo_pc == UINT64_MAX))) { - curr_base_addr = hi_pc + m_loclist_slide; + base_address = hi_pc; continue; } - lo_pc += curr_base_addr - m_loclist_slide; - hi_pc += curr_base_addr - m_loclist_slide; - + RelocateLowHighPC(base_address, func_load_addr, lo_pc, hi_pc); length = m_data.GetU16(&offset); if (length > 0 && lo_pc <= pc && pc < hi_pc) @@ -700,12 +695,12 @@ bool DWARFExpression::DumpLocationForAddress(Stream *s, lldb::DescriptionLevel level, - addr_t base_addr, addr_t address, - ABI *abi) { + addr_t func_load_addr, + addr_t address, ABI *abi) { lldb::offset_t offset = 0; lldb::offset_t length = 0; - if (GetLocation(base_addr, address, offset, length)) { + if (GetLocation(func_load_addr, address, offset, length)) { if (length > 0) { DumpLocation(s, offset, length, level, abi); return true; @@ -936,7 +931,7 @@ bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx, RegisterContext *reg_ctx, - lldb::addr_t loclist_base_load_addr, + lldb::addr_t func_load_addr, const Value *initial_value_ptr, const Value *object_address_ptr, Value &result, Status *error_ptr) const { @@ -958,15 +953,14 @@ pc = reg_ctx_sp->GetPC(); } - if (loclist_base_load_addr != LLDB_INVALID_ADDRESS) { + if (func_load_addr != LLDB_INVALID_ADDRESS) { if (pc == LLDB_INVALID_ADDRESS) { if (error_ptr) error_ptr->SetErrorString("Invalid PC in frame."); return false; } - addr_t curr_loclist_base_load_addr = loclist_base_load_addr; - + addr_t base_address = m_loclist_addresses->cu_file_addr; while (m_data.ValidOffset(offset)) { // We need to figure out what the value is for the location. addr_t lo_pc = LLDB_INVALID_ADDRESS; @@ -982,12 +976,11 @@ (lo_pc == UINT32_MAX)) || (m_data.GetAddressByteSize() == 8 && (lo_pc == UINT64_MAX))) { - curr_loclist_base_load_addr = hi_pc + m_loclist_slide; + base_address = hi_pc; continue; } - lo_pc += curr_loclist_base_load_addr - m_loclist_slide; - hi_pc += curr_loclist_base_load_addr - m_loclist_slide; + RelocateLowHighPC(base_address, func_load_addr, lo_pc, hi_pc); uint16_t length = m_data.GetU16(&offset); if (length > 0 && lo_pc <= pc && pc < hi_pc) { @@ -2969,6 +2962,20 @@ return true; } +void DWARFExpression::RelocateLowHighPC(addr_t base_address, + addr_t func_load_addr, addr_t &low_pc, + addr_t &high_pc) const { + // How this works: + // base_address is the current base address, as known in the file. low_pc and + // high_pc are relative to that. First, we relocate the base address by + // applying the load bias (the difference between an address in the file and + // the actual address in memory). Then we relocate low_pc and high_pc based on + // that. + base_address += func_load_addr - m_loclist_addresses->func_file_addr; + low_pc += base_address; + high_pc += base_address; +} + bool DWARFExpression::MatchesOperand(StackFrame &frame, const Instruction::Operand &operand) { using namespace OperandMatchers; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -350,8 +350,8 @@ *frame_base = DWARFExpression(module, data, cu); if (lo_pc != LLDB_INVALID_ADDRESS) { assert(lo_pc >= cu->GetBaseAddress()); - frame_base->SetLocationListSlide(lo_pc - - cu->GetBaseAddress()); + frame_base->SetLocationListAddresses(cu->GetBaseAddress(), + lo_pc); } else { set_frame_base_loclist_addr = true; } @@ -379,7 +379,7 @@ if (set_frame_base_loclist_addr) { dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0); assert(lowest_range_pc >= cu->GetBaseAddress()); - frame_base->SetLocationListSlide(lowest_range_pc - cu->GetBaseAddress()); + frame_base->SetLocationListAddresses(cu->GetBaseAddress(), lowest_range_pc); } if (ranges.IsEmpty() || name == nullptr || mangled == nullptr) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3370,9 +3370,9 @@ data = DataExtractor(data, offset, data.GetByteSize() - offset); location = DWARFExpression(module, data, die.GetCU()); assert(func_low_pc != LLDB_INVALID_ADDRESS); - location.SetLocationListSlide( - func_low_pc - - attributes.CompileUnitAtIndex(i)->GetBaseAddress()); + location.SetLocationListAddresses( + attributes.CompileUnitAtIndex(i)->GetBaseAddress(), + func_low_pc); } } } break; diff --git a/lldb/test/Shell/SymbolFile/DWARF/Inputs/debug_loc-aslr.yaml b/lldb/test/Shell/SymbolFile/DWARF/Inputs/debug_loc-aslr.yaml new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/Inputs/debug_loc-aslr.yaml @@ -0,0 +1,30 @@ +--- !minidump +Streams: + - Type: ThreadList + Threads: + - Thread Id: 0x00003E81 + Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B001000000000006CAE000000006B7FC05A0000C81D415A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A2BF9E5A6B7F0000000000000000000000000000000000008850C14BFD7F00009850C14BFD7F00000100000000000000B04AC14BFD7F0000000000000000000060812D01000000000800000000000000B065E05A6B7F00008004400000000000E050C14BFD7F00000000000000000000000000000000000001004700000000007F03FFFF0000FFFFFFFFFFFF000000000000000000000000801F00006B7F00000400000000000000B84CC14BFD7F0000304D405A6B7F0000C84DC14BFD7F0000C0AA405A6B7F00004F033D0000000000B84DC14BFD7F0000E84DC14BFD7F0000000000000000000000000000000000000070E05A6B7F000078629E5A6B7F0000C81D415A6B7F0000804F9E5A6B7F00000000000001000000E603000001000000E093115A6B7F0000804EC14BFD7F0000584EC14BFD7F000099ADC05A6B7F00000100000000000000AAAAD77D0000000002000000000000000800000000000000B065E05A6B7F0000E6B7C05A6B7F0000010000006B7F0000884DC14BFD7F0000106F7C5A6B7F0000984EC14BFD7F0000488B7C5A6B7F0000C4A71CB90000000001000000000000000800000000000000B065E05A6B7F000048B6C05A6B7F0000702AE25A6B7F0000D84DC14BFD7F000030489E5A6B7F0000E84EC14BFD7F0000E05E9E5A6B7F00000991F0460000000001000000000000000800000000000000B065E05A6B7F000048B6C05A6B7F00000100000000000000284EC14BFD7F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + Stack: + Start of Memory Range: 0x00007FFCEB34A000 + Content: DEAD + - Type: SystemInfo + Processor Arch: AMD64 + Processor Level: 6 + Processor Revision: 15876 + Number of Processors: 40 + Platform ID: Linux + CSD Version: 'Linux 3.13.0-91-generic' + CPU: + Vendor ID: GenuineIntel + Version Info: 0x00000000 + Feature Info: 0x00000000 + - Type: LinuxProcStatus + Text: | + Name: linux-x86_64 + State: t (tracing stop) + Tgid: 29917 + Ngid: 0 + Pid: 29917 + PPid: 29370 + +... diff --git a/lldb/test/Shell/SymbolFile/DWARF/debug_loc-aslr.s b/lldb/test/Shell/SymbolFile/DWARF/debug_loc-aslr.s new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/debug_loc-aslr.s @@ -0,0 +1,129 @@ +# This test checks the handling of location lists in the case when the module is +# not loaded at the address at which it was linked (as happens with ASLR for +# instance). + +# REQUIRES: x86 + +# RUN: yaml2obj %S/Inputs/debug_loc-aslr.yaml >%t.dmp +# RUN: llvm-mc --triple=x86_64-pc-linux --filetype=obj %s >%t.o +# RUN: %lldb -c %t.dmp -o "image add %t.o" \ +# RUN: -o "image load --file %t.o --slide 0x470000" \ +# RUN: -o "thread info" -o "frame variable" -o exit | FileCheck %s + +# CHECK: thread #1: tid = 16001, 0x0000000000470001 {{.*}}`_start +# CHECK: (int) x = 47 +# CHECK: (int) y = 74 + + .text + .globl _start +_start: + nop + retq +.Lstart_end: + + .section .debug_loc,"",@progbits +# This location list implicitly uses the base address of the compile unit. +.Ldebug_loc0: + .quad _start-_start + .quad .Lstart_end-_start + .short 3 # Loc expr size + .byte 8 # DW_OP_const1u + .byte 47 + .byte 159 # DW_OP_stack_value + .quad 0 + .quad 0 + +# This is an equivalent location list to the first one, but here the base +# address is set explicitly. +.Ldebug_loc1: + .quad -1 + .quad _start + .quad _start-_start + .quad .Lstart_end-_start + .short 3 # Loc expr size + .byte 8 # DW_OP_const1u + .byte 74 + .byte 159 # DW_OP_stack_value + .quad 0 + .quad 0 + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 8 # DW_FORM_string + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 23 # DW_FORM_sec_offset + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x6a DW_TAG_compile_unit + .asciz "Hand-written DWARF" # DW_AT_producer + .short 12 # DW_AT_language + .quad _start # DW_AT_low_pc + .long .Lstart_end-_start # DW_AT_high_pc + .byte 2 # Abbrev [2] 0x2a:0x43 DW_TAG_subprogram + .quad _start # DW_AT_low_pc + .long .Lstart_end-_start # DW_AT_high_pc + .asciz "_start" # DW_AT_name + .byte 4 # Abbrev [4] 0x52:0xf DW_TAG_variable + .long .Ldebug_loc0 # DW_AT_location + .asciz "x" # DW_AT_name + .long .Lint # DW_AT_type + .byte 4 # Abbrev [4] 0x52:0xf DW_TAG_variable + .long .Ldebug_loc1 # DW_AT_location + .asciz "y" # DW_AT_name + .long .Lint # DW_AT_type + .byte 0 # End Of Children Mark +.Lint: + .byte 6 # Abbrev [6] 0x6d:0x7 DW_TAG_base_type + .asciz "int" # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: