Skip to content

Commit 7b676e9

Browse files
bors[bot]vext01
andauthored
Merge #5
5: Use the libc and elf crates instead of bindgen. r=ptersilie a=vext01 This make phdrs simpler and more lightweight. For now this would only work on Linux, but it'd be easy to get working elsewhere with small patches to libc (see [this issue](rust-lang/libc#1066)). Makes phdrs build so much faster. Co-authored-by: Edd Barrett <vext01@gmail.com>
2 parents 5dcf099 + 42b0e60 commit 7b676e9

4 files changed

Lines changed: 35 additions & 94 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,4 @@ license = "Apache-2.0 OR MIT"
77

88
[dependencies]
99
libc = "0.2.71"
10-
11-
[build-dependencies]
12-
bindgen = "0.54.1"
10+
elf = "0.0.10"

build.rs

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/lib.rs

Lines changed: 34 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,45 @@
1-
extern crate libc;
2-
3-
use libc::c_int;
1+
use elf::types::{PF_R, PF_W, PF_X};
2+
use libc::{
3+
c_int, dl_iterate_phdr, dl_phdr_info, PT_DYNAMIC, PT_GNU_EH_FRAME, PT_GNU_RELRO, PT_INTERP,
4+
PT_LOAD, PT_LOOS, PT_NOTE, PT_NULL, PT_PHDR, PT_SHLIB, PT_TLS,
5+
};
46
use std::{
57
ffi::{CStr, CString},
68
fmt::{self, Debug},
79
iter::Iterator,
810
os::raw::c_void,
911
};
1012

11-
// We are using bindgen to access the `dl_iterate_phdr` API and its types. The `libc` crate exposes
12-
// everything we need, but only on *some* platforms. If the `libc` definitions ever become portable
13-
// then it would make sense to use those instead of bindgen. There's an issue for this here:
14-
// https://github.com/rust-lang/libc/issues/1066
15-
//
16-
// Until then, we avoid namespace pollution by containing all the auto-generated stuff inside a
17-
// (private) sub-module, exposing only what we intend to be public.
18-
mod p_ffi {
19-
#![allow(non_upper_case_globals)]
20-
#![allow(non_camel_case_types)]
21-
#![allow(non_snake_case)]
22-
#![allow(dead_code)]
23-
#![allow(improper_ctypes)]
24-
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
25-
26-
// Re-define C types that are usually erased by C macros.
27-
#[cfg(target_pointer_width = "64")]
28-
pub type Elf_Phdr = Elf64_Phdr;
29-
#[cfg(target_pointer_width = "32")]
30-
pub type Elf_Phdr = Elf32_Phdr;
31-
32-
#[cfg(target_pointer_width = "64")]
33-
pub type Elf_Half = Elf64_Half;
34-
#[cfg(target_pointer_width = "32")]
35-
pub type Elf_Half = Elf32_Half;
36-
37-
#[cfg(target_pointer_width = "64")]
38-
pub type Elf_Addr = Elf64_Addr;
39-
#[cfg(target_pointer_width = "32")]
40-
pub type Elf_Addr = Elf32_Addr;
41-
42-
#[cfg(target_pointer_width = "64")]
43-
pub type Elf_Off = Elf64_Off;
44-
#[cfg(target_pointer_width = "32")]
45-
pub type Elf_Off = Elf32_Off;
46-
47-
#[cfg(target_pointer_width = "64")]
48-
pub type Elf_Word = Elf64_Word;
49-
#[cfg(target_pointer_width = "32")]
50-
pub type Elf_Word = Elf32_Word;
51-
52-
#[cfg(target_pointer_width = "64")]
53-
pub type Elf_Xword = u64;
54-
#[cfg(target_pointer_width = "32")]
55-
pub type Elf_Xword = u32;
56-
}
13+
#[cfg(target_pointer_width = "64")]
14+
use libc::{
15+
Elf64_Addr as Elf_Addr, Elf64_Half as Elf_Half, Elf64_Off as Elf_Off, Elf64_Phdr as Elf_Phdr,
16+
Elf64_Word as Elf_Word, Elf64_Xword as Elf_Xword,
17+
};
5718

