1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "partition_alloc/partition_alloc_base/debug/stack_trace.h"
6
7 #include "partition_alloc/partition_alloc_base/logging.h"
8 #include "partition_alloc/partition_alloc_base/strings/safe_sprintf.h"
9
10 #include <string.h>
11 #include <unistd.h>
12 #include <unwind.h>
13
14 namespace partition_alloc::internal::base::debug {
15
16 namespace {
17
18 struct StackCrawlState {
StackCrawlStatepartition_alloc::internal::base::debug::__anonad7a07070111::StackCrawlState19 StackCrawlState(uintptr_t* frames, size_t max_depth)
20 : frames(frames),
21 frame_count(0),
22 max_depth(max_depth),
23 have_skipped_self(false) {}
24
25 uintptr_t* frames;
26 size_t frame_count;
27 size_t max_depth;
28 bool have_skipped_self;
29 };
30
TraceStackFrame(_Unwind_Context * context,void * arg)31 _Unwind_Reason_Code TraceStackFrame(_Unwind_Context* context, void* arg) {
32 StackCrawlState* state = static_cast<StackCrawlState*>(arg);
33 uintptr_t ip = _Unwind_GetIP(context);
34
35 // The first stack frame is this function itself. Skip it.
36 if (ip != 0 && !state->have_skipped_self) {
37 state->have_skipped_self = true;
38 return _URC_NO_REASON;
39 }
40
41 state->frames[state->frame_count++] = ip;
42 if (state->frame_count >= state->max_depth) {
43 return _URC_END_OF_STACK;
44 }
45 return _URC_NO_REASON;
46 }
47
48 } // namespace
49
CollectStackTrace(const void ** trace,size_t count)50 size_t CollectStackTrace(const void** trace, size_t count) {
51 StackCrawlState state(reinterpret_cast<uintptr_t*>(trace), count);
52 _Unwind_Backtrace(&TraceStackFrame, &state);
53 return state.frame_count;
54 }
55
OutputStackTrace(unsigned index,uintptr_t address,uintptr_t base_address,const char * module_name,uintptr_t offset)56 void OutputStackTrace(unsigned index,
57 uintptr_t address,
58 uintptr_t base_address,
59 const char* module_name,
60 uintptr_t offset) {
61 size_t module_name_len = strlen(module_name);
62
63 char buffer[256];
64 if (module_name_len > 4 &&
65 !strcmp(module_name + module_name_len - 4, ".apk")) {
66 strings::SafeSPrintf(buffer, "#%02d pc 0x%0x %s (offset 0x%0x)\n", index,
67 address - base_address, module_name, offset);
68 } else {
69 strings::SafeSPrintf(buffer, "#%02d pc 0x%0x %s\n", index,
70 address - base_address, module_name);
71 }
72 PA_RAW_LOG(INFO, buffer);
73 }
74
75 } // namespace partition_alloc::internal::base::debug
76