13cab2bb3Spatrick //===-- sanitizer_stacktrace_libcdep.cpp ----------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is shared between AddressSanitizer and ThreadSanitizer
103cab2bb3Spatrick // run-time libraries.
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick
133cab2bb3Spatrick #include "sanitizer_common.h"
143cab2bb3Spatrick #include "sanitizer_placement_new.h"
153cab2bb3Spatrick #include "sanitizer_stacktrace.h"
163cab2bb3Spatrick #include "sanitizer_stacktrace_printer.h"
173cab2bb3Spatrick #include "sanitizer_symbolizer.h"
183cab2bb3Spatrick
193cab2bb3Spatrick namespace __sanitizer {
203cab2bb3Spatrick
21d89ec533Spatrick namespace {
22d89ec533Spatrick
23d89ec533Spatrick class StackTraceTextPrinter {
24d89ec533Spatrick public:
StackTraceTextPrinter(const char * stack_trace_fmt,char frame_delimiter,InternalScopedString * output,InternalScopedString * dedup_token)25d89ec533Spatrick StackTraceTextPrinter(const char *stack_trace_fmt, char frame_delimiter,
26d89ec533Spatrick InternalScopedString *output,
27d89ec533Spatrick InternalScopedString *dedup_token)
28d89ec533Spatrick : stack_trace_fmt_(stack_trace_fmt),
29d89ec533Spatrick frame_delimiter_(frame_delimiter),
30d89ec533Spatrick output_(output),
31d89ec533Spatrick dedup_token_(dedup_token),
32d89ec533Spatrick symbolize_(RenderNeedsSymbolization(stack_trace_fmt)) {}
33d89ec533Spatrick
ProcessAddressFrames(uptr pc)34d89ec533Spatrick bool ProcessAddressFrames(uptr pc) {
35d89ec533Spatrick SymbolizedStack *frames = symbolize_
36d89ec533Spatrick ? Symbolizer::GetOrInit()->SymbolizePC(pc)
37d89ec533Spatrick : SymbolizedStack::New(pc);
38d89ec533Spatrick if (!frames)
39d89ec533Spatrick return false;
40d89ec533Spatrick
41d89ec533Spatrick for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
42d89ec533Spatrick uptr prev_len = output_->length();
43d89ec533Spatrick RenderFrame(output_, stack_trace_fmt_, frame_num_++, cur->info.address,
44d89ec533Spatrick symbolize_ ? &cur->info : nullptr,
45d89ec533Spatrick common_flags()->symbolize_vs_style,
46d89ec533Spatrick common_flags()->strip_path_prefix);
47d89ec533Spatrick
48d89ec533Spatrick if (prev_len != output_->length())
49d89ec533Spatrick output_->append("%c", frame_delimiter_);
50d89ec533Spatrick
51d89ec533Spatrick ExtendDedupToken(cur);
52d89ec533Spatrick }
53d89ec533Spatrick frames->ClearAll();
54d89ec533Spatrick return true;
55d89ec533Spatrick }
56d89ec533Spatrick
57d89ec533Spatrick private:
58d89ec533Spatrick // Extend the dedup token by appending a new frame.
ExtendDedupToken(SymbolizedStack * stack)59d89ec533Spatrick void ExtendDedupToken(SymbolizedStack *stack) {
60d89ec533Spatrick if (!dedup_token_)
61d89ec533Spatrick return;
62d89ec533Spatrick
63d89ec533Spatrick if (dedup_frames_-- > 0) {
64d89ec533Spatrick if (dedup_token_->length())
65d89ec533Spatrick dedup_token_->append("--");
66d89ec533Spatrick if (stack->info.function != nullptr)
67*810390e3Srobert dedup_token_->append("%s", stack->info.function);
68d89ec533Spatrick }
69d89ec533Spatrick }
70d89ec533Spatrick
71d89ec533Spatrick const char *stack_trace_fmt_;
72d89ec533Spatrick const char frame_delimiter_;
73d89ec533Spatrick int dedup_frames_ = common_flags()->dedup_token_length;
74d89ec533Spatrick uptr frame_num_ = 0;
75d89ec533Spatrick InternalScopedString *output_;
76d89ec533Spatrick InternalScopedString *dedup_token_;
77d89ec533Spatrick const bool symbolize_ = false;
78d89ec533Spatrick };
79d89ec533Spatrick
CopyStringToBuffer(const InternalScopedString & str,char * out_buf,uptr out_buf_size)80d89ec533Spatrick static void CopyStringToBuffer(const InternalScopedString &str, char *out_buf,
81d89ec533Spatrick uptr out_buf_size) {
82d89ec533Spatrick if (!out_buf_size)
83d89ec533Spatrick return;
84d89ec533Spatrick
85d89ec533Spatrick CHECK_GT(out_buf_size, 0);
86d89ec533Spatrick uptr copy_size = Min(str.length(), out_buf_size - 1);
87d89ec533Spatrick internal_memcpy(out_buf, str.data(), copy_size);
88d89ec533Spatrick out_buf[copy_size] = '\0';
89d89ec533Spatrick }
90d89ec533Spatrick
91d89ec533Spatrick } // namespace
92d89ec533Spatrick
PrintTo(InternalScopedString * output) const93d89ec533Spatrick void StackTrace::PrintTo(InternalScopedString *output) const {
94d89ec533Spatrick CHECK(output);
95d89ec533Spatrick
96d89ec533Spatrick InternalScopedString dedup_token;
97d89ec533Spatrick StackTraceTextPrinter printer(common_flags()->stack_trace_format, '\n',
98d89ec533Spatrick output, &dedup_token);
99d89ec533Spatrick
1003cab2bb3Spatrick if (trace == nullptr || size == 0) {
101d89ec533Spatrick output->append(" <empty stack>\n\n");
1023cab2bb3Spatrick return;
1033cab2bb3Spatrick }
104d89ec533Spatrick
1053cab2bb3Spatrick for (uptr i = 0; i < size && trace[i]; i++) {
1063cab2bb3Spatrick // PCs in stack traces are actually the return addresses, that is,
1073cab2bb3Spatrick // addresses of the next instructions after the call.
1083cab2bb3Spatrick uptr pc = GetPreviousInstructionPc(trace[i]);
109d89ec533Spatrick CHECK(printer.ProcessAddressFrames(pc));
110d89ec533Spatrick }
111d89ec533Spatrick
112d89ec533Spatrick // Always add a trailing empty line after stack trace.
113d89ec533Spatrick output->append("\n");
114d89ec533Spatrick
115d89ec533Spatrick // Append deduplication token, if non-empty.
1163cab2bb3Spatrick if (dedup_token.length())
117d89ec533Spatrick output->append("DEDUP_TOKEN: %s\n", dedup_token.data());
1183cab2bb3Spatrick }
119d89ec533Spatrick
PrintTo(char * out_buf,uptr out_buf_size) const120d89ec533Spatrick uptr StackTrace::PrintTo(char *out_buf, uptr out_buf_size) const {
121d89ec533Spatrick CHECK(out_buf);
122d89ec533Spatrick
123d89ec533Spatrick InternalScopedString output;
124d89ec533Spatrick PrintTo(&output);
125d89ec533Spatrick CopyStringToBuffer(output, out_buf, out_buf_size);
126d89ec533Spatrick
127d89ec533Spatrick return output.length();
1283cab2bb3Spatrick }
129d89ec533Spatrick
Print() const130d89ec533Spatrick void StackTrace::Print() const {
131d89ec533Spatrick InternalScopedString output;
132d89ec533Spatrick PrintTo(&output);
133d89ec533Spatrick Printf("%s", output.data());
1343cab2bb3Spatrick }
1353cab2bb3Spatrick
Unwind(u32 max_depth,uptr pc,uptr bp,void * context,uptr stack_top,uptr stack_bottom,bool request_fast_unwind)1363cab2bb3Spatrick void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
1373cab2bb3Spatrick uptr stack_top, uptr stack_bottom,
1383cab2bb3Spatrick bool request_fast_unwind) {
1393cab2bb3Spatrick // Ensures all call sites get what they requested.
1403cab2bb3Spatrick CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind));
1413cab2bb3Spatrick top_frame_bp = (max_depth > 0) ? bp : 0;
1423cab2bb3Spatrick // Avoid doing any work for small max_depth.
1433cab2bb3Spatrick if (max_depth == 0) {
1443cab2bb3Spatrick size = 0;
1453cab2bb3Spatrick return;
1463cab2bb3Spatrick }
1473cab2bb3Spatrick if (max_depth == 1) {
1483cab2bb3Spatrick size = 1;
1493cab2bb3Spatrick trace_buffer[0] = pc;
1503cab2bb3Spatrick return;
1513cab2bb3Spatrick }
1523cab2bb3Spatrick if (!WillUseFastUnwind(request_fast_unwind)) {
1533cab2bb3Spatrick #if SANITIZER_CAN_SLOW_UNWIND
1543cab2bb3Spatrick if (context)
1553cab2bb3Spatrick UnwindSlow(pc, context, max_depth);
1563cab2bb3Spatrick else
1573cab2bb3Spatrick UnwindSlow(pc, max_depth);
158d89ec533Spatrick // If there are too few frames, the program may be built with
159d89ec533Spatrick // -fno-asynchronous-unwind-tables. Fall back to fast unwinder below.
160d89ec533Spatrick if (size > 2 || size >= max_depth)
161d89ec533Spatrick return;
1623cab2bb3Spatrick #else
1633cab2bb3Spatrick UNREACHABLE("slow unwind requested but not available");
1643cab2bb3Spatrick #endif
1653cab2bb3Spatrick }
166d89ec533Spatrick UnwindFast(pc, bp, stack_top, stack_bottom, max_depth);
1673cab2bb3Spatrick }
1683cab2bb3Spatrick
GetModuleAndOffsetForPc(uptr pc,char * module_name,uptr module_name_len,uptr * pc_offset)169*810390e3Srobert int GetModuleAndOffsetForPc(uptr pc, char *module_name, uptr module_name_len,
170*810390e3Srobert uptr *pc_offset) {
1713cab2bb3Spatrick const char *found_module_name = nullptr;
1723cab2bb3Spatrick bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(
1733cab2bb3Spatrick pc, &found_module_name, pc_offset);
1743cab2bb3Spatrick
1753cab2bb3Spatrick if (!ok) return false;
1763cab2bb3Spatrick
1773cab2bb3Spatrick if (module_name && module_name_len) {
1783cab2bb3Spatrick internal_strncpy(module_name, found_module_name, module_name_len);
1793cab2bb3Spatrick module_name[module_name_len - 1] = '\x00';
1803cab2bb3Spatrick }
1813cab2bb3Spatrick return true;
1823cab2bb3Spatrick }
1833cab2bb3Spatrick
1843cab2bb3Spatrick } // namespace __sanitizer
1853cab2bb3Spatrick using namespace __sanitizer;
1863cab2bb3Spatrick
1873cab2bb3Spatrick extern "C" {
1883cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_symbolize_pc(uptr pc,const char * fmt,char * out_buf,uptr out_buf_size)1893cab2bb3Spatrick void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
1903cab2bb3Spatrick uptr out_buf_size) {
191d89ec533Spatrick if (!out_buf_size)
1923cab2bb3Spatrick return;
193d89ec533Spatrick
194d89ec533Spatrick pc = StackTrace::GetPreviousInstructionPc(pc);
195d89ec533Spatrick
196d89ec533Spatrick InternalScopedString output;
197d89ec533Spatrick StackTraceTextPrinter printer(fmt, '\0', &output, nullptr);
198d89ec533Spatrick if (!printer.ProcessAddressFrames(pc)) {
199d89ec533Spatrick output.clear();
200d89ec533Spatrick output.append("<can't symbolize>");
2013cab2bb3Spatrick }
202d89ec533Spatrick CopyStringToBuffer(output, out_buf, out_buf_size);
2033cab2bb3Spatrick }
2043cab2bb3Spatrick
2053cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_symbolize_global(uptr data_addr,const char * fmt,char * out_buf,uptr out_buf_size)2063cab2bb3Spatrick void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
2073cab2bb3Spatrick char *out_buf, uptr out_buf_size) {
2083cab2bb3Spatrick if (!out_buf_size) return;
2093cab2bb3Spatrick out_buf[0] = 0;
2103cab2bb3Spatrick DataInfo DI;
2113cab2bb3Spatrick if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
212d89ec533Spatrick InternalScopedString data_desc;
2133cab2bb3Spatrick RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
2143cab2bb3Spatrick internal_strncpy(out_buf, data_desc.data(), out_buf_size);
2153cab2bb3Spatrick out_buf[out_buf_size - 1] = 0;
2163cab2bb3Spatrick }
2173cab2bb3Spatrick
2183cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_get_module_and_offset_for_pc(void * pc,char * module_name,uptr module_name_len,void ** pc_offset)219*810390e3Srobert int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_name,
2203cab2bb3Spatrick uptr module_name_len,
221*810390e3Srobert void **pc_offset) {
222*810390e3Srobert return __sanitizer::GetModuleAndOffsetForPc(
223*810390e3Srobert reinterpret_cast<uptr>(pc), module_name, module_name_len,
224*810390e3Srobert reinterpret_cast<uptr *>(pc_offset));
2253cab2bb3Spatrick }
2263cab2bb3Spatrick } // extern "C"
227