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