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// GetCStr 200//---------------------------------------------------------------------- 201const char * 202DNBDataRef::GetCStr(offset_t *offset_ptr, uint32_t fixed_length) const 203{ 204 const char *s = NULL; 205 if ( m_start < m_end ) 206 { 207 s = (char*)m_start + *offset_ptr; 208 209 // Advance the offset 210 if (fixed_length) 211 *offset_ptr += fixed_length; 212 else 213 *offset_ptr += strlen(s) + 1; 214 } 215 return s; 216} 217 218 219//---------------------------------------------------------------------- 220// GetData 221//---------------------------------------------------------------------- 222const uint8_t * 223DNBDataRef::GetData(offset_t *offset_ptr, uint32_t length) const 224{ 225 const uint8_t *data = NULL; 226 if ( length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length) ) 227 { 228 data = m_start + *offset_ptr; 229 *offset_ptr += length; 230 } 231 return data; 232} 233 234 235//---------------------------------------------------------------------- 236// Get_ULEB128 237//---------------------------------------------------------------------- 238uint64_t 239DNBDataRef::Get_ULEB128 (offset_t *offset_ptr) const 240{ 241 uint64_t result = 0; 242 if ( m_start < m_end ) 243 { 244 int shift = 0; 245 const uint8_t *src = m_start + *offset_ptr; 246 uint8_t byte; 247 int bytecount = 0; 248 249 while (src < m_end) 250 { 251 bytecount++; 252 byte = *src++; 253 result |= (byte & 0x7f) << shift; 254 shift += 7; 255 if ((byte & 0x80) == 0) 256 break; 257 } 258 259 *offset_ptr += bytecount; 260 } 261 return result; 262} 263 264 265//---------------------------------------------------------------------- 266// Get_SLEB128 267//---------------------------------------------------------------------- 268int64_t 269DNBDataRef::Get_SLEB128 (offset_t *offset_ptr) const 270{ 271 int64_t result = 0; 272 273 if ( m_start < m_end ) 274 { 275 int shift = 0; 276 int size = sizeof (uint32_t) * 8; 277 const uint8_t *src = m_start + *offset_ptr; 278 279 uint8_t byte = 0; 280 int bytecount = 0; 281 282 while (src < m_end) 283 { 284 bytecount++; 285 byte = *src++; 286 result |= (byte & 0x7f) << shift; 287 shift += 7; 288 if ((byte & 0x80) == 0) 289 break; 290 } 291 292 // Sign bit of byte is 2nd high order bit (0x40) 293 if (shift < size && (byte & 0x40)) 294 result |= - (1ll << shift); 295 296 *offset_ptr += bytecount; 297 } 298 return result; 299} 300 301 302//---------------------------------------------------------------------- 303// Skip_LEB128 304// 305// Skips past ULEB128 and SLEB128 numbers (just updates the offset) 306//---------------------------------------------------------------------- 307void 308DNBDataRef::Skip_LEB128 (offset_t *offset_ptr) const 309{ 310 if ( m_start < m_end ) 311 { 312 const uint8_t *start = m_start + *offset_ptr; 313 const uint8_t *src = start; 314 315 while ((src < m_end) && (*src++ & 0x80)) 316 /* Do nothing */; 317 318 *offset_ptr += src - start; 319 } 320} 321 322uint32_t 323DNBDataRef::Dump 324( 325 uint32_t startOffset, 326 uint32_t endOffset, 327 uint64_t offsetBase, 328 DNBDataRef::Type type, 329 uint32_t numPerLine, 330 const char *format 331) 332{ 333 uint32_t offset; 334 uint32_t count; 335 char str[1024]; 336 str[0] = '\0'; 337 int str_offset = 0; 338 339 for (offset = startOffset, count = 0; ValidOffset(offset) && offset < endOffset; ++count) 340 { 341 if ((count % numPerLine) == 0) 342 { 343 // Print out any previous string 344 if (str[0] != '\0') 345 DNBLog("%s", str); 346 // Reset string offset and fill the current line string with address: 347 str_offset = 0; 348 str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", (uint64_t)(offsetBase + (offset - startOffset))); 349 } 350 351 // Make sure we don't pass the bounds of our current string buffer on each iteration through this loop 352 if (str_offset >= sizeof(str)) 353 { 354 // The last snprintf consumed our string buffer, we will need to dump this out 355 // and reset the string with no address 356 DNBLog("%s", str); 357 str_offset = 0; 358 str[0] = '\0'; 359 } 360 361 // We already checked that there is at least some room in the string str above, so it is safe to make 362 // the snprintf call each time through this loop 363 switch (type) 364 { 365 default: 366 case TypeUInt8: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %2.2x", Get8(&offset)); break; 367 case TypeChar: 368 { 369 char ch = Get8(&offset); 370 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %c", isprint(ch) ? ch : ' '); 371 } 372 break; 373 case TypeUInt16: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %4.4x", Get16(&offset)); break; 374 case TypeUInt32: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %8.8x", Get32(&offset)); break; 375 case TypeUInt64: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %16.16llx", Get64(&offset)); break; 376 case TypePointer: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx", GetPointer(&offset)); break; 377 case TypeULEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx", Get_ULEB128(&offset)); break; 378 case TypeSLEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %lld", Get_SLEB128(&offset)); break; 379 } 380 } 381 382 if (str[0] != '\0') 383 DNBLog("%s", str); 384 385 return offset; // Return the offset at which we ended up 386} 387