1use std::env;
23use sentry_core::protocol::{DebugImage, SymbolicDebugImage};
4use sentry_core::types::{CodeId, DebugId, Uuid};
56use findshlibs::{SharedLibrary, SharedLibraryId, TargetSharedLibrary, TARGET_SUPPORTED};
78const UUID_SIZE: usize = 16;
910/// Converts an ELF object identifier into a `DebugId`.
11///
12/// The identifier data is first truncated or extended to match 16 byte size of
13/// Uuids. If the data is declared in little endian, the first three Uuid fields
14/// are flipped to match the big endian expected by the breakpad processor.
15///
16/// The `DebugId::appendix` field is always `0` for ELF.
17fn debug_id_from_build_id(build_id: &[u8]) -> Option<DebugId> {
18let mut data = [0u8; UUID_SIZE];
19let len = build_id.len().min(UUID_SIZE);
20 data[0..len].copy_from_slice(&build_id[0..len]);
2122#[cfg(target_endian = "little")]
23{
24// The ELF file targets a little endian architecture. Convert to
25 // network byte order (big endian) to match the Breakpad processor's
26 // expectations. For big endian object files, this is not needed.
27data[0..4].reverse(); // uuid field 1
28data[4..6].reverse(); // uuid field 2
29data[6..8].reverse(); // uuid field 3
30}
3132 Uuid::from_slice(&data).map(DebugId::from_uuid).ok()
33}
3435/// Returns the list of loaded libraries/images.
36pub fn debug_images() -> Vec<DebugImage> {
37let mut images = vec![];
38if !TARGET_SUPPORTED {
39return images;
40 }
4142 TargetSharedLibrary::each(|shlib| {
43let maybe_debug_id = shlib.debug_id().and_then(|id| match id {
44 SharedLibraryId::Uuid(bytes) => Some(DebugId::from_uuid(Uuid::from_bytes(bytes))),
45 SharedLibraryId::GnuBuildId(ref id) => debug_id_from_build_id(id),
46 SharedLibraryId::PdbSignature(guid, age) => DebugId::from_guid_age(&guid, age).ok(),
47_ => None,
48 });
4950let debug_id = match maybe_debug_id {
51Some(debug_id) => debug_id,
52None => return,
53 };
5455let mut name = shlib.name().to_string_lossy().to_string();
56if name.is_empty() {
57 name = env::current_exe()
58 .map(|x| x.display().to_string())
59 .unwrap_or_else(|_| "<main>".to_string());
60 }
6162let code_id = shlib.id().map(|id| CodeId::new(id.to_string()));
63let debug_name = shlib.debug_name().map(|n| n.to_string_lossy().to_string());
6465// For windows, the `virtual_memory_bias` actually returns the real
66 // `module_base`, which is the address that sentry uses for symbolication.
67 // Going via the segments means that the `image_addr` would be offset in
68 // a way that symbolication yields wrong results.
69let (image_addr, image_vmaddr) = if cfg!(windows) {
70 (shlib.virtual_memory_bias().0.into(), 0.into())
71 } else {
72 (
73 shlib.actual_load_addr().0.into(),
74 shlib.stated_load_addr().0.into(),
75 )
76 };
7778 images.push(
79 SymbolicDebugImage {
80 id: debug_id,
81 name,
82 arch: None,
83 image_addr,
84 image_size: shlib.len() as u64,
85 image_vmaddr,
86 code_id,
87 debug_file: debug_name,
88 }
89 .into(),
90 );
91 });
9293 images
94}