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