blob: 62cb12d8da6decd584aa5de96eaeecaf9425c3bc [file] [log] [blame]
Kostya Serebryanyc7be4072012-08-28 14:27:06 +00001//===-- 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
Kostya Serebryany9ada1f32012-08-28 14:48:28 +000014#include "sanitizer_common.h"
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +000015#include "sanitizer_flags.h"
Kostya Serebryany9ada1f32012-08-28 14:48:28 +000016#include "sanitizer_procmaps.h"
17#include "sanitizer_stacktrace.h"
18#include "sanitizer_symbolizer.h"
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000019
20namespace __sanitizer {
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000021
Alexey Samsonovd2f08ff2012-12-18 09:57:34 +000022uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000023#ifdef __arm__
24 // Cancel Thumb bit.
25 pc = pc & (~1);
26#endif
Kostya Serebryanyd7d46502012-11-20 07:00:42 +000027#if defined(__powerpc__) || defined(__powerpc64__)
28 // PCs are always 4 byte aligned.
29 return pc - 4;
Kostya Serebryany68aad432012-12-03 18:39:21 +000030#elif defined(__sparc__)
31 return pc - 8;
Kostya Serebryanyd7d46502012-11-20 07:00:42 +000032#else
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000033 return pc - 1;
Kostya Serebryanyd7d46502012-11-20 07:00:42 +000034#endif
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000035}
36
Alexey Samsonovbb4697f2013-11-14 09:41:24 +000037static void PrintStackFramePrefix(InternalScopedString *buffer, uptr frame_num,
38 uptr pc) {
39 buffer->append(" #%zu 0x%zx", frame_num, pc);
Alexey Samsonov1ca53572012-10-02 12:11:17 +000040}
41
Alexey Samsonov7996a2e2013-10-29 05:31:25 +000042void StackTrace::PrintStack(const uptr *addr, uptr size,
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +000043 SymbolizeCallback symbolize_callback) {
Alexey Samsonova96c4dc2013-11-01 00:19:46 +000044 if (addr == 0) {
45 Printf("<empty stack>\n\n");
46 return;
47 }
Alexander Potapenko9ae28832013-03-26 10:34:37 +000048 MemoryMappingLayout proc_maps(/*cache_enabled*/true);
Kostya Serebryanye89f1842012-11-24 05:03:11 +000049 InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
Kostya Serebryany4fa111c2012-08-29 08:40:36 +000050 InternalScopedBuffer<AddressInfo> addr_frames(64);
Alexey Samsonovbb4697f2013-11-14 09:41:24 +000051 InternalScopedString frame_desc(GetPageSizeCached() * 2);
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000052 uptr frame_num = 0;
53 for (uptr i = 0; i < size && addr[i]; i++) {
Alexey Samsonovd2f08ff2012-12-18 09:57:34 +000054 // 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]);
Alexey Samsonov1ca53572012-10-02 12:11:17 +000057 uptr addr_frames_num = 0; // The number of stack frames for current
58 // instruction address.
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000059 if (symbolize_callback) {
Alexey Samsonov1ca53572012-10-02 12:11:17 +000060 if (symbolize_callback((void*)pc, buff.data(), buff.size())) {
61 addr_frames_num = 1;
Alexey Samsonovbb4697f2013-11-14 09:41:24 +000062 frame_desc.clear();
63 PrintStackFramePrefix(&frame_desc, frame_num, pc);
Alexey Samsonov1ca53572012-10-02 12:11:17 +000064 // 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.
Alexey Samsonovbb4697f2013-11-14 09:41:24 +000067 frame_desc.append(
68 " %s",
69 StripPathPrefix(buff.data(), common_flags()->strip_path_prefix));
70 Printf("%s\n", frame_desc.data());
Alexey Samsonov1ca53572012-10-02 12:11:17 +000071 frame_num++;
72 }
Alexey Samsonovd5951e62012-10-18 11:46:22 +000073 }
Alexey Samsonov7996a2e2013-10-29 05:31:25 +000074 if (common_flags()->symbolize && addr_frames_num == 0) {
Alexey Samsonov1ca53572012-10-02 12:11:17 +000075 // Use our own (online) symbolizer, if necessary.
Peter Collingbournec1a1ed62013-10-25 23:03:29 +000076 if (Symbolizer *sym = Symbolizer::GetOrNull())
77 addr_frames_num =
78 sym->SymbolizeCode(pc, addr_frames.data(), addr_frames.size());
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000079 for (uptr j = 0; j < addr_frames_num; j++) {
80 AddressInfo &info = addr_frames[j];
Alexey Samsonovbb4697f2013-11-14 09:41:24 +000081 frame_desc.clear();
82 PrintStackFramePrefix(&frame_desc, frame_num, pc);
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000083 if (info.function) {
Alexey Samsonovbb4697f2013-11-14 09:41:24 +000084 frame_desc.append(" in %s", info.function);
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000085 }
86 if (info.file) {
Alexey Samsonovbb4697f2013-11-14 09:41:24 +000087 frame_desc.append(" ");
88 PrintSourceLocation(&frame_desc, info.file, info.line, info.column);
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000089 } else if (info.module) {
Alexey Samsonovbb4697f2013-11-14 09:41:24 +000090 frame_desc.append(" ");
91 PrintModuleAndOffset(&frame_desc, info.module, info.module_offset);
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000092 }
Alexey Samsonovbb4697f2013-11-14 09:41:24 +000093 Printf("%s\n", frame_desc.data());
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000094 frame_num++;
Alexey Samsonovbb4697f2013-11-14 09:41:24 +000095 info.Clear();
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000096 }
Alexey Samsonov1ca53572012-10-02 12:11:17 +000097 }
98 if (addr_frames_num == 0) {
99 // If online symbolization failed, try to output at least module and
100 // offset for instruction.
Alexey Samsonovbb4697f2013-11-14 09:41:24 +0000101 frame_desc.clear();
102 PrintStackFramePrefix(&frame_desc, frame_num, pc);
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000103 uptr offset;
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000104 if (proc_maps.GetObjectNameAndOffset(pc, &offset,
Alexey Samsonov45717c92013-03-13 06:51:02 +0000105 buff.data(), buff.size(),
106 /* protection */0)) {
Alexey Samsonovbb4697f2013-11-14 09:41:24 +0000107 frame_desc.append(" ");
108 PrintModuleAndOffset(&frame_desc, buff.data(), offset);
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000109 }
Alexey Samsonovbb4697f2013-11-14 09:41:24 +0000110 Printf("%s\n", frame_desc.data());
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000111 frame_num++;
112 }
113 }
Alexey Samsonova96c4dc2013-11-01 00:19:46 +0000114 // Always print a trailing empty line after stack trace.
115 Printf("\n");
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000116}
117
118uptr StackTrace::GetCurrentPc() {
119 return GET_CALLER_PC();
120}
121
122void StackTrace::FastUnwindStack(uptr pc, uptr bp,
Alexey Samsonov064da322013-10-11 09:58:30 +0000123 uptr stack_top, uptr stack_bottom,
124 uptr max_depth) {
Alexey Samsonov3e0b8ff2013-10-12 12:40:47 +0000125 if (max_depth == 0) {
Alexey Samsonov064da322013-10-11 09:58:30 +0000126 size = 0;
127 return;
128 }
129 trace[0] = pc;
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000130 size = 1;
Kostya Serebryany574618a2012-11-19 10:31:00 +0000131 uhwptr *frame = (uhwptr *)bp;
Reid Kleckner20aed572013-02-20 20:29:48 +0000132 uhwptr *prev_frame = frame - 1;
Kostya Serebryany8301c732013-06-18 14:47:40 +0000133 if (stack_top < 4096) return; // Sanity check for stack top.
Reid Kleckner20aed572013-02-20 20:29:48 +0000134 // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
135 while (frame > prev_frame &&
Kostya Serebryany574618a2012-11-19 10:31:00 +0000136 frame < (uhwptr *)stack_top - 2 &&
137 frame > (uhwptr *)stack_bottom &&
Kostya Serebryany583025d2013-04-04 06:52:40 +0000138 IsAligned((uptr)frame, sizeof(*frame)) &&
Alexey Samsonov3e0b8ff2013-10-12 12:40:47 +0000139 size < max_depth) {
Kostya Serebryany574618a2012-11-19 10:31:00 +0000140 uhwptr pc1 = frame[1];
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000141 if (pc1 != pc) {
Kostya Serebryany574618a2012-11-19 10:31:00 +0000142 trace[size++] = (uptr) pc1;
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000143 }
144 prev_frame = frame;
Kostya Serebryany574618a2012-11-19 10:31:00 +0000145 frame = (uhwptr *)frame[0];
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000146 }
147}
148
Kostya Serebryanyd7d46502012-11-20 07:00:42 +0000149void StackTrace::PopStackFrames(uptr count) {
Evgeniy Stepanov6523fe22012-11-21 13:00:04 +0000150 CHECK(size >= count);
Kostya Serebryanyd7d46502012-11-20 07:00:42 +0000151 size -= count;
152 for (uptr i = 0; i < size; i++) {
153 trace[i] = trace[i + count];
154 }
155}
156
Timur Iskhodzhanov7177d2b2013-11-09 13:59:12 +0000157static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
158 return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
159}
160
161uptr
Alexey Samsonov24d775e2013-11-13 15:20:10 +0000162StackTrace::LocatePcInTrace(uptr pc, uptr max_pc_depth) {
163 // Use threshold to find PC in stack trace, as PC we want to unwind from may
164 // slightly differ from return address in the actual unwinded stack trace.
165 const int kPcThreshold = 64;
Timur Iskhodzhanov7177d2b2013-11-09 13:59:12 +0000166 for (uptr i = 0; i < max_pc_depth && i < size; ++i) {
Alexey Samsonov24d775e2013-11-13 15:20:10 +0000167 if (MatchPc(pc, trace[i], kPcThreshold))
Timur Iskhodzhanov7177d2b2013-11-09 13:59:12 +0000168 return i;
169 }
170 return 0;
171}
172
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000173} // namespace __sanitizer