/// 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
// 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
/// 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();
/// 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;
}
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,
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(
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;
/// 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<LoclistAddresses> m_loclist_addresses;
};
} // namespace lldb_private
// 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;
}
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; }
}
bool DWARFExpression::IsLocationList() const {
- return m_loclist_slide != LLDB_INVALID_ADDRESS;
+ return bool(m_loclist_addresses);
}
void DWARFExpression::GetDescription(Stream *s, lldb::DescriptionLevel level,
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;
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;
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)
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;
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 {
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;
(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) {
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;
*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;
}
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) {
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;
--- /dev/null
+--- !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
+
+...
--- /dev/null
+# 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: