sanitizer_stacktrace.cc revision 24d775e42b87f6d7464582eb8e5c2eed347224c5
1//===-- sanitizer_stacktrace.cc -------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is shared between AddressSanitizer and ThreadSanitizer
11// run-time libraries.
12//===----------------------------------------------------------------------===//
13
14#include "sanitizer_common.h"
15#include "sanitizer_flags.h"
16#include "sanitizer_procmaps.h"
17#include "sanitizer_stacktrace.h"
18#include "sanitizer_symbolizer.h"
19
20namespace __sanitizer {
21
22uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
23#ifdef __arm__
24  // Cancel Thumb bit.
25  pc = pc & (~1);
26#endif
27#if defined(__powerpc__) || defined(__powerpc64__)
28  // PCs are always 4 byte aligned.
29  return pc - 4;
30#elif defined(__sparc__)
31  return pc - 8;
32#else
33  return pc - 1;
34#endif
35}
36
37static void PrintStackFramePrefix(uptr frame_num, uptr pc) {
38  Printf("    #%zu 0x%zx", frame_num, pc);
39}
40
41void StackTrace::PrintStack(const uptr *addr, uptr size,
42                            SymbolizeCallback symbolize_callback) {
43  if (addr == 0) {
44    Printf("<empty stack>\n\n");
45    return;
46  }
47  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
48  InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
49  InternalScopedBuffer<AddressInfo> addr_frames(64);
50  uptr frame_num = 0;
51  for (uptr i = 0; i < size && addr[i]; i++) {
52    // PCs in stack traces are actually the return addresses, that is,
53    // addresses of the next instructions after the call.
54    uptr pc = GetPreviousInstructionPc(addr[i]);
55    uptr addr_frames_num = 0;  // The number of stack frames for current
56                               // instruction address.
57    if (symbolize_callback) {
58      if (symbolize_callback((void*)pc, buff.data(), buff.size())) {
59        addr_frames_num = 1;
60        PrintStackFramePrefix(frame_num, pc);
61        // We can't know anything about the string returned by external
62        // symbolizer, but if it starts with filename, try to strip path prefix
63        // from it.
64        Printf(" %s\n",
65               StripPathPrefix(buff.data(), common_flags()->strip_path_prefix));
66        frame_num++;
67      }
68    }
69    if (common_flags()->symbolize && addr_frames_num == 0) {
70      // Use our own (online) symbolizer, if necessary.
71      if (Symbolizer *sym = Symbolizer::GetOrNull())
72        addr_frames_num =
73            sym->SymbolizeCode(pc, addr_frames.data(), addr_frames.size());
74      for (uptr j = 0; j < addr_frames_num; j++) {
75        AddressInfo &info = addr_frames[j];
76        PrintStackFramePrefix(frame_num, pc);
77        if (info.function) {
78          Printf(" in %s", info.function);
79        }
80        if (info.file) {
81          Printf(" ");
82          PrintSourceLocation(info.file, info.line, info.column);
83        } else if (info.module) {
84          Printf(" ");
85          PrintModuleAndOffset(info.module, info.module_offset);
86        }
87        Printf("\n");
88        info.Clear();
89        frame_num++;
90      }
91    }
92    if (addr_frames_num == 0) {
93      // If online symbolization failed, try to output at least module and
94      // offset for instruction.
95      PrintStackFramePrefix(frame_num, pc);
96      uptr offset;
97      if (proc_maps.GetObjectNameAndOffset(pc, &offset,
98                                           buff.data(), buff.size(),
99                                           /* protection */0)) {
100        Printf(" ");
101        PrintModuleAndOffset(buff.data(), offset);
102      }
103      Printf("\n");
104      frame_num++;
105    }
106  }
107  // Always print a trailing empty line after stack trace.
108  Printf("\n");
109}
110
111uptr StackTrace::GetCurrentPc() {
112  return GET_CALLER_PC();
113}
114
115void StackTrace::FastUnwindStack(uptr pc, uptr bp,
116                                 uptr stack_top, uptr stack_bottom,
117                                 uptr max_depth) {
118  if (max_depth == 0) {
119    size = 0;
120    return;
121  }
122  trace[0] = pc;
123  size = 1;
124  uhwptr *frame = (uhwptr *)bp;
125  uhwptr *prev_frame = frame - 1;
126  if (stack_top < 4096) return;  // Sanity check for stack top.
127  // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
128  while (frame > prev_frame &&
129         frame < (uhwptr *)stack_top - 2 &&
130         frame > (uhwptr *)stack_bottom &&
131         IsAligned((uptr)frame, sizeof(*frame)) &&
132         size < max_depth) {
133    uhwptr pc1 = frame[1];
134    if (pc1 != pc) {
135      trace[size++] = (uptr) pc1;
136    }
137    prev_frame = frame;
138    frame = (uhwptr *)frame[0];
139  }
140}
141
142void StackTrace::PopStackFrames(uptr count) {
143  CHECK(size >= count);
144  size -= count;
145  for (uptr i = 0; i < size; i++) {
146    trace[i] = trace[i + count];
147  }
148}
149
150static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
151  return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
152}
153
154uptr
155StackTrace::LocatePcInTrace(uptr pc, uptr max_pc_depth) {
156  // Use threshold to find PC in stack trace, as PC we want to unwind from may
157  // slightly differ from return address in the actual unwinded stack trace.
158  const int kPcThreshold = 64;
159  for (uptr i = 0; i < max_pc_depth && i < size; ++i) {
160    if (MatchPc(pc, trace[i], kPcThreshold))
161      return i;
162  }
163  return 0;
164}
165
166}  // namespace __sanitizer
167