1 //===-- sanitizer_stacktrace_libcdep.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_stacktrace.h"
16 #include "sanitizer_symbolizer.h"
17
18 namespace __sanitizer {
19
PrintStackFramePrefix(InternalScopedString * buffer,uptr frame_num,uptr pc)20 static void PrintStackFramePrefix(InternalScopedString *buffer, uptr frame_num,
21 uptr pc) {
22 buffer->append(" #%zu 0x%zx", frame_num, pc);
23 }
24
PrintStack(const uptr * addr,uptr size)25 void StackTrace::PrintStack(const uptr *addr, uptr size) {
26 if (addr == 0 || size == 0) {
27 Printf(" <empty stack>\n\n");
28 return;
29 }
30 InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
31 InternalScopedBuffer<AddressInfo> addr_frames(64);
32 InternalScopedString frame_desc(GetPageSizeCached() * 2);
33 uptr frame_num = 0;
34 for (uptr i = 0; i < size && addr[i]; i++) {
35 // PCs in stack traces are actually the return addresses, that is,
36 // addresses of the next instructions after the call.
37 uptr pc = GetPreviousInstructionPc(addr[i]);
38 uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
39 pc, addr_frames.data(), addr_frames.size());
40 if (addr_frames_num == 0) {
41 frame_desc.clear();
42 PrintStackFramePrefix(&frame_desc, frame_num, pc);
43 frame_desc.append(" (<unknown module>)");
44 Printf("%s\n", frame_desc.data());
45 frame_num++;
46 continue;
47 }
48 for (uptr j = 0; j < addr_frames_num; j++) {
49 AddressInfo &info = addr_frames[j];
50 frame_desc.clear();
51 PrintStackFramePrefix(&frame_desc, frame_num, pc);
52 if (info.function) {
53 frame_desc.append(" in %s", info.function);
54 // Print offset in function if we don't know the source file.
55 if (!info.file && info.function_offset != AddressInfo::kUnknown)
56 frame_desc.append("+0x%zx", info.function_offset);
57 }
58 if (info.file) {
59 frame_desc.append(" ");
60 PrintSourceLocation(&frame_desc, info.file, info.line, info.column);
61 } else if (info.module) {
62 frame_desc.append(" ");
63 PrintModuleAndOffset(&frame_desc, info.module, info.module_offset);
64 }
65 Printf("%s\n", frame_desc.data());
66 frame_num++;
67 info.Clear();
68 }
69 }
70 // Always print a trailing empty line after stack trace.
71 Printf("\n");
72 }
73
Unwind(uptr max_depth,uptr pc,uptr bp,void * context,uptr stack_top,uptr stack_bottom,bool request_fast_unwind)74 void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context,
75 uptr stack_top, uptr stack_bottom,
76 bool request_fast_unwind) {
77 top_frame_bp = (max_depth > 0) ? bp : 0;
78 // Avoid doing any work for small max_depth.
79 if (max_depth == 0) {
80 size = 0;
81 return;
82 }
83 if (max_depth == 1) {
84 size = 1;
85 trace[0] = pc;
86 return;
87 }
88 if (!WillUseFastUnwind(request_fast_unwind)) {
89 if (context)
90 SlowUnwindStackWithContext(pc, context, max_depth);
91 else
92 SlowUnwindStack(pc, max_depth);
93 } else {
94 FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
95 }
96 }
97
98 } // namespace __sanitizer
99