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