Home | History | Annotate | Download | only in dwarf
      1 // Copyright (c) 2010 Google Inc. All Rights Reserved.
      2 //
      3 // Redistribution and use in source and binary forms, with or without
      4 // modification, are permitted provided that the following conditions are
      5 // met:
      6 //
      7 //     * Redistributions of source code must retain the above copyright
      8 // notice, this list of conditions and the following disclaimer.
      9 //     * Redistributions in binary form must reproduce the above
     10 // copyright notice, this list of conditions and the following disclaimer
     11 // in the documentation and/or other materials provided with the
     12 // distribution.
     13 //     * Neither the name of Google Inc. nor the names of its
     14 // contributors may be used to endorse or promote products derived from
     15 // this software without specific prior written permission.
     16 //
     17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 #include <assert.h>
     30 #include <stdlib.h>
     31 
     32 #include "common/dwarf/bytereader-inl.h"
     33 #include "common/dwarf/bytereader.h"
     34 
     35 namespace dwarf2reader {
     36 
     37 ByteReader::ByteReader(enum Endianness endian)
     38     :offset_reader_(NULL), address_reader_(NULL), endian_(endian),
     39      address_size_(0), offset_size_(0),
     40      have_section_base_(), have_text_base_(), have_data_base_(),
     41      have_function_base_() { }
     42 
     43 ByteReader::~ByteReader() { }
     44 
     45 void ByteReader::SetOffsetSize(uint8 size) {
     46   offset_size_ = size;
     47   assert(size == 4 || size == 8);
     48   if (size == 4) {
     49     this->offset_reader_ = &ByteReader::ReadFourBytes;
     50   } else {
     51     this->offset_reader_ = &ByteReader::ReadEightBytes;
     52   }
     53 }
     54 
     55 void ByteReader::SetAddressSize(uint8 size) {
     56   address_size_ = size;
     57   assert(size == 4 || size == 8);
     58   if (size == 4) {
     59     this->address_reader_ = &ByteReader::ReadFourBytes;
     60   } else {
     61     this->address_reader_ = &ByteReader::ReadEightBytes;
     62   }
     63 }
     64 
     65 uint64 ByteReader::ReadInitialLength(const char* start, size_t* len) {
     66   const uint64 initial_length = ReadFourBytes(start);
     67   start += 4;
     68 
     69   // In DWARF2/3, if the initial length is all 1 bits, then the offset
     70   // size is 8 and we need to read the next 8 bytes for the real length.
     71   if (initial_length == 0xffffffff) {
     72     SetOffsetSize(8);
     73     *len = 12;
     74     return ReadOffset(start);
     75   } else {
     76     SetOffsetSize(4);
     77     *len = 4;
     78   }
     79   return initial_length;
     80 }
     81 
     82 bool ByteReader::ValidEncoding(DwarfPointerEncoding encoding) const {
     83   if (encoding == DW_EH_PE_omit) return true;
     84   if (encoding == DW_EH_PE_aligned) return true;
     85   if ((encoding & 0x7) > DW_EH_PE_udata8)
     86     return false;
     87   if ((encoding & 0x70) > DW_EH_PE_funcrel)
     88     return false;
     89   return true;
     90 }
     91 
     92 bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const {
     93   switch (encoding & 0x70) {
     94     case DW_EH_PE_absptr:  return true;
     95     case DW_EH_PE_pcrel:   return have_section_base_;
     96     case DW_EH_PE_textrel: return have_text_base_;
     97     case DW_EH_PE_datarel: return have_data_base_;
     98     case DW_EH_PE_funcrel: return have_function_base_;
     99     default:               return false;
    100   }
    101 }
    102 
    103 uint64 ByteReader::ReadEncodedPointer(const char *buffer,
    104                                       DwarfPointerEncoding encoding,
    105                                       size_t *len) const {
    106   // UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't
    107   // see it here.
    108   assert(encoding != DW_EH_PE_omit);
    109 
    110   // The Linux Standards Base 4.0 does not make this clear, but the
    111   // GNU tools (gcc/unwind-pe.h; readelf/dwarf.c; gdb/dwarf2-frame.c)
    112   // agree that aligned pointers are always absolute, machine-sized,
    113   // machine-signed pointers.
    114   if (encoding == DW_EH_PE_aligned) {
    115     assert(have_section_base_);
    116 
    117     // We don't need to align BUFFER in *our* address space. Rather, we
    118     // need to find the next position in our buffer that would be aligned
    119     // when the .eh_frame section the buffer contains is loaded into the
    120     // program's memory. So align assuming that buffer_base_ gets loaded at
    121     // address section_base_, where section_base_ itself may or may not be
    122     // aligned.
    123 
    124     // First, find the offset to START from the closest prior aligned
    125     // address.
    126     uint64 skew = section_base_ & (AddressSize() - 1);
    127     // Now find the offset from that aligned address to buffer.
    128     uint64 offset = skew + (buffer - buffer_base_);
    129     // Round up to the next boundary.
    130     uint64 aligned = (offset + AddressSize() - 1) & -AddressSize();
    131     // Convert back to a pointer.
    132     const char *aligned_buffer = buffer_base_ + (aligned - skew);
    133     // Finally, store the length and actually fetch the pointer.
    134     *len = aligned_buffer - buffer + AddressSize();
    135     return ReadAddress(aligned_buffer);
    136   }
    137 
    138   // Extract the value first, ignoring whether it's a pointer or an
    139   // offset relative to some base.
    140   uint64 offset;
    141   switch (encoding & 0x0f) {
    142     case DW_EH_PE_absptr:
    143       // DW_EH_PE_absptr is weird, as it is used as a meaningful value for
    144       // both the high and low nybble of encoding bytes. When it appears in
    145       // the high nybble, it means that the pointer is absolute, not an
    146       // offset from some base address. When it appears in the low nybble,
    147       // as here, it means that the pointer is stored as a normal
    148       // machine-sized and machine-signed address. A low nybble of
    149       // DW_EH_PE_absptr does not imply that the pointer is absolute; it is
    150       // correct for us to treat the value as an offset from a base address
    151       // if the upper nybble is not DW_EH_PE_absptr.
    152       offset = ReadAddress(buffer);
    153       *len = AddressSize();
    154       break;
    155 
    156     case DW_EH_PE_uleb128:
    157       offset = ReadUnsignedLEB128(buffer, len);
    158       break;
    159 
    160     case DW_EH_PE_udata2:
    161       offset = ReadTwoBytes(buffer);
    162       *len = 2;
    163       break;
    164 
    165     case DW_EH_PE_udata4:
    166       offset = ReadFourBytes(buffer);
    167       *len = 4;
    168       break;
    169 
    170     case DW_EH_PE_udata8:
    171       offset = ReadEightBytes(buffer);
    172       *len = 8;
    173       break;
    174 
    175     case DW_EH_PE_sleb128:
    176       offset = ReadSignedLEB128(buffer, len);
    177       break;
    178 
    179     case DW_EH_PE_sdata2:
    180       offset = ReadTwoBytes(buffer);
    181       // Sign-extend from 16 bits.
    182       offset = (offset ^ 0x8000) - 0x8000;
    183       *len = 2;
    184       break;
    185 
    186     case DW_EH_PE_sdata4:
    187       offset = ReadFourBytes(buffer);
    188       // Sign-extend from 32 bits.
    189       offset = (offset ^ 0x80000000ULL) - 0x80000000ULL;
    190       *len = 4;
    191       break;
    192 
    193     case DW_EH_PE_sdata8:
    194       // No need to sign-extend; this is the full width of our type.
    195       offset = ReadEightBytes(buffer);
    196       *len = 8;
    197       break;
    198 
    199     default:
    200       abort();
    201   }
    202 
    203   // Find the appropriate base address.
    204   uint64 base;
    205   switch (encoding & 0x70) {
    206     case DW_EH_PE_absptr:
    207       base = 0;
    208       break;
    209 
    210     case DW_EH_PE_pcrel:
    211       assert(have_section_base_);
    212       base = section_base_ + (buffer - buffer_base_);
    213       break;
    214 
    215     case DW_EH_PE_textrel:
    216       assert(have_text_base_);
    217       base = text_base_;
    218       break;
    219 
    220     case DW_EH_PE_datarel:
    221       assert(have_data_base_);
    222       base = data_base_;
    223       break;
    224 
    225     case DW_EH_PE_funcrel:
    226       assert(have_function_base_);
    227       base = function_base_;
    228       break;
    229 
    230     default:
    231       abort();
    232   }
    233 
    234   uint64 pointer = base + offset;
    235 
    236   // Remove inappropriate upper bits.
    237   if (AddressSize() == 4)
    238     pointer = pointer & 0xffffffff;
    239   else
    240     assert(AddressSize() == sizeof(uint64));
    241 
    242   return pointer;
    243 }
    244 
    245 }  // namespace dwarf2reader
    246