1//===-- sanitizer_stacktrace_libcdep.cc -----------------------------------===// 2// 3// This file is distributed under the University of Illinois Open Source 4// License. See LICENSE.TXT for details. 5// 6//===----------------------------------------------------------------------===// 7// 8// This file is shared between AddressSanitizer and ThreadSanitizer 9// run-time libraries. 10//===----------------------------------------------------------------------===// 11 12#include "sanitizer_common.h" 13#include "sanitizer_placement_new.h" 14#include "sanitizer_stacktrace.h" 15#include "sanitizer_stacktrace_printer.h" 16#include "sanitizer_symbolizer.h" 17 18namespace __sanitizer { 19 20void StackTrace::Print() const { 21 if (trace == nullptr || size == 0) { 22 Printf(" <empty stack>\n\n"); 23 return; 24 } 25 InternalScopedString frame_desc(GetPageSizeCached() * 2); 26 InternalScopedString dedup_token(GetPageSizeCached()); 27 int dedup_frames = common_flags()->dedup_token_length; 28 uptr frame_num = 0; 29 for (uptr i = 0; i < size && trace[i]; i++) { 30 // PCs in stack traces are actually the return addresses, that is, 31 // addresses of the next instructions after the call. 32 uptr pc = GetPreviousInstructionPc(trace[i]); 33 SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc); 34 CHECK(frames); 35 for (SymbolizedStack *cur = frames; cur; cur = cur->next) { 36 frame_desc.clear(); 37 RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++, 38 cur->info, common_flags()->symbolize_vs_style, 39 common_flags()->strip_path_prefix); 40 Printf("%s\n", frame_desc.data()); 41 if (dedup_frames-- > 0) { 42 if (dedup_token.length()) 43 dedup_token.append("--"); 44 if (cur->info.function != nullptr) 45 dedup_token.append(cur->info.function); 46 } 47 } 48 frames->ClearAll(); 49 } 50 // Always print a trailing empty line after stack trace. 51 Printf("\n"); 52 if (dedup_token.length()) 53 Printf("DEDUP_TOKEN: %s\n", dedup_token.data()); 54} 55 56void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context, 57 uptr stack_top, uptr stack_bottom, 58 bool request_fast_unwind) { 59 top_frame_bp = (max_depth > 0) ? bp : 0; 60 // Avoid doing any work for small max_depth. 61 if (max_depth == 0) { 62 size = 0; 63 return; 64 } 65 if (max_depth == 1) { 66 size = 1; 67 trace_buffer[0] = pc; 68 return; 69 } 70 if (!WillUseFastUnwind(request_fast_unwind)) { 71#if SANITIZER_CAN_SLOW_UNWIND 72 if (context) 73 SlowUnwindStackWithContext(pc, context, max_depth); 74 else 75 SlowUnwindStack(pc, max_depth); 76#else 77 UNREACHABLE("slow unwind requested but not available"); 78#endif 79 } else { 80 FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth); 81 } 82} 83 84static int GetModuleAndOffsetForPc(uptr pc, char *module_name, 85 uptr module_name_len, uptr *pc_offset) { 86 const char *found_module_name = nullptr; 87 bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( 88 pc, &found_module_name, pc_offset); 89 90 if (!ok) return false; 91 92 if (module_name && module_name_len) { 93 internal_strncpy(module_name, found_module_name, module_name_len); 94 module_name[module_name_len - 1] = '\x00'; 95 } 96 return true; 97} 98 99} // namespace __sanitizer 100using namespace __sanitizer; 101 102extern "C" { 103SANITIZER_INTERFACE_ATTRIBUTE 104void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, 105 uptr out_buf_size) { 106 if (!out_buf_size) return; 107 pc = StackTrace::GetPreviousInstructionPc(pc); 108 SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); 109 if (!frame) { 110 internal_strncpy(out_buf, "<can't symbolize>", out_buf_size); 111 out_buf[out_buf_size - 1] = 0; 112 return; 113 } 114 InternalScopedString frame_desc(GetPageSizeCached()); 115 uptr frame_num = 0; 116 // Reserve one byte for the final 0. 117 char *out_end = out_buf + out_buf_size - 1; 118 for (SymbolizedStack *cur = frame; cur && out_buf < out_end; 119 cur = cur->next) { 120 frame_desc.clear(); 121 RenderFrame(&frame_desc, fmt, frame_num++, cur->info, 122 common_flags()->symbolize_vs_style, 123 common_flags()->strip_path_prefix); 124 if (!frame_desc.length()) 125 continue; 126 // Reserve one byte for the terminating 0. 127 uptr n = out_end - out_buf - 1; 128 internal_strncpy(out_buf, frame_desc.data(), n); 129 out_buf += __sanitizer::Min<uptr>(n, frame_desc.length()); 130 *out_buf++ = 0; 131 } 132 CHECK(out_buf <= out_end); 133 *out_buf = 0; 134} 135 136SANITIZER_INTERFACE_ATTRIBUTE 137void __sanitizer_symbolize_global(uptr data_addr, const char *fmt, 138 char *out_buf, uptr out_buf_size) { 139 if (!out_buf_size) return; 140 out_buf[0] = 0; 141 DataInfo DI; 142 if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return; 143 InternalScopedString data_desc(GetPageSizeCached()); 144 RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix); 145 internal_strncpy(out_buf, data_desc.data(), out_buf_size); 146 out_buf[out_buf_size - 1] = 0; 147} 148 149SANITIZER_INTERFACE_ATTRIBUTE 150int __sanitizer_get_module_and_offset_for_pc( // NOLINT 151 uptr pc, char *module_name, uptr module_name_len, uptr *pc_offset) { 152 return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len, 153 pc_offset); 154} 155} // extern "C" 156