1*0b57cec5SDimitry Andric //===-- DWARFDebugRanges.cpp ----------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric
9*0b57cec5SDimitry Andric #include "DWARFDebugRanges.h"
10*0b57cec5SDimitry Andric #include "DWARFUnit.h"
11*0b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
12*0b57cec5SDimitry Andric
13*0b57cec5SDimitry Andric using namespace lldb_private;
14*0b57cec5SDimitry Andric
GetBaseAddressMarker(uint32_t addr_size)15*0b57cec5SDimitry Andric static dw_addr_t GetBaseAddressMarker(uint32_t addr_size) {
16*0b57cec5SDimitry Andric switch(addr_size) {
17*0b57cec5SDimitry Andric case 2:
18*0b57cec5SDimitry Andric return 0xffff;
19*0b57cec5SDimitry Andric case 4:
20*0b57cec5SDimitry Andric return 0xffffffff;
21*0b57cec5SDimitry Andric case 8:
22*0b57cec5SDimitry Andric return 0xffffffffffffffff;
23*0b57cec5SDimitry Andric }
24*0b57cec5SDimitry Andric llvm_unreachable("GetBaseAddressMarker unsupported address size.");
25*0b57cec5SDimitry Andric }
26*0b57cec5SDimitry Andric
DWARFDebugRanges()27*0b57cec5SDimitry Andric DWARFDebugRanges::DWARFDebugRanges() : m_range_map() {}
28*0b57cec5SDimitry Andric
Extract(DWARFContext & context)29*0b57cec5SDimitry Andric void DWARFDebugRanges::Extract(DWARFContext &context) {
30*0b57cec5SDimitry Andric DWARFRangeList range_list;
31*0b57cec5SDimitry Andric lldb::offset_t offset = 0;
32*0b57cec5SDimitry Andric dw_offset_t debug_ranges_offset = offset;
33*0b57cec5SDimitry Andric while (Extract(context, &offset, range_list)) {
34*0b57cec5SDimitry Andric range_list.Sort();
35*0b57cec5SDimitry Andric m_range_map[debug_ranges_offset] = range_list;
36*0b57cec5SDimitry Andric debug_ranges_offset = offset;
37*0b57cec5SDimitry Andric }
38*0b57cec5SDimitry Andric }
39*0b57cec5SDimitry Andric
Extract(DWARFContext & context,lldb::offset_t * offset_ptr,DWARFRangeList & range_list)40*0b57cec5SDimitry Andric bool DWARFDebugRanges::Extract(DWARFContext &context,
41*0b57cec5SDimitry Andric lldb::offset_t *offset_ptr,
42*0b57cec5SDimitry Andric DWARFRangeList &range_list) {
43*0b57cec5SDimitry Andric range_list.Clear();
44*0b57cec5SDimitry Andric
45*0b57cec5SDimitry Andric lldb::offset_t range_offset = *offset_ptr;
46*0b57cec5SDimitry Andric const DWARFDataExtractor &debug_ranges_data = context.getOrLoadRangesData();
47*0b57cec5SDimitry Andric uint32_t addr_size = debug_ranges_data.GetAddressByteSize();
48*0b57cec5SDimitry Andric dw_addr_t base_addr = 0;
49*0b57cec5SDimitry Andric dw_addr_t base_addr_marker = GetBaseAddressMarker(addr_size);
50*0b57cec5SDimitry Andric
51*0b57cec5SDimitry Andric while (
52*0b57cec5SDimitry Andric debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
53*0b57cec5SDimitry Andric dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
54*0b57cec5SDimitry Andric dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
55*0b57cec5SDimitry Andric
56*0b57cec5SDimitry Andric if (!begin && !end) {
57*0b57cec5SDimitry Andric // End of range list
58*0b57cec5SDimitry Andric break;
59*0b57cec5SDimitry Andric }
60*0b57cec5SDimitry Andric
61*0b57cec5SDimitry Andric if (begin == base_addr_marker) {
62*0b57cec5SDimitry Andric base_addr = end;
63*0b57cec5SDimitry Andric continue;
64*0b57cec5SDimitry Andric }
65*0b57cec5SDimitry Andric
66*0b57cec5SDimitry Andric // Filter out empty ranges
67*0b57cec5SDimitry Andric if (begin < end)
68*0b57cec5SDimitry Andric range_list.Append(DWARFRangeList::Entry(begin + base_addr, end - begin));
69*0b57cec5SDimitry Andric }
70*0b57cec5SDimitry Andric
71*0b57cec5SDimitry Andric // Make sure we consumed at least something
72*0b57cec5SDimitry Andric return range_offset != *offset_ptr;
73*0b57cec5SDimitry Andric }
74*0b57cec5SDimitry Andric
Dump(Stream & s,const DWARFDataExtractor & debug_ranges_data,lldb::offset_t * offset_ptr,dw_addr_t cu_base_addr)75*0b57cec5SDimitry Andric void DWARFDebugRanges::Dump(Stream &s,
76*0b57cec5SDimitry Andric const DWARFDataExtractor &debug_ranges_data,
77*0b57cec5SDimitry Andric lldb::offset_t *offset_ptr,
78*0b57cec5SDimitry Andric dw_addr_t cu_base_addr) {
79*0b57cec5SDimitry Andric uint32_t addr_size = s.GetAddressByteSize();
80*0b57cec5SDimitry Andric
81*0b57cec5SDimitry Andric dw_addr_t base_addr = cu_base_addr;
82*0b57cec5SDimitry Andric while (
83*0b57cec5SDimitry Andric debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
84*0b57cec5SDimitry Andric dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
85*0b57cec5SDimitry Andric dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
86*0b57cec5SDimitry Andric // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits of
87*0b57cec5SDimitry Andric // ones
88*0b57cec5SDimitry Andric if (begin == 0xFFFFFFFFull && addr_size == 4)
89*0b57cec5SDimitry Andric begin = LLDB_INVALID_ADDRESS;
90*0b57cec5SDimitry Andric
91*0b57cec5SDimitry Andric s.Indent();
92*0b57cec5SDimitry Andric if (begin == 0 && end == 0) {
93*0b57cec5SDimitry Andric s.PutCString(" End");
94*0b57cec5SDimitry Andric break;
95*0b57cec5SDimitry Andric } else if (begin == LLDB_INVALID_ADDRESS) {
96*0b57cec5SDimitry Andric // A base address selection entry
97*0b57cec5SDimitry Andric base_addr = end;
98*0b57cec5SDimitry Andric DumpAddress(s.AsRawOstream(), base_addr, sizeof(dw_addr_t),
99*0b57cec5SDimitry Andric " Base address = ");
100*0b57cec5SDimitry Andric } else {
101*0b57cec5SDimitry Andric // Convert from offset to an address
102*0b57cec5SDimitry Andric dw_addr_t begin_addr = begin + base_addr;
103*0b57cec5SDimitry Andric dw_addr_t end_addr = end + base_addr;
104*0b57cec5SDimitry Andric
105*0b57cec5SDimitry Andric DumpAddressRange(s.AsRawOstream(), begin_addr, end_addr,
106*0b57cec5SDimitry Andric sizeof(dw_addr_t), nullptr);
107*0b57cec5SDimitry Andric }
108*0b57cec5SDimitry Andric }
109*0b57cec5SDimitry Andric }
110*0b57cec5SDimitry Andric
FindRanges(const DWARFUnit * cu,dw_offset_t debug_ranges_offset,DWARFRangeList & range_list) const111*0b57cec5SDimitry Andric bool DWARFDebugRanges::FindRanges(const DWARFUnit *cu,
112*0b57cec5SDimitry Andric dw_offset_t debug_ranges_offset,
113*0b57cec5SDimitry Andric DWARFRangeList &range_list) const {
114*0b57cec5SDimitry Andric dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset;
115*0b57cec5SDimitry Andric range_map_const_iterator pos = m_range_map.find(debug_ranges_address);
116*0b57cec5SDimitry Andric if (pos != m_range_map.end()) {
117*0b57cec5SDimitry Andric range_list = pos->second;
118*0b57cec5SDimitry Andric
119*0b57cec5SDimitry Andric // All DW_AT_ranges are relative to the base address of the compile
120*0b57cec5SDimitry Andric // unit. We add the compile unit base address to make sure all the
121*0b57cec5SDimitry Andric // addresses are properly fixed up.
122*0b57cec5SDimitry Andric range_list.Slide(cu->GetBaseAddress());
123*0b57cec5SDimitry Andric return true;
124*0b57cec5SDimitry Andric }
125*0b57cec5SDimitry Andric return false;
126*0b57cec5SDimitry Andric }
127*0b57cec5SDimitry Andric