1 //===-- sanitizer_stacktrace_libcdep.cpp ----------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is shared between AddressSanitizer and ThreadSanitizer
10 // run-time libraries.
11 //===----------------------------------------------------------------------===//
12 
13 #include "sanitizer_common.h"
14 #include "sanitizer_placement_new.h"
15 #include "sanitizer_stacktrace.h"
16 #include "sanitizer_stacktrace_printer.h"
17 #include "sanitizer_symbolizer.h"
18 
19 namespace __sanitizer {
20 
21 void StackTrace::Print() const {
22   if (trace == nullptr || size == 0) {
23     Printf("    <empty stack>\n\n");
24     return;
25   }
26   InternalScopedString frame_desc;
27   InternalScopedString dedup_token;
28   int dedup_frames = common_flags()->dedup_token_length;
29   bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format);
30   uptr frame_num = 0;
31   for (uptr i = 0; i < size && trace[i]; i++) {
32     // PCs in stack traces are actually the return addresses, that is,
33     // addresses of the next instructions after the call.
34     uptr pc = GetPreviousInstructionPc(trace[i]);
35     SymbolizedStack *frames;
36     if (symbolize)
37       frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
38     else
39       frames = SymbolizedStack::New(pc);
40     CHECK(frames);
41     for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
42       frame_desc.clear();
43       RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
44                   cur->info.address, symbolize ? &cur->info : nullptr,
45                   common_flags()->symbolize_vs_style,
46                   common_flags()->strip_path_prefix);
47       Printf("%s\n", frame_desc.data());
48       if (dedup_frames-- > 0) {
49         if (dedup_token.length())
50           dedup_token.append("--");
51         if (cur->info.function != nullptr)
52           dedup_token.append(cur->info.function);
53       }
54     }
55     frames->ClearAll();
56   }
57   // Always print a trailing empty line after stack trace.
58   Printf("\n");
59   if (dedup_token.length())
60     Printf("DEDUP_TOKEN: %s\n", dedup_token.data());
61 }
62 
63 void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
64                                 uptr stack_top, uptr stack_bottom,
65                                 bool request_fast_unwind) {
66   // Ensures all call sites get what they requested.
67   CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind));
68   top_frame_bp = (max_depth > 0) ? bp : 0;
69   // Avoid doing any work for small max_depth.
70   if (max_depth == 0) {
71     size = 0;
72     return;
73   }
74   if (max_depth == 1) {
75     size = 1;
76     trace_buffer[0] = pc;
77     return;
78   }
79   if (!WillUseFastUnwind(request_fast_unwind)) {
80 #if SANITIZER_CAN_SLOW_UNWIND
81     if (context)
82       UnwindSlow(pc, context, max_depth);
83     else
84       UnwindSlow(pc, max_depth);
85     // If there are too few frames, the program may be built with
86     // -fno-asynchronous-unwind-tables. Fall back to fast unwinder below.
87     if (size > 2 || size >= max_depth)
88       return;
89 #else
90     UNREACHABLE("slow unwind requested but not available");
91 #endif
92   }
93   UnwindFast(pc, bp, stack_top, stack_bottom, max_depth);
94 }
95 
96 static int GetModuleAndOffsetForPc(uptr pc, char *module_name,
97                                    uptr module_name_len, uptr *pc_offset) {
98   const char *found_module_name = nullptr;
99   bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(
100       pc, &found_module_name, pc_offset);
101 
102   if (!ok) return false;
103 
104   if (module_name && module_name_len) {
105     internal_strncpy(module_name, found_module_name, module_name_len);
106     module_name[module_name_len - 1] = '\x00';
107   }
108   return true;
109 }
110 
111 }  // namespace __sanitizer
112 using namespace __sanitizer;
113 
114 extern "C" {
115 SANITIZER_INTERFACE_ATTRIBUTE
116 void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
117                               uptr out_buf_size) {
118   if (!out_buf_size) return;
119   pc = StackTrace::GetPreviousInstructionPc(pc);
120   SymbolizedStack *frame;
121   bool symbolize = RenderNeedsSymbolization(fmt);
122   if (symbolize)
123     frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
124   else
125     frame = SymbolizedStack::New(pc);
126   if (!frame) {
127     internal_strncpy(out_buf, "<can't symbolize>", out_buf_size);
128     out_buf[out_buf_size - 1] = 0;
129     return;
130   }
131   InternalScopedString frame_desc;
132   uptr frame_num = 0;
133   // Reserve one byte for the final 0.
134   char *out_end = out_buf + out_buf_size - 1;
135   for (SymbolizedStack *cur = frame; cur && out_buf < out_end;
136        cur = cur->next) {
137     frame_desc.clear();
138     RenderFrame(&frame_desc, fmt, frame_num++, cur->info.address,
139                 symbolize ? &cur->info : nullptr,
140                 common_flags()->symbolize_vs_style,
141                 common_flags()->strip_path_prefix);
142     if (!frame_desc.length())
143       continue;
144     // Reserve one byte for the terminating 0.
145     uptr n = out_end - out_buf - 1;
146     internal_strncpy(out_buf, frame_desc.data(), n);
147     out_buf += __sanitizer::Min<uptr>(n, frame_desc.length());
148     *out_buf++ = 0;
149   }
150   CHECK(out_buf <= out_end);
151   *out_buf = 0;
152   frame->ClearAll();
153 }
154 
155 SANITIZER_INTERFACE_ATTRIBUTE
156 void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
157                                   char *out_buf, uptr out_buf_size) {
158   if (!out_buf_size) return;
159   out_buf[0] = 0;
160   DataInfo DI;
161   if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
162   InternalScopedString data_desc;
163   RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
164   internal_strncpy(out_buf, data_desc.data(), out_buf_size);
165   out_buf[out_buf_size - 1] = 0;
166 }
167 
168 SANITIZER_INTERFACE_ATTRIBUTE
169 int __sanitizer_get_module_and_offset_for_pc(uptr pc, char *module_name,
170                                              uptr module_name_len,
171                                              uptr *pc_offset) {
172   return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len,
173                                               pc_offset);
174 }
175 }  // extern "C"
176