1//===-- sanitizer_stacktrace_libcdep.cc -----------------------------------===//
2//
3// This file is distributed under the University of Illinois Open Source
4// License. See LICENSE.TXT for details.
5//
6//===----------------------------------------------------------------------===//
7//
8// This file is shared between AddressSanitizer and ThreadSanitizer
9// run-time libraries.
10//===----------------------------------------------------------------------===//
11
12#include "sanitizer_common.h"
13#include "sanitizer_placement_new.h"
14#include "sanitizer_stacktrace.h"
15#include "sanitizer_stacktrace_printer.h"
16#include "sanitizer_symbolizer.h"
17
18namespace __sanitizer {
19
20void StackTrace::Print() const {
21  if (trace == nullptr || size == 0) {
22    Printf("    <empty stack>\n\n");
23    return;
24  }
25  InternalScopedString frame_desc(GetPageSizeCached() * 2);
26  InternalScopedString dedup_token(GetPageSizeCached());
27  int dedup_frames = common_flags()->dedup_token_length;
28  uptr frame_num = 0;
29  for (uptr i = 0; i < size && trace[i]; i++) {
30    // PCs in stack traces are actually the return addresses, that is,
31    // addresses of the next instructions after the call.
32    uptr pc = GetPreviousInstructionPc(trace[i]);
33    SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
34    CHECK(frames);
35    for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
36      frame_desc.clear();
37      RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
38                  cur->info, common_flags()->symbolize_vs_style,
39                  common_flags()->strip_path_prefix);
40      Printf("%s\n", frame_desc.data());
41      if (dedup_frames-- > 0) {
42        if (dedup_token.length())
43          dedup_token.append("--");
44        if (cur->info.function != nullptr)
45          dedup_token.append(cur->info.function);
46      }
47    }
48    frames->ClearAll();
49  }
50  // Always print a trailing empty line after stack trace.
51  Printf("\n");
52  if (dedup_token.length())
53    Printf("DEDUP_TOKEN: %s\n", dedup_token.data());
54}
55
56void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
57                                uptr stack_top, uptr stack_bottom,
58                                bool request_fast_unwind) {
59  top_frame_bp = (max_depth > 0) ? bp : 0;
60  // Avoid doing any work for small max_depth.
61  if (max_depth == 0) {
62    size = 0;
63    return;
64  }
65  if (max_depth == 1) {
66    size = 1;
67    trace_buffer[0] = pc;
68    return;
69  }
70  if (!WillUseFastUnwind(request_fast_unwind)) {
71#if SANITIZER_CAN_SLOW_UNWIND
72    if (context)
73      SlowUnwindStackWithContext(pc, context, max_depth);
74    else
75      SlowUnwindStack(pc, max_depth);
76#else
77    UNREACHABLE("slow unwind requested but not available");
78#endif
79  } else {
80    FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
81  }
82}
83
84static int GetModuleAndOffsetForPc(uptr pc, char *module_name,
85                                   uptr module_name_len, uptr *pc_offset) {
86  const char *found_module_name = nullptr;
87  bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(
88      pc, &found_module_name, pc_offset);
89
90  if (!ok) return false;
91
92  if (module_name && module_name_len) {
93    internal_strncpy(module_name, found_module_name, module_name_len);
94    module_name[module_name_len - 1] = '\x00';
95  }
96  return true;
97}
98
99}  // namespace __sanitizer
100using namespace __sanitizer;
101
102extern "C" {
103SANITIZER_INTERFACE_ATTRIBUTE
104void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
105                              uptr out_buf_size) {
106  if (!out_buf_size) return;
107  pc = StackTrace::GetPreviousInstructionPc(pc);
108  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
109  if (!frame) {
110    internal_strncpy(out_buf, "<can't symbolize>", out_buf_size);
111    out_buf[out_buf_size - 1] = 0;
112    return;
113  }
114  InternalScopedString frame_desc(GetPageSizeCached());
115  uptr frame_num = 0;
116  // Reserve one byte for the final 0.
117  char *out_end = out_buf + out_buf_size - 1;
118  for (SymbolizedStack *cur = frame; cur && out_buf < out_end;
119       cur = cur->next) {
120    frame_desc.clear();
121    RenderFrame(&frame_desc, fmt, frame_num++, cur->info,
122                common_flags()->symbolize_vs_style,
123                common_flags()->strip_path_prefix);
124    if (!frame_desc.length())
125      continue;
126    // Reserve one byte for the terminating 0.
127    uptr n = out_end - out_buf - 1;
128    internal_strncpy(out_buf, frame_desc.data(), n);
129    out_buf += __sanitizer::Min<uptr>(n, frame_desc.length());
130    *out_buf++ = 0;
131  }
132  CHECK(out_buf <= out_end);
133  *out_buf = 0;
134}
135
136SANITIZER_INTERFACE_ATTRIBUTE
137void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
138                                  char *out_buf, uptr out_buf_size) {
139  if (!out_buf_size) return;
140  out_buf[0] = 0;
141  DataInfo DI;
142  if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
143  InternalScopedString data_desc(GetPageSizeCached());
144  RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
145  internal_strncpy(out_buf, data_desc.data(), out_buf_size);
146  out_buf[out_buf_size - 1] = 0;
147}
148
149SANITIZER_INTERFACE_ATTRIBUTE
150int __sanitizer_get_module_and_offset_for_pc( // NOLINT
151    uptr pc, char *module_name, uptr module_name_len, uptr *pc_offset) {
152  return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len,
153                                              pc_offset);
154}
155}  // extern "C"
156