1 //===-- msan.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 a part of MemorySanitizer. 11 // 12 // MemorySanitizer runtime. 13 //===----------------------------------------------------------------------===// 14 15 #include "msan.h" 16 #include "msan_chained_origin_depot.h" 17 #include "msan_origin.h" 18 #include "msan_thread.h" 19 #include "msan_poisoning.h" 20 #include "sanitizer_common/sanitizer_atomic.h" 21 #include "sanitizer_common/sanitizer_common.h" 22 #include "sanitizer_common/sanitizer_flags.h" 23 #include "sanitizer_common/sanitizer_flag_parser.h" 24 #include "sanitizer_common/sanitizer_libc.h" 25 #include "sanitizer_common/sanitizer_procmaps.h" 26 #include "sanitizer_common/sanitizer_stacktrace.h" 27 #include "sanitizer_common/sanitizer_symbolizer.h" 28 #include "sanitizer_common/sanitizer_stackdepot.h" 29 30 // ACHTUNG! No system header includes in this file. 31 32 using namespace __sanitizer; 33 34 // Globals. 35 static THREADLOCAL int msan_expect_umr = 0; 36 static THREADLOCAL int msan_expected_umr_found = 0; 37 38 // Function argument shadow. Each argument starts at the next available 8-byte 39 // aligned address. 40 SANITIZER_INTERFACE_ATTRIBUTE 41 THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)]; 42 43 // Function argument origin. Each argument starts at the same offset as the 44 // corresponding shadow in (__msan_param_tls). Slightly weird, but changing this 45 // would break compatibility with older prebuilt binaries. 46 SANITIZER_INTERFACE_ATTRIBUTE 47 THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)]; 48 49 SANITIZER_INTERFACE_ATTRIBUTE 50 THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)]; 51 52 SANITIZER_INTERFACE_ATTRIBUTE 53 THREADLOCAL u32 __msan_retval_origin_tls; 54 55 SANITIZER_INTERFACE_ATTRIBUTE 56 THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)]; 57 58 SANITIZER_INTERFACE_ATTRIBUTE 59 THREADLOCAL u64 __msan_va_arg_overflow_size_tls; 60 61 SANITIZER_INTERFACE_ATTRIBUTE 62 THREADLOCAL u32 __msan_origin_tls; 63 64 static THREADLOCAL int is_in_symbolizer; 65 66 extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins; 67 68 int __msan_get_track_origins() { 69 return &__msan_track_origins ? __msan_track_origins : 0; 70 } 71 72 extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_keep_going; 73 74 namespace __msan { 75 76 void EnterSymbolizer() { ++is_in_symbolizer; } 77 void ExitSymbolizer() { --is_in_symbolizer; } 78 bool IsInSymbolizer() { return is_in_symbolizer; } 79 80 static Flags msan_flags; 81 82 Flags *flags() { 83 return &msan_flags; 84 } 85 86 int msan_inited = 0; 87 bool msan_init_is_running; 88 89 int msan_report_count = 0; 90 91 void (*death_callback)(void); 92 93 // Array of stack origins. 94 // FIXME: make it resizable. 95 static const uptr kNumStackOriginDescrs = 1024 * 1024; 96 static const char *StackOriginDescr[kNumStackOriginDescrs]; 97 static uptr StackOriginPC[kNumStackOriginDescrs]; 98 static atomic_uint32_t NumStackOriginDescrs; 99 100 void Flags::SetDefaults() { 101 #define MSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; 102 #include "msan_flags.inc" 103 #undef MSAN_FLAG 104 } 105 106 // keep_going is an old name for halt_on_error, 107 // and it has inverse meaning. 108 class FlagHandlerKeepGoing : public FlagHandlerBase { 109 bool *halt_on_error_; 110 111 public: 112 explicit FlagHandlerKeepGoing(bool *halt_on_error) 113 : halt_on_error_(halt_on_error) {} 114 bool Parse(const char *value) final { 115 bool tmp; 116 FlagHandler<bool> h(&tmp); 117 if (!h.Parse(value)) return false; 118 *halt_on_error_ = !tmp; 119 return true; 120 } 121 }; 122 123 static void RegisterMsanFlags(FlagParser *parser, Flags *f) { 124 #define MSAN_FLAG(Type, Name, DefaultValue, Description) \ 125 RegisterFlag(parser, #Name, Description, &f->Name); 126 #include "msan_flags.inc" 127 #undef MSAN_FLAG 128 129 FlagHandlerKeepGoing *fh_keep_going = new (FlagParser::Alloc) // NOLINT 130 FlagHandlerKeepGoing(&f->halt_on_error); 131 parser->RegisterHandler("keep_going", fh_keep_going, 132 "deprecated, use halt_on_error"); 133 } 134 135 static void InitializeFlags() { 136 Flags *f = flags(); 137 FlagParser parser; 138 RegisterMsanFlags(&parser, f); 139 RegisterCommonFlags(&parser); 140 141 SetCommonFlagsDefaults(); 142 { 143 CommonFlags cf; 144 cf.CopyFrom(*common_flags()); 145 cf.external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH"); 146 cf.malloc_context_size = 20; 147 cf.handle_ioctl = true; 148 // FIXME: test and enable. 149 cf.check_printf = false; 150 cf.intercept_tls_get_addr = true; 151 OverrideCommonFlags(cf); 152 } 153 154 f->SetDefaults(); 155 156 // Override from user-specified string. 157 if (__msan_default_options) 158 parser.ParseString(__msan_default_options()); 159 160 const char *msan_options = GetEnv("MSAN_OPTIONS"); 161 parser.ParseString(msan_options); 162 VPrintf(1, "MSAN_OPTIONS: %s\n", msan_options ? msan_options : "<empty>"); 163 164 SetVerbosity(common_flags()->verbosity); 165 166 if (Verbosity()) ReportUnrecognizedFlags(); 167 168 if (common_flags()->help) parser.PrintFlagDescriptions(); 169 170 // Check flag values: 171 if (f->exit_code < 0 || f->exit_code > 127) { 172 Printf("Exit code not in [0, 128) range: %d\n", f->exit_code); 173 Die(); 174 } 175 if (f->origin_history_size < 0 || 176 f->origin_history_size > Origin::kMaxDepth) { 177 Printf( 178 "Origin history size invalid: %d. Must be 0 (unlimited) or in [1, %d] " 179 "range.\n", 180 f->origin_history_size, Origin::kMaxDepth); 181 Die(); 182 } 183 // Limiting to kStackDepotMaxUseCount / 2 to avoid overflow in 184 // StackDepotHandle::inc_use_count_unsafe. 185 if (f->origin_history_per_stack_limit < 0 || 186 f->origin_history_per_stack_limit > kStackDepotMaxUseCount / 2) { 187 Printf( 188 "Origin per-stack limit invalid: %d. Must be 0 (unlimited) or in [1, " 189 "%d] range.\n", 190 f->origin_history_per_stack_limit, kStackDepotMaxUseCount / 2); 191 Die(); 192 } 193 if (f->store_context_size < 1) f->store_context_size = 1; 194 } 195 196 void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp, 197 bool request_fast_unwind) { 198 MsanThread *t = GetCurrentThread(); 199 if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) { 200 // Block reports from our interceptors during _Unwind_Backtrace. 201 SymbolizerScope sym_scope; 202 return stack->Unwind(max_s, pc, bp, 0, 0, 0, request_fast_unwind); 203 } 204 stack->Unwind(max_s, pc, bp, 0, t->stack_top(), t->stack_bottom(), 205 request_fast_unwind); 206 } 207 208 void PrintWarning(uptr pc, uptr bp) { 209 PrintWarningWithOrigin(pc, bp, __msan_origin_tls); 210 } 211 212 void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) { 213 if (msan_expect_umr) { 214 // Printf("Expected UMR\n"); 215 __msan_origin_tls = origin; 216 msan_expected_umr_found = 1; 217 return; 218 } 219 220 ++msan_report_count; 221 222 GET_FATAL_STACK_TRACE_PC_BP(pc, bp); 223 224 u32 report_origin = 225 (__msan_get_track_origins() && Origin::isValidId(origin)) ? origin : 0; 226 ReportUMR(&stack, report_origin); 227 228 if (__msan_get_track_origins() && !Origin::isValidId(origin)) { 229 Printf( 230 " ORIGIN: invalid (%x). Might be a bug in MemorySanitizer origin " 231 "tracking.\n This could still be a bug in your code, too!\n", 232 origin); 233 } 234 } 235 236 void UnpoisonParam(uptr n) { 237 internal_memset(__msan_param_tls, 0, n * sizeof(*__msan_param_tls)); 238 } 239 240 // Backup MSan runtime TLS state. 241 // Implementation must be async-signal-safe. 242 // Instances of this class may live on the signal handler stack, and data size 243 // may be an issue. 244 void ScopedThreadLocalStateBackup::Backup() { 245 va_arg_overflow_size_tls = __msan_va_arg_overflow_size_tls; 246 } 247 248 void ScopedThreadLocalStateBackup::Restore() { 249 // A lame implementation that only keeps essential state and resets the rest. 250 __msan_va_arg_overflow_size_tls = va_arg_overflow_size_tls; 251 252 internal_memset(__msan_param_tls, 0, sizeof(__msan_param_tls)); 253 internal_memset(__msan_retval_tls, 0, sizeof(__msan_retval_tls)); 254 internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls)); 255 256 if (__msan_get_track_origins()) { 257 internal_memset(&__msan_retval_origin_tls, 0, 258 sizeof(__msan_retval_origin_tls)); 259 internal_memset(__msan_param_origin_tls, 0, 260 sizeof(__msan_param_origin_tls)); 261 } 262 } 263 264 void UnpoisonThreadLocalState() { 265 } 266 267 const char *GetStackOriginDescr(u32 id, uptr *pc) { 268 CHECK_LT(id, kNumStackOriginDescrs); 269 if (pc) *pc = StackOriginPC[id]; 270 return StackOriginDescr[id]; 271 } 272 273 u32 ChainOrigin(u32 id, StackTrace *stack) { 274 MsanThread *t = GetCurrentThread(); 275 if (t && t->InSignalHandler()) 276 return id; 277 278 Origin o = Origin::FromRawId(id); 279 stack->tag = StackTrace::TAG_UNKNOWN; 280 Origin chained = Origin::CreateChainedOrigin(o, stack); 281 return chained.raw_id(); 282 } 283 284 } // namespace __msan 285 286 // Interface. 287 288 using namespace __msan; 289 290 #define MSAN_MAYBE_WARNING(type, size) \ 291 void __msan_maybe_warning_##size(type s, u32 o) { \ 292 GET_CALLER_PC_BP_SP; \ 293 (void) sp; \ 294 if (UNLIKELY(s)) { \ 295 PrintWarningWithOrigin(pc, bp, o); \ 296 if (__msan::flags()->halt_on_error) { \ 297 Printf("Exiting\n"); \ 298 Die(); \ 299 } \ 300 } \ 301 } 302 303 MSAN_MAYBE_WARNING(u8, 1) 304 MSAN_MAYBE_WARNING(u16, 2) 305 MSAN_MAYBE_WARNING(u32, 4) 306 MSAN_MAYBE_WARNING(u64, 8) 307 308 #define MSAN_MAYBE_STORE_ORIGIN(type, size) \ 309 void __msan_maybe_store_origin_##size(type s, void *p, u32 o) { \ 310 if (UNLIKELY(s)) { \ 311 if (__msan_get_track_origins() > 1) { \ 312 GET_CALLER_PC_BP_SP; \ 313 (void) sp; \ 314 GET_STORE_STACK_TRACE_PC_BP(pc, bp); \ 315 o = ChainOrigin(o, &stack); \ 316 } \ 317 *(u32 *)MEM_TO_ORIGIN((uptr)p & ~3UL) = o; \ 318 } \ 319 } 320 321 MSAN_MAYBE_STORE_ORIGIN(u8, 1) 322 MSAN_MAYBE_STORE_ORIGIN(u16, 2) 323 MSAN_MAYBE_STORE_ORIGIN(u32, 4) 324 MSAN_MAYBE_STORE_ORIGIN(u64, 8) 325 326 void __msan_warning() { 327 GET_CALLER_PC_BP_SP; 328 (void)sp; 329 PrintWarning(pc, bp); 330 if (__msan::flags()->halt_on_error) { 331 if (__msan::flags()->print_stats) 332 ReportStats(); 333 Printf("Exiting\n"); 334 Die(); 335 } 336 } 337 338 void __msan_warning_noreturn() { 339 GET_CALLER_PC_BP_SP; 340 (void)sp; 341 PrintWarning(pc, bp); 342 if (__msan::flags()->print_stats) 343 ReportStats(); 344 Printf("Exiting\n"); 345 Die(); 346 } 347 348 void __msan_init() { 349 CHECK(!msan_init_is_running); 350 if (msan_inited) return; 351 msan_init_is_running = 1; 352 SanitizerToolName = "MemorySanitizer"; 353 354 SetDieCallback(MsanDie); 355 InitTlsSize(); 356 357 InitializeFlags(); 358 __sanitizer_set_report_path(common_flags()->log_path); 359 360 InitializeInterceptors(); 361 InstallAtExitHandler(); // Needs __cxa_atexit interceptor. 362 363 if (MSAN_REPLACE_OPERATORS_NEW_AND_DELETE) 364 ReplaceOperatorsNewAndDelete(); 365 DisableCoreDumperIfNecessary(); 366 if (StackSizeIsUnlimited()) { 367 VPrintf(1, "Unlimited stack, doing reexec\n"); 368 // A reasonably large stack size. It is bigger than the usual 8Mb, because, 369 // well, the program could have been run with unlimited stack for a reason. 370 SetStackSizeLimitInBytes(32 * 1024 * 1024); 371 ReExec(); 372 } 373 374 __msan_clear_on_return(); 375 if (__msan_get_track_origins()) 376 VPrintf(1, "msan_track_origins\n"); 377 if (!InitShadow(/* map_shadow */ true, __msan_get_track_origins())) { 378 Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n"); 379 Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n"); 380 Printf("FATAL: Disabling ASLR is known to cause this error.\n"); 381 Printf("FATAL: If running under GDB, try " 382 "'set disable-randomization off'.\n"); 383 DumpProcessMap(); 384 Die(); 385 } 386 387 Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer); 388 389 InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); 390 391 MsanTSDInit(MsanTSDDtor); 392 393 MsanThread *main_thread = MsanThread::Create(0, 0); 394 SetCurrentThread(main_thread); 395 main_thread->ThreadStart(); 396 397 VPrintf(1, "MemorySanitizer init done\n"); 398 399 msan_init_is_running = 0; 400 msan_inited = 1; 401 } 402 403 void __msan_set_exit_code(int exit_code) { 404 flags()->exit_code = exit_code; 405 } 406 407 void __msan_set_keep_going(int keep_going) { 408 flags()->halt_on_error = !keep_going; 409 } 410 411 void __msan_set_expect_umr(int expect_umr) { 412 if (expect_umr) { 413 msan_expected_umr_found = 0; 414 } else if (!msan_expected_umr_found) { 415 GET_CALLER_PC_BP_SP; 416 (void)sp; 417 GET_FATAL_STACK_TRACE_PC_BP(pc, bp); 418 ReportExpectedUMRNotFound(&stack); 419 Die(); 420 } 421 msan_expect_umr = expect_umr; 422 } 423 424 void __msan_print_shadow(const void *x, uptr size) { 425 if (!MEM_IS_APP(x)) { 426 Printf("Not a valid application address: %p\n", x); 427 return; 428 } 429 430 DescribeMemoryRange(x, size); 431 } 432 433 void __msan_dump_shadow(const void *x, uptr size) { 434 if (!MEM_IS_APP(x)) { 435 Printf("Not a valid application address: %p\n", x); 436 return; 437 } 438 439 unsigned char *s = (unsigned char*)MEM_TO_SHADOW(x); 440 for (uptr i = 0; i < size; i++) { 441 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 442 Printf("%x%x ", s[i] & 0xf, s[i] >> 4); 443 #else 444 Printf("%x%x ", s[i] >> 4, s[i] & 0xf); 445 #endif 446 } 447 Printf("\n"); 448 } 449 450 sptr __msan_test_shadow(const void *x, uptr size) { 451 if (!MEM_IS_APP(x)) return -1; 452 unsigned char *s = (unsigned char *)MEM_TO_SHADOW((uptr)x); 453 for (uptr i = 0; i < size; ++i) 454 if (s[i]) 455 return i; 456 return -1; 457 } 458 459 void __msan_check_mem_is_initialized(const void *x, uptr size) { 460 if (!__msan::flags()->report_umrs) return; 461 sptr offset = __msan_test_shadow(x, size); 462 if (offset < 0) 463 return; 464 465 GET_CALLER_PC_BP_SP; 466 (void)sp; 467 ReportUMRInsideAddressRange(__func__, x, size, offset); 468 __msan::PrintWarningWithOrigin(pc, bp, 469 __msan_get_origin(((const char *)x) + offset)); 470 if (__msan::flags()->halt_on_error) { 471 Printf("Exiting\n"); 472 Die(); 473 } 474 } 475 476 int __msan_set_poison_in_malloc(int do_poison) { 477 int old = flags()->poison_in_malloc; 478 flags()->poison_in_malloc = do_poison; 479 return old; 480 } 481 482 int __msan_has_dynamic_component() { return false; } 483 484 NOINLINE 485 void __msan_clear_on_return() { 486 __msan_param_tls[0] = 0; 487 } 488 489 void __msan_partial_poison(const void* data, void* shadow, uptr size) { 490 internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size); 491 } 492 493 void __msan_load_unpoisoned(void *src, uptr size, void *dst) { 494 internal_memcpy(dst, src, size); 495 __msan_unpoison(dst, size); 496 } 497 498 void __msan_set_origin(const void *a, uptr size, u32 origin) { 499 if (__msan_get_track_origins()) SetOrigin(a, size, origin); 500 } 501 502 // 'descr' is created at compile time and contains '----' in the beginning. 503 // When we see descr for the first time we replace '----' with a uniq id 504 // and set the origin to (id | (31-th bit)). 505 void __msan_set_alloca_origin(void *a, uptr size, char *descr) { 506 __msan_set_alloca_origin4(a, size, descr, 0); 507 } 508 509 void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc) { 510 static const u32 dash = '-'; 511 static const u32 first_timer = 512 dash + (dash << 8) + (dash << 16) + (dash << 24); 513 u32 *id_ptr = (u32*)descr; 514 bool print = false; // internal_strstr(descr + 4, "AllocaTOTest") != 0; 515 u32 id = *id_ptr; 516 if (id == first_timer) { 517 u32 idx = atomic_fetch_add(&NumStackOriginDescrs, 1, memory_order_relaxed); 518 CHECK_LT(idx, kNumStackOriginDescrs); 519 StackOriginDescr[idx] = descr + 4; 520 StackOriginPC[idx] = pc; 521 id = Origin::CreateStackOrigin(idx).raw_id(); 522 *id_ptr = id; 523 if (print) 524 Printf("First time: idx=%d id=%d %s %p \n", idx, id, descr + 4, pc); 525 } 526 if (print) 527 Printf("__msan_set_alloca_origin: descr=%s id=%x\n", descr + 4, id); 528 __msan_set_origin(a, size, id); 529 } 530 531 u32 __msan_chain_origin(u32 id) { 532 GET_CALLER_PC_BP_SP; 533 (void)sp; 534 GET_STORE_STACK_TRACE_PC_BP(pc, bp); 535 return ChainOrigin(id, &stack); 536 } 537 538 u32 __msan_get_origin(const void *a) { 539 if (!__msan_get_track_origins()) return 0; 540 uptr x = (uptr)a; 541 uptr aligned = x & ~3ULL; 542 uptr origin_ptr = MEM_TO_ORIGIN(aligned); 543 return *(u32*)origin_ptr; 544 } 545 546 int __msan_origin_is_descendant_or_same(u32 this_id, u32 prev_id) { 547 Origin o = Origin::FromRawId(this_id); 548 while (o.raw_id() != prev_id && o.isChainedOrigin()) 549 o = o.getNextChainedOrigin(nullptr); 550 return o.raw_id() == prev_id; 551 } 552 553 u32 __msan_get_umr_origin() { 554 return __msan_origin_tls; 555 } 556 557 u16 __sanitizer_unaligned_load16(const uu16 *p) { 558 __msan_retval_tls[0] = *(uu16 *)MEM_TO_SHADOW((uptr)p); 559 if (__msan_get_track_origins()) 560 __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p)); 561 return *p; 562 } 563 u32 __sanitizer_unaligned_load32(const uu32 *p) { 564 __msan_retval_tls[0] = *(uu32 *)MEM_TO_SHADOW((uptr)p); 565 if (__msan_get_track_origins()) 566 __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p)); 567 return *p; 568 } 569 u64 __sanitizer_unaligned_load64(const uu64 *p) { 570 __msan_retval_tls[0] = *(uu64 *)MEM_TO_SHADOW((uptr)p); 571 if (__msan_get_track_origins()) 572 __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p)); 573 return *p; 574 } 575 void __sanitizer_unaligned_store16(uu16 *p, u16 x) { 576 u16 s = __msan_param_tls[1]; 577 *(uu16 *)MEM_TO_SHADOW((uptr)p) = s; 578 if (s && __msan_get_track_origins()) 579 if (uu32 o = __msan_param_origin_tls[2]) 580 SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o); 581 *p = x; 582 } 583 void __sanitizer_unaligned_store32(uu32 *p, u32 x) { 584 u32 s = __msan_param_tls[1]; 585 *(uu32 *)MEM_TO_SHADOW((uptr)p) = s; 586 if (s && __msan_get_track_origins()) 587 if (uu32 o = __msan_param_origin_tls[2]) 588 SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o); 589 *p = x; 590 } 591 void __sanitizer_unaligned_store64(uu64 *p, u64 x) { 592 u64 s = __msan_param_tls[1]; 593 *(uu64 *)MEM_TO_SHADOW((uptr)p) = s; 594 if (s && __msan_get_track_origins()) 595 if (uu32 o = __msan_param_origin_tls[2]) 596 SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o); 597 *p = x; 598 } 599 600 void __msan_set_death_callback(void (*callback)(void)) { 601 death_callback = callback; 602 } 603 604 #if !SANITIZER_SUPPORTS_WEAK_HOOKS 605 extern "C" { 606 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 607 const char* __msan_default_options() { return ""; } 608 } // extern "C" 609 #endif 610 611 extern "C" { 612 SANITIZER_INTERFACE_ATTRIBUTE 613 void __sanitizer_print_stack_trace() { 614 GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()); 615 stack.Print(); 616 } 617 } // extern "C" 618