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