From 8f7839f41bb58eefc7aa64a3eadf1486e4cf171d Mon Sep 17 00:00:00 2001
From: Steven Fackler <sfackler@gmail.com>
Date: Fri, 10 Nov 2017 19:58:04 -0800
Subject: [PATCH] Add dl_iterate_phdr and related types

A lot of this is more broadly supported than just Linux, but support for
those can be added later.
---
 libc-test/build.rs           |  6 ++-
 src/unix/notbsd/linux/mod.rs | 82 ++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/libc-test/build.rs b/libc-test/build.rs
index 7b93f2d6..ce3c6f5f 100644
--- a/libc-test/build.rs
+++ b/libc-test/build.rs
@@ -256,6 +256,8 @@ fn main() {
 
     if linux {
         cfg.header("linux/random.h");
+        cfg.header("elf.h");
+        cfg.header("link.h");
     }
 
     if freebsd {
@@ -301,7 +303,9 @@ fn main() {
             "FILE" |
             "fd_set" |
             "Dl_info" |
-            "DIR" => ty.to_string(),
+            "DIR" |
+            "Elf32_Phdr" |
+            "Elf64_Phdr" => ty.to_string(),
 
             // Fixup a few types on windows that don't actually exist.
             "time64_t" if windows => "__time64_t".to_string(),
diff --git a/src/unix/notbsd/linux/mod.rs b/src/unix/notbsd/linux/mod.rs
index fb9299bb..46cf538f 100644
--- a/src/unix/notbsd/linux/mod.rs
+++ b/src/unix/notbsd/linux/mod.rs
@@ -23,6 +23,17 @@ pub type __s16 = ::c_short;
 pub type __u32 = ::c_uint;
 pub type __s32 = ::c_int;
 
+pub type Elf32_Half = u16;
+pub type Elf32_Word = u32;
+pub type Elf32_Off = u32;
+pub type Elf32_Addr = u32;
+
+pub type Elf64_Half = u16;
+pub type Elf64_Word = u32;
+pub type Elf64_Off = u64;
+pub type Elf64_Addr = u64;
+pub type Elf64_Xword = u64;
+
 pub enum fpos64_t {} // TODO: fill this out with a struct
 
 s! {
@@ -391,6 +402,52 @@ s! {
         #[cfg(target_pointer_width = "32")]
         pub u: [u32; 7],
     }
+
+    pub struct dl_phdr_info {
+        #[cfg(target_pointer_width = "64")]
+        pub dlpi_addr: Elf64_Addr,
+        #[cfg(target_pointer_width = "32")]
+        pub dlpi_addr: Elf32_Addr,
+
+        pub dlpi_name: *const ::c_char,
+
+        #[cfg(target_pointer_width = "64")]
+        pub dlpi_phdr: *const Elf64_Phdr,
+        #[cfg(target_pointer_width = "32")]
+        pub dlpi_phdr: *const Elf32_Phdr,
+
+        #[cfg(target_pointer_width = "64")]
+        pub dlpi_phnum: Elf64_Half,
+        #[cfg(target_pointer_width = "32")]
+        pub dlpi_phnum: Elf32_Half,
+
+        pub dlpi_adds: ::c_ulonglong,
+        pub dlpi_subs: ::c_ulonglong,
+        pub dlpi_tls_modid: ::size_t,
+        pub dlpi_tls_data: *mut ::c_void,
+    }
+
+    pub struct Elf32_Phdr {
+        pub p_type: Elf32_Word,
+        pub p_offset: Elf32_Off,
+        pub p_vaddr: Elf32_Addr,
+        pub p_paddr: Elf32_Addr,
+        pub p_filesz: Elf32_Word,
+        pub p_memsz: Elf32_Word,
+        pub p_flags: Elf32_Word,
+        pub p_align: Elf32_Word,
+    }
+
+    pub struct Elf64_Phdr {
+        pub p_type: Elf64_Word,
+        pub p_flags: Elf64_Word,
+        pub p_offset: Elf64_Off,
+        pub p_vaddr: Elf64_Addr,
+        pub p_paddr: Elf64_Addr,
+        pub p_filesz: Elf64_Xword,
+        pub p_memsz: Elf64_Xword,
+        pub p_align: Elf64_Xword,
+    }
 }
 
 pub const ABDAY_1: ::nl_item = 0x20000;
@@ -1031,6 +1088,23 @@ pub const CMSPAR: ::tcflag_t = 0o10000000000;
 pub const MFD_CLOEXEC: ::c_uint = 0x0001;
 pub const MFD_ALLOW_SEALING: ::c_uint = 0x0002;
 
+// these are used in the p_type field of Elf32_Phdr and Elf64_Phdr, which has
+// the type Elf32Word and Elf64Word respectively. Luckily, both of those are u32
+// so we can use that type here to avoid having to cast.
+pub const PT_NULL: u32 = 0;
+pub const PT_LOAD: u32 = 1;
+pub const PT_DYNAMIC: u32 = 2;
+pub const PT_INTERP: u32 = 3;
+pub const PT_NOTE: u32 = 4;
+pub const PT_SHLIB: u32 = 5;
+pub const PT_PHDR: u32 = 6;
+pub const PT_TLS: u32 = 7;
+pub const PT_NUM: u32 = 8;
+pub const PT_LOOS: u32 = 0x60000000;
+pub const PT_GNU_EH_FRAME: u32 = 0x6474e550;
+pub const PT_GNU_STACK: u32 = 0x6474e551;
+pub const PT_GNU_RELRO: u32 = 0x6474e552;
+
 f! {
     pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () {
         for slot in cpuset.bits.iter_mut() {
@@ -1488,6 +1562,14 @@ extern {
                           attr: *const ::pthread_attr_t,
                           f: extern fn(*mut ::c_void) -> *mut ::c_void,
                           value: *mut ::c_void) -> ::c_int;
+    pub fn dl_iterate_phdr(
+        callback: Option<unsafe extern fn(
+            info: *mut ::dl_phdr_info,
+            size: ::size_t,
+            data: *mut ::c_void
+        ) -> ::c_int>,
+        data: *mut ::c_void
+    ) -> ::c_int;
 }
 
 cfg_if! {
-- 
GitLab