DNBDataRef.cpp revision 7559f33de7b3706324fcc8467179463f7aaec348
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
24DNBDataRef::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
40DNBDataRef::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
56DNBDataRef::~DNBDataRef()
57{
58}
59
60
61//----------------------------------------------------------------------
62// Get8
63//----------------------------------------------------------------------
64uint8_t
65DNBDataRef::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//----------------------------------------------------------------------
80uint16_t
81DNBDataRef::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//----------------------------------------------------------------------
102uint32_t
103DNBDataRef::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//----------------------------------------------------------------------
123uint64_t
124DNBDataRef::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//----------------------------------------------------------------------
147uint32_t
148DNBDataRef::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//----------------------------------------------------------------------
169uint64_t
170DNBDataRef::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//----------------------------------------------------------------------
191uint64_t
192DNBDataRef::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//----------------------------------------------------------------------
200// GetDwarfEHPtr
201//
202// Used for calls when the value type is specified by a DWARF EH Frame
203// pointer encoding.
204//----------------------------------------------------------------------
205/*
206uint64_t
207DNBDataRef::GetDwarfEHPtr(offset_t *offset_ptr, uint32_t encoding) const
208{
209    if (encoding == DW_EH_PE_omit)
210        return ULLONG_MAX;    // Value isn't in the buffer...
211
212    uint64_t baseAddress = 0;
213    uint64_t addressValue = 0;
214
215    BOOL signExtendValue = NO;
216    // Decode the base part or adjust our offset
217    switch (encoding & 0x70)
218    {
219        case DW_EH_PE_pcrel:
220            // SetEHPtrBaseAddresses should be called prior to extracting these
221            // so the base addresses are cached.
222            assert(m_addrPCRelative != INVALID_NUB_ADDRESS);
223            signExtendValue = YES;
224            baseAddress = *offset_ptr + m_addrPCRelative;
225            break;
226
227        case DW_EH_PE_textrel:
228            // SetEHPtrBaseAddresses should be called prior to extracting these
229            // so the base addresses are cached.
230            assert(m_addrTEXT != INVALID_NUB_ADDRESS);
231            signExtendValue = YES;
232            baseAddress = m_addrTEXT;
233            break;
234
235        case DW_EH_PE_datarel:
236            // SetEHPtrBaseAddresses should be called prior to extracting these
237            // so the base addresses are cached.
238            assert(m_addrDATA != INVALID_NUB_ADDRESS);
239            signExtendValue = YES;
240            baseAddress = m_addrDATA;
241            break;
242
243        case DW_EH_PE_funcrel:
244            signExtendValue = YES;
245            break;
246
247        case DW_EH_PE_aligned:
248            // SetPointerSize should be called prior to extracting these so the
249            // pointer size is cached
250            assert(m_ptrSize != 0);
251            if (m_ptrSize)
252            {
253                // Align to a address size boundary first
254                uint32_t alignOffset = *offset_ptr % m_ptrSize;
255                if (alignOffset)
256                    offset_ptr += m_ptrSize - alignOffset;
257            }
258                break;
259
260        default:
261            break;
262    }
263
264    // Decode the value part
265    switch (encoding & DW_EH_PE_MASK_ENCODING)
266    {
267        case DW_EH_PE_absptr    : addressValue = GetPointer(offset_ptr);         break;
268        case DW_EH_PE_uleb128   : addressValue = Get_ULEB128(offset_ptr);         break;
269        case DW_EH_PE_udata2    : addressValue = Get16(offset_ptr);                 break;
270        case DW_EH_PE_udata4    : addressValue = Get32(offset_ptr);                 break;
271        case DW_EH_PE_udata8    : addressValue = Get64(offset_ptr);                 break;
272        case DW_EH_PE_sleb128   : addressValue = Get_SLEB128(offset_ptr);         break;
273        case DW_EH_PE_sdata2    : addressValue = (int16_t)Get16(offset_ptr);     break;
274        case DW_EH_PE_sdata4    : addressValue = (int32_t)Get32(offset_ptr);     break;
275        case DW_EH_PE_sdata8    : addressValue = (int64_t)Get64(offset_ptr);     break;
276        default:
277            // Unhandled encoding type
278            assert(encoding);
279            break;
280    }
281
282    // Since we promote everything to 64 bit, we may need to sign extend
283    if (signExtendValue && m_ptrSize < sizeof(baseAddress))
284    {
285        uint64_t sign_bit = 1ull << ((m_ptrSize * 8ull) - 1ull);
286        if (sign_bit & addressValue)
287        {
288            uint64_t mask = ~sign_bit + 1;
289            addressValue |= mask;
290        }
291    }
292    return baseAddress + addressValue;
293}
294*/
295
296
297//----------------------------------------------------------------------
298// GetCStr
299//----------------------------------------------------------------------
300const char *
301DNBDataRef::GetCStr(offset_t *offset_ptr, uint32_t fixed_length) const
302{
303    const char *s = NULL;
304    if ( m_start < m_end )
305    {
306        s = (char*)m_start + *offset_ptr;
307
308        // Advance the offset
309        if (fixed_length)
310            *offset_ptr += fixed_length;
311        else
312            *offset_ptr += strlen(s) + 1;
313    }
314    return s;
315}
316
317
318//----------------------------------------------------------------------
319// GetData
320//----------------------------------------------------------------------
321const uint8_t *
322DNBDataRef::GetData(offset_t *offset_ptr, uint32_t length) const
323{
324    const uint8_t *data = NULL;
325    if ( length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length) )
326    {
327        data = m_start + *offset_ptr;
328        *offset_ptr += length;
329    }
330    return data;
331}
332
333
334//----------------------------------------------------------------------
335// Get_ULEB128
336//----------------------------------------------------------------------
337uint64_t
338DNBDataRef::Get_ULEB128 (offset_t *offset_ptr) const
339{
340    uint64_t result = 0;
341    if ( m_start < m_end )
342    {
343        int shift = 0;
344        const uint8_t *src = m_start + *offset_ptr;
345        uint8_t byte;
346        int bytecount = 0;
347
348        while (src < m_end)
349        {
350            bytecount++;
351            byte = *src++;
352            result |= (byte & 0x7f) << shift;
353            shift += 7;
354            if ((byte & 0x80) == 0)
355                break;
356        }
357
358        *offset_ptr += bytecount;
359    }
360    return result;
361}
362
363
364//----------------------------------------------------------------------
365// Get_SLEB128
366//----------------------------------------------------------------------
367int64_t
368DNBDataRef::Get_SLEB128 (offset_t *offset_ptr) const
369{
370    int64_t result = 0;
371
372    if ( m_start < m_end )
373    {
374        int shift = 0;
375        int size = sizeof (uint32_t) * 8;
376        const uint8_t *src = m_start + *offset_ptr;
377
378        uint8_t byte = 0;
379        int bytecount = 0;
380
381        while (src < m_end)
382        {
383            bytecount++;
384            byte = *src++;
385            result |= (byte & 0x7f) << shift;
386            shift += 7;
387            if ((byte & 0x80) == 0)
388                break;
389        }
390
391        // Sign bit of byte is 2nd high order bit (0x40)
392        if (shift < size && (byte & 0x40))
393            result |= - (1ll << shift);
394
395        *offset_ptr += bytecount;
396    }
397    return result;
398}
399
400
401//----------------------------------------------------------------------
402// Skip_LEB128
403//
404// Skips past ULEB128 and SLEB128 numbers (just updates the offset)
405//----------------------------------------------------------------------
406void
407DNBDataRef::Skip_LEB128 (offset_t *offset_ptr) const
408{
409    if ( m_start < m_end )
410    {
411        const uint8_t *start = m_start + *offset_ptr;
412        const uint8_t *src = start;
413
414        while ((src < m_end) && (*src++ & 0x80))
415            /* Do nothing */;
416
417        *offset_ptr += src - start;
418    }
419}
420
421uint32_t
422DNBDataRef::Dump
423(
424    uint32_t startOffset,
425    uint32_t endOffset,
426    uint64_t offsetBase,
427    DNBDataRef::Type type,
428    uint32_t numPerLine,
429    const char *format
430)
431{
432    uint32_t offset;
433    uint32_t count;
434    char str[1024];
435    str[0] = '\0';
436    int str_offset = 0;
437
438    for (offset = startOffset, count = 0; ValidOffset(offset) && offset < endOffset; ++count)
439    {
440        if ((count % numPerLine) == 0)
441        {
442            // Print out any previous string
443            if (str[0] != '\0')
444                DNBLog("%s", str);
445            // Reset string offset and fill the current line string with address:
446            str_offset = 0;
447            str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", (uint64_t)(offsetBase + (offset - startOffset)));
448        }
449
450        // Make sure we don't pass the bounds of our current string buffer on each iteration through this loop
451        if (str_offset >= sizeof(str))
452        {
453            // The last snprintf consumed our string buffer, we will need to dump this out
454            // and reset the string with no address
455            DNBLog("%s", str);
456            str_offset = 0;
457            str[0] = '\0';
458        }
459
460        // We already checked that there is at least some room in the string str above, so it is safe to make
461        // the snprintf call each time through this loop
462        switch (type)
463        {
464            default:
465            case TypeUInt8:   str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %2.2x", Get8(&offset)); break;
466            case TypeChar:
467                {
468                    char ch = Get8(&offset);
469                    str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %c",    isprint(ch) ? ch : ' ');
470                }
471                break;
472            case TypeUInt16:  str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %4.4x",       Get16(&offset)); break;
473            case TypeUInt32:  str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %8.8x",       Get32(&offset)); break;
474            case TypeUInt64:  str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %16.16llx",   Get64(&offset)); break;
475            case TypePointer: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx",      GetPointer(&offset)); break;
476            case TypeULEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx",      Get_ULEB128(&offset)); break;
477            case TypeSLEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %lld",        Get_SLEB128(&offset)); break;
478        }
479    }
480
481    if (str[0] != '\0')
482        DNBLog("%s", str);
483
484    return offset;  // Return the offset at which we ended up
485}
486