DNBDataRef.cpp revision 7559f33de7b3706324fcc8467179463f7aaec348
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 24DNBDataRef::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 40DNBDataRef::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 56DNBDataRef::~DNBDataRef() 57{ 58} 59 60 61//---------------------------------------------------------------------- 62// Get8 63//---------------------------------------------------------------------- 64uint8_t 65DNBDataRef::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//---------------------------------------------------------------------- 80uint16_t 81DNBDataRef::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//---------------------------------------------------------------------- 102uint32_t 103DNBDataRef::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//---------------------------------------------------------------------- 123uint64_t 124DNBDataRef::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//---------------------------------------------------------------------- 147uint32_t 148DNBDataRef::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//---------------------------------------------------------------------- 169uint64_t 170DNBDataRef::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//---------------------------------------------------------------------- 191uint64_t 192DNBDataRef::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/* 206uint64_t 207DNBDataRef::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//---------------------------------------------------------------------- 300const char * 301DNBDataRef::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//---------------------------------------------------------------------- 321const uint8_t * 322DNBDataRef::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//---------------------------------------------------------------------- 337uint64_t 338DNBDataRef::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//---------------------------------------------------------------------- 367int64_t 368DNBDataRef::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//---------------------------------------------------------------------- 406void 407DNBDataRef::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 421uint32_t 422DNBDataRef::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