168d75effSDimitry Andric //===-- sanitizer_stacktrace_libcdep.cpp ----------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 1068d75effSDimitry Andric // run-time libraries. 1168d75effSDimitry Andric //===----------------------------------------------------------------------===// 1268d75effSDimitry Andric 1368d75effSDimitry Andric #include "sanitizer_common.h" 1468d75effSDimitry Andric #include "sanitizer_placement_new.h" 1568d75effSDimitry Andric #include "sanitizer_stacktrace.h" 1668d75effSDimitry Andric #include "sanitizer_stacktrace_printer.h" 1768d75effSDimitry Andric #include "sanitizer_symbolizer.h" 1868d75effSDimitry Andric 1968d75effSDimitry Andric namespace __sanitizer { 2068d75effSDimitry Andric 21fe6060f1SDimitry Andric namespace { 22fe6060f1SDimitry Andric 23fe6060f1SDimitry Andric class StackTraceTextPrinter { 24fe6060f1SDimitry Andric public: 25fe6060f1SDimitry Andric StackTraceTextPrinter(const char *stack_trace_fmt, char frame_delimiter, 26fe6060f1SDimitry Andric InternalScopedString *output, 27fe6060f1SDimitry Andric InternalScopedString *dedup_token) 28fe6060f1SDimitry Andric : stack_trace_fmt_(stack_trace_fmt), 29fe6060f1SDimitry Andric frame_delimiter_(frame_delimiter), 30fe6060f1SDimitry Andric output_(output), 31fe6060f1SDimitry Andric dedup_token_(dedup_token), 325f757f3fSDimitry Andric symbolize_(StackTracePrinter::GetOrInit()->RenderNeedsSymbolization( 335f757f3fSDimitry Andric stack_trace_fmt)) {} 34fe6060f1SDimitry Andric 35fe6060f1SDimitry Andric bool ProcessAddressFrames(uptr pc) { 361db9f3b2SDimitry Andric SymbolizedStackHolder symbolized_stack( 371db9f3b2SDimitry Andric symbolize_ ? Symbolizer::GetOrInit()->SymbolizePC(pc) 381db9f3b2SDimitry Andric : SymbolizedStack::New(pc)); 391db9f3b2SDimitry Andric const SymbolizedStack *frames = symbolized_stack.get(); 40fe6060f1SDimitry Andric if (!frames) 41fe6060f1SDimitry Andric return false; 42fe6060f1SDimitry Andric 431db9f3b2SDimitry Andric for (const SymbolizedStack *cur = frames; cur; cur = cur->next) { 44fe6060f1SDimitry Andric uptr prev_len = output_->length(); 455f757f3fSDimitry Andric StackTracePrinter::GetOrInit()->RenderFrame( 465f757f3fSDimitry Andric output_, stack_trace_fmt_, frame_num_++, cur->info.address, 475f757f3fSDimitry Andric symbolize_ ? &cur->info : nullptr, common_flags()->symbolize_vs_style, 48fe6060f1SDimitry Andric common_flags()->strip_path_prefix); 49fe6060f1SDimitry Andric 50fe6060f1SDimitry Andric if (prev_len != output_->length()) 515f757f3fSDimitry Andric output_->AppendF("%c", frame_delimiter_); 52fe6060f1SDimitry Andric 53fe6060f1SDimitry Andric ExtendDedupToken(cur); 54fe6060f1SDimitry Andric } 55fe6060f1SDimitry Andric return true; 56fe6060f1SDimitry Andric } 57fe6060f1SDimitry Andric 58fe6060f1SDimitry Andric private: 59fe6060f1SDimitry Andric // Extend the dedup token by appending a new frame. 601db9f3b2SDimitry Andric void ExtendDedupToken(const SymbolizedStack *stack) { 61fe6060f1SDimitry Andric if (!dedup_token_) 62fe6060f1SDimitry Andric return; 63fe6060f1SDimitry Andric 64fe6060f1SDimitry Andric if (dedup_frames_-- > 0) { 65fe6060f1SDimitry Andric if (dedup_token_->length()) 66*0fca6ea1SDimitry Andric dedup_token_->Append("--"); 675f757f3fSDimitry Andric if (stack->info.function) 685f757f3fSDimitry Andric dedup_token_->Append(stack->info.function); 69fe6060f1SDimitry Andric } 70fe6060f1SDimitry Andric } 71fe6060f1SDimitry Andric 72fe6060f1SDimitry Andric const char *stack_trace_fmt_; 73fe6060f1SDimitry Andric const char frame_delimiter_; 74fe6060f1SDimitry Andric int dedup_frames_ = common_flags()->dedup_token_length; 75fe6060f1SDimitry Andric uptr frame_num_ = 0; 76fe6060f1SDimitry Andric InternalScopedString *output_; 77fe6060f1SDimitry Andric InternalScopedString *dedup_token_; 78fe6060f1SDimitry Andric const bool symbolize_ = false; 79fe6060f1SDimitry Andric }; 80fe6060f1SDimitry Andric 81fe6060f1SDimitry Andric static void CopyStringToBuffer(const InternalScopedString &str, char *out_buf, 82fe6060f1SDimitry Andric uptr out_buf_size) { 83fe6060f1SDimitry Andric if (!out_buf_size) 84fe6060f1SDimitry Andric return; 85fe6060f1SDimitry Andric 86fe6060f1SDimitry Andric CHECK_GT(out_buf_size, 0); 87fe6060f1SDimitry Andric uptr copy_size = Min(str.length(), out_buf_size - 1); 88fe6060f1SDimitry Andric internal_memcpy(out_buf, str.data(), copy_size); 89fe6060f1SDimitry Andric out_buf[copy_size] = '\0'; 90fe6060f1SDimitry Andric } 91fe6060f1SDimitry Andric 92fe6060f1SDimitry Andric } // namespace 93fe6060f1SDimitry Andric 94fe6060f1SDimitry Andric void StackTrace::PrintTo(InternalScopedString *output) const { 95fe6060f1SDimitry Andric CHECK(output); 96fe6060f1SDimitry Andric 97fe6060f1SDimitry Andric InternalScopedString dedup_token; 98fe6060f1SDimitry Andric StackTraceTextPrinter printer(common_flags()->stack_trace_format, '\n', 99fe6060f1SDimitry Andric output, &dedup_token); 100fe6060f1SDimitry Andric 10168d75effSDimitry Andric if (trace == nullptr || size == 0) { 102*0fca6ea1SDimitry Andric output->Append(" <empty stack>\n\n"); 10368d75effSDimitry Andric return; 10468d75effSDimitry Andric } 105fe6060f1SDimitry Andric 10668d75effSDimitry Andric for (uptr i = 0; i < size && trace[i]; i++) { 10768d75effSDimitry Andric // PCs in stack traces are actually the return addresses, that is, 10868d75effSDimitry Andric // addresses of the next instructions after the call. 10968d75effSDimitry Andric uptr pc = GetPreviousInstructionPc(trace[i]); 110fe6060f1SDimitry Andric CHECK(printer.ProcessAddressFrames(pc)); 111fe6060f1SDimitry Andric } 112fe6060f1SDimitry Andric 113fe6060f1SDimitry Andric // Always add a trailing empty line after stack trace. 114*0fca6ea1SDimitry Andric output->Append("\n"); 115fe6060f1SDimitry Andric 116fe6060f1SDimitry Andric // Append deduplication token, if non-empty. 11768d75effSDimitry Andric if (dedup_token.length()) 1185f757f3fSDimitry Andric output->AppendF("DEDUP_TOKEN: %s\n", dedup_token.data()); 11968d75effSDimitry Andric } 120fe6060f1SDimitry Andric 121fe6060f1SDimitry Andric uptr StackTrace::PrintTo(char *out_buf, uptr out_buf_size) const { 122fe6060f1SDimitry Andric CHECK(out_buf); 123fe6060f1SDimitry Andric 124fe6060f1SDimitry Andric InternalScopedString output; 125fe6060f1SDimitry Andric PrintTo(&output); 126fe6060f1SDimitry Andric CopyStringToBuffer(output, out_buf, out_buf_size); 127fe6060f1SDimitry Andric 128fe6060f1SDimitry Andric return output.length(); 12968d75effSDimitry Andric } 130fe6060f1SDimitry Andric 131fe6060f1SDimitry Andric void StackTrace::Print() const { 132fe6060f1SDimitry Andric InternalScopedString output; 133fe6060f1SDimitry Andric PrintTo(&output); 134fe6060f1SDimitry Andric Printf("%s", output.data()); 13568d75effSDimitry Andric } 13668d75effSDimitry Andric 13768d75effSDimitry Andric void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context, 13868d75effSDimitry Andric uptr stack_top, uptr stack_bottom, 13968d75effSDimitry Andric bool request_fast_unwind) { 14068d75effSDimitry Andric // Ensures all call sites get what they requested. 14168d75effSDimitry Andric CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind)); 14268d75effSDimitry Andric top_frame_bp = (max_depth > 0) ? bp : 0; 14368d75effSDimitry Andric // Avoid doing any work for small max_depth. 14468d75effSDimitry Andric if (max_depth == 0) { 14568d75effSDimitry Andric size = 0; 14668d75effSDimitry Andric return; 14768d75effSDimitry Andric } 14868d75effSDimitry Andric if (max_depth == 1) { 14968d75effSDimitry Andric size = 1; 15068d75effSDimitry Andric trace_buffer[0] = pc; 15168d75effSDimitry Andric return; 15268d75effSDimitry Andric } 15368d75effSDimitry Andric if (!WillUseFastUnwind(request_fast_unwind)) { 15468d75effSDimitry Andric #if SANITIZER_CAN_SLOW_UNWIND 15568d75effSDimitry Andric if (context) 15668d75effSDimitry Andric UnwindSlow(pc, context, max_depth); 15768d75effSDimitry Andric else 15868d75effSDimitry Andric UnwindSlow(pc, max_depth); 159fe6060f1SDimitry Andric // If there are too few frames, the program may be built with 160fe6060f1SDimitry Andric // -fno-asynchronous-unwind-tables. Fall back to fast unwinder below. 161fe6060f1SDimitry Andric if (size > 2 || size >= max_depth) 162fe6060f1SDimitry Andric return; 16368d75effSDimitry Andric #else 16468d75effSDimitry Andric UNREACHABLE("slow unwind requested but not available"); 16568d75effSDimitry Andric #endif 16668d75effSDimitry Andric } 167fe6060f1SDimitry Andric UnwindFast(pc, bp, stack_top, stack_bottom, max_depth); 16868d75effSDimitry Andric } 16968d75effSDimitry Andric 17081ad6265SDimitry Andric int GetModuleAndOffsetForPc(uptr pc, char *module_name, uptr module_name_len, 17181ad6265SDimitry Andric uptr *pc_offset) { 17268d75effSDimitry Andric const char *found_module_name = nullptr; 17368d75effSDimitry Andric bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( 17468d75effSDimitry Andric pc, &found_module_name, pc_offset); 17568d75effSDimitry Andric 17668d75effSDimitry Andric if (!ok) return false; 17768d75effSDimitry Andric 17868d75effSDimitry Andric if (module_name && module_name_len) { 17968d75effSDimitry Andric internal_strncpy(module_name, found_module_name, module_name_len); 18068d75effSDimitry Andric module_name[module_name_len - 1] = '\x00'; 18168d75effSDimitry Andric } 18268d75effSDimitry Andric return true; 18368d75effSDimitry Andric } 18468d75effSDimitry Andric 18568d75effSDimitry Andric } // namespace __sanitizer 18668d75effSDimitry Andric using namespace __sanitizer; 18768d75effSDimitry Andric 18868d75effSDimitry Andric extern "C" { 18968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 19068d75effSDimitry Andric void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, 19168d75effSDimitry Andric uptr out_buf_size) { 192fe6060f1SDimitry Andric if (!out_buf_size) 19368d75effSDimitry Andric return; 194fe6060f1SDimitry Andric 195fe6060f1SDimitry Andric pc = StackTrace::GetPreviousInstructionPc(pc); 196fe6060f1SDimitry Andric 197fe6060f1SDimitry Andric InternalScopedString output; 198fe6060f1SDimitry Andric StackTraceTextPrinter printer(fmt, '\0', &output, nullptr); 199fe6060f1SDimitry Andric if (!printer.ProcessAddressFrames(pc)) { 200fe6060f1SDimitry Andric output.clear(); 201*0fca6ea1SDimitry Andric output.Append("<can't symbolize>"); 20268d75effSDimitry Andric } 203fe6060f1SDimitry Andric CopyStringToBuffer(output, out_buf, out_buf_size); 20468d75effSDimitry Andric } 20568d75effSDimitry Andric 20668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 20768d75effSDimitry Andric void __sanitizer_symbolize_global(uptr data_addr, const char *fmt, 20868d75effSDimitry Andric char *out_buf, uptr out_buf_size) { 20968d75effSDimitry Andric if (!out_buf_size) return; 21068d75effSDimitry Andric out_buf[0] = 0; 21168d75effSDimitry Andric DataInfo DI; 21268d75effSDimitry Andric if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return; 213fe6060f1SDimitry Andric InternalScopedString data_desc; 2145f757f3fSDimitry Andric StackTracePrinter::GetOrInit()->RenderData(&data_desc, fmt, &DI, 2155f757f3fSDimitry Andric common_flags()->strip_path_prefix); 21668d75effSDimitry Andric internal_strncpy(out_buf, data_desc.data(), out_buf_size); 21768d75effSDimitry Andric out_buf[out_buf_size - 1] = 0; 21868d75effSDimitry Andric } 21968d75effSDimitry Andric 22068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 22181ad6265SDimitry Andric int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_name, 22268d75effSDimitry Andric uptr module_name_len, 22381ad6265SDimitry Andric void **pc_offset) { 22481ad6265SDimitry Andric return __sanitizer::GetModuleAndOffsetForPc( 22581ad6265SDimitry Andric reinterpret_cast<uptr>(pc), module_name, module_name_len, 22681ad6265SDimitry Andric reinterpret_cast<uptr *>(pc_offset)); 22768d75effSDimitry Andric } 22868d75effSDimitry Andric } // extern "C" 229