321 lines · cpp
1//===-- DNBDataRef.cpp ------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Created by Greg Clayton on 1/11/06.10//11//===----------------------------------------------------------------------===//12 13#include "DNBDataRef.h"14#include "DNBLog.h"15#include <cassert>16#include <cctype>17#include <libkern/OSByteOrder.h>18 19// Constructor20 21DNBDataRef::DNBDataRef()22 : m_start(NULL), m_end(NULL), m_swap(false), m_ptrSize(0),23 m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS),24 m_addrDATA(INVALID_NUB_ADDRESS) {}25 26// Constructor27 28DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap)29 : m_start(start), m_end(start + size), m_swap(swap), m_ptrSize(0),30 m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS),31 m_addrDATA(INVALID_NUB_ADDRESS) {}32 33// Destructor34 35DNBDataRef::~DNBDataRef() = default;36 37// Get838uint8_t DNBDataRef::Get8(offset_t *offset_ptr) const {39 uint8_t val = 0;40 if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {41 val = *(m_start + *offset_ptr);42 *offset_ptr += sizeof(val);43 }44 return val;45}46 47// Get1648uint16_t DNBDataRef::Get16(offset_t *offset_ptr) const {49 uint16_t val = 0;50 if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {51 const uint8_t *p = m_start + *offset_ptr;52 memcpy(&val, p, sizeof(uint16_t));53 54 if (m_swap)55 val = OSSwapInt16(val);56 57 // Advance the offset58 *offset_ptr += sizeof(val);59 }60 return val;61}62 63// Get3264uint32_t DNBDataRef::Get32(offset_t *offset_ptr) const {65 uint32_t val = 0;66 if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {67 const uint8_t *p = m_start + *offset_ptr;68 memcpy(&val, p, sizeof(uint32_t));69 if (m_swap)70 val = OSSwapInt32(val);71 72 // Advance the offset73 *offset_ptr += sizeof(val);74 }75 return val;76}77 78// Get6479uint64_t DNBDataRef::Get64(offset_t *offset_ptr) const {80 uint64_t val = 0;81 if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {82 const uint8_t *p = m_start + *offset_ptr;83 memcpy(&val, p, sizeof(uint64_t));84 if (m_swap)85 val = OSSwapInt64(val);86 87 // Advance the offset88 *offset_ptr += sizeof(val);89 }90 return val;91}92 93// GetMax3294//95// Used for calls when the size can vary. Fill in extra cases if they96// are ever needed.97uint32_t DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const {98 switch (byte_size) {99 case 1:100 return Get8(offset_ptr);101 break;102 case 2:103 return Get16(offset_ptr);104 break;105 case 4:106 return Get32(offset_ptr);107 break;108 default:109 assert(false && "GetMax32 unhandled case!");110 break;111 }112 return 0;113}114 115// GetMax64116//117// Used for calls when the size can vary. Fill in extra cases if they118// are ever needed.119uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const {120 switch (size) {121 case 1:122 return Get8(offset_ptr);123 break;124 case 2:125 return Get16(offset_ptr);126 break;127 case 4:128 return Get32(offset_ptr);129 break;130 case 8:131 return Get64(offset_ptr);132 break;133 default:134 assert(false && "GetMax64 unhandled case!");135 break;136 }137 return 0;138}139 140// GetPointer141//142// Extract a pointer value from the buffer. The pointer size must be143// set prior to using this using one of the SetPointerSize functions.144uint64_t DNBDataRef::GetPointer(offset_t *offset_ptr) const {145 // Must set pointer size prior to using this call146 assert(m_ptrSize != 0);147 return GetMax64(offset_ptr, m_ptrSize);148}149// GetCStr150const char *DNBDataRef::GetCStr(offset_t *offset_ptr,151 uint32_t fixed_length) const {152 const char *s = NULL;153 if (m_start < m_end) {154 s = (const char *)m_start + *offset_ptr;155 156 // Advance the offset157 if (fixed_length)158 *offset_ptr += fixed_length;159 else160 *offset_ptr += strlen(s) + 1;161 }162 return s;163}164 165// GetData166const uint8_t *DNBDataRef::GetData(offset_t *offset_ptr,167 uint32_t length) const {168 const uint8_t *data = NULL;169 if (length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length)) {170 data = m_start + *offset_ptr;171 *offset_ptr += length;172 }173 return data;174}175 176// Get_ULEB128177uint64_t DNBDataRef::Get_ULEB128(offset_t *offset_ptr) const {178 uint64_t result = 0;179 if (m_start < m_end) {180 int shift = 0;181 const uint8_t *src = m_start + *offset_ptr;182 uint8_t byte;183 int bytecount = 0;184 185 while (src < m_end) {186 bytecount++;187 byte = *src++;188 result |= (uint64_t)(byte & 0x7f) << shift;189 shift += 7;190 if ((byte & 0x80) == 0)191 break;192 }193 194 *offset_ptr += bytecount;195 }196 return result;197}198 199// Get_SLEB128200int64_t DNBDataRef::Get_SLEB128(offset_t *offset_ptr) const {201 int64_t result = 0;202 203 if (m_start < m_end) {204 int shift = 0;205 int size = sizeof(uint32_t) * 8;206 const uint8_t *src = m_start + *offset_ptr;207 208 uint8_t byte = 0;209 int bytecount = 0;210 211 while (src < m_end) {212 bytecount++;213 byte = *src++;214 result |= (int64_t)(byte & 0x7f) << shift;215 shift += 7;216 if ((byte & 0x80) == 0)217 break;218 }219 220 // Sign bit of byte is 2nd high order bit (0x40)221 if (shift < size && (byte & 0x40))222 result |= -(1ll << shift);223 224 *offset_ptr += bytecount;225 }226 return result;227}228 229// Skip_LEB128230//231// Skips past ULEB128 and SLEB128 numbers (just updates the offset)232void DNBDataRef::Skip_LEB128(offset_t *offset_ptr) const {233 if (m_start < m_end) {234 const uint8_t *start = m_start + *offset_ptr;235 const uint8_t *src = start;236 237 while ((src < m_end) && (*src++ & 0x80))238 /* Do nothing */;239 240 *offset_ptr += src - start;241 }242}243 244uint32_t DNBDataRef::Dump(uint32_t startOffset, uint32_t endOffset,245 uint64_t offsetBase, DNBDataRef::Type type,246 uint32_t numPerLine, const char *format) {247 uint32_t offset;248 uint32_t count;249 char str[1024];250 str[0] = '\0';251 size_t str_offset = 0;252 253 for (offset = startOffset, count = 0;254 ValidOffset(offset) && offset < endOffset; ++count) {255 if ((count % numPerLine) == 0) {256 // Print out any previous string257 if (str[0] != '\0')258 DNBLog("%s", str);259 // Reset string offset and fill the current line string with address:260 str_offset = 0;261 str_offset += snprintf(str, sizeof(str), "0x%8.8llx:",262 (uint64_t)(offsetBase + (offset - startOffset)));263 }264 265 // Make sure we don't pass the bounds of our current string buffer on each266 // iteration through this loop267 if (str_offset >= sizeof(str)) {268 // The last snprintf consumed our string buffer, we will need to dump this269 // out270 // and reset the string with no address271 DNBLog("%s", str);272 str_offset = 0;273 str[0] = '\0';274 }275 276 // We already checked that there is at least some room in the string str277 // above, so it is safe to make278 // the snprintf call each time through this loop279 switch (type) {280 case TypeUInt8:281 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,282 format ? format : " %2.2x", Get8(&offset));283 break;284 case TypeChar: {285 char ch = Get8(&offset);286 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,287 format ? format : " %c", isprint(ch) ? ch : ' ');288 } break;289 case TypeUInt16:290 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,291 format ? format : " %4.4x", Get16(&offset));292 break;293 case TypeUInt32:294 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,295 format ? format : " %8.8x", Get32(&offset));296 break;297 case TypeUInt64:298 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,299 format ? format : " %16.16llx", Get64(&offset));300 break;301 case TypePointer:302 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,303 format ? format : " 0x%llx", GetPointer(&offset));304 break;305 case TypeULEB128:306 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,307 format ? format : " 0x%llx", Get_ULEB128(&offset));308 break;309 case TypeSLEB128:310 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,311 format ? format : " %lld", Get_SLEB128(&offset));312 break;313 }314 }315 316 if (str[0] != '\0')317 DNBLog("%s", str);318 319 return offset; // Return the offset at which we ended up320}321