1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // N.B. The offline symbolizer (scripts/symbolize) reads our output,
6 // don't break it.
7
8 #include <inttypes.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <backtrace/backtrace.h>
15
16 #include <ngunwind/libunwind.h>
17 #include <ngunwind/fuchsia.h>
18
19 #include <zircon/types.h>
20 #include <zircon/syscalls.h>
21 #include <zircon/syscalls/object.h>
22
23 #include <fbl/alloc_checker.h>
24 #include <fbl/array.h>
25
26 #include "inspector/inspector.h"
27 #include "dso-list-impl.h"
28 #include "utils-impl.h"
29
30 namespace inspector {
31
32 // Keep open debug info for this many files.
33 constexpr size_t kDebugInfoCacheNumWays = 2;
34
35 constexpr unsigned int kBacktraceFrameLimit = 50;
36
37 // Error callback for libbacktrace.
38
39 static void
bt_error_callback(void * vdata,const char * msg,int errnum)40 bt_error_callback(void* vdata, const char* msg, int errnum) {
41 fprintf(stderr, "%s", msg);
42 if (errnum > 0)
43 fprintf(stderr, ": %s", strerror (errnum));
44 fprintf(stderr, "\n");
45 }
46
47 // backtrace_so_iterator function.
48 // We don't use libbacktrace to do the unwinding, we only use it to get
49 // file,line#,function_name for each pc. Therefore we don't need it to
50 // iterate over all shared libs.
51
52 static int
bt_so_iterator(void * iter_state,backtrace_so_callback * callback,void * data)53 bt_so_iterator (void* iter_state, backtrace_so_callback* callback, void* data) {
54 // Return non-zero so iteration stops.
55 return 1;
56 }
57
58 // A cache of data stored for each shared lib.
59 // This lets us lazily obtain debug info, and only keep
60 // a subset of it in memory.
61 class DebugInfoCache {
62 public:
63 DebugInfoCache(inspector_dsoinfo_t* dso_list, size_t nr_ways);
64 ~DebugInfoCache();
65
dso_list()66 inspector_dsoinfo_t* dso_list() { return dso_list_; }
67
68 zx_status_t GetDebugInfo(uintptr_t pc, inspector_dsoinfo_t** out_dso,
69 backtrace_state** out_bt_state);
70
71 private:
72 inspector_dsoinfo_t* dso_list_;
73
74 size_t last_used_ = 0;
75
76 bool cache_avail_ = false;
77
78 struct way {
79 // Not owned by us. This is the "tag".
80 inspector_dsoinfo_t* dso = nullptr;
81 // Owned by us.
82 backtrace_state* bt_state = nullptr;
83 };
84
85 fbl::Array<way> ways_;
86 };
87
88 // Note: We *do not* take ownership of |dso_list|.
89 // Its lifetime must survive ours.
90
DebugInfoCache(inspector_dsoinfo_t * dso_list,size_t nr_ways)91 DebugInfoCache::DebugInfoCache(inspector_dsoinfo_t* dso_list, size_t nr_ways)
92 : dso_list_(dso_list) {
93 fbl::AllocChecker ac;
94 auto ways = new (&ac) way[nr_ways];
95 if (!ac.check()) {
96 debugf(1, "unable to initialize debug info cache\n");
97 return;
98 }
99 ways_.reset(ways, nr_ways);
100 cache_avail_ = true;
101 }
102
~DebugInfoCache()103 DebugInfoCache::~DebugInfoCache() {
104 if (cache_avail_) {
105 for (size_t i = 0; i < ways_.size(); ++i) {
106 backtrace_destroy_state(ways_[i].bt_state, bt_error_callback, nullptr);
107 }
108 }
109 }
110
111 // Find the DSO and debug info (backtrace_state) for PC.
112 // Returns ZX_ERR_NOT_FOUND if |pc| is not in any DSO.
113 // Otherwise the result is ZX_OK, even if there is no extended debug
114 // info for libbacktrace (e.g., -g1 info).
115 // If the result is ZX_OK then |*out_dso| is set.
116 // If the result is ZX_OK then |*out_bt_state| is set to the
117 // accompanying libbacktrace state if available or nullptr if not.
118
GetDebugInfo(uintptr_t pc,inspector_dsoinfo_t ** out_dso,backtrace_state ** out_bt_state)119 zx_status_t DebugInfoCache::GetDebugInfo(uintptr_t pc,
120 inspector_dsoinfo_t** out_dso,
121 backtrace_state** out_bt_state) {
122 inspector_dsoinfo_t* dso = inspector_dso_lookup(dso_list_, pc);
123 if (dso == nullptr) {
124 debugf(1, "No DSO found for pc %p\n", (void*) pc);
125 return ZX_ERR_NOT_FOUND;
126 }
127
128 #if 1 // Skip using libbacktrace until leaks are fixed. ZX-351
129 *out_dso = dso;
130 *out_bt_state = nullptr;
131 return ZX_OK;
132 #endif
133
134 // If we failed to initialize the cache (OOM) we can still report the
135 // DSO we found.
136 if (!cache_avail_) {
137 *out_dso = dso;
138 *out_bt_state = nullptr;
139 return ZX_OK;
140 }
141
142 const size_t nr_ways = ways_.size();
143
144 for (size_t i = 0; i < nr_ways; ++i) {
145 if (ways_[i].dso == dso) {
146 debugf(1, "using cached debug info entry for pc %p\n", (void*) pc);
147 *out_dso = dso;
148 *out_bt_state = ways_[i].bt_state;
149 return ZX_OK;
150 }
151 }
152
153 // PC is in a DSO, but not found in the cache.
154 // N.B. From this point on the result is ZX_OK.
155 // If there is an "error" the user can still print something (and there's
156 // no point in having error messages pollute the backtrace, at least by
157 // default).
158
159 *out_dso = dso;
160 *out_bt_state = nullptr;
161
162 const char* debug_file = nullptr;
163 auto status = inspector_dso_find_debug_file(dso, &debug_file);
164 if (status != ZX_OK) {
165 // There's no additional debug file available, but we did find the DSO.
166 return ZX_OK;
167 }
168
169 struct backtrace_state* bt_state =
170 backtrace_create_state(debug_file, 0 /*!threaded*/,
171 bt_error_callback, nullptr);
172 if (bt_state == nullptr) {
173 debugf(1, "backtrace_create_state failed (OOM)\n");
174 return ZX_OK;
175 }
176
177 // last_used_+1: KISS until there's data warranting something better
178 size_t way = (last_used_ + 1) % nr_ways;
179 if (ways_[way].dso != nullptr) {
180 // Free the entry.
181 backtrace_destroy_state(ways_[way].bt_state, bt_error_callback, nullptr);
182 ways_[way].dso = nullptr;
183 ways_[way].bt_state = nullptr;
184 }
185
186 // The iterator doesn't do anything, but we pass |list| anyway
187 // in case some day we need it to.
188 backtrace_set_so_iterator(bt_state, bt_so_iterator, dso_list_);
189 backtrace_set_base_address(bt_state, dso->base);
190
191 ways_[way].dso = dso;
192 ways_[way].bt_state = bt_state;
193 *out_bt_state = bt_state;
194 last_used_ = way;
195 return ZX_OK;
196 }
197
198 // Data to pass back from backtrace_pcinfo.
199 // We don't use libbacktrace to print the backtrace, we only use it to
200 // obtain file,line#,function_name.
201
202 struct bt_pcinfo_data
203 {
204 const char* filename;
205 int lineno;
206 const char* function;
207 };
208
209 // Callback invoked by libbacktrace.
210
211 static int
btprint_callback(void * vdata,uintptr_t pc,const char * filename,int lineno,const char * function)212 btprint_callback(void* vdata, uintptr_t pc, const char* filename, int lineno,
213 const char* function) {
214 auto data = reinterpret_cast<bt_pcinfo_data*> (vdata);
215
216 data->filename = filename;
217 data->lineno = lineno;
218 data->function = function;
219
220 return 0;
221 }
222
btprint(FILE * f,DebugInfoCache * di_cache,uint32_t n,uintptr_t pc,uintptr_t sp,bool use_new_format)223 static void btprint(FILE* f, DebugInfoCache* di_cache,
224 uint32_t n, uintptr_t pc, uintptr_t sp,
225 bool use_new_format) {
226 if (use_new_format) {
227 fprintf(f, "{{{bt:%u:%#" PRIxPTR "}}}\n", n, pc);
228 return;
229 }
230
231 inspector_dsoinfo_t* dso;
232 backtrace_state* bt_state;
233 auto status = di_cache->GetDebugInfo(pc, &dso, &bt_state);
234
235 if (status != ZX_OK) {
236 // The pc is not in any DSO.
237 fprintf(f, "bt#%02u: pc %p sp %p\n",
238 n, (void*) pc, (void*) sp);
239 return;
240 }
241
242 // Try to use libbacktrace if we can.
243
244 struct bt_pcinfo_data pcinfo_data;
245 memset(&pcinfo_data, 0, sizeof(pcinfo_data));
246
247 if (bt_state != nullptr) {
248 auto ret = backtrace_pcinfo(bt_state, pc, btprint_callback,
249 bt_error_callback, &pcinfo_data);
250 if (ret == 0) {
251 // FIXME: How to interpret the result is seriously confusing.
252 // There are cases where zero means failure and others where
253 // zero means success. For now we just assume that pcinfo_data
254 // will only be filled in on success.
255 }
256 }
257
258 fprintf(f, "bt#%02u: pc %p sp %p (%s,%p)",
259 n, (void*) pc, (void*) sp, dso->name, (void*) (pc - dso->base));
260 if (pcinfo_data.filename != nullptr && pcinfo_data.lineno > 0) {
261 const char* base = path_basename(pcinfo_data.filename);
262 // Be paranoid and handle |pcinfo_data.filename| having a trailing /.
263 // If so, just print the whole thing and let the user figure it out.
264 if (*base == '\0')
265 base = pcinfo_data.filename;
266 fprintf(f, " %s:%d", base, pcinfo_data.lineno);
267 }
268 if (pcinfo_data.function != nullptr)
269 fprintf(f, " %s", pcinfo_data.function);
270 fprintf(f, "\n");
271 }
272
dso_lookup_for_unw(void * context,unw_word_t pc,unw_word_t * base,const char ** name)273 static int dso_lookup_for_unw(void* context, unw_word_t pc,
274 unw_word_t* base, const char** name) {
275 auto dso_list = reinterpret_cast<inspector_dsoinfo_t*>(context);
276 inspector_dsoinfo_t* dso = inspector_dso_lookup(dso_list, pc);
277 if (dso == nullptr)
278 return 0;
279 *base = dso->base;
280 *name = dso->name;
281 return 1;
282 }
283
284 static
inspector_print_backtrace_impl(FILE * f,zx_handle_t process,zx_handle_t thread,inspector_dsoinfo_t * dso_list,uintptr_t pc,uintptr_t sp,uintptr_t fp,bool use_libunwind,bool use_new_format)285 void inspector_print_backtrace_impl(FILE* f,
286 zx_handle_t process, zx_handle_t thread,
287 inspector_dsoinfo_t* dso_list,
288 uintptr_t pc, uintptr_t sp, uintptr_t fp,
289 bool use_libunwind,
290 bool use_new_format) {
291 // Set up libunwind if requested.
292
293 bool libunwind_ok = use_libunwind;
294 if (verbosity_level > 0) {
295 // Don't turn on libunwind debugging for -d1.
296 // Note: max libunwind debugging level is 16
297 unw_set_debug_level(verbosity_level - 1);
298 }
299
300 unw_fuchsia_info_t* fuchsia = nullptr;
301 unw_addr_space_t remote_as = nullptr;
302
303 if (libunwind_ok) {
304 fuchsia = unw_create_fuchsia(process, thread, dso_list, dso_lookup_for_unw);
305 if (fuchsia == nullptr)
306 {
307 print_error("unw_fuchsia_create failed (OOM)");
308 libunwind_ok = false;
309 }
310 }
311
312 if (libunwind_ok) {
313 remote_as =
314 unw_create_addr_space((unw_accessors_t*) &_UFuchsia_accessors, 0);
315 if (remote_as == nullptr)
316 {
317 print_error("unw_create_addr_space failed (OOM)");
318 libunwind_ok = false;
319 }
320 }
321
322 unw_cursor_t cursor;
323 if (libunwind_ok) {
324 int ret = unw_init_remote(&cursor, remote_as, fuchsia);
325 if (ret < 0) {
326 print_error("unw_init_remote failed (%d)", ret);
327 libunwind_ok = false;
328 }
329 }
330
331 if (!libunwind_ok) {
332 print_error("Unable to initialize libunwind.");
333 print_error("Falling back on heuristics which likely won't work");
334 print_error("with optimized code.");
335 }
336
337 // TODO: Handle libunwind not finding .eh_frame in which case fallback
338 // on using heuristics. Ideally this would be handled on a per-DSO basis.
339
340 // Keep a cache of loaded debug info to maintain some performance
341 // without loading debug info for all shared libs.
342 // This won't get used if initializing libunwind failed, but we can still
343 // use |dso_list|.
344 DebugInfoCache di_cache(dso_list, kDebugInfoCacheNumWays);
345
346 // On with the show.
347
348 uint32_t n = 1;
349 btprint(f, &di_cache, n++, pc, sp, use_new_format);
350 while ((sp >= 0x1000000) && (n < kBacktraceFrameLimit)) {
351 if (libunwind_ok) {
352 int ret = unw_step(&cursor);
353 if (ret < 0) {
354 print_error("unw_step failed for pc %p, aborting backtrace here",
355 (void*) pc);
356 break;
357 }
358 if (ret == 0)
359 break;
360 unw_word_t val;
361 unw_get_reg(&cursor, UNW_REG_IP, &val);
362 pc = val;
363 unw_get_reg(&cursor, UNW_REG_SP, &val);
364 sp = val;
365 } else {
366 sp = fp;
367 if (read_mem(process, fp + 8, &pc, sizeof(pc))) {
368 break;
369 }
370 if (read_mem(process, fp, &fp, sizeof(fp))) {
371 break;
372 }
373 }
374 btprint(f, &di_cache, n++, pc, sp, use_new_format);
375 }
376
377 if (!use_new_format) {
378 fprintf(f, "bt#%02d: end\n", n);
379 }
380
381 if (n >= kBacktraceFrameLimit) {
382 fprintf(f, "warning: backtrace frame limit exceeded; backtrace may be truncated\n");
383 }
384
385 unw_destroy_addr_space(remote_as);
386 unw_destroy_fuchsia(fuchsia);
387 }
388
389 extern "C"
inspector_print_backtrace_markup(FILE * f,zx_handle_t process,zx_handle_t thread,inspector_dsoinfo_t * dso_list,uintptr_t pc,uintptr_t sp,uintptr_t fp,bool use_libunwind)390 void inspector_print_backtrace_markup(FILE* f,
391 zx_handle_t process, zx_handle_t thread,
392 inspector_dsoinfo_t* dso_list,
393 uintptr_t pc, uintptr_t sp, uintptr_t fp,
394 bool use_libunwind) {
395 inspector_print_backtrace_impl(f, process, thread, dso_list, pc, sp, fp,
396 use_libunwind, true);
397 }
398
399 extern "C"
inspector_print_backtrace(FILE * f,zx_handle_t process,zx_handle_t thread,inspector_dsoinfo_t * dso_list,uintptr_t pc,uintptr_t sp,uintptr_t fp,bool use_libunwind)400 void inspector_print_backtrace(FILE* f,
401 zx_handle_t process, zx_handle_t thread,
402 inspector_dsoinfo_t* dso_list,
403 uintptr_t pc, uintptr_t sp, uintptr_t fp,
404 bool use_libunwind) {
405 inspector_print_backtrace_impl(f, process, thread, dso_list, pc, sp, fp,
406 use_libunwind, false);
407 }
408
409 } // namespace inspector
410