130fdc8d8SChris Lattner //===-- DNBDataRef.cpp ------------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner //
1030fdc8d8SChris Lattner //  Created by Greg Clayton on 1/11/06.
1130fdc8d8SChris Lattner //
1230fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1330fdc8d8SChris Lattner 
1430fdc8d8SChris Lattner #include "DNBDataRef.h"
1530fdc8d8SChris Lattner #include "DNBLog.h"
1630fdc8d8SChris Lattner #include <assert.h>
1730fdc8d8SChris Lattner #include <ctype.h>
1830fdc8d8SChris Lattner #include <libkern/OSByteOrder.h>
1930fdc8d8SChris Lattner 
2030fdc8d8SChris Lattner //----------------------------------------------------------------------
2130fdc8d8SChris Lattner // Constructor
2230fdc8d8SChris Lattner //----------------------------------------------------------------------
2330fdc8d8SChris Lattner 
24b9c1b51eSKate Stone DNBDataRef::DNBDataRef()
25b9c1b51eSKate Stone     : m_start(NULL), m_end(NULL), m_swap(false), m_ptrSize(0),
26b9c1b51eSKate Stone       m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS),
27b9c1b51eSKate Stone       m_addrDATA(INVALID_NUB_ADDRESS) {}
2830fdc8d8SChris Lattner 
2930fdc8d8SChris Lattner //----------------------------------------------------------------------
3030fdc8d8SChris Lattner // Constructor
3130fdc8d8SChris Lattner //----------------------------------------------------------------------
3230fdc8d8SChris Lattner 
33b9c1b51eSKate Stone DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap)
34b9c1b51eSKate Stone     : m_start(start), m_end(start + size), m_swap(swap), m_ptrSize(0),
35b9c1b51eSKate Stone       m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS),
36b9c1b51eSKate Stone       m_addrDATA(INVALID_NUB_ADDRESS) {}
3730fdc8d8SChris Lattner 
3830fdc8d8SChris Lattner //----------------------------------------------------------------------
3930fdc8d8SChris Lattner // Destructor
4030fdc8d8SChris Lattner //----------------------------------------------------------------------
4130fdc8d8SChris Lattner 
42b9c1b51eSKate Stone DNBDataRef::~DNBDataRef() {}
4330fdc8d8SChris Lattner 
4430fdc8d8SChris Lattner //----------------------------------------------------------------------
4530fdc8d8SChris Lattner // Get8
4630fdc8d8SChris Lattner //----------------------------------------------------------------------
47b9c1b51eSKate Stone uint8_t DNBDataRef::Get8(offset_t *offset_ptr) const {
4830fdc8d8SChris Lattner   uint8_t val = 0;
49b9c1b51eSKate Stone   if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
5030fdc8d8SChris Lattner     val = *(m_start + *offset_ptr);
5130fdc8d8SChris Lattner     *offset_ptr += sizeof(val);
5230fdc8d8SChris Lattner   }
5330fdc8d8SChris Lattner   return val;
5430fdc8d8SChris Lattner }
5530fdc8d8SChris Lattner 
5630fdc8d8SChris Lattner //----------------------------------------------------------------------
5730fdc8d8SChris Lattner // Get16
5830fdc8d8SChris Lattner //----------------------------------------------------------------------
59b9c1b51eSKate Stone uint16_t DNBDataRef::Get16(offset_t *offset_ptr) const {
6030fdc8d8SChris Lattner   uint16_t val = 0;
61b9c1b51eSKate Stone   if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
6230fdc8d8SChris Lattner     const uint8_t *p = m_start + *offset_ptr;
6330fdc8d8SChris Lattner     val = *(uint16_t *)p;
6430fdc8d8SChris Lattner 
6530fdc8d8SChris Lattner     if (m_swap)
6630fdc8d8SChris Lattner       val = OSSwapInt16(val);
6730fdc8d8SChris Lattner 
6830fdc8d8SChris Lattner     // Advance the offset
6930fdc8d8SChris Lattner     *offset_ptr += sizeof(val);
7030fdc8d8SChris Lattner   }
7130fdc8d8SChris Lattner   return val;
7230fdc8d8SChris Lattner }
7330fdc8d8SChris Lattner 
7430fdc8d8SChris Lattner //----------------------------------------------------------------------
7530fdc8d8SChris Lattner // Get32
7630fdc8d8SChris Lattner //----------------------------------------------------------------------
77b9c1b51eSKate Stone uint32_t DNBDataRef::Get32(offset_t *offset_ptr) const {
7830fdc8d8SChris Lattner   uint32_t val = 0;
79b9c1b51eSKate Stone   if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
8030fdc8d8SChris Lattner     const uint8_t *p = m_start + *offset_ptr;
8130fdc8d8SChris Lattner     val = *(uint32_t *)p;
8230fdc8d8SChris Lattner     if (m_swap)
8330fdc8d8SChris Lattner       val = OSSwapInt32(val);
8430fdc8d8SChris Lattner 
8530fdc8d8SChris Lattner     // Advance the offset
8630fdc8d8SChris Lattner     *offset_ptr += sizeof(val);
8730fdc8d8SChris Lattner   }
8830fdc8d8SChris Lattner   return val;
8930fdc8d8SChris Lattner }
9030fdc8d8SChris Lattner 
9130fdc8d8SChris Lattner //----------------------------------------------------------------------
9230fdc8d8SChris Lattner // Get64
9330fdc8d8SChris Lattner //----------------------------------------------------------------------
94b9c1b51eSKate Stone uint64_t DNBDataRef::Get64(offset_t *offset_ptr) const {
9530fdc8d8SChris Lattner   uint64_t val = 0;
96b9c1b51eSKate Stone   if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
9730fdc8d8SChris Lattner     const uint8_t *p = m_start + *offset_ptr;
9830fdc8d8SChris Lattner     val = *(uint64_t *)p;
9930fdc8d8SChris Lattner     if (m_swap)
10030fdc8d8SChris Lattner       val = OSSwapInt64(val);
10130fdc8d8SChris Lattner 
10230fdc8d8SChris Lattner     // Advance the offset
10330fdc8d8SChris Lattner     *offset_ptr += sizeof(val);
10430fdc8d8SChris Lattner   }
10530fdc8d8SChris Lattner   return val;
10630fdc8d8SChris Lattner }
10730fdc8d8SChris Lattner 
10830fdc8d8SChris Lattner //----------------------------------------------------------------------
10930fdc8d8SChris Lattner // GetMax32
11030fdc8d8SChris Lattner //
11130fdc8d8SChris Lattner // Used for calls when the size can vary. Fill in extra cases if they
11230fdc8d8SChris Lattner // are ever needed.
11330fdc8d8SChris Lattner //----------------------------------------------------------------------
114b9c1b51eSKate Stone uint32_t DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const {
115b9c1b51eSKate Stone   switch (byte_size) {
116b9c1b51eSKate Stone   case 1:
117b9c1b51eSKate Stone     return Get8(offset_ptr);
118*a77ec68eSDavid Blaikie     break;
119b9c1b51eSKate Stone   case 2:
120b9c1b51eSKate Stone     return Get16(offset_ptr);
121*a77ec68eSDavid Blaikie     break;
122b9c1b51eSKate Stone   case 4:
123b9c1b51eSKate Stone     return Get32(offset_ptr);
124*a77ec68eSDavid Blaikie     break;
12530fdc8d8SChris Lattner   default:
126*a77ec68eSDavid Blaikie     assert(!"GetMax32 unhandled case!");
127*a77ec68eSDavid Blaikie     break;
12830fdc8d8SChris Lattner   }
129*a77ec68eSDavid Blaikie   return 0;
13030fdc8d8SChris Lattner }
13130fdc8d8SChris Lattner 
13230fdc8d8SChris Lattner //----------------------------------------------------------------------
13330fdc8d8SChris Lattner // GetMax64
13430fdc8d8SChris Lattner //
13530fdc8d8SChris Lattner // Used for calls when the size can vary. Fill in extra cases if they
13630fdc8d8SChris Lattner // are ever needed.
13730fdc8d8SChris Lattner //----------------------------------------------------------------------
138b9c1b51eSKate Stone uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const {
139b9c1b51eSKate Stone   switch (size) {
140b9c1b51eSKate Stone   case 1:
141b9c1b51eSKate Stone     return Get8(offset_ptr);
142*a77ec68eSDavid Blaikie     break;
143b9c1b51eSKate Stone   case 2:
144b9c1b51eSKate Stone     return Get16(offset_ptr);
145*a77ec68eSDavid Blaikie     break;
146b9c1b51eSKate Stone   case 4:
147b9c1b51eSKate Stone     return Get32(offset_ptr);
148*a77ec68eSDavid Blaikie     break;
149b9c1b51eSKate Stone   case 8:
150b9c1b51eSKate Stone     return Get64(offset_ptr);
151*a77ec68eSDavid Blaikie     break;
15230fdc8d8SChris Lattner   default:
153*a77ec68eSDavid Blaikie     assert(!"GetMax64 unhandled case!");
154*a77ec68eSDavid Blaikie     break;
15530fdc8d8SChris Lattner   }
156*a77ec68eSDavid Blaikie   return 0;
15730fdc8d8SChris Lattner }
15830fdc8d8SChris Lattner 
15930fdc8d8SChris Lattner //----------------------------------------------------------------------
16030fdc8d8SChris Lattner // GetPointer
16130fdc8d8SChris Lattner //
16230fdc8d8SChris Lattner // Extract a pointer value from the buffer. The pointer size must be
16330fdc8d8SChris Lattner // set prior to using this using one of the SetPointerSize functions.
16430fdc8d8SChris Lattner //----------------------------------------------------------------------
165b9c1b51eSKate Stone uint64_t DNBDataRef::GetPointer(offset_t *offset_ptr) const {
16630fdc8d8SChris Lattner   // Must set pointer size prior to using this call
16730fdc8d8SChris Lattner   assert(m_ptrSize != 0);
16830fdc8d8SChris Lattner   return GetMax64(offset_ptr, m_ptrSize);
16930fdc8d8SChris Lattner }
17030fdc8d8SChris Lattner //----------------------------------------------------------------------
17130fdc8d8SChris Lattner // GetCStr
17230fdc8d8SChris Lattner //----------------------------------------------------------------------
173b9c1b51eSKate Stone const char *DNBDataRef::GetCStr(offset_t *offset_ptr,
174b9c1b51eSKate Stone                                 uint32_t fixed_length) const {
17530fdc8d8SChris Lattner   const char *s = NULL;
176b9c1b51eSKate Stone   if (m_start < m_end) {
17730fdc8d8SChris Lattner     s = (char *)m_start + *offset_ptr;
17830fdc8d8SChris Lattner 
17930fdc8d8SChris Lattner     // Advance the offset
18030fdc8d8SChris Lattner     if (fixed_length)
18130fdc8d8SChris Lattner       *offset_ptr += fixed_length;
18230fdc8d8SChris Lattner     else
18330fdc8d8SChris Lattner       *offset_ptr += strlen(s) + 1;
18430fdc8d8SChris Lattner   }
18530fdc8d8SChris Lattner   return s;
18630fdc8d8SChris Lattner }
18730fdc8d8SChris Lattner 
18830fdc8d8SChris Lattner //----------------------------------------------------------------------
18930fdc8d8SChris Lattner // GetData
19030fdc8d8SChris Lattner //----------------------------------------------------------------------
191b9c1b51eSKate Stone const uint8_t *DNBDataRef::GetData(offset_t *offset_ptr,
192b9c1b51eSKate Stone                                    uint32_t length) const {
19330fdc8d8SChris Lattner   const uint8_t *data = NULL;
194b9c1b51eSKate Stone   if (length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length)) {
19530fdc8d8SChris Lattner     data = m_start + *offset_ptr;
19630fdc8d8SChris Lattner     *offset_ptr += length;
19730fdc8d8SChris Lattner   }
19830fdc8d8SChris Lattner   return data;
19930fdc8d8SChris Lattner }
20030fdc8d8SChris Lattner 
20130fdc8d8SChris Lattner //----------------------------------------------------------------------
20230fdc8d8SChris Lattner // Get_ULEB128
20330fdc8d8SChris Lattner //----------------------------------------------------------------------
204b9c1b51eSKate Stone uint64_t DNBDataRef::Get_ULEB128(offset_t *offset_ptr) const {
20530fdc8d8SChris Lattner   uint64_t result = 0;
206b9c1b51eSKate Stone   if (m_start < m_end) {
20730fdc8d8SChris Lattner     int shift = 0;
20830fdc8d8SChris Lattner     const uint8_t *src = m_start + *offset_ptr;
20930fdc8d8SChris Lattner     uint8_t byte;
21030fdc8d8SChris Lattner     int bytecount = 0;
21130fdc8d8SChris Lattner 
212b9c1b51eSKate Stone     while (src < m_end) {
21330fdc8d8SChris Lattner       bytecount++;
21430fdc8d8SChris Lattner       byte = *src++;
215d781d2c9SGreg Clayton       result |= (uint64_t)(byte & 0x7f) << shift;
21630fdc8d8SChris Lattner       shift += 7;
21730fdc8d8SChris Lattner       if ((byte & 0x80) == 0)
21830fdc8d8SChris Lattner         break;
21930fdc8d8SChris Lattner     }
22030fdc8d8SChris Lattner 
22130fdc8d8SChris Lattner     *offset_ptr += bytecount;
22230fdc8d8SChris Lattner   }
22330fdc8d8SChris Lattner   return result;
22430fdc8d8SChris Lattner }
22530fdc8d8SChris Lattner 
22630fdc8d8SChris Lattner //----------------------------------------------------------------------
22730fdc8d8SChris Lattner // Get_SLEB128
22830fdc8d8SChris Lattner //----------------------------------------------------------------------
229b9c1b51eSKate Stone int64_t DNBDataRef::Get_SLEB128(offset_t *offset_ptr) const {
23030fdc8d8SChris Lattner   int64_t result = 0;
23130fdc8d8SChris Lattner 
232b9c1b51eSKate Stone   if (m_start < m_end) {
23330fdc8d8SChris Lattner     int shift = 0;
23430fdc8d8SChris Lattner     int size = sizeof(uint32_t) * 8;
23530fdc8d8SChris Lattner     const uint8_t *src = m_start + *offset_ptr;
23630fdc8d8SChris Lattner 
237d14651afSJohnny Chen     uint8_t byte = 0;
23830fdc8d8SChris Lattner     int bytecount = 0;
23930fdc8d8SChris Lattner 
240b9c1b51eSKate Stone     while (src < m_end) {
24130fdc8d8SChris Lattner       bytecount++;
24230fdc8d8SChris Lattner       byte = *src++;
243d781d2c9SGreg Clayton       result |= (int64_t)(byte & 0x7f) << shift;
24430fdc8d8SChris Lattner       shift += 7;
24530fdc8d8SChris Lattner       if ((byte & 0x80) == 0)
24630fdc8d8SChris Lattner         break;
24730fdc8d8SChris Lattner     }
24830fdc8d8SChris Lattner 
24930fdc8d8SChris Lattner     // Sign bit of byte is 2nd high order bit (0x40)
25030fdc8d8SChris Lattner     if (shift < size && (byte & 0x40))
25130fdc8d8SChris Lattner       result |= -(1ll << shift);
25230fdc8d8SChris Lattner 
25330fdc8d8SChris Lattner     *offset_ptr += bytecount;
25430fdc8d8SChris Lattner   }
25530fdc8d8SChris Lattner   return result;
25630fdc8d8SChris Lattner }
25730fdc8d8SChris Lattner 
25830fdc8d8SChris Lattner //----------------------------------------------------------------------
25930fdc8d8SChris Lattner // Skip_LEB128
26030fdc8d8SChris Lattner //
26130fdc8d8SChris Lattner // Skips past ULEB128 and SLEB128 numbers (just updates the offset)
26230fdc8d8SChris Lattner //----------------------------------------------------------------------
263b9c1b51eSKate Stone void DNBDataRef::Skip_LEB128(offset_t *offset_ptr) const {
264b9c1b51eSKate Stone   if (m_start < m_end) {
26530fdc8d8SChris Lattner     const uint8_t *start = m_start + *offset_ptr;
26630fdc8d8SChris Lattner     const uint8_t *src = start;
26730fdc8d8SChris Lattner 
26830fdc8d8SChris Lattner     while ((src < m_end) && (*src++ & 0x80))
26930fdc8d8SChris Lattner       /* Do nothing */;
27030fdc8d8SChris Lattner 
27130fdc8d8SChris Lattner     *offset_ptr += src - start;
27230fdc8d8SChris Lattner   }
27330fdc8d8SChris Lattner }
27430fdc8d8SChris Lattner 
275b9c1b51eSKate Stone uint32_t DNBDataRef::Dump(uint32_t startOffset, uint32_t endOffset,
276b9c1b51eSKate Stone                           uint64_t offsetBase, DNBDataRef::Type type,
277b9c1b51eSKate Stone                           uint32_t numPerLine, const char *format) {
27830fdc8d8SChris Lattner   uint32_t offset;
27930fdc8d8SChris Lattner   uint32_t count;
28030fdc8d8SChris Lattner   char str[1024];
28130fdc8d8SChris Lattner   str[0] = '\0';
282a026de05SBruce Mitchener   size_t str_offset = 0;
28330fdc8d8SChris Lattner 
284b9c1b51eSKate Stone   for (offset = startOffset, count = 0;
285b9c1b51eSKate Stone        ValidOffset(offset) && offset < endOffset; ++count) {
286b9c1b51eSKate Stone     if ((count % numPerLine) == 0) {
28730fdc8d8SChris Lattner       // Print out any previous string
28830fdc8d8SChris Lattner       if (str[0] != '\0')
28930fdc8d8SChris Lattner         DNBLog("%s", str);
29030fdc8d8SChris Lattner       // Reset string offset and fill the current line string with address:
29130fdc8d8SChris Lattner       str_offset = 0;
292b9c1b51eSKate Stone       str_offset += snprintf(str, sizeof(str), "0x%8.8llx:",
293b9c1b51eSKate Stone                              (uint64_t)(offsetBase + (offset - startOffset)));
29430fdc8d8SChris Lattner     }
29530fdc8d8SChris Lattner 
296b9c1b51eSKate Stone     // Make sure we don't pass the bounds of our current string buffer on each
297b9c1b51eSKate Stone     // iteration through this loop
298b9c1b51eSKate Stone     if (str_offset >= sizeof(str)) {
299b9c1b51eSKate Stone       // The last snprintf consumed our string buffer, we will need to dump this
300b9c1b51eSKate Stone       // out
30130fdc8d8SChris Lattner       // and reset the string with no address
30230fdc8d8SChris Lattner       DNBLog("%s", str);
30330fdc8d8SChris Lattner       str_offset = 0;
30430fdc8d8SChris Lattner       str[0] = '\0';
30530fdc8d8SChris Lattner     }
30630fdc8d8SChris Lattner 
307b9c1b51eSKate Stone     // We already checked that there is at least some room in the string str
308b9c1b51eSKate Stone     // above, so it is safe to make
30930fdc8d8SChris Lattner     // the snprintf call each time through this loop
310b9c1b51eSKate Stone     switch (type) {
311b9c1b51eSKate Stone     case TypeUInt8:
312b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
313b9c1b51eSKate Stone                              format ? format : " %2.2x", Get8(&offset));
31430fdc8d8SChris Lattner       break;
315b9c1b51eSKate Stone     case TypeChar: {
316b9c1b51eSKate Stone       char ch = Get8(&offset);
317b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
318b9c1b51eSKate Stone                              format ? format : " %c", isprint(ch) ? ch : ' ');
319b9c1b51eSKate Stone     } break;
320b9c1b51eSKate Stone     case TypeUInt16:
321b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
322b9c1b51eSKate Stone                              format ? format : " %4.4x", Get16(&offset));
323b9c1b51eSKate Stone       break;
324b9c1b51eSKate Stone     case TypeUInt32:
325b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
326b9c1b51eSKate Stone                              format ? format : " %8.8x", Get32(&offset));
327b9c1b51eSKate Stone       break;
328b9c1b51eSKate Stone     case TypeUInt64:
329b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
330b9c1b51eSKate Stone                              format ? format : " %16.16llx", Get64(&offset));
331b9c1b51eSKate Stone       break;
332b9c1b51eSKate Stone     case TypePointer:
333b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
334b9c1b51eSKate Stone                              format ? format : " 0x%llx", GetPointer(&offset));
335b9c1b51eSKate Stone       break;
336b9c1b51eSKate Stone     case TypeULEB128:
337b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
338b9c1b51eSKate Stone                              format ? format : " 0x%llx", Get_ULEB128(&offset));
339b9c1b51eSKate Stone       break;
340b9c1b51eSKate Stone     case TypeSLEB128:
341b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
342b9c1b51eSKate Stone                              format ? format : " %lld", Get_SLEB128(&offset));
343b9c1b51eSKate Stone       break;
34430fdc8d8SChris Lattner     }
34530fdc8d8SChris Lattner   }
34630fdc8d8SChris Lattner 
34730fdc8d8SChris Lattner   if (str[0] != '\0')
34830fdc8d8SChris Lattner     DNBLog("%s", str);
34930fdc8d8SChris Lattner 
35030fdc8d8SChris Lattner   return offset; // Return the offset at which we ended up
35130fdc8d8SChris Lattner }
352