Skip to main content

wasmtime/runtime/
trap.rs

1#[cfg(feature = "coredump")]
2use super::coredump::WasmCoreDump;
3use crate::prelude::*;
4use crate::store::StoreOpaque;
5use crate::{AsContext, Module, bug};
6use core::fmt;
7use core::num::NonZeroUsize;
8use wasmtime_core::alloc::TryVec;
9use wasmtime_environ::{
10    CompiledTrap, FilePos, demangle_function_name, demangle_function_name_or_index,
11};
12
13/// Representation of a WebAssembly trap and what caused it to occur.
14///
15/// WebAssembly traps happen explicitly for instructions such as `unreachable`
16/// but can also happen as side effects of other instructions such as `i32.load`
17/// loading an out-of-bounds address. Traps halt the execution of WebAssembly
18/// and cause an error to be returned to the host. This enumeration is a list of
19/// all possible traps that can happen in wasm, in addition to some
20/// Wasmtime-specific trap codes listed here as well.
21///
22/// # Errors in Wasmtime
23///
24/// Error-handling in Wasmtime is primarily done through the
25/// [`wasmtime::Error`] type where most results are a
26/// [`wasmtime::Result<T>`] which is an alias for [`Result<T,
27/// wasmtime::Error>`](std::result::Result). Errors in Wasmtime are represented
28/// with [`wasmtime::Error`] which acts as a container for any type of error in
29/// addition to optional context for this error. The "base" error or
30/// [`wasmtime::Error::root_cause`] is a [`Trap`] whenever WebAssembly hits a
31/// trap, or otherwise it's whatever the host created the error with when
32/// returning an error for a host call.
33///
34/// Any error which happens while WebAssembly is executing will also, by
35/// default, capture a backtrace of the wasm frames while executing. This
36/// backtrace is represented with a [`WasmBacktrace`] instance and is attached
37/// to the [`wasmtime::Error`] return value as a
38/// [`context`](crate::Error::context). Inspecting a [`WasmBacktrace`] can be
39/// done with the [`downcast_ref`](crate::Error::downcast_ref) function. For
40/// information on this see the [`WasmBacktrace`] documentation.
41///
42/// [`wasmtime::Error`]: crate::Error
43/// [`wasmtime::Result<T>`]: crate::Result
44/// [`wasmtime::Error::root_cause`]: crate::Error::root_cause
45///
46/// # Examples
47///
48/// ```
49/// # use wasmtime::*;
50/// # fn main() -> Result<()> {
51/// let engine = Engine::default();
52/// let module = Module::new(
53///     &engine,
54///     r#"
55///         (module
56///             (func (export "trap")
57///                 unreachable)
58///             (func $overflow (export "overflow")
59///                 call $overflow)
60///         )
61///     "#,
62/// )?;
63/// let mut store = Store::new(&engine, ());
64/// let instance = Instance::new(&mut store, &module, &[])?;
65///
66/// let trap = instance.get_typed_func::<(), ()>(&mut store, "trap")?;
67/// let error = trap.call(&mut store, ()).unwrap_err();
68/// assert_eq!(*error.downcast_ref::<Trap>().unwrap(), Trap::UnreachableCodeReached);
69/// assert!(error.root_cause().is::<Trap>());
70///
71/// let overflow = instance.get_typed_func::<(), ()>(&mut store, "overflow")?;
72/// let error = overflow.call(&mut store, ()).unwrap_err();
73/// assert_eq!(*error.downcast_ref::<Trap>().unwrap(), Trap::StackOverflow);
74/// # Ok(())
75/// # }
76/// ```
77pub use wasmtime_environ::Trap;
78
79#[cold] // traps are exceptional, this helps move handling off the main path
80pub(crate) fn from_runtime_box(
81    store: &mut StoreOpaque,
82    runtime_trap: Box<crate::runtime::vm::Trap>,
83) -> Error {
84    let crate::runtime::vm::Trap {
85        reason,
86        backtrace,
87        coredumpstack,
88    } = *runtime_trap;
89    let (mut error, pc) = match reason {
90        // For user-defined errors they're already an `crate::Error` so no
91        // conversion is really necessary here, but a `backtrace` may have
92        // been captured so it's attempted to get inserted here.
93        //
94        // If the error is actually a `Trap` then the backtrace is inserted
95        // directly into the `Trap` since there's storage there for it.
96        // Otherwise though this represents a host-defined error which isn't
97        // using a `Trap` but instead some other condition that was fatal to
98        // wasm itself. In that situation the backtrace is inserted as
99        // contextual information on error using `error.context(...)` to
100        // provide useful information to debug with for the embedder/caller,
101        // otherwise the information about what the wasm was doing when the
102        // error was generated would be lost.
103        crate::runtime::vm::TrapReason::User(error) => (error, None),
104        crate::runtime::vm::TrapReason::Jit {
105            pc,
106            faulting_addr,
107            trap,
108        } => {
109            let mut err: Error = match trap {
110                CompiledTrap::Normal(trap) => trap.into(),
111                CompiledTrap::InternalAssert => {
112                    bug!("internal assert triggered in compiled code").into()
113                }
114                CompiledTrap::GcHeapCorrupt => {
115                    bug!("gc heap corruption detected in compiled code").into()
116                }
117            };
118
119            // If a fault address was present, for example with segfaults,
120            // then simultaneously assert that it's within a known linear memory
121            // and additionally translate it to a wasm-local address to be added
122            // as context to the error.
123            if let Some(fault) = faulting_addr.and_then(|addr| store.wasm_fault(pc, addr)) {
124                err = err.context(fault);
125            }
126            (err, Some(pc))
127        }
128    };
129
130    if let Some(bt) = backtrace {
131        let bt = WasmBacktrace::from_captured(
132            store,
133            bt,
134            pc,
135            store.engine().config().wasm_backtrace_max_frames,
136        );
137        if !bt.wasm_trace.is_empty() {
138            error = error.context(bt);
139        }
140    }
141
142    let _ = &coredumpstack;
143    #[cfg(feature = "coredump")]
144    if let Some(coredump) = coredumpstack {
145        let bt = WasmBacktrace::from_captured(
146            store,
147            coredump.bt,
148            pc,
149            store.engine().config().wasm_backtrace_max_frames,
150        );
151        let cd = WasmCoreDump::new(store, bt);
152        error = error.context(cd);
153    }
154
155    error
156}
157
158/// Representation of a backtrace of function frames in a WebAssembly module for
159/// where an error happened.
160///
161/// This structure is attached to the [`wasmtime::Error`] returned from many
162/// Wasmtime functions that execute WebAssembly such as [`Instance::new`] or
163/// [`Func::call`]. This can be acquired with the
164/// [`Error::downcast`](crate::Error::downcast) family of methods to
165/// programmatically inspect the backtrace. Otherwise since it's part of the
166/// error returned this will get printed along with the rest of the error when
167/// the error is logged.
168///
169/// Capturing of wasm backtraces can be configured through the
170/// [`Config::wasm_backtrace_max_frames`](crate::Config::wasm_backtrace_max_frames) method.
171///
172/// For more information about errors in wasmtime see the documentation of the
173/// [`Trap`] type.
174///
175/// [`Func::call`]: crate::Func::call
176/// [`Instance::new`]: crate::Instance::new
177/// [`wasmtime::Error`]: crate::Error
178///
179/// # Examples
180///
181/// ```
182/// # use wasmtime::*;
183/// # fn main() -> Result<()> {
184/// let engine = Engine::default();
185/// let module = Module::new(
186///     &engine,
187///     r#"
188///         (module
189///             (func $start (export "run")
190///                 call $trap)
191///             (func $trap
192///                 unreachable)
193///         )
194///     "#,
195/// )?;
196/// let mut store = Store::new(&engine, ());
197/// let instance = Instance::new(&mut store, &module, &[])?;
198/// let func = instance.get_typed_func::<(), ()>(&mut store, "run")?;
199/// let error = func.call(&mut store, ()).unwrap_err();
200/// let bt = error.downcast_ref::<WasmBacktrace>().unwrap();
201/// let frames = bt.frames();
202/// assert_eq!(frames.len(), 2);
203/// assert_eq!(frames[0].func_name(), Some("trap"));
204/// assert_eq!(frames[1].func_name(), Some("start"));
205/// # Ok(())
206/// # }
207/// ```
208#[derive(Debug)]
209pub struct WasmBacktrace {
210    wasm_trace: Vec<FrameInfo>,
211    hint_wasm_backtrace_details_env: bool,
212    // This is currently only present for the `Debug` implementation for extra
213    // context.
214    _runtime_trace: crate::runtime::vm::Backtrace,
215}
216
217impl WasmBacktrace {
218    /// Captures a trace of the WebAssembly frames on the stack for the
219    /// provided store.
220    ///
221    /// This will return a [`WasmBacktrace`] which holds captured
222    /// [`FrameInfo`]s for each frame of WebAssembly on the call stack of the
223    /// current thread. If no WebAssembly is on the stack then the returned
224    /// backtrace will have no frames in it.
225    ///
226    /// Note that this function will respect the
227    /// [`Config::wasm_backtrace_max_frames`] configuration option and will
228    /// return an empty backtrace if that is set to `None`. To always capture a
229    /// backtrace use the [`WasmBacktrace::force_capture`] method.
230    ///
231    /// Also note that this function will only capture frames from the
232    /// specified `store` on the stack, ignoring frames from other stores if
233    /// present.
234    ///
235    /// [`Config::wasm_backtrace_max_frames`]: crate::Config::wasm_backtrace_max_frames
236    ///
237    /// # Example
238    ///
239    /// ```
240    /// # use wasmtime::*;
241    /// # fn main() -> Result<()> {
242    /// let engine = Engine::default();
243    /// let module = Module::new(
244    ///     &engine,
245    ///     r#"
246    ///         (module
247    ///             (import "" "" (func $host))
248    ///             (func $foo (export "f") call $bar)
249    ///             (func $bar call $host)
250    ///         )
251    ///     "#,
252    /// )?;
253    ///
254    /// let mut store = Store::new(&engine, ());
255    /// let func = Func::wrap(&mut store, |cx: Caller<'_, ()>| {
256    ///     let trace = WasmBacktrace::capture(&cx);
257    ///     println!("{trace:?}");
258    /// });
259    /// let instance = Instance::new(&mut store, &module, &[func.into()])?;
260    /// let func = instance.get_typed_func::<(), ()>(&mut store, "f")?;
261    /// func.call(&mut store, ())?;
262    /// # Ok(())
263    /// # }
264    /// ```
265    pub fn capture(store: impl AsContext) -> WasmBacktrace {
266        let store = store.as_context();
267        if let Some(max_frames) = store.engine().config().wasm_backtrace_max_frames {
268            Self::from_captured(
269                store.0,
270                crate::runtime::vm::Backtrace::new(store.0),
271                None,
272                Some(max_frames),
273            )
274        } else {
275            WasmBacktrace {
276                wasm_trace: Vec::new(),
277                hint_wasm_backtrace_details_env: false,
278                _runtime_trace: crate::runtime::vm::Backtrace::empty(),
279            }
280        }
281    }
282
283    /// Unconditionally captures a trace of the WebAssembly frames on the stack
284    /// for the provided store.
285    ///
286    /// Same as [`WasmBacktrace::capture`] except that it disregards the
287    /// [`Config::wasm_backtrace_max_frames`](crate::Config::wasm_backtrace_max_frames)
288    /// setting and always captures a backtrace.
289    pub fn force_capture(store: impl AsContext) -> WasmBacktrace {
290        let store = store.as_context();
291        let max_frames = store
292            .engine()
293            .config()
294            .wasm_backtrace_max_frames
295            .unwrap_or(crate::config::DEFAULT_WASM_BACKTRACE_MAX_FRAMES);
296        Self::from_captured(
297            store.0,
298            crate::runtime::vm::Backtrace::new(store.0),
299            None,
300            Some(max_frames),
301        )
302    }
303
304    fn from_captured(
305        store: &StoreOpaque,
306        runtime_trace: crate::runtime::vm::Backtrace,
307        trap_pc: Option<usize>,
308        max_frames: Option<NonZeroUsize>,
309    ) -> Self {
310        let Some(max_frames) = max_frames else {
311            return WasmBacktrace {
312                wasm_trace: Vec::new(),
313                hint_wasm_backtrace_details_env: false,
314                _runtime_trace: crate::runtime::vm::Backtrace::empty(),
315            };
316        };
317        let mut wasm_trace = match TryVec::with_capacity(max_frames.get()) {
318            Ok(v) => v,
319            Err(_) => {
320                return Self {
321                    wasm_trace: Vec::new(),
322                    hint_wasm_backtrace_details_env: false,
323                    _runtime_trace: crate::runtime::vm::Backtrace::empty(),
324                };
325            }
326        };
327        let mut hint_wasm_backtrace_details_env = false;
328        let wasm_backtrace_details_env_used =
329            store.engine().config().wasm_backtrace_details_env_used;
330
331        for frame in runtime_trace.frames() {
332            if wasm_trace.len() >= max_frames.get() {
333                break;
334            }
335
336            debug_assert!(frame.pc() != 0);
337
338            // Note that we need to be careful about the pc we pass in
339            // here to lookup frame information. This program counter is
340            // used to translate back to an original source location in
341            // the origin wasm module. If this pc is the exact pc that
342            // the trap happened at, then we look up that pc precisely.
343            // Otherwise backtrace information typically points at the
344            // pc *after* the call instruction (because otherwise it's
345            // likely a call instruction on the stack). In that case we
346            // want to lookup information for the previous instruction
347            // (the call instruction) so we subtract one as the lookup.
348            let pc_to_lookup = if Some(frame.pc()) == trap_pc {
349                frame.pc()
350            } else {
351                frame.pc() - 1
352            };
353
354            // NB: The PC we are looking up _must_ be a Wasm PC since
355            // `crate::runtime::vm::Backtrace` only contains Wasm frames.
356            //
357            // However, consider the case where we have multiple, nested calls
358            // across stores (with host code in between, by necessity, since
359            // only things in the same store can be linked directly together):
360            //
361            //     | ...             |
362            //     | Host            |  |
363            //     +-----------------+  | stack
364            //     | Wasm in store A |  | grows
365            //     +-----------------+  | down
366            //     | Host            |  |
367            //     +-----------------+  |
368            //     | Wasm in store B |  V
369            //     +-----------------+
370            //
371            // In this scenario, the `crate::runtime::vm::Backtrace` will
372            // contain two frames: Wasm in store B followed by Wasm in store
373            // A. But `store.modules()` will only have the module information
374            // for modules instantiated within this store. Therefore, we use `if
375            // let Some(..)` instead of the `unwrap` you might otherwise expect
376            // and we ignore frames from modules that were not registered in
377            // this store's module registry.
378            if let Some((info, module)) = store.modules().lookup_frame_info(pc_to_lookup) {
379                if wasm_trace.push(info).is_err() {
380                    // Better to return a partial backtrace than none.
381                    break;
382                }
383
384                // If this frame has unparsed debug information and the
385                // store's configuration indicates that we were
386                // respecting the environment variable of whether to
387                // do this then we will print out a helpful note in
388                // `Display` to indicate that more detailed information
389                // in a trap may be available.
390                let has_unparsed_debuginfo =
391                    module.module().compiled_module().has_unparsed_debuginfo();
392                if has_unparsed_debuginfo
393                    && wasm_backtrace_details_env_used
394                    && cfg!(feature = "addr2line")
395                {
396                    hint_wasm_backtrace_details_env = true;
397                }
398            }
399        }
400
401        Self {
402            wasm_trace: wasm_trace.into(),
403            _runtime_trace: runtime_trace,
404            hint_wasm_backtrace_details_env,
405        }
406    }
407
408    /// Returns a list of function frames in WebAssembly this backtrace
409    /// represents.
410    pub fn frames(&self) -> &[FrameInfo] {
411        self.wasm_trace.as_slice()
412    }
413}
414
415impl fmt::Display for WasmBacktrace {
416    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
417        writeln!(f, "error while executing at wasm backtrace:")?;
418
419        let mut needs_newline = false;
420        for (i, frame) in self.wasm_trace.iter().enumerate() {
421            // Avoid putting a trailing newline on the output
422            if needs_newline {
423                writeln!(f, "")?;
424            } else {
425                needs_newline = true;
426            }
427            let name = frame.module().name().unwrap_or("<unknown>");
428            write!(f, "  {i:>3}: ")?;
429
430            if let Some(offset) = frame.module_offset() {
431                write!(f, "{offset:#8x} - ")?;
432            }
433
434            let write_raw_func_name = |f: &mut fmt::Formatter<'_>| {
435                demangle_function_name_or_index(f, frame.func_name(), frame.func_index() as usize)
436            };
437            if frame.symbols().is_empty() {
438                write!(f, "{name}!")?;
439                write_raw_func_name(f)?;
440            } else {
441                for (i, symbol) in frame.symbols().iter().enumerate() {
442                    if i > 0 {
443                        if needs_newline {
444                            writeln!(f, "")?;
445                        } else {
446                            needs_newline = true;
447                        }
448                        write!(f, "                - ")?;
449                    } else {
450                        // ...
451                    }
452                    match symbol.name() {
453                        Some(name) => demangle_function_name(f, name)?,
454                        None if i == 0 => write_raw_func_name(f)?,
455                        None => write!(f, "<inlined function>")?,
456                    }
457                    if let Some(file) = symbol.file() {
458                        writeln!(f, "")?;
459                        write!(f, "                    at {file}")?;
460                        if let Some(line) = symbol.line() {
461                            write!(f, ":{line}")?;
462                            if let Some(col) = symbol.column() {
463                                write!(f, ":{col}")?;
464                            }
465                        }
466                    }
467                }
468            }
469        }
470        if self.hint_wasm_backtrace_details_env {
471            write!(
472                f,
473                "\nnote: using the `WASMTIME_BACKTRACE_DETAILS=1` \
474                 environment variable may show more debugging information"
475            )?;
476        }
477        Ok(())
478    }
479}
480
481/// Description of a frame in a backtrace for a [`WasmBacktrace`].
482///
483/// Whenever an error happens while WebAssembly is executing a
484/// [`WasmBacktrace`] will be attached to the error returned which can be used
485/// to acquire this `FrameInfo`. For more information see [`WasmBacktrace`].
486#[derive(Debug)]
487pub struct FrameInfo {
488    module: Module,
489    func_index: u32,
490    func_name: Option<String>,
491    func_start: FilePos,
492    instr: Option<FilePos>,
493    symbols: Vec<FrameSymbol>,
494}
495
496impl FrameInfo {
497    /// Fetches frame information about a program counter in a backtrace.
498    ///
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 func_start = compiled_module.func_start_srcloc(index);
505        let instr =
506            wasmtime_environ::lookup_file_pos(module.engine_code().address_map_data(), text_offset);
507        let index = compiled_module.module().func_index(index);
508        let func_index = index.as_u32();
509        let func_name = compiled_module.func_name(index).map(|s| s.to_string());
510
511        // In debug mode for now assert that we found a mapping for `pc` within
512        // the function, because otherwise something is buggy along the way and
513        // not accounting for all the instructions. This isn't super critical
514        // though so we can omit this check in release mode.
515        //
516        // Note that if the module doesn't even have an address map due to
517        // compilation settings then it's expected that `instr` is `None`.
518        debug_assert!(
519            instr.is_some() || !compiled_module.has_address_map(),
520            "failed to find instruction for {text_offset:#x}"
521        );
522
523        // Use our wasm-relative pc to symbolize this frame. If there's a
524        // symbolication context (dwarf debug info) available then we can try to
525        // look this up there.
526        //
527        // Note that dwarf pcs are code-section-relative, hence the subtraction
528        // from the location of `instr`. Also note that all errors are ignored
529        // here for now since technically wasm modules can always have any
530        // custom section contents.
531        let mut symbols = Vec::new();
532
533        let _ = &mut symbols;
534        #[cfg(feature = "addr2line")]
535        if let Some(s) = &compiled_module.symbolize_context().ok().and_then(|c| c) {
536            if let Some(offset) = instr.and_then(|i| i.file_offset()) {
537                let to_lookup = u64::from(offset) - s.code_section_offset();
538                if let Ok(mut frames) = s.addr2line().find_frames(to_lookup).skip_all_loads() {
539                    while let Ok(Some(frame)) = frames.next() {
540                        symbols.push(FrameSymbol {
541                            name: frame
542                                .function
543                                .as_ref()
544                                .and_then(|l| l.raw_name().ok())
545                                .map(|s| s.to_string()),
546                            file: frame
547                                .location
548                                .as_ref()
549                                .and_then(|l| l.file)
550                                .map(|s| s.to_string()),
551                            line: frame.location.as_ref().and_then(|l| l.line),
552                            column: frame.location.as_ref().and_then(|l| l.column),
553                        });
554                    }
555                }
556            }
557        }
558
559        Some(FrameInfo {
560            module,
561            func_index,
562            func_name,
563            instr,
564            func_start,
565            symbols,
566        })
567    }
568
569    /// Returns the WebAssembly function index for this frame.
570    ///
571    /// This function index is the index in the function index space of the
572    /// WebAssembly module that this frame comes from.
573    pub fn func_index(&self) -> u32 {
574        self.func_index
575    }
576
577    /// Returns the module for this frame.
578    ///
579    /// This is the module who's code was being run in this frame.
580    pub fn module(&self) -> &Module {
581        &self.module
582    }
583
584    /// Returns a descriptive name of the function for this frame, if one is
585    /// available.
586    ///
587    /// The name of this function may come from the `name` section of the
588    /// WebAssembly binary, or wasmtime may try to infer a better name for it if
589    /// not available, for example the name of the export if it's exported.
590    ///
591    /// This return value is primarily used for debugging and human-readable
592    /// purposes for things like traps. Note that the exact return value may be
593    /// tweaked over time here and isn't guaranteed to be something in
594    /// particular about a wasm module due to its primary purpose of assisting
595    /// in debugging.
596    ///
597    /// This function returns `None` when no name could be inferred.
598    pub fn func_name(&self) -> Option<&str> {
599        self.func_name.as_deref()
600    }
601
602    /// Returns the offset within the original wasm module this frame's program
603    /// counter was at.
604    ///
605    /// The offset here is the offset from the beginning of the original wasm
606    /// module to the instruction that this frame points to.
607    ///
608    /// Note that `None` may be returned if the original module was not
609    /// compiled with mapping information to yield this information. This is
610    /// controlled by the
611    /// [`Config::generate_address_map`](crate::Config::generate_address_map)
612    /// configuration option.
613    pub fn module_offset(&self) -> Option<usize> {
614        Some(self.instr?.file_offset()? as usize)
615    }
616
617    /// Returns the offset from the original wasm module's function to this
618    /// frame's program counter.
619    ///
620    /// The offset here is the offset from the beginning of the defining
621    /// function of this frame (within the wasm module) to the instruction this
622    /// frame points to.
623    ///
624    /// Note that `None` may be returned if the original module was not
625    /// compiled with mapping information to yield this information. This is
626    /// controlled by the
627    /// [`Config::generate_address_map`](crate::Config::generate_address_map)
628    /// configuration option.
629    pub fn func_offset(&self) -> Option<usize> {
630        let instr_offset = self.instr?.file_offset()?;
631        Some((instr_offset - self.func_start.file_offset()?) as usize)
632    }
633
634    /// Returns the debug symbols found, if any, for this function frame.
635    ///
636    /// When a wasm program is compiled with DWARF debug information then this
637    /// function may be populated to return symbols which contain extra debug
638    /// information about a frame including the filename and line number. If no
639    /// debug information was found or if it was malformed then this will return
640    /// an empty array.
641    pub fn symbols(&self) -> &[FrameSymbol] {
642        &self.symbols
643    }
644}
645
646/// Debug information for a symbol that is attached to a [`FrameInfo`].
647///
648/// When DWARF debug information is present in a wasm file then this structure
649/// can be found on a [`FrameInfo`] and can be used to learn about filenames,
650/// line numbers, etc, which are the origin of a function in a stack trace.
651#[derive(Debug)]
652pub struct FrameSymbol {
653    name: Option<String>,
654    file: Option<String>,
655    line: Option<u32>,
656    column: Option<u32>,
657}
658
659impl FrameSymbol {
660    /// Returns the function name associated with this symbol.
661    ///
662    /// Note that this may not be present with malformed debug information, or
663    /// the debug information may not include it. Also note that the symbol is
664    /// frequently mangled, so you might need to run some form of demangling
665    /// over it.
666    pub fn name(&self) -> Option<&str> {
667        self.name.as_deref()
668    }
669
670    /// Returns the source code filename this symbol was defined in.
671    ///
672    /// Note that this may not be present with malformed debug information, or
673    /// the debug information may not include it.
674    pub fn file(&self) -> Option<&str> {
675        self.file.as_deref()
676    }
677
678    /// Returns the 1-indexed source code line number this symbol was defined
679    /// on.
680    ///
681    /// Note that this may not be present with malformed debug information, or
682    /// the debug information may not include it.
683    pub fn line(&self) -> Option<u32> {
684        self.line
685    }
686
687    /// Returns the 1-indexed source code column number this symbol was defined
688    /// on.
689    ///
690    /// Note that this may not be present with malformed debug information, or
691    /// the debug information may not include it.
692    pub fn column(&self) -> Option<u32> {
693        self.column
694    }
695}