1//===-- sanitizer_symbolizer_libbacktrace.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// Libbacktrace implementation of symbolizer parts.
11//===----------------------------------------------------------------------===//
12
13#include "sanitizer_platform.h"
14
15#include "sanitizer_internal_defs.h"
16#include "sanitizer_symbolizer.h"
17#include "sanitizer_symbolizer_libbacktrace.h"
18
19#if SANITIZER_LIBBACKTRACE
20# include "backtrace-supported.h"
21# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC
22#  include "backtrace.h"
23#  if SANITIZER_CP_DEMANGLE
24#   undef ARRAY_SIZE
25#   include "demangle.h"
26#  endif
27# else
28#  define SANITIZER_LIBBACKTRACE 0
29# endif
30#endif
31
32namespace __sanitizer {
33
34#if SANITIZER_LIBBACKTRACE
35
36namespace {
37
38# if SANITIZER_CP_DEMANGLE
39struct CplusV3DemangleData {
40  char *buf;
41  uptr size, allocated;
42};
43
44extern "C" {
45static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) {
46  CplusV3DemangleData *data = (CplusV3DemangleData *)vdata;
47  uptr needed = data->size + l + 1;
48  if (needed > data->allocated) {
49    data->allocated *= 2;
50    if (needed > data->allocated)
51      data->allocated = needed;
52    char *buf = (char *)InternalAlloc(data->allocated);
53    if (data->buf) {
54      internal_memcpy(buf, data->buf, data->size);
55      InternalFree(data->buf);
56    }
57    data->buf = buf;
58  }
59  internal_memcpy(data->buf + data->size, s, l);
60  data->buf[data->size + l] = '\0';
61  data->size += l;
62}
63}  // extern "C"
64
65char *CplusV3Demangle(const char *name) {
66  CplusV3DemangleData data;
67  data.buf = 0;
68  data.size = 0;
69  data.allocated = 0;
70  if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI,
71                                 CplusV3DemangleCallback, &data)) {
72    if (data.size + 64 > data.allocated)
73      return data.buf;
74    char *buf = internal_strdup(data.buf);
75    InternalFree(data.buf);
76    return buf;
77  }
78  if (data.buf)
79    InternalFree(data.buf);
80  return 0;
81}
82# endif  // SANITIZER_CP_DEMANGLE
83
84struct SymbolizeCodeData {
85  AddressInfo *frames;
86  uptr n_frames;
87  uptr max_frames;
88  const char *module_name;
89  uptr module_offset;
90};
91
92extern "C" {
93static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr,
94                                       const char *filename, int lineno,
95                                       const char *function) {
96  SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata;
97  if (function) {
98    AddressInfo *info = &cdata->frames[cdata->n_frames++];
99    info->Clear();
100    info->FillAddressAndModuleInfo(addr, cdata->module_name,
101                                   cdata->module_offset);
102    info->function = LibbacktraceSymbolizer::Demangle(function, true);
103    if (filename)
104      info->file = internal_strdup(filename);
105    info->line = lineno;
106    if (cdata->n_frames == cdata->max_frames)
107      return 1;
108  }
109  return 0;
110}
111
112static void SymbolizeCodeCallback(void *vdata, uintptr_t addr,
113                                  const char *symname, uintptr_t, uintptr_t) {
114  SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata;
115  if (symname) {
116    AddressInfo *info = &cdata->frames[0];
117    info->Clear();
118    info->FillAddressAndModuleInfo(addr, cdata->module_name,
119                                   cdata->module_offset);
120    info->function = LibbacktraceSymbolizer::Demangle(symname, true);
121    cdata->n_frames = 1;
122  }
123}
124
125static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname,
126                                  uintptr_t symval, uintptr_t symsize) {
127  DataInfo *info = (DataInfo *)vdata;
128  if (symname && symval) {
129    info->name = LibbacktraceSymbolizer::Demangle(symname, true);
130    info->start = symval;
131    info->size = symsize;
132  }
133}
134
135static void ErrorCallback(void *, const char *, int) {}
136}  // extern "C"
137
138}  // namespace
139
140LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
141  // State created in backtrace_create_state is leaked.
142  void *state = (void *)(backtrace_create_state("/proc/self/exe", 0,
143                                                ErrorCallback, NULL));
144  if (!state)
145    return 0;
146  return new(*alloc) LibbacktraceSymbolizer(state);
147}
148
149uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames,
150                                           uptr max_frames,
151                                           const char *module_name,
152                                           uptr module_offset) {
153  SymbolizeCodeData data;
154  data.frames = frames;
155  data.n_frames = 0;
156  data.max_frames = max_frames;
157  data.module_name = module_name;
158  data.module_offset = module_offset;
159  backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback,
160                   ErrorCallback, &data);
161  if (data.n_frames)
162    return data.n_frames;
163  backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback,
164                    ErrorCallback, &data);
165  return data.n_frames;
166}
167
168bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
169  backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback,
170                    ErrorCallback, info);
171  return true;
172}
173
174#else  // SANITIZER_LIBBACKTRACE
175
176LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
177  return 0;
178}
179
180uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames,
181                                           uptr max_frames,
182                                           const char *module_name,
183                                           uptr module_offset) {
184  (void)state_;
185  return 0;
186}
187
188bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
189  return false;
190}
191
192#endif  // SANITIZER_LIBBACKTRACE
193
194char *LibbacktraceSymbolizer::Demangle(const char *name, bool always_alloc) {
195#if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE
196  if (char *demangled = CplusV3Demangle(name))
197    return demangled;
198#endif
199  if (always_alloc)
200    return internal_strdup(name);
201  return 0;
202}
203
204}  // namespace __sanitizer
205