1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use debugid::DebugId;
use object::{Object, ObjectSection, SectionKind};
use std::convert::TryInto;
use uuid::Uuid;
pub trait DebugIdExt {
fn from_identifier(identifier: &[u8], little_endian: bool) -> Self;
fn from_text_first_page(text_first_page: &[u8], little_endian: bool) -> Self;
}
impl DebugIdExt for DebugId {
fn from_identifier(identifier: &[u8], little_endian: bool) -> Self {
let mut d = [0u8; 16];
let shared_len = identifier.len().min(d.len());
d[0..shared_len].copy_from_slice(&identifier[0..shared_len]);
let (d1, d2, d3) = if little_endian {
(
u32::from_le_bytes([d[0], d[1], d[2], d[3]]),
u16::from_le_bytes([d[4], d[5]]),
u16::from_le_bytes([d[6], d[7]]),
)
} else {
(
u32::from_be_bytes([d[0], d[1], d[2], d[3]]),
u16::from_be_bytes([d[4], d[5]]),
u16::from_be_bytes([d[6], d[7]]),
)
};
let uuid = Uuid::from_fields(d1, d2, d3, d[8..16].try_into().unwrap());
DebugId::from_uuid(uuid)
}
fn from_text_first_page(text_first_page: &[u8], little_endian: bool) -> Self {
const UUID_SIZE: usize = 16;
const PAGE_SIZE: usize = 4096;
let mut hash = [0; UUID_SIZE];
for (i, byte) in text_first_page.iter().cloned().take(PAGE_SIZE).enumerate() {
hash[i % UUID_SIZE] ^= byte;
}
DebugId::from_identifier(&hash, little_endian)
}
}
pub fn debug_id_for_object<'data: 'file, 'file>(
obj: &'file impl Object<'data, 'file>,
) -> Option<DebugId> {
if let Ok(Some(pdb_info)) = obj.pdb_info() {
return Some(DebugId::from_guid_age(&pdb_info.guid(), pdb_info.age()).unwrap());
}
if let Ok(Some(build_id)) = obj.build_id() {
return Some(DebugId::from_identifier(build_id, obj.is_little_endian()));
}
if let Ok(Some(uuid)) = obj.mach_uuid() {
return Some(DebugId::from_uuid(Uuid::from_bytes(uuid)));
}
if let Some(section) = obj
.sections()
.find(|section| section.kind() == SectionKind::Text)
{
let data_len = section.size().min(4096);
if let Ok(Some(first_page_data)) = section.data_range(section.address(), data_len) {
return Some(DebugId::from_text_first_page(
first_page_data,
obj.is_little_endian(),
));
}
}
None
}