Fetches frame information about a program counter in a backtrace. Returns an object if this `pc` is known to this module, or returns `None` if no information can be found.
(module: Module, text_offset: usize)
| 499 | /// Returns an object if this `pc` is known to this module, or returns `None` |
| 500 | /// if no information can be found. |
| 501 | pub(crate) fn new(module: Module, text_offset: usize) -> Option<FrameInfo> { |
| 502 | let compiled_module = module.compiled_module(); |
| 503 | let index = compiled_module.func_by_text_offset(text_offset)?; |
| 504 | let key = FuncKey::DefinedWasmFunction(compiled_module.module().module_index, index); |
| 505 | let func_start = compiled_module.func_start_srcloc(key); |
| 506 | let instr = |
| 507 | wasmtime_environ::lookup_file_pos(module.engine_code().address_map_data(), text_offset); |
| 508 | let index = compiled_module.module().func_index(index); |
| 509 | let func_index = index.as_u32(); |
| 510 | let func_name = compiled_module.func_name(index).map(|s| s.to_string()); |
| 511 | |
| 512 | // In debug mode for now assert that we found a mapping for `pc` within |
| 513 | // the function, because otherwise something is buggy along the way and |
| 514 | // not accounting for all the instructions. This isn't super critical |
| 515 | // though so we can omit this check in release mode. |
| 516 | // |
| 517 | // Note that if the module doesn't even have an address map due to |
| 518 | // compilation settings then it's expected that `instr` is `None`. |
| 519 | debug_assert!( |
| 520 | instr.is_some() || !compiled_module.has_address_map(), |
| 521 | "failed to find instruction for {text_offset:#x}" |
| 522 | ); |
| 523 | |
| 524 | // Use our wasm-relative pc to symbolize this frame. If there's a |
| 525 | // symbolication context (dwarf debug info) available then we can try to |
| 526 | // look this up there. |
| 527 | // |
| 528 | // Note that dwarf pcs are code-section-relative, hence the subtraction |
| 529 | // from the location of `instr`. Also note that all errors are ignored |
| 530 | // here for now since technically wasm modules can always have any |
| 531 | // custom section contents. |
| 532 | let mut symbols = Vec::new(); |
| 533 | |
| 534 | let _ = &mut symbols; |
| 535 | #[cfg(feature = "addr2line")] |
| 536 | if let Some(s) = &compiled_module.symbolize_context().ok().and_then(|c| c) { |
| 537 | if let Some(offset) = instr.and_then(|i| i.file_offset()) { |
| 538 | let to_lookup = u64::from(offset) - s.code_section_offset(); |
| 539 | if let Ok(mut frames) = s.addr2line().find_frames(to_lookup).skip_all_loads() { |
| 540 | while let Ok(Some(frame)) = frames.next() { |
| 541 | symbols.push(FrameSymbol { |
| 542 | name: frame |
| 543 | .function |
| 544 | .as_ref() |
| 545 | .and_then(|l| l.raw_name().ok()) |
| 546 | .map(|s| s.to_string()), |
| 547 | file: frame |
| 548 | .location |
| 549 | .as_ref() |
| 550 | .and_then(|l| l.file) |
| 551 | .map(|s| s.to_string()), |
| 552 | line: frame.location.as_ref().and_then(|l| l.line), |
| 553 | column: frame.location.as_ref().and_then(|l| l.column), |
| 554 | }); |
| 555 | } |
| 556 | } |
| 557 | } |
| 558 | } |
nothing calls this directly
no test coverage detected