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