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