#include "DNBDataRef.h"
#include "DNBLog.h"
#include <assert.h>
#include <ctype.h>
#include <libkern/OSByteOrder.h>
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)
{
}
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)
{
}
DNBDataRef::~DNBDataRef()
{
}
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;
}
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);
*offset_ptr += sizeof(val);
}
return val;
}
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);
*offset_ptr += sizeof(val);
}
return val;
}
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);
*offset_ptr += sizeof(val);
}
return val;
}
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;
}
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;
}
uint64_t
DNBDataRef::GetPointer(offset_t *offset_ptr) const
{
assert(m_ptrSize != 0);
return GetMax64(offset_ptr, m_ptrSize);
}
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;
if (fixed_length)
*offset_ptr += fixed_length;
else
*offset_ptr += strlen(s) + 1;
}
return s;
}
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;
}
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;
}
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;
}
if (shift < size && (byte & 0x40))
result |= - (1ll << shift);
*offset_ptr += bytecount;
}
return result;
}
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))
;
*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';
int str_offset = 0;
for (offset = startOffset, count = 0; ValidOffset(offset) && offset < endOffset; ++count)
{
if ((count % numPerLine) == 0)
{
if (str[0] != '\0')
DNBLog("%s", str);
str_offset = 0;
str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", (uint64_t)(offsetBase + (offset - startOffset)));
}
if (str_offset >= sizeof(str))
{
DNBLog("%s", str);
str_offset = 0;
str[0] = '\0';
}
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; }