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-exception 6// 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// Constructor 20 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// Constructor 27 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// Destructor 34 35DNBDataRef::~DNBDataRef() = default; 36 37// Get8 38uint8_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// Get16 48uint16_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 offset 58 *offset_ptr += sizeof(val); 59 } 60 return val; 61} 62 63// Get32 64uint32_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 offset 73 *offset_ptr += sizeof(val); 74 } 75 return val; 76} 77 78// Get64 79uint64_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 offset 88 *offset_ptr += sizeof(val); 89 } 90 return val; 91} 92 93// GetMax32 94// 95// Used for calls when the size can vary. Fill in extra cases if they 96// 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// GetMax64 116// 117// Used for calls when the size can vary. Fill in extra cases if they 118// 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// GetPointer 141// 142// Extract a pointer value from the buffer. The pointer size must be 143// 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 call 146 assert(m_ptrSize != 0); 147 return GetMax64(offset_ptr, m_ptrSize); 148} 149// GetCStr 150const 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 offset 157 if (fixed_length) 158 *offset_ptr += fixed_length; 159 else 160 *offset_ptr += strlen(s) + 1; 161 } 162 return s; 163} 164 165// GetData 166const 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_ULEB128 177uint64_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_SLEB128 200int64_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_LEB128 230// 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 string 257 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 each 266 // iteration through this loop 267 if (str_offset >= sizeof(str)) { 268 // The last snprintf consumed our string buffer, we will need to dump this 269 // out 270 // and reset the string with no address 271 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 str 277 // above, so it is safe to make 278 // the snprintf call each time through this loop 279 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 up 320} 321