sanitizer_stacktrace_libcdep.cpp revision 360784
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 19namespace __sanitizer { 20 21void 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 uptr frame_num = 0; 30 for (uptr i = 0; i < size && trace[i]; i++) { 31 // PCs in stack traces are actually the return addresses, that is, 32 // addresses of the next instructions after the call. 33 uptr pc = GetPreviousInstructionPc(trace[i]); 34 SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc); 35 CHECK(frames); 36 for (SymbolizedStack *cur = frames; cur; cur = cur->next) { 37 frame_desc.clear(); 38 RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++, 39 cur->info, common_flags()->symbolize_vs_style, 40 common_flags()->strip_path_prefix); 41 Printf("%s\n", frame_desc.data()); 42 if (dedup_frames-- > 0) { 43 if (dedup_token.length()) 44 dedup_token.append("--"); 45 if (cur->info.function != nullptr) 46 dedup_token.append(cur->info.function); 47 } 48 } 49 frames->ClearAll(); 50 } 51 // Always print a trailing empty line after stack trace. 52 Printf("\n"); 53 if (dedup_token.length()) 54 Printf("DEDUP_TOKEN: %s\n", dedup_token.data()); 55} 56 57void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context, 58 uptr stack_top, uptr stack_bottom, 59 bool request_fast_unwind) { 60 // Ensures all call sites get what they requested. 61 CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind)); 62 top_frame_bp = (max_depth > 0) ? bp : 0; 63 // Avoid doing any work for small max_depth. 64 if (max_depth == 0) { 65 size = 0; 66 return; 67 } 68 if (max_depth == 1) { 69 size = 1; 70 trace_buffer[0] = pc; 71 return; 72 } 73 if (!WillUseFastUnwind(request_fast_unwind)) { 74#if SANITIZER_CAN_SLOW_UNWIND 75 if (context) 76 UnwindSlow(pc, context, max_depth); 77 else 78 UnwindSlow(pc, max_depth); 79#else 80 UNREACHABLE("slow unwind requested but not available"); 81#endif 82 } else { 83 UnwindFast(pc, bp, stack_top, stack_bottom, max_depth); 84 } 85} 86 87static int GetModuleAndOffsetForPc(uptr pc, char *module_name, 88 uptr module_name_len, uptr *pc_offset) { 89 const char *found_module_name = nullptr; 90 bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( 91 pc, &found_module_name, pc_offset); 92 93 if (!ok) return false; 94 95 if (module_name && module_name_len) { 96 internal_strncpy(module_name, found_module_name, module_name_len); 97 module_name[module_name_len - 1] = '\x00'; 98 } 99 return true; 100} 101 102} // namespace __sanitizer 103using namespace __sanitizer; 104 105extern "C" { 106SANITIZER_INTERFACE_ATTRIBUTE 107void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, 108 uptr out_buf_size) { 109 if (!out_buf_size) return; 110 pc = StackTrace::GetPreviousInstructionPc(pc); 111 SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); 112 if (!frame) { 113 internal_strncpy(out_buf, "<can't symbolize>", out_buf_size); 114 out_buf[out_buf_size - 1] = 0; 115 return; 116 } 117 InternalScopedString frame_desc(GetPageSizeCached()); 118 uptr frame_num = 0; 119 // Reserve one byte for the final 0. 120 char *out_end = out_buf + out_buf_size - 1; 121 for (SymbolizedStack *cur = frame; cur && out_buf < out_end; 122 cur = cur->next) { 123 frame_desc.clear(); 124 RenderFrame(&frame_desc, fmt, frame_num++, cur->info, 125 common_flags()->symbolize_vs_style, 126 common_flags()->strip_path_prefix); 127 if (!frame_desc.length()) 128 continue; 129 // Reserve one byte for the terminating 0. 130 uptr n = out_end - out_buf - 1; 131 internal_strncpy(out_buf, frame_desc.data(), n); 132 out_buf += __sanitizer::Min<uptr>(n, frame_desc.length()); 133 *out_buf++ = 0; 134 } 135 CHECK(out_buf <= out_end); 136 *out_buf = 0; 137} 138 139SANITIZER_INTERFACE_ATTRIBUTE 140void __sanitizer_symbolize_global(uptr data_addr, const char *fmt, 141 char *out_buf, uptr out_buf_size) { 142 if (!out_buf_size) return; 143 out_buf[0] = 0; 144 DataInfo DI; 145 if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return; 146 InternalScopedString data_desc(GetPageSizeCached()); 147 RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix); 148 internal_strncpy(out_buf, data_desc.data(), out_buf_size); 149 out_buf[out_buf_size - 1] = 0; 150} 151 152SANITIZER_INTERFACE_ATTRIBUTE 153int __sanitizer_get_module_and_offset_for_pc(uptr pc, char *module_name, 154 uptr module_name_len, 155 uptr *pc_offset) { 156 return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len, 157 pc_offset); 158} 159} // extern "C" 160