xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp (revision 6ba2210ee039f2f12878c217bcf058e9c8b26b29)
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(GetPageSizeCached() * 2);
27   InternalScopedString dedup_token(GetPageSizeCached());
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 #else
86     UNREACHABLE("slow unwind requested but not available");
87 #endif
88   } else {
89     UnwindFast(pc, bp, stack_top, stack_bottom, max_depth);
90   }
91 }
92 
93 static int GetModuleAndOffsetForPc(uptr pc, char *module_name,
94                                    uptr module_name_len, uptr *pc_offset) {
95   const char *found_module_name = nullptr;
96   bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(
97       pc, &found_module_name, pc_offset);
98 
99   if (!ok) return false;
100 
101   if (module_name && module_name_len) {
102     internal_strncpy(module_name, found_module_name, module_name_len);
103     module_name[module_name_len - 1] = '\x00';
104   }
105   return true;
106 }
107 
108 }  // namespace __sanitizer
109 using namespace __sanitizer;
110 
111 extern "C" {
112 SANITIZER_INTERFACE_ATTRIBUTE
113 void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
114                               uptr out_buf_size) {
115   if (!out_buf_size) return;
116   pc = StackTrace::GetPreviousInstructionPc(pc);
117   SymbolizedStack *frame;
118   bool symbolize = RenderNeedsSymbolization(fmt);
119   if (symbolize)
120     frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
121   else
122     frame = SymbolizedStack::New(pc);
123   if (!frame) {
124     internal_strncpy(out_buf, "<can't symbolize>", out_buf_size);
125     out_buf[out_buf_size - 1] = 0;
126     return;
127   }
128   InternalScopedString frame_desc(GetPageSizeCached());
129   uptr frame_num = 0;
130   // Reserve one byte for the final 0.
131   char *out_end = out_buf + out_buf_size - 1;
132   for (SymbolizedStack *cur = frame; cur && out_buf < out_end;
133        cur = cur->next) {
134     frame_desc.clear();
135     RenderFrame(&frame_desc, fmt, frame_num++, cur->info.address,
136                 symbolize ? &cur->info : nullptr,
137                 common_flags()->symbolize_vs_style,
138                 common_flags()->strip_path_prefix);
139     if (!frame_desc.length())
140       continue;
141     // Reserve one byte for the terminating 0.
142     uptr n = out_end - out_buf - 1;
143     internal_strncpy(out_buf, frame_desc.data(), n);
144     out_buf += __sanitizer::Min<uptr>(n, frame_desc.length());
145     *out_buf++ = 0;
146   }
147   CHECK(out_buf <= out_end);
148   *out_buf = 0;
149   frame->ClearAll();
150 }
151 
152 SANITIZER_INTERFACE_ATTRIBUTE
153 void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
154                                   char *out_buf, uptr out_buf_size) {
155   if (!out_buf_size) return;
156   out_buf[0] = 0;
157   DataInfo DI;
158   if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
159   InternalScopedString data_desc(GetPageSizeCached());
160   RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
161   internal_strncpy(out_buf, data_desc.data(), out_buf_size);
162   out_buf[out_buf_size - 1] = 0;
163 }
164 
165 SANITIZER_INTERFACE_ATTRIBUTE
166 int __sanitizer_get_module_and_offset_for_pc(uptr pc, char *module_name,
167                                              uptr module_name_len,
168                                              uptr *pc_offset) {
169   return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len,
170                                               pc_offset);
171 }
172 }  // extern "C"
173