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:
StackTraceTextPrinter(const char * stack_trace_fmt,char frame_delimiter,InternalScopedString * output,InternalScopedString * dedup_token)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
ProcessAddressFrames(uptr pc)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.
ExtendDedupToken(const SymbolizedStack * stack)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
CopyStringToBuffer(const InternalScopedString & str,char * out_buf,uptr out_buf_size)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
PrintTo(InternalScopedString * output) const94fe6060f1SDimitry 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
PrintTo(char * out_buf,uptr out_buf_size) const121fe6060f1SDimitry 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
Print() const131fe6060f1SDimitry Andric void StackTrace::Print() const {
132fe6060f1SDimitry Andric InternalScopedString output;
133fe6060f1SDimitry Andric PrintTo(&output);
134fe6060f1SDimitry Andric Printf("%s", output.data());
13568d75effSDimitry Andric }
13668d75effSDimitry Andric
Unwind(u32 max_depth,uptr pc,uptr bp,void * context,uptr stack_top,uptr stack_bottom,bool request_fast_unwind)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
GetModuleAndOffsetForPc(uptr pc,char * module_name,uptr module_name_len,uptr * pc_offset)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
__sanitizer_symbolize_pc(uptr pc,const char * fmt,char * out_buf,uptr out_buf_size)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
__sanitizer_symbolize_global(uptr data_addr,const char * fmt,char * out_buf,uptr out_buf_size)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
__sanitizer_get_module_and_offset_for_pc(void * pc,char * module_name,uptr module_name_len,void ** pc_offset)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