1254721Semaste//===-- DWARFDebugArangeSet.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 "DWARFDebugArangeSet.h"
10353358Sdim#include "DWARFDataExtractor.h"
11353358Sdim#include "llvm/Object/Error.h"
12353358Sdim#include <cassert>
13254721Semaste
14254721Semasteusing namespace lldb_private;
15254721Semaste
16314564SdimDWARFDebugArangeSet::DWARFDebugArangeSet()
17314564Sdim    : m_offset(DW_INVALID_OFFSET), m_header(), m_arange_descriptors() {
18314564Sdim  m_header.length = 0;
19314564Sdim  m_header.version = 0;
20314564Sdim  m_header.cu_offset = 0;
21314564Sdim  m_header.addr_size = 0;
22314564Sdim  m_header.seg_size = 0;
23254721Semaste}
24254721Semaste
25314564Sdimvoid DWARFDebugArangeSet::Clear() {
26314564Sdim  m_offset = DW_INVALID_OFFSET;
27314564Sdim  m_header.length = 0;
28314564Sdim  m_header.version = 0;
29314564Sdim  m_header.cu_offset = 0;
30314564Sdim  m_header.addr_size = 0;
31314564Sdim  m_header.seg_size = 0;
32314564Sdim  m_arange_descriptors.clear();
33254721Semaste}
34254721Semaste
35353358Sdimllvm::Error DWARFDebugArangeSet::extract(const DWARFDataExtractor &data,
36353358Sdim                                         lldb::offset_t *offset_ptr) {
37353358Sdim  assert(data.ValidOffset(*offset_ptr));
38254721Semaste
39353358Sdim  m_arange_descriptors.clear();
40353358Sdim  m_offset = *offset_ptr;
41254721Semaste
42353358Sdim  // 7.20 Address Range Table
43353358Sdim  //
44353358Sdim  // Each set of entries in the table of address ranges contained in the
45353358Sdim  // .debug_aranges section begins with a header consisting of: a 4-byte
46353358Sdim  // length containing the length of the set of entries for this compilation
47353358Sdim  // unit, not including the length field itself; a 2-byte version identifier
48353358Sdim  // containing the value 2 for DWARF Version 2; a 4-byte offset into
49353358Sdim  // the.debug_infosection; a 1-byte unsigned integer containing the size in
50353358Sdim  // bytes of an address (or the offset portion of an address for segmented
51353358Sdim  // addressing) on the target system; and a 1-byte unsigned integer
52353358Sdim  // containing the size in bytes of a segment descriptor on the target
53353358Sdim  // system. This header is followed by a series of tuples. Each tuple
54353358Sdim  // consists of an address and a length, each in the size appropriate for an
55353358Sdim  // address on the target architecture.
56353358Sdim  m_header.length = data.GetDWARFInitialLength(offset_ptr);
57353358Sdim  m_header.version = data.GetU16(offset_ptr);
58353358Sdim  m_header.cu_offset = data.GetDWARFOffset(offset_ptr);
59353358Sdim  m_header.addr_size = data.GetU8(offset_ptr);
60353358Sdim  m_header.seg_size = data.GetU8(offset_ptr);
61254721Semaste
62353358Sdim  // Try to avoid reading invalid arange sets by making sure:
63353358Sdim  // 1 - the version looks good
64353358Sdim  // 2 - the address byte size looks plausible
65353358Sdim  // 3 - the length seems to make sense
66353358Sdim  // size looks plausible
67353358Sdim  if (m_header.version < 2 || m_header.version > 5)
68353358Sdim    return llvm::make_error<llvm::object::GenericBinaryError>(
69353358Sdim        "Invalid arange header version");
70254721Semaste
71353358Sdim  if (m_header.addr_size != 4 && m_header.addr_size != 8)
72353358Sdim    return llvm::make_error<llvm::object::GenericBinaryError>(
73353358Sdim        "Invalid arange header address size");
74254721Semaste
75353358Sdim  if (m_header.length == 0)
76353358Sdim    return llvm::make_error<llvm::object::GenericBinaryError>(
77353358Sdim        "Invalid arange header length");
78254721Semaste
79353358Sdim  if (!data.ValidOffset(m_offset + sizeof(m_header.length) + m_header.length -
80353358Sdim                        1))
81353358Sdim    return llvm::make_error<llvm::object::GenericBinaryError>(
82353358Sdim        "Invalid arange header length");
83314564Sdim
84353358Sdim  // The first tuple following the header in each set begins at an offset
85353358Sdim  // that is a multiple of the size of a single tuple (that is, twice the
86353358Sdim  // size of an address). The header is padded, if necessary, to the
87353358Sdim  // appropriate boundary.
88353358Sdim  const uint32_t header_size = *offset_ptr - m_offset;
89353358Sdim  const uint32_t tuple_size = m_header.addr_size << 1;
90353358Sdim  uint32_t first_tuple_offset = 0;
91353358Sdim  while (first_tuple_offset < header_size)
92353358Sdim    first_tuple_offset += tuple_size;
93314564Sdim
94353358Sdim  *offset_ptr = m_offset + first_tuple_offset;
95314564Sdim
96353358Sdim  Descriptor arangeDescriptor;
97314564Sdim
98353358Sdim  static_assert(sizeof(arangeDescriptor.address) ==
99353358Sdim                    sizeof(arangeDescriptor.length),
100353358Sdim                "DWARFDebugArangeSet::Descriptor.address and "
101353358Sdim                "DWARFDebugArangeSet::Descriptor.length must have same size");
102314564Sdim
103353358Sdim  while (data.ValidOffset(*offset_ptr)) {
104353358Sdim    arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size);
105353358Sdim    arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size);
106314564Sdim
107353358Sdim    // Each set of tuples is terminated by a 0 for the address and 0 for
108353358Sdim    // the length.
109353358Sdim    if (!arangeDescriptor.address && !arangeDescriptor.length)
110353358Sdim      return llvm::ErrorSuccess();
111314564Sdim
112353358Sdim    m_arange_descriptors.push_back(arangeDescriptor);
113314564Sdim  }
114254721Semaste
115353358Sdim  return llvm::make_error<llvm::object::GenericBinaryError>(
116353358Sdim      "arange descriptors not terminated by null entry");
117254721Semaste}
118254721Semaste
119314564Sdimclass DescriptorContainsAddress {
120314564Sdimpublic:
121314564Sdim  DescriptorContainsAddress(dw_addr_t address) : m_address(address) {}
122314564Sdim  bool operator()(const DWARFDebugArangeSet::Descriptor &desc) const {
123314564Sdim    return (m_address >= desc.address) &&
124314564Sdim           (m_address < (desc.address + desc.length));
125314564Sdim  }
126254721Semaste
127314564Sdimprivate:
128314564Sdim  const dw_addr_t m_address;
129254721Semaste};
130254721Semaste
131314564Sdimdw_offset_t DWARFDebugArangeSet::FindAddress(dw_addr_t address) const {
132314564Sdim  DescriptorConstIter end = m_arange_descriptors.end();
133314564Sdim  DescriptorConstIter pos =
134314564Sdim      std::find_if(m_arange_descriptors.begin(), end,   // Range
135314564Sdim                   DescriptorContainsAddress(address)); // Predicate
136314564Sdim  if (pos != end)
137314564Sdim    return m_header.cu_offset;
138254721Semaste
139314564Sdim  return DW_INVALID_OFFSET;
140254721Semaste}
141