1 //===-- DNBDataRef.cpp ------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Created by Greg Clayton on 1/11/06. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "DNBDataRef.h" 15 #include "DNBLog.h" 16 #include <assert.h> 17 #include <ctype.h> 18 #include <libkern/OSByteOrder.h> 19 20 //---------------------------------------------------------------------- 21 // Constructor 22 //---------------------------------------------------------------------- 23 24 DNBDataRef::DNBDataRef() : 25 m_start(NULL), 26 m_end(NULL), 27 m_swap(false), 28 m_ptrSize(0), 29 m_addrPCRelative(INVALID_NUB_ADDRESS), 30 m_addrTEXT(INVALID_NUB_ADDRESS), 31 m_addrDATA(INVALID_NUB_ADDRESS) 32 { 33 } 34 35 36 //---------------------------------------------------------------------- 37 // Constructor 38 //---------------------------------------------------------------------- 39 40 DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap) : 41 m_start(start), 42 m_end(start+size), 43 m_swap(swap), 44 m_ptrSize(0), 45 m_addrPCRelative(INVALID_NUB_ADDRESS), 46 m_addrTEXT(INVALID_NUB_ADDRESS), 47 m_addrDATA(INVALID_NUB_ADDRESS) 48 { 49 } 50 51 52 //---------------------------------------------------------------------- 53 // Destructor 54 //---------------------------------------------------------------------- 55 56 DNBDataRef::~DNBDataRef() 57 { 58 } 59 60 61 //---------------------------------------------------------------------- 62 // Get8 63 //---------------------------------------------------------------------- 64 uint8_t 65 DNBDataRef::Get8(offset_t *offset_ptr) const 66 { 67 uint8_t val = 0; 68 if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) ) 69 { 70 val = *(m_start + *offset_ptr); 71 *offset_ptr += sizeof(val); 72 } 73 return val; 74 } 75 76 77 //---------------------------------------------------------------------- 78 // Get16 79 //---------------------------------------------------------------------- 80 uint16_t 81 DNBDataRef::Get16(offset_t *offset_ptr) const 82 { 83 uint16_t val = 0; 84 if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) ) 85 { 86 const uint8_t *p = m_start + *offset_ptr; 87 val = *(uint16_t*)p; 88 89 if (m_swap) 90 val = OSSwapInt16(val); 91 92 // Advance the offset 93 *offset_ptr += sizeof(val); 94 } 95 return val; 96 } 97 98 99 //---------------------------------------------------------------------- 100 // Get32 101 //---------------------------------------------------------------------- 102 uint32_t 103 DNBDataRef::Get32(offset_t *offset_ptr) const 104 { 105 uint32_t val = 0; 106 if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) ) 107 { 108 const uint8_t *p = m_start + *offset_ptr; 109 val = *(uint32_t*)p; 110 if (m_swap) 111 val = OSSwapInt32(val); 112 113 // Advance the offset 114 *offset_ptr += sizeof(val); 115 } 116 return val; 117 } 118 119 120 //---------------------------------------------------------------------- 121 // Get64 122 //---------------------------------------------------------------------- 123 uint64_t 124 DNBDataRef::Get64(offset_t *offset_ptr) const 125 { 126 uint64_t val = 0; 127 if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) ) 128 { 129 const uint8_t *p = m_start + *offset_ptr; 130 val = *(uint64_t*)p; 131 if (m_swap) 132 val = OSSwapInt64(val); 133 134 // Advance the offset 135 *offset_ptr += sizeof(val); 136 } 137 return val; 138 } 139 140 141 //---------------------------------------------------------------------- 142 // GetMax32 143 // 144 // Used for calls when the size can vary. Fill in extra cases if they 145 // are ever needed. 146 //---------------------------------------------------------------------- 147 uint32_t 148 DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const 149 { 150 switch (byte_size) 151 { 152 case 1: return Get8 (offset_ptr); break; 153 case 2: return Get16(offset_ptr); break; 154 case 4: return Get32(offset_ptr); break; 155 default: 156 assert(!"GetMax32 unhandled case!"); 157 break; 158 } 159 return 0; 160 } 161 162 163 //---------------------------------------------------------------------- 164 // GetMax64 165 // 166 // Used for calls when the size can vary. Fill in extra cases if they 167 // are ever needed. 168 //---------------------------------------------------------------------- 169 uint64_t 170 DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const 171 { 172 switch (size) 173 { 174 case 1: return Get8 (offset_ptr); break; 175 case 2: return Get16(offset_ptr); break; 176 case 4: return Get32(offset_ptr); break; 177 case 8: return Get64(offset_ptr); break; 178 default: 179 assert(!"GetMax64 unhandled case!"); 180 break; 181 } 182 return 0; 183 } 184 185 //---------------------------------------------------------------------- 186 // GetPointer 187 // 188 // Extract a pointer value from the buffer. The pointer size must be 189 // set prior to using this using one of the SetPointerSize functions. 190 //---------------------------------------------------------------------- 191 uint64_t 192 DNBDataRef::GetPointer(offset_t *offset_ptr) const 193 { 194 // Must set pointer size prior to using this call 195 assert(m_ptrSize != 0); 196 return GetMax64(offset_ptr, m_ptrSize); 197 } 198 199 //---------------------------------------------------------------------- 200 // GetDwarfEHPtr 201 // 202 // Used for calls when the value type is specified by a DWARF EH Frame 203 // pointer encoding. 204 //---------------------------------------------------------------------- 205 /* 206 uint64_t 207 DNBDataRef::GetDwarfEHPtr(offset_t *offset_ptr, uint32_t encoding) const 208 { 209 if (encoding == DW_EH_PE_omit) 210 return ULLONG_MAX; // Value isn't in the buffer... 211 212 uint64_t baseAddress = 0; 213 uint64_t addressValue = 0; 214 215 BOOL signExtendValue = NO; 216 // Decode the base part or adjust our offset 217 switch (encoding & 0x70) 218 { 219 case DW_EH_PE_pcrel: 220 // SetEHPtrBaseAddresses should be called prior to extracting these 221 // so the base addresses are cached. 222 assert(m_addrPCRelative != INVALID_NUB_ADDRESS); 223 signExtendValue = YES; 224 baseAddress = *offset_ptr + m_addrPCRelative; 225 break; 226 227 case DW_EH_PE_textrel: 228 // SetEHPtrBaseAddresses should be called prior to extracting these 229 // so the base addresses are cached. 230 assert(m_addrTEXT != INVALID_NUB_ADDRESS); 231 signExtendValue = YES; 232 baseAddress = m_addrTEXT; 233 break; 234 235 case DW_EH_PE_datarel: 236 // SetEHPtrBaseAddresses should be called prior to extracting these 237 // so the base addresses are cached. 238 assert(m_addrDATA != INVALID_NUB_ADDRESS); 239 signExtendValue = YES; 240 baseAddress = m_addrDATA; 241 break; 242 243 case DW_EH_PE_funcrel: 244 signExtendValue = YES; 245 break; 246 247 case DW_EH_PE_aligned: 248 // SetPointerSize should be called prior to extracting these so the 249 // pointer size is cached 250 assert(m_ptrSize != 0); 251 if (m_ptrSize) 252 { 253 // Align to a address size boundary first 254 uint32_t alignOffset = *offset_ptr % m_ptrSize; 255 if (alignOffset) 256 offset_ptr += m_ptrSize - alignOffset; 257 } 258 break; 259 260 default: 261 break; 262 } 263 264 // Decode the value part 265 switch (encoding & DW_EH_PE_MASK_ENCODING) 266 { 267 case DW_EH_PE_absptr : addressValue = GetPointer(offset_ptr); break; 268 case DW_EH_PE_uleb128 : addressValue = Get_ULEB128(offset_ptr); break; 269 case DW_EH_PE_udata2 : addressValue = Get16(offset_ptr); break; 270 case DW_EH_PE_udata4 : addressValue = Get32(offset_ptr); break; 271 case DW_EH_PE_udata8 : addressValue = Get64(offset_ptr); break; 272 case DW_EH_PE_sleb128 : addressValue = Get_SLEB128(offset_ptr); break; 273 case DW_EH_PE_sdata2 : addressValue = (int16_t)Get16(offset_ptr); break; 274 case DW_EH_PE_sdata4 : addressValue = (int32_t)Get32(offset_ptr); break; 275 case DW_EH_PE_sdata8 : addressValue = (int64_t)Get64(offset_ptr); break; 276 default: 277 // Unhandled encoding type 278 assert(encoding); 279 break; 280 } 281 282 // Since we promote everything to 64 bit, we may need to sign extend 283 if (signExtendValue && m_ptrSize < sizeof(baseAddress)) 284 { 285 uint64_t sign_bit = 1ull << ((m_ptrSize * 8ull) - 1ull); 286 if (sign_bit & addressValue) 287 { 288 uint64_t mask = ~sign_bit + 1; 289 addressValue |= mask; 290 } 291 } 292 return baseAddress + addressValue; 293 } 294 */ 295 296 297 //---------------------------------------------------------------------- 298 // GetCStr 299 //---------------------------------------------------------------------- 300 const char * 301 DNBDataRef::GetCStr(offset_t *offset_ptr, uint32_t fixed_length) const 302 { 303 const char *s = NULL; 304 if ( m_start < m_end ) 305 { 306 s = (char*)m_start + *offset_ptr; 307 308 // Advance the offset 309 if (fixed_length) 310 *offset_ptr += fixed_length; 311 else 312 *offset_ptr += strlen(s) + 1; 313 } 314 return s; 315 } 316 317 318 //---------------------------------------------------------------------- 319 // GetData 320 //---------------------------------------------------------------------- 321 const uint8_t * 322 DNBDataRef::GetData(offset_t *offset_ptr, uint32_t length) const 323 { 324 const uint8_t *data = NULL; 325 if ( length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length) ) 326 { 327 data = m_start + *offset_ptr; 328 *offset_ptr += length; 329 } 330 return data; 331 } 332 333 334 //---------------------------------------------------------------------- 335 // Get_ULEB128 336 //---------------------------------------------------------------------- 337 uint64_t 338 DNBDataRef::Get_ULEB128 (offset_t *offset_ptr) const 339 { 340 uint64_t result = 0; 341 if ( m_start < m_end ) 342 { 343 int shift = 0; 344 const uint8_t *src = m_start + *offset_ptr; 345 uint8_t byte; 346 int bytecount = 0; 347 348 while (src < m_end) 349 { 350 bytecount++; 351 byte = *src++; 352 result |= (byte & 0x7f) << shift; 353 shift += 7; 354 if ((byte & 0x80) == 0) 355 break; 356 } 357 358 *offset_ptr += bytecount; 359 } 360 return result; 361 } 362 363 364 //---------------------------------------------------------------------- 365 // Get_SLEB128 366 //---------------------------------------------------------------------- 367 int64_t 368 DNBDataRef::Get_SLEB128 (offset_t *offset_ptr) const 369 { 370 int64_t result = 0; 371 372 if ( m_start < m_end ) 373 { 374 int shift = 0; 375 int size = sizeof (uint32_t) * 8; 376 const uint8_t *src = m_start + *offset_ptr; 377 378 uint8_t byte = 0; 379 int bytecount = 0; 380 381 while (src < m_end) 382 { 383 bytecount++; 384 byte = *src++; 385 result |= (byte & 0x7f) << shift; 386 shift += 7; 387 if ((byte & 0x80) == 0) 388 break; 389 } 390 391 // Sign bit of byte is 2nd high order bit (0x40) 392 if (shift < size && (byte & 0x40)) 393 result |= - (1ll << shift); 394 395 *offset_ptr += bytecount; 396 } 397 return result; 398 } 399 400 401 //---------------------------------------------------------------------- 402 // Skip_LEB128 403 // 404 // Skips past ULEB128 and SLEB128 numbers (just updates the offset) 405 //---------------------------------------------------------------------- 406 void 407 DNBDataRef::Skip_LEB128 (offset_t *offset_ptr) const 408 { 409 if ( m_start < m_end ) 410 { 411 const uint8_t *start = m_start + *offset_ptr; 412 const uint8_t *src = start; 413 414 while ((src < m_end) && (*src++ & 0x80)) 415 /* Do nothing */; 416 417 *offset_ptr += src - start; 418 } 419 } 420 421 uint32_t 422 DNBDataRef::Dump 423 ( 424 uint32_t startOffset, 425 uint32_t endOffset, 426 uint64_t offsetBase, 427 DNBDataRef::Type type, 428 uint32_t numPerLine, 429 const char *format 430 ) 431 { 432 uint32_t offset; 433 uint32_t count; 434 char str[1024]; 435 str[0] = '\0'; 436 int str_offset = 0; 437 438 for (offset = startOffset, count = 0; ValidOffset(offset) && offset < endOffset; ++count) 439 { 440 if ((count % numPerLine) == 0) 441 { 442 // Print out any previous string 443 if (str[0] != '\0') 444 DNBLog("%s", str); 445 // Reset string offset and fill the current line string with address: 446 str_offset = 0; 447 str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", (uint64_t)(offsetBase + (offset - startOffset))); 448 } 449 450 // Make sure we don't pass the bounds of our current string buffer on each iteration through this loop 451 if (str_offset >= sizeof(str)) 452 { 453 // The last snprintf consumed our string buffer, we will need to dump this out 454 // and reset the string with no address 455 DNBLog("%s", str); 456 str_offset = 0; 457 str[0] = '\0'; 458 } 459 460 // We already checked that there is at least some room in the string str above, so it is safe to make 461 // the snprintf call each time through this loop 462 switch (type) 463 { 464 default: 465 case TypeUInt8: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %2.2x", Get8(&offset)); break; 466 case TypeChar: 467 { 468 char ch = Get8(&offset); 469 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %c", isprint(ch) ? ch : ' '); 470 } 471 break; 472 case TypeUInt16: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %4.4x", Get16(&offset)); break; 473 case TypeUInt32: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %8.8x", Get32(&offset)); break; 474 case TypeUInt64: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %16.16llx", Get64(&offset)); break; 475 case TypePointer: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx", GetPointer(&offset)); break; 476 case TypeULEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx", Get_ULEB128(&offset)); break; 477 case TypeSLEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %lld", Get_SLEB128(&offset)); break; 478 } 479 } 480 481 if (str[0] != '\0') 482 DNBLog("%s", str); 483 484 return offset; // Return the offset at which we ended up 485 } 486