1 //===-- DWARFDebugRanges.cpp ------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "DWARFDebugRanges.h"
11 #include "SymbolFileDWARF.h"
12 #include "lldb/Utility/Stream.h"
13 #include <assert.h>
14 
15 using namespace lldb_private;
16 using namespace std;
17 
18 DWARFDebugRanges::DWARFDebugRanges() : m_range_map() {}
19 
20 DWARFDebugRanges::~DWARFDebugRanges() {}
21 
22 void DWARFDebugRanges::Extract(SymbolFileDWARF *dwarf2Data) {
23   DWARFRangeList range_list;
24   lldb::offset_t offset = 0;
25   dw_offset_t debug_ranges_offset = offset;
26   while (Extract(dwarf2Data, &offset, range_list)) {
27     range_list.Sort();
28     m_range_map[debug_ranges_offset] = range_list;
29     debug_ranges_offset = offset;
30   }
31 }
32 
33 bool DWARFDebugRanges::Extract(SymbolFileDWARF *dwarf2Data,
34                                lldb::offset_t *offset_ptr,
35                                DWARFRangeList &range_list) {
36   range_list.Clear();
37 
38   lldb::offset_t range_offset = *offset_ptr;
39   const DWARFDataExtractor &debug_ranges_data =
40       dwarf2Data->get_debug_ranges_data();
41   uint32_t addr_size = debug_ranges_data.GetAddressByteSize();
42 
43   while (
44       debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
45     dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
46     dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
47     if (!begin && !end) {
48       // End of range list
49       break;
50     }
51     // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits
52     // of ones
53     switch (addr_size) {
54     case 2:
55       if (begin == 0xFFFFull)
56         begin = LLDB_INVALID_ADDRESS;
57       break;
58 
59     case 4:
60       if (begin == 0xFFFFFFFFull)
61         begin = LLDB_INVALID_ADDRESS;
62       break;
63 
64     case 8:
65       break;
66 
67     default:
68       llvm_unreachable("DWARFRangeList::Extract() unsupported address size.");
69     }
70 
71     // Filter out empty ranges
72     if (begin < end)
73       range_list.Append(DWARFRangeList::Entry(begin, end - begin));
74   }
75 
76   // Make sure we consumed at least something
77   return range_offset != *offset_ptr;
78 }
79 
80 void DWARFDebugRanges::Dump(Stream &s,
81                             const DWARFDataExtractor &debug_ranges_data,
82                             lldb::offset_t *offset_ptr,
83                             dw_addr_t cu_base_addr) {
84   uint32_t addr_size = s.GetAddressByteSize();
85 
86   dw_addr_t base_addr = cu_base_addr;
87   while (
88       debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
89     dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
90     dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
91     // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits
92     // of ones
93     if (begin == 0xFFFFFFFFull && addr_size == 4)
94       begin = LLDB_INVALID_ADDRESS;
95 
96     s.Indent();
97     if (begin == 0 && end == 0) {
98       s.PutCString(" End");
99       break;
100     } else if (begin == LLDB_INVALID_ADDRESS) {
101       // A base address selection entry
102       base_addr = end;
103       s.Address(base_addr, sizeof(dw_addr_t), " Base address = ");
104     } else {
105       // Convert from offset to an address
106       dw_addr_t begin_addr = begin + base_addr;
107       dw_addr_t end_addr = end + base_addr;
108 
109       s.AddressRange(begin_addr, end_addr, sizeof(dw_addr_t), NULL);
110     }
111   }
112 }
113 
114 bool DWARFDebugRanges::FindRanges(dw_addr_t debug_ranges_base,
115                                   dw_offset_t debug_ranges_offset,
116                                   DWARFRangeList &range_list) const {
117   dw_addr_t debug_ranges_address = debug_ranges_base + debug_ranges_offset;
118   range_map_const_iterator pos = m_range_map.find(debug_ranges_address);
119   if (pos != m_range_map.end()) {
120     range_list = pos->second;
121     return true;
122   }
123   return false;
124 }
125