diff -Nru rust-findshlibs-0.5.0/build.rs rust-findshlibs-0.10.2/build.rs --- rust-findshlibs-0.5.0/build.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-findshlibs-0.10.2/build.rs 1970-01-01 00:00:00.000000000 +0000 @@ -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::().unwrap_or_else(|_| { + println!("cargo:warning=failed to get android api version."); + 0 + }); + + if version >= 21 { + println!("cargo:rustc-cfg=feature=\"dl_iterate_phdr\""); + } +} diff -Nru rust-findshlibs-0.5.0/Cargo.lock rust-findshlibs-0.10.2/Cargo.lock --- rust-findshlibs-0.5.0/Cargo.lock 1970-01-01 00:00:00.000000000 +0000 +++ rust-findshlibs-0.10.2/Cargo.lock 1970-01-01 00:00:00.000000000 +0000 @@ -0,0 +1,53 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" + +[[package]] +name = "findshlibs" +version = "0.10.2" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff -Nru rust-findshlibs-0.5.0/Cargo.toml rust-findshlibs-0.10.2/Cargo.toml --- rust-findshlibs-0.5.0/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rust-findshlibs-0.10.2/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 @@ -3,7 +3,7 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -11,25 +11,21 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "findshlibs" -version = "0.5.0" -authors = ["Nick Fitzgerald "] +version = "0.10.2" description = "Find the set of shared libraries loaded in the current process with a cross platform API" documentation = "https://docs.rs/findshlibs" readme = "./README.md" keywords = ["dyld", "dylib", "shared", "library", "dl_iterate_phdr"] -license = "Apache-2.0/MIT" +license = "MIT OR Apache-2.0" repository = "https://github.com/gimli-rs/findshlibs" -[dependencies.lazy_static] -version = "1.0.0" - [dependencies.libc] -version = "0.2.55" - -[features] -nightly = [] -[badges.coveralls] -repository = "gimli-rs/findshlibs" - -[badges.travis-ci] -repository = "gimli-rs/findshlibs" +version = "0.2.104" +[build-dependencies.cc] +version = "1.0.67" +[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.lazy_static] +version = "1.4" +[target."cfg(target_os = \"windows\")".dependencies.winapi] +version = "0.3.9" +features = ["psapi", "memoryapi", "libloaderapi", "processthreadsapi"] diff -Nru rust-findshlibs-0.5.0/Cargo.toml.orig rust-findshlibs-0.10.2/Cargo.toml.orig --- rust-findshlibs-0.5.0/Cargo.toml.orig 1970-01-01 00:00:00.000000000 +0000 +++ rust-findshlibs-0.10.2/Cargo.toml.orig 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +1,24 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - [package] name = "findshlibs" -version = "0.5.0" -authors = ["Nick Fitzgerald "] +version = "0.10.2" description = "Find the set of shared libraries loaded in the current process with a cross platform API" documentation = "https://docs.rs/findshlibs" -readme = "./README.md" +edition = "2018" keywords = ["dyld", "dylib", "shared", "library", "dl_iterate_phdr"] -license = "Apache-2.0/MIT" +license = "MIT OR Apache-2.0" +readme = "./README.md" repository = "https://github.com/gimli-rs/findshlibs" -[dependencies.lazy_static] -version = "1.0.0" -[dependencies.libc] -version = "0.2.55" +[dependencies] +libc = "0.2.104" + +[build-dependencies] +# Only needed for Android, but cannot be target dependent +# https://github.com/rust-lang/cargo/issues/4932 +cc = "1.0.67" -[features] -nightly = [] -[badges.coveralls] -repository = "gimli-rs/findshlibs" +[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] +lazy_static = "1.4" -[badges.travis-ci] -repository = "gimli-rs/findshlibs" +[target.'cfg(target_os = "windows")'.dependencies] +winapi = { version = "0.3.9", features = ["psapi", "memoryapi", "libloaderapi", "processthreadsapi"] } diff -Nru rust-findshlibs-0.5.0/.cargo_vcs_info.json rust-findshlibs-0.10.2/.cargo_vcs_info.json --- rust-findshlibs-0.5.0/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 +++ rust-findshlibs-0.10.2/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +1,5 @@ { "git": { - "sha1": "c39efb3a846d8e84d99b2571b93afe3555fd5639" + "sha1": "83dbb5de60d46cecc368966171ec58e6f4f4277d" } } diff -Nru rust-findshlibs-0.5.0/ci/before_install.sh rust-findshlibs-0.10.2/ci/before_install.sh --- rust-findshlibs-0.5.0/ci/before_install.sh 2017-08-16 00:45:54.000000000 +0000 +++ rust-findshlibs-0.10.2/ci/before_install.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -# We always want backtraces for everything. -export RUST_BACKTRACE=1 - -case "$TRAVIS_OS_NAME" in - "osx") - brew update - brew install llvm@3.9 - export LIBCLANG_PATH=$(find /usr/local/Cellar/llvm -type f -name libclang.dylib | head -n 1) - export LIBCLANG_PATH=$(dirname $LIBCLANG_PATH) - ;; - - "linux") - export LIBCLANG_PATH=/usr/lib/llvm-3.9/lib - ;; - - *) - echo "Error: unknown \$TRAVIS_OS_NAME: $TRAVIS_OS_NAME" - exit 1 - ;; -esac diff -Nru rust-findshlibs-0.5.0/ci/script.sh rust-findshlibs-0.10.2/ci/script.sh --- rust-findshlibs-0.5.0/ci/script.sh 2018-04-13 22:23:46.000000000 +0000 +++ rust-findshlibs-0.10.2/ci/script.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -eux - -# We always want backtraces for everything. -export RUST_BACKTRACE=1 - -cargo build --examples $PROFILE -cargo test $PROFILE - -if [[ "$PROFILE" == "--release" ]]; then - cargo bench -fi diff -Nru rust-findshlibs-0.5.0/coverage rust-findshlibs-0.10.2/coverage --- rust-findshlibs-0.5.0/coverage 2017-08-15 17:35:52.000000000 +0000 +++ rust-findshlibs-0.10.2/coverage 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -# -# Usage: -# ./coverage -# -# Run kcov on the tests, and merge the results. -# -# Environment variables: -# TRAVIS_JOB_ID - id for coveralls, defaults to none -# KCOV - path to kcov, defaults to 'kcov' - -[ -n "$TRAVIS_JOB_ID" ] && COVERALLS_ID="--coveralls-id=$TRAVIS_JOB_ID" -[ -z "$KCOV" ] && KCOV=kcov - -# Rebuild tests with dead code included, and get a list of the filenames. -export RUSTFLAGS="-C link-dead-code" -TEST_FILES=$(cargo test 2>&1 >/dev/null | awk '/^ Running target\/debug\// { print $2 }') - -KCOV_OPTS="--verify --exclude-pattern=/.cargo" -OUT_DIR=target/kcov - -for f in $TEST_FILES; do - "$KCOV" $KCOV_OPTS "$OUT_DIR" $f -done -"$KCOV" --merge $KCOV_OPTS $COVERALLS_ID "$OUT_DIR" "$OUT_DIR" - diff -Nru rust-findshlibs-0.5.0/debian/cargo-checksum.json rust-findshlibs-0.10.2/debian/cargo-checksum.json --- rust-findshlibs-0.5.0/debian/cargo-checksum.json 2019-07-14 18:27:52.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/cargo-checksum.json 2022-08-21 02:39:41.000000000 +0000 @@ -1 +1 @@ -{"package":"Could not get crate checksum","files":{}} +{"package":"40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64","files":{}} diff -Nru rust-findshlibs-0.5.0/debian/changelog rust-findshlibs-0.10.2/debian/changelog --- rust-findshlibs-0.5.0/debian/changelog 2019-10-04 15:12:12.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/changelog 2022-08-21 02:39:41.000000000 +0000 @@ -1,8 +1,11 @@ -rust-findshlibs (0.5.0-1build1) eoan; urgency=medium +rust-findshlibs (0.10.2-1) unstable; urgency=medium - * No-change rebuild to drop i386 + * Team upload. + * Package findshlibs 0.10.2 from crates.io using debcargo 2.5.0 + * Drop no-nightly.patch - no longer needed. + * Exclude newly added file src/andriod-api.c - -- Steve Langasek Fri, 04 Oct 2019 15:12:12 +0000 + -- Peter Michael Green Sun, 21 Aug 2022 02:39:41 +0000 rust-findshlibs (0.5.0-1) unstable; urgency=medium diff -Nru rust-findshlibs-0.5.0/debian/compat rust-findshlibs-0.10.2/debian/compat --- rust-findshlibs-0.5.0/debian/compat 2019-07-14 18:27:52.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/compat 2022-08-21 02:39:41.000000000 +0000 @@ -1 +1 @@ -11 +12 diff -Nru rust-findshlibs-0.5.0/debian/control rust-findshlibs-0.10.2/debian/control --- rust-findshlibs-0.5.0/debian/control 2019-07-14 18:27:52.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/control 2022-08-21 02:39:41.000000000 +0000 @@ -1,36 +1,49 @@ Source: rust-findshlibs Section: rust Priority: optional -Build-Depends: debhelper (>= 11), - dh-cargo (>= 15), +Build-Depends: debhelper (>= 12), + dh-cargo (>= 25), cargo:native , rustc:native , libstd-rust-dev , - librust-lazy-static-1+default-dev , - librust-libc-0.2+default-dev (>= 0.2.55-~~) + librust-cc-1+default-dev (>= 1.0.67-~~) , + librust-lazy-static-1+default-dev (>= 1.4-~~) , + librust-libc-0.2+default-dev (>= 0.2.104-~~) , + librust-winapi-0.3+default-dev (>= 0.3.9-~~) , + librust-winapi-0.3+libloaderapi-dev (>= 0.3.9-~~) , + librust-winapi-0.3+memoryapi-dev (>= 0.3.9-~~) , + librust-winapi-0.3+processthreadsapi-dev (>= 0.3.9-~~) , + librust-winapi-0.3+psapi-dev (>= 0.3.9-~~) Maintainer: Debian Rust Maintainers Uploaders: Ximin Luo , kpcyrd -Standards-Version: 4.2.0 +Standards-Version: 4.5.1 Vcs-Git: https://salsa.debian.org/rust-team/debcargo-conf.git [src/findshlibs] Vcs-Browser: https://salsa.debian.org/rust-team/debcargo-conf/tree/master/src/findshlibs +Rules-Requires-Root: no Package: librust-findshlibs-dev Architecture: any Multi-Arch: same Depends: ${misc:Depends}, - librust-lazy-static-1+default-dev, - librust-libc-0.2+default-dev (>= 0.2.55-~~) + librust-cc-1+default-dev (>= 1.0.67-~~), + librust-lazy-static-1+default-dev (>= 1.4-~~), + librust-libc-0.2+default-dev (>= 0.2.104-~~), + librust-winapi-0.3+default-dev (>= 0.3.9-~~), + librust-winapi-0.3+libloaderapi-dev (>= 0.3.9-~~), + librust-winapi-0.3+memoryapi-dev (>= 0.3.9-~~), + librust-winapi-0.3+processthreadsapi-dev (>= 0.3.9-~~), + librust-winapi-0.3+psapi-dev (>= 0.3.9-~~) Provides: librust-findshlibs+default-dev (= ${binary:Version}), librust-findshlibs-0-dev (= ${binary:Version}), librust-findshlibs-0+default-dev (= ${binary:Version}), - librust-findshlibs-0.5-dev (= ${binary:Version}), - librust-findshlibs-0.5+default-dev (= ${binary:Version}), - librust-findshlibs-0.5.0-dev (= ${binary:Version}), - librust-findshlibs-0.5.0+default-dev (= ${binary:Version}) + librust-findshlibs-0.10-dev (= ${binary:Version}), + librust-findshlibs-0.10+default-dev (= ${binary:Version}), + librust-findshlibs-0.10.2-dev (= ${binary:Version}), + librust-findshlibs-0.10.2+default-dev (= ${binary:Version}) Description: Find shared libraries loaded in the current process - Rust source code This package contains the source for the Rust findshlibs crate, packaged by debcargo for use with cargo and dh-cargo. diff -Nru rust-findshlibs-0.5.0/debian/copyright rust-findshlibs-0.10.2/debian/copyright --- rust-findshlibs-0.5.0/debian/copyright 2019-07-14 18:27:52.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/copyright 2022-08-21 02:39:41.000000000 +0000 @@ -5,13 +5,13 @@ Files: * Copyright: - 2016-2018 Nick Fitzgerald + 2016-2021 Nick Fitzgerald 2015 The Rust Project Developers License: Apache-2.0 or MIT Files: debian/* Copyright: - 2018 Debian Rust Maintainers + 2018-2022 Debian Rust Maintainers 2018 Ximin Luo License: Apache-2.0 or MIT diff -Nru rust-findshlibs-0.5.0/debian/copyright.debcargo.hint rust-findshlibs-0.10.2/debian/copyright.debcargo.hint --- rust-findshlibs-0.5.0/debian/copyright.debcargo.hint 2019-07-14 18:27:52.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/copyright.debcargo.hint 2022-08-21 02:39:41.000000000 +0000 @@ -1,11 +1,11 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: findshlibs -Upstream-Contact: Nick Fitzgerald +Upstream-Contact: FIXME (overlay) UNKNOWN-AUTHORS Source: https://github.com/gimli-rs/findshlibs Files: * -Copyright: FIXME (overlay) UNKNOWN-YEARS Nick Fitzgerald -License: Apache-2.0 or MIT +Copyright: FIXME (overlay) UNKNOWN-AUTHORS FIXME (overlay) UNKNOWN-YEARS +License: MIT or Apache-2.0 Comment: FIXME (overlay): Since upstream copyright years are not available in Cargo.toml, they were extracted from the upstream Git repository. This may not @@ -21,10 +21,10 @@ Files: debian/* Copyright: - 2018-2019 Debian Rust Maintainers - 2018-2019 Ximin Luo - 2018-2019 kpcyrd -License: Apache-2.0 or MIT + 2018-2022 Debian Rust Maintainers + 2018-2022 Ximin Luo + 2018-2022 kpcyrd +License: MIT or Apache-2.0 License: Apache-2.0 Debian systems provide the Apache 2.0 license in diff -Nru rust-findshlibs-0.5.0/debian/debcargo.toml rust-findshlibs-0.10.2/debian/debcargo.toml --- rust-findshlibs-0.5.0/debian/debcargo.toml 2019-07-14 18:27:52.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/debcargo.toml 2022-08-21 02:39:41.000000000 +0000 @@ -3,6 +3,7 @@ "Ximin Luo ", "kpcyrd ", ] +excludes = ["src/android-api.c"] # The auto-generated summary is too long. summary = "Find shared libraries loaded in the current process" diff -Nru rust-findshlibs-0.5.0/debian/patches/no-nightly.patch rust-findshlibs-0.10.2/debian/patches/no-nightly.patch --- rust-findshlibs-0.5.0/debian/patches/no-nightly.patch 2019-07-14 18:27:52.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/patches/no-nightly.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -27,7 +27,6 @@ - version = "0.2.55" - - [features] --nightly = [] - [badges.coveralls] - repository = "gimli-rs/findshlibs" - diff -Nru rust-findshlibs-0.5.0/debian/patches/series rust-findshlibs-0.10.2/debian/patches/series --- rust-findshlibs-0.5.0/debian/patches/series 2019-07-14 18:27:52.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -no-nightly.patch diff -Nru rust-findshlibs-0.5.0/debian/rules rust-findshlibs-0.10.2/debian/rules --- rust-findshlibs-0.5.0/debian/rules 2019-07-14 18:27:52.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/rules 2022-08-21 02:39:41.000000000 +0000 @@ -1,3 +1,6 @@ #!/usr/bin/make -f %: dh $@ --buildsystem cargo + +override_dh_auto_test: + dh_auto_test -- test --all diff -Nru rust-findshlibs-0.5.0/debian/tests/control rust-findshlibs-0.10.2/debian/tests/control --- rust-findshlibs-0.5.0/debian/tests/control 1970-01-01 00:00:00.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/tests/control 2022-08-21 02:39:41.000000000 +0000 @@ -0,0 +1,14 @@ +Test-Command: /usr/share/cargo/bin/cargo-auto-test findshlibs 0.10.2 --all-targets --all-features +Features: test-name=rust-findshlibs:@ +Depends: dh-cargo (>= 18), @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test findshlibs 0.10.2 --all-targets +Features: test-name=librust-findshlibs-dev:default +Depends: dh-cargo (>= 18), @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test findshlibs 0.10.2 --all-targets --no-default-features +Features: test-name=librust-findshlibs-dev: +Depends: dh-cargo (>= 18), @ +Restrictions: allow-stderr, skip-not-installable diff -Nru rust-findshlibs-0.5.0/debian/watch rust-findshlibs-0.10.2/debian/watch --- rust-findshlibs-0.5.0/debian/watch 2019-07-14 18:27:52.000000000 +0000 +++ rust-findshlibs-0.10.2/debian/watch 2022-08-21 02:39:41.000000000 +0000 @@ -2,4 +2,3 @@ opts=filenamemangle=s/.*\/(.*)\/download/findshlibs-$1\.tar\.gz/g,\ uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/ \ https://qa.debian.org/cgi-bin/fakeupstream.cgi?upstream=crates.io/findshlibs .*/crates/findshlibs/@ANY_VERSION@/download - diff -Nru rust-findshlibs-0.5.0/.github/dependabot.yml rust-findshlibs-0.10.2/.github/dependabot.yml --- rust-findshlibs-0.5.0/.github/dependabot.yml 1970-01-01 00:00:00.000000000 +0000 +++ rust-findshlibs-0.10.2/.github/dependabot.yml 1970-01-01 00:00:00.000000000 +0000 @@ -0,0 +1,7 @@ +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 diff -Nru rust-findshlibs-0.5.0/.github/workflows/main.yml rust-findshlibs-0.10.2/.github/workflows/main.yml --- rust-findshlibs-0.5.0/.github/workflows/main.yml 1970-01-01 00:00:00.000000000 +0000 +++ rust-findshlibs-0.10.2/.github/workflows/main.yml 1970-01-01 00:00:00.000000000 +0000 @@ -0,0 +1,44 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + test: + strategy: + matrix: + os: ["ubuntu-latest", "macos-latest", "windows-latest"] + rust: ["stable", "beta", "nightly", "1.34.0"] + runs-on: ${{matrix.os}} + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Install rust + run: | + rustup install ${{matrix.rust}} + rustup default ${{matrix.rust}} + - name: Test debug + run: cargo test --verbose + - name: Test release + run: cargo test --verbose --release + + rustfmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install rust + run: | + rustup install stable + rustup default stable + rustup component add rustfmt + - run: cargo fmt --all -- --check + + doc: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: cargo doc diff -Nru rust-findshlibs-0.5.0/README.md rust-findshlibs-0.10.2/README.md --- rust-findshlibs-0.5.0/README.md 2018-04-13 22:24:35.000000000 +0000 +++ rust-findshlibs-0.10.2/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +1,8 @@ # `findshlibs` -[![](http://meritbadge.herokuapp.com/findshlibs) ![](https://img.shields.io/crates/d/findshlibs.png)](https://crates.io/crates/findshlibs) [![Build Status](https://travis-ci.org/gimli-rs/findshlibs.png?branch=master)](https://travis-ci.org/gimli-rs/findshlibs) [![Coverage Status](https://coveralls.io/repos/github/gimli-rs/findshlibs/badge.svg?branch=master)](https://coveralls.io/github/gimli-rs/findshlibs?branch=master) +[![](https://img.shields.io/crates/v/findshlibs.svg)](https://crates.io/crates/findshlibs) +[![](https://docs.rs/findshlibs/badge.svg)](https://docs.rs/findshlibs) +[![Build Status](https://github.com/gimli-rs/findshlibs/workflows/CI/badge.svg)](https://github.com/gimli-rs/findshlibs/actions) Find the shared libraries loaded in the current process with a cross platform API. @@ -38,6 +40,9 @@ * Linux * macOS +* Windows +* Android +* iOS If a platform is not supported then a fallback implementation is used that does nothing. To see if your platform does something at runtime the diff -Nru rust-findshlibs-0.5.0/src/lib.rs rust-findshlibs-0.10.2/src/lib.rs --- rust-findshlibs-0.5.0/src/lib.rs 2019-06-03 21:47:06.000000000 +0000 +++ rust-findshlibs-0.10.2/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 @@ -35,6 +35,9 @@ //! //! * Linux //! * macOS +//! * Windows +//! * Android +//! * iOS //! //! If a platform is not supported then a fallback implementation is used that //! does nothing. To see if your platform does something at runtime the @@ -73,35 +76,64 @@ //! > text section (for example), we can compute the AVMAs of all of //! > its text symbols by adding the bias to their SVMAs. //! -//! [LUL]: http://searchfox.org/mozilla-central/rev/13148faaa91a1c823a7d68563d9995480e714979/tools/profiler/lul/LulMain.h#17-51 +//! [LUL]: https://searchfox.org/mozilla-central/rev/13148faaa91a1c823a7d68563d9995480e714979/tools/profiler/lul/LulMain.h#17-51 +//! +//! ## Names and IDs +//! +//! `findshlibs` also gives access to module names and IDs. Since this is also +//! not consistent across operating systems the following general rules apply: +//! +//! > * `id` refers to the ID of the object file itself. This is generally +//! > available on all platforms however it might still not be compiled into +//! > the binary in all case. For instance on Linux the `gnu.build-id` note +//! > needs to be compiled in (which Rust does automatically). +//! > * `debug_id` refers to the ID of the debug file. This only plays a role +//! > on Windows where the executable and the debug file (PDB) have a different +//! > ID. +//! > * `name` is the name of the executable. On most operating systems (and +//! > all systems implemented currently) this is not just the name but in fact +//! > the entire path to the executable. +//! > * `debug_name` is the name of the debug file if known. This is again +//! > the case on windows where this will be the path to the PDB file. #![deny(missing_docs)] -#[cfg(target_os = "macos")] -#[macro_use] -extern crate lazy_static; - -#[cfg(any(target_os = "linux", target_os = "macos"))] -extern crate libc; - -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] 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")] +pub mod windows; + use std::ffi::OsStr; use std::fmt::{self, Debug}; -use std::ptr; +use std::usize; pub mod unsupported; -#[cfg(target_os = "linux")] -use linux as native_mod; - -#[cfg(target_os = "macos")] -use macos as native_mod; - -#[cfg(not(any(target_os = "macos", target_os = "linux")))] +#[cfg(any( + target_os = "linux", + all(target_os = "android", feature = "dl_iterate_phdr") +))] +use crate::linux as native_mod; + +#[cfg(any(target_os = "macos", target_os = "ios"))] +use crate::macos as native_mod; + +#[cfg(target_os = "windows")] +use crate::windows as native_mod; + +#[cfg(not(any( + target_os = "macos", + target_os = "ios", + 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) @@ -109,7 +141,13 @@ pub type TargetSharedLibrary<'a> = native_mod::SharedLibrary<'a>; /// An indicator if this platform is supported. -pub const TARGET_SUPPORTED: bool = cfg!(any(target_os = "macos", target_os = "linux")); +pub const TARGET_SUPPORTED: bool = cfg!(any( + target_os = "macos", + target_os = "ios", + target_os = "linux", + all(target_os = "android", feature = "dl_iterate_phdr"), + target_os = "windows" +)); macro_rules! simple_newtypes { ( @@ -158,23 +196,23 @@ /// Stated virtual memory address. /// /// See the module documentation for details. - type Svma = *const u8 + type Svma = usize where - default = ptr::null(), - display = "{:p}"; + default = 0, + display = "{:#x}"; /// Actual virtual memory address. /// /// See the module documentation for details. - type Avma = *const u8 + type Avma = usize where - default = ptr::null(), - display = "{:p}"; + default = 0, + display = "{:#x}"; /// Virtual memory bias. /// /// See the module documentation for details. - type Bias = isize + type Bias = usize where default = 0, display = "{:#x}"; @@ -195,6 +233,12 @@ false } + /// Returns `true` if this is a segment loaded into memory. + #[inline] + fn is_load(&self) -> bool { + self.is_code() + } + /// Get this segment's stated virtual address of this segment. /// /// This is the virtual memory address without the bias applied. See the @@ -214,24 +258,24 @@ fn actual_virtual_memory_address(&self, shlib: &Self::SharedLibrary) -> Avma { let svma = self.stated_virtual_memory_address(); let bias = shlib.virtual_memory_bias(); - Avma(unsafe { svma.0.offset(bias.0) }) + Avma(svma.0 + bias.0) } /// Does this segment contain the given address? #[inline] fn contains_svma(&self, address: Svma) -> bool { - let start = self.stated_virtual_memory_address().0 as usize; + let start = self.stated_virtual_memory_address().0; let end = start + self.len(); - let address = address.0 as usize; + let address = address.0; start <= address && address < end } /// Does this segment contain the given address? #[inline] fn contains_avma(&self, shlib: &Self::SharedLibrary, address: Avma) -> bool { - let start = self.actual_virtual_memory_address(shlib).0 as usize; + let start = self.actual_virtual_memory_address(shlib).0; let end = start + self.len(); - let address = address.0 as usize; + let address = address.0; start <= address && address < end } } @@ -243,6 +287,10 @@ Uuid([u8; 16]), /// A GNU build ID GnuBuildId(Vec), + /// The PE timestamp and size + PeSignature(u32, u32), + /// A PDB GUID and age, + PdbSignature([u8; 16], u32), } impl SharedLibraryId { @@ -250,22 +298,41 @@ pub fn as_bytes(&self) -> &[u8] { match *self { SharedLibraryId::Uuid(ref bytes) => &*bytes, - SharedLibraryId::GnuBuildId(ref bytes) => &bytes, + SharedLibraryId::GnuBuildId(ref bytes) => bytes, + SharedLibraryId::PeSignature(_, _) => &[][..], + SharedLibraryId::PdbSignature(ref bytes, _) => &*bytes, } } } impl fmt::Display for SharedLibraryId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (bytes, is_uuid): (&[u8], _) = match *self { - SharedLibraryId::Uuid(ref bytes) => (&*bytes, true), - SharedLibraryId::GnuBuildId(ref bytes) => (&bytes, false), - }; - for (idx, byte) in bytes.iter().enumerate() { - if is_uuid && (idx == 4 || idx == 6 || idx == 8 || idx == 10) { - try!(write!(f, "-")); + match *self { + SharedLibraryId::Uuid(ref bytes) => { + for (idx, byte) in bytes.iter().enumerate() { + if idx == 4 || idx == 6 || idx == 8 || idx == 10 { + write!(f, "-")?; + } + write!(f, "{:02x}", byte)?; + } + } + SharedLibraryId::GnuBuildId(ref bytes) => { + for byte in bytes { + write!(f, "{:02x}", byte)?; + } + } + SharedLibraryId::PeSignature(timestamp, size_of_image) => { + write!(f, "{:08X}{:x}", timestamp, size_of_image)?; + } + SharedLibraryId::PdbSignature(ref bytes, age) => { + for (idx, byte) in bytes.iter().enumerate() { + if idx == 4 || idx == 6 || idx == 8 || idx == 10 { + write!(f, "-")?; + } + write!(f, "{:02X}", byte)?; + } + write!(f, "{:x}", age)?; } - try!(write!(f, "{:02x}", byte)); } Ok(()) } @@ -273,19 +340,18 @@ impl fmt::Debug for SharedLibraryId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - SharedLibraryId::Uuid(..) => { - write!(f, "Uuid(\"{}\")", self)?; - } - SharedLibraryId::GnuBuildId(..) => { - write!(f, "GnuBuildId(\"{}\")", self)?; - } - } - Ok(()) + let name = match *self { + SharedLibraryId::Uuid(..) => "Uuid", + SharedLibraryId::GnuBuildId(..) => "GnuBuildId", + SharedLibraryId::PeSignature(..) => "PeSignature", + SharedLibraryId::PdbSignature(..) => "PdbSignature", + }; + write!(f, "{}(\"{}\")", name, self) } } /// A trait representing a shared library that is loaded in this process. +#[allow(clippy::len_without_is_empty)] pub trait SharedLibrary: Sized + Debug { /// The associated segment type for this shared library. type Segment: Segment; @@ -296,9 +362,66 @@ /// Get the name of this shared library. fn name(&self) -> &OsStr; - /// Get the debug-id of this shared library if available. + /// Get the name of the debug file with this shared library if there is one. + fn debug_name(&self) -> Option<&OsStr> { + None + } + + /// Get the code-id of this shared library if available. fn id(&self) -> Option; + /// Get the debug-id of this shared library if available. + fn debug_id(&self) -> Option { + self.id() + } + + /// Returns the address of where the library is loaded into virtual + /// memory. + /// + /// This address maps to the `Avma` of the first segment loaded into + /// memory. Depending on the platform, this segment may not contain code. + fn actual_load_addr(&self) -> Avma { + self.segments() + .find(|x| x.is_load()) + .map(|x| x.actual_virtual_memory_address(self)) + .unwrap_or(Avma(usize::MAX)) + } + + #[inline] + #[doc(hidden)] + #[deprecated(note = "use stated_load_address() instead")] + fn load_addr(&self) -> Svma { + self.stated_load_addr() + } + + /// Returns the address of where the library prefers to be loaded into + /// virtual memory. + /// + /// This address maps to the `Svma` of the first segment loaded into + /// memory. Depending on the platform, this segment may not contain code. + fn stated_load_addr(&self) -> Svma { + self.segments() + .find(|x| x.is_load()) + .map(|x| x.stated_virtual_memory_address()) + .unwrap_or(Svma(usize::MAX)) + } + + /// Returns the size of the image. + /// + /// This typically is the size of the executable code segment. This is + /// normally used by server side symbolication systems to determine when + /// an IP no longer falls into an image. + fn len(&self) -> usize { + let end_address = self + .segments() + .filter(|x| x.is_load()) + .map(|x| x.actual_virtual_memory_address(self).0 + x.len()) + .max() + .unwrap_or(usize::MAX); + + end_address - self.actual_load_addr().0 + } + /// Iterate over this shared library's segments. fn segments(&self) -> Self::SegmentIter; @@ -312,8 +435,7 @@ #[inline] fn avma_to_svma(&self, address: Avma) -> Svma { let bias = self.virtual_memory_bias(); - let reverse_bias = -bias.0; - Svma(unsafe { address.0.offset(reverse_bias) }) + Svma(address.0 - bias.0) } /// Find all shared libraries in this process and invoke `f` with each one. @@ -360,4 +482,13 @@ } } } + + #[test] + fn test_load_address_bias() { + TargetSharedLibrary::each(|lib| { + let svma = lib.stated_load_addr(); + let avma = lib.actual_load_addr(); + assert_eq!(lib.avma_to_svma(avma), svma); + }); + } } diff -Nru rust-findshlibs-0.5.0/src/linux/mod.rs rust-findshlibs-0.10.2/src/linux/mod.rs --- rust-findshlibs-0.5.0/src/linux/mod.rs 2019-06-03 21:47:06.000000000 +0000 +++ rust-findshlibs-0.10.2/src/linux/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +1,24 @@ //! Linux-specific implementation of the `SharedLibrary` trait. -use super::Segment as SegmentTrait; -use super::SharedLibrary as SharedLibraryTrait; -use super::{Bias, IterationControl, SharedLibraryId, Svma}; +use libc; + +use crate::Segment as SegmentTrait; +use crate::SharedLibrary as SharedLibraryTrait; +use crate::{Bias, IterationControl, SharedLibraryId, Svma}; use std::any::Any; use std::borrow::Cow; use std::env::current_exe; use std::ffi::{CStr, CString, OsStr}; use std::fmt; -use std::isize; +use std::iter; use std::marker::PhantomData; use std::mem; use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStringExt; use std::panic; use std::slice; - -use libc; +use std::usize; #[cfg(target_pointer_width = "32")] type Phdr = libc::Elf32_Phdr; @@ -27,7 +28,12 @@ const NT_GNU_BUILD_ID: u32 = 3; -struct Nhdr32 { +// 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 +// used, and reading through binutil's `readelf` source confirms this. +#[repr(C)] +#[derive(Debug, Clone, Copy)] +struct Nhdr { pub n_namesz: libc::Elf32_Word, pub n_descsz: libc::Elf32_Word, pub n_type: libc::Elf32_Word, @@ -37,11 +43,103 @@ #[derive(Debug)] pub struct Segment<'a> { phdr: *const Phdr, - shlib: PhantomData<&'a ::linux::SharedLibrary<'a>>, + shlib: PhantomData<&'a SharedLibrary<'a>>, +} + +impl<'a> Segment<'a> { + fn phdr(&self) -> &'a Phdr { + unsafe { self.phdr.as_ref().unwrap() } + } + + /// You must pass this segment's `SharedLibrary` or else this is wild UB. + unsafe fn data(&self, shlib: &SharedLibrary<'a>) -> &'a [u8] { + let phdr = self.phdr(); + let avma = (shlib.addr as usize).wrapping_add(phdr.p_vaddr as usize); + slice::from_raw_parts(avma as *const u8, phdr.p_memsz as usize) + } + + fn is_note(&self) -> bool { + self.phdr().p_type == libc::PT_NOTE + } + + /// Parse the contents of a `PT_NOTE` segment. + /// + /// Returns a triple of + /// + /// 1. The `NT_*` note type. + /// 2. The note name. + /// 3. The note descriptor payload. + /// + /// You must pass this segment's `SharedLibrary` or else this is wild UB. + unsafe fn notes( + &self, + shlib: &SharedLibrary<'a>, + ) -> impl Iterator { + // `man 5 readelf` says that all of the `Nhdr`, name, and descriptor are + // always 4-byte aligned, but we copy this alignment behavior from + // `readelf` since that seems to match reality in practice. + let alignment = std::cmp::max(self.phdr().p_align as usize, 4); + let align_up = move |data: &'a [u8]| { + if alignment != 4 && alignment != 8 { + return None; + } + + let ptr = data.as_ptr() as usize; + let alignment_minus_one = alignment - 1; + let aligned_ptr = ptr.checked_add(alignment_minus_one)? & !alignment_minus_one; + let diff = aligned_ptr - ptr; + if data.len() < diff { + None + } else { + Some(&data[diff..]) + } + }; + + let mut data = self.data(shlib); + + iter::from_fn(move || { + if (data.as_ptr() as usize % alignment) != 0 { + return None; + } + + // Each entry in a `PT_NOTE` segment begins with a + // fixed-size header `Nhdr`. + let nhdr_size = mem::size_of::(); + let nhdr = try_split_at(&mut data, nhdr_size)?; + let nhdr = (nhdr.as_ptr() as *const Nhdr).as_ref().unwrap(); + + // No need to `align_up` after the `Nhdr` + // It is followed by a name of size `n_namesz`. + let name_size = nhdr.n_namesz as usize; + let name = try_split_at(&mut data, name_size)?; + + // And after that is the note's (aligned) descriptor payload of size + // `n_descsz`. + data = align_up(data)?; + let desc_size = nhdr.n_descsz as usize; + let desc = try_split_at(&mut data, desc_size)?; + + // Align the data for the next `Nhdr`. + data = align_up(data)?; + + Some((nhdr.n_type, name, desc)) + }) + .fuse() + } +} + +fn try_split_at<'a>(data: &mut &'a [u8], index: usize) -> Option<&'a [u8]> { + if data.len() < index { + None + } else { + let (head, tail) = data.split_at(index); + *data = tail; + Some(head) + } } impl<'a> SegmentTrait for Segment<'a> { - type SharedLibrary = ::linux::SharedLibrary<'a>; + type SharedLibrary = SharedLibrary<'a>; fn name(&self) -> &str { unsafe { @@ -51,11 +149,9 @@ libc::PT_DYNAMIC => "DYNAMIC", libc::PT_INTERP => "INTERP", libc::PT_NOTE => "NOTE", - libc::PT_SHLIB => "SHLI", + libc::PT_SHLIB => "SHLIB", 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", @@ -66,30 +162,30 @@ #[inline] fn is_code(&self) -> bool { - unsafe { - let hdr = self.phdr.as_ref().unwrap(); - match hdr.p_type { - // 0x1 is PT_X for executable - libc::PT_LOAD => (hdr.p_flags & 0x1) != 0, - _ => false, - } - } + let hdr = self.phdr(); + // 0x1 is PT_X for executable + hdr.p_type == libc::PT_LOAD && (hdr.p_flags & 0x1) != 0 + } + + #[inline] + fn is_load(&self) -> bool { + self.phdr().p_type == libc::PT_LOAD } #[inline] fn stated_virtual_memory_address(&self) -> Svma { - Svma(unsafe { (*self.phdr).p_vaddr as _ }) + Svma(self.phdr().p_vaddr as _) } #[inline] fn len(&self) -> usize { - unsafe { (*self.phdr).p_memsz as _ } + self.phdr().p_memsz as _ } } /// An iterator of mapped segments in a shared library. pub struct SegmentIter<'a> { - inner: ::std::slice::Iter<'a, Phdr>, + inner: std::slice::Iter<'a, Phdr>, } impl<'a> Iterator for SegmentIter<'a> { @@ -124,7 +220,7 @@ struct IterState { f: F, - panic: Option>, + panic: Option>, idx: usize, } @@ -175,6 +271,10 @@ F: FnMut(&Self) -> C, C: Into, { + if (*info).dlpi_phdr.is_null() { + return CONTINUE; + } + let state = &mut *(state as *mut IterState); state.idx += 1; @@ -192,6 +292,10 @@ } } } + + fn note_segments(&self) -> impl Iterator> { + self.segments().filter(|s| s.is_note()) + } } impl<'a> SharedLibraryTrait for SharedLibrary<'a> { @@ -204,46 +308,14 @@ } fn id(&self) -> Option { - fn align(alignment: usize, offset: &mut usize) { - let diff = *offset % alignment; - if diff != 0 { - *offset += alignment - diff; - } - } - - unsafe { - for segment in self.segments() { - let phdr = segment.phdr.as_ref().unwrap(); - if phdr.p_type != libc::PT_NOTE { - continue; - } - - let mut alignment = phdr.p_align as usize; - // same logic as in gimli which took it from readelf - if alignment < 4 { - alignment = 4; - } else if alignment != 4 && alignment != 8 { - continue; - } - - let mut offset = phdr.p_offset as usize; - let end = offset + phdr.p_filesz as usize; - - while offset < end { - // we always use an nhdr32 here as 64bit notes have not - // been observed in practice. - let nhdr = &*((self.addr as usize + offset) as *const Nhdr32); - offset += mem::size_of_val(nhdr); - offset += nhdr.n_namesz as usize; - align(alignment, &mut offset); - let value = - slice::from_raw_parts(self.addr.add(offset), nhdr.n_descsz as usize); - offset += nhdr.n_descsz as usize; - align(alignment, &mut offset); - - if nhdr.n_type as u32 == NT_GNU_BUILD_ID { - return Some(SharedLibraryId::GnuBuildId(value.to_vec())); - } + // Search for `PT_NOTE` segments, containing auxilliary information. + // Such segments contain a series of "notes" and one kind of note is + // `NT_GNU_BUILD_ID`, whose payload contains a unique identifier + // generated by the linker. Return the first one we find, if any. + for segment in self.note_segments() { + for (note_type, note_name, note_descriptor) in unsafe { segment.notes(self) } { + if note_type == NT_GNU_BUILD_ID && note_name == b"GNU\0" { + return Some(SharedLibraryId::GnuBuildId(note_descriptor.to_vec())); } } } @@ -260,8 +332,7 @@ #[inline] fn virtual_memory_bias(&self) -> Bias { - assert!((self.addr as usize) < (isize::MAX as usize)); - Bias(self.addr as usize as isize) + Bias(self.addr as usize) } #[inline] @@ -332,8 +403,8 @@ #[cfg(test)] mod tests { - use super::super::{IterationControl, Segment, SharedLibrary}; - use linux; + use crate::linux; + use crate::{IterationControl, Segment, SharedLibrary}; #[test] fn have_libc() { @@ -382,11 +453,12 @@ } }); - 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; diff -Nru rust-findshlibs-0.5.0/src/macos/bindings.h rust-findshlibs-0.10.2/src/macos/bindings.h --- rust-findshlibs-0.5.0/src/macos/bindings.h 2017-08-15 17:35:52.000000000 +0000 +++ rust-findshlibs-0.10.2/src/macos/bindings.h 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -#include diff -Nru rust-findshlibs-0.5.0/src/macos/bindings.rs rust-findshlibs-0.10.2/src/macos/bindings.rs --- rust-findshlibs-0.5.0/src/macos/bindings.rs 2019-06-03 16:54:33.000000000 +0000 +++ rust-findshlibs-0.10.2/src/macos/bindings.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -#![allow(non_snake_case)] -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![allow(clippy::unreadable_literal)] - -include!(concat!(env!("OUT_DIR"), "/macos_bindings.rs")); diff -Nru rust-findshlibs-0.5.0/src/macos/mod.rs rust-findshlibs-0.10.2/src/macos/mod.rs --- rust-findshlibs-0.5.0/src/macos/mod.rs 2019-06-03 21:47:06.000000000 +0000 +++ rust-findshlibs-0.10.2/src/macos/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -2,9 +2,12 @@ //! trait](../trait.SharedLibrary.html). #![allow(clippy::cast_ptr_alignment)] -use super::Segment as SegmentTrait; -use super::SharedLibrary as SharedLibraryTrait; -use super::{Bias, IterationControl, SharedLibraryId, Svma}; +use lazy_static::lazy_static; +use libc; + +use crate::Segment as SegmentTrait; +use crate::SharedLibrary as SharedLibraryTrait; +use crate::{Bias, IterationControl, SharedLibraryId, Svma}; use std::ffi::{CStr, OsStr}; use std::fmt; @@ -13,8 +16,6 @@ use std::sync::Mutex; use std::usize; -use libc; - const LC_UUID: u32 = 27; #[repr(C)] @@ -53,7 +54,7 @@ } impl<'a> SegmentTrait for Segment<'a> { - type SharedLibrary = ::macos::SharedLibrary<'a>; + type SharedLibrary = SharedLibrary<'a>; #[inline] fn name(&self) -> &str { @@ -72,10 +73,10 @@ #[inline] fn stated_virtual_memory_address(&self) -> Svma { match *self { - Segment::Segment32(seg) => Svma(seg.vmaddr as usize as *const u8), + Segment::Segment32(seg) => Svma(seg.vmaddr as usize), Segment::Segment64(seg) => { assert!(seg.vmaddr <= (usize::MAX as u64)); - Svma(seg.vmaddr as usize as *const u8) + Svma(seg.vmaddr as usize) } } } @@ -198,7 +199,7 @@ /// `` header. pub struct SharedLibrary<'a> { header: MachHeader<'a>, - slide: isize, + slide: usize, name: &'a CStr, } @@ -212,7 +213,7 @@ } impl<'a> SharedLibrary<'a> { - fn new(header: MachHeader<'a>, slide: isize, name: &'a CStr) -> Self { + fn new(header: MachHeader<'a>, slide: usize, name: &'a CStr) -> Self { SharedLibrary { header: header, slide: slide, @@ -286,16 +287,12 @@ if let Some(header) = unsafe { MachHeader::from_header_ptr(header) } { assert!( - slide != 0, - "If we have a header pointer, slide should be valid" - ); - assert!( !name.is_null(), "If we have a header pointer, name should be valid" ); let name = unsafe { CStr::from_ptr(name) }; - let shlib = SharedLibrary::new(header, slide, name); + let shlib = SharedLibrary::new(header, slide as usize, name); match f(&shlib).into() { IterationControl::Break => break, @@ -308,8 +305,8 @@ #[cfg(test)] mod tests { - use super::super::{IterationControl, Segment, SharedLibrary}; - use macos; + use crate::macos; + use crate::{IterationControl, Segment, SharedLibrary}; #[test] fn have_libdyld() { diff -Nru rust-findshlibs-0.5.0/src/unsupported.rs rust-findshlibs-0.10.2/src/unsupported.rs --- rust-findshlibs-0.5.0/src/unsupported.rs 2019-06-03 16:54:33.000000000 +0000 +++ rust-findshlibs-0.10.2/src/unsupported.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +1,9 @@ //! The fallback implementation of the [SharedLibrary //! trait](../trait.SharedLibrary.html) that does nothing. -use super::Segment as SegmentTrait; -use super::SharedLibrary as SharedLibraryTrait; -use super::{Bias, IterationControl, SharedLibraryId, Svma}; +use crate::Segment as SegmentTrait; +use crate::SharedLibrary as SharedLibraryTrait; +use crate::{Bias, IterationControl, SharedLibraryId, Svma}; use std::ffi::OsStr; use std::marker::PhantomData; @@ -16,7 +16,7 @@ } impl<'a> SegmentTrait for Segment<'a> { - type SharedLibrary = ::unsupported::SharedLibrary<'a>; + type SharedLibrary = SharedLibrary<'a>; #[inline] fn name(&self) -> &str { diff -Nru rust-findshlibs-0.5.0/src/windows/mod.rs rust-findshlibs-0.10.2/src/windows/mod.rs --- rust-findshlibs-0.5.0/src/windows/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-findshlibs-0.10.2/src/windows/mod.rs 1970-01-01 00:00:00.000000000 +0000 @@ -0,0 +1,397 @@ +//! Windows-specific implementation of the `SharedLibrary` trait. + +use crate::Segment as SegmentTrait; +use crate::SharedLibrary as SharedLibraryTrait; +use crate::{Bias, IterationControl, SharedLibraryId, Svma}; + +use std::ffi::{CStr, OsStr, OsString}; +use std::fmt; +use std::marker::PhantomData; +use std::mem; +use std::os::windows::ffi::OsStringExt; +use std::ptr; +use std::slice; +use std::usize; + +use winapi::ctypes::c_char; +use winapi::shared::minwindef::{HMODULE, MAX_PATH}; +use winapi::um::libloaderapi::{FreeLibrary, LoadLibraryExW, LOAD_LIBRARY_AS_DATAFILE}; +use winapi::um::memoryapi::VirtualQuery; +use winapi::um::processthreadsapi::GetCurrentProcess; +use winapi::um::psapi::{ + EnumProcessModules, GetModuleFileNameExW, GetModuleInformation, MODULEINFO, +}; +use winapi::um::winnt::{ + IMAGE_DEBUG_DIRECTORY, IMAGE_DEBUG_TYPE_CODEVIEW, IMAGE_DIRECTORY_ENTRY_DEBUG, + IMAGE_DOS_HEADER, IMAGE_DOS_SIGNATURE, IMAGE_NT_HEADERS, IMAGE_NT_SIGNATURE, + IMAGE_SCN_CNT_CODE, IMAGE_SECTION_HEADER, MEMORY_BASIC_INFORMATION, MEM_COMMIT, +}; + +// This is 'RSDS'. +const CV_SIGNATURE: u32 = 0x5344_5352; + +/// An unsupported segment +pub struct Segment<'a> { + section: &'a IMAGE_SECTION_HEADER, +} + +impl<'a> fmt::Debug for Segment<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Segment") + .field("name", &self.name()) + .field("is_code", &self.is_code()) + .finish() + } +} + +impl<'a> SegmentTrait for Segment<'a> { + type SharedLibrary = SharedLibrary<'a>; + + #[inline] + fn name(&self) -> &str { + std::str::from_utf8(&self.section.Name) + .unwrap_or("") + .trim_end_matches('\0') + } + + fn is_code(&self) -> bool { + (self.section.Characteristics & IMAGE_SCN_CNT_CODE) != 0 + } + + #[inline] + fn stated_virtual_memory_address(&self) -> Svma { + Svma(self.section.VirtualAddress as usize) + } + + #[inline] + fn len(&self) -> usize { + *unsafe { self.section.Misc.VirtualSize() } as usize + } +} + +/// An iterator over PE sections. +pub struct SegmentIter<'a> { + sections: std::slice::Iter<'a, IMAGE_SECTION_HEADER>, +} + +impl<'a> fmt::Debug for SegmentIter<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SegmentIter").finish() + } +} + +impl<'a> Iterator for SegmentIter<'a> { + type Item = Segment<'a>; + + fn next(&mut self) -> Option { + self.sections.next().map(|section| Segment { section }) + } +} + +#[repr(C)] +struct CodeViewRecord70 { + signature: u32, + pdb_signature: [u8; 16], + pdb_age: u32, + // This struct has a flexible array containing a UTF-8 \0-terminated string. + // This is only represented by its first byte here. + pdb_filename: c_char, +} + +/// A shared library on Windows. +pub struct SharedLibrary<'a> { + module_info: MODULEINFO, + module_name: OsString, + phantom: PhantomData<&'a ()>, +} + +impl<'a> fmt::Debug for SharedLibrary<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SharedLibrary") + .field("module_base", &self.module_base()) + .field("name", &self.name()) + .field("debug_name", &self.debug_name()) + .field("id", &self.id()) + .field("debug_id", &self.debug_id()) + .finish() + } +} + +impl<'a> SharedLibrary<'a> { + fn new(module_info: MODULEINFO, module_name: OsString) -> SharedLibrary<'a> { + SharedLibrary { + module_info, + module_name, + phantom: PhantomData, + } + } + + #[inline] + fn module_base(&self) -> *const c_char { + self.module_info.lpBaseOfDll as *const c_char + } + + fn dos_header(&self) -> Option<&IMAGE_DOS_HEADER> { + let header: &IMAGE_DOS_HEADER = unsafe { &*(self.module_base() as *const _) }; + if header.e_magic == IMAGE_DOS_SIGNATURE { + Some(header) + } else { + None + } + } + + fn nt_headers(&self) -> Option<&IMAGE_NT_HEADERS> { + self.dos_header().and_then(|dos_header| { + let nt_headers: &IMAGE_NT_HEADERS = + unsafe { &*(self.module_base().offset(dos_header.e_lfanew as isize) as *const _) }; + if nt_headers.Signature == IMAGE_NT_SIGNATURE { + Some(nt_headers) + } else { + None + } + }) + } + + fn debug_directories(&self) -> &[IMAGE_DEBUG_DIRECTORY] { + self.nt_headers().map_or(&[], |nt_headers| { + if nt_headers.OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_DEBUG as u32 { + return &[]; + } + let data_dir = + nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG as usize]; + if data_dir.VirtualAddress == 0 { + return &[]; + } + let size = data_dir.Size as usize; + if size % mem::size_of::() != 0 { + return &[]; + } + let nb_dirs = size / mem::size_of::(); + unsafe { + slice::from_raw_parts( + self.module_base().offset(data_dir.VirtualAddress as isize) as *const _, + nb_dirs, + ) + } + }) + } + + fn codeview_record70(&self) -> Option<&CodeViewRecord70> { + self.debug_directories().iter().find_map(|debug_directory| { + if debug_directory.Type != IMAGE_DEBUG_TYPE_CODEVIEW { + return None; + } + + let debug_info: &CodeViewRecord70 = unsafe { + &*(self + .module_base() + .offset(debug_directory.AddressOfRawData as isize) + as *const _) + }; + if debug_info.signature == CV_SIGNATURE { + Some(debug_info) + } else { + None + } + }) + } +} + +impl<'a> SharedLibraryTrait for SharedLibrary<'a> { + type Segment = Segment<'a>; + type SegmentIter = SegmentIter<'a>; + + #[inline] + fn name(&self) -> &OsStr { + &self.module_name + } + + #[inline] + fn debug_name(&self) -> Option<&OsStr> { + self.codeview_record70().and_then(|codeview| { + let cstr = unsafe { CStr::from_ptr(&codeview.pdb_filename as *const _) }; + if let Ok(s) = cstr.to_str() { + Some(OsStr::new(s)) + } else { + None + } + }) + } + + fn id(&self) -> Option { + self.nt_headers().map(|nt_headers| { + SharedLibraryId::PeSignature( + nt_headers.FileHeader.TimeDateStamp, + nt_headers.OptionalHeader.SizeOfImage, + ) + }) + } + + #[inline] + fn debug_id(&self) -> Option { + self.codeview_record70() + .map(|codeview| SharedLibraryId::PdbSignature(codeview.pdb_signature, codeview.pdb_age)) + } + + fn segments(&self) -> Self::SegmentIter { + let sections = self.nt_headers().map(|nt_headers| unsafe { + let base = + (nt_headers as *const _ as *const u8).add(mem::size_of::()); + slice::from_raw_parts( + base as *const IMAGE_SECTION_HEADER, + nt_headers.FileHeader.NumberOfSections as usize, + ) + }); + SegmentIter { + sections: sections.unwrap_or(&[][..]).iter(), + } + } + + #[inline] + fn virtual_memory_bias(&self) -> Bias { + Bias(self.module_base() as usize) + } + + fn each(mut f: F) + where + F: FnMut(&Self) -> C, + C: Into, + { + let proc = unsafe { GetCurrentProcess() }; + let mut modules_size = 0; + unsafe { + if EnumProcessModules(proc, ptr::null_mut(), 0, &mut modules_size) == 0 { + return; + } + } + let module_count = modules_size / mem::size_of::() as u32; + let mut modules = vec![unsafe { mem::zeroed() }; module_count as usize]; + unsafe { + if EnumProcessModules(proc, modules.as_mut_ptr(), modules_size, &mut modules_size) == 0 + { + return; + } + } + + modules.truncate(modules_size as usize / mem::size_of::()); + + for module in modules { + unsafe { + let mut module_path = vec![0u16; MAX_PATH + 1]; + let module_path_len = GetModuleFileNameExW( + proc, + module, + module_path.as_mut_ptr(), + MAX_PATH as u32 + 1, + ) as usize; + if module_path_len == 0 { + continue; + } + + let mut module_info = mem::zeroed(); + if GetModuleInformation( + proc, + module, + &mut module_info, + mem::size_of::() as u32, + ) == 0 + { + continue; + } + + // to prevent something else from unloading the module while + // we're poking around in memory we load it a second time. This + // will effectively just increment the refcount since it has been + // loaded before. + let handle_lock = LoadLibraryExW( + module_path.as_ptr(), + ptr::null_mut(), + LOAD_LIBRARY_AS_DATAFILE, + ); + + let mut vmem_info = mem::zeroed(); + let mut should_break = false; + if VirtualQuery( + module_info.lpBaseOfDll, + &mut vmem_info, + mem::size_of::(), + ) == mem::size_of::() + { + let module_path = OsString::from_wide(&module_path[..module_path_len]); + if vmem_info.State == MEM_COMMIT { + let shlib = SharedLibrary::new(module_info, module_path); + match f(&shlib).into() { + IterationControl::Break => should_break = true, + IterationControl::Continue => {} + } + } + } + + FreeLibrary(handle_lock); + + if should_break { + break; + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::super::{IterationControl, Segment, SharedLibrary}; + use crate::windows; + + #[test] + fn can_break() { + let mut first_count = 0; + windows::SharedLibrary::each(|_| { + first_count += 1; + }); + assert!(first_count > 2); + + let mut second_count = 0; + windows::SharedLibrary::each(|_| { + second_count += 1; + + if second_count == first_count - 1 { + IterationControl::Break + } else { + IterationControl::Continue + } + }); + assert_eq!(second_count, first_count - 1); + } + + #[test] + fn get_name() { + windows::SharedLibrary::each(|shlib| { + let _ = shlib.name(); + assert!(shlib.debug_name().is_some()); + }); + } + + #[test] + fn have_code() { + windows::SharedLibrary::each(|shlib| { + println!("shlib = {:?}", shlib.name()); + + let mut found_code = false; + for seg in shlib.segments() { + println!(" segment = {:?}", seg.name()); + if seg.is_code() { + found_code = true; + } + } + assert!(found_code); + }); + } + + #[test] + fn get_id() { + windows::SharedLibrary::each(|shlib| { + assert!(shlib.id().is_some()); + assert!(shlib.debug_id().is_some()); + }); + } +} diff -Nru rust-findshlibs-0.5.0/.travis.yml rust-findshlibs-0.10.2/.travis.yml --- rust-findshlibs-0.5.0/.travis.yml 2017-08-16 00:45:54.000000000 +0000 +++ rust-findshlibs-0.10.2/.travis.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -sudo: false - -dist: trusty - -language: rust - -os: -- linux -- osx - -rust: -- nightly -- beta -- stable - -addons: - sources: - - llvm-toolchain-trusty-3.9 # Provides clang-3.9 - apt: - packages: - - binutils-dev - - clang-3.9 # Required for bindgen - - libcurl4-openssl-dev - - libelf-dev - - libdw-dev - -before_install: -- source ./ci/before_install.sh - -env: - matrix: - - PROFILE="--release" - - PROFILE="" - -script: -- PROFILE="$PROFILE" ./ci/script.sh