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