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 //----------------------------------------------------------------------
200 // GetDwarfEHPtr
201 //
202 // Used for calls when the value type is specified by a DWARF EH Frame
203 // pointer encoding.
204 //----------------------------------------------------------------------
205 /*
206 uint64_t
207 DNBDataRef::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 //----------------------------------------------------------------------
300 const char *
301 DNBDataRef::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 //----------------------------------------------------------------------
321 const uint8_t *
322 DNBDataRef::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 //----------------------------------------------------------------------
337 uint64_t
338 DNBDataRef::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 //----------------------------------------------------------------------
367 int64_t
368 DNBDataRef::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 //----------------------------------------------------------------------
406 void
407 DNBDataRef::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 
421 uint32_t
422 DNBDataRef::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