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