1061da546Spatrick //===-- DNBDataRef.cpp ------------------------------------------*- C++ -*-===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick // 9061da546Spatrick // Created by Greg Clayton on 1/11/06. 10061da546Spatrick // 11061da546Spatrick //===----------------------------------------------------------------------===// 12061da546Spatrick 13061da546Spatrick #include "DNBDataRef.h" 14061da546Spatrick #include "DNBLog.h" 15*be691f3bSpatrick #include <cassert> 16*be691f3bSpatrick #include <cctype> 17061da546Spatrick #include <libkern/OSByteOrder.h> 18061da546Spatrick 19061da546Spatrick // Constructor 20061da546Spatrick 21061da546Spatrick DNBDataRef::DNBDataRef() 22061da546Spatrick : m_start(NULL), m_end(NULL), m_swap(false), m_ptrSize(0), 23061da546Spatrick m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS), 24061da546Spatrick m_addrDATA(INVALID_NUB_ADDRESS) {} 25061da546Spatrick 26061da546Spatrick // Constructor 27061da546Spatrick 28061da546Spatrick DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap) 29061da546Spatrick : m_start(start), m_end(start + size), m_swap(swap), m_ptrSize(0), 30061da546Spatrick m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS), 31061da546Spatrick m_addrDATA(INVALID_NUB_ADDRESS) {} 32061da546Spatrick 33061da546Spatrick // Destructor 34061da546Spatrick 35061da546Spatrick DNBDataRef::~DNBDataRef() {} 36061da546Spatrick 37061da546Spatrick // Get8 38061da546Spatrick uint8_t DNBDataRef::Get8(offset_t *offset_ptr) const { 39061da546Spatrick uint8_t val = 0; 40061da546Spatrick if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { 41061da546Spatrick val = *(m_start + *offset_ptr); 42061da546Spatrick *offset_ptr += sizeof(val); 43061da546Spatrick } 44061da546Spatrick return val; 45061da546Spatrick } 46061da546Spatrick 47061da546Spatrick // Get16 48061da546Spatrick uint16_t DNBDataRef::Get16(offset_t *offset_ptr) const { 49061da546Spatrick uint16_t val = 0; 50061da546Spatrick if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { 51061da546Spatrick const uint8_t *p = m_start + *offset_ptr; 52061da546Spatrick memcpy(&val, p, sizeof(uint16_t)); 53061da546Spatrick 54061da546Spatrick if (m_swap) 55061da546Spatrick val = OSSwapInt16(val); 56061da546Spatrick 57061da546Spatrick // Advance the offset 58061da546Spatrick *offset_ptr += sizeof(val); 59061da546Spatrick } 60061da546Spatrick return val; 61061da546Spatrick } 62061da546Spatrick 63061da546Spatrick // Get32 64061da546Spatrick uint32_t DNBDataRef::Get32(offset_t *offset_ptr) const { 65061da546Spatrick uint32_t val = 0; 66061da546Spatrick if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { 67061da546Spatrick const uint8_t *p = m_start + *offset_ptr; 68061da546Spatrick memcpy(&val, p, sizeof(uint32_t)); 69061da546Spatrick if (m_swap) 70061da546Spatrick val = OSSwapInt32(val); 71061da546Spatrick 72061da546Spatrick // Advance the offset 73061da546Spatrick *offset_ptr += sizeof(val); 74061da546Spatrick } 75061da546Spatrick return val; 76061da546Spatrick } 77061da546Spatrick 78061da546Spatrick // Get64 79061da546Spatrick uint64_t DNBDataRef::Get64(offset_t *offset_ptr) const { 80061da546Spatrick uint64_t val = 0; 81061da546Spatrick if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { 82061da546Spatrick const uint8_t *p = m_start + *offset_ptr; 83061da546Spatrick memcpy(&val, p, sizeof(uint64_t)); 84061da546Spatrick if (m_swap) 85061da546Spatrick val = OSSwapInt64(val); 86061da546Spatrick 87061da546Spatrick // Advance the offset 88061da546Spatrick *offset_ptr += sizeof(val); 89061da546Spatrick } 90061da546Spatrick return val; 91061da546Spatrick } 92061da546Spatrick 93061da546Spatrick // GetMax32 94061da546Spatrick // 95061da546Spatrick // Used for calls when the size can vary. Fill in extra cases if they 96061da546Spatrick // are ever needed. 97061da546Spatrick uint32_t DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const { 98061da546Spatrick switch (byte_size) { 99061da546Spatrick case 1: 100061da546Spatrick return Get8(offset_ptr); 101061da546Spatrick break; 102061da546Spatrick case 2: 103061da546Spatrick return Get16(offset_ptr); 104061da546Spatrick break; 105061da546Spatrick case 4: 106061da546Spatrick return Get32(offset_ptr); 107061da546Spatrick break; 108061da546Spatrick default: 109061da546Spatrick assert(false && "GetMax32 unhandled case!"); 110061da546Spatrick break; 111061da546Spatrick } 112061da546Spatrick return 0; 113061da546Spatrick } 114061da546Spatrick 115061da546Spatrick // GetMax64 116061da546Spatrick // 117061da546Spatrick // Used for calls when the size can vary. Fill in extra cases if they 118061da546Spatrick // are ever needed. 119061da546Spatrick uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const { 120061da546Spatrick switch (size) { 121061da546Spatrick case 1: 122061da546Spatrick return Get8(offset_ptr); 123061da546Spatrick break; 124061da546Spatrick case 2: 125061da546Spatrick return Get16(offset_ptr); 126061da546Spatrick break; 127061da546Spatrick case 4: 128061da546Spatrick return Get32(offset_ptr); 129061da546Spatrick break; 130061da546Spatrick case 8: 131061da546Spatrick return Get64(offset_ptr); 132061da546Spatrick break; 133061da546Spatrick default: 134061da546Spatrick assert(false && "GetMax64 unhandled case!"); 135061da546Spatrick break; 136061da546Spatrick } 137061da546Spatrick return 0; 138061da546Spatrick } 139061da546Spatrick 140061da546Spatrick // GetPointer 141061da546Spatrick // 142061da546Spatrick // Extract a pointer value from the buffer. The pointer size must be 143061da546Spatrick // set prior to using this using one of the SetPointerSize functions. 144061da546Spatrick uint64_t DNBDataRef::GetPointer(offset_t *offset_ptr) const { 145061da546Spatrick // Must set pointer size prior to using this call 146061da546Spatrick assert(m_ptrSize != 0); 147061da546Spatrick return GetMax64(offset_ptr, m_ptrSize); 148061da546Spatrick } 149061da546Spatrick // GetCStr 150061da546Spatrick const char *DNBDataRef::GetCStr(offset_t *offset_ptr, 151061da546Spatrick uint32_t fixed_length) const { 152061da546Spatrick const char *s = NULL; 153061da546Spatrick if (m_start < m_end) { 154061da546Spatrick s = (const char *)m_start + *offset_ptr; 155061da546Spatrick 156061da546Spatrick // Advance the offset 157061da546Spatrick if (fixed_length) 158061da546Spatrick *offset_ptr += fixed_length; 159061da546Spatrick else 160061da546Spatrick *offset_ptr += strlen(s) + 1; 161061da546Spatrick } 162061da546Spatrick return s; 163061da546Spatrick } 164061da546Spatrick 165061da546Spatrick // GetData 166061da546Spatrick const uint8_t *DNBDataRef::GetData(offset_t *offset_ptr, 167061da546Spatrick uint32_t length) const { 168061da546Spatrick const uint8_t *data = NULL; 169061da546Spatrick if (length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length)) { 170061da546Spatrick data = m_start + *offset_ptr; 171061da546Spatrick *offset_ptr += length; 172061da546Spatrick } 173061da546Spatrick return data; 174061da546Spatrick } 175061da546Spatrick 176061da546Spatrick // Get_ULEB128 177061da546Spatrick uint64_t DNBDataRef::Get_ULEB128(offset_t *offset_ptr) const { 178061da546Spatrick uint64_t result = 0; 179061da546Spatrick if (m_start < m_end) { 180061da546Spatrick int shift = 0; 181061da546Spatrick const uint8_t *src = m_start + *offset_ptr; 182061da546Spatrick uint8_t byte; 183061da546Spatrick int bytecount = 0; 184061da546Spatrick 185061da546Spatrick while (src < m_end) { 186061da546Spatrick bytecount++; 187061da546Spatrick byte = *src++; 188061da546Spatrick result |= (uint64_t)(byte & 0x7f) << shift; 189061da546Spatrick shift += 7; 190061da546Spatrick if ((byte & 0x80) == 0) 191061da546Spatrick break; 192061da546Spatrick } 193061da546Spatrick 194061da546Spatrick *offset_ptr += bytecount; 195061da546Spatrick } 196061da546Spatrick return result; 197061da546Spatrick } 198061da546Spatrick 199061da546Spatrick // Get_SLEB128 200061da546Spatrick int64_t DNBDataRef::Get_SLEB128(offset_t *offset_ptr) const { 201061da546Spatrick int64_t result = 0; 202061da546Spatrick 203061da546Spatrick if (m_start < m_end) { 204061da546Spatrick int shift = 0; 205061da546Spatrick int size = sizeof(uint32_t) * 8; 206061da546Spatrick const uint8_t *src = m_start + *offset_ptr; 207061da546Spatrick 208061da546Spatrick uint8_t byte = 0; 209061da546Spatrick int bytecount = 0; 210061da546Spatrick 211061da546Spatrick while (src < m_end) { 212061da546Spatrick bytecount++; 213061da546Spatrick byte = *src++; 214061da546Spatrick result |= (int64_t)(byte & 0x7f) << shift; 215061da546Spatrick shift += 7; 216061da546Spatrick if ((byte & 0x80) == 0) 217061da546Spatrick break; 218061da546Spatrick } 219061da546Spatrick 220061da546Spatrick // Sign bit of byte is 2nd high order bit (0x40) 221061da546Spatrick if (shift < size && (byte & 0x40)) 222061da546Spatrick result |= -(1ll << shift); 223061da546Spatrick 224061da546Spatrick *offset_ptr += bytecount; 225061da546Spatrick } 226061da546Spatrick return result; 227061da546Spatrick } 228061da546Spatrick 229061da546Spatrick // Skip_LEB128 230061da546Spatrick // 231061da546Spatrick // Skips past ULEB128 and SLEB128 numbers (just updates the offset) 232061da546Spatrick void DNBDataRef::Skip_LEB128(offset_t *offset_ptr) const { 233061da546Spatrick if (m_start < m_end) { 234061da546Spatrick const uint8_t *start = m_start + *offset_ptr; 235061da546Spatrick const uint8_t *src = start; 236061da546Spatrick 237061da546Spatrick while ((src < m_end) && (*src++ & 0x80)) 238061da546Spatrick /* Do nothing */; 239061da546Spatrick 240061da546Spatrick *offset_ptr += src - start; 241061da546Spatrick } 242061da546Spatrick } 243061da546Spatrick 244061da546Spatrick uint32_t DNBDataRef::Dump(uint32_t startOffset, uint32_t endOffset, 245061da546Spatrick uint64_t offsetBase, DNBDataRef::Type type, 246061da546Spatrick uint32_t numPerLine, const char *format) { 247061da546Spatrick uint32_t offset; 248061da546Spatrick uint32_t count; 249061da546Spatrick char str[1024]; 250061da546Spatrick str[0] = '\0'; 251061da546Spatrick size_t str_offset = 0; 252061da546Spatrick 253061da546Spatrick for (offset = startOffset, count = 0; 254061da546Spatrick ValidOffset(offset) && offset < endOffset; ++count) { 255061da546Spatrick if ((count % numPerLine) == 0) { 256061da546Spatrick // Print out any previous string 257061da546Spatrick if (str[0] != '\0') 258061da546Spatrick DNBLog("%s", str); 259061da546Spatrick // Reset string offset and fill the current line string with address: 260061da546Spatrick str_offset = 0; 261061da546Spatrick str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", 262061da546Spatrick (uint64_t)(offsetBase + (offset - startOffset))); 263061da546Spatrick } 264061da546Spatrick 265061da546Spatrick // Make sure we don't pass the bounds of our current string buffer on each 266061da546Spatrick // iteration through this loop 267061da546Spatrick if (str_offset >= sizeof(str)) { 268061da546Spatrick // The last snprintf consumed our string buffer, we will need to dump this 269061da546Spatrick // out 270061da546Spatrick // and reset the string with no address 271061da546Spatrick DNBLog("%s", str); 272061da546Spatrick str_offset = 0; 273061da546Spatrick str[0] = '\0'; 274061da546Spatrick } 275061da546Spatrick 276061da546Spatrick // We already checked that there is at least some room in the string str 277061da546Spatrick // above, so it is safe to make 278061da546Spatrick // the snprintf call each time through this loop 279061da546Spatrick switch (type) { 280061da546Spatrick case TypeUInt8: 281061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 282061da546Spatrick format ? format : " %2.2x", Get8(&offset)); 283061da546Spatrick break; 284061da546Spatrick case TypeChar: { 285061da546Spatrick char ch = Get8(&offset); 286061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 287061da546Spatrick format ? format : " %c", isprint(ch) ? ch : ' '); 288061da546Spatrick } break; 289061da546Spatrick case TypeUInt16: 290061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 291061da546Spatrick format ? format : " %4.4x", Get16(&offset)); 292061da546Spatrick break; 293061da546Spatrick case TypeUInt32: 294061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 295061da546Spatrick format ? format : " %8.8x", Get32(&offset)); 296061da546Spatrick break; 297061da546Spatrick case TypeUInt64: 298061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 299061da546Spatrick format ? format : " %16.16llx", Get64(&offset)); 300061da546Spatrick break; 301061da546Spatrick case TypePointer: 302061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 303061da546Spatrick format ? format : " 0x%llx", GetPointer(&offset)); 304061da546Spatrick break; 305061da546Spatrick case TypeULEB128: 306061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 307061da546Spatrick format ? format : " 0x%llx", Get_ULEB128(&offset)); 308061da546Spatrick break; 309061da546Spatrick case TypeSLEB128: 310061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 311061da546Spatrick format ? format : " %lld", Get_SLEB128(&offset)); 312061da546Spatrick break; 313061da546Spatrick } 314061da546Spatrick } 315061da546Spatrick 316061da546Spatrick if (str[0] != '\0') 317061da546Spatrick DNBLog("%s", str); 318061da546Spatrick 319061da546Spatrick return offset; // Return the offset at which we ended up 320061da546Spatrick } 321