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