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