1353944Sdim//===-- sanitizer_stacktrace_libcdep.cpp ----------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is shared between AddressSanitizer and ThreadSanitizer
10353944Sdim// run-time libraries.
11353944Sdim//===----------------------------------------------------------------------===//
12353944Sdim
13353944Sdim#include "sanitizer_common.h"
14353944Sdim#include "sanitizer_placement_new.h"
15353944Sdim#include "sanitizer_stacktrace.h"
16353944Sdim#include "sanitizer_stacktrace_printer.h"
17353944Sdim#include "sanitizer_symbolizer.h"
18353944Sdim
19353944Sdimnamespace __sanitizer {
20353944Sdim
21353944Sdimvoid StackTrace::Print() const {
22353944Sdim  if (trace == nullptr || size == 0) {
23353944Sdim    Printf("    <empty stack>\n\n");
24353944Sdim    return;
25353944Sdim  }
26353944Sdim  InternalScopedString frame_desc(GetPageSizeCached() * 2);
27353944Sdim  InternalScopedString dedup_token(GetPageSizeCached());
28353944Sdim  int dedup_frames = common_flags()->dedup_token_length;
29353944Sdim  uptr frame_num = 0;
30353944Sdim  for (uptr i = 0; i < size && trace[i]; i++) {
31353944Sdim    // PCs in stack traces are actually the return addresses, that is,
32353944Sdim    // addresses of the next instructions after the call.
33353944Sdim    uptr pc = GetPreviousInstructionPc(trace[i]);
34353944Sdim    SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
35353944Sdim    CHECK(frames);
36353944Sdim    for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
37353944Sdim      frame_desc.clear();
38353944Sdim      RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
39353944Sdim                  cur->info, common_flags()->symbolize_vs_style,
40353944Sdim                  common_flags()->strip_path_prefix);
41353944Sdim      Printf("%s\n", frame_desc.data());
42353944Sdim      if (dedup_frames-- > 0) {
43353944Sdim        if (dedup_token.length())
44353944Sdim          dedup_token.append("--");
45353944Sdim        if (cur->info.function != nullptr)
46353944Sdim          dedup_token.append(cur->info.function);
47353944Sdim      }
48353944Sdim    }
49353944Sdim    frames->ClearAll();
50353944Sdim  }
51353944Sdim  // Always print a trailing empty line after stack trace.
52353944Sdim  Printf("\n");
53353944Sdim  if (dedup_token.length())
54353944Sdim    Printf("DEDUP_TOKEN: %s\n", dedup_token.data());
55353944Sdim}
56353944Sdim
57353944Sdimvoid BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
58353944Sdim                                uptr stack_top, uptr stack_bottom,
59353944Sdim                                bool request_fast_unwind) {
60353944Sdim  // Ensures all call sites get what they requested.
61353944Sdim  CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind));
62353944Sdim  top_frame_bp = (max_depth > 0) ? bp : 0;
63353944Sdim  // Avoid doing any work for small max_depth.
64353944Sdim  if (max_depth == 0) {
65353944Sdim    size = 0;
66353944Sdim    return;
67353944Sdim  }
68353944Sdim  if (max_depth == 1) {
69353944Sdim    size = 1;
70353944Sdim    trace_buffer[0] = pc;
71353944Sdim    return;
72353944Sdim  }
73353944Sdim  if (!WillUseFastUnwind(request_fast_unwind)) {
74353944Sdim#if SANITIZER_CAN_SLOW_UNWIND
75353944Sdim    if (context)
76353944Sdim      UnwindSlow(pc, context, max_depth);
77353944Sdim    else
78353944Sdim      UnwindSlow(pc, max_depth);
79353944Sdim#else
80353944Sdim    UNREACHABLE("slow unwind requested but not available");
81353944Sdim#endif
82353944Sdim  } else {
83353944Sdim    UnwindFast(pc, bp, stack_top, stack_bottom, max_depth);
84353944Sdim  }
85353944Sdim}
86353944Sdim
87353944Sdimstatic int GetModuleAndOffsetForPc(uptr pc, char *module_name,
88353944Sdim                                   uptr module_name_len, uptr *pc_offset) {
89353944Sdim  const char *found_module_name = nullptr;
90353944Sdim  bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(
91353944Sdim      pc, &found_module_name, pc_offset);
92353944Sdim
93353944Sdim  if (!ok) return false;
94353944Sdim
95353944Sdim  if (module_name && module_name_len) {
96353944Sdim    internal_strncpy(module_name, found_module_name, module_name_len);
97353944Sdim    module_name[module_name_len - 1] = '\x00';
98353944Sdim  }
99353944Sdim  return true;
100353944Sdim}
101353944Sdim
102353944Sdim}  // namespace __sanitizer
103353944Sdimusing namespace __sanitizer;
104353944Sdim
105353944Sdimextern "C" {
106353944SdimSANITIZER_INTERFACE_ATTRIBUTE
107353944Sdimvoid __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
108353944Sdim                              uptr out_buf_size) {
109353944Sdim  if (!out_buf_size) return;
110353944Sdim  pc = StackTrace::GetPreviousInstructionPc(pc);
111353944Sdim  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
112353944Sdim  if (!frame) {
113353944Sdim    internal_strncpy(out_buf, "<can't symbolize>", out_buf_size);
114353944Sdim    out_buf[out_buf_size - 1] = 0;
115353944Sdim    return;
116353944Sdim  }
117353944Sdim  InternalScopedString frame_desc(GetPageSizeCached());
118353944Sdim  uptr frame_num = 0;
119353944Sdim  // Reserve one byte for the final 0.
120353944Sdim  char *out_end = out_buf + out_buf_size - 1;
121353944Sdim  for (SymbolizedStack *cur = frame; cur && out_buf < out_end;
122353944Sdim       cur = cur->next) {
123353944Sdim    frame_desc.clear();
124353944Sdim    RenderFrame(&frame_desc, fmt, frame_num++, cur->info,
125353944Sdim                common_flags()->symbolize_vs_style,
126353944Sdim                common_flags()->strip_path_prefix);
127353944Sdim    if (!frame_desc.length())
128353944Sdim      continue;
129353944Sdim    // Reserve one byte for the terminating 0.
130353944Sdim    uptr n = out_end - out_buf - 1;
131353944Sdim    internal_strncpy(out_buf, frame_desc.data(), n);
132353944Sdim    out_buf += __sanitizer::Min<uptr>(n, frame_desc.length());
133353944Sdim    *out_buf++ = 0;
134353944Sdim  }
135353944Sdim  CHECK(out_buf <= out_end);
136353944Sdim  *out_buf = 0;
137353944Sdim}
138353944Sdim
139353944SdimSANITIZER_INTERFACE_ATTRIBUTE
140353944Sdimvoid __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
141353944Sdim                                  char *out_buf, uptr out_buf_size) {
142353944Sdim  if (!out_buf_size) return;
143353944Sdim  out_buf[0] = 0;
144353944Sdim  DataInfo DI;
145353944Sdim  if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
146353944Sdim  InternalScopedString data_desc(GetPageSizeCached());
147353944Sdim  RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
148353944Sdim  internal_strncpy(out_buf, data_desc.data(), out_buf_size);
149353944Sdim  out_buf[out_buf_size - 1] = 0;
150353944Sdim}
151353944Sdim
152353944SdimSANITIZER_INTERFACE_ATTRIBUTE
153353944Sdimint __sanitizer_get_module_and_offset_for_pc(uptr pc, char *module_name,
154353944Sdim                                             uptr module_name_len,
155353944Sdim                                             uptr *pc_offset) {
156353944Sdim  return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len,
157353944Sdim                                              pc_offset);
158353944Sdim}
159353944Sdim}  // extern "C"
160