2013-08-23 13:46:38 -04:00
//===-- DWARFDebugArangeSet.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "DWARFDebugArangeSet.h"
# include <assert.h>
# include "lldb/Core/Stream.h"
# include "SymbolFileDWARF.h"
using namespace lldb_private ;
DWARFDebugArangeSet : : DWARFDebugArangeSet ( ) :
m_offset ( DW_INVALID_OFFSET ) ,
m_header ( ) ,
m_arange_descriptors ( )
{
m_header . length = 0 ;
m_header . version = 0 ;
m_header . cu_offset = 0 ;
m_header . addr_size = 0 ;
m_header . seg_size = 0 ;
}
void
DWARFDebugArangeSet : : Clear ( )
{
m_offset = DW_INVALID_OFFSET ;
m_header . length = 0 ;
m_header . version = 0 ;
m_header . cu_offset = 0 ;
m_header . addr_size = 0 ;
m_header . seg_size = 0 ;
m_arange_descriptors . clear ( ) ;
}
void
DWARFDebugArangeSet : : SetHeader
(
uint16_t version ,
uint32_t cu_offset ,
uint8_t addr_size ,
uint8_t seg_size
)
{
m_header . version = version ;
m_header . cu_offset = cu_offset ;
m_header . addr_size = addr_size ;
m_header . seg_size = seg_size ;
}
void
DWARFDebugArangeSet : : Compact ( )
{
if ( m_arange_descriptors . empty ( ) )
return ;
// Iterate through all arange descriptors and combine any ranges that
// overlap or have matching boundaries. The m_arange_descriptors are assumed
// to be in ascending order after being built by adding descriptors
// using the AddDescriptor method.
uint32_t i = 0 ;
while ( i + 1 < m_arange_descriptors . size ( ) )
{
if ( m_arange_descriptors [ i ] . end_address ( ) > = m_arange_descriptors [ i + 1 ] . address )
{
// The current range ends at or exceeds the start of the next address range.
// Compute the max end address between the two and use that to make the new
// length.
const dw_addr_t max_end_addr = std : : max ( m_arange_descriptors [ i ] . end_address ( ) , m_arange_descriptors [ i + 1 ] . end_address ( ) ) ;
m_arange_descriptors [ i ] . length = max_end_addr - m_arange_descriptors [ i ] . address ;
// Now remove the next entry as it was just combined with the previous one.
m_arange_descriptors . erase ( m_arange_descriptors . begin ( ) + i + 1 ) ;
}
else
{
// Discontiguous address range, just proceed to the next one.
+ + i ;
}
}
}
//----------------------------------------------------------------------
// Compare function DWARFDebugArangeSet::Descriptor structures
//----------------------------------------------------------------------
static bool DescriptorLessThan ( const DWARFDebugArangeSet : : Descriptor & range1 , const DWARFDebugArangeSet : : Descriptor & range2 )
{
return range1 . address < range2 . address ;
}
//----------------------------------------------------------------------
// Add a range descriptor and keep things sorted so we can easily
// compact the ranges before being saved or used.
//----------------------------------------------------------------------
void
DWARFDebugArangeSet : : AddDescriptor ( const DWARFDebugArangeSet : : Descriptor & range )
{
if ( m_arange_descriptors . empty ( ) )
{
m_arange_descriptors . push_back ( range ) ;
return ;
}
DescriptorIter end = m_arange_descriptors . end ( ) ;
DescriptorIter pos = lower_bound ( m_arange_descriptors . begin ( ) , end , range , DescriptorLessThan ) ;
const dw_addr_t range_end_addr = range . end_address ( ) ;
if ( pos ! = end )
{
const dw_addr_t found_end_addr = pos - > end_address ( ) ;
if ( range . address < pos - > address )
{
if ( range_end_addr < pos - > address )
{
// Non-contiguous entries, add this one before the found entry
m_arange_descriptors . insert ( pos , range ) ;
}
else if ( range_end_addr = = pos - > address )
{
// The top end of 'range' is the lower end of the entry
// pointed to by 'pos'. We can combine range with the
// entry we found by setting the starting address and
// increasing the length since they don't overlap.
pos - > address = range . address ;
pos - > length + = range . length ;
}
else
{
// We can combine these two and make sure the largest end
// address is used to make end address.
pos - > address = range . address ;
pos - > length = std : : max ( found_end_addr , range_end_addr ) - pos - > address ;
}
}
else if ( range . address = = pos - > address )
{
pos - > length = std : : max ( pos - > length , range . length ) ;
}
}
else
{
// NOTE: 'pos' points to entry past the end which is ok for insert,
// don't use otherwise!!!
const dw_addr_t max_addr = m_arange_descriptors . back ( ) . end_address ( ) ;
if ( max_addr < range . address )
{
// Non-contiguous entries, add this one before the found entry
m_arange_descriptors . insert ( pos , range ) ;
}
else if ( max_addr = = range . address )
{
m_arange_descriptors . back ( ) . length + = range . length ;
}
else
{
m_arange_descriptors . back ( ) . length = std : : max ( max_addr , range_end_addr ) - m_arange_descriptors . back ( ) . address ;
}
}
}
bool
2013-11-06 11:48:53 -05:00
DWARFDebugArangeSet : : Extract ( const DWARFDataExtractor & data , lldb : : offset_t * offset_ptr )
2013-08-23 13:46:38 -04:00
{
if ( data . ValidOffset ( * offset_ptr ) )
{
m_arange_descriptors . clear ( ) ;
m_offset = * offset_ptr ;
// 7.20 Address Range Table
//
// Each set of entries in the table of address ranges contained in
// the .debug_aranges section begins with a header consisting of: a
// 4-byte length containing the length of the set of entries for this
// compilation unit, not including the length field itself; a 2-byte
// version identifier containing the value 2 for DWARF Version 2; a
// 4-byte offset into the.debug_infosection; a 1-byte unsigned integer
// containing the size in bytes of an address (or the offset portion of
// an address for segmented addressing) on the target system; and a
// 1-byte unsigned integer containing the size in bytes of a segment
// descriptor on the target system. This header is followed by a series
// of tuples. Each tuple consists of an address and a length, each in
// the size appropriate for an address on the target architecture.
2013-11-06 11:48:53 -05:00
m_header . length = data . GetDWARFInitialLength ( offset_ptr ) ;
2013-08-23 13:46:38 -04:00
m_header . version = data . GetU16 ( offset_ptr ) ;
2013-11-06 11:48:53 -05:00
m_header . cu_offset = data . GetDWARFOffset ( offset_ptr ) ;
2013-08-23 13:46:38 -04:00
m_header . addr_size = data . GetU8 ( offset_ptr ) ;
m_header . seg_size = data . GetU8 ( offset_ptr ) ;
2014-11-25 16:00:58 -05:00
// Try to avoid reading invalid arange sets by making sure:
// 1 - the version looks good
// 2 - the address byte size looks plausible
// 3 - the length seems to make sense
// size looks plausible
if ( ( m_header . version > = 2 & & m_header . version < = 5 ) & &
( m_header . addr_size = = 4 | | m_header . addr_size = = 8 ) & &
( m_header . length > 0 ) )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
if ( data . ValidOffset ( m_offset + sizeof ( m_header . length ) + m_header . length - 1 ) )
{
// The first tuple following the header in each set begins at an offset
// that is a multiple of the size of a single tuple (that is, twice the
// size of an address). The header is padded, if necessary, to the
// appropriate boundary.
const uint32_t header_size = * offset_ptr - m_offset ;
const uint32_t tuple_size = m_header . addr_size < < 1 ;
uint32_t first_tuple_offset = 0 ;
while ( first_tuple_offset < header_size )
first_tuple_offset + = tuple_size ;
* offset_ptr = m_offset + first_tuple_offset ;
Descriptor arangeDescriptor ;
static_assert ( sizeof ( arangeDescriptor . address ) = = sizeof ( arangeDescriptor . length ) ,
" DWARFDebugArangeSet::Descriptor.address and DWARFDebugArangeSet::Descriptor.length must have same size " ) ;
while ( data . ValidOffset ( * offset_ptr ) )
{
arangeDescriptor . address = data . GetMaxU64 ( offset_ptr , m_header . addr_size ) ;
arangeDescriptor . length = data . GetMaxU64 ( offset_ptr , m_header . addr_size ) ;
// Each set of tuples is terminated by a 0 for the address and 0
// for the length.
if ( arangeDescriptor . address | | arangeDescriptor . length )
m_arange_descriptors . push_back ( arangeDescriptor ) ;
else
break ; // We are done if we get a zero address and length
}
}
# if defined (LLDB_CONFIGURATION_DEBUG)
2013-08-23 13:46:38 -04:00
else
2014-11-25 16:00:58 -05:00
{
printf ( " warning: .debug_arange set length is too large arange data at 0x%8.8x: length=0x%8.8x, version=0x%4.4x, cu_offset=0x%8.8x, addr_size=%u, seg_size=%u \n " ,
m_offset ,
m_header . length ,
m_header . version ,
m_header . cu_offset ,
m_header . addr_size ,
m_header . seg_size ) ;
}
# endif
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
# if defined (LLDB_CONFIGURATION_DEBUG)
else
{
printf ( " warning: .debug_arange set has bad header at 0x%8.8x: length=0x%8.8x, version=0x%4.4x, cu_offset=0x%8.8x, addr_size=%u, seg_size=%u \n " ,
m_offset ,
m_header . length ,
m_header . version ,
m_header . cu_offset ,
m_header . addr_size ,
m_header . seg_size ) ;
}
# endif
2013-08-23 13:46:38 -04:00
return ! m_arange_descriptors . empty ( ) ;
}
return false ;
}
dw_offset_t
DWARFDebugArangeSet : : GetOffsetOfNextEntry ( ) const
{
return m_offset + m_header . length + 4 ;
}
void
DWARFDebugArangeSet : : Dump ( Stream * s ) const
{
s - > Printf ( " Address Range Header: length = 0x%8.8x, version = 0x%4.4x, cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x \n " ,
m_header . length , m_header . version , m_header . cu_offset , m_header . addr_size , m_header . seg_size ) ;
const uint32_t hex_width = m_header . addr_size * 2 ;
DescriptorConstIter pos ;
DescriptorConstIter end = m_arange_descriptors . end ( ) ;
for ( pos = m_arange_descriptors . begin ( ) ; pos ! = end ; + + pos )
s - > Printf ( " [0x%*.* " PRIx64 " - 0x%*.* " PRIx64 " ) \n " ,
hex_width , hex_width , pos - > address ,
hex_width , hex_width , pos - > end_address ( ) ) ;
}
class DescriptorContainsAddress
{
public :
DescriptorContainsAddress ( dw_addr_t address ) : m_address ( address ) { }
bool operator ( ) ( const DWARFDebugArangeSet : : Descriptor & desc ) const
{
return ( m_address > = desc . address ) & & ( m_address < ( desc . address + desc . length ) ) ;
}
private :
const dw_addr_t m_address ;
} ;
dw_offset_t
DWARFDebugArangeSet : : FindAddress ( dw_addr_t address ) const
{
DescriptorConstIter end = m_arange_descriptors . end ( ) ;
DescriptorConstIter pos = std : : find_if ( m_arange_descriptors . begin ( ) , end , // Range
DescriptorContainsAddress ( address ) ) ; // Predicate
if ( pos ! = end )
return m_header . cu_offset ;
return DW_INVALID_OFFSET ;
}