LLDB  mainline
DWARFDebugArangeSet.cpp
Go to the documentation of this file.
1 //===-- DWARFDebugArangeSet.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 "DWARFDebugArangeSet.h"
10 #include "DWARFDataExtractor.h"
11 #include "LogChannelDWARF.h"
12 #include "llvm/Object/Error.h"
13 #include <cassert>
14 
15 using namespace lldb_private;
16 
18  : m_offset(DW_INVALID_OFFSET), m_next_offset(DW_INVALID_OFFSET) {}
19 
23  m_header.length = 0;
24  m_header.version = 0;
25  m_header.cu_offset = 0;
26  m_header.addr_size = 0;
27  m_header.seg_size = 0;
28  m_arange_descriptors.clear();
29 }
30 
32  lldb::offset_t *offset_ptr) {
33  assert(data.ValidOffset(*offset_ptr));
34 
35  m_arange_descriptors.clear();
36  m_offset = *offset_ptr;
37 
38  // 7.20 Address Range Table
39  //
40  // Each set of entries in the table of address ranges contained in the
41  // .debug_aranges section begins with a header consisting of: a 4-byte
42  // length containing the length of the set of entries for this compilation
43  // unit, not including the length field itself; a 2-byte version identifier
44  // containing the value 2 for DWARF Version 2; a 4-byte offset into
45  // the.debug_infosection; a 1-byte unsigned integer containing the size in
46  // bytes of an address (or the offset portion of an address for segmented
47  // addressing) on the target system; and a 1-byte unsigned integer
48  // containing the size in bytes of a segment descriptor on the target
49  // system. This header is followed by a series of tuples. Each tuple
50  // consists of an address and a length, each in the size appropriate for an
51  // address on the target architecture.
52  m_header.length = data.GetDWARFInitialLength(offset_ptr);
53  // The length could be 4 bytes or 12 bytes, so use the current offset to
54  // determine the next offset correctly.
55  if (m_header.length > 0)
56  m_next_offset = *offset_ptr + m_header.length;
57  else
59  m_header.version = data.GetU16(offset_ptr);
60  m_header.cu_offset = data.GetDWARFOffset(offset_ptr);
61  m_header.addr_size = data.GetU8(offset_ptr);
62  m_header.seg_size = data.GetU8(offset_ptr);
63 
64  // Try to avoid reading invalid arange sets by making sure:
65  // 1 - the version looks good
66  // 2 - the address byte size looks plausible
67  // 3 - the length seems to make sense
68  // 4 - size looks plausible
69  // 5 - the arange tuples do not contain a segment field
70  if (m_header.version < 2 || m_header.version > 5)
71  return llvm::make_error<llvm::object::GenericBinaryError>(
72  "Invalid arange header version");
73 
74  if (m_header.addr_size != 4 && m_header.addr_size != 8)
75  return llvm::make_error<llvm::object::GenericBinaryError>(
76  "Invalid arange header address size");
77 
78  if (m_header.length == 0)
79  return llvm::make_error<llvm::object::GenericBinaryError>(
80  "Invalid arange header length");
81 
82  if (!data.ValidOffset(m_offset + sizeof(m_header.length) + m_header.length -
83  1))
84  return llvm::make_error<llvm::object::GenericBinaryError>(
85  "Invalid arange header length");
86 
87  if (m_header.seg_size)
88  return llvm::make_error<llvm::object::GenericBinaryError>(
89  "segmented arange entries are not supported");
90 
91  // The first tuple following the header in each set begins at an offset
92  // that is a multiple of the size of a single tuple (that is, twice the
93  // size of an address). The header is padded, if necessary, to the
94  // appropriate boundary.
95  const uint32_t header_size = *offset_ptr - m_offset;
96  const uint32_t tuple_size = m_header.addr_size << 1;
97  uint32_t first_tuple_offset = 0;
98  while (first_tuple_offset < header_size)
99  first_tuple_offset += tuple_size;
100 
101  *offset_ptr = m_offset + first_tuple_offset;
102 
103  Descriptor arangeDescriptor;
104 
105  static_assert(sizeof(arangeDescriptor.address) ==
106  sizeof(arangeDescriptor.length),
107  "DWARFDebugArangeSet::Descriptor.address and "
108  "DWARFDebugArangeSet::Descriptor.length must have same size");
109 
110  const lldb::offset_t next_offset = GetNextOffset();
111  assert(next_offset != DW_INVALID_OFFSET);
112  uint32_t num_terminators = 0;
113  bool last_was_terminator = false;
114  while (*offset_ptr < next_offset) {
115  arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size);
116  arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size);
117 
118  // Each set of tuples is terminated by a 0 for the address and 0 for
119  // the length. Some linkers can emit .debug_aranges with multiple
120  // terminator pair entries that are still withing the length of the
121  // DWARFDebugArangeSet. We want to be sure to parse all entries for
122  // this DWARFDebugArangeSet so that we don't stop parsing early and end up
123  // treating addresses as a header of the next DWARFDebugArangeSet. We also
124  // need to make sure we parse all valid address pairs so we don't omit them
125  // from the aranges result, so we can't stop at the first terminator entry
126  // we find.
127  if (arangeDescriptor.address == 0 && arangeDescriptor.length == 0) {
128  ++num_terminators;
129  last_was_terminator = true;
130  } else {
131  last_was_terminator = false;
132  // Only add .debug_aranges address entries that have a non zero size.
133  // Some linkers will zero out the length field for some .debug_aranges
134  // entries if they were stripped. We also could watch out for multiple
135  // entries at address zero and remove those as well.
136  if (arangeDescriptor.length > 0)
137  m_arange_descriptors.push_back(arangeDescriptor);
138  }
139  }
140  if (num_terminators > 1) {
141  Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO);
142  LLDB_LOG(log,
143  "warning: DWARFDebugArangeSet at %#" PRIx64 " contains %u "
144  "terminator entries",
145  m_offset, num_terminators);
146  }
147  if (last_was_terminator)
148  return llvm::ErrorSuccess();
149 
150  return llvm::make_error<llvm::object::GenericBinaryError>(
151  "arange descriptors not terminated by null entry");
152 }
153 
155 public:
157  bool operator()(const DWARFDebugArangeSet::Descriptor &desc) const {
158  return (m_address >= desc.address) &&
159  (m_address < (desc.address + desc.length));
160  }
161 
162 private:
164 };
165 
168  DescriptorConstIter pos =
169  std::find_if(m_arange_descriptors.begin(), end, // Range
170  DescriptorContainsAddress(address)); // Predicate
171  if (pos != end)
172  return m_header.cu_offset;
173 
174  return DW_INVALID_OFFSET;
175 }
DWARFDebugArangeSet::Header::seg_size
uint8_t seg_size
The size in bytes of a segment descriptor on the target architecture.
Definition: DWARFDebugArangeSet.h:33
lldb_private::DataExtractor::ValidOffset
bool ValidOffset(lldb::offset_t offset) const
Test the validity of offset.
Definition: DataExtractor.h:945
DWARFDebugArangeSet::FindAddress
dw_offset_t FindAddress(dw_addr_t address) const
Definition: DWARFDebugArangeSet.cpp:166
DWARFDebugArangeSet::Descriptor::length
dw_addr_t length
Definition: DWARFDebugArangeSet.h:38
DWARFDebugArangeSet.h
lldb::offset_t
uint64_t offset_t
Definition: lldb-types.h:87
lldb_private::DWARFDataExtractor
Definition: DWARFDataExtractor.h:18
DW_INVALID_OFFSET
#define DW_INVALID_OFFSET
Definition: dwarf.h:34
DWARFDebugArangeSet::extract
llvm::Error extract(const lldb_private::DWARFDataExtractor &data, lldb::offset_t *offset_ptr)
Definition: DWARFDebugArangeSet.cpp:31
DWARFDebugArangeSet::DWARFDebugArangeSet
DWARFDebugArangeSet()
Definition: DWARFDebugArangeSet.cpp:17
DWARFDebugArangeSet::Header::version
uint16_t version
The DWARF version number.
Definition: DWARFDebugArangeSet.h:23
DWARF_LOG_DEBUG_INFO
#define DWARF_LOG_DEBUG_INFO
Definition: LogChannelDWARF.h:14
DescriptorContainsAddress::m_address
const dw_addr_t m_address
Definition: DWARFDebugArangeSet.cpp:163
lldb_private::DataExtractor::GetU8
uint8_t GetU8(lldb::offset_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
Definition: DataExtractor.cpp:318
lldb_private::DWARFDataExtractor::GetDWARFInitialLength
uint64_t GetDWARFInitialLength(lldb::offset_t *offset_ptr) const
Definition: DWARFDataExtractor.cpp:15
DWARFDebugArangeSet::Header::cu_offset
uint32_t cu_offset
The offset from the beginning of the .debug_info section of the compilation unit entry referenced by ...
Definition: DWARFDebugArangeSet.h:26
LogChannelDWARF.h
DWARFDebugArangeSet::m_arange_descriptors
DescriptorColl m_arange_descriptors
Definition: DWARFDebugArangeSet.h:63
DWARFDebugArangeSet::Header::length
uint32_t length
The total length of the entries for that set, not including the length field itself.
Definition: DWARFDebugArangeSet.h:21
lldb_private::DWARFDataExtractor::GetDWARFOffset
dw_offset_t GetDWARFOffset(lldb::offset_t *offset_ptr) const
Definition: DWARFDataExtractor.cpp:20
DWARFDebugArangeSet::m_header
Header m_header
Definition: DWARFDebugArangeSet.h:62
DescriptorContainsAddress::operator()
bool operator()(const DWARFDebugArangeSet::Descriptor &desc) const
Definition: DWARFDebugArangeSet.cpp:157
DescriptorContainsAddress
Definition: DWARFDebugArangeSet.cpp:154
uint32_t
lldb_private::DataExtractor::GetMaxU64
uint64_t GetMaxU64(lldb::offset_t *offset_ptr, size_t byte_size) const
Extract an unsigned integer of size byte_size from *offset_ptr.
Definition: DataExtractor.cpp:526
DWARFDebugArangeSet::Header::addr_size
uint8_t addr_size
The size in bytes of an address on the target architecture.
Definition: DWARFDebugArangeSet.h:30
DWARFDebugArangeSet::DescriptorConstIter
DescriptorColl::const_iterator DescriptorConstIter
Definition: DWARFDebugArangeSet.h:58
LLDB_LOG
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:242
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::DataExtractor::GetU16
uint16_t GetU16(lldb::offset_t *offset_ptr) const
Extract a uint16_t value from *offset_ptr.
Definition: DataExtractor.cpp:349
Error
llvm::Error Error
Definition: UdtRecordCompleter.cpp:29
DWARFDebugArangeSet::Descriptor::address
dw_addr_t address
Definition: DWARFDebugArangeSet.h:37
DWARFDebugArangeSet::GetNextOffset
dw_offset_t GetNextOffset() const
Definition: DWARFDebugArangeSet.h:50
DWARFDebugArangeSet::Descriptor
Definition: DWARFDebugArangeSet.h:36
DWARFDebugArangeSet::m_next_offset
dw_offset_t m_next_offset
Definition: DWARFDebugArangeSet.h:61
lldb_private::Log
Definition: Log.h:49
DWARFDebugArangeSet::m_offset
dw_offset_t m_offset
Definition: DWARFDebugArangeSet.h:60
dw_addr_t
uint64_t dw_addr_t
Definition: dwarf.h:26
DWARFDebugArangeSet::Clear
void Clear()
Definition: DWARFDebugArangeSet.cpp:20
DescriptorContainsAddress::DescriptorContainsAddress
DescriptorContainsAddress(dw_addr_t address)
Definition: DWARFDebugArangeSet.cpp:156
DWARFDataExtractor.h