summaryrefslogtreecommitdiffstats
path: root/library/backtrace/src/symbolize/gimli/libs_windows.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/backtrace/src/symbolize/gimli/libs_windows.rs')
-rw-r--r--library/backtrace/src/symbolize/gimli/libs_windows.rs89
1 files changed, 89 insertions, 0 deletions
diff --git a/library/backtrace/src/symbolize/gimli/libs_windows.rs b/library/backtrace/src/symbolize/gimli/libs_windows.rs
new file mode 100644
index 000000000..b47ed4245
--- /dev/null
+++ b/library/backtrace/src/symbolize/gimli/libs_windows.rs
@@ -0,0 +1,89 @@
+use super::super::super::windows::*;
+use super::mystd::os::windows::prelude::*;
+use super::{coff, mmap, Library, LibrarySegment, OsString};
+use alloc::vec;
+use alloc::vec::Vec;
+use core::mem;
+use core::mem::MaybeUninit;
+
+// For loading native libraries on Windows, see some discussion on
+// rust-lang/rust#71060 for the various strategies here.
+pub(super) fn native_libraries() -> Vec<Library> {
+ let mut ret = Vec::new();
+ unsafe {
+ add_loaded_images(&mut ret);
+ }
+ return ret;
+}
+
+unsafe fn add_loaded_images(ret: &mut Vec<Library>) {
+ let snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
+ if snap == INVALID_HANDLE_VALUE {
+ return;
+ }
+
+ let mut me = MaybeUninit::<MODULEENTRY32W>::zeroed().assume_init();
+ me.dwSize = mem::size_of_val(&me) as DWORD;
+ if Module32FirstW(snap, &mut me) == TRUE {
+ loop {
+ if let Some(lib) = load_library(&me) {
+ ret.push(lib);
+ }
+
+ if Module32NextW(snap, &mut me) != TRUE {
+ break;
+ }
+ }
+ }
+
+ CloseHandle(snap);
+}
+
+unsafe fn load_library(me: &MODULEENTRY32W) -> Option<Library> {
+ let pos = me
+ .szExePath
+ .iter()
+ .position(|i| *i == 0)
+ .unwrap_or(me.szExePath.len());
+ let name = OsString::from_wide(&me.szExePath[..pos]);
+
+ // MinGW libraries currently don't support ASLR
+ // (rust-lang/rust#16514), but DLLs can still be relocated around in
+ // the address space. It appears that addresses in debug info are
+ // all as-if this library was loaded at its "image base", which is a
+ // field in its COFF file headers. Since this is what debuginfo
+ // seems to list we parse the symbol table and store addresses as if
+ // the library was loaded at "image base" as well.
+ //
+ // The library may not be loaded at "image base", however.
+ // (presumably something else may be loaded there?) This is where
+ // the `bias` field comes into play, and we need to figure out the
+ // value of `bias` here. Unfortunately though it's not clear how to
+ // acquire this from a loaded module. What we do have, however, is
+ // the actual load address (`modBaseAddr`).
+ //
+ // As a bit of a cop-out for now we mmap the file, read the file
+ // header information, then drop the mmap. This is wasteful because
+ // we'll probably reopen the mmap later, but this should work well
+ // enough for now.
+ //
+ // Once we have the `image_base` (desired load location) and the
+ // `base_addr` (actual load location) we can fill in the `bias`
+ // (difference between the actual and desired) and then the stated
+ // address of each segment is the `image_base` since that's what the
+ // file says.
+ //
+ // For now it appears that unlike ELF/MachO we can make do with one
+ // segment per library, using `modBaseSize` as the whole size.
+ let mmap = mmap(name.as_ref())?;
+ let image_base = coff::get_image_base(&mmap)?;
+ let base_addr = me.modBaseAddr as usize;
+ Some(Library {
+ name,
+ bias: base_addr.wrapping_sub(image_base),
+ segments: vec![LibrarySegment {
+ stated_virtual_memory_address: image_base,
+ len: me.modBaseSize as usize,
+ }],
+ })
+}