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 <assert.h> 16 #include <ctype.h> 17 #include <libkern/OSByteOrder.h> 18 19 //---------------------------------------------------------------------- 20 // Constructor 21 //---------------------------------------------------------------------- 22 23 DNBDataRef::DNBDataRef() 24 : m_start(NULL), m_end(NULL), m_swap(false), m_ptrSize(0), 25 m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS), 26 m_addrDATA(INVALID_NUB_ADDRESS) {} 27 28 //---------------------------------------------------------------------- 29 // Constructor 30 //---------------------------------------------------------------------- 31 32 DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap) 33 : m_start(start), m_end(start + size), m_swap(swap), m_ptrSize(0), 34 m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS), 35 m_addrDATA(INVALID_NUB_ADDRESS) {} 36 37 //---------------------------------------------------------------------- 38 // Destructor 39 //---------------------------------------------------------------------- 40 41 DNBDataRef::~DNBDataRef() {} 42 43 //---------------------------------------------------------------------- 44 // Get8 45 //---------------------------------------------------------------------- 46 uint8_t DNBDataRef::Get8(offset_t *offset_ptr) const { 47 uint8_t val = 0; 48 if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { 49 val = *(m_start + *offset_ptr); 50 *offset_ptr += sizeof(val); 51 } 52 return val; 53 } 54 55 //---------------------------------------------------------------------- 56 // Get16 57 //---------------------------------------------------------------------- 58 uint16_t DNBDataRef::Get16(offset_t *offset_ptr) const { 59 uint16_t val = 0; 60 if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { 61 const uint8_t *p = m_start + *offset_ptr; 62 memcpy(&val, p, sizeof(uint16_t)); 63 64 if (m_swap) 65 val = OSSwapInt16(val); 66 67 // Advance the offset 68 *offset_ptr += sizeof(val); 69 } 70 return val; 71 } 72 73 //---------------------------------------------------------------------- 74 // Get32 75 //---------------------------------------------------------------------- 76 uint32_t DNBDataRef::Get32(offset_t *offset_ptr) const { 77 uint32_t val = 0; 78 if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { 79 const uint8_t *p = m_start + *offset_ptr; 80 memcpy(&val, p, sizeof(uint32_t)); 81 if (m_swap) 82 val = OSSwapInt32(val); 83 84 // Advance the offset 85 *offset_ptr += sizeof(val); 86 } 87 return val; 88 } 89 90 //---------------------------------------------------------------------- 91 // Get64 92 //---------------------------------------------------------------------- 93 uint64_t DNBDataRef::Get64(offset_t *offset_ptr) const { 94 uint64_t val = 0; 95 if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { 96 const uint8_t *p = m_start + *offset_ptr; 97 memcpy(&val, p, sizeof(uint64_t)); 98 if (m_swap) 99 val = OSSwapInt64(val); 100 101 // Advance the offset 102 *offset_ptr += sizeof(val); 103 } 104 return val; 105 } 106 107 //---------------------------------------------------------------------- 108 // GetMax32 109 // 110 // Used for calls when the size can vary. Fill in extra cases if they 111 // are ever needed. 112 //---------------------------------------------------------------------- 113 uint32_t DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const { 114 switch (byte_size) { 115 case 1: 116 return Get8(offset_ptr); 117 break; 118 case 2: 119 return Get16(offset_ptr); 120 break; 121 case 4: 122 return Get32(offset_ptr); 123 break; 124 default: 125 assert(false && "GetMax32 unhandled case!"); 126 break; 127 } 128 return 0; 129 } 130 131 //---------------------------------------------------------------------- 132 // GetMax64 133 // 134 // Used for calls when the size can vary. Fill in extra cases if they 135 // are ever needed. 136 //---------------------------------------------------------------------- 137 uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const { 138 switch (size) { 139 case 1: 140 return Get8(offset_ptr); 141 break; 142 case 2: 143 return Get16(offset_ptr); 144 break; 145 case 4: 146 return Get32(offset_ptr); 147 break; 148 case 8: 149 return Get64(offset_ptr); 150 break; 151 default: 152 assert(false && "GetMax64 unhandled case!"); 153 break; 154 } 155 return 0; 156 } 157 158 //---------------------------------------------------------------------- 159 // GetPointer 160 // 161 // Extract a pointer value from the buffer. The pointer size must be 162 // set prior to using this using one of the SetPointerSize functions. 163 //---------------------------------------------------------------------- 164 uint64_t DNBDataRef::GetPointer(offset_t *offset_ptr) const { 165 // Must set pointer size prior to using this call 166 assert(m_ptrSize != 0); 167 return GetMax64(offset_ptr, m_ptrSize); 168 } 169 //---------------------------------------------------------------------- 170 // GetCStr 171 //---------------------------------------------------------------------- 172 const char *DNBDataRef::GetCStr(offset_t *offset_ptr, 173 uint32_t fixed_length) const { 174 const char *s = NULL; 175 if (m_start < m_end) { 176 s = (const char *)m_start + *offset_ptr; 177 178 // Advance the offset 179 if (fixed_length) 180 *offset_ptr += fixed_length; 181 else 182 *offset_ptr += strlen(s) + 1; 183 } 184 return s; 185 } 186 187 //---------------------------------------------------------------------- 188 // GetData 189 //---------------------------------------------------------------------- 190 const uint8_t *DNBDataRef::GetData(offset_t *offset_ptr, 191 uint32_t length) const { 192 const uint8_t *data = NULL; 193 if (length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length)) { 194 data = m_start + *offset_ptr; 195 *offset_ptr += length; 196 } 197 return data; 198 } 199 200 //---------------------------------------------------------------------- 201 // Get_ULEB128 202 //---------------------------------------------------------------------- 203 uint64_t DNBDataRef::Get_ULEB128(offset_t *offset_ptr) const { 204 uint64_t result = 0; 205 if (m_start < m_end) { 206 int shift = 0; 207 const uint8_t *src = m_start + *offset_ptr; 208 uint8_t byte; 209 int bytecount = 0; 210 211 while (src < m_end) { 212 bytecount++; 213 byte = *src++; 214 result |= (uint64_t)(byte & 0x7f) << shift; 215 shift += 7; 216 if ((byte & 0x80) == 0) 217 break; 218 } 219 220 *offset_ptr += bytecount; 221 } 222 return result; 223 } 224 225 //---------------------------------------------------------------------- 226 // Get_SLEB128 227 //---------------------------------------------------------------------- 228 int64_t DNBDataRef::Get_SLEB128(offset_t *offset_ptr) const { 229 int64_t result = 0; 230 231 if (m_start < m_end) { 232 int shift = 0; 233 int size = sizeof(uint32_t) * 8; 234 const uint8_t *src = m_start + *offset_ptr; 235 236 uint8_t byte = 0; 237 int bytecount = 0; 238 239 while (src < m_end) { 240 bytecount++; 241 byte = *src++; 242 result |= (int64_t)(byte & 0x7f) << shift; 243 shift += 7; 244 if ((byte & 0x80) == 0) 245 break; 246 } 247 248 // Sign bit of byte is 2nd high order bit (0x40) 249 if (shift < size && (byte & 0x40)) 250 result |= -(1ll << shift); 251 252 *offset_ptr += bytecount; 253 } 254 return result; 255 } 256 257 //---------------------------------------------------------------------- 258 // Skip_LEB128 259 // 260 // Skips past ULEB128 and SLEB128 numbers (just updates the offset) 261 //---------------------------------------------------------------------- 262 void DNBDataRef::Skip_LEB128(offset_t *offset_ptr) const { 263 if (m_start < m_end) { 264 const uint8_t *start = m_start + *offset_ptr; 265 const uint8_t *src = start; 266 267 while ((src < m_end) && (*src++ & 0x80)) 268 /* Do nothing */; 269 270 *offset_ptr += src - start; 271 } 272 } 273 274 uint32_t DNBDataRef::Dump(uint32_t startOffset, uint32_t endOffset, 275 uint64_t offsetBase, DNBDataRef::Type type, 276 uint32_t numPerLine, const char *format) { 277 uint32_t offset; 278 uint32_t count; 279 char str[1024]; 280 str[0] = '\0'; 281 size_t str_offset = 0; 282 283 for (offset = startOffset, count = 0; 284 ValidOffset(offset) && offset < endOffset; ++count) { 285 if ((count % numPerLine) == 0) { 286 // Print out any previous string 287 if (str[0] != '\0') 288 DNBLog("%s", str); 289 // Reset string offset and fill the current line string with address: 290 str_offset = 0; 291 str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", 292 (uint64_t)(offsetBase + (offset - startOffset))); 293 } 294 295 // Make sure we don't pass the bounds of our current string buffer on each 296 // iteration through this loop 297 if (str_offset >= sizeof(str)) { 298 // The last snprintf consumed our string buffer, we will need to dump this 299 // out 300 // and reset the string with no address 301 DNBLog("%s", str); 302 str_offset = 0; 303 str[0] = '\0'; 304 } 305 306 // We already checked that there is at least some room in the string str 307 // above, so it is safe to make 308 // the snprintf call each time through this loop 309 switch (type) { 310 case TypeUInt8: 311 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 312 format ? format : " %2.2x", Get8(&offset)); 313 break; 314 case TypeChar: { 315 char ch = Get8(&offset); 316 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 317 format ? format : " %c", isprint(ch) ? ch : ' '); 318 } break; 319 case TypeUInt16: 320 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 321 format ? format : " %4.4x", Get16(&offset)); 322 break; 323 case TypeUInt32: 324 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 325 format ? format : " %8.8x", Get32(&offset)); 326 break; 327 case TypeUInt64: 328 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 329 format ? format : " %16.16llx", Get64(&offset)); 330 break; 331 case TypePointer: 332 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 333 format ? format : " 0x%llx", GetPointer(&offset)); 334 break; 335 case TypeULEB128: 336 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 337 format ? format : " 0x%llx", Get_ULEB128(&offset)); 338 break; 339 case TypeSLEB128: 340 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 341 format ? format : " %lld", Get_SLEB128(&offset)); 342 break; 343 } 344 } 345 346 if (str[0] != '\0') 347 DNBLog("%s", str); 348 349 return offset; // Return the offset at which we ended up 350 } 351