58-
pub use p_ffi::{
59-
Elf_Addr, Elf_Half, Elf_Off, Elf_Phdr, Elf_Word, Elf_Xword, PF_MASKPROC, PF_R, PF_W, PF_X,
60-
PT_DYNAMIC, PT_GNU_EH_FRAME, PT_GNU_RELRO, PT_HIOS, PT_HIPROC, PT_INTERP, PT_LOAD, PT_LOOS,
61-
PT_LOPROC, PT_NOTE, PT_NULL, PT_PHDR, PT_SHLIB, PT_TLS,
19+
#[cfg(target_pointer_width = "32")]
20+
use libc::{
21+
Elf32_Addr as Elf_Addr, Elf32_Half as Elf_Half, Elf32_Off as Elf_Off, Elf32_Phdr as Elf_Phdr,
22+
Elf32_Word as Elf_Word, Elf32_Xword as Elf_Xword,
6223
};
6324

25+
// At the time of writing these ELF constants are defined neither in `elf` nor `libc`.
26+
const PF_MASKPROC: u32 = 0xf0000000;
27+
const PT_HIOS: u32 = 0x6fffffff;
28+
const PT_LOPROC: u32 = 0x70000000;
29+
const PT_HIPROC: u32 = 0x7fffffff;
30+
6431
/// Contains information about an "object" in the virtual address space.
6532
/// This corresponds with a `dl_phdr_info` in C. Note that the contents of the C struct differ
6633
/// between platforms. We expose only the common fields for now.
6734
pub struct Object {
6835
/// The base address of the object.
69-
addr: p_ffi::Elf_Addr,
36+
addr: Elf_Addr,
7037
/// The name of the object.
7138
name: CString,
7239
/// Pointer to program headers C array.
73-
phdrs: *const p_ffi::Elf_Phdr,
40+
phdrs: *const Elf_Phdr,
7441
/// The number of program headers.
75-
num_phdrs: p_ffi::Elf_Half,
42+
num_phdrs: Elf_Half,
7643
}
7744

7845
impl Object {
@@ -96,7 +63,7 @@ impl Object {
9663
}
9764

9865
/// Returns the number of program headers.
99-
pub fn num_phdrs(&self) -> p_ffi::Elf_Half {
66+
pub fn num_phdrs(&self) -> Elf_Half {
10067
self.num_phdrs
10168
}
10269
}
@@ -111,7 +78,7 @@ impl Debug for Object {
11178
}
11279
}
11380

114-
pub struct ProgramHeader(*const p_ffi::Elf_Phdr);
81+
pub struct ProgramHeader(*const Elf_Phdr);
11582

11683
impl ProgramHeader {
11784
/// Returns the segment type (as one of the `PT_*` constants).
@@ -160,7 +127,6 @@ impl ProgramHeader {
160127
impl Debug for ProgramHeader {
161128
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162129
let mut to_write = String::from("ProgramHeader(");
163-
164130
let type_ = self.type_();
165131
let type_str = match type_ {
166132
PT_NULL => "PT_NULL",
@@ -184,13 +150,13 @@ impl Debug for ProgramHeader {
184150

185151
let flags = self.flags();
186152
let mut flag_strs = Vec::new();
187-
if flags & PF_X != 0 {
153+
if flags & PF_X.0 != 0 {
188154
flag_strs.push("PF_X");
189155
}
190-
if flags & PF_W != 0 {
156+
if flags & PF_W.0 != 0 {
191157
flag_strs.push("PF_W");
192158
}
193-
if flags & PF_R != 0 {
159+
if flags & PF_R.0 != 0 {
194160
flag_strs.push("PF_R");
195161
}
196162
if flags & PF_MASKPROC != 0 {
@@ -211,8 +177,8 @@ impl Debug for ProgramHeader {
211177
///
212178
/// Each program header describes an ELF segment loaded in the virtual adress space.
213179
pub struct ProgramHeaderIterator {
214-
ptr: *const p_ffi::Elf_Phdr, // Pointer to the next raw `Elf_Phdr`.
215-
num: p_ffi::Elf_Half, // How many left.
180+
ptr: *const Elf_Phdr, // Pointer to the next raw `Elf_Phdr`.
181+
num: Elf_Half, // How many left.
216182
}
217183

218184
impl Iterator for ProgramHeaderIterator {
@@ -235,7 +201,7 @@ pub fn objects() -> Vec<Object> {
235201
let mut ret = Vec::new();
236202

237203
// Pushes an `Object` into the result vector on the behalf of C.
238-
extern "C" fn push_object(objs: &mut Vec<Object>, obj: &p_ffi::dl_phdr_info) {
204+
extern "C" fn push_object(objs: &mut Vec<Object>, obj: &dl_phdr_info) {
239205
let name = unsafe { CStr::from_ptr(obj.dlpi_name) }.to_owned();
240206
// We have to copy the `dl_phdr_info` struct out, as the same memory buffer is used for
241207
// each entry during the iteration process. Otherwise we could have used a vector of
@@ -250,16 +216,16 @@ pub fn objects() -> Vec<Object> {
250216

251217
// Callback for `dl_iterate_phdr(3)`.
252218
unsafe extern "C" fn collect_objs(
253-
info: *mut p_ffi::dl_phdr_info,
254-
_sz: u64,
219+
info: *mut dl_phdr_info,
220+
_sz: usize,
255221
data: *mut c_void,
256222
) -> c_int {
257223
push_object(&mut *(data as *mut Vec<Object>), &*info); // Get Rust to push the object.
258224
0
259225
};
260226

261227
let ret_void_p = &mut ret as *mut Vec<Object> as *mut c_void;
262-
unsafe { p_ffi::dl_iterate_phdr(Some(collect_objs), ret_void_p) };
228+
unsafe { dl_iterate_phdr(Some(collect_objs), ret_void_p) };
263229

264230
ret
265231
}

wrapper.h

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)