1254721Semaste//===-- DWARFDebugRanges.cpp ------------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9254721Semaste#include "DWARFDebugRanges.h"
10344779Sdim#include "DWARFUnit.h"
11321369Sdim#include "lldb/Utility/Stream.h"
12254721Semaste
13254721Semasteusing namespace lldb_private;
14254721Semaste
15327952Sdimstatic dw_addr_t GetBaseAddressMarker(uint32_t addr_size) {
16327952Sdim  switch(addr_size) {
17327952Sdim    case 2:
18327952Sdim      return 0xffff;
19327952Sdim    case 4:
20327952Sdim      return 0xffffffff;
21327952Sdim    case 8:
22327952Sdim      return 0xffffffffffffffff;
23327952Sdim  }
24327952Sdim  llvm_unreachable("GetBaseAddressMarker unsupported address size.");
25327952Sdim}
26327952Sdim
27314564SdimDWARFDebugRanges::DWARFDebugRanges() : m_range_map() {}
28254721Semaste
29353358Sdimvoid DWARFDebugRanges::Extract(DWARFContext &context) {
30314564Sdim  DWARFRangeList range_list;
31314564Sdim  lldb::offset_t offset = 0;
32314564Sdim  dw_offset_t debug_ranges_offset = offset;
33353358Sdim  while (Extract(context, &offset, range_list)) {
34314564Sdim    range_list.Sort();
35314564Sdim    m_range_map[debug_ranges_offset] = range_list;
36314564Sdim    debug_ranges_offset = offset;
37314564Sdim  }
38254721Semaste}
39254721Semaste
40353358Sdimbool DWARFDebugRanges::Extract(DWARFContext &context,
41314564Sdim                               lldb::offset_t *offset_ptr,
42314564Sdim                               DWARFRangeList &range_list) {
43314564Sdim  range_list.Clear();
44254721Semaste
45314564Sdim  lldb::offset_t range_offset = *offset_ptr;
46353358Sdim  const DWARFDataExtractor &debug_ranges_data = context.getOrLoadRangesData();
47314564Sdim  uint32_t addr_size = debug_ranges_data.GetAddressByteSize();
48327952Sdim  dw_addr_t base_addr = 0;
49327952Sdim  dw_addr_t base_addr_marker = GetBaseAddressMarker(addr_size);
50254721Semaste
51314564Sdim  while (
52314564Sdim      debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
53314564Sdim    dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
54314564Sdim    dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
55327952Sdim
56314564Sdim    if (!begin && !end) {
57314564Sdim      // End of range list
58314564Sdim      break;
59314564Sdim    }
60254721Semaste
61327952Sdim    if (begin == base_addr_marker) {
62327952Sdim      base_addr = end;
63327952Sdim      continue;
64254721Semaste    }
65254721Semaste
66314564Sdim    // Filter out empty ranges
67314564Sdim    if (begin < end)
68327952Sdim      range_list.Append(DWARFRangeList::Entry(begin + base_addr, end - begin));
69314564Sdim  }
70314564Sdim
71314564Sdim  // Make sure we consumed at least something
72314564Sdim  return range_offset != *offset_ptr;
73254721Semaste}
74254721Semaste
75314564Sdimvoid DWARFDebugRanges::Dump(Stream &s,
76314564Sdim                            const DWARFDataExtractor &debug_ranges_data,
77314564Sdim                            lldb::offset_t *offset_ptr,
78314564Sdim                            dw_addr_t cu_base_addr) {
79314564Sdim  uint32_t addr_size = s.GetAddressByteSize();
80254721Semaste
81314564Sdim  dw_addr_t base_addr = cu_base_addr;
82314564Sdim  while (
83314564Sdim      debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
84314564Sdim    dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
85314564Sdim    dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
86341825Sdim    // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits of
87341825Sdim    // ones
88314564Sdim    if (begin == 0xFFFFFFFFull && addr_size == 4)
89314564Sdim      begin = LLDB_INVALID_ADDRESS;
90254721Semaste
91314564Sdim    s.Indent();
92314564Sdim    if (begin == 0 && end == 0) {
93314564Sdim      s.PutCString(" End");
94314564Sdim      break;
95314564Sdim    } else if (begin == LLDB_INVALID_ADDRESS) {
96314564Sdim      // A base address selection entry
97314564Sdim      base_addr = end;
98360784Sdim      DumpAddress(s.AsRawOstream(), base_addr, sizeof(dw_addr_t),
99360784Sdim                  " Base address = ");
100314564Sdim    } else {
101314564Sdim      // Convert from offset to an address
102314564Sdim      dw_addr_t begin_addr = begin + base_addr;
103314564Sdim      dw_addr_t end_addr = end + base_addr;
104254721Semaste
105360784Sdim      DumpAddressRange(s.AsRawOstream(), begin_addr, end_addr,
106360784Sdim                       sizeof(dw_addr_t), nullptr);
107254721Semaste    }
108314564Sdim  }
109254721Semaste}
110254721Semaste
111344779Sdimbool DWARFDebugRanges::FindRanges(const DWARFUnit *cu,
112314564Sdim                                  dw_offset_t debug_ranges_offset,
113314564Sdim                                  DWARFRangeList &range_list) const {
114344779Sdim  dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset;
115314564Sdim  range_map_const_iterator pos = m_range_map.find(debug_ranges_address);
116314564Sdim  if (pos != m_range_map.end()) {
117314564Sdim    range_list = pos->second;
118344779Sdim
119344779Sdim    // All DW_AT_ranges are relative to the base address of the compile
120344779Sdim    // unit. We add the compile unit base address to make sure all the
121344779Sdim    // addresses are properly fixed up.
122344779Sdim    range_list.Slide(cu->GetBaseAddress());
123314564Sdim    return true;
124314564Sdim  }
125314564Sdim  return false;
126254721Semaste}
127