| //===-- DNBDataRef.cpp ------------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Created by Greg Clayton on 1/11/06. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "DNBDataRef.h" |
| #include "DNBLog.h" |
| #include <assert.h> |
| #include <ctype.h> |
| #include <libkern/OSByteOrder.h> |
| |
| //---------------------------------------------------------------------- |
| // Constructor |
| //---------------------------------------------------------------------- |
| |
| DNBDataRef::DNBDataRef() |
| : m_start(NULL), m_end(NULL), m_swap(false), m_ptrSize(0), |
| m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS), |
| m_addrDATA(INVALID_NUB_ADDRESS) {} |
| |
| //---------------------------------------------------------------------- |
| // Constructor |
| //---------------------------------------------------------------------- |
| |
| DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap) |
| : m_start(start), m_end(start + size), m_swap(swap), m_ptrSize(0), |
| m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS), |
| m_addrDATA(INVALID_NUB_ADDRESS) {} |
| |
| //---------------------------------------------------------------------- |
| // Destructor |
| //---------------------------------------------------------------------- |
| |
| DNBDataRef::~DNBDataRef() {} |
| |
| //---------------------------------------------------------------------- |
| // Get8 |
| //---------------------------------------------------------------------- |
| uint8_t DNBDataRef::Get8(offset_t *offset_ptr) const { |
| uint8_t val = 0; |
| if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { |
| val = *(m_start + *offset_ptr); |
| *offset_ptr += sizeof(val); |
| } |
| return val; |
| } |
| |
| //---------------------------------------------------------------------- |
| // Get16 |
| //---------------------------------------------------------------------- |
| uint16_t DNBDataRef::Get16(offset_t *offset_ptr) const { |
| uint16_t val = 0; |
| if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { |
| const uint8_t *p = m_start + *offset_ptr; |
| memcpy(&val, p, sizeof(uint16_t)); |
| |
| if (m_swap) |
| val = OSSwapInt16(val); |
| |
| // Advance the offset |
| *offset_ptr += sizeof(val); |
| } |
| return val; |
| } |
| |
| //---------------------------------------------------------------------- |
| // Get32 |
| //---------------------------------------------------------------------- |
| uint32_t DNBDataRef::Get32(offset_t *offset_ptr) const { |
| uint32_t val = 0; |
| if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { |
| const uint8_t *p = m_start + *offset_ptr; |
| memcpy(&val, p, sizeof(uint32_t)); |
| if (m_swap) |
| val = OSSwapInt32(val); |
| |
| // Advance the offset |
| *offset_ptr += sizeof(val); |
| } |
| return val; |
| } |
| |
| //---------------------------------------------------------------------- |
| // Get64 |
| //---------------------------------------------------------------------- |
| uint64_t DNBDataRef::Get64(offset_t *offset_ptr) const { |
| uint64_t val = 0; |
| if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { |
| const uint8_t *p = m_start + *offset_ptr; |
| memcpy(&val, p, sizeof(uint64_t)); |
| if (m_swap) |
| val = OSSwapInt64(val); |
| |
| // Advance the offset |
| *offset_ptr += sizeof(val); |
| } |
| return val; |
| } |
| |
| //---------------------------------------------------------------------- |
| // GetMax32 |
| // |
| // Used for calls when the size can vary. Fill in extra cases if they |
| // are ever needed. |
| //---------------------------------------------------------------------- |
| uint32_t DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const { |
| switch (byte_size) { |
| case 1: |
| return Get8(offset_ptr); |
| break; |
| case 2: |
| return Get16(offset_ptr); |
| break; |
| case 4: |
| return Get32(offset_ptr); |
| break; |
| default: |
| assert(false && "GetMax32 unhandled case!"); |
| break; |
| } |
| return 0; |
| } |
| |
| //---------------------------------------------------------------------- |
| // GetMax64 |
| // |
| // Used for calls when the size can vary. Fill in extra cases if they |
| // are ever needed. |
| //---------------------------------------------------------------------- |
| uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const { |
| switch (size) { |
| case 1: |
| return Get8(offset_ptr); |
| break; |
| case 2: |
| return Get16(offset_ptr); |
| break; |
| case 4: |
| return Get32(offset_ptr); |
| break; |
| case 8: |
| return Get64(offset_ptr); |
| break; |
| default: |
| assert(false && "GetMax64 unhandled case!"); |
| break; |
| } |
| return 0; |
| } |
| |
| //---------------------------------------------------------------------- |
| // GetPointer |
| // |
| // Extract a pointer value from the buffer. The pointer size must be |
| // set prior to using this using one of the SetPointerSize functions. |
| //---------------------------------------------------------------------- |
| uint64_t DNBDataRef::GetPointer(offset_t *offset_ptr) const { |
| // Must set pointer size prior to using this call |
| assert(m_ptrSize != 0); |
| return GetMax64(offset_ptr, m_ptrSize); |
| } |
| //---------------------------------------------------------------------- |
| // GetCStr |
| //---------------------------------------------------------------------- |
| const char *DNBDataRef::GetCStr(offset_t *offset_ptr, |
| uint32_t fixed_length) const { |
| const char *s = NULL; |
| if (m_start < m_end) { |
| s = (const char *)m_start + *offset_ptr; |
| |
| // Advance the offset |
| if (fixed_length) |
| *offset_ptr += fixed_length; |
| else |
| *offset_ptr += strlen(s) + 1; |
| } |
| return s; |
| } |
| |
| //---------------------------------------------------------------------- |
| // GetData |
| //---------------------------------------------------------------------- |
| const uint8_t *DNBDataRef::GetData(offset_t *offset_ptr, |
| uint32_t length) const { |
| const uint8_t *data = NULL; |
| if (length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length)) { |
| data = m_start + *offset_ptr; |
| *offset_ptr += length; |
| } |
| return data; |
| } |
| |
| //---------------------------------------------------------------------- |
| // Get_ULEB128 |
| //---------------------------------------------------------------------- |
| uint64_t DNBDataRef::Get_ULEB128(offset_t *offset_ptr) const { |
| uint64_t result = 0; |
| if (m_start < m_end) { |
| int shift = 0; |
| const uint8_t *src = m_start + *offset_ptr; |
| uint8_t byte; |
| int bytecount = 0; |
| |
| while (src < m_end) { |
| bytecount++; |
| byte = *src++; |
| result |= (uint64_t)(byte & 0x7f) << shift; |
| shift += 7; |
| if ((byte & 0x80) == 0) |
| break; |
| } |
| |
| *offset_ptr += bytecount; |
| } |
| return result; |
| } |
| |
| //---------------------------------------------------------------------- |
| // Get_SLEB128 |
| //---------------------------------------------------------------------- |
| int64_t DNBDataRef::Get_SLEB128(offset_t *offset_ptr) const { |
| int64_t result = 0; |
| |
| if (m_start < m_end) { |
| int shift = 0; |
| int size = sizeof(uint32_t) * 8; |
| const uint8_t *src = m_start + *offset_ptr; |
| |
| uint8_t byte = 0; |
| int bytecount = 0; |
| |
| while (src < m_end) { |
| bytecount++; |
| byte = *src++; |
| result |= (int64_t)(byte & 0x7f) << shift; |
| shift += 7; |
| if ((byte & 0x80) == 0) |
| break; |
| } |
| |
| // Sign bit of byte is 2nd high order bit (0x40) |
| if (shift < size && (byte & 0x40)) |
| result |= -(1ll << shift); |
| |
| *offset_ptr += bytecount; |
| } |
| return result; |
| } |
| |
| //---------------------------------------------------------------------- |
| // Skip_LEB128 |
| // |
| // Skips past ULEB128 and SLEB128 numbers (just updates the offset) |
| //---------------------------------------------------------------------- |
| void DNBDataRef::Skip_LEB128(offset_t *offset_ptr) const { |
| if (m_start < m_end) { |
| const uint8_t *start = m_start + *offset_ptr; |
| const uint8_t *src = start; |
| |
| while ((src < m_end) && (*src++ & 0x80)) |
| /* Do nothing */; |
| |
| *offset_ptr += src - start; |
| } |
| } |
| |
| uint32_t DNBDataRef::Dump(uint32_t startOffset, uint32_t endOffset, |
| uint64_t offsetBase, DNBDataRef::Type type, |
| uint32_t numPerLine, const char *format) { |
| uint32_t offset; |
| uint32_t count; |
| char str[1024]; |
| str[0] = '\0'; |
| size_t str_offset = 0; |
| |
| for (offset = startOffset, count = 0; |
| ValidOffset(offset) && offset < endOffset; ++count) { |
| if ((count % numPerLine) == 0) { |
| // Print out any previous string |
| if (str[0] != '\0') |
| DNBLog("%s", str); |
| // Reset string offset and fill the current line string with address: |
| str_offset = 0; |
| str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", |
| (uint64_t)(offsetBase + (offset - startOffset))); |
| } |
| |
| // Make sure we don't pass the bounds of our current string buffer on each |
| // iteration through this loop |
| if (str_offset >= sizeof(str)) { |
| // The last snprintf consumed our string buffer, we will need to dump this |
| // out |
| // and reset the string with no address |
| DNBLog("%s", str); |
| str_offset = 0; |
| str[0] = '\0'; |
| } |
| |
| // We already checked that there is at least some room in the string str |
| // above, so it is safe to make |
| // the snprintf call each time through this loop |
| switch (type) { |
| case TypeUInt8: |
| str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, |
| format ? format : " %2.2x", Get8(&offset)); |
| break; |
| case TypeChar: { |
| char ch = Get8(&offset); |
| str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, |
| format ? format : " %c", isprint(ch) ? ch : ' '); |
| } break; |
| case TypeUInt16: |
| str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, |
| format ? format : " %4.4x", Get16(&offset)); |
| break; |
| case TypeUInt32: |
| str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, |
| format ? format : " %8.8x", Get32(&offset)); |
| break; |
| case TypeUInt64: |
| str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, |
| format ? format : " %16.16llx", Get64(&offset)); |
| break; |
| case TypePointer: |
| str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, |
| format ? format : " 0x%llx", GetPointer(&offset)); |
| break; |
| case TypeULEB128: |
| str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, |
| format ? format : " 0x%llx", Get_ULEB128(&offset)); |
| break; |
| case TypeSLEB128: |
| str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, |
| format ? format : " %lld", Get_SLEB128(&offset)); |
| break; |
| } |
| } |
| |
| if (str[0] != '\0') |
| DNBLog("%s", str); |
| |
| return offset; // Return the offset at which we ended up |
| } |