DNBDataRef.cpp revision 36da2aa6dc5ad9994b638ed09eb81c44cc05540b
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// GetCStr
200//----------------------------------------------------------------------
201const char *
202DNBDataRef::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//----------------------------------------------------------------------
222const uint8_t *
223DNBDataRef::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//----------------------------------------------------------------------
238uint64_t
239DNBDataRef::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//----------------------------------------------------------------------
268int64_t
269DNBDataRef::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//----------------------------------------------------------------------
307void
308DNBDataRef::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
322uint32_t
323DNBDataRef::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