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