ghostscope_process/
util.rs

1use std::fs::File;
2use std::io::{Read, Seek, SeekFrom};
3use std::path::Path;
4
5/// Return true if `path` looks like a shared object (ELF ET_DYN without PT_INTERP).
6/// Returns false for executables (ET_EXEC, or ET_DYN with PT_INTERP i.e. PIE).
7pub fn is_shared_object(path: &Path) -> bool {
8    const ET_EXEC: u16 = 2;
9    const ET_DYN: u16 = 3;
10    const PT_INTERP: u32 = 3;
11
12    let mut f = match File::open(path) {
13        Ok(f) => f,
14        Err(_) => return false,
15    };
16    let mut ehdr = [0u8; 64];
17    if f.read(&mut ehdr).ok().filter(|&n| n >= 52).is_none() {
18        return false;
19    }
20    if &ehdr[0..4] != b"\x7FELF" {
21        return false;
22    }
23    let class = ehdr[4]; // EI_CLASS
24    let data = ehdr[5]; // EI_DATA
25    let is_le = data == 1;
26    let rd16 = |b: &[u8]| -> u16 {
27        if is_le {
28            u16::from_le_bytes([b[0], b[1]])
29        } else {
30            u16::from_be_bytes([b[0], b[1]])
31        }
32    };
33    let rd32 = |b: &[u8]| -> u32 {
34        if is_le {
35            u32::from_le_bytes([b[0], b[1], b[2], b[3]])
36        } else {
37            u32::from_be_bytes([b[0], b[1], b[2], b[3]])
38        }
39    };
40    let rd64 = |b: &[u8]| -> u64 {
41        if is_le {
42            u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
43        } else {
44            u64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
45        }
46    };
47
48    let e_type = rd16(&ehdr[16..18]);
49    if e_type == ET_EXEC {
50        return false;
51    }
52
53    let (e_phoff, e_phentsize, e_phnum) = match class {
54        1 => {
55            let phoff = rd32(&ehdr[28..32]) as u64;
56            let entsz = rd16(&ehdr[42..44]) as u64;
57            let phnum = rd16(&ehdr[44..46]) as u64;
58            (phoff, entsz, phnum)
59        }
60        2 => {
61            let phoff = rd64(&ehdr[32..40]);
62            let entsz = rd16(&ehdr[54..56]) as u64;
63            let phnum = rd16(&ehdr[56..58]) as u64;
64            (phoff, entsz, phnum)
65        }
66        _ => return false,
67    };
68
69    if e_type == ET_DYN {
70        if e_phoff == 0 || e_phentsize < 4 || e_phnum == 0 {
71            return true; // conservative: treat as shared lib
72        }
73        for i in 0..e_phnum {
74            let off = e_phoff + i * e_phentsize;
75            if f.seek(SeekFrom::Start(off)).is_err() {
76                return true;
77            }
78            let mut p = [0u8; 8];
79            if f.read(&mut p[..4]).ok().filter(|&n| n == 4).is_none() {
80                return true;
81            }
82            let p_type = rd32(&p[..4]);
83            if p_type == PT_INTERP {
84                return false; // PIE executable
85            }
86        }
87        return true; // ET_DYN w/o PT_INTERP => shared library
88    }
89
90    // Unknown types: default to not shared
91    false
92}