sanitizer_stacktrace.cc revision 2bbe0d1429a46cb93aafc055de6a8f1b5433e454
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(InternalScopedString *buffer, uptr frame_num,
38                                  uptr pc) {
39  buffer->append("    #%zu 0x%zx", frame_num, pc);
40}
41
42void StackTrace::PrintStack(const uptr *addr, uptr size,
43                            SymbolizeCallback symbolize_callback) {
44  if (addr == 0) {
45    Printf("<empty stack>\n\n");
46    return;
47  }
48  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
49  InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
50  InternalScopedBuffer<AddressInfo> addr_frames(64);
51  InternalScopedString frame_desc(GetPageSizeCached() * 2);
52  uptr frame_num = 0;
53  for (uptr i = 0; i < size && addr[i]; i++) {
54    // PCs in stack traces are actually the return addresses, that is,
55    // addresses of the next instructions after the call.
56    uptr pc = GetPreviousInstructionPc(addr[i]);
57    uptr addr_frames_num = 0;  // The number of stack frames for current
58                               // instruction address.
59    if (symbolize_callback) {
60      if (symbolize_callback((void*)pc, buff.data(), buff.size())) {
61        addr_frames_num = 1;
62        frame_desc.clear();
63        PrintStackFramePrefix(&frame_desc, frame_num, pc);
64        // We can't know anything about the string returned by external
65        // symbolizer, but if it starts with filename, try to strip path prefix
66        // from it.
67        frame_desc.append(
68            " %s",
69            StripPathPrefix(buff.data(), common_flags()->strip_path_prefix));
70        Printf("%s\n", frame_desc.data());
71        frame_num++;
72      }
73    }
74    if (common_flags()->symbolize && addr_frames_num == 0) {
75      // Use our own (online) symbolizer, if necessary.
76      if (Symbolizer *sym = Symbolizer::GetOrNull())
77        addr_frames_num =
78            sym->SymbolizeCode(pc, addr_frames.data(), addr_frames.size());
79      for (uptr j = 0; j < addr_frames_num; j++) {
80        AddressInfo &info = addr_frames[j];
81        frame_desc.clear();
82        PrintStackFramePrefix(&frame_desc, frame_num, pc);
83        if (info.function) {
84          frame_desc.append(" in %s", info.function);
85        }
86        if (info.file) {
87          frame_desc.append(" ");
88          PrintSourceLocation(&frame_desc, info.file, info.line, info.column);
89        } else if (info.module) {
90          frame_desc.append(" ");
91          PrintModuleAndOffset(&frame_desc, info.module, info.module_offset);
92        }
93        Printf("%s\n", frame_desc.data());
94        frame_num++;
95        info.Clear();
96      }
97    }
98    if (addr_frames_num == 0) {
99      // If online symbolization failed, try to output at least module and
100      // offset for instruction.
101      frame_desc.clear();
102      PrintStackFramePrefix(&frame_desc, frame_num, pc);
103      uptr offset;
104      if (proc_maps.GetObjectNameAndOffset(pc, &offset,
105                                           buff.data(), buff.size(),
106                                           /* protection */0)) {
107        frame_desc.append(" ");
108        PrintModuleAndOffset(&frame_desc, buff.data(), offset);
109      }
110      Printf("%s\n", frame_desc.data());
111      frame_num++;
112    }
113  }
114  // Always print a trailing empty line after stack trace.
115  Printf("\n");
116}
117
118uptr StackTrace::GetCurrentPc() {
119  return GET_CALLER_PC();
120}
121
122void StackTrace::FastUnwindStack(uptr pc, uptr bp,
123                                 uptr stack_top, uptr stack_bottom,
124                                 uptr max_depth) {
125  if (max_depth == 0) {
126    size = 0;
127    return;
128  }
129  trace[0] = pc;
130  size = 1;
131  uhwptr *frame = (uhwptr *)bp;
132  uhwptr *prev_frame = frame - 1;
133  if (stack_top < 4096) return;  // Sanity check for stack top.
134  // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
135  while (frame > prev_frame &&
136         frame < (uhwptr *)stack_top - 2 &&
137         frame > (uhwptr *)stack_bottom &&
138         IsAligned((uptr)frame, sizeof(*frame)) &&
139         size < max_depth) {
140    uhwptr pc1 = frame[1];
141    if (pc1 != pc) {
142      trace[size++] = (uptr) pc1;
143    }
144    prev_frame = frame;
145    frame = (uhwptr *)frame[0];
146  }
147}
148
149void StackTrace::PopStackFrames(uptr count) {
150  CHECK(size >= count);
151  size -= count;
152  for (uptr i = 0; i < size; i++) {
153    trace[i] = trace[i + count];
154  }
155}
156
157static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
158  return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
159}
160
161void StackTrace::PopStackFrames(uptr count) {
162  CHECK(count < size);
163  size -= count;
164  for (uptr i = 0; i < size; ++i) {
165    trace[i] = trace[i + count];
166  }
167}
168
169uptr StackTrace::LocatePcInTrace(uptr pc) {
170  // Use threshold to find PC in stack trace, as PC we want to unwind from may
171  // slightly differ from return address in the actual unwinded stack trace.
172  const int kPcThreshold = 96;
173  for (uptr i = 0; i < size; ++i) {
174    if (MatchPc(pc, trace[i], kPcThreshold))
175      return i;
176  }
177  return 0;
178}
179
180}  // namespace __sanitizer
181