Skip to content

Commit

Permalink
Add android support for api version 21+ (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
name1e5s authored Oct 11, 2021
1 parent 8b4a516 commit c5a0293
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 21 deletions.
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ readme = "./README.md"
repository = "https://github.com/gimli-rs/findshlibs"

[dependencies]
libc = "0.2.65"
libc = "0.2.98"

[build-dependencies]
# Only needed for Android, but cannot be target dependent
# https://github.com/rust-lang/cargo/issues/4932
cc = "1.0.67"

[target.'cfg(target_os = "macos")'.dependencies]
lazy_static = "1.4"
Expand Down
41 changes: 41 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
extern crate cc;

use std::env;

fn main() {
match env::var("CARGO_CFG_TARGET_OS").unwrap_or_default().as_str() {
"android" => build_android(),
_ => {}
}
}

fn build_android() {
let expansion = match cc::Build::new().file("src/android-api.c").try_expand() {
Ok(result) => result,
Err(e) => {
println!("cargo:warning=failed to run C compiler: {}", e);
return;
}
};

let expansion = match std::str::from_utf8(&expansion) {
Ok(s) => s,
Err(_) => return,
};

let marker = "APIVERSION";
let i = expansion.find(marker).unwrap_or_default();

let version = expansion[i + marker.len() + 1..]
.split_whitespace()
.next()
.unwrap_or("");
let version = version.parse::<u32>().unwrap_or_else(|_| {
println!("cargo:warning=failed to get android api version.");
0
});

if version >= 21 {
println!("cargo:rustc-cfg=feature=\"dl_iterate_phdr\"");
}
}
4 changes: 4 additions & 0 deletions src/android-api.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Used from the build script to detect the value of the `__ANDROID_API__`
// builtin #define

APIVERSION __ANDROID_API__
18 changes: 15 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@
#[cfg(target_os = "macos")]
pub mod macos;

#[cfg(target_os = "linux")]
#[cfg(any(
target_os = "linux",
all(target_os = "android", feature = "dl_iterate_phdr")
))]
pub mod linux;

#[cfg(target_os = "windows")]
Expand All @@ -110,7 +113,10 @@ use std::usize;

pub mod unsupported;

#[cfg(target_os = "linux")]
#[cfg(any(
target_os = "linux",
all(target_os = "android", feature = "dl_iterate_phdr")
))]
use crate::linux as native_mod;

#[cfg(target_os = "macos")]
Expand All @@ -119,7 +125,12 @@ use crate::macos as native_mod;
#[cfg(target_os = "windows")]
use crate::windows as native_mod;

#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
#[cfg(not(any(
target_os = "macos",
target_os = "linux",
all(target_os = "android", feature = "dl_iterate_phdr"),
target_os = "windows"
)))]
use unsupported as native_mod;

/// The [`SharedLibrary` trait](./trait.SharedLibrary.html)
Expand All @@ -130,6 +141,7 @@ pub type TargetSharedLibrary<'a> = native_mod::SharedLibrary<'a>;
pub const TARGET_SUPPORTED: bool = cfg!(any(
target_os = "macos",
target_os = "linux",
all(target_os = "android", feature = "dl_iterate_phdr"),
target_os = "windows"
));

Expand Down
52 changes: 35 additions & 17 deletions src/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ type Phdr = libc::Elf32_Phdr;
type Phdr = libc::Elf64_Phdr;

const NT_GNU_BUILD_ID: u32 = 3;
const PT_NULL: u32 = 0;
const PT_LOAD: u32 = 1;
const PT_DYNAMIC: u32 = 2;
const PT_INTERP: u32 = 3;
const PT_NOTE: u32 = 4;
const PT_SHLIB: u32 = 5;
const PT_PHDR: u32 = 6;
const PT_TLS: u32 = 7;
const PT_NUM: u32 = 8;
const PT_LOOS: u32 = 0x60000000;
const PT_GNU_EH_FRAME: u32 = 0x6474e550;
const PT_GNU_STACK: u32 = 0x6474e551;
const PT_GNU_RELRO: u32 = 0x6474e552;

// Normally we would use `Elf32_Nhdr` on 32-bit platforms and `Elf64_Nhdr` on
// 64-bit platforms. However, in practice it seems that only `Elf32_Nhdr` is
Expand Down Expand Up @@ -59,7 +72,7 @@ impl<'a> Segment<'a> {
}

fn is_note(&self) -> bool {
self.phdr().p_type == libc::PT_NOTE
self.phdr().p_type == PT_NOTE
}

/// Parse the contents of a `PT_NOTE` segment.
Expand Down Expand Up @@ -144,19 +157,19 @@ impl<'a> SegmentTrait for Segment<'a> {
fn name(&self) -> &str {
unsafe {
match self.phdr.as_ref().unwrap().p_type {
libc::PT_NULL => "NULL",
libc::PT_LOAD => "LOAD",
libc::PT_DYNAMIC => "DYNAMIC",
libc::PT_INTERP => "INTERP",
libc::PT_NOTE => "NOTE",
libc::PT_SHLIB => "SHLI",
libc::PT_PHDR => "PHDR",
libc::PT_TLS => "TLS",
libc::PT_NUM => "NUM",
libc::PT_LOOS => "LOOS",
libc::PT_GNU_EH_FRAME => "GNU_EH_FRAME",
libc::PT_GNU_STACK => "GNU_STACK",
libc::PT_GNU_RELRO => "GNU_RELRO",
PT_NULL => "NULL",
PT_LOAD => "LOAD",
PT_DYNAMIC => "DYNAMIC",
PT_INTERP => "INTERP",
PT_NOTE => "NOTE",
PT_SHLIB => "SHLI",
PT_PHDR => "PHDR",
PT_TLS => "TLS",
PT_NUM => "NUM",
PT_LOOS => "LOOS",
PT_GNU_EH_FRAME => "GNU_EH_FRAME",
PT_GNU_STACK => "GNU_STACK",
PT_GNU_RELRO => "GNU_RELRO",
_ => "(unknown segment type)",
}
}
Expand All @@ -166,12 +179,12 @@ impl<'a> SegmentTrait for Segment<'a> {
fn is_code(&self) -> bool {
let hdr = self.phdr();
// 0x1 is PT_X for executable
hdr.p_type == libc::PT_LOAD && (hdr.p_flags & 0x1) != 0
hdr.p_type == PT_LOAD && (hdr.p_flags & 0x1) != 0
}

#[inline]
fn is_load(&self) -> bool {
self.phdr().p_type == libc::PT_LOAD
self.phdr().p_type == PT_LOAD
}

#[inline]
Expand Down Expand Up @@ -273,6 +286,10 @@ impl<'a> SharedLibrary<'a> {
F: FnMut(&Self) -> C,
C: Into<IterationControl>,
{
if (*info).dlpi_phdr.is_null() {
return CONTINUE;
}

let state = &mut *(state as *mut IterState<F>);
state.idx += 1;

Expand Down Expand Up @@ -451,11 +468,12 @@ mod tests {
}
});

assert!(names[0].contains("/findshlibs"));
assert!(names.iter().any(|x| x.contains("findshlibs")));
assert!(names.iter().any(|x| x.contains("libc.so")));
}

#[test]
#[cfg(target_os = "linux")]
fn get_id() {
use std::path::Path;
use std::process::Command;
Expand Down

0 comments on commit c5a0293

Please sign in to comment.