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 namespace { 22 23 class StackTraceTextPrinter { 24 public: 25 StackTraceTextPrinter(const char *stack_trace_fmt, char frame_delimiter, 26 InternalScopedString *output, 27 InternalScopedString *dedup_token) 28 : stack_trace_fmt_(stack_trace_fmt), 29 frame_delimiter_(frame_delimiter), 30 output_(output), 31 dedup_token_(dedup_token), 32 symbolize_(StackTracePrinter::GetOrInit()->RenderNeedsSymbolization( 33 stack_trace_fmt)) {} 34 35 bool ProcessAddressFrames(uptr pc) { 36 SymbolizedStackHolder symbolized_stack( 37 symbolize_ ? Symbolizer::GetOrInit()->SymbolizePC(pc) 38 : SymbolizedStack::New(pc)); 39 const SymbolizedStack *frames = symbolized_stack.get(); 40 if (!frames) 41 return false; 42 43 for (const SymbolizedStack *cur = frames; cur; cur = cur->next) { 44 uptr prev_len = output_->length(); 45 StackTracePrinter::GetOrInit()->RenderFrame( 46 output_, stack_trace_fmt_, frame_num_++, cur->info.address, 47 symbolize_ ? &cur->info : nullptr, common_flags()->symbolize_vs_style, 48 common_flags()->strip_path_prefix); 49 50 if (prev_len != output_->length()) 51 output_->AppendF("%c", frame_delimiter_); 52 53 ExtendDedupToken(cur); 54 } 55 return true; 56 } 57 58 private: 59 // Extend the dedup token by appending a new frame. 60 void ExtendDedupToken(const SymbolizedStack *stack) { 61 if (!dedup_token_) 62 return; 63 64 if (dedup_frames_-- > 0) { 65 if (dedup_token_->length()) 66 dedup_token_->AppendF("--"); 67 if (stack->info.function) 68 dedup_token_->Append(stack->info.function); 69 } 70 } 71 72 const char *stack_trace_fmt_; 73 const char frame_delimiter_; 74 int dedup_frames_ = common_flags()->dedup_token_length; 75 uptr frame_num_ = 0; 76 InternalScopedString *output_; 77 InternalScopedString *dedup_token_; 78 const bool symbolize_ = false; 79 }; 80 81 static void CopyStringToBuffer(const InternalScopedString &str, char *out_buf, 82 uptr out_buf_size) { 83 if (!out_buf_size) 84 return; 85 86 CHECK_GT(out_buf_size, 0); 87 uptr copy_size = Min(str.length(), out_buf_size - 1); 88 internal_memcpy(out_buf, str.data(), copy_size); 89 out_buf[copy_size] = '\0'; 90 } 91 92 } // namespace 93 94 void StackTrace::PrintTo(InternalScopedString *output) const { 95 CHECK(output); 96 97 InternalScopedString dedup_token; 98 StackTraceTextPrinter printer(common_flags()->stack_trace_format, '\n', 99 output, &dedup_token); 100 101 if (trace == nullptr || size == 0) { 102 output->AppendF(" <empty stack>\n\n"); 103 return; 104 } 105 106 for (uptr i = 0; i < size && trace[i]; i++) { 107 // PCs in stack traces are actually the return addresses, that is, 108 // addresses of the next instructions after the call. 109 uptr pc = GetPreviousInstructionPc(trace[i]); 110 CHECK(printer.ProcessAddressFrames(pc)); 111 } 112 113 // Always add a trailing empty line after stack trace. 114 output->AppendF("\n"); 115 116 // Append deduplication token, if non-empty. 117 if (dedup_token.length()) 118 output->AppendF("DEDUP_TOKEN: %s\n", dedup_token.data()); 119 } 120 121 uptr StackTrace::PrintTo(char *out_buf, uptr out_buf_size) const { 122 CHECK(out_buf); 123 124 InternalScopedString output; 125 PrintTo(&output); 126 CopyStringToBuffer(output, out_buf, out_buf_size); 127 128 return output.length(); 129 } 130 131 void StackTrace::Print() const { 132 InternalScopedString output; 133 PrintTo(&output); 134 Printf("%s", output.data()); 135 } 136 137 void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context, 138 uptr stack_top, uptr stack_bottom, 139 bool request_fast_unwind) { 140 // Ensures all call sites get what they requested. 141 CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind)); 142 top_frame_bp = (max_depth > 0) ? bp : 0; 143 // Avoid doing any work for small max_depth. 144 if (max_depth == 0) { 145 size = 0; 146 return; 147 } 148 if (max_depth == 1) { 149 size = 1; 150 trace_buffer[0] = pc; 151 return; 152 } 153 if (!WillUseFastUnwind(request_fast_unwind)) { 154 #if SANITIZER_CAN_SLOW_UNWIND 155 if (context) 156 UnwindSlow(pc, context, max_depth); 157 else 158 UnwindSlow(pc, max_depth); 159 // If there are too few frames, the program may be built with 160 // -fno-asynchronous-unwind-tables. Fall back to fast unwinder below. 161 if (size > 2 || size >= max_depth) 162 return; 163 #else 164 UNREACHABLE("slow unwind requested but not available"); 165 #endif 166 } 167 UnwindFast(pc, bp, stack_top, stack_bottom, max_depth); 168 } 169 170 int GetModuleAndOffsetForPc(uptr pc, char *module_name, uptr module_name_len, 171 uptr *pc_offset) { 172 const char *found_module_name = nullptr; 173 bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( 174 pc, &found_module_name, pc_offset); 175 176 if (!ok) return false; 177 178 if (module_name && module_name_len) { 179 internal_strncpy(module_name, found_module_name, module_name_len); 180 module_name[module_name_len - 1] = '\x00'; 181 } 182 return true; 183 } 184 185 } // namespace __sanitizer 186 using namespace __sanitizer; 187 188 extern "C" { 189 SANITIZER_INTERFACE_ATTRIBUTE 190 void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, 191 uptr out_buf_size) { 192 if (!out_buf_size) 193 return; 194 195 pc = StackTrace::GetPreviousInstructionPc(pc); 196 197 InternalScopedString output; 198 StackTraceTextPrinter printer(fmt, '\0', &output, nullptr); 199 if (!printer.ProcessAddressFrames(pc)) { 200 output.clear(); 201 output.AppendF("<can't symbolize>"); 202 } 203 CopyStringToBuffer(output, out_buf, out_buf_size); 204 } 205 206 SANITIZER_INTERFACE_ATTRIBUTE 207 void __sanitizer_symbolize_global(uptr data_addr, const char *fmt, 208 char *out_buf, uptr out_buf_size) { 209 if (!out_buf_size) return; 210 out_buf[0] = 0; 211 DataInfo DI; 212 if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return; 213 InternalScopedString data_desc; 214 StackTracePrinter::GetOrInit()->RenderData(&data_desc, fmt, &DI, 215 common_flags()->strip_path_prefix); 216 internal_strncpy(out_buf, data_desc.data(), out_buf_size); 217 out_buf[out_buf_size - 1] = 0; 218 } 219 220 SANITIZER_INTERFACE_ATTRIBUTE 221 int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_name, 222 uptr module_name_len, 223 void **pc_offset) { 224 return __sanitizer::GetModuleAndOffsetForPc( 225 reinterpret_cast<uptr>(pc), module_name, module_name_len, 226 reinterpret_cast<uptr *>(pc_offset)); 227 } 228 } // extern "C" 229