1 #ifndef DWARF_I_H 2 #define DWARF_I_H 3 4 /* This file contains definitions that cannot be used in code outside 5 of libunwind. In particular, most inline functions are here 6 because otherwise they'd generate unresolved references when the 7 files are compiled with inlining disabled. */ 8 9 #include "dwarf.h" 10 #include "libunwind_i.h" 11 12 /* Unless we are told otherwise, assume that a "machine address" is 13 the size of an unw_word_t. */ 14 #ifndef dwarf_addr_size 15 # define dwarf_addr_size(as) (sizeof (unw_word_t)) 16 #endif 17 18 #ifndef dwarf_to_unw_regnum 19 # define dwarf_to_unw_regnum_map UNW_OBJ (dwarf_to_unw_regnum_map) 20 extern const uint8_t dwarf_to_unw_regnum_map[DWARF_REGNUM_MAP_LENGTH]; 21 /* REG is evaluated multiple times; it better be side-effects free! */ 22 # define dwarf_to_unw_regnum(reg) \ 23 (((reg) <= DWARF_REGNUM_MAP_LENGTH) ? dwarf_to_unw_regnum_map[reg] : 0) 24 #endif 25 26 #ifdef UNW_LOCAL_ONLY 27 28 /* In the local-only case, we can let the compiler directly access 29 memory and don't need to worry about differing byte-order. */ 30 31 typedef union __attribute__ ((packed)) 32 { 33 int8_t s8; 34 int16_t s16; 35 int32_t s32; 36 int64_t s64; 37 uint8_t u8; 38 uint16_t u16; 39 uint32_t u32; 40 uint64_t u64; 41 void *ptr; 42 } 43 dwarf_misaligned_value_t; 44 45 static inline int 46 dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 47 int8_t *val, void *arg) 48 { 49 dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; 50 51 *val = mvp->s8; 52 *addr += sizeof (mvp->s8); 53 return 0; 54 } 55 56 static inline int 57 dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 58 int16_t *val, void *arg) 59 { 60 dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; 61 62 *val = mvp->s16; 63 *addr += sizeof (mvp->s16); 64 return 0; 65 } 66 67 static inline int 68 dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 69 int32_t *val, void *arg) 70 { 71 dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; 72 73 *val = mvp->s32; 74 *addr += sizeof (mvp->s32); 75 return 0; 76 } 77 78 static inline int 79 dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 80 int64_t *val, void *arg) 81 { 82 dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; 83 84 *val = mvp->s64; 85 *addr += sizeof (mvp->s64); 86 return 0; 87 } 88 89 static inline int 90 dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 91 uint8_t *val, void *arg) 92 { 93 dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; 94 95 *val = mvp->u8; 96 *addr += sizeof (mvp->u8); 97 return 0; 98 } 99 100 static inline int 101 dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 102 uint16_t *val, void *arg) 103 { 104 dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; 105 106 *val = mvp->u16; 107 *addr += sizeof (mvp->u16); 108 return 0; 109 } 110 111 static inline int 112 dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 113 uint32_t *val, void *arg) 114 { 115 dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; 116 117 *val = mvp->u32; 118 *addr += sizeof (mvp->u32); 119 return 0; 120 } 121 122 static inline int 123 dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 124 uint64_t *val, void *arg) 125 { 126 dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; 127 128 *val = mvp->u64; 129 *addr += sizeof (mvp->u64); 130 return 0; 131 } 132 133 #else /* !UNW_LOCAL_ONLY */ 134 135 static inline int 136 dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 137 uint8_t *valp, void *arg) 138 { 139 unw_word_t val, aligned_addr = *addr & -sizeof (unw_word_t); 140 unw_word_t off = *addr - aligned_addr; 141 int ret; 142 143 *addr += 1; 144 ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg); 145 #if __BYTE_ORDER == __LITTLE_ENDIAN 146 val >>= 8*off; 147 #else 148 val >>= 8*(sizeof (unw_word_t) - 1 - off); 149 #endif 150 *valp = (uint8_t) val; 151 return ret; 152 } 153 154 static inline int 155 dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 156 uint16_t *val, void *arg) 157 { 158 uint8_t v0, v1; 159 int ret; 160 161 if ((ret = dwarf_readu8 (as, a, addr, &v0, arg)) < 0 162 || (ret = dwarf_readu8 (as, a, addr, &v1, arg)) < 0) 163 return ret; 164 165 if (tdep_big_endian (as)) 166 *val = (uint16_t) v0 << 8 | v1; 167 else 168 *val = (uint16_t) v1 << 8 | v0; 169 return 0; 170 } 171 172 static inline int 173 dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 174 uint32_t *val, void *arg) 175 { 176 uint16_t v0, v1; 177 int ret; 178 179 if ((ret = dwarf_readu16 (as, a, addr, &v0, arg)) < 0 180 || (ret = dwarf_readu16 (as, a, addr, &v1, arg)) < 0) 181 return ret; 182 183 if (tdep_big_endian (as)) 184 *val = (uint32_t) v0 << 16 | v1; 185 else 186 *val = (uint32_t) v1 << 16 | v0; 187 return 0; 188 } 189 190 static inline int 191 dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 192 uint64_t *val, void *arg) 193 { 194 uint32_t v0, v1; 195 int ret; 196 197 if ((ret = dwarf_readu32 (as, a, addr, &v0, arg)) < 0 198 || (ret = dwarf_readu32 (as, a, addr, &v1, arg)) < 0) 199 return ret; 200 201 if (tdep_big_endian (as)) 202 *val = (uint64_t) v0 << 32 | v1; 203 else 204 *val = (uint64_t) v1 << 32 | v0; 205 return 0; 206 } 207 208 static inline int 209 dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 210 int8_t *val, void *arg) 211 { 212 uint8_t uval; 213 int ret; 214 215 if ((ret = dwarf_readu8 (as, a, addr, &uval, arg)) < 0) 216 return ret; 217 *val = (int8_t) uval; 218 return 0; 219 } 220 221 static inline int 222 dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 223 int16_t *val, void *arg) 224 { 225 uint16_t uval; 226 int ret; 227 228 if ((ret = dwarf_readu16 (as, a, addr, &uval, arg)) < 0) 229 return ret; 230 *val = (int16_t) uval; 231 return 0; 232 } 233 234 static inline int 235 dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 236 int32_t *val, void *arg) 237 { 238 uint32_t uval; 239 int ret; 240 241 if ((ret = dwarf_readu32 (as, a, addr, &uval, arg)) < 0) 242 return ret; 243 *val = (int32_t) uval; 244 return 0; 245 } 246 247 static inline int 248 dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 249 int64_t *val, void *arg) 250 { 251 uint64_t uval; 252 int ret; 253 254 if ((ret = dwarf_readu64 (as, a, addr, &uval, arg)) < 0) 255 return ret; 256 *val = (int64_t) uval; 257 return 0; 258 } 259 260 #endif /* !UNW_LOCAL_ONLY */ 261 262 static inline int 263 dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 264 unw_word_t *val, void *arg) 265 { 266 uint32_t u32; 267 uint64_t u64; 268 int ret; 269 270 switch (dwarf_addr_size (as)) 271 { 272 case 4: 273 ret = dwarf_readu32 (as, a, addr, &u32, arg); 274 if (ret < 0) 275 return ret; 276 *val = u32; 277 return ret; 278 279 case 8: 280 ret = dwarf_readu64 (as, a, addr, &u64, arg); 281 if (ret < 0) 282 return ret; 283 *val = u64; 284 return ret; 285 286 default: 287 abort (); 288 } 289 } 290 291 /* Read an unsigned "little-endian base 128" value. See Chapter 7.6 292 of DWARF spec v3. */ 293 294 static inline int 295 dwarf_read_uleb128 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 296 unw_word_t *valp, void *arg) 297 { 298 unw_word_t val = 0, shift = 0; 299 unsigned char byte; 300 int ret; 301 302 do 303 { 304 if ((ret = dwarf_readu8 (as, a, addr, &byte, arg)) < 0) 305 return ret; 306 307 val |= ((unw_word_t) byte & 0x7f) << shift; 308 shift += 7; 309 } 310 while (byte & 0x80); 311 312 *valp = val; 313 return 0; 314 } 315 316 /* Read a signed "little-endian base 128" value. See Chapter 7.6 of 317 DWARF spec v3. */ 318 319 static inline int 320 dwarf_read_sleb128 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, 321 unw_word_t *valp, void *arg) 322 { 323 unw_word_t val = 0, shift = 0; 324 unsigned char byte; 325 int ret; 326 327 do 328 { 329 if ((ret = dwarf_readu8 (as, a, addr, &byte, arg)) < 0) 330 return ret; 331 332 val |= ((unw_word_t) byte & 0x7f) << shift; 333 shift += 7; 334 } 335 while (byte & 0x80); 336 337 if (shift < 8 * sizeof (unw_word_t) && (byte & 0x40) != 0) 338 /* sign-extend negative value */ 339 val |= ((unw_word_t) -1) << shift; 340 341 *valp = val; 342 return 0; 343 } 344 345 static ALWAYS_INLINE int 346 dwarf_read_encoded_pointer_inlined (unw_addr_space_t as, unw_accessors_t *a, 347 unw_word_t *addr, unsigned char encoding, 348 const unw_proc_info_t *pi, 349 unw_word_t *valp, void *arg) 350 { 351 unw_word_t val, initial_addr = *addr; 352 uint16_t uval16; 353 uint32_t uval32; 354 uint64_t uval64; 355 int16_t sval16; 356 int32_t sval32; 357 int64_t sval64; 358 int ret; 359 360 /* DW_EH_PE_omit and DW_EH_PE_aligned don't follow the normal 361 format/application encoding. Handle them first. */ 362 if (encoding == DW_EH_PE_omit) 363 { 364 *valp = 0; 365 return 0; 366 } 367 else if (encoding == DW_EH_PE_aligned) 368 { 369 int size = dwarf_addr_size (as); 370 *addr = (initial_addr + size - 1) & -size; 371 return dwarf_readw (as, a, addr, valp, arg); 372 } 373 374 switch (encoding & DW_EH_PE_FORMAT_MASK) 375 { 376 case DW_EH_PE_ptr: 377 if ((ret = dwarf_readw (as, a, addr, &val, arg)) < 0) 378 return ret; 379 break; 380 381 case DW_EH_PE_uleb128: 382 if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0) 383 return ret; 384 break; 385 386 case DW_EH_PE_udata2: 387 if ((ret = dwarf_readu16 (as, a, addr, &uval16, arg)) < 0) 388 return ret; 389 val = uval16; 390 break; 391 392 case DW_EH_PE_udata4: 393 if ((ret = dwarf_readu32 (as, a, addr, &uval32, arg)) < 0) 394 return ret; 395 val = uval32; 396 break; 397 398 case DW_EH_PE_udata8: 399 if ((ret = dwarf_readu64 (as, a, addr, &uval64, arg)) < 0) 400 return ret; 401 val = uval64; 402 break; 403 404 case DW_EH_PE_sleb128: 405 if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0) 406 return ret; 407 break; 408 409 case DW_EH_PE_sdata2: 410 if ((ret = dwarf_reads16 (as, a, addr, &sval16, arg)) < 0) 411 return ret; 412 val = sval16; 413 break; 414 415 case DW_EH_PE_sdata4: 416 if ((ret = dwarf_reads32 (as, a, addr, &sval32, arg)) < 0) 417 return ret; 418 val = sval32; 419 break; 420 421 case DW_EH_PE_sdata8: 422 if ((ret = dwarf_reads64 (as, a, addr, &sval64, arg)) < 0) 423 return ret; 424 val = sval64; 425 break; 426 427 default: 428 Debug (1, "unexpected encoding format 0x%x\n", 429 encoding & DW_EH_PE_FORMAT_MASK); 430 return -UNW_EINVAL; 431 } 432 433 if (val == 0) 434 { 435 /* 0 is a special value and always absolute. */ 436 *valp = 0; 437 return 0; 438 } 439 440 switch (encoding & DW_EH_PE_APPL_MASK) 441 { 442 case DW_EH_PE_absptr: 443 break; 444 445 case DW_EH_PE_pcrel: 446 val += initial_addr; 447 break; 448 449 case DW_EH_PE_datarel: 450 /* XXX For now, assume that data-relative addresses are relative 451 to the global pointer. */ 452 val += pi->gp; 453 break; 454 455 case DW_EH_PE_funcrel: 456 val += pi->start_ip; 457 break; 458 459 case DW_EH_PE_textrel: 460 /* XXX For now we don't support text-rel values. If there is a 461 platform which needs this, we probably would have to add a 462 "segbase" member to unw_proc_info_t. */ 463 default: 464 Debug (1, "unexpected application type 0x%x\n", 465 encoding & DW_EH_PE_APPL_MASK); 466 return -UNW_EINVAL; 467 } 468 469 /* Trim off any extra bits. Assume that sign extension isn't 470 required; the only place it is needed is MIPS kernel space 471 addresses. */ 472 if (sizeof (val) > dwarf_addr_size (as)) 473 { 474 assert (dwarf_addr_size (as) == 4); 475 val = (uint32_t) val; 476 } 477 478 if (encoding & DW_EH_PE_indirect) 479 { 480 unw_word_t indirect_addr = val; 481 482 if ((ret = dwarf_readw (as, a, &indirect_addr, &val, arg)) < 0) 483 return ret; 484 } 485 486 *valp = val; 487 return 0; 488 } 489 490 #endif /* DWARF_I_H */ 491