| 572 | } |
| 573 | |
| 574 | void StackTrace::Collect(int skip_frames) { |
| 575 | if (!debug::SafeToUnwindStack()) { |
| 576 | // Build a fake stack so that the user sees an appropriate message upon symbolizing |
| 577 | // rather than seeing an empty stack. |
| 578 | uintptr_t f_ptr = reinterpret_cast<uintptr_t>(&CouldNotCollectStackTraceBecauseInsideLibDl); |
| 579 | // Increase the pointer by one byte since the return address from a function call |
| 580 | // would not be the beginning of the function itself. |
| 581 | frames_[0] = reinterpret_cast<void*>(f_ptr + 1); |
| 582 | num_frames_ = 1; |
| 583 | return; |
| 584 | } |
| 585 | const int kMaxDepth = arraysize(frames_); |
| 586 | |
| 587 | #ifdef __linux__ |
| 588 | GoogleOnceInit(&g_prime_libunwind_once, &PrimeLibunwind); |
| 589 | |
| 590 | unw_cursor_t cursor; |
| 591 | unw_context_t uc; |
| 592 | unw_getcontext(&uc); |
| 593 | RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed"); |
| 594 | skip_frames++; // Do not include the "Collect" frame |
| 595 | |
| 596 | num_frames_ = 0; |
| 597 | while (num_frames_ < kMaxDepth) { |
| 598 | void *ip; |
| 599 | int ret = unw_get_reg(&cursor, UNW_REG_IP, reinterpret_cast<unw_word_t *>(&ip)); |
| 600 | if (ret < 0) { |
| 601 | break; |
| 602 | } |
| 603 | if (skip_frames > 0) { |
| 604 | skip_frames--; |
| 605 | } else { |
| 606 | frames_[num_frames_++] = ip; |
| 607 | } |
| 608 | ret = unw_step(&cursor); |
| 609 | if (ret <= 0) { |
| 610 | break; |
| 611 | } |
| 612 | } |
| 613 | #else |
| 614 | // On OSX, use the unwinder from glog. However, that unwinder has an issue where |
| 615 | // concurrent invocations will return no frames. See: |
| 616 | // https://github.com/google/glog/issues/298 |
| 617 | // The worst result here is an empty result. |
| 618 | |
| 619 | // google::GetStackTrace has a data race. This is called frequently, so better |
| 620 | // to ignore it with an annotation rather than use a suppression. |
| 621 | debug::ScopedTSANIgnoreReadsAndWrites ignore_tsan; |
| 622 | num_frames_ = google::GetStackTrace(frames_, kMaxDepth, skip_frames + 1); |
| 623 | #endif |
| 624 | } |
| 625 | |
| 626 | void StackTrace::StringifyToHex(char* buf, size_t size, int flags) const { |
| 627 | char* dst = buf; |