| | 297 | |
|---|
| | 298 | #if defined(VPR_OS_Darwin) |
|---|
| | 299 | struct CrawlFrame |
|---|
| | 300 | { |
|---|
| | 301 | unsigned int pc; |
|---|
| | 302 | size_t frame; |
|---|
| | 303 | std::string name; |
|---|
| | 304 | unsigned int offset; |
|---|
| | 305 | }; |
|---|
| | 306 | |
|---|
| | 307 | const mach_header* findOwnerOfPC(const unsigned int pc) |
|---|
| | 308 | { |
|---|
| | 309 | const unsigned int count = _dyld_image_count(); |
|---|
| | 310 | for ( unsigned int index = 0; index < count; ++index ) |
|---|
| | 311 | { |
|---|
| | 312 | const mach_header* header = _dyld_get_image_header(index); |
|---|
| | 313 | const unsigned int offset = _dyld_get_image_vmaddr_slide(index); |
|---|
| | 314 | const load_command* cmd = |
|---|
| | 315 | reinterpret_cast<const load_command*>( |
|---|
| | 316 | reinterpret_cast<const char*>(header) + sizeof(mach_header) |
|---|
| | 317 | ); |
|---|
| | 318 | |
|---|
| | 319 | for ( unsigned int cmdex = 0; |
|---|
| | 320 | cmdex < header->ncmds; |
|---|
| | 321 | ++cmdex, cmd = reinterpret_cast<const load_command*>(reinterpret_cast<const char*>(cmd) + cmd->cmdsize)) |
|---|
| | 322 | { |
|---|
| | 323 | switch (cmd->cmd) |
|---|
| | 324 | { |
|---|
| | 325 | case LC_SEGMENT: |
|---|
| | 326 | { |
|---|
| | 327 | const segment_command* seg = |
|---|
| | 328 | reinterpret_cast<const segment_command*>(cmd); |
|---|
| | 329 | if ( pc >= (seg->vmaddr + offset) && |
|---|
| | 330 | pc < (seg->vmaddr + offset + seg->vmsize) ) |
|---|
| | 331 | { |
|---|
| | 332 | return header; |
|---|
| | 333 | } |
|---|
| | 334 | } |
|---|
| | 335 | break; |
|---|
| | 336 | } |
|---|
| | 337 | } |
|---|
| | 338 | } |
|---|
| | 339 | |
|---|
| | 340 | return NULL; |
|---|
| | 341 | } |
|---|
| | 342 | |
|---|
| | 343 | std::string getFunctionName(const unsigned int pc, unsigned int* offset) |
|---|
| | 344 | { |
|---|
| | 345 | const mach_header* header = findOwnerOfPC(pc); |
|---|
| | 346 | if ( header != NULL ) |
|---|
| | 347 | { |
|---|
| | 348 | const segment_command* seg_linkedit(NULL); |
|---|
| | 349 | const segment_command* seg_text(NULL); |
|---|
| | 350 | const symtab_command* symtab(NULL); |
|---|
| | 351 | |
|---|
| | 352 | const load_command* cmd = |
|---|
| | 353 | reinterpret_cast<const load_command*>( |
|---|
| | 354 | reinterpret_cast<const char*>(header) + sizeof(mach_header) |
|---|
| | 355 | ); |
|---|
| | 356 | |
|---|
| | 357 | for ( unsigned int index = 0; |
|---|
| | 358 | index < header->ncmds; |
|---|
| | 359 | ++index, cmd = reinterpret_cast<const load_command*>(reinterpret_cast<const char*>(cmd) + cmd->cmdsize) ) |
|---|
| | 360 | { |
|---|
| | 361 | switch (cmd->cmd) |
|---|
| | 362 | { |
|---|
| | 363 | case LC_SEGMENT: |
|---|
| | 364 | if ( ! strncmp(reinterpret_cast<const segment_command*>(cmd)->segname, SEG_TEXT, 16) ) |
|---|
| | 365 | { |
|---|
| | 366 | seg_text = reinterpret_cast<const segment_command*>(cmd); |
|---|
| | 367 | } |
|---|
| | 368 | else if ( ! strncmp(reinterpret_cast<const segment_command*>(cmd)->segname, SEG_LINKEDIT, 16) ) |
|---|
| | 369 | { |
|---|
| | 370 | seg_linkedit = reinterpret_cast<const segment_command*>(cmd); |
|---|
| | 371 | } |
|---|
| | 372 | break; |
|---|
| | 373 | |
|---|
| | 374 | case LC_SYMTAB: |
|---|
| | 375 | symtab = reinterpret_cast<const symtab_command*>(cmd); |
|---|
| | 376 | break; |
|---|
| | 377 | } |
|---|
| | 378 | } |
|---|
| | 379 | |
|---|
| | 380 | if ( seg_text == NULL || seg_linkedit == NULL || symtab == NULL ) |
|---|
| | 381 | { |
|---|
| | 382 | *offset = 0; |
|---|
| | 383 | return NULL; |
|---|
| | 384 | } |
|---|
| | 385 | |
|---|
| | 386 | size_t vm_slide = reinterpret_cast<size_t>(header) - seg_text->vmaddr; |
|---|
| | 387 | const size_t file_slide = (seg_linkedit->vmaddr - seg_text->vmaddr) - |
|---|
| | 388 | seg_linkedit->fileoff; |
|---|
| | 389 | struct nlist* symbase = |
|---|
| | 390 | reinterpret_cast<struct nlist*>( |
|---|
| | 391 | reinterpret_cast<size_t>(header) + symtab->symoff + file_slide |
|---|
| | 392 | ); |
|---|
| | 393 | char* strings = |
|---|
| | 394 | reinterpret_cast<char*>( |
|---|
| | 395 | reinterpret_cast<size_t>(header) + symtab->stroff + file_slide |
|---|
| | 396 | ); |
|---|
| | 397 | |
|---|
| | 398 | // Look for a global symbol. |
|---|
| | 399 | unsigned int index; |
|---|
| | 400 | struct nlist* sym(NULL); |
|---|
| | 401 | for ( index = 0, sym = symbase; index < symtab->nsyms; ++index, ++sym ) |
|---|
| | 402 | { |
|---|
| | 403 | if ( sym->n_type != N_FUN ) |
|---|
| | 404 | { |
|---|
| | 405 | continue; |
|---|
| | 406 | } |
|---|
| | 407 | |
|---|
| | 408 | char* name = sym->n_un.n_strx ? (strings + sym->n_un.n_strx) : NULL; |
|---|
| | 409 | const unsigned int base = sym->n_value + vm_slide; |
|---|
| | 410 | |
|---|
| | 411 | for ( index += 1, sym += 1; index < symtab->nsyms; ++index, ++sym ) |
|---|
| | 412 | { |
|---|
| | 413 | if ( sym->n_type == N_FUN ) |
|---|
| | 414 | { |
|---|
| | 415 | break; |
|---|
| | 416 | } |
|---|
| | 417 | } |
|---|
| | 418 | |
|---|
| | 419 | if ( pc >= base && pc <= (base + sym->n_value) && name != NULL && |
|---|
| | 420 | std::strlen(name) > 0 ) |
|---|
| | 421 | { |
|---|
| | 422 | *offset = pc - base; |
|---|
| | 423 | return std::string(name); |
|---|
| | 424 | } |
|---|
| | 425 | } |
|---|
| | 426 | |
|---|
| | 427 | // Look for a reasonably close private symbol. |
|---|
| | 428 | char* name; |
|---|
| | 429 | unsigned int base; |
|---|
| | 430 | for ( name = NULL, base = 0xFFFFFFFF, index = 0, sym = symbase; |
|---|
| | 431 | index < symtab->nsyms; |
|---|
| | 432 | ++index, ++sym ) |
|---|
| | 433 | { |
|---|
| | 434 | if ( (sym->n_type & 0x0E) != 0x0E ) |
|---|
| | 435 | { |
|---|
| | 436 | continue; |
|---|
| | 437 | } |
|---|
| | 438 | |
|---|
| | 439 | if ( (sym->n_value + vm_slide) > pc ) |
|---|
| | 440 | { |
|---|
| | 441 | continue; |
|---|
| | 442 | } |
|---|
| | 443 | |
|---|
| | 444 | if ( base != 0xFFFFFFFF && |
|---|
| | 445 | (pc - (sym->n_value + vm_slide)) >= (pc - base) ) |
|---|
| | 446 | { |
|---|
| | 447 | continue; |
|---|
| | 448 | } |
|---|
| | 449 | |
|---|
| | 450 | name = sym->n_un.n_strx ? (strings + sym->n_un.n_strx) : NULL; |
|---|
| | 451 | base = sym->n_value + vm_slide; |
|---|
| | 452 | } |
|---|
| | 453 | |
|---|
| | 454 | *offset = pc - base; |
|---|
| | 455 | return (name != NULL) ? std::string(name) : std::string(); |
|---|
| | 456 | } |
|---|
| | 457 | |
|---|
| | 458 | *offset = 0; |
|---|
| | 459 | return std::string(); |
|---|
| | 460 | } |
|---|
| | 461 | #endif /* VPR_OS_Darwin */ |
|---|
| | 490 | |
|---|
| | 491 | ret_stack = trace_stream.str(); |
|---|
| | 492 | #elif defined(VPR_OS_Darwin) |
|---|
| | 493 | #if defined(__ppc__) || defined(__ppc64__) |
|---|
| | 494 | struct StackFrame |
|---|
| | 495 | { |
|---|
| | 496 | unsigned int savedSP; |
|---|
| | 497 | unsigned int savedCR; |
|---|
| | 498 | unsigned int savedLR; |
|---|
| | 499 | unsigned int reserved[2]; |
|---|
| | 500 | unsigned int savedRTOC; |
|---|
| | 501 | }; |
|---|
| | 502 | #elif defined(__i386__) |
|---|
| | 503 | struct StackFrame |
|---|
| | 504 | { |
|---|
| | 505 | unsigned int savedSP; |
|---|
| | 506 | unsigned int savedLR; |
|---|
| | 507 | }; |
|---|
| | 508 | #else |
|---|
| | 509 | #error Unknown platform |
|---|
| | 510 | #endif |
|---|
| | 511 | |
|---|
| | 512 | std::ostringstream trace_stream; |
|---|
| | 513 | trace_stream << "Stack trace for process: " << getpid() << std::endl; |
|---|
| | 514 | |
|---|
| | 515 | std::vector<CrawlFrame> stack; |
|---|
| | 516 | StackFrame* frame(NULL); |
|---|
| | 517 | |
|---|
| | 518 | #if defined(__ppc__) || defined(__ppc64__) |
|---|
| | 519 | frame = *(StackFrame**) __builtin_frame_address(0); |
|---|
| | 520 | #elif defined(__i386__) |
|---|
| | 521 | frame = (StackFrame*) __builtin_frame_address(0); |
|---|
| | 522 | #endif |
|---|
| | 523 | |
|---|
| | 524 | for ( ; frame != NULL; frame = (StackFrame*) frame->savedSP) |
|---|
| | 525 | { |
|---|
| | 526 | if ( (frame->savedLR & ~3) == 0 || (~(frame->savedLR) & ~3) == 0 ) |
|---|
| | 527 | { |
|---|
| | 528 | break; |
|---|
| | 529 | } |
|---|
| | 530 | |
|---|
| | 531 | CrawlFrame cur_frame; |
|---|
| | 532 | cur_frame.pc = frame->savedLR; |
|---|
| | 533 | cur_frame.frame = reinterpret_cast<size_t>(frame); |
|---|
| | 534 | |
|---|
| | 535 | const std::string func_name = getFunctionName(frame->savedLR, |
|---|
| | 536 | &cur_frame.offset); |
|---|
| | 537 | |
|---|
| | 538 | if ( ! func_name.empty() ) |
|---|
| | 539 | { |
|---|
| | 540 | cur_frame.name = demangleTraceString(func_name); |
|---|
| | 541 | } |
|---|
| | 542 | |
|---|
| | 543 | if ( cur_frame.pc != 0 ) |
|---|
| | 544 | { |
|---|
| | 545 | cur_frame.pc -= 4; |
|---|
| | 546 | } |
|---|
| | 547 | |
|---|
| | 548 | stack.push_back(cur_frame); |
|---|
| | 549 | } |
|---|
| | 550 | |
|---|
| | 551 | typedef std::vector<CrawlFrame>::reverse_iterator iter_type; |
|---|
| | 552 | for ( iter_type i = stack.rbegin(); i != stack.rend(); ++i ) |
|---|
| | 553 | { |
|---|
| | 554 | std::string func_name("(unknown)"); |
|---|
| | 555 | |
|---|
| | 556 | if ( ! (*i).name.empty() ) |
|---|
| | 557 | { |
|---|
| | 558 | typedef std::string::size_type size_type; |
|---|
| | 559 | const size_type name_len((*i).name.size()); |
|---|
| | 560 | for ( size_type j = 0; j < name_len; ++j ) |
|---|
| | 561 | { |
|---|
| | 562 | bool objc(false); |
|---|
| | 563 | if ( j == 1 && (*i).name[j] == '[' ) |
|---|
| | 564 | { |
|---|
| | 565 | objc = true; |
|---|
| | 566 | } |
|---|
| | 567 | |
|---|
| | 568 | if ( objc && (*i).name[j] == ']' ) |
|---|
| | 569 | { |
|---|
| | 570 | objc = false; |
|---|
| | 571 | } |
|---|
| | 572 | |
|---|
| | 573 | if ( ! objc && (*i).name[j] == ':' ) |
|---|
| | 574 | { |
|---|
| | 575 | break; |
|---|
| | 576 | } |
|---|
| | 577 | } |
|---|
| | 578 | |
|---|
| | 579 | std::ostringstream func_stream; |
|---|
| | 580 | func_stream << (*i).name << "+" << std::hex << (*i).offset; |
|---|
| | 581 | func_name = func_stream.str(); |
|---|
| | 582 | } |
|---|
| | 583 | |
|---|
| | 584 | const char fill_char(trace_stream.fill()); |
|---|
| | 585 | const std::ios::fmtflags fmt_flags(trace_stream.flags()); |
|---|
| | 586 | trace_stream.fill('0'); |
|---|
| | 587 | trace_stream.setf(std::ios::uppercase); |
|---|
| | 588 | trace_stream.setf(std::ios::hex | std::ios::right, |
|---|
| | 589 | std::ios::adjustfield | std::ios::basefield); |
|---|
| | 590 | trace_stream << " " << std::setw(sizeof(void*) * 2) << (*i).frame |
|---|
| | 591 | << " " << std::setw(sizeof(void*) * 2) << (*i).pc; |
|---|
| | 592 | trace_stream.flags(fmt_flags); |
|---|
| | 593 | trace_stream.fill(fill_char); |
|---|
| | 594 | trace_stream << " " << func_name << std::endl; |
|---|
| | 595 | } |
|---|