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 case 2: 119 return Get16(offset_ptr); 120 case 4: 121 return Get32(offset_ptr); 122 default: 123 llvm_unreachable("GetMax32 unhandled case!"); 124 } 125 } 126 127 //---------------------------------------------------------------------- 128 // GetMax64 129 // 130 // Used for calls when the size can vary. Fill in extra cases if they 131 // are ever needed. 132 //---------------------------------------------------------------------- 133 uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const { 134 switch (size) { 135 case 1: 136 return Get8(offset_ptr); 137 case 2: 138 return Get16(offset_ptr); 139 case 4: 140 return Get32(offset_ptr); 141 case 8: 142 return Get64(offset_ptr); 143 default: 144 llvm_unreachable("GetMax64 unhandled case!"); 145 } 146 } 147 148 //---------------------------------------------------------------------- 149 // GetPointer 150 // 151 // Extract a pointer value from the buffer. The pointer size must be 152 // set prior to using this using one of the SetPointerSize functions. 153 //---------------------------------------------------------------------- 154 uint64_t DNBDataRef::GetPointer(offset_t *offset_ptr) const { 155 // Must set pointer size prior to using this call 156 assert(m_ptrSize != 0); 157 return GetMax64(offset_ptr, m_ptrSize); 158 } 159 //---------------------------------------------------------------------- 160 // GetCStr 161 //---------------------------------------------------------------------- 162 const char *DNBDataRef::GetCStr(offset_t *offset_ptr, 163 uint32_t fixed_length) const { 164 const char *s = NULL; 165 if (m_start < m_end) { 166 s = (char *)m_start + *offset_ptr; 167 168 // Advance the offset 169 if (fixed_length) 170 *offset_ptr += fixed_length; 171 else 172 *offset_ptr += strlen(s) + 1; 173 } 174 return s; 175 } 176 177 //---------------------------------------------------------------------- 178 // GetData 179 //---------------------------------------------------------------------- 180 const uint8_t *DNBDataRef::GetData(offset_t *offset_ptr, 181 uint32_t length) const { 182 const uint8_t *data = NULL; 183 if (length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length)) { 184 data = m_start + *offset_ptr; 185 *offset_ptr += length; 186 } 187 return data; 188 } 189 190 //---------------------------------------------------------------------- 191 // Get_ULEB128 192 //---------------------------------------------------------------------- 193 uint64_t DNBDataRef::Get_ULEB128(offset_t *offset_ptr) const { 194 uint64_t result = 0; 195 if (m_start < m_end) { 196 int shift = 0; 197 const uint8_t *src = m_start + *offset_ptr; 198 uint8_t byte; 199 int bytecount = 0; 200 201 while (src < m_end) { 202 bytecount++; 203 byte = *src++; 204 result |= (uint64_t)(byte & 0x7f) << shift; 205 shift += 7; 206 if ((byte & 0x80) == 0) 207 break; 208 } 209 210 *offset_ptr += bytecount; 211 } 212 return result; 213 } 214 215 //---------------------------------------------------------------------- 216 // Get_SLEB128 217 //---------------------------------------------------------------------- 218 int64_t DNBDataRef::Get_SLEB128(offset_t *offset_ptr) const { 219 int64_t result = 0; 220 221 if (m_start < m_end) { 222 int shift = 0; 223 int size = sizeof(uint32_t) * 8; 224 const uint8_t *src = m_start + *offset_ptr; 225 226 uint8_t byte = 0; 227 int bytecount = 0; 228 229 while (src < m_end) { 230 bytecount++; 231 byte = *src++; 232 result |= (int64_t)(byte & 0x7f) << shift; 233 shift += 7; 234 if ((byte & 0x80) == 0) 235 break; 236 } 237 238 // Sign bit of byte is 2nd high order bit (0x40) 239 if (shift < size && (byte & 0x40)) 240 result |= -(1ll << shift); 241 242 *offset_ptr += bytecount; 243 } 244 return result; 245 } 246 247 //---------------------------------------------------------------------- 248 // Skip_LEB128 249 // 250 // Skips past ULEB128 and SLEB128 numbers (just updates the offset) 251 //---------------------------------------------------------------------- 252 void DNBDataRef::Skip_LEB128(offset_t *offset_ptr) const { 253 if (m_start < m_end) { 254 const uint8_t *start = m_start + *offset_ptr; 255 const uint8_t *src = start; 256 257 while ((src < m_end) && (*src++ & 0x80)) 258 /* Do nothing */; 259 260 *offset_ptr += src - start; 261 } 262 } 263 264 uint32_t DNBDataRef::Dump(uint32_t startOffset, uint32_t endOffset, 265 uint64_t offsetBase, DNBDataRef::Type type, 266 uint32_t numPerLine, const char *format) { 267 uint32_t offset; 268 uint32_t count; 269 char str[1024]; 270 str[0] = '\0'; 271 size_t str_offset = 0; 272 273 for (offset = startOffset, count = 0; 274 ValidOffset(offset) && offset < endOffset; ++count) { 275 if ((count % numPerLine) == 0) { 276 // Print out any previous string 277 if (str[0] != '\0') 278 DNBLog("%s", str); 279 // Reset string offset and fill the current line string with address: 280 str_offset = 0; 281 str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", 282 (uint64_t)(offsetBase + (offset - startOffset))); 283 } 284 285 // Make sure we don't pass the bounds of our current string buffer on each 286 // iteration through this loop 287 if (str_offset >= sizeof(str)) { 288 // The last snprintf consumed our string buffer, we will need to dump this 289 // out 290 // and reset the string with no address 291 DNBLog("%s", str); 292 str_offset = 0; 293 str[0] = '\0'; 294 } 295 296 // We already checked that there is at least some room in the string str 297 // above, so it is safe to make 298 // the snprintf call each time through this loop 299 switch (type) { 300 case TypeUInt8: 301 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 302 format ? format : " %2.2x", Get8(&offset)); 303 break; 304 case TypeChar: { 305 char ch = Get8(&offset); 306 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 307 format ? format : " %c", isprint(ch) ? ch : ' '); 308 } break; 309 case TypeUInt16: 310 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 311 format ? format : " %4.4x", Get16(&offset)); 312 break; 313 case TypeUInt32: 314 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 315 format ? format : " %8.8x", Get32(&offset)); 316 break; 317 case TypeUInt64: 318 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 319 format ? format : " %16.16llx", Get64(&offset)); 320 break; 321 case TypePointer: 322 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 323 format ? format : " 0x%llx", GetPointer(&offset)); 324 break; 325 case TypeULEB128: 326 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 327 format ? format : " 0x%llx", Get_ULEB128(&offset)); 328 break; 329 case TypeSLEB128: 330 str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, 331 format ? format : " %lld", Get_SLEB128(&offset)); 332 break; 333 } 334 } 335 336 if (str[0] != '\0') 337 DNBLog("%s", str); 338 339 return offset; // Return the offset at which we ended up 340 } 341