|  | //===-- 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; | 
|  | val = *(uint16_t*)p; | 
|  |  | 
|  | 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; | 
|  | val = *(uint32_t*)p; | 
|  | 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; | 
|  | val = *(uint64_t*)p; | 
|  | 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(!"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(!"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 = (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 |= (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 |= (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) | 
|  | { | 
|  | default: | 
|  | 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 | 
|  | } |