xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp (revision dda2819751e49c83612958492e38917049128b41)
1*dda28197Spatrick //===-- DWARFDebugRanges.cpp ----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "DWARFDebugRanges.h"
10061da546Spatrick #include "DWARFUnit.h"
11061da546Spatrick #include "lldb/Utility/Stream.h"
12061da546Spatrick 
13061da546Spatrick using namespace lldb_private;
14061da546Spatrick 
GetBaseAddressMarker(uint32_t addr_size)15061da546Spatrick static dw_addr_t GetBaseAddressMarker(uint32_t addr_size) {
16061da546Spatrick   switch(addr_size) {
17061da546Spatrick     case 2:
18061da546Spatrick       return 0xffff;
19061da546Spatrick     case 4:
20061da546Spatrick       return 0xffffffff;
21061da546Spatrick     case 8:
22061da546Spatrick       return 0xffffffffffffffff;
23061da546Spatrick   }
24061da546Spatrick   llvm_unreachable("GetBaseAddressMarker unsupported address size.");
25061da546Spatrick }
26061da546Spatrick 
DWARFDebugRanges()27061da546Spatrick DWARFDebugRanges::DWARFDebugRanges() : m_range_map() {}
28061da546Spatrick 
Extract(DWARFContext & context)29061da546Spatrick void DWARFDebugRanges::Extract(DWARFContext &context) {
30061da546Spatrick   DWARFRangeList range_list;
31061da546Spatrick   lldb::offset_t offset = 0;
32061da546Spatrick   dw_offset_t debug_ranges_offset = offset;
33061da546Spatrick   while (Extract(context, &offset, range_list)) {
34061da546Spatrick     range_list.Sort();
35061da546Spatrick     m_range_map[debug_ranges_offset] = range_list;
36061da546Spatrick     debug_ranges_offset = offset;
37061da546Spatrick   }
38061da546Spatrick }
39061da546Spatrick 
Extract(DWARFContext & context,lldb::offset_t * offset_ptr,DWARFRangeList & range_list)40061da546Spatrick bool DWARFDebugRanges::Extract(DWARFContext &context,
41061da546Spatrick                                lldb::offset_t *offset_ptr,
42061da546Spatrick                                DWARFRangeList &range_list) {
43061da546Spatrick   range_list.Clear();
44061da546Spatrick 
45061da546Spatrick   lldb::offset_t range_offset = *offset_ptr;
46061da546Spatrick   const DWARFDataExtractor &debug_ranges_data = context.getOrLoadRangesData();
47061da546Spatrick   uint32_t addr_size = debug_ranges_data.GetAddressByteSize();
48061da546Spatrick   dw_addr_t base_addr = 0;
49061da546Spatrick   dw_addr_t base_addr_marker = GetBaseAddressMarker(addr_size);
50061da546Spatrick 
51061da546Spatrick   while (
52061da546Spatrick       debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
53061da546Spatrick     dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
54061da546Spatrick     dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
55061da546Spatrick 
56061da546Spatrick     if (!begin && !end) {
57061da546Spatrick       // End of range list
58061da546Spatrick       break;
59061da546Spatrick     }
60061da546Spatrick 
61061da546Spatrick     if (begin == base_addr_marker) {
62061da546Spatrick       base_addr = end;
63061da546Spatrick       continue;
64061da546Spatrick     }
65061da546Spatrick 
66061da546Spatrick     // Filter out empty ranges
67061da546Spatrick     if (begin < end)
68061da546Spatrick       range_list.Append(DWARFRangeList::Entry(begin + base_addr, end - begin));
69061da546Spatrick   }
70061da546Spatrick 
71061da546Spatrick   // Make sure we consumed at least something
72061da546Spatrick   return range_offset != *offset_ptr;
73061da546Spatrick }
74061da546Spatrick 
Dump(Stream & s,const DWARFDataExtractor & debug_ranges_data,lldb::offset_t * offset_ptr,dw_addr_t cu_base_addr)75061da546Spatrick void DWARFDebugRanges::Dump(Stream &s,
76061da546Spatrick                             const DWARFDataExtractor &debug_ranges_data,
77061da546Spatrick                             lldb::offset_t *offset_ptr,
78061da546Spatrick                             dw_addr_t cu_base_addr) {
79061da546Spatrick   uint32_t addr_size = s.GetAddressByteSize();
80061da546Spatrick 
81061da546Spatrick   dw_addr_t base_addr = cu_base_addr;
82061da546Spatrick   while (
83061da546Spatrick       debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
84061da546Spatrick     dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
85061da546Spatrick     dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
86061da546Spatrick     // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits of
87061da546Spatrick     // ones
88061da546Spatrick     if (begin == 0xFFFFFFFFull && addr_size == 4)
89061da546Spatrick       begin = LLDB_INVALID_ADDRESS;
90061da546Spatrick 
91061da546Spatrick     s.Indent();
92061da546Spatrick     if (begin == 0 && end == 0) {
93061da546Spatrick       s.PutCString(" End");
94061da546Spatrick       break;
95061da546Spatrick     } else if (begin == LLDB_INVALID_ADDRESS) {
96061da546Spatrick       // A base address selection entry
97061da546Spatrick       base_addr = end;
98061da546Spatrick       DumpAddress(s.AsRawOstream(), base_addr, sizeof(dw_addr_t),
99061da546Spatrick                   " Base address = ");
100061da546Spatrick     } else {
101061da546Spatrick       // Convert from offset to an address
102061da546Spatrick       dw_addr_t begin_addr = begin + base_addr;
103061da546Spatrick       dw_addr_t end_addr = end + base_addr;
104061da546Spatrick 
105061da546Spatrick       DumpAddressRange(s.AsRawOstream(), begin_addr, end_addr,
106061da546Spatrick                        sizeof(dw_addr_t), nullptr);
107061da546Spatrick     }
108061da546Spatrick   }
109061da546Spatrick }
110061da546Spatrick 
FindRanges(const DWARFUnit * cu,dw_offset_t debug_ranges_offset,DWARFRangeList & range_list) const111061da546Spatrick bool DWARFDebugRanges::FindRanges(const DWARFUnit *cu,
112061da546Spatrick                                   dw_offset_t debug_ranges_offset,
113061da546Spatrick                                   DWARFRangeList &range_list) const {
114061da546Spatrick   dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset;
115061da546Spatrick   range_map_const_iterator pos = m_range_map.find(debug_ranges_address);
116061da546Spatrick   if (pos != m_range_map.end()) {
117061da546Spatrick     range_list = pos->second;
118061da546Spatrick 
119061da546Spatrick     // All DW_AT_ranges are relative to the base address of the compile
120061da546Spatrick     // unit. We add the compile unit base address to make sure all the
121061da546Spatrick     // addresses are properly fixed up.
122061da546Spatrick     range_list.Slide(cu->GetBaseAddress());
123061da546Spatrick     return true;
124061da546Spatrick   }
125061da546Spatrick   return false;
126061da546Spatrick }
127