130fdc8d8SChris Lattner //===-- DNBDataRef.cpp ------------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner //
930fdc8d8SChris Lattner //  Created by Greg Clayton on 1/11/06.
1030fdc8d8SChris Lattner //
1130fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1230fdc8d8SChris Lattner 
1330fdc8d8SChris Lattner #include "DNBDataRef.h"
1430fdc8d8SChris Lattner #include "DNBLog.h"
1576e47d48SRaphael Isemann #include <cassert>
1676e47d48SRaphael Isemann #include <cctype>
1730fdc8d8SChris Lattner #include <libkern/OSByteOrder.h>
1830fdc8d8SChris Lattner 
1930fdc8d8SChris Lattner // Constructor
2030fdc8d8SChris Lattner 
DNBDataRef()21b9c1b51eSKate Stone DNBDataRef::DNBDataRef()
22b9c1b51eSKate Stone     : m_start(NULL), m_end(NULL), m_swap(false), m_ptrSize(0),
23b9c1b51eSKate Stone       m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS),
24b9c1b51eSKate Stone       m_addrDATA(INVALID_NUB_ADDRESS) {}
2530fdc8d8SChris Lattner 
2630fdc8d8SChris Lattner // Constructor
2730fdc8d8SChris Lattner 
DNBDataRef(const uint8_t * start,size_t size,bool swap)28b9c1b51eSKate Stone DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap)
29b9c1b51eSKate Stone     : m_start(start), m_end(start + size), m_swap(swap), m_ptrSize(0),
30b9c1b51eSKate Stone       m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS),
31b9c1b51eSKate Stone       m_addrDATA(INVALID_NUB_ADDRESS) {}
3230fdc8d8SChris Lattner 
3330fdc8d8SChris Lattner // Destructor
3430fdc8d8SChris Lattner 
35*24f9a2f5SShafik Yaghmour DNBDataRef::~DNBDataRef() = default;
3630fdc8d8SChris Lattner 
3730fdc8d8SChris Lattner // Get8
Get8(offset_t * offset_ptr) const38b9c1b51eSKate Stone uint8_t DNBDataRef::Get8(offset_t *offset_ptr) const {
3930fdc8d8SChris Lattner   uint8_t val = 0;
40b9c1b51eSKate Stone   if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
4130fdc8d8SChris Lattner     val = *(m_start + *offset_ptr);
4230fdc8d8SChris Lattner     *offset_ptr += sizeof(val);
4330fdc8d8SChris Lattner   }
4430fdc8d8SChris Lattner   return val;
4530fdc8d8SChris Lattner }
4630fdc8d8SChris Lattner 
4730fdc8d8SChris Lattner // Get16
Get16(offset_t * offset_ptr) const48b9c1b51eSKate Stone uint16_t DNBDataRef::Get16(offset_t *offset_ptr) const {
4930fdc8d8SChris Lattner   uint16_t val = 0;
50b9c1b51eSKate Stone   if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
5130fdc8d8SChris Lattner     const uint8_t *p = m_start + *offset_ptr;
5201e86df6SVedant Kumar     memcpy(&val, p, sizeof(uint16_t));
5330fdc8d8SChris Lattner 
5430fdc8d8SChris Lattner     if (m_swap)
5530fdc8d8SChris Lattner       val = OSSwapInt16(val);
5630fdc8d8SChris Lattner 
5730fdc8d8SChris Lattner     // Advance the offset
5830fdc8d8SChris Lattner     *offset_ptr += sizeof(val);
5930fdc8d8SChris Lattner   }
6030fdc8d8SChris Lattner   return val;
6130fdc8d8SChris Lattner }
6230fdc8d8SChris Lattner 
6330fdc8d8SChris Lattner // Get32
Get32(offset_t * offset_ptr) const64b9c1b51eSKate Stone uint32_t DNBDataRef::Get32(offset_t *offset_ptr) const {
6530fdc8d8SChris Lattner   uint32_t val = 0;
66b9c1b51eSKate Stone   if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
6730fdc8d8SChris Lattner     const uint8_t *p = m_start + *offset_ptr;
6801e86df6SVedant Kumar     memcpy(&val, p, sizeof(uint32_t));
6930fdc8d8SChris Lattner     if (m_swap)
7030fdc8d8SChris Lattner       val = OSSwapInt32(val);
7130fdc8d8SChris Lattner 
7230fdc8d8SChris Lattner     // Advance the offset
7330fdc8d8SChris Lattner     *offset_ptr += sizeof(val);
7430fdc8d8SChris Lattner   }
7530fdc8d8SChris Lattner   return val;
7630fdc8d8SChris Lattner }
7730fdc8d8SChris Lattner 
7830fdc8d8SChris Lattner // Get64
Get64(offset_t * offset_ptr) const79b9c1b51eSKate Stone uint64_t DNBDataRef::Get64(offset_t *offset_ptr) const {
8030fdc8d8SChris Lattner   uint64_t val = 0;
81b9c1b51eSKate Stone   if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
8230fdc8d8SChris Lattner     const uint8_t *p = m_start + *offset_ptr;
8301e86df6SVedant Kumar     memcpy(&val, p, sizeof(uint64_t));
8430fdc8d8SChris Lattner     if (m_swap)
8530fdc8d8SChris Lattner       val = OSSwapInt64(val);
8630fdc8d8SChris Lattner 
8730fdc8d8SChris Lattner     // Advance the offset
8830fdc8d8SChris Lattner     *offset_ptr += sizeof(val);
8930fdc8d8SChris Lattner   }
9030fdc8d8SChris Lattner   return val;
9130fdc8d8SChris Lattner }
9230fdc8d8SChris Lattner 
9330fdc8d8SChris Lattner // GetMax32
9430fdc8d8SChris Lattner //
9530fdc8d8SChris Lattner // Used for calls when the size can vary. Fill in extra cases if they
9630fdc8d8SChris Lattner // are ever needed.
GetMax32(offset_t * offset_ptr,uint32_t byte_size) const97b9c1b51eSKate Stone uint32_t DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const {
98b9c1b51eSKate Stone   switch (byte_size) {
99b9c1b51eSKate Stone   case 1:
100b9c1b51eSKate Stone     return Get8(offset_ptr);
101a77ec68eSDavid Blaikie     break;
102b9c1b51eSKate Stone   case 2:
103b9c1b51eSKate Stone     return Get16(offset_ptr);
104a77ec68eSDavid Blaikie     break;
105b9c1b51eSKate Stone   case 4:
106b9c1b51eSKate Stone     return Get32(offset_ptr);
107a77ec68eSDavid Blaikie     break;
10830fdc8d8SChris Lattner   default:
10901e86df6SVedant Kumar     assert(false && "GetMax32 unhandled case!");
110a77ec68eSDavid Blaikie     break;
11130fdc8d8SChris Lattner   }
112a77ec68eSDavid Blaikie   return 0;
11330fdc8d8SChris Lattner }
11430fdc8d8SChris Lattner 
11530fdc8d8SChris Lattner // GetMax64
11630fdc8d8SChris Lattner //
11730fdc8d8SChris Lattner // Used for calls when the size can vary. Fill in extra cases if they
11830fdc8d8SChris Lattner // are ever needed.
GetMax64(offset_t * offset_ptr,uint32_t size) const119b9c1b51eSKate Stone uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const {
120b9c1b51eSKate Stone   switch (size) {
121b9c1b51eSKate Stone   case 1:
122b9c1b51eSKate Stone     return Get8(offset_ptr);
123a77ec68eSDavid Blaikie     break;
124b9c1b51eSKate Stone   case 2:
125b9c1b51eSKate Stone     return Get16(offset_ptr);
126a77ec68eSDavid Blaikie     break;
127b9c1b51eSKate Stone   case 4:
128b9c1b51eSKate Stone     return Get32(offset_ptr);
129a77ec68eSDavid Blaikie     break;
130b9c1b51eSKate Stone   case 8:
131b9c1b51eSKate Stone     return Get64(offset_ptr);
132a77ec68eSDavid Blaikie     break;
13330fdc8d8SChris Lattner   default:
13401e86df6SVedant Kumar     assert(false && "GetMax64 unhandled case!");
135a77ec68eSDavid Blaikie     break;
13630fdc8d8SChris Lattner   }
137a77ec68eSDavid Blaikie   return 0;
13830fdc8d8SChris Lattner }
13930fdc8d8SChris Lattner 
14030fdc8d8SChris Lattner // GetPointer
14130fdc8d8SChris Lattner //
14230fdc8d8SChris Lattner // Extract a pointer value from the buffer. The pointer size must be
14330fdc8d8SChris Lattner // set prior to using this using one of the SetPointerSize functions.
GetPointer(offset_t * offset_ptr) const144b9c1b51eSKate Stone uint64_t DNBDataRef::GetPointer(offset_t *offset_ptr) const {
14530fdc8d8SChris Lattner   // Must set pointer size prior to using this call
14630fdc8d8SChris Lattner   assert(m_ptrSize != 0);
14730fdc8d8SChris Lattner   return GetMax64(offset_ptr, m_ptrSize);
14830fdc8d8SChris Lattner }
14930fdc8d8SChris Lattner // GetCStr
GetCStr(offset_t * offset_ptr,uint32_t fixed_length) const150b9c1b51eSKate Stone const char *DNBDataRef::GetCStr(offset_t *offset_ptr,
151b9c1b51eSKate Stone                                 uint32_t fixed_length) const {
15230fdc8d8SChris Lattner   const char *s = NULL;
153b9c1b51eSKate Stone   if (m_start < m_end) {
15401e86df6SVedant Kumar     s = (const char *)m_start + *offset_ptr;
15530fdc8d8SChris Lattner 
15630fdc8d8SChris Lattner     // Advance the offset
15730fdc8d8SChris Lattner     if (fixed_length)
15830fdc8d8SChris Lattner       *offset_ptr += fixed_length;
15930fdc8d8SChris Lattner     else
16030fdc8d8SChris Lattner       *offset_ptr += strlen(s) + 1;
16130fdc8d8SChris Lattner   }
16230fdc8d8SChris Lattner   return s;
16330fdc8d8SChris Lattner }
16430fdc8d8SChris Lattner 
16530fdc8d8SChris Lattner // GetData
GetData(offset_t * offset_ptr,uint32_t length) const166b9c1b51eSKate Stone const uint8_t *DNBDataRef::GetData(offset_t *offset_ptr,
167b9c1b51eSKate Stone                                    uint32_t length) const {
16830fdc8d8SChris Lattner   const uint8_t *data = NULL;
169b9c1b51eSKate Stone   if (length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length)) {
17030fdc8d8SChris Lattner     data = m_start + *offset_ptr;
17130fdc8d8SChris Lattner     *offset_ptr += length;
17230fdc8d8SChris Lattner   }
17330fdc8d8SChris Lattner   return data;
17430fdc8d8SChris Lattner }
17530fdc8d8SChris Lattner 
17630fdc8d8SChris Lattner // Get_ULEB128
Get_ULEB128(offset_t * offset_ptr) const177b9c1b51eSKate Stone uint64_t DNBDataRef::Get_ULEB128(offset_t *offset_ptr) const {
17830fdc8d8SChris Lattner   uint64_t result = 0;
179b9c1b51eSKate Stone   if (m_start < m_end) {
18030fdc8d8SChris Lattner     int shift = 0;
18130fdc8d8SChris Lattner     const uint8_t *src = m_start + *offset_ptr;
18230fdc8d8SChris Lattner     uint8_t byte;
18330fdc8d8SChris Lattner     int bytecount = 0;
18430fdc8d8SChris Lattner 
185b9c1b51eSKate Stone     while (src < m_end) {
18630fdc8d8SChris Lattner       bytecount++;
18730fdc8d8SChris Lattner       byte = *src++;
188d781d2c9SGreg Clayton       result |= (uint64_t)(byte & 0x7f) << shift;
18930fdc8d8SChris Lattner       shift += 7;
19030fdc8d8SChris Lattner       if ((byte & 0x80) == 0)
19130fdc8d8SChris Lattner         break;
19230fdc8d8SChris Lattner     }
19330fdc8d8SChris Lattner 
19430fdc8d8SChris Lattner     *offset_ptr += bytecount;
19530fdc8d8SChris Lattner   }
19630fdc8d8SChris Lattner   return result;
19730fdc8d8SChris Lattner }
19830fdc8d8SChris Lattner 
19930fdc8d8SChris Lattner // Get_SLEB128
Get_SLEB128(offset_t * offset_ptr) const200b9c1b51eSKate Stone int64_t DNBDataRef::Get_SLEB128(offset_t *offset_ptr) const {
20130fdc8d8SChris Lattner   int64_t result = 0;
20230fdc8d8SChris Lattner 
203b9c1b51eSKate Stone   if (m_start < m_end) {
20430fdc8d8SChris Lattner     int shift = 0;
20530fdc8d8SChris Lattner     int size = sizeof(uint32_t) * 8;
20630fdc8d8SChris Lattner     const uint8_t *src = m_start + *offset_ptr;
20730fdc8d8SChris Lattner 
208d14651afSJohnny Chen     uint8_t byte = 0;
20930fdc8d8SChris Lattner     int bytecount = 0;
21030fdc8d8SChris Lattner 
211b9c1b51eSKate Stone     while (src < m_end) {
21230fdc8d8SChris Lattner       bytecount++;
21330fdc8d8SChris Lattner       byte = *src++;
214d781d2c9SGreg Clayton       result |= (int64_t)(byte & 0x7f) << shift;
21530fdc8d8SChris Lattner       shift += 7;
21630fdc8d8SChris Lattner       if ((byte & 0x80) == 0)
21730fdc8d8SChris Lattner         break;
21830fdc8d8SChris Lattner     }
21930fdc8d8SChris Lattner 
22030fdc8d8SChris Lattner     // Sign bit of byte is 2nd high order bit (0x40)
22130fdc8d8SChris Lattner     if (shift < size && (byte & 0x40))
22230fdc8d8SChris Lattner       result |= -(1ll << shift);
22330fdc8d8SChris Lattner 
22430fdc8d8SChris Lattner     *offset_ptr += bytecount;
22530fdc8d8SChris Lattner   }
22630fdc8d8SChris Lattner   return result;
22730fdc8d8SChris Lattner }
22830fdc8d8SChris Lattner 
22930fdc8d8SChris Lattner // Skip_LEB128
23030fdc8d8SChris Lattner //
23130fdc8d8SChris Lattner // Skips past ULEB128 and SLEB128 numbers (just updates the offset)
Skip_LEB128(offset_t * offset_ptr) const232b9c1b51eSKate Stone void DNBDataRef::Skip_LEB128(offset_t *offset_ptr) const {
233b9c1b51eSKate Stone   if (m_start < m_end) {
23430fdc8d8SChris Lattner     const uint8_t *start = m_start + *offset_ptr;
23530fdc8d8SChris Lattner     const uint8_t *src = start;
23630fdc8d8SChris Lattner 
23730fdc8d8SChris Lattner     while ((src < m_end) && (*src++ & 0x80))
23830fdc8d8SChris Lattner       /* Do nothing */;
23930fdc8d8SChris Lattner 
24030fdc8d8SChris Lattner     *offset_ptr += src - start;
24130fdc8d8SChris Lattner   }
24230fdc8d8SChris Lattner }
24330fdc8d8SChris Lattner 
Dump(uint32_t startOffset,uint32_t endOffset,uint64_t offsetBase,DNBDataRef::Type type,uint32_t numPerLine,const char * format)244b9c1b51eSKate Stone uint32_t DNBDataRef::Dump(uint32_t startOffset, uint32_t endOffset,
245b9c1b51eSKate Stone                           uint64_t offsetBase, DNBDataRef::Type type,
246b9c1b51eSKate Stone                           uint32_t numPerLine, const char *format) {
24730fdc8d8SChris Lattner   uint32_t offset;
24830fdc8d8SChris Lattner   uint32_t count;
24930fdc8d8SChris Lattner   char str[1024];
25030fdc8d8SChris Lattner   str[0] = '\0';
251a026de05SBruce Mitchener   size_t str_offset = 0;
25230fdc8d8SChris Lattner 
253b9c1b51eSKate Stone   for (offset = startOffset, count = 0;
254b9c1b51eSKate Stone        ValidOffset(offset) && offset < endOffset; ++count) {
255b9c1b51eSKate Stone     if ((count % numPerLine) == 0) {
25630fdc8d8SChris Lattner       // Print out any previous string
25730fdc8d8SChris Lattner       if (str[0] != '\0')
25830fdc8d8SChris Lattner         DNBLog("%s", str);
25930fdc8d8SChris Lattner       // Reset string offset and fill the current line string with address:
26030fdc8d8SChris Lattner       str_offset = 0;
261b9c1b51eSKate Stone       str_offset += snprintf(str, sizeof(str), "0x%8.8llx:",
262b9c1b51eSKate Stone                              (uint64_t)(offsetBase + (offset - startOffset)));
26330fdc8d8SChris Lattner     }
26430fdc8d8SChris Lattner 
265b9c1b51eSKate Stone     // Make sure we don't pass the bounds of our current string buffer on each
266b9c1b51eSKate Stone     // iteration through this loop
267b9c1b51eSKate Stone     if (str_offset >= sizeof(str)) {
268b9c1b51eSKate Stone       // The last snprintf consumed our string buffer, we will need to dump this
269b9c1b51eSKate Stone       // out
27030fdc8d8SChris Lattner       // and reset the string with no address
27130fdc8d8SChris Lattner       DNBLog("%s", str);
27230fdc8d8SChris Lattner       str_offset = 0;
27330fdc8d8SChris Lattner       str[0] = '\0';
27430fdc8d8SChris Lattner     }
27530fdc8d8SChris Lattner 
276b9c1b51eSKate Stone     // We already checked that there is at least some room in the string str
277b9c1b51eSKate Stone     // above, so it is safe to make
27830fdc8d8SChris Lattner     // the snprintf call each time through this loop
279b9c1b51eSKate Stone     switch (type) {
280b9c1b51eSKate Stone     case TypeUInt8:
281b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
282b9c1b51eSKate Stone                              format ? format : " %2.2x", Get8(&offset));
28330fdc8d8SChris Lattner       break;
284b9c1b51eSKate Stone     case TypeChar: {
285b9c1b51eSKate Stone       char ch = Get8(&offset);
286b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
287b9c1b51eSKate Stone                              format ? format : " %c", isprint(ch) ? ch : ' ');
288b9c1b51eSKate Stone     } break;
289b9c1b51eSKate Stone     case TypeUInt16:
290b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
291b9c1b51eSKate Stone                              format ? format : " %4.4x", Get16(&offset));
292b9c1b51eSKate Stone       break;
293b9c1b51eSKate Stone     case TypeUInt32:
294b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
295b9c1b51eSKate Stone                              format ? format : " %8.8x", Get32(&offset));
296b9c1b51eSKate Stone       break;
297b9c1b51eSKate Stone     case TypeUInt64:
298b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
299b9c1b51eSKate Stone                              format ? format : " %16.16llx", Get64(&offset));
300b9c1b51eSKate Stone       break;
301b9c1b51eSKate Stone     case TypePointer:
302b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
303b9c1b51eSKate Stone                              format ? format : " 0x%llx", GetPointer(&offset));
304b9c1b51eSKate Stone       break;
305b9c1b51eSKate Stone     case TypeULEB128:
306b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
307b9c1b51eSKate Stone                              format ? format : " 0x%llx", Get_ULEB128(&offset));
308b9c1b51eSKate Stone       break;
309b9c1b51eSKate Stone     case TypeSLEB128:
310b9c1b51eSKate Stone       str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
311b9c1b51eSKate Stone                              format ? format : " %lld", Get_SLEB128(&offset));
312b9c1b51eSKate Stone       break;
31330fdc8d8SChris Lattner     }
31430fdc8d8SChris Lattner   }
31530fdc8d8SChris Lattner 
31630fdc8d8SChris Lattner   if (str[0] != '\0')
31730fdc8d8SChris Lattner     DNBLog("%s", str);
31830fdc8d8SChris Lattner 
31930fdc8d8SChris Lattner   return offset; // Return the offset at which we ended up
32030fdc8d8SChris Lattner }
321