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