Chromium Code Reviews| Index: base/debug/stack_trace.cc |
| diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc |
| index 1c96a569d9795544231714f0d0b1f9b0da036355..0150abe0a2a655489c8d295a349c66528d78dc44 100644 |
| --- a/base/debug/stack_trace.cc |
| +++ b/base/debug/stack_trace.cc |
| @@ -11,6 +11,16 @@ |
| #include "base/macros.h" |
| +#if HAVE_TRACE_STACK_FRAME_POINTERS && \ |
| + (defined(OS_ANDROID) || defined(OS_LINUX)) |
| +#define HAVE_MINCORE |
| +#include <sys/mman.h> |
| +#include <unistd.h> |
| +#include "base/posix/eintr_wrapper.h" |
| +#include "base/process/process_metrics.h" |
| +#endif |
| + |
| + |
| namespace base { |
| namespace debug { |
| @@ -41,9 +51,61 @@ std::string StackTrace::ToString() const { |
| #if HAVE_TRACE_STACK_FRAME_POINTERS |
| +#ifdef HAVE_MINCORE |
| + |
| +// Attempts to advance |address| by PageCount pages, checking that all |
| +// pages are mapped. |
| +// Returns true if no unmapped pages were found, and adds PageCount |
| +// pages to |address| and rounds result down to a page. |
| +// Returns false if unmapped pages were detected, and sets |address| to |
| +// the address of the lowest unmapped page. |
| +template <size_t PageCount> |
|
Primiano Tucci (use gerrit)
2016/05/31 16:13:06
why do you need a template function with a lambda
|
| +bool AdvanceMappedPages(uintptr_t* address) { |
| + auto probe = [](uintptr_t address, size_t size) -> bool { |
| + uint8_t vec[PageCount]; |
| + int result = HANDLE_EINTR( |
|
Primiano Tucci (use gerrit)
2016/05/31 16:13:07
accordin to its manpage mincore doesn't EINTR (vm
Dmitry Skiba
2016/05/31 21:52:18
Done.
|
| + mincore(reinterpret_cast<void*>(address), size, vec)); |
| + if (result == 0) { |
| + return true; |
| + } |
| + // mincore() returns ENOMEM if address range contains unmapped pages. |
| + CHECK_EQ(errno, ENOMEM); |
|
Primiano Tucci (use gerrit)
2016/05/31 16:13:06
I'd remove this CHECK or make it a DCHECK.
1) you
Dmitry Skiba
2016/05/31 21:52:18
Done.
|
| + return false; |
| + }; |
| + |
| + size_t page_size = GetPageSize(); |
| + |
| + // Rewind address to the page boundary. |
| + *address -= *address % page_size; |
| + |
| + // Probe the whole range first. |
| + if (probe(*address, PageCount * page_size)) { |
| + *address += PageCount * page_size; |
| + return true; |
| + } |
| + |
| + // Binary search leftmost page that is not mapped. |
| + for (size_t pages = PageCount; pages != 1;) { |
|
Primiano Tucci (use gerrit)
2016/05/31 16:13:06
I think this is a bit hard to follow as you do a b
Dmitry Skiba
2016/05/31 21:52:18
I don't see how it can be a single loop. When bina
|
| + size_t half_pages = pages / 2; |
| + if (!probe(*address, half_pages * page_size)) { |
| + pages = half_pages; |
| + continue; |
| + } |
| + *address += half_pages * page_size; |
| + pages -= half_pages; |
| + } |
| + return false; |
| +} |
| + |
| +#endif // HAVE_MINCORE |
| + |
| +PerThreadStackInfo::PerThreadStackInfo() |
| + : start_address(0), start_address_final(false) {} |
| + |
| size_t TraceStackFramePointers(const void** out_trace, |
| size_t max_depth, |
| - size_t skip_initial) { |
| + size_t skip_initial, |
| + PerThreadStackInfo* stack_info) { |
| // Usage of __builtin_frame_address() enables frame pointers in this |
| // function even if they are not enabled globally. So 'sp' will always |
| // be valid. |
| @@ -58,6 +120,26 @@ size_t TraceStackFramePointers(const void** out_trace, |
| sp -= sizeof(uintptr_t); |
| #endif |
| +#ifdef HAVE_MINCORE |
| + if (stack_info) { |
| + // Both sp[0] and s[1] must be valid. |
| + uintptr_t max_sp = sp + 2 * sizeof(uintptr_t); |
| + if (!stack_info->start_address) { |
| + // Initialize start_address so that it satisfies while() below. |
| + stack_info->start_address = max_sp - 1; |
| + } |
| + while (max_sp > stack_info->start_address && |
| + !stack_info->start_address_final) { |
| + stack_info->start_address_final = !AdvanceMappedPages<32>( |
| + &stack_info->start_address); |
| + } |
| + if (max_sp > stack_info->start_address && |
| + stack_info->start_address_final) { |
| + break; |
| + } |
| + } |
| +#endif |
| + |
| if (skip_initial != 0) { |
| skip_initial--; |
| } else { |