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 // GetCStr 200 //---------------------------------------------------------------------- 201 const char * 202 DNBDataRef::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 //---------------------------------------------------------------------- 222 const uint8_t * 223 DNBDataRef::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 //---------------------------------------------------------------------- 238 uint64_t 239 DNBDataRef::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 //---------------------------------------------------------------------- 268 int64_t 269 DNBDataRef::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 //---------------------------------------------------------------------- 307 void 308 DNBDataRef::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 322 uint32_t 323 DNBDataRef::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