Home | History | Annotate | Download | only in source
      1 //===-- DNBDataRef.cpp ------------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  Created by Greg Clayton on 1/11/06.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "DNBDataRef.h"
     15 #include "DNBLog.h"
     16 #include <assert.h>
     17 #include <ctype.h>
     18 #include <libkern/OSByteOrder.h>
     19 
     20 //----------------------------------------------------------------------
     21 // Constructor
     22 //----------------------------------------------------------------------
     23 
     24 DNBDataRef::DNBDataRef() :
     25     m_start(NULL),
     26     m_end(NULL),
     27     m_swap(false),
     28     m_ptrSize(0),
     29     m_addrPCRelative(INVALID_NUB_ADDRESS),
     30     m_addrTEXT(INVALID_NUB_ADDRESS),
     31     m_addrDATA(INVALID_NUB_ADDRESS)
     32 {
     33 }
     34 
     35 
     36 //----------------------------------------------------------------------
     37 // Constructor
     38 //----------------------------------------------------------------------
     39 
     40 DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap) :
     41     m_start(start),
     42     m_end(start+size),
     43     m_swap(swap),
     44     m_ptrSize(0),
     45     m_addrPCRelative(INVALID_NUB_ADDRESS),
     46     m_addrTEXT(INVALID_NUB_ADDRESS),
     47     m_addrDATA(INVALID_NUB_ADDRESS)
     48 {
     49 }
     50 
     51 
     52 //----------------------------------------------------------------------
     53 // Destructor
     54 //----------------------------------------------------------------------
     55 
     56 DNBDataRef::~DNBDataRef()
     57 {
     58 }
     59 
     60 
     61 //----------------------------------------------------------------------
     62 // Get8
     63 //----------------------------------------------------------------------
     64 uint8_t
     65 DNBDataRef::Get8(offset_t *offset_ptr) const
     66 {
     67     uint8_t val = 0;
     68     if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) )
     69     {
     70         val = *(m_start + *offset_ptr);
     71         *offset_ptr += sizeof(val);
     72     }
     73     return val;
     74 }
     75 
     76 
     77 //----------------------------------------------------------------------
     78 // Get16
     79 //----------------------------------------------------------------------
     80 uint16_t
     81 DNBDataRef::Get16(offset_t *offset_ptr) const
     82 {
     83     uint16_t val = 0;
     84     if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) )
     85     {
     86         const uint8_t *p = m_start + *offset_ptr;
     87         val = *(uint16_t*)p;
     88 
     89         if (m_swap)
     90             val = OSSwapInt16(val);
     91 
     92         // Advance the offset
     93         *offset_ptr += sizeof(val);
     94     }
     95     return val;
     96 }
     97 
     98 
     99 //----------------------------------------------------------------------
    100 // Get32
    101 //----------------------------------------------------------------------
    102 uint32_t
    103 DNBDataRef::Get32(offset_t *offset_ptr) const
    104 {
    105     uint32_t val = 0;
    106     if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) )
    107     {
    108         const uint8_t *p = m_start + *offset_ptr;
    109         val = *(uint32_t*)p;
    110         if (m_swap)
    111             val = OSSwapInt32(val);
    112 
    113         // Advance the offset
    114         *offset_ptr += sizeof(val);
    115     }
    116     return val;
    117 }
    118 
    119 
    120 //----------------------------------------------------------------------
    121 // Get64
    122 //----------------------------------------------------------------------
    123 uint64_t
    124 DNBDataRef::Get64(offset_t *offset_ptr) const
    125 {
    126     uint64_t val = 0;
    127     if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) )
    128     {
    129         const uint8_t *p = m_start + *offset_ptr;
    130         val = *(uint64_t*)p;
    131         if (m_swap)
    132             val = OSSwapInt64(val);
    133 
    134         // Advance the offset
    135         *offset_ptr += sizeof(val);
    136     }
    137     return val;
    138 }
    139 
    140 
    141 //----------------------------------------------------------------------
    142 // GetMax32
    143 //
    144 // Used for calls when the size can vary. Fill in extra cases if they
    145 // are ever needed.
    146 //----------------------------------------------------------------------
    147 uint32_t
    148 DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const
    149 {
    150     switch (byte_size)
    151     {
    152         case 1: return Get8 (offset_ptr); break;
    153         case 2: return Get16(offset_ptr); break;
    154         case 4:    return Get32(offset_ptr); break;
    155         default:
    156         assert(!"GetMax32 unhandled case!");
    157             break;
    158     }
    159     return 0;
    160 }
    161 
    162 
    163 //----------------------------------------------------------------------
    164 // GetMax64
    165 //
    166 // Used for calls when the size can vary. Fill in extra cases if they
    167 // are ever needed.
    168 //----------------------------------------------------------------------
    169 uint64_t
    170 DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const
    171 {
    172     switch (size)
    173     {
    174         case 1: return Get8 (offset_ptr); break;
    175         case 2: return Get16(offset_ptr); break;
    176         case 4: return Get32(offset_ptr); break;
    177         case 8: return Get64(offset_ptr); break;
    178         default:
    179         assert(!"GetMax64 unhandled case!");
    180             break;
    181     }
    182     return 0;
    183 }
    184 
    185 //----------------------------------------------------------------------
    186 // GetPointer
    187 //
    188 // Extract a pointer value from the buffer. The pointer size must be
    189 // set prior to using this using one of the SetPointerSize functions.
    190 //----------------------------------------------------------------------
    191 uint64_t
    192 DNBDataRef::GetPointer(offset_t *offset_ptr) const
    193 {
    194     // Must set pointer size prior to using this call
    195     assert(m_ptrSize != 0);
    196     return GetMax64(offset_ptr, m_ptrSize);
    197 }
    198 //----------------------------------------------------------------------
    199 // GetCStr
    200 //----------------------------------------------------------------------
    201 const char *
    202 DNBDataRef::GetCStr(offset_t *offset_ptr, uint32_t fixed_length) const
    203 {
    204     const char *s = NULL;
    205     if ( m_start < m_end )
    206     {
    207         s = (char*)m_start + *offset_ptr;
    208 
    209         // Advance the offset
    210         if (fixed_length)
    211             *offset_ptr += fixed_length;
    212         else
    213             *offset_ptr += strlen(s) + 1;
    214     }
    215     return s;
    216 }
    217 
    218 
    219 //----------------------------------------------------------------------
    220 // GetData
    221 //----------------------------------------------------------------------
    222 const uint8_t *
    223 DNBDataRef::GetData(offset_t *offset_ptr, uint32_t length) const
    224 {
    225     const uint8_t *data = NULL;
    226     if ( length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length) )
    227     {
    228         data = m_start + *offset_ptr;
    229         *offset_ptr += length;
    230     }
    231     return data;
    232 }
    233 
    234 
    235 //----------------------------------------------------------------------
    236 // Get_ULEB128
    237 //----------------------------------------------------------------------
    238 uint64_t
    239 DNBDataRef::Get_ULEB128 (offset_t *offset_ptr) const
    240 {
    241     uint64_t result = 0;
    242     if ( m_start < m_end )
    243     {
    244         int shift = 0;
    245         const uint8_t *src = m_start + *offset_ptr;
    246         uint8_t byte;
    247         int bytecount = 0;
    248 
    249         while (src < m_end)
    250         {
    251             bytecount++;
    252             byte = *src++;
    253             result |= (byte & 0x7f) << shift;
    254             shift += 7;
    255             if ((byte & 0x80) == 0)
    256                 break;
    257         }
    258 
    259         *offset_ptr += bytecount;
    260     }
    261     return result;
    262 }
    263 
    264 
    265 //----------------------------------------------------------------------
    266 // Get_SLEB128
    267 //----------------------------------------------------------------------
    268 int64_t
    269 DNBDataRef::Get_SLEB128 (offset_t *offset_ptr) const
    270 {
    271     int64_t result = 0;
    272 
    273     if ( m_start < m_end )
    274     {
    275         int shift = 0;
    276         int size = sizeof (uint32_t) * 8;
    277         const uint8_t *src = m_start + *offset_ptr;
    278 
    279         uint8_t byte = 0;
    280         int bytecount = 0;
    281 
    282         while (src < m_end)
    283         {
    284             bytecount++;
    285             byte = *src++;
    286             result |= (byte & 0x7f) << shift;
    287             shift += 7;
    288             if ((byte & 0x80) == 0)
    289                 break;
    290         }
    291 
    292         // Sign bit of byte is 2nd high order bit (0x40)
    293         if (shift < size && (byte & 0x40))
    294             result |= - (1ll << shift);
    295 
    296         *offset_ptr += bytecount;
    297     }
    298     return result;
    299 }
    300 
    301 
    302 //----------------------------------------------------------------------
    303 // Skip_LEB128
    304 //
    305 // Skips past ULEB128 and SLEB128 numbers (just updates the offset)
    306 //----------------------------------------------------------------------
    307 void
    308 DNBDataRef::Skip_LEB128 (offset_t *offset_ptr) const
    309 {
    310     if ( m_start < m_end )
    311     {
    312         const uint8_t *start = m_start + *offset_ptr;
    313         const uint8_t *src = start;
    314 
    315         while ((src < m_end) && (*src++ & 0x80))
    316             /* Do nothing */;
    317 
    318         *offset_ptr += src - start;
    319     }
    320 }
    321 
    322 uint32_t
    323 DNBDataRef::Dump
    324 (
    325     uint32_t startOffset,
    326     uint32_t endOffset,
    327     uint64_t offsetBase,
    328     DNBDataRef::Type type,
    329     uint32_t numPerLine,
    330     const char *format
    331 )
    332 {
    333     uint32_t offset;
    334     uint32_t count;
    335     char str[1024];
    336     str[0] = '\0';
    337     int str_offset = 0;
    338 
    339     for (offset = startOffset, count = 0; ValidOffset(offset) && offset < endOffset; ++count)
    340     {
    341         if ((count % numPerLine) == 0)
    342         {
    343             // Print out any previous string
    344             if (str[0] != '\0')
    345                 DNBLog("%s", str);
    346             // Reset string offset and fill the current line string with address:
    347             str_offset = 0;
    348             str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", (uint64_t)(offsetBase + (offset - startOffset)));
    349         }
    350 
    351         // Make sure we don't pass the bounds of our current string buffer on each iteration through this loop
    352         if (str_offset >= sizeof(str))
    353         {
    354             // The last snprintf consumed our string buffer, we will need to dump this out
    355             // and reset the string with no address
    356             DNBLog("%s", str);
    357             str_offset = 0;
    358             str[0] = '\0';
    359         }
    360 
    361         // We already checked that there is at least some room in the string str above, so it is safe to make
    362         // the snprintf call each time through this loop
    363         switch (type)
    364         {
    365             default:
    366             case TypeUInt8:   str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %2.2x", Get8(&offset)); break;
    367             case TypeChar:
    368                 {
    369                     char ch = Get8(&offset);
    370                     str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %c",    isprint(ch) ? ch : ' ');
    371                 }
    372                 break;
    373             case TypeUInt16:  str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %4.4x",       Get16(&offset)); break;
    374             case TypeUInt32:  str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %8.8x",       Get32(&offset)); break;
    375             case TypeUInt64:  str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %16.16llx",   Get64(&offset)); break;
    376             case TypePointer: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx",      GetPointer(&offset)); break;
    377             case TypeULEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx",      Get_ULEB128(&offset)); break;
    378             case TypeSLEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %lld",        Get_SLEB128(&offset)); break;
    379         }
    380     }
    381 
    382     if (str[0] != '\0')
    383         DNBLog("%s", str);
    384 
    385     return offset;  // Return the offset at which we ended up
    386 }
    387