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
DNBDataRef()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
DNBDataRef(const uint8_t * start,size_t size,bool swap)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
~DNBDataRef()56 DNBDataRef::~DNBDataRef()
57 {
58 }
59
60
61 //----------------------------------------------------------------------
62 // Get8
63 //----------------------------------------------------------------------
64 uint8_t
Get8(offset_t * offset_ptr) const65 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
Get16(offset_t * offset_ptr) const81 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
Get32(offset_t * offset_ptr) const103 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
Get64(offset_t * offset_ptr) const124 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
GetMax32(offset_t * offset_ptr,uint32_t byte_size) const148 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
GetMax64(offset_t * offset_ptr,uint32_t size) const170 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
GetPointer(offset_t * offset_ptr) const192 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 *
GetCStr(offset_t * offset_ptr,uint32_t fixed_length) const202 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 *
GetData(offset_t * offset_ptr,uint32_t length) const223 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
Get_ULEB128(offset_t * offset_ptr) const239 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
Get_SLEB128(offset_t * offset_ptr) const269 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
Skip_LEB128(offset_t * offset_ptr) const308 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
Dump(uint32_t startOffset,uint32_t endOffset,uint64_t offsetBase,DNBDataRef::Type type,uint32_t numPerLine,const char * format)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