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