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