1*80814287SRaphael Isemann //===-- DWARFDebugRanges.cpp ----------------------------------------------===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner 
930fdc8d8SChris Lattner #include "DWARFDebugRanges.h"
107e7f9c10SGeorge Rimar #include "DWARFUnit.h"
11bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
1230fdc8d8SChris Lattner 
1330fdc8d8SChris Lattner using namespace lldb_private;
1430fdc8d8SChris Lattner 
GetBaseAddressMarker(uint32_t addr_size)1515cf3795STamas Berghammer static dw_addr_t GetBaseAddressMarker(uint32_t addr_size) {
1615cf3795STamas Berghammer   switch(addr_size) {
1715cf3795STamas Berghammer     case 2:
1815cf3795STamas Berghammer       return 0xffff;
1915cf3795STamas Berghammer     case 4:
2015cf3795STamas Berghammer       return 0xffffffff;
2115cf3795STamas Berghammer     case 8:
2215cf3795STamas Berghammer       return 0xffffffffffffffff;
2315cf3795STamas Berghammer   }
2415cf3795STamas Berghammer   llvm_unreachable("GetBaseAddressMarker unsupported address size.");
2515cf3795STamas Berghammer }
2615cf3795STamas Berghammer 
DWARFDebugRanges()27b9c1b51eSKate Stone DWARFDebugRanges::DWARFDebugRanges() : m_range_map() {}
2830fdc8d8SChris Lattner 
Extract(DWARFContext & context)2900e3968bSPavel Labath void DWARFDebugRanges::Extract(DWARFContext &context) {
306071e6fcSGreg Clayton   DWARFRangeList range_list;
31c7bece56SGreg Clayton   lldb::offset_t offset = 0;
3230fdc8d8SChris Lattner   dw_offset_t debug_ranges_offset = offset;
3300e3968bSPavel Labath   while (Extract(context, &offset, range_list)) {
34f44e3cd7SEd Maste     range_list.Sort();
3530fdc8d8SChris Lattner     m_range_map[debug_ranges_offset] = range_list;
3630fdc8d8SChris Lattner     debug_ranges_offset = offset;
3730fdc8d8SChris Lattner   }
3830fdc8d8SChris Lattner }
3930fdc8d8SChris Lattner 
Extract(DWARFContext & context,lldb::offset_t * offset_ptr,DWARFRangeList & range_list)4000e3968bSPavel Labath bool DWARFDebugRanges::Extract(DWARFContext &context,
41b9c1b51eSKate Stone                                lldb::offset_t *offset_ptr,
42b9c1b51eSKate Stone                                DWARFRangeList &range_list) {
43ea3e7d5cSGreg Clayton   range_list.Clear();
44ea3e7d5cSGreg Clayton 
45c7bece56SGreg Clayton   lldb::offset_t range_offset = *offset_ptr;
4600e3968bSPavel Labath   const DWARFDataExtractor &debug_ranges_data = context.getOrLoadRangesData();
474c2ef9a0SPavel Labath   uint32_t addr_size = debug_ranges_data.GetAddressByteSize();
4815cf3795STamas Berghammer   dw_addr_t base_addr = 0;
4915cf3795STamas Berghammer   dw_addr_t base_addr_marker = GetBaseAddressMarker(addr_size);
5030fdc8d8SChris Lattner 
514c2ef9a0SPavel Labath   while (
524c2ef9a0SPavel Labath       debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
534c2ef9a0SPavel Labath     dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
544c2ef9a0SPavel Labath     dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
5515cf3795STamas Berghammer 
56b9c1b51eSKate Stone     if (!begin && !end) {
5730fdc8d8SChris Lattner       // End of range list
5830fdc8d8SChris Lattner       break;
5930fdc8d8SChris Lattner     }
6030fdc8d8SChris Lattner 
6115cf3795STamas Berghammer     if (begin == base_addr_marker) {
6215cf3795STamas Berghammer       base_addr = end;
6315cf3795STamas Berghammer       continue;
6430fdc8d8SChris Lattner     }
6530fdc8d8SChris Lattner 
6630fdc8d8SChris Lattner     // Filter out empty ranges
67ea3e7d5cSGreg Clayton     if (begin < end)
6815cf3795STamas Berghammer       range_list.Append(DWARFRangeList::Entry(begin + base_addr, end - begin));
6930fdc8d8SChris Lattner   }
7030fdc8d8SChris Lattner 
7130fdc8d8SChris Lattner   // Make sure we consumed at least something
7230fdc8d8SChris Lattner   return range_offset != *offset_ptr;
7330fdc8d8SChris Lattner }
7430fdc8d8SChris Lattner 
Dump(Stream & s,const DWARFDataExtractor & debug_ranges_data,lldb::offset_t * offset_ptr,dw_addr_t cu_base_addr)75b9c1b51eSKate Stone void DWARFDebugRanges::Dump(Stream &s,
76b9c1b51eSKate Stone                             const DWARFDataExtractor &debug_ranges_data,
77b9c1b51eSKate Stone                             lldb::offset_t *offset_ptr,
78b9c1b51eSKate Stone                             dw_addr_t cu_base_addr) {
79d3d25d91SJim Ingham   uint32_t addr_size = s.GetAddressByteSize();
8030fdc8d8SChris Lattner 
8130fdc8d8SChris Lattner   dw_addr_t base_addr = cu_base_addr;
82b9c1b51eSKate Stone   while (
83b9c1b51eSKate Stone       debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
8430fdc8d8SChris Lattner     dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
8530fdc8d8SChris Lattner     dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
8605097246SAdrian Prantl     // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits of
8705097246SAdrian Prantl     // ones
8830fdc8d8SChris Lattner     if (begin == 0xFFFFFFFFull && addr_size == 4)
89c7bece56SGreg Clayton       begin = LLDB_INVALID_ADDRESS;
9030fdc8d8SChris Lattner 
91d3d25d91SJim Ingham     s.Indent();
92b9c1b51eSKate Stone     if (begin == 0 && end == 0) {
93d3d25d91SJim Ingham       s.PutCString(" End");
9430fdc8d8SChris Lattner       break;
95b9c1b51eSKate Stone     } else if (begin == LLDB_INVALID_ADDRESS) {
9630fdc8d8SChris Lattner       // A base address selection entry
9730fdc8d8SChris Lattner       base_addr = end;
981462f5a4SRaphael Isemann       DumpAddress(s.AsRawOstream(), base_addr, sizeof(dw_addr_t),
991462f5a4SRaphael Isemann                   " Base address = ");
100b9c1b51eSKate Stone     } else {
10130fdc8d8SChris Lattner       // Convert from offset to an address
10230fdc8d8SChris Lattner       dw_addr_t begin_addr = begin + base_addr;
10330fdc8d8SChris Lattner       dw_addr_t end_addr = end + base_addr;
10430fdc8d8SChris Lattner 
1051462f5a4SRaphael Isemann       DumpAddressRange(s.AsRawOstream(), begin_addr, end_addr,
1061462f5a4SRaphael Isemann                        sizeof(dw_addr_t), nullptr);
10730fdc8d8SChris Lattner     }
10830fdc8d8SChris Lattner   }
10930fdc8d8SChris Lattner }
11030fdc8d8SChris Lattner 
FindRanges(const DWARFUnit * cu,dw_offset_t debug_ranges_offset,DWARFRangeList & range_list) const1117e7f9c10SGeorge Rimar bool DWARFDebugRanges::FindRanges(const DWARFUnit *cu,
1122540a553STamas Berghammer                                   dw_offset_t debug_ranges_offset,
113b9c1b51eSKate Stone                                   DWARFRangeList &range_list) const {
1147e7f9c10SGeorge Rimar   dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset;
1152540a553STamas Berghammer   range_map_const_iterator pos = m_range_map.find(debug_ranges_address);
116b9c1b51eSKate Stone   if (pos != m_range_map.end()) {
11730fdc8d8SChris Lattner     range_list = pos->second;
1187e7f9c10SGeorge Rimar 
1197e7f9c10SGeorge Rimar     // All DW_AT_ranges are relative to the base address of the compile
1207e7f9c10SGeorge Rimar     // unit. We add the compile unit base address to make sure all the
1217e7f9c10SGeorge Rimar     // addresses are properly fixed up.
1227e7f9c10SGeorge Rimar     range_list.Slide(cu->GetBaseAddress());
12330fdc8d8SChris Lattner     return true;
12430fdc8d8SChris Lattner   }
12530fdc8d8SChris Lattner   return false;
12630fdc8d8SChris Lattner }
127