зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1412037 - Upgrade webdriver dependencies. r=jgraham
MozReview-Commit-ID: GN9AldKK6uO --HG-- rename : third_party/rust/backtrace/.cargo-checksum.json => third_party/rust/backtrace-0.3.2/.cargo-checksum.json rename : third_party/rust/backtrace/.travis.yml => third_party/rust/backtrace-0.3.2/.travis.yml rename : third_party/rust/backtrace/Cargo.toml => third_party/rust/backtrace-0.3.2/Cargo.toml rename : third_party/rust/backtrace/src/backtrace/mod.rs => third_party/rust/backtrace-0.3.2/src/backtrace/mod.rs rename : third_party/rust/backtrace/src/backtrace/unix_backtrace.rs => third_party/rust/backtrace-0.3.2/src/backtrace/unix_backtrace.rs rename : third_party/rust/backtrace/src/capture.rs => third_party/rust/backtrace-0.3.2/src/capture.rs rename : third_party/rust/backtrace/src/lib.rs => third_party/rust/backtrace-0.3.2/src/lib.rs rename : third_party/rust/backtrace/src/symbolize/dbghelp.rs => third_party/rust/backtrace-0.3.2/src/symbolize/dbghelp.rs rename : third_party/rust/backtrace/src/symbolize/mod.rs => third_party/rust/backtrace-0.3.2/src/symbolize/mod.rs rename : third_party/rust/backtrace/tests/smoke.rs => third_party/rust/backtrace-0.3.2/tests/smoke.rs rename : third_party/rust/backtrace-sys/.cargo-checksum.json => third_party/rust/backtrace-sys-0.1.10/.cargo-checksum.json rename : third_party/rust/backtrace-sys/Cargo.toml => third_party/rust/backtrace-sys-0.1.10/Cargo.toml rename : third_party/rust/backtrace-sys/build.rs => third_party/rust/backtrace-sys-0.1.10/build.rs rename : third_party/rust/base64/.cargo-checksum.json => third_party/rust/base64-0.5.2/.cargo-checksum.json rename : third_party/rust/base64/Cargo.toml => third_party/rust/base64-0.5.2/Cargo.toml rename : third_party/rust/base64/README.md => third_party/rust/base64-0.5.2/README.md rename : third_party/rust/base64/benches/benchmarks.rs => third_party/rust/base64-0.5.2/benches/benchmarks.rs rename : third_party/rust/base64/src/lib.rs => third_party/rust/base64-0.5.2/src/lib.rs rename : third_party/rust/base64/tests/tests.rs => third_party/rust/base64-0.5.2/tests/tests.rs rename : third_party/rust/byteorder/.cargo-checksum.json => third_party/rust/byteorder-1.0.0/.cargo-checksum.json rename : third_party/rust/byteorder/.travis.yml => third_party/rust/byteorder-1.0.0/.travis.yml rename : third_party/rust/byteorder/Cargo.toml => third_party/rust/byteorder-1.0.0/Cargo.toml rename : third_party/rust/byteorder/benches/bench.rs => third_party/rust/byteorder-1.0.0/benches/bench.rs rename : third_party/rust/byteorder/src/lib.rs => third_party/rust/byteorder-1.0.0/src/lib.rs rename : third_party/rust/byteorder/src/new.rs => third_party/rust/byteorder-1.0.0/src/new.rs rename : third_party/rust/cfg-if/.cargo-checksum.json => third_party/rust/cfg-if-0.1.1/.cargo-checksum.json rename : third_party/rust/cfg-if/Cargo.toml => third_party/rust/cfg-if-0.1.1/Cargo.toml rename : third_party/rust/cfg-if/src/lib.rs => third_party/rust/cfg-if-0.1.1/src/lib.rs rename : third_party/rust/gcc/.cargo-checksum.json => third_party/rust/gcc-0.3.51/.cargo-checksum.json rename : third_party/rust/gcc/.travis.yml => third_party/rust/gcc-0.3.51/.travis.yml rename : third_party/rust/gcc/Cargo.toml => third_party/rust/gcc-0.3.51/Cargo.toml rename : third_party/rust/gcc/README.md => third_party/rust/gcc-0.3.51/README.md rename : third_party/rust/gcc/appveyor.yml => third_party/rust/gcc-0.3.51/appveyor.yml rename : third_party/rust/gcc/src/lib.rs => third_party/rust/gcc-0.3.51/src/lib.rs rename : third_party/rust/gcc/src/windows_registry.rs => third_party/rust/gcc-0.3.51/src/windows_registry.rs rename : third_party/rust/gcc/tests/support/mod.rs => third_party/rust/gcc-0.3.51/tests/support/mod.rs rename : third_party/rust/gcc/tests/test.rs => third_party/rust/gcc-0.3.51/tests/test.rs rename : third_party/rust/httparse/.cargo-checksum.json => third_party/rust/httparse-1.2.2/.cargo-checksum.json rename : third_party/rust/httparse/.travis.yml => third_party/rust/httparse-1.2.2/.travis.yml rename : third_party/rust/httparse/.travis_after.sh => third_party/rust/httparse-1.2.2/.travis_after.sh rename : third_party/rust/httparse/Cargo.toml => third_party/rust/httparse-1.2.2/Cargo.toml rename : third_party/rust/httparse/LICENSE-APACHE => third_party/rust/httparse-1.2.2/LICENSE-APACHE rename : third_party/rust/httparse/LICENSE-MIT => third_party/rust/httparse-1.2.2/LICENSE-MIT rename : third_party/rust/httparse/README.md => third_party/rust/httparse-1.2.2/README.md rename : third_party/rust/httparse/benches/parse.rs => third_party/rust/httparse-1.2.2/benches/parse.rs rename : third_party/rust/httparse/src/iter.rs => third_party/rust/httparse-1.2.2/src/iter.rs rename : third_party/rust/httparse/src/lib.rs => third_party/rust/httparse-1.2.2/src/lib.rs rename : third_party/rust/hyper/.cargo-checksum.json => third_party/rust/hyper-0.10.10/.cargo-checksum.json rename : third_party/rust/hyper/Cargo.toml => third_party/rust/hyper-0.10.10/Cargo.toml rename : third_party/rust/hyper/build.rs => third_party/rust/hyper-0.10.10/build.rs rename : third_party/rust/hyper/src/buffer.rs => third_party/rust/hyper-0.10.10/src/buffer.rs rename : third_party/rust/hyper/src/client/mod.rs => third_party/rust/hyper-0.10.10/src/client/mod.rs rename : third_party/rust/hyper/src/client/pool.rs => third_party/rust/hyper-0.10.10/src/client/pool.rs rename : third_party/rust/hyper/src/client/response.rs => third_party/rust/hyper-0.10.10/src/client/response.rs rename : third_party/rust/hyper/src/header/common/authorization.rs => third_party/rust/hyper-0.10.10/src/header/common/authorization.rs rename : third_party/rust/hyper/src/header/common/mod.rs => third_party/rust/hyper-0.10.10/src/header/common/mod.rs rename : third_party/rust/hyper/src/header/internals/cell.rs => third_party/rust/hyper-0.10.10/src/header/internals/cell.rs rename : third_party/rust/hyper/src/header/internals/vec_map.rs => third_party/rust/hyper-0.10.10/src/header/internals/vec_map.rs rename : third_party/rust/hyper/src/header/mod.rs => third_party/rust/hyper-0.10.10/src/header/mod.rs rename : third_party/rust/hyper/src/http/h1.rs => third_party/rust/hyper-0.10.10/src/http/h1.rs rename : third_party/rust/hyper/src/lib.rs => third_party/rust/hyper-0.10.10/src/lib.rs rename : third_party/rust/hyper/src/mock.rs => third_party/rust/hyper-0.10.10/src/mock.rs rename : third_party/rust/hyper/src/server/listener.rs => third_party/rust/hyper-0.10.10/src/server/listener.rs rename : third_party/rust/hyper/src/server/mod.rs => third_party/rust/hyper-0.10.10/src/server/mod.rs rename : third_party/rust/hyper/src/server/request.rs => third_party/rust/hyper-0.10.10/src/server/request.rs rename : third_party/rust/hyper/src/server/response.rs => third_party/rust/hyper-0.10.10/src/server/response.rs rename : third_party/rust/hyper/src/uri.rs => third_party/rust/hyper-0.10.10/src/uri.rs rename : third_party/rust/hyper/src/version.rs => third_party/rust/hyper-0.10.10/src/version.rs rename : third_party/rust/libc/.cargo-checksum.json => third_party/rust/libc-0.2.24/.cargo-checksum.json rename : third_party/rust/libc/.travis.yml => third_party/rust/libc-0.2.24/.travis.yml rename : third_party/rust/libc/Cargo.toml => third_party/rust/libc-0.2.24/Cargo.toml rename : third_party/rust/libc/README.md => third_party/rust/libc-0.2.24/README.md rename : third_party/rust/libc/appveyor.yml => third_party/rust/libc-0.2.24/appveyor.yml rename : third_party/rust/libc/ci/android-install-ndk.sh => third_party/rust/libc-0.2.24/ci/android-install-ndk.sh rename : third_party/rust/libc/ci/docker/aarch64-linux-android/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/aarch64-linux-android/Dockerfile rename : third_party/rust/libc/ci/docker/aarch64-unknown-linux-gnu/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/aarch64-unknown-linux-gnu/Dockerfile rename : third_party/rust/libc/ci/docker/arm-linux-androideabi/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/arm-linux-androideabi/Dockerfile rename : third_party/rust/libc/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile rename : third_party/rust/libc/ci/docker/i686-linux-android/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/i686-linux-android/Dockerfile rename : third_party/rust/libc/ci/docker/i686-unknown-linux-gnu/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/i686-unknown-linux-gnu/Dockerfile rename : third_party/rust/libc/ci/docker/i686-unknown-linux-musl/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/i686-unknown-linux-musl/Dockerfile rename : third_party/rust/libc/ci/docker/mips-unknown-linux-gnu/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/mips-unknown-linux-gnu/Dockerfile rename : third_party/rust/libc/ci/docker/mips-unknown-linux-musl/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/mips-unknown-linux-musl/Dockerfile rename : third_party/rust/libc/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile rename : third_party/rust/libc/ci/docker/mipsel-unknown-linux-musl/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/mipsel-unknown-linux-musl/Dockerfile rename : third_party/rust/libc/ci/docker/powerpc-unknown-linux-gnu/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/powerpc-unknown-linux-gnu/Dockerfile rename : third_party/rust/libc/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile rename : third_party/rust/libc/ci/docker/x86_64-linux-android/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/x86_64-linux-android/Dockerfile rename : third_party/rust/libc/ci/docker/x86_64-rumprun-netbsd/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/x86_64-rumprun-netbsd/Dockerfile rename : third_party/rust/libc/ci/docker/x86_64-unknown-linux-gnu/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/x86_64-unknown-linux-gnu/Dockerfile rename : third_party/rust/libc/ci/docker/x86_64-unknown-linux-musl/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/x86_64-unknown-linux-musl/Dockerfile rename : third_party/rust/libc/ci/docker/x86_64-unknown-openbsd/Dockerfile => third_party/rust/libc-0.2.24/ci/docker/x86_64-unknown-openbsd/Dockerfile rename : third_party/rust/libc/ci/run-docker.sh => third_party/rust/libc-0.2.24/ci/run-docker.sh rename : third_party/rust/libc/ci/run.sh => third_party/rust/libc-0.2.24/ci/run.sh rename : third_party/rust/libc/src/lib.rs => third_party/rust/libc-0.2.24/src/lib.rs rename : third_party/rust/libc/src/macros.rs => third_party/rust/libc-0.2.24/src/macros.rs rename : third_party/rust/libc/src/redox.rs => third_party/rust/libc-0.2.24/src/redox.rs rename : third_party/rust/libc/src/unix/bsd/apple/b32.rs => third_party/rust/libc-0.2.24/src/unix/bsd/apple/b32.rs rename : third_party/rust/libc/src/unix/bsd/apple/b64.rs => third_party/rust/libc-0.2.24/src/unix/bsd/apple/b64.rs rename : third_party/rust/libc/src/unix/bsd/apple/mod.rs => third_party/rust/libc-0.2.24/src/unix/bsd/apple/mod.rs rename : third_party/rust/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs => third_party/rust/libc-0.2.24/src/unix/bsd/freebsdlike/dragonfly/mod.rs rename : third_party/rust/libc/src/unix/bsd/freebsdlike/freebsd/aarch64.rs => third_party/rust/libc-0.2.24/src/unix/bsd/freebsdlike/freebsd/aarch64.rs rename : third_party/rust/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs => third_party/rust/libc-0.2.24/src/unix/bsd/freebsdlike/freebsd/mod.rs rename : third_party/rust/libc/src/unix/bsd/freebsdlike/freebsd/x86_64.rs => third_party/rust/libc-0.2.24/src/unix/bsd/freebsdlike/freebsd/x86_64.rs rename : third_party/rust/libc/src/unix/bsd/freebsdlike/mod.rs => third_party/rust/libc-0.2.24/src/unix/bsd/freebsdlike/mod.rs rename : third_party/rust/libc/src/unix/bsd/mod.rs => third_party/rust/libc-0.2.24/src/unix/bsd/mod.rs rename : third_party/rust/libc/src/unix/bsd/netbsdlike/mod.rs => third_party/rust/libc-0.2.24/src/unix/bsd/netbsdlike/mod.rs rename : third_party/rust/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs => third_party/rust/libc-0.2.24/src/unix/bsd/netbsdlike/netbsd/mod.rs rename : third_party/rust/libc/src/unix/bsd/netbsdlike/openbsdlike/mod.rs => third_party/rust/libc-0.2.24/src/unix/bsd/netbsdlike/openbsdlike/mod.rs rename : third_party/rust/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd.rs => third_party/rust/libc-0.2.24/src/unix/bsd/netbsdlike/openbsdlike/openbsd.rs rename : third_party/rust/libc/src/unix/haiku/mod.rs => third_party/rust/libc-0.2.24/src/unix/haiku/mod.rs rename : third_party/rust/libc/src/unix/mod.rs => third_party/rust/libc-0.2.24/src/unix/mod.rs rename : third_party/rust/libc/src/unix/notbsd/android/b32/arm.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/android/b32/arm.rs rename : third_party/rust/libc/src/unix/notbsd/android/b32/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/android/b32/mod.rs rename : third_party/rust/libc/src/unix/notbsd/android/b32/x86.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/android/b32/x86.rs rename : third_party/rust/libc/src/unix/notbsd/android/b64/aarch64.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/android/b64/aarch64.rs rename : third_party/rust/libc/src/unix/notbsd/android/b64/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/android/b64/mod.rs rename : third_party/rust/libc/src/unix/notbsd/android/b64/x86_64.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/android/b64/x86_64.rs rename : third_party/rust/libc/src/unix/notbsd/android/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/android/mod.rs rename : third_party/rust/libc/src/unix/notbsd/linux/mips/mips32.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/mips/mips32.rs rename : third_party/rust/libc/src/unix/notbsd/linux/mips/mips64.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/mips/mips64.rs rename : third_party/rust/libc/src/unix/notbsd/linux/mips/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/mips/mod.rs rename : third_party/rust/libc/src/unix/notbsd/linux/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/mod.rs rename : third_party/rust/libc/src/unix/notbsd/linux/musl/b32/arm.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/musl/b32/arm.rs rename : third_party/rust/libc/src/unix/notbsd/linux/musl/b32/asmjs.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/musl/b32/asmjs.rs rename : third_party/rust/libc/src/unix/notbsd/linux/musl/b32/mips.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/musl/b32/mips.rs rename : third_party/rust/libc/src/unix/notbsd/linux/musl/b32/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/musl/b32/mod.rs rename : third_party/rust/libc/src/unix/notbsd/linux/musl/b32/x86.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/musl/b32/x86.rs rename : third_party/rust/libc/src/unix/notbsd/linux/musl/b64/aarch64.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/musl/b64/aarch64.rs rename : third_party/rust/libc/src/unix/notbsd/linux/musl/b64/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/musl/b64/mod.rs rename : third_party/rust/libc/src/unix/notbsd/linux/musl/b64/powerpc64.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/musl/b64/powerpc64.rs rename : third_party/rust/libc/src/unix/notbsd/linux/musl/b64/x86_64.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/musl/b64/x86_64.rs rename : third_party/rust/libc/src/unix/notbsd/linux/musl/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/musl/mod.rs rename : third_party/rust/libc/src/unix/notbsd/linux/other/b32/arm.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/other/b32/arm.rs rename : third_party/rust/libc/src/unix/notbsd/linux/other/b32/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/other/b32/mod.rs rename : third_party/rust/libc/src/unix/notbsd/linux/other/b32/powerpc.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/other/b32/powerpc.rs rename : third_party/rust/libc/src/unix/notbsd/linux/other/b32/x86.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/other/b32/x86.rs rename : third_party/rust/libc/src/unix/notbsd/linux/other/b64/aarch64.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/other/b64/aarch64.rs rename : third_party/rust/libc/src/unix/notbsd/linux/other/b64/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/other/b64/mod.rs rename : third_party/rust/libc/src/unix/notbsd/linux/other/b64/powerpc64.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/other/b64/powerpc64.rs rename : third_party/rust/libc/src/unix/notbsd/linux/other/b64/sparc64.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/other/b64/sparc64.rs rename : third_party/rust/libc/src/unix/notbsd/linux/other/b64/x86_64.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/other/b64/x86_64.rs rename : third_party/rust/libc/src/unix/notbsd/linux/other/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/other/mod.rs rename : third_party/rust/libc/src/unix/notbsd/linux/s390x.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/linux/s390x.rs rename : third_party/rust/libc/src/unix/notbsd/mod.rs => third_party/rust/libc-0.2.24/src/unix/notbsd/mod.rs rename : third_party/rust/libc/src/unix/solaris/mod.rs => third_party/rust/libc-0.2.24/src/unix/solaris/mod.rs rename : third_party/rust/libc/src/unix/uclibc/mod.rs => third_party/rust/libc-0.2.24/src/unix/uclibc/mod.rs rename : third_party/rust/libc/src/unix/uclibc/x86_64/mod.rs => third_party/rust/libc-0.2.24/src/unix/uclibc/x86_64/mod.rs rename : third_party/rust/libc/src/windows.rs => third_party/rust/libc-0.2.24/src/windows.rs rename : third_party/rust/matches/.cargo-checksum.json => third_party/rust/matches-0.1.4/.cargo-checksum.json rename : third_party/rust/matches/Cargo.toml => third_party/rust/matches-0.1.4/Cargo.toml rename : third_party/rust/matches/lib.rs => third_party/rust/matches-0.1.4/lib.rs rename : third_party/rust/mime/.cargo-checksum.json => third_party/rust/mime-0.2.4/.cargo-checksum.json rename : third_party/rust/mime/Cargo.toml => third_party/rust/mime-0.2.4/Cargo.toml rename : third_party/rust/mime/src/lib.rs => third_party/rust/mime-0.2.4/src/lib.rs rename : third_party/rust/num_cpus/.cargo-checksum.json => third_party/rust/num_cpus-1.6.0/.cargo-checksum.json rename : third_party/rust/num_cpus/Cargo.toml => third_party/rust/num_cpus-1.6.0/Cargo.toml rename : third_party/rust/redox_syscall/.cargo-checksum.json => third_party/rust/redox_syscall-0.1.16/.cargo-checksum.json rename : third_party/rust/redox_syscall/Cargo.toml => third_party/rust/redox_syscall-0.1.16/Cargo.toml rename : third_party/rust/redox_syscall/src/arch/arm.rs => third_party/rust/redox_syscall-0.1.16/src/arch/arm.rs rename : third_party/rust/redox_syscall/src/arch/x86.rs => third_party/rust/redox_syscall-0.1.16/src/arch/x86.rs rename : third_party/rust/redox_syscall/src/arch/x86_64.rs => third_party/rust/redox_syscall-0.1.16/src/arch/x86_64.rs rename : third_party/rust/redox_syscall/src/call.rs => third_party/rust/redox_syscall-0.1.16/src/call.rs rename : third_party/rust/redox_syscall/src/data.rs => third_party/rust/redox_syscall-0.1.16/src/data.rs rename : third_party/rust/redox_syscall/src/flag.rs => third_party/rust/redox_syscall-0.1.16/src/flag.rs rename : third_party/rust/redox_syscall/src/number.rs => third_party/rust/redox_syscall-0.1.16/src/number.rs rename : third_party/rust/redox_syscall/src/scheme.rs => third_party/rust/redox_syscall-0.1.16/src/scheme.rs rename : third_party/rust/rustc-demangle/.cargo-checksum.json => third_party/rust/rustc-demangle-0.1.4/.cargo-checksum.json rename : third_party/rust/rustc-demangle/Cargo.toml => third_party/rust/rustc-demangle-0.1.4/Cargo.toml rename : third_party/rust/rustc-demangle/src/lib.rs => third_party/rust/rustc-demangle-0.1.4/src/lib.rs rename : third_party/rust/httparse/LICENSE-APACHE => third_party/rust/safemem/LICENSE-APACHE rename : third_party/rust/thread_local/.cargo-checksum.json => third_party/rust/thread_local-0.3.3/.cargo-checksum.json rename : third_party/rust/thread_local/.travis.yml => third_party/rust/thread_local-0.3.3/.travis.yml rename : third_party/rust/thread_local/Cargo.toml => third_party/rust/thread_local-0.3.3/Cargo.toml rename : third_party/rust/thread_local/src/lib.rs => third_party/rust/thread_local-0.3.3/src/lib.rs rename : third_party/rust/time/.cargo-checksum.json => third_party/rust/time-0.1.36/.cargo-checksum.json rename : third_party/rust/time/Cargo.toml => third_party/rust/time-0.1.36/Cargo.toml rename : third_party/rust/time/src/sys.rs => third_party/rust/time-0.1.36/src/sys.rs rename : third_party/rust/unicase/.cargo-checksum.json => third_party/rust/unicase-1.4.0/.cargo-checksum.json rename : third_party/rust/unicase/.travis.yml => third_party/rust/unicase-1.4.0/.travis.yml rename : third_party/rust/unicase/Cargo.toml => third_party/rust/unicase-1.4.0/Cargo.toml rename : third_party/rust/unicase/build.rs => third_party/rust/unicase-1.4.0/build.rs rename : third_party/rust/unicase/src/lib.rs => third_party/rust/unicase-1.4.0/src/lib.rs rename : third_party/rust/unicode-bidi/.cargo-checksum.json => third_party/rust/unicode-bidi-0.3.3/.cargo-checksum.json rename : third_party/rust/unicode-bidi/.travis.yml => third_party/rust/unicode-bidi-0.3.3/.travis.yml rename : third_party/rust/unicode-bidi/Cargo.toml => third_party/rust/unicode-bidi-0.3.3/Cargo.toml rename : third_party/rust/unicode-bidi/README.md => third_party/rust/unicode-bidi-0.3.3/README.md rename : third_party/rust/unicode-bidi/benches/basic.rs => third_party/rust/unicode-bidi-0.3.3/benches/basic.rs rename : third_party/rust/unicode-bidi/benches/udhr.rs => third_party/rust/unicode-bidi-0.3.3/benches/udhr.rs rename : third_party/rust/unicode-bidi/benches/udhr_data/README.md => third_party/rust/unicode-bidi-0.3.3/benches/udhr_data/README.md rename : third_party/rust/unicode-bidi/src/char_data/mod.rs => third_party/rust/unicode-bidi-0.3.3/src/char_data/mod.rs rename : third_party/rust/unicode-bidi/src/char_data/tables.rs => third_party/rust/unicode-bidi-0.3.3/src/char_data/tables.rs rename : third_party/rust/unicode-bidi/src/deprecated.rs => third_party/rust/unicode-bidi-0.3.3/src/deprecated.rs rename : third_party/rust/unicode-bidi/src/explicit.rs => third_party/rust/unicode-bidi-0.3.3/src/explicit.rs rename : third_party/rust/unicode-bidi/src/format_chars.rs => third_party/rust/unicode-bidi-0.3.3/src/format_chars.rs rename : third_party/rust/unicode-bidi/src/implicit.rs => third_party/rust/unicode-bidi-0.3.3/src/implicit.rs rename : third_party/rust/unicode-bidi/src/level.rs => third_party/rust/unicode-bidi-0.3.3/src/level.rs rename : third_party/rust/unicode-bidi/src/lib.rs => third_party/rust/unicode-bidi-0.3.3/src/lib.rs rename : third_party/rust/unicode-bidi/src/prepare.rs => third_party/rust/unicode-bidi-0.3.3/src/prepare.rs rename : third_party/rust/unicode-bidi/tests/conformance_tests.rs => third_party/rust/unicode-bidi-0.3.3/tests/conformance_tests.rs rename : third_party/rust/unicode-bidi/tools/generate.py => third_party/rust/unicode-bidi-0.3.3/tools/generate.py rename : third_party/rust/unreachable/.cargo-checksum.json => third_party/rust/unreachable-0.1.1/.cargo-checksum.json rename : third_party/rust/unreachable/Cargo.toml => third_party/rust/unreachable-0.1.1/Cargo.toml rename : third_party/rust/unreachable/README.md => third_party/rust/unreachable-0.1.1/README.md extra : rebase_source : 96e680e0cbbc32bd164eb91af60af1623dc888ea
This commit is contained in:
Родитель
f056551b50
Коммит
654cd8402d
|
@ -0,0 +1 @@
|
|||
{"files":{".travis.yml":"6f11d19317924088c90d605e1d13e4af230b10e289c5df6139c40a62409eabd9","Cargo.toml":"f893b7b701611e48ab80db25670342084b11d8d4ed3f3471b68842c490d247b8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"11061a4c1e27fde148b5b1fb6df553f8eb464e279be0f5e278d262bf35d7b0f8","appveyor.yml":"29d9f44137560479a75b02a7953cfa0c378c2577ed1925f579b400295c7937e3","examples/backtrace.rs":"fd6e1cc6c3378ec7d41cd03b2bef187051298dceb01147e71f207dbb8a0c4867","examples/raw.rs":"f07be26d1f97cd7ac79290ac99d19c4eec5d27031fe270ab5364c25d9c2ad9e0","src/backtrace/dbghelp.rs":"45c5052763857d4a3727c3082be1b2f6c28f7973afd66706657defda5d97c6ec","src/backtrace/libunwind.rs":"cc9cdc1d389571cdedf43dfc2d39b8c3af85531a3965ed700c724f436afb213e","src/backtrace/mod.rs":"d00f4a574fae44df81b1d40bf44acea84addb70b4c76c85bfaa1f3ab0bcd7f0d","src/backtrace/noop.rs":"dc4a6602e9852b945c382194402314d3d68c8ca90199af9a8159419fb91a3c99","src/backtrace/unix_backtrace.rs":"1bb4a4a2f1e56f8ac04002dd77411116d8b4920f905d1ddfcb289e242f939a86","src/capture.rs":"de3250fcb9ff941391dea24decc8166d058f17abe77d25ff82b766ac384f00ea","src/dylib.rs":"09f3d7f32849cf0daa4de9df48f8e4a4d5ba62e20723c79578201bd271dc4777","src/lib.rs":"7ccd8cc3679435f0e39efd26f23d9d7a01094ab09ba6d411c6587b2420c6886b","src/symbolize/coresymbolication.rs":"99280684791694f560824b39291ee7ad78a2b53f82e5972ff3d9b77b43671f60","src/symbolize/dbghelp.rs":"d743545bb3e64eafc4903e3e7aec115b64da2174e75afd7b465bc0b89573b88a","src/symbolize/dladdr.rs":"8287cbca440a9e92e74d88c5a7b920f6b4cf6d8f50bc8b0f61aca5ba42d5b5ec","src/symbolize/libbacktrace.rs":"0cdad7de2501baef9da193ee6aab21c453d26348a2071c805a133efe1209eaa1","src/symbolize/mod.rs":"7f2efe54ce40f42ba38673614cff2a510632123cb6d1bc3da88566f12bcba588","src/symbolize/noop.rs":"b622fcecb4e22b42c3d3e2ef5dc5a6ab14601fec83c7797ee1fbbacc12fe6ca1","tests/smoke.rs":"fc882d7db0f4842e4415e3319774a33ba27c4d6412a62f8ee194a5dafd8a6128"},"package":"72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"}
|
|
@ -0,0 +1,40 @@
|
|||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
sudo: false
|
||||
before_script:
|
||||
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
|
||||
script:
|
||||
- cargo test
|
||||
- cargo test --no-default-features
|
||||
- cargo test --no-default-features --features 'libunwind'
|
||||
- cargo test --no-default-features --features 'libunwind dladdr'
|
||||
- cargo test --no-default-features --features 'libunwind libbacktrace'
|
||||
- cargo test --no-default-features --features 'unix-backtrace'
|
||||
- cargo test --no-default-features --features 'unix-backtrace dladdr'
|
||||
- cargo test --no-default-features --features 'unix-backtrace libbacktrace'
|
||||
- cargo test --no-default-features --features 'serialize-serde'
|
||||
- cargo test --no-default-features --features 'serialize-rustc'
|
||||
- cargo test --no-default-features --features 'serialize-rustc serialize-serde'
|
||||
- cargo test --no-default-features --features 'cpp_demangle'
|
||||
- cd ./cpp_smoke_test && cargo test && cd ..
|
||||
- cargo clean && cargo build
|
||||
- rustdoc --test README.md -L target/debug/deps -L target/debug
|
||||
- cargo doc --no-deps
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
after_success:
|
||||
- travis-cargo --only nightly doc-upload
|
||||
env:
|
||||
global:
|
||||
# serde-codegen has historically needed a large stack to expand
|
||||
- RUST_MIN_STACK=16777216
|
||||
- secure: "Kuf3j6gC3MhR+F7g8/5J4+3tu+FXJP/SqKjsUVVjs/qjniIVX3MwZPhtP/pVtdRvYjW0NzLw5Nufb4o1cyY4uKwR8BHHNuEUE/h3mPShjWHqzLyn5QiBumPozsFCa32H4gconRmp3+s0YrBT7nLoGvUZZS0dkldMkpvvrPL/yUKXLS8HEP4L1GO5iMQQYG6i3sbWTbHikE6ZQogW/iZommyqUkVB/s/SQvdH9SXu89ttNXlm/F+EIsgsgyzpbULp5sD34GRDPJe+H1m+sgA1kTRrzmuBGNmz9mx6GyIKaqACTm1gRcb06nFjTPVTQioJBNnoV7TEqZCvjuSsUjcGmP4Aeissafo93ADzV+bd0uoWIScE9ltSVS+RgCDV+sd0GHz5U6FjhgZp0amaVl3d6hPp8lbTfK/gfj1i9ktQfKZbG7rB4tfIU1KeQRkyE9vb/TaKp8nwBbc4SVQ4EKFOlRbE1S1FooaKZweW8w57d2u+sMMMVJbO28/Ap8tk9xDSOl4shPaT0iM0U9/heF8FmCZB1OKXLKn6TAaNFnaMTvdTHl+Tjrf6Vzd/oPXJ7GuaB6eLxXYjXvZHuKiLkSZriOzhL7PbijNILbSgZt7+Fa0vcnXP8zgD4dmupx/CoIHLN9NP4o9cGXuBcaJ/iFryJ4i5LKGFNEUHtXkavDrcgcA="
|
||||
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
|
@ -0,0 +1,87 @@
|
|||
[package]
|
||||
name = "backtrace"
|
||||
version = "0.3.2"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>",
|
||||
"The Rust Project Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/alexcrichton/backtrace-rs"
|
||||
homepage = "https://github.com/alexcrichton/backtrace-rs"
|
||||
documentation = "http://alexcrichton.com/backtrace-rs"
|
||||
description = """
|
||||
A library to acquire a stack trace (backtrace) at runtime in a Rust program.
|
||||
"""
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
cfg-if = "0.1"
|
||||
rustc-demangle = "0.1.4"
|
||||
|
||||
# Optionally enable the ability to serialize a `Backtrace`
|
||||
serde = { version = "1.0", optional = true }
|
||||
serde_derive = { version = "1.0", optional = true }
|
||||
rustc-serialize = { version = "0.3", optional = true }
|
||||
|
||||
# Optionally demangle C++ frames' symbols in backtraces.
|
||||
cpp_demangle = { default-features = false, version = "0.2.3", optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
dbghelp-sys = { version = "0.2", optional = true }
|
||||
kernel32-sys = { version = "0.2", optional = true }
|
||||
winapi = { version = "0.2.5", optional = true }
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "emscripten"), not(target_os = "macos"), not(target_os = "ios")))'.dependencies]
|
||||
backtrace-sys = { path = "backtrace-sys", version = "0.1.3", optional = true }
|
||||
|
||||
# Each feature controls the two phases of finding a backtrace: getting a
|
||||
# backtrace and then resolving instruction pointers to symbols. The default
|
||||
# feature enables all the necessary features for each platform this library
|
||||
# supports, but it can be disabled to have finer grained control over the
|
||||
# dependencies.
|
||||
#
|
||||
# Note that not all features are available on all platforms, so even though a
|
||||
# feature is enabled some other feature may be used instead.
|
||||
[features]
|
||||
default = ["libunwind", "libbacktrace", "coresymbolication", "dladdr", "dbghelp"]
|
||||
|
||||
#=======================================
|
||||
# Methods of acquiring a backtrace
|
||||
#
|
||||
# - libunwind: when using this the libgcc library is linked against to get
|
||||
# the unwinding support. This is generally the most reliable method to get
|
||||
# a backtrace on unix.
|
||||
# - unix-backtrace: this uses the backtrace(3) function to acquire a
|
||||
# backtrace, but is not as reliable as libunwind. It is, however,
|
||||
# generally found in more locations.
|
||||
# - dbghelp: on windows this enables usage of dbghelp.dll to find a
|
||||
# backtrace at runtime
|
||||
# - kernel32: on windows this enables using RtlCaptureStackBackTrace as the
|
||||
# function to acquire a backtrace
|
||||
libunwind = []
|
||||
unix-backtrace = []
|
||||
dbghelp = ["kernel32-sys", "winapi", "dbghelp-sys"]
|
||||
kernel32 = []
|
||||
|
||||
#=======================================
|
||||
# Methods of resolving symbols
|
||||
#
|
||||
# - libbacktrace: this feature activates the `backtrace-sys` dependency,
|
||||
# building the libbacktrace library found in gcc repos. This library
|
||||
# parses the DWARF info of ELF executables to find symbol names, and it
|
||||
# can also provide filename/line number information if debuginfo is
|
||||
# compiled in. This library currently only primarily works on unixes that
|
||||
# are not OSX, however.
|
||||
# - dladdr: this feature uses the dladdr(3) function (a glibc extension) to
|
||||
# resolve symbol names. This is fairly unreliable on linux, but works well
|
||||
# enough on OSX.
|
||||
# - coresymbolication: this feature uses the undocumented core symbolication
|
||||
# framework on OS X to symbolize.
|
||||
libbacktrace = ["backtrace-sys"]
|
||||
dladdr = []
|
||||
coresymbolication = []
|
||||
|
||||
#=======================================
|
||||
# Methods of serialization
|
||||
#
|
||||
# Various features used for enabling rustc-serialize or syntex codegen.
|
||||
serialize-rustc = ["rustc-serialize"]
|
||||
serialize-serde = ["serde", "serde_derive"]
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2014 Alex Crichton
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,82 @@
|
|||
# backtrace-rs
|
||||
|
||||
[![Build Status](https://travis-ci.org/alexcrichton/backtrace-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/backtrace-rs)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/v4l9oj4aqbbgyx44?svg=true)](https://ci.appveyor.com/project/alexcrichton/backtrace-rs)
|
||||
|
||||
[Documentation](http://alexcrichton.com/backtrace-rs)
|
||||
|
||||
A library for acquiring backtraces at runtime for Rust. This library aims to
|
||||
enhance the support given by the standard library at `std::rt` by providing a
|
||||
more stable and programmatic interface.
|
||||
|
||||
## Install
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
backtrace = "0.3"
|
||||
```
|
||||
|
||||
```rust
|
||||
extern crate backtrace;
|
||||
```
|
||||
|
||||
Note that this crate requires `make`, `objcopy`, and `ar` to be present on Linux
|
||||
systems.
|
||||
|
||||
## Usage
|
||||
|
||||
To simply capture a backtrace and defer dealing with it until a later time,
|
||||
you can use the top-level `Backtrace` type.
|
||||
|
||||
```rust
|
||||
extern crate backtrace;
|
||||
|
||||
use backtrace::Backtrace;
|
||||
|
||||
fn main() {
|
||||
let bt = Backtrace::new();
|
||||
|
||||
// do_some_work();
|
||||
|
||||
println!("{:?}", bt);
|
||||
}
|
||||
```
|
||||
|
||||
If, however, you'd like more raw access to the actual tracing functionality, you
|
||||
can use the `trace` and `resolve` functions directly.
|
||||
|
||||
```rust
|
||||
extern crate backtrace;
|
||||
|
||||
fn main() {
|
||||
backtrace::trace(|frame| {
|
||||
let ip = frame.ip();
|
||||
let symbol_address = frame.symbol_address();
|
||||
|
||||
// Resolve this instruction pointer to a symbol name
|
||||
backtrace::resolve(ip, |symbol| {
|
||||
if let Some(name) = symbol.name() {
|
||||
// ...
|
||||
}
|
||||
if let Some(filename) = symbol.filename() {
|
||||
// ...
|
||||
}
|
||||
});
|
||||
|
||||
true // keep going to the next frame
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Platform Support
|
||||
|
||||
This library currently supports OSX, Linux, and Windows. Support for other
|
||||
platforms is always welcome!
|
||||
|
||||
## License
|
||||
|
||||
`backtrace-rs` is primarily distributed under the terms of both the MIT license
|
||||
and the Apache License (Version 2.0), with portions covered by various BSD-like
|
||||
licenses.
|
||||
|
||||
See LICENSE-APACHE, and LICENSE-MIT for details.
|
|
@ -0,0 +1,20 @@
|
|||
environment:
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
MSYS_BITS: 64
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
MSYS_BITS: 32
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
install:
|
||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
|
||||
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
||||
- set PATH=%PATH%;C:\Program Files (x86)\Rust\bin
|
||||
- if defined MSYS_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS_BITS%\bin
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo test --target %TARGET%
|
|
@ -0,0 +1,7 @@
|
|||
extern crate backtrace;
|
||||
|
||||
use backtrace::Backtrace;
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", Backtrace::new());
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
extern crate backtrace;
|
||||
|
||||
fn main() {
|
||||
foo();
|
||||
}
|
||||
|
||||
fn foo() { bar() }
|
||||
fn bar() { baz() }
|
||||
fn baz() { print() }
|
||||
|
||||
#[cfg(target_pointer_width = "32")] const HEX_WIDTH: usize = 10;
|
||||
#[cfg(target_pointer_width = "64")] const HEX_WIDTH: usize = 20;
|
||||
|
||||
fn print() {
|
||||
let mut cnt = 0;
|
||||
backtrace::trace(|frame| {
|
||||
let ip = frame.ip();
|
||||
print!("frame #{:<2} - {:#02$x}", cnt, ip as usize, HEX_WIDTH);
|
||||
cnt += 1;
|
||||
|
||||
let mut resolved = false;
|
||||
backtrace::resolve(frame.ip(), |symbol| {
|
||||
if !resolved {
|
||||
resolved = true;
|
||||
} else {
|
||||
print!("{}", vec![" "; 7 + 2 + 3 + HEX_WIDTH].join(""));
|
||||
}
|
||||
|
||||
if let Some(name) = symbol.name() {
|
||||
print!(" - {}", name);
|
||||
} else {
|
||||
print!(" - <unknown>");
|
||||
}
|
||||
if let Some(file) = symbol.filename() {
|
||||
if let Some(l) = symbol.lineno() {
|
||||
print!("\n{:13}{:4$}@ {}:{}", "", "", file.display(), l,
|
||||
HEX_WIDTH);
|
||||
}
|
||||
}
|
||||
println!("");
|
||||
|
||||
});
|
||||
if !resolved {
|
||||
println!(" - <no info>");
|
||||
}
|
||||
true // keep going
|
||||
});
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(bad_style)]
|
||||
|
||||
use std::mem;
|
||||
use winapi::*;
|
||||
use kernel32;
|
||||
|
||||
pub struct Frame {
|
||||
inner: STACKFRAME64,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
self.inner.AddrPC.Offset as *mut _
|
||||
}
|
||||
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
self.ip()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn trace(cb: &mut FnMut(&super::Frame) -> bool) {
|
||||
// According to windows documentation, all dbghelp functions are
|
||||
// single-threaded.
|
||||
let _g = ::lock::lock();
|
||||
|
||||
unsafe {
|
||||
// Allocate necessary structures for doing the stack walk
|
||||
let process = kernel32::GetCurrentProcess();
|
||||
let thread = kernel32::GetCurrentThread();
|
||||
|
||||
// The CONTEXT structure needs to be aligned on a 16-byte boundary for
|
||||
// 64-bit Windows, but currently we don't have a way to express that in
|
||||
// Rust. Allocations are generally aligned to 16-bytes, though, so we
|
||||
// box this up.
|
||||
let mut context = Box::new(mem::zeroed::<CONTEXT>());
|
||||
kernel32::RtlCaptureContext(&mut *context);
|
||||
let mut frame = super::Frame {
|
||||
inner: Frame { inner: mem::zeroed() },
|
||||
};
|
||||
let image = init_frame(&mut frame.inner.inner, &context);
|
||||
|
||||
// Initialize this process's symbols
|
||||
let _c = ::dbghelp_init();
|
||||
|
||||
// And now that we're done with all the setup, do the stack walking!
|
||||
while ::dbghelp::StackWalk64(image as DWORD,
|
||||
process,
|
||||
thread,
|
||||
&mut frame.inner.inner,
|
||||
&mut *context as *mut _ as *mut _,
|
||||
None,
|
||||
Some(::dbghelp::SymFunctionTableAccess64),
|
||||
Some(::dbghelp::SymGetModuleBase64),
|
||||
None) == TRUE {
|
||||
if frame.inner.inner.AddrPC.Offset == frame.inner.inner.AddrReturn.Offset ||
|
||||
frame.inner.inner.AddrPC.Offset == 0 ||
|
||||
frame.inner.inner.AddrReturn.Offset == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if !cb(&frame) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn init_frame(frame: &mut STACKFRAME64, ctx: &CONTEXT) -> WORD {
|
||||
frame.AddrPC.Offset = ctx.Rip as u64;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = ctx.Rsp as u64;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = ctx.Rbp as u64;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
IMAGE_FILE_MACHINE_AMD64
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
fn init_frame(frame: &mut STACKFRAME64, ctx: &CONTEXT) -> WORD {
|
||||
frame.AddrPC.Offset = ctx.Eip as u64;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = ctx.Esp as u64;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = ctx.Ebp as u64;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
IMAGE_FILE_MACHINE_I386
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::os::raw::c_void;
|
||||
|
||||
pub struct Frame {
|
||||
ctx: *mut uw::_Unwind_Context,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
let mut ip_before_insn = 0;
|
||||
let mut ip = unsafe {
|
||||
uw::_Unwind_GetIPInfo(self.ctx, &mut ip_before_insn) as *mut c_void
|
||||
};
|
||||
if !ip.is_null() && ip_before_insn == 0 {
|
||||
// this is a non-signaling frame, so `ip` refers to the address
|
||||
// after the calling instruction. account for that.
|
||||
ip = (ip as usize - 1) as *mut _;
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
// dladdr() on osx gets whiny when we use FindEnclosingFunction, and
|
||||
// it appears to work fine without it, so we only use
|
||||
// FindEnclosingFunction on non-osx platforms. In doing so, we get a
|
||||
// slightly more accurate stack trace in the process.
|
||||
//
|
||||
// This is often because panic involves the last instruction of a
|
||||
// function being "call std::rt::begin_unwind", with no ret
|
||||
// instructions after it. This means that the return instruction
|
||||
// pointer points *outside* of the calling function, and by
|
||||
// unwinding it we go back to the original function.
|
||||
if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
|
||||
self.ip()
|
||||
} else {
|
||||
unsafe { uw::_Unwind_FindEnclosingFunction(self.ip()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn trace(mut cb: &mut FnMut(&super::Frame) -> bool) {
|
||||
unsafe {
|
||||
uw::_Unwind_Backtrace(trace_fn, &mut cb as *mut _ as *mut _);
|
||||
}
|
||||
|
||||
extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
|
||||
arg: *mut c_void) -> uw::_Unwind_Reason_Code {
|
||||
let cb = unsafe { &mut *(arg as *mut &mut FnMut(&super::Frame) -> bool) };
|
||||
let cx = super::Frame {
|
||||
inner: Frame { ctx: ctx },
|
||||
};
|
||||
|
||||
let mut bomb = ::Bomb { enabled: true };
|
||||
let keep_going = cb(&cx);
|
||||
bomb.enabled = false;
|
||||
|
||||
if keep_going {
|
||||
uw::_URC_NO_REASON
|
||||
} else {
|
||||
uw::_URC_FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwind library interface used for backtraces
|
||||
///
|
||||
/// Note that dead code is allowed as here are just bindings
|
||||
/// iOS doesn't use all of them it but adding more
|
||||
/// platform-specific configs pollutes the code too much
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(dead_code)]
|
||||
mod uw {
|
||||
pub use self::_Unwind_Reason_Code::*;
|
||||
|
||||
use libc;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
|
||||
#[repr(C)]
|
||||
pub enum _Unwind_Reason_Code {
|
||||
_URC_NO_REASON = 0,
|
||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
_URC_FATAL_PHASE2_ERROR = 2,
|
||||
_URC_FATAL_PHASE1_ERROR = 3,
|
||||
_URC_NORMAL_STOP = 4,
|
||||
_URC_END_OF_STACK = 5,
|
||||
_URC_HANDLER_FOUND = 6,
|
||||
_URC_INSTALL_CONTEXT = 7,
|
||||
_URC_CONTINUE_UNWIND = 8,
|
||||
_URC_FAILURE = 9, // used only by ARM EABI
|
||||
}
|
||||
|
||||
pub enum _Unwind_Context {}
|
||||
|
||||
pub type _Unwind_Trace_Fn =
|
||||
extern fn(ctx: *mut _Unwind_Context,
|
||||
arg: *mut c_void) -> _Unwind_Reason_Code;
|
||||
|
||||
extern {
|
||||
// No native _Unwind_Backtrace on iOS
|
||||
#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
|
||||
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
|
||||
trace_argument: *mut c_void)
|
||||
-> _Unwind_Reason_Code;
|
||||
|
||||
// available since GCC 4.2.0, should be fine for our purpose
|
||||
#[cfg(all(not(all(target_os = "android", target_arch = "arm")),
|
||||
not(all(target_os = "linux", target_arch = "arm"))))]
|
||||
pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
|
||||
ip_before_insn: *mut c_int)
|
||||
-> libc::uintptr_t;
|
||||
|
||||
#[cfg(all(not(target_os = "android"),
|
||||
not(all(target_os = "linux", target_arch = "arm"))))]
|
||||
pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void)
|
||||
-> *mut c_void;
|
||||
}
|
||||
|
||||
// On android, the function _Unwind_GetIP is a macro, and this is the
|
||||
// expansion of the macro. This is all copy/pasted directly from the
|
||||
// header file with the definition of _Unwind_GetIP.
|
||||
#[cfg(any(all(target_os = "android", target_arch = "arm"),
|
||||
all(target_os = "linux", target_arch = "arm")))]
|
||||
pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
|
||||
#[repr(C)]
|
||||
enum _Unwind_VRS_Result {
|
||||
_UVRSR_OK = 0,
|
||||
_UVRSR_NOT_IMPLEMENTED = 1,
|
||||
_UVRSR_FAILED = 2,
|
||||
}
|
||||
#[repr(C)]
|
||||
enum _Unwind_VRS_RegClass {
|
||||
_UVRSC_CORE = 0,
|
||||
_UVRSC_VFP = 1,
|
||||
_UVRSC_FPA = 2,
|
||||
_UVRSC_WMMXD = 3,
|
||||
_UVRSC_WMMXC = 4,
|
||||
}
|
||||
#[repr(C)]
|
||||
enum _Unwind_VRS_DataRepresentation {
|
||||
_UVRSD_UINT32 = 0,
|
||||
_UVRSD_VFPX = 1,
|
||||
_UVRSD_FPAX = 2,
|
||||
_UVRSD_UINT64 = 3,
|
||||
_UVRSD_FLOAT = 4,
|
||||
_UVRSD_DOUBLE = 5,
|
||||
}
|
||||
|
||||
type _Unwind_Word = libc::c_uint;
|
||||
extern {
|
||||
fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
|
||||
klass: _Unwind_VRS_RegClass,
|
||||
word: _Unwind_Word,
|
||||
repr: _Unwind_VRS_DataRepresentation,
|
||||
data: *mut c_void)
|
||||
-> _Unwind_VRS_Result;
|
||||
}
|
||||
|
||||
let mut val: _Unwind_Word = 0;
|
||||
let ptr = &mut val as *mut _Unwind_Word;
|
||||
let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15,
|
||||
_Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
|
||||
ptr as *mut c_void);
|
||||
(val & !1) as libc::uintptr_t
|
||||
}
|
||||
|
||||
// This function doesn't exist on Android or ARM/Linux, so make it same
|
||||
// to _Unwind_GetIP
|
||||
#[cfg(any(all(target_os = "android", target_arch = "arm"),
|
||||
all(target_os = "linux", target_arch = "arm")))]
|
||||
pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
|
||||
ip_before_insn: *mut c_int)
|
||||
-> libc::uintptr_t
|
||||
{
|
||||
*ip_before_insn = 0;
|
||||
_Unwind_GetIP(ctx)
|
||||
}
|
||||
|
||||
// This function also doesn't exist on Android or ARM/Linux, so make it
|
||||
// a no-op
|
||||
#[cfg(any(target_os = "android",
|
||||
all(target_os = "linux", target_arch = "arm")))]
|
||||
pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void)
|
||||
-> *mut c_void
|
||||
{
|
||||
pc
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
use std::fmt;
|
||||
|
||||
use std::os::raw::c_void;
|
||||
|
||||
/// Inspects the current call-stack, passing all active frames into the closure
|
||||
/// provided to calculate a stack trace.
|
||||
///
|
||||
/// This function is the workhorse of this library in calculating the stack
|
||||
/// traces for a program. The given closure `cb` is yielded instances of a
|
||||
/// `Frame` which represent information about that call frame on the stack. The
|
||||
/// closure is yielded frames in a top-down fashion (most recently called
|
||||
/// functions first).
|
||||
///
|
||||
/// The closure's return value is an indication of whether the backtrace should
|
||||
/// continue. A return value of `false` will terminate the backtrace and return
|
||||
/// immediately.
|
||||
///
|
||||
/// Once a `Frame` is acquired you will likely want to call `backtrace::resolve`
|
||||
/// to convert the `ip` (instruction pointer) or symbol address to a `Symbol`
|
||||
/// through which the name and/or filename/line number can be learned.
|
||||
///
|
||||
/// Note that this is a relatively low-level function and if you'd like to, for
|
||||
/// example, capture a backtrace to be inspected later, then the `Backtrace`
|
||||
/// type may be more appropriate.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// extern crate backtrace;
|
||||
///
|
||||
/// fn main() {
|
||||
/// backtrace::trace(|frame| {
|
||||
/// // ...
|
||||
///
|
||||
/// true // continue the backtrace
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
#[inline(never)] // if this is never inlined then the first frame can be konwn
|
||||
// to be skipped
|
||||
pub fn trace<F: FnMut(&Frame) -> bool>(mut cb: F) {
|
||||
trace_imp(&mut cb)
|
||||
}
|
||||
|
||||
/// A trait representing one frame of a backtrace, yielded to the `trace`
|
||||
/// function of this crate.
|
||||
///
|
||||
/// The tracing function's closure will be yielded frames, and the frame is
|
||||
/// virtually dispatched as the underlying implementation is not always known
|
||||
/// until runtime.
|
||||
pub struct Frame {
|
||||
inner: FrameImp,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
/// Returns the current instruction pointer of this frame.
|
||||
///
|
||||
/// This is normally the next instruction to execute in the frame, but not
|
||||
/// all implementations list this with 100% accuracy (but it's generally
|
||||
/// pretty close).
|
||||
///
|
||||
/// It is recommended to pass this value to `backtrace::resolve` to turn it
|
||||
/// into a symbol name.
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
self.inner.ip()
|
||||
}
|
||||
|
||||
/// Returns the starting symbol address of the frame of this function.
|
||||
///
|
||||
/// This will attempt to rewind the instruction pointer returned by `ip` to
|
||||
/// the start of the function, returning that value. In some cases, however,
|
||||
/// backends will just return `ip` from this function.
|
||||
///
|
||||
/// The returned value can sometimes be used if `backtrace::resolve` failed
|
||||
/// on the `ip` given above.
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
self.inner.symbol_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Frame {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Frame")
|
||||
.field("ip", &self.ip())
|
||||
.field("symbol_address", &self.symbol_address())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(all(unix,
|
||||
not(target_os = "emscripten"),
|
||||
feature = "libunwind"))] {
|
||||
mod libunwind;
|
||||
use self::libunwind::trace as trace_imp;
|
||||
use self::libunwind::Frame as FrameImp;
|
||||
} else if #[cfg(all(unix,
|
||||
not(target_os = "emscripten"),
|
||||
feature = "unix-backtrace"))] {
|
||||
mod unix_backtrace;
|
||||
use self::unix_backtrace::trace as trace_imp;
|
||||
use self::unix_backtrace::Frame as FrameImp;
|
||||
} else if #[cfg(all(windows, feature = "dbghelp"))] {
|
||||
mod dbghelp;
|
||||
use self::dbghelp::trace as trace_imp;
|
||||
use self::dbghelp::Frame as FrameImp;
|
||||
} else {
|
||||
mod noop;
|
||||
use self::noop::trace as trace_imp;
|
||||
use self::noop::Frame as FrameImp;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
use std::os::raw::c_void;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn trace(_cb: &mut FnMut(&super::Frame) -> bool) {}
|
||||
|
||||
pub struct Frame;
|
||||
|
||||
impl Frame {
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
0 as *mut _
|
||||
}
|
||||
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
0 as *mut _
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::mem;
|
||||
use std::os::raw::{c_void, c_int};
|
||||
|
||||
pub struct Frame {
|
||||
addr: *mut c_void,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn ip(&self) -> *mut c_void { self.addr }
|
||||
pub fn symbol_address(&self) -> *mut c_void { self.addr }
|
||||
}
|
||||
|
||||
extern {
|
||||
fn backtrace(buf: *mut *mut c_void, sz: c_int) -> c_int;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn trace(mut cb: &mut FnMut(&super::Frame) -> bool) {
|
||||
const SIZE: usize = 100;
|
||||
|
||||
let mut buf: [*mut c_void; SIZE];
|
||||
let cnt;
|
||||
unsafe {
|
||||
buf = mem::zeroed();
|
||||
cnt = backtrace(buf.as_mut_ptr(), SIZE as c_int);
|
||||
}
|
||||
|
||||
for addr in buf[..cnt as usize].iter() {
|
||||
let cx = super::Frame {
|
||||
inner: Frame { addr: *addr },
|
||||
};
|
||||
if !cb(&cx) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use {trace, resolve, SymbolName};
|
||||
|
||||
/// Representation of an owned and self-contained backtrace.
|
||||
///
|
||||
/// This structure can be used to capture a backtrace at various points in a
|
||||
/// program and later used to inspect what the backtrace was at that time.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
|
||||
#[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))]
|
||||
pub struct Backtrace {
|
||||
frames: Vec<BacktraceFrame>,
|
||||
}
|
||||
|
||||
/// Captured version of a frame in a backtrace.
|
||||
///
|
||||
/// This type is returned as a list from `Backtrace::frames` and represents one
|
||||
/// stack frame in a captured backtrace.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
|
||||
#[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))]
|
||||
pub struct BacktraceFrame {
|
||||
ip: usize,
|
||||
symbol_address: usize,
|
||||
symbols: Vec<BacktraceSymbol>,
|
||||
}
|
||||
|
||||
/// Captured version of a symbol in a backtrace.
|
||||
///
|
||||
/// This type is returned as a list from `BacktraceFrame::symbols` and
|
||||
/// represents the metadata for a symbol in a backtrace.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
|
||||
#[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))]
|
||||
pub struct BacktraceSymbol {
|
||||
name: Option<Vec<u8>>,
|
||||
addr: Option<usize>,
|
||||
filename: Option<PathBuf>,
|
||||
lineno: Option<u32>,
|
||||
}
|
||||
|
||||
impl Backtrace {
|
||||
/// Captures a backtrace at the callsite of this function, returning an
|
||||
/// owned representation.
|
||||
///
|
||||
/// This function is useful for representing a backtrace as an object in
|
||||
/// Rust. This returned value can be sent across threads and printed
|
||||
/// elsewhere, and thie purpose of this value is to be entirely self
|
||||
/// contained.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use backtrace::Backtrace;
|
||||
///
|
||||
/// let current_backtrace = Backtrace::new();
|
||||
/// ```
|
||||
pub fn new() -> Backtrace {
|
||||
let mut frames = Vec::new();
|
||||
trace(|frame| {
|
||||
let mut symbols = Vec::new();
|
||||
resolve(frame.ip(), |symbol| {
|
||||
symbols.push(BacktraceSymbol {
|
||||
name: symbol.name().map(|m| m.as_bytes().to_vec()),
|
||||
addr: symbol.addr().map(|a| a as usize),
|
||||
filename: symbol.filename().map(|m| m.to_path_buf()),
|
||||
lineno: symbol.lineno(),
|
||||
});
|
||||
});
|
||||
frames.push(BacktraceFrame {
|
||||
ip: frame.ip() as usize,
|
||||
symbol_address: frame.symbol_address() as usize,
|
||||
symbols: symbols,
|
||||
});
|
||||
true
|
||||
});
|
||||
|
||||
Backtrace { frames: frames }
|
||||
}
|
||||
|
||||
/// Returns the frames from when this backtrace was captured.
|
||||
///
|
||||
/// The first entry of this slice is likely the function `Backtrace::new`,
|
||||
/// and the last frame is likely something about how this thread or the main
|
||||
/// function started.
|
||||
pub fn frames(&self) -> &[BacktraceFrame] {
|
||||
&self.frames
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<BacktraceFrame>> for Backtrace {
|
||||
fn from(frames: Vec<BacktraceFrame>) -> Self {
|
||||
Backtrace {
|
||||
frames: frames
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<BacktraceFrame>> for Backtrace {
|
||||
fn into(self) -> Vec<BacktraceFrame> {
|
||||
self.frames
|
||||
}
|
||||
}
|
||||
|
||||
impl BacktraceFrame {
|
||||
/// Same as `Frame::ip`
|
||||
pub fn ip(&self) -> *mut c_void {
|
||||
self.ip as *mut c_void
|
||||
}
|
||||
|
||||
/// Same as `Frame::symbol_address`
|
||||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
self.symbol_address as *mut c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl BacktraceFrame {
|
||||
/// Returns the list of symbols that this frame corresponds to.
|
||||
///
|
||||
/// Normally there is only one symbol per frame, but sometimes if a number
|
||||
/// of functions are inlined into one frame then multiple symbols will be
|
||||
/// returned. The first symbol listed is the "innermost function", whereas
|
||||
/// the last symbol is the outermost (last caller).
|
||||
pub fn symbols(&self) -> &[BacktraceSymbol] {
|
||||
&self.symbols
|
||||
}
|
||||
}
|
||||
|
||||
impl BacktraceSymbol {
|
||||
/// Same as `Symbol::name`
|
||||
pub fn name(&self) -> Option<SymbolName> {
|
||||
self.name.as_ref().map(|s| SymbolName::new(s))
|
||||
}
|
||||
|
||||
/// Same as `Symbol::addr`
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
self.addr.map(|s| s as *mut c_void)
|
||||
}
|
||||
|
||||
/// Same as `Symbol::filename`
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
self.filename.as_ref().map(|p| &**p)
|
||||
}
|
||||
|
||||
/// Same as `Symbol::lineno`
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
self.lineno
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Backtrace {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let hex_width = mem::size_of::<usize>() * 2 + 2;
|
||||
|
||||
try!(write!(fmt, "stack backtrace:"));
|
||||
|
||||
for (idx, frame) in self.frames().iter().enumerate() {
|
||||
let ip = frame.ip();
|
||||
try!(write!(fmt, "\n{:4}: {:2$?}", idx, ip, hex_width));
|
||||
|
||||
if frame.symbols.len() == 0 {
|
||||
try!(write!(fmt, " - <no info>"));
|
||||
}
|
||||
|
||||
for (idx, symbol) in frame.symbols().iter().enumerate() {
|
||||
if idx != 0 {
|
||||
try!(write!(fmt, "\n {:1$}", "", hex_width));
|
||||
}
|
||||
|
||||
if let Some(name) = symbol.name() {
|
||||
try!(write!(fmt, " - {}", name));
|
||||
} else {
|
||||
try!(write!(fmt, " - <unknown>"));
|
||||
}
|
||||
|
||||
if let (Some(file), Some(line)) = (symbol.filename(), symbol.lineno()) {
|
||||
try!(write!(fmt, "\n {:3$}at {}:{}", "", file.display(), line, hex_width));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Backtrace {
|
||||
fn default() -> Backtrace {
|
||||
Backtrace::new()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
use std::ffi::CString;
|
||||
use std::marker;
|
||||
use std::mem;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use libc::{self, c_char, c_void};
|
||||
|
||||
pub struct Dylib {
|
||||
pub init: AtomicUsize,
|
||||
}
|
||||
|
||||
pub struct Symbol<T> {
|
||||
pub name: &'static str,
|
||||
pub addr: AtomicUsize,
|
||||
pub _marker: marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl Dylib {
|
||||
pub unsafe fn get<'a, T>(&self, sym: &'a Symbol<T>) -> Option<&'a T> {
|
||||
self.load().and_then(|handle| {
|
||||
sym.get(handle)
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn init(&self, path: &str) -> bool {
|
||||
if self.init.load(Ordering::SeqCst) != 0 {
|
||||
return true
|
||||
}
|
||||
let name = CString::new(path).unwrap();
|
||||
let ptr = libc::dlopen(name.as_ptr() as *const c_char, libc::RTLD_LAZY);
|
||||
if ptr.is_null() {
|
||||
return false
|
||||
}
|
||||
match self.init.compare_and_swap(0, ptr as usize, Ordering::SeqCst) {
|
||||
0 => {}
|
||||
_ => { libc::dlclose(ptr); }
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
unsafe fn load(&self) -> Option<*mut c_void> {
|
||||
match self.init.load(Ordering::SeqCst) {
|
||||
0 => None,
|
||||
n => Some(n as *mut c_void),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Symbol<T> {
|
||||
unsafe fn get(&self, handle: *mut c_void) -> Option<&T> {
|
||||
assert_eq!(mem::size_of::<T>(), mem::size_of_val(&self.addr));
|
||||
if self.addr.load(Ordering::SeqCst) == 0 {
|
||||
self.addr.store(fetch(handle, self.name.as_ptr()), Ordering::SeqCst)
|
||||
}
|
||||
if self.addr.load(Ordering::SeqCst) == 1 {
|
||||
None
|
||||
} else {
|
||||
mem::transmute::<&AtomicUsize, Option<&T>>(&self.addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn fetch(handle: *mut c_void, name: *const u8) -> usize {
|
||||
let ptr = libc::dlsym(handle, name as *const _);
|
||||
if ptr.is_null() {
|
||||
1
|
||||
} else {
|
||||
ptr as usize
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
//! A library for acquiring a backtrace at runtime
|
||||
//!
|
||||
//! This library is meant to supplement the `RUST_BACKTRACE=1` support of the
|
||||
//! standard library by allowing an acquisition of a backtrace at runtime
|
||||
//! programmatically. The backtraces generated by this library do not need to be
|
||||
//! parsed, for example, and expose the functionality of multiple backend
|
||||
//! implementations.
|
||||
//!
|
||||
//! # Implementation
|
||||
//!
|
||||
//! This library makes use of a number of strategies for actually acquiring a
|
||||
//! backtrace. For example unix uses libgcc's libunwind bindings by default to
|
||||
//! acquire a backtrace, but coresymbolication or dladdr is used on OSX to
|
||||
//! acquire symbol names while linux uses gcc's libbacktrace.
|
||||
//!
|
||||
//! When using the default feature set of this library the "most reasonable" set
|
||||
//! of defaults is chosen for the current platform, but the features activated
|
||||
//! can also be controlled at a finer granularity.
|
||||
//!
|
||||
//! # Platform Support
|
||||
//!
|
||||
//! Currently this library is verified to work on Linux, OSX, and Windows, but
|
||||
//! it may work on other platforms as well. Note that the quality of the
|
||||
//! backtrace may vary across platforms.
|
||||
//!
|
||||
//! # API Principles
|
||||
//!
|
||||
//! This library attempts to be as flexible as possible to accomodate different
|
||||
//! backend implementations of acquiring a backtrace. Consequently the currently
|
||||
//! exported functions are closure-based as opposed to the likely expected
|
||||
//! iterator-based versions. This is done due to limitations of the underlying
|
||||
//! APIs used from the system.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! First, add this to your Cargo.toml
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! backtrace = "0.2"
|
||||
//! ```
|
||||
//!
|
||||
//! Next:
|
||||
//!
|
||||
//! ```
|
||||
//! extern crate backtrace;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! backtrace::trace(|frame| {
|
||||
//! let ip = frame.ip();
|
||||
//! let symbol_address = frame.symbol_address();
|
||||
//!
|
||||
//! // Resolve this instruction pointer to a symbol name
|
||||
//! backtrace::resolve(ip, |symbol| {
|
||||
//! if let Some(name) = symbol.name() {
|
||||
//! // ...
|
||||
//! }
|
||||
//! if let Some(filename) = symbol.filename() {
|
||||
//! // ...
|
||||
//! }
|
||||
//! });
|
||||
//!
|
||||
//! true // keep going to the next frame
|
||||
//! });
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "http://alexcrichton.com/backtrace-rs")]
|
||||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate libc;
|
||||
#[cfg(all(windows, feature = "kernel32-sys"))] extern crate kernel32;
|
||||
#[cfg(all(windows, feature = "winapi"))] extern crate winapi;
|
||||
#[cfg(all(windows, feature = "dbghelp"))] extern crate dbghelp;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
extern crate serde;
|
||||
|
||||
#[cfg(feature = "serde_derive")]
|
||||
#[cfg_attr(feature = "serde_derive", macro_use)]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
extern crate rustc_serialize;
|
||||
|
||||
#[macro_use]
|
||||
extern crate cfg_if;
|
||||
|
||||
extern crate rustc_demangle;
|
||||
|
||||
#[cfg(feature = "cpp_demangle")]
|
||||
extern crate cpp_demangle;
|
||||
|
||||
#[allow(dead_code)] // not used everywhere
|
||||
#[cfg(unix)]
|
||||
#[macro_use]
|
||||
mod dylib;
|
||||
|
||||
pub use backtrace::{trace, Frame};
|
||||
mod backtrace;
|
||||
|
||||
pub use symbolize::{resolve, Symbol, SymbolName};
|
||||
mod symbolize;
|
||||
|
||||
pub use capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
|
||||
mod capture;
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Bomb {
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Drop for Bomb {
|
||||
fn drop(&mut self) {
|
||||
if self.enabled {
|
||||
panic!("cannot panic during the backtrace function");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod lock {
|
||||
use std::cell::Cell;
|
||||
use std::mem;
|
||||
use std::sync::{Once, Mutex, MutexGuard, ONCE_INIT};
|
||||
|
||||
pub struct LockGuard(MutexGuard<'static, ()>);
|
||||
|
||||
static mut LOCK: *mut Mutex<()> = 0 as *mut _;
|
||||
static INIT: Once = ONCE_INIT;
|
||||
thread_local!(static LOCK_HELD: Cell<bool> = Cell::new(false));
|
||||
|
||||
impl Drop for LockGuard {
|
||||
fn drop(&mut self) {
|
||||
LOCK_HELD.with(|slot| {
|
||||
assert!(slot.get());
|
||||
slot.set(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lock() -> Option<LockGuard> {
|
||||
if LOCK_HELD.with(|l| l.get()) {
|
||||
return None
|
||||
}
|
||||
LOCK_HELD.with(|s| s.set(true));
|
||||
unsafe {
|
||||
INIT.call_once(|| {
|
||||
LOCK = mem::transmute(Box::new(Mutex::new(())));
|
||||
});
|
||||
Some(LockGuard((*LOCK).lock().unwrap()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// requires external synchronization
|
||||
#[cfg(all(windows, feature = "dbghelp"))]
|
||||
unsafe fn dbghelp_init() {
|
||||
static mut INITIALIZED: bool = false;
|
||||
|
||||
if !INITIALIZED {
|
||||
dbghelp::SymInitializeW(kernel32::GetCurrentProcess(),
|
||||
0 as *mut _,
|
||||
winapi::TRUE);
|
||||
INITIALIZED = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(bad_style)]
|
||||
|
||||
use std::ffi::{CStr, OsStr};
|
||||
use std::mem;
|
||||
use std::os::raw::{c_void, c_char, c_int};
|
||||
use std::os::unix::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::ATOMIC_USIZE_INIT;
|
||||
|
||||
use libc::{self, Dl_info};
|
||||
|
||||
use SymbolName;
|
||||
use dylib::Dylib;
|
||||
use dylib::Symbol as DylibSymbol;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct CSTypeRef {
|
||||
cpp_data: *const c_void,
|
||||
cpp_obj: *const c_void
|
||||
}
|
||||
|
||||
const CS_NOW: u64 = 0x80000000;
|
||||
const CSREF_NULL: CSTypeRef = CSTypeRef {
|
||||
cpp_data: 0 as *const c_void,
|
||||
cpp_obj: 0 as *const c_void,
|
||||
};
|
||||
|
||||
pub enum Symbol {
|
||||
Core {
|
||||
path: *const c_char,
|
||||
lineno: u32,
|
||||
name: *const c_char,
|
||||
addr: *mut c_void,
|
||||
},
|
||||
Dladdr(Dl_info),
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
pub fn name(&self) -> Option<SymbolName> {
|
||||
let name = match *self {
|
||||
Symbol::Core { name, .. } => name,
|
||||
Symbol::Dladdr(ref info) => info.dli_sname,
|
||||
};
|
||||
if name.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(SymbolName::new(unsafe {
|
||||
CStr::from_ptr(name).to_bytes()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
match *self {
|
||||
Symbol::Core { addr, .. } => Some(addr),
|
||||
Symbol::Dladdr(ref info) => Some(info.dli_saddr as *mut _),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
match *self {
|
||||
Symbol::Core { path, .. } => {
|
||||
if path.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Path::new(OsStr::from_bytes(unsafe {
|
||||
CStr::from_ptr(path).to_bytes()
|
||||
})))
|
||||
}
|
||||
}
|
||||
Symbol::Dladdr(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
match *self {
|
||||
Symbol::Core { lineno: 0, .. } => None,
|
||||
Symbol::Core { lineno, .. } => Some(lineno),
|
||||
Symbol::Dladdr(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static CORESYMBOLICATION: Dylib = Dylib { init: ATOMIC_USIZE_INIT };
|
||||
|
||||
macro_rules! dlsym {
|
||||
(extern {
|
||||
$(fn $name:ident($($arg:ident: $t:ty),*) -> $ret:ty;)*
|
||||
}) => ($(
|
||||
static $name: ::dylib::Symbol<unsafe extern fn($($t),*) -> $ret> =
|
||||
::dylib::Symbol {
|
||||
name: concat!(stringify!($name), "\0"),
|
||||
addr: ::std::sync::atomic::ATOMIC_USIZE_INIT,
|
||||
_marker: ::std::marker::PhantomData,
|
||||
};
|
||||
)*)
|
||||
}
|
||||
|
||||
dlsym! {
|
||||
extern {
|
||||
fn CSSymbolicatorCreateWithPid(pid: c_int) -> CSTypeRef;
|
||||
fn CSRelease(rf: CSTypeRef) -> c_void;
|
||||
fn CSSymbolicatorGetSymbolWithAddressAtTime(
|
||||
cs: CSTypeRef, addr: *const c_void, time: u64) -> CSTypeRef;
|
||||
fn CSSymbolicatorGetSourceInfoWithAddressAtTime(
|
||||
cs: CSTypeRef, addr: *const c_void, time: u64) -> CSTypeRef;
|
||||
fn CSSourceInfoGetLineNumber(info: CSTypeRef) -> c_int;
|
||||
fn CSSourceInfoGetPath(info: CSTypeRef) -> *const c_char;
|
||||
fn CSSourceInfoGetSymbol(info: CSTypeRef) -> CSTypeRef;
|
||||
fn CSSymbolGetName(sym: CSTypeRef) -> *const c_char;
|
||||
fn CSSymbolGetSymbolOwner(sym: CSTypeRef) -> CSTypeRef;
|
||||
fn CSSymbolOwnerGetBaseAddress(symowner: CSTypeRef) -> *mut c_void;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn get<T>(sym: &DylibSymbol<T>) -> &T {
|
||||
CORESYMBOLICATION.get(sym).unwrap()
|
||||
}
|
||||
|
||||
unsafe fn try_resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) -> bool {
|
||||
let path = "/System/Library/PrivateFrameworks/CoreSymbolication.framework\
|
||||
/Versions/A/CoreSymbolication";
|
||||
if !CORESYMBOLICATION.init(path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let cs = get(&CSSymbolicatorCreateWithPid)(libc::getpid());
|
||||
if cs == CSREF_NULL {
|
||||
return false
|
||||
}
|
||||
|
||||
let info = get(&CSSymbolicatorGetSourceInfoWithAddressAtTime)(
|
||||
cs, addr, CS_NOW);
|
||||
let sym = if info == CSREF_NULL {
|
||||
get(&CSSymbolicatorGetSymbolWithAddressAtTime)(cs, addr, CS_NOW)
|
||||
} else {
|
||||
get(&CSSourceInfoGetSymbol)(info)
|
||||
};
|
||||
|
||||
let mut rv = false;
|
||||
if sym != CSREF_NULL {
|
||||
let owner = get(&CSSymbolGetSymbolOwner)(sym);
|
||||
if owner != CSREF_NULL {
|
||||
cb(&super::Symbol {
|
||||
inner: Symbol::Core {
|
||||
path: if info != CSREF_NULL {
|
||||
get(&CSSourceInfoGetPath)(info)
|
||||
} else {
|
||||
ptr::null()
|
||||
},
|
||||
lineno: if info != CSREF_NULL {
|
||||
get(&CSSourceInfoGetLineNumber)(info) as u32
|
||||
} else {
|
||||
0
|
||||
},
|
||||
name: get(&CSSymbolGetName)(sym),
|
||||
addr: get(&CSSymbolOwnerGetBaseAddress)(owner),
|
||||
},
|
||||
});
|
||||
rv = true;
|
||||
}
|
||||
}
|
||||
get(&CSRelease)(cs);
|
||||
|
||||
rv
|
||||
}
|
||||
|
||||
pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {
|
||||
unsafe {
|
||||
if try_resolve(addr, cb) {
|
||||
return
|
||||
}
|
||||
let mut info: Dl_info = mem::zeroed();
|
||||
if libc::dladdr(addr as *mut _, &mut info) != 0 {
|
||||
cb(&super::Symbol {
|
||||
inner: Symbol::Dladdr(info),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(bad_style)]
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::mem;
|
||||
use std::path::Path;
|
||||
use std::os::windows::prelude::*;
|
||||
use std::slice;
|
||||
use kernel32;
|
||||
use winapi::*;
|
||||
|
||||
use SymbolName;
|
||||
|
||||
pub struct Symbol {
|
||||
name: OsString,
|
||||
addr: *mut c_void,
|
||||
line: Option<u32>,
|
||||
filename: Option<OsString>,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
pub fn name(&self) -> Option<SymbolName> {
|
||||
self.name.to_str().map(|s| SymbolName::new(s.as_bytes()))
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
Some(self.addr as *mut _)
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
self.filename.as_ref().map(Path::new)
|
||||
}
|
||||
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
self.line
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {
|
||||
// According to windows documentation, all dbghelp functions are
|
||||
// single-threaded.
|
||||
let _g = ::lock::lock();
|
||||
|
||||
unsafe {
|
||||
let size = 2 * MAX_SYM_NAME + mem::size_of::<SYMBOL_INFOW>();
|
||||
let mut data = vec![0u8; size];
|
||||
let info = &mut *(data.as_mut_ptr() as *mut SYMBOL_INFOW);
|
||||
info.MaxNameLen = MAX_SYM_NAME as ULONG;
|
||||
// the struct size in C. the value is different to
|
||||
// `size_of::<SYMBOL_INFOW>() - MAX_SYM_NAME + 1` (== 81)
|
||||
// due to struct alignment.
|
||||
info.SizeOfStruct = 88;
|
||||
|
||||
let _c = ::dbghelp_init();
|
||||
|
||||
let mut displacement = 0u64;
|
||||
let ret = ::dbghelp::SymFromAddrW(kernel32::GetCurrentProcess(),
|
||||
addr as DWORD64,
|
||||
&mut displacement,
|
||||
info);
|
||||
if ret != TRUE {
|
||||
return
|
||||
}
|
||||
let name = slice::from_raw_parts(info.Name.as_ptr() as *const u16,
|
||||
info.NameLen as usize);
|
||||
let name = OsString::from_wide(name);
|
||||
|
||||
let mut line = mem::zeroed::<IMAGEHLP_LINEW64>();
|
||||
line.SizeOfStruct = mem::size_of::<IMAGEHLP_LINEW64>() as DWORD;
|
||||
let mut displacement = 0;
|
||||
let ret = ::dbghelp::SymGetLineFromAddrW64(kernel32::GetCurrentProcess(),
|
||||
addr as DWORD64,
|
||||
&mut displacement,
|
||||
&mut line);
|
||||
let mut filename = None;
|
||||
let mut lineno = None;
|
||||
if ret == TRUE {
|
||||
lineno = Some(line.LineNumber as u32);
|
||||
|
||||
let base = line.FileName;
|
||||
let mut len = 0;
|
||||
while *base.offset(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
let name = slice::from_raw_parts(base, len as usize);
|
||||
filename = Some(OsString::from_wide(name));
|
||||
}
|
||||
|
||||
cb(&super::Symbol {
|
||||
inner: Symbol {
|
||||
name: name,
|
||||
addr: info.Address as *mut _,
|
||||
line: lineno,
|
||||
filename: filename,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use std::path::Path;
|
||||
|
||||
use libc::{self, Dl_info};
|
||||
|
||||
use SymbolName;
|
||||
|
||||
pub struct Symbol {
|
||||
inner: Dl_info,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
pub fn name(&self) -> Option<SymbolName> {
|
||||
if self.inner.dli_sname.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(SymbolName::new(unsafe {
|
||||
CStr::from_ptr(self.inner.dli_sname).to_bytes()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
Some(self.inner.dli_saddr as *mut _)
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {
|
||||
unsafe {
|
||||
let mut info: super::Symbol = super::Symbol {
|
||||
inner: Symbol {
|
||||
inner: mem::zeroed(),
|
||||
},
|
||||
};
|
||||
if libc::dladdr(addr as *mut _, &mut info.inner.inner) != 0 {
|
||||
cb(&info)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(bad_style)]
|
||||
|
||||
extern crate backtrace_sys as bt;
|
||||
|
||||
use libc::uintptr_t;
|
||||
use std::ffi::{CStr, OsStr};
|
||||
use std::os::raw::{c_void, c_char, c_int};
|
||||
use std::os::unix::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
use std::sync::{ONCE_INIT, Once};
|
||||
|
||||
use SymbolName;
|
||||
|
||||
pub enum Symbol {
|
||||
Syminfo {
|
||||
pc: uintptr_t,
|
||||
symname: *const c_char,
|
||||
},
|
||||
Pcinfo {
|
||||
pc: uintptr_t,
|
||||
filename: *const c_char,
|
||||
lineno: c_int,
|
||||
function: *const c_char,
|
||||
},
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
pub fn name(&self) -> Option<SymbolName> {
|
||||
let ptr = match *self {
|
||||
Symbol::Syminfo { symname, .. } => symname,
|
||||
Symbol::Pcinfo { function, .. } => function,
|
||||
};
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(SymbolName::new(unsafe { CStr::from_ptr(ptr).to_bytes() }))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
let pc = match *self {
|
||||
Symbol::Syminfo { pc, .. } => pc,
|
||||
Symbol::Pcinfo { pc, .. } => pc,
|
||||
};
|
||||
if pc == 0 {None} else {Some(pc as *mut _)}
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
match *self {
|
||||
Symbol::Syminfo { .. } => None,
|
||||
Symbol::Pcinfo { filename, .. } => {
|
||||
Some(Path::new(OsStr::from_bytes(unsafe {
|
||||
CStr::from_ptr(filename).to_bytes()
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
match *self {
|
||||
Symbol::Syminfo { .. } => None,
|
||||
Symbol::Pcinfo { lineno, .. } => Some(lineno as u32),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern fn error_cb(_data: *mut c_void, _msg: *const c_char,
|
||||
_errnum: c_int) {
|
||||
// do nothing for now
|
||||
}
|
||||
|
||||
extern fn syminfo_cb(data: *mut c_void,
|
||||
pc: uintptr_t,
|
||||
symname: *const c_char,
|
||||
_symval: uintptr_t,
|
||||
_symsize: uintptr_t) {
|
||||
unsafe {
|
||||
call(data, &super::Symbol {
|
||||
inner: Symbol::Syminfo {
|
||||
pc: pc,
|
||||
symname: symname,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extern fn pcinfo_cb(data: *mut c_void,
|
||||
pc: uintptr_t,
|
||||
filename: *const c_char,
|
||||
lineno: c_int,
|
||||
function: *const c_char) -> c_int {
|
||||
unsafe {
|
||||
if filename.is_null() || function.is_null() {
|
||||
return -1
|
||||
}
|
||||
call(data, &super::Symbol {
|
||||
inner: Symbol::Pcinfo {
|
||||
pc: pc,
|
||||
filename: filename,
|
||||
lineno: lineno,
|
||||
function: function,
|
||||
},
|
||||
});
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn call(data: *mut c_void, sym: &super::Symbol) {
|
||||
let cb = data as *mut &mut FnMut(&super::Symbol);
|
||||
let mut bomb = ::Bomb { enabled: true };
|
||||
(*cb)(sym);
|
||||
bomb.enabled = false;
|
||||
}
|
||||
|
||||
// The libbacktrace API supports creating a state, but it does not
|
||||
// support destroying a state. I personally take this to mean that a
|
||||
// state is meant to be created and then live forever.
|
||||
//
|
||||
// I would love to register an at_exit() handler which cleans up this
|
||||
// state, but libbacktrace provides no way to do so.
|
||||
//
|
||||
// With these constraints, this function has a statically cached state
|
||||
// that is calculated the first time this is requested. Remember that
|
||||
// backtracing all happens serially (one global lock).
|
||||
//
|
||||
// Things don't work so well on not-Linux since libbacktrace can't track down
|
||||
// that executable this is. We at one point used env::current_exe but it turns
|
||||
// out that there are some serious security issues with that approach.
|
||||
//
|
||||
// Specifically, on certain platforms like BSDs, a malicious actor can cause an
|
||||
// arbitrary file to be placed at the path returned by current_exe. libbacktrace
|
||||
// does not behave defensively in the presence of ill-formed DWARF information,
|
||||
// and has been demonstrated to segfault in at least one case. There is no
|
||||
// evidence at the moment to suggest that a more carefully constructed file
|
||||
// can't cause arbitrary code execution. As a result of all of this, we don't
|
||||
// hint libbacktrace with the path to the current process.
|
||||
unsafe fn init_state() -> *mut bt::backtrace_state {
|
||||
static mut STATE: *mut bt::backtrace_state = 0 as *mut _;
|
||||
static INIT: Once = ONCE_INIT;
|
||||
INIT.call_once(|| {
|
||||
// Our libbacktrace may not have multithreading support, so
|
||||
// set `threaded = 0` and synchronize ourselves.
|
||||
STATE = bt::backtrace_create_state(ptr::null(), 0, error_cb,
|
||||
ptr::null_mut());
|
||||
});
|
||||
|
||||
STATE
|
||||
}
|
||||
|
||||
pub fn resolve(symaddr: *mut c_void, mut cb: &mut FnMut(&super::Symbol)) {
|
||||
let _guard = ::lock::lock();
|
||||
|
||||
// backtrace errors are currently swept under the rug
|
||||
unsafe {
|
||||
let state = init_state();
|
||||
if state.is_null() {
|
||||
return
|
||||
}
|
||||
|
||||
let ret = bt::backtrace_pcinfo(state, symaddr as uintptr_t,
|
||||
pcinfo_cb, error_cb,
|
||||
&mut cb as *mut _ as *mut _);
|
||||
if ret != 0 {
|
||||
bt::backtrace_syminfo(state, symaddr as uintptr_t,
|
||||
syminfo_cb, error_cb,
|
||||
&mut cb as *mut _ as *mut _);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
use std::fmt;
|
||||
#[cfg(not(feature = "cpp_demangle"))]
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_void;
|
||||
use std::path::Path;
|
||||
use std::str;
|
||||
use rustc_demangle::{try_demangle, Demangle};
|
||||
|
||||
/// Resolve an address to a symbol, passing the symbol to the specified
|
||||
/// closure.
|
||||
///
|
||||
/// This function will look up the given address in areas such as the local
|
||||
/// symbol table, dynamic symbol table, or DWARF debug info (depending on the
|
||||
/// activated implementation) to find symbols to yield.
|
||||
///
|
||||
/// The closure may not be called if resolution could not be performed, and it
|
||||
/// also may be called more than once in the case of inlined functions.
|
||||
///
|
||||
/// Symbols yielded represent the execution at the specified `addr`, returning
|
||||
/// file/line pairs for that addres (if available).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// extern crate backtrace;
|
||||
///
|
||||
/// fn main() {
|
||||
/// backtrace::trace(|frame| {
|
||||
/// let ip = frame.ip();
|
||||
///
|
||||
/// backtrace::resolve(ip, |symbol| {
|
||||
/// // ...
|
||||
/// });
|
||||
///
|
||||
/// false // only look at the top frame
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, mut cb: F) {
|
||||
resolve_imp(addr, &mut cb)
|
||||
}
|
||||
|
||||
/// A trait representing the resolution of a symbol in a file.
|
||||
///
|
||||
/// This trait is yielded as a trait object to the closure given to the
|
||||
/// `backtrace::resolve` function, and it is virtually dispatched as it's
|
||||
/// unknown which implementation is behind it.
|
||||
///
|
||||
/// A symbol can give contextual information about a funciton, for example the
|
||||
/// name, filename, line number, precise address, etc. Not all information is
|
||||
/// always available in a symbol, however, so all methods return an `Option`.
|
||||
pub struct Symbol {
|
||||
inner: SymbolImp,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
/// Returns the name of this function.
|
||||
///
|
||||
/// The returned structure can be used to query various properties about the
|
||||
/// symbol name:
|
||||
///
|
||||
/// * The `Display` implementation will print out the demangled symbol.
|
||||
/// * The raw `str` value of the symbol can be accessed (if it's valid
|
||||
/// utf-8).
|
||||
/// * The raw bytes for the symbol name can be accessed.
|
||||
pub fn name(&self) -> Option<SymbolName> {
|
||||
self.inner.name()
|
||||
}
|
||||
|
||||
/// Returns the starting address of this function.
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
self.inner.addr()
|
||||
}
|
||||
|
||||
/// Returns the file name where this function was defined.
|
||||
///
|
||||
/// This is currently only available when libbacktrace is being used (e.g.
|
||||
/// unix platforms other than OSX) and when a binary is compiled with
|
||||
/// debuginfo. If neither of these conditions is met then this will likely
|
||||
/// return `None`.
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
self.inner.filename()
|
||||
}
|
||||
|
||||
/// Returns the line number for where this symbol is currently executing.
|
||||
///
|
||||
/// This return value is typically `Some` if `filename` returns `Some`, and
|
||||
/// is consequently subject to similar caveats.
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
self.inner.lineno()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Symbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut d = f.debug_struct("Symbol");
|
||||
if let Some(name) = self.name() {
|
||||
d.field("name", &name);
|
||||
}
|
||||
if let Some(addr) = self.addr() {
|
||||
d.field("addr", &addr);
|
||||
}
|
||||
if let Some(filename) = self.filename() {
|
||||
d.field("filename", &filename);
|
||||
}
|
||||
if let Some(lineno) = self.lineno() {
|
||||
d.field("lineno", &lineno);
|
||||
}
|
||||
d.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "cpp_demangle")] {
|
||||
// Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust
|
||||
// failed.
|
||||
struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>);
|
||||
|
||||
impl<'a> OptionCppSymbol<'a> {
|
||||
fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> {
|
||||
OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok())
|
||||
}
|
||||
|
||||
fn none() -> OptionCppSymbol<'a> {
|
||||
OptionCppSymbol(None)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Make sure to keep this zero-sized, so that the `cpp_demangle` feature
|
||||
// has no cost when disabled.
|
||||
struct OptionCppSymbol<'a>(PhantomData<&'a ()>);
|
||||
|
||||
impl<'a> OptionCppSymbol<'a> {
|
||||
fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> {
|
||||
OptionCppSymbol(PhantomData)
|
||||
}
|
||||
|
||||
fn none() -> OptionCppSymbol<'a> {
|
||||
OptionCppSymbol(PhantomData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around a symbol name to provide ergonomic accessors to the
|
||||
/// demangled name, the raw bytes, the raw string, etc.
|
||||
// Allow dead code for when the `cpp_demangle` feature is not enabled.
|
||||
#[allow(dead_code)]
|
||||
pub struct SymbolName<'a> {
|
||||
bytes: &'a [u8],
|
||||
demangled: Option<Demangle<'a>>,
|
||||
cpp_demangled: OptionCppSymbol<'a>,
|
||||
}
|
||||
|
||||
impl<'a> SymbolName<'a> {
|
||||
/// Creates a new symbol name from the raw underlying bytes.
|
||||
pub fn new(bytes: &'a [u8]) -> SymbolName<'a> {
|
||||
let str_bytes = str::from_utf8(bytes).ok();
|
||||
let demangled = str_bytes.and_then(|s| try_demangle(s).ok());
|
||||
|
||||
let cpp = if demangled.is_none() {
|
||||
OptionCppSymbol::parse(bytes)
|
||||
} else {
|
||||
OptionCppSymbol::none()
|
||||
};
|
||||
|
||||
SymbolName {
|
||||
bytes: bytes,
|
||||
demangled: demangled,
|
||||
cpp_demangled: cpp,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the raw symbol name as a `str` if the symbols is valid utf-8.
|
||||
pub fn as_str(&self) -> Option<&'a str> {
|
||||
self.demangled
|
||||
.as_ref()
|
||||
.map(|s| s.as_str())
|
||||
.or_else(|| {
|
||||
str::from_utf8(self.bytes).ok()
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the raw symbol name as a list of bytes
|
||||
pub fn as_bytes(&self) -> &'a [u8] {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "cpp_demangle")] {
|
||||
impl<'a> fmt::Display for SymbolName<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(ref s) = self.demangled {
|
||||
s.fmt(f)
|
||||
} else if let Some(ref cpp) = self.cpp_demangled.0 {
|
||||
cpp.fmt(f)
|
||||
} else {
|
||||
String::from_utf8_lossy(self.bytes).fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
impl<'a> fmt::Display for SymbolName<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(ref s) = self.demangled {
|
||||
s.fmt(f)
|
||||
} else {
|
||||
String::from_utf8_lossy(self.bytes).fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "cpp_demangle")] {
|
||||
impl<'a> fmt::Debug for SymbolName<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use std::fmt::Write;
|
||||
|
||||
if let Some(ref s) = self.demangled {
|
||||
return s.fmt(f)
|
||||
}
|
||||
|
||||
// This may to print if the demangled symbol isn't actually
|
||||
// valid, so handle the error here gracefully by not propagating
|
||||
// it outwards.
|
||||
if let Some(ref cpp) = self.cpp_demangled.0 {
|
||||
let mut s = String::new();
|
||||
if write!(s, "{}", cpp).is_ok() {
|
||||
return s.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
String::from_utf8_lossy(self.bytes).fmt(f)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
impl<'a> fmt::Debug for SymbolName<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(ref s) = self.demangled {
|
||||
s.fmt(f)
|
||||
} else {
|
||||
String::from_utf8_lossy(self.bytes).fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(all(windows, feature = "dbghelp"))] {
|
||||
mod dbghelp;
|
||||
use self::dbghelp::resolve as resolve_imp;
|
||||
use self::dbghelp::Symbol as SymbolImp;
|
||||
} else if #[cfg(all(feature = "libbacktrace",
|
||||
unix,
|
||||
not(target_os = "emscripten"),
|
||||
not(target_os = "macos"),
|
||||
not(target_os = "ios")))] {
|
||||
mod libbacktrace;
|
||||
use self::libbacktrace::resolve as resolve_imp;
|
||||
use self::libbacktrace::Symbol as SymbolImp;
|
||||
} else if #[cfg(all(feature = "coresymbolication",
|
||||
any(target_os = "macos",
|
||||
target_os = "ios")))] {
|
||||
mod coresymbolication;
|
||||
use self::coresymbolication::resolve as resolve_imp;
|
||||
use self::coresymbolication::Symbol as SymbolImp;
|
||||
} else if #[cfg(all(unix,
|
||||
not(target_os = "emscripten"),
|
||||
feature = "dladdr"))] {
|
||||
mod dladdr;
|
||||
use self::dladdr::resolve as resolve_imp;
|
||||
use self::dladdr::Symbol as SymbolImp;
|
||||
} else {
|
||||
mod noop;
|
||||
use self::noop::resolve as resolve_imp;
|
||||
use self::noop::Symbol as SymbolImp;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
use std::path::Path;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
use SymbolName;
|
||||
|
||||
pub fn resolve(_addr: *mut c_void, _cb: &mut FnMut(&super::Symbol)) {
|
||||
}
|
||||
|
||||
pub struct Symbol;
|
||||
|
||||
impl Symbol {
|
||||
pub fn name(&self) -> Option<SymbolName> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
None
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
extern crate backtrace;
|
||||
|
||||
use std::os::raw::c_void;
|
||||
use std::thread;
|
||||
|
||||
static LIBUNWIND: bool = cfg!(all(unix, feature = "libunwind"));
|
||||
static UNIX_BACKTRACE: bool = cfg!(all(unix, feature = "unix-backtrace"));
|
||||
static LIBBACKTRACE: bool = cfg!(all(unix, feature = "libbacktrace")) &&
|
||||
!cfg!(target_os = "macos") && !cfg!(target_os = "ios");
|
||||
static CORESYMBOLICATION: bool = cfg!(all(any(target_os = "macos", target_os = "ios"),
|
||||
feature = "coresymbolication"));
|
||||
static DLADDR: bool = cfg!(all(unix, feature = "dladdr"));
|
||||
static DBGHELP: bool = cfg!(all(windows, feature = "dbghelp"));
|
||||
static MSVC: bool = cfg!(target_env = "msvc");
|
||||
|
||||
#[test]
|
||||
fn smoke_test_frames() {
|
||||
frame_1(line!());
|
||||
#[inline(never)] fn frame_1(start_line: u32) { frame_2(start_line) }
|
||||
#[inline(never)] fn frame_2(start_line: u32) { frame_3(start_line) }
|
||||
#[inline(never)] fn frame_3(start_line: u32) { frame_4(start_line) }
|
||||
#[inline(never)] fn frame_4(start_line: u32) {
|
||||
let mut v = Vec::new();
|
||||
backtrace::trace(|cx| {
|
||||
v.push((cx.ip(), cx.symbol_address()));
|
||||
true
|
||||
});
|
||||
|
||||
if v.len() < 5 {
|
||||
assert!(!LIBUNWIND);
|
||||
assert!(!UNIX_BACKTRACE);
|
||||
assert!(!DBGHELP);
|
||||
return
|
||||
}
|
||||
|
||||
// On 32-bit windows apparently the first frame isn't our backtrace
|
||||
// frame but it's actually this frame. I'm not entirely sure why, but at
|
||||
// least it seems consistent?
|
||||
let o = if cfg!(all(windows, target_pointer_width = "32")) {1} else {0};
|
||||
// frame offset 0 is the `backtrace::trace` function, but that's generic
|
||||
assert_frame(&v, o, 1, frame_4 as usize, "frame_4",
|
||||
"tests/smoke.rs", start_line + 6);
|
||||
assert_frame(&v, o, 2, frame_3 as usize, "frame_3", "tests/smoke.rs",
|
||||
start_line + 3);
|
||||
assert_frame(&v, o, 3, frame_2 as usize, "frame_2", "tests/smoke.rs",
|
||||
start_line + 2);
|
||||
assert_frame(&v, o, 4, frame_1 as usize, "frame_1", "tests/smoke.rs",
|
||||
start_line + 1);
|
||||
assert_frame(&v, o, 5, smoke_test_frames as usize,
|
||||
"smoke_test_frames", "", 0);
|
||||
}
|
||||
|
||||
fn assert_frame(syms: &[(*mut c_void, *mut c_void)],
|
||||
offset: usize,
|
||||
idx: usize,
|
||||
actual_fn_pointer: usize,
|
||||
expected_name: &str,
|
||||
expected_file: &str,
|
||||
expected_line: u32) {
|
||||
if offset > idx { return }
|
||||
let (ip, sym) = syms[idx - offset];
|
||||
let ip = ip as usize;
|
||||
let sym = sym as usize;
|
||||
assert!(ip >= sym);
|
||||
assert!(sym >= actual_fn_pointer);
|
||||
|
||||
// windows dbghelp is *quite* liberal (and wrong) in many of its reports
|
||||
// right now...
|
||||
if !DBGHELP {
|
||||
assert!(sym - actual_fn_pointer < 1024);
|
||||
}
|
||||
|
||||
let mut resolved = 0;
|
||||
let can_resolve = DLADDR || LIBBACKTRACE || CORESYMBOLICATION || DBGHELP;
|
||||
|
||||
let mut name = None;
|
||||
let mut addr = None;
|
||||
let mut line = None;
|
||||
let mut file = None;
|
||||
backtrace::resolve(ip as *mut c_void, |sym| {
|
||||
resolved += 1;
|
||||
name = sym.name().map(|v| v.to_string());
|
||||
addr = sym.addr();
|
||||
line = sym.lineno();
|
||||
file = sym.filename().map(|v| v.to_path_buf());
|
||||
});
|
||||
|
||||
// dbghelp doesn't always resolve symbols right now
|
||||
match resolved {
|
||||
0 => return assert!(!can_resolve || DBGHELP),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// * linux dladdr doesn't work (only consults local symbol table)
|
||||
// * windows dbghelp isn't great for GNU
|
||||
if can_resolve &&
|
||||
!(cfg!(target_os = "linux") && DLADDR) &&
|
||||
!(DBGHELP && !MSVC)
|
||||
{
|
||||
let name = name.expect("didn't find a name");
|
||||
assert!(name.contains(expected_name),
|
||||
"didn't find `{}` in `{}`", expected_name, name);
|
||||
}
|
||||
|
||||
if can_resolve {
|
||||
addr.expect("didn't find a symbol");
|
||||
}
|
||||
|
||||
if (LIBBACKTRACE || CORESYMBOLICATION || (DBGHELP && MSVC)) && cfg!(debug_assertions) {
|
||||
let line = line.expect("didn't find a line number");
|
||||
let file = file.expect("didn't find a line number");
|
||||
if !expected_file.is_empty() {
|
||||
assert!(file.ends_with(expected_file),
|
||||
"{:?} didn't end with {:?}", file, expected_file);
|
||||
}
|
||||
if expected_line != 0 {
|
||||
assert!(line == expected_line,
|
||||
"bad line number on frame for `{}`: {} != {}",
|
||||
expected_name, line, expected_line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_threads() {
|
||||
let threads = (0..16).map(|_| {
|
||||
thread::spawn(|| {
|
||||
for _ in 0..16 {
|
||||
backtrace::trace(|frame| {
|
||||
backtrace::resolve(frame.ip(), |symbol| {
|
||||
let _s = symbol.name().map(|s| s.to_string());
|
||||
});
|
||||
true
|
||||
});
|
||||
}
|
||||
})
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
for t in threads {
|
||||
t.join().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
fn is_rustc_serialize() {
|
||||
extern crate rustc_serialize;
|
||||
|
||||
fn is_encode<T: rustc_serialize::Encodable>() {}
|
||||
fn is_decode<T: rustc_serialize::Decodable>() {}
|
||||
|
||||
is_encode::<backtrace::Backtrace>();
|
||||
is_decode::<backtrace::Backtrace>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "serde")]
|
||||
fn is_serde() {
|
||||
extern crate serde;
|
||||
|
||||
fn is_serialize<T: serde::ser::Serialize>() {}
|
||||
fn is_deserialize<T: serde::de::DeserializeOwned>() {}
|
||||
|
||||
is_serialize::<backtrace::Backtrace>();
|
||||
is_deserialize::<backtrace::Backtrace>();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"749f043da5cdbd988e2068e94feb3e75ed326945a99cf288c94ae444f5328680","build.rs":"2cf7c28f03f85c8e68969bcb5b076c8effa8543d39a12fe651ff332ac6a394c7","src/lib.rs":"cb45ba047240bceac6ea74da50c2f48ae81a965b578c833a766a3ea0db1075f3","src/libbacktrace/ChangeLog":"ad6f9058524b950aed734db83419e0624df55a48af8091c8bcad7a125aeeffdd","src/libbacktrace/ChangeLog.jit":"ee143b5c9dc571d9aca006be246a83b1f019c39a3fd7b0025eb37463e30200ce","src/libbacktrace/Makefile.am":"74d0036c9715cb7fa6c749cead794ba96283f47d243cf2b25bc6fac8f04667d5","src/libbacktrace/Makefile.in":"9ca92df95c8d62b8a0e106357a796ef4d2c5ec7fd02ab133fd0a65de1984e096","src/libbacktrace/README":"3d1a15714583197945df8db054da6f30613316ec311c5ec2d68b92fab12364a2","src/libbacktrace/aclocal.m4":"e3a6dfa4ce929624ac289b260987a7fa9b512cfbf3ff6f39c5d1e38cbad1a0ea","src/libbacktrace/alloc.c":"829ceab369210fc60758f339807fe0bf55832c77adb3a4450fae586a90a9673d","src/libbacktrace/ansidecl.h":"14acfcd6c044bc73de85b120cbc3e626771a01712911ee1f6137585fd710fb1e","src/libbacktrace/atomic.c":"3e1882a520e0e1115107e194fbd97daa8d3feef15a70047969f4976e7542c263","src/libbacktrace/backtrace-supported.h.in":"42277f3c383386b6cfa3d3d889336e92303fac0ae1a9fb8a6a56737245dfb8f3","src/libbacktrace/backtrace.c":"76bdabddc4eb8a46a7eec98ce610c86909c89c629eb850a0cde98f5a78c9b99d","src/libbacktrace/backtrace.h":"cd2db6474556b655e42c0a973b871c1b6cb4796809490bf59cc8d3d0e8c083f5","src/libbacktrace/btest.c":"fff55e4acf6ad02a6f719046fc4e3f8bf795166ed9956122a79e17c6be266738","src/libbacktrace/config.guess":"8131853dbc8c3be5171fa96353de7a884a79d3f1d6b3fbf48f99037f5f95fe27","src/libbacktrace/config.h.in":"9b0d30416c93906e5c0ce36c95a7426bfd41228114f381949e89d263305b5b65","src/libbacktrace/config.sub":"3b739084e4b409aacf8531f87b57efa602eccdd17b5cddbc4ae1313a2c866f34","src/libbacktrace/configure":"2b45c89d06809c6ed49d70bfdf51a93e44370fc81f689169a073f47b14b366e5","src/libbacktrace/configure.ac":"360b1a033e33d2c58d2f36aaa6644a2aac0dd8960417df6d64202cc099a1c3f3","src/libbacktrace/dwarf.c":"b969c3abb07a09aa4ac5094dba5777d2c23fee77ade4ec0934142d6b81049785","src/libbacktrace/dwarf2.def":"d947302d8b259f0abdd9dd2f50a0713f4e7395c05ce88ddfdb37a7145b045d82","src/libbacktrace/dwarf2.h":"b3b13fa412a1573e3ee8dcb1d603ec33de7140f00b3bbbaa5292724f0087ace3","src/libbacktrace/elf.c":"728d7e47bf077de4dad6eecc76c134b4b4898dc5866572587692848f29aaec5c","src/libbacktrace/fileline.c":"bae25b6662bfd01a43bccc645206e00aeea27f18a51f6303f00f4fa1d9f2e861","src/libbacktrace/filenames.h":"bce400200dbc7452ca2a7f27dd36516949c4c94a135a6a322f011f3ce7817377","src/libbacktrace/filetype.awk":"9dd5352f288c3737fccd24a2c7583f4d0dbca2b95b2735a90a26b644478018af","src/libbacktrace/hashtab.h":"4cb7f68db5c2e8ff1190ecf859e7feb58447ea20bd9818bb1f447b46e2813c58","src/libbacktrace/install-sh":"d7c113e5484fce8b48f9a34a7a91e385ec279247d415b0b7d749bd56ad8ee8a2","src/libbacktrace/internal.h":"ed657e14aa33b4b5217919435e69019c5a677a00a9c134bf0297f000f146b093","src/libbacktrace/ltmain.sh":"ee4019f80b993cdb1bd13bf39434ad4f1ef15ae57a97594c53fb7b1d76d776a4","src/libbacktrace/missing":"b1a337b731bbb58846d31ca2f5143c293a455fa41b481e236e89a9016d96b034","src/libbacktrace/mmap.c":"fec72286a2d8a0c53fd56ea61b3766b87031f6f803f6de6c3c656e39bc85cdc2","src/libbacktrace/mmapio.c":"32a672fd2b8b3395c8a16ef11d839437ca35570fbc235bb0e2e70ef8097a12fc","src/libbacktrace/nounwind.c":"7694636af38ef488c814ab9b71854d6a259c1f3f635bd4c3ed99a88ca2beb5f1","src/libbacktrace/pecoff.c":"00cf6976cfc1e018f5e5473d4fbef4ae86de825dd2749897c45dfcebcefc6abf","src/libbacktrace/posix.c":"73754fcfa0a5b0342e8fe32166e7228b61e022699a8a3c9a2ef8e46260736704","src/libbacktrace/print.c":"ec1e80e17e27130bf9412470e8dc9155a0dc9ca3a78125081f5073b438b54157","src/libbacktrace/read.c":"399458fb06389aa4bd5ce376c4620cf733b5555d1dabe7ef19f185da1e37e614","src/libbacktrace/simple.c":"686d976c2bdb1a074f9be05af026d4b4c7a4978c2602268747d492563f18e0dc","src/libbacktrace/sort.c":"1a1e44af4e4d02fc568b318aa1517792edd6972a27029ba78e938856ef8ba1a0","src/libbacktrace/state.c":"49d547f5622b0ea0c39bc873b09a7dce276fdc6469118f5ab2e72c55bd0457fb","src/libbacktrace/stest.c":"aa1b90fe2d6dc8ac65ac0168776c2d242efc6460ac596deb14ac1e72bf764871","src/libbacktrace/unknown.c":"914aa113cd17ed678d40927391b35f6027e87b3a02e36e9f1822ec1efe9c0e20","symbol-map":"b941b2516efbb9e46521eeb166c60b31d52b2a4aaaf35d7f9af24946bbe1328a"},"package":"d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842"}
|
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.10"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
build = "build.rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/alexcrichton/backtrace-rs"
|
||||
homepage = "https://github.com/alexcrichton/backtrace-rs"
|
||||
documentation = "http://alexcrichton.com/backtrace-rs"
|
||||
description = """
|
||||
Bindings to the libbacktrace gcc library
|
||||
"""
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3"
|
|
@ -0,0 +1,136 @@
|
|||
extern crate gcc;
|
||||
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
macro_rules! t {
|
||||
($e:expr) => (match $e {
|
||||
Ok(e) => e,
|
||||
Err(e) => panic!("{} failed with {}", stringify!($e), e),
|
||||
})
|
||||
}
|
||||
|
||||
fn try_tool(compiler: &gcc::Tool, cc: &str, compiler_suffix: &str, tool_suffix: &str)
|
||||
-> Option<PathBuf> {
|
||||
if !cc.ends_with(compiler_suffix) {
|
||||
return None
|
||||
}
|
||||
let cc = cc.replace(compiler_suffix, tool_suffix);
|
||||
let candidate = compiler.path().parent().unwrap().join(cc);
|
||||
if Command::new(&candidate).output().is_ok() {
|
||||
Some(candidate)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn find_tool(compiler: &gcc::Tool, cc: &str, tool: &str) -> PathBuf {
|
||||
// Allow overrides via env var
|
||||
if let Some(s) = env::var_os(tool.to_uppercase()) {
|
||||
return s.into()
|
||||
}
|
||||
let tool_suffix = format!("-{}", tool);
|
||||
try_tool(compiler, cc, "-gcc", &tool_suffix)
|
||||
.or_else(|| try_tool(compiler, cc, "-cc", &tool_suffix))
|
||||
.unwrap_or_else(|| PathBuf::from(tool))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let src = env::current_dir().unwrap();
|
||||
let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let host = env::var("HOST").unwrap();
|
||||
|
||||
// libbacktrace doesn't currently support Mach-O files
|
||||
if target.contains("darwin") {
|
||||
return
|
||||
}
|
||||
|
||||
// libbacktrace isn't used on windows
|
||||
if target.contains("windows") {
|
||||
return
|
||||
}
|
||||
|
||||
// no way this will ever compile for emscripten
|
||||
if target.contains("emscripten") {
|
||||
return
|
||||
}
|
||||
|
||||
let cfg = gcc::Config::new();
|
||||
let compiler = cfg.get_compiler();
|
||||
let cc = compiler.path().file_name().unwrap().to_str().unwrap();
|
||||
let mut flags = OsString::new();
|
||||
for (i, flag) in compiler.args().iter().enumerate() {
|
||||
if i > 0 {
|
||||
flags.push(" ");
|
||||
}
|
||||
flags.push(flag);
|
||||
}
|
||||
let ar = find_tool(&compiler, cc, "ar");
|
||||
run(Command::new(src.join("src/libbacktrace/configure"))
|
||||
.current_dir(&dst)
|
||||
.env("CC", compiler.path())
|
||||
.env("CFLAGS", flags)
|
||||
.arg("--with-pic")
|
||||
.arg("--disable-multilib")
|
||||
.arg("--disable-shared")
|
||||
.arg("--disable-host-shared")
|
||||
.arg(format!("--target={}", target))
|
||||
.arg(format!("--host={}", host)),
|
||||
"sh");
|
||||
run(Command::new("make")
|
||||
.current_dir(&dst)
|
||||
.arg(format!("INCDIR={}",
|
||||
src.join("src/libbacktrace").display())),
|
||||
"make");
|
||||
println!("cargo:rustc-link-search=native={}/.libs", dst.display());
|
||||
println!("cargo:rustc-link-lib=static=backtrace");
|
||||
|
||||
// The standard library currently bundles in libbacktrace, but it's
|
||||
// compiled with hidden visibility (naturally) so we can't use it.
|
||||
//
|
||||
// To prevent conflicts with a second statically linked copy we rename all
|
||||
// symbols with a '__rbt_' prefix manually here through `objcopy`.
|
||||
let lib = dst.join(".libs/libbacktrace.a");
|
||||
let tmpdir = dst.join("__tmp");
|
||||
drop(fs::remove_dir_all(&tmpdir));
|
||||
t!(fs::create_dir_all(&tmpdir));
|
||||
run(Command::new(&ar).arg("x").arg(&lib).current_dir(&tmpdir),
|
||||
ar.to_str().unwrap());
|
||||
|
||||
t!(fs::remove_file(&lib));
|
||||
let mut objs = Vec::new();
|
||||
let objcopy = find_tool(&compiler, cc, "objcopy");
|
||||
for obj in t!(tmpdir.read_dir()) {
|
||||
let obj = t!(obj);
|
||||
run(Command::new(&objcopy)
|
||||
.arg("--redefine-syms=symbol-map")
|
||||
.arg(obj.path()),
|
||||
objcopy.to_str().unwrap());
|
||||
objs.push(obj.path());
|
||||
}
|
||||
|
||||
run(Command::new(&ar).arg("crus").arg(&lib).args(&objs),
|
||||
ar.to_str().unwrap());
|
||||
}
|
||||
|
||||
fn run(cmd: &mut Command, program: &str) {
|
||||
println!("running: {:?}", cmd);
|
||||
let status = match cmd.status() {
|
||||
Ok(s) => s,
|
||||
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
|
||||
panic!("\n\nfailed to execute command: {}\nIs `{}` \
|
||||
not installed?\n\n",
|
||||
e,
|
||||
program);
|
||||
}
|
||||
Err(e) => panic!("failed to get status: {}", e),
|
||||
};
|
||||
if !status.success() {
|
||||
panic!("failed with: {}", status);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#![allow(bad_style)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use libc::uintptr_t;
|
||||
use std::os::raw::{c_void, c_char, c_int};
|
||||
|
||||
pub type backtrace_syminfo_callback =
|
||||
extern fn(data: *mut c_void,
|
||||
pc: uintptr_t,
|
||||
symname: *const c_char,
|
||||
symval: uintptr_t,
|
||||
symsize: uintptr_t);
|
||||
pub type backtrace_full_callback =
|
||||
extern fn(data: *mut c_void,
|
||||
pc: uintptr_t,
|
||||
filename: *const c_char,
|
||||
lineno: c_int,
|
||||
function: *const c_char) -> c_int;
|
||||
pub type backtrace_error_callback =
|
||||
extern fn(data: *mut c_void,
|
||||
msg: *const c_char,
|
||||
errnum: c_int);
|
||||
pub enum backtrace_state {}
|
||||
|
||||
extern {
|
||||
#[link_name = "__rbt_backtrace_create_state"]
|
||||
pub fn backtrace_create_state(filename: *const c_char,
|
||||
threaded: c_int,
|
||||
error: backtrace_error_callback,
|
||||
data: *mut c_void) -> *mut backtrace_state;
|
||||
#[link_name = "__rbt_backtrace_syminfo"]
|
||||
pub fn backtrace_syminfo(state: *mut backtrace_state,
|
||||
addr: uintptr_t,
|
||||
cb: backtrace_syminfo_callback,
|
||||
error: backtrace_error_callback,
|
||||
data: *mut c_void) -> c_int;
|
||||
#[link_name = "__rbt_backtrace_pcinfo"]
|
||||
pub fn backtrace_pcinfo(state: *mut backtrace_state,
|
||||
addr: uintptr_t,
|
||||
cb: backtrace_full_callback,
|
||||
error: backtrace_error_callback,
|
||||
data: *mut c_void) -> c_int;
|
||||
}
|
|
@ -0,0 +1,598 @@
|
|||
2016-11-15 Matthias Klose <doko@ubuntu.com>
|
||||
|
||||
* configure: Regenerate.
|
||||
|
||||
2016-09-11 Carlos Liam <carlos@aarzee.me>
|
||||
|
||||
* all: Remove meaningless trailing whitespace.
|
||||
|
||||
2016-05-18 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
PR target/71161
|
||||
* elf.c (phdr_callback) [__i386__]: Add
|
||||
__attribute__((__force_align_arg_pointer__)).
|
||||
|
||||
2016-03-02 Maxim Ostapenko <m.ostapenko@partner.samsung.com>
|
||||
|
||||
* elf.c (backtrace_initialize): Properly initialize elf_fileline_fn to
|
||||
avoid possible crash.
|
||||
(elf_add): Don't set *fileline_fn to elf_nodebug value in case of
|
||||
missing debug info anymore.
|
||||
|
||||
2016-02-06 John David Anglin <danglin@gcc.gnu.org>
|
||||
|
||||
* mmap.c (MAP_FAILED): Define if not defined.
|
||||
|
||||
2016-01-04 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
Update copyright years.
|
||||
|
||||
2015-12-18 Andris Pavenis <andris.pavenis@iki.fi>
|
||||
|
||||
* configure.ac: Specify that DJGPP do not have mmap
|
||||
even when sys/mman.h exists.
|
||||
* configure: Regenerate
|
||||
|
||||
2015-12-09 John David Anglin <danglin@gcc.gnu.org>
|
||||
|
||||
PR libgfortran/68115
|
||||
* configure.ac: Set libbacktrace_cv_sys_sync to no on hppa*-*-hpux*.
|
||||
* configure: Regenerate.
|
||||
* elf.c (backtrace_initialize): Cast __sync_bool_compare_and_swap call
|
||||
to void.
|
||||
|
||||
2015-09-17 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* posix.c (backtrace_open): Cast second argument of open() to int.
|
||||
|
||||
2015-09-11 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* Makefile.am (backtrace.lo): Depend on internal.h.
|
||||
(sort.lo, stest.lo): Add explicit dependencies.
|
||||
* Makefile.in: Rebuild.
|
||||
|
||||
2015-09-09 Hans-Peter Nilsson <hp@axis.com>
|
||||
|
||||
* backtrace.c: #include <sys/types.h>.
|
||||
|
||||
2015-09-08 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR other/67457
|
||||
* backtrace.c: #include "internal.h".
|
||||
(struct backtrace_data): Add can_alloc field.
|
||||
(unwind): If can_alloc is false, don't try to get file/line
|
||||
information.
|
||||
(backtrace_full): Set can_alloc field in bdata.
|
||||
* alloc.c (backtrace_alloc): Don't call error_callback if it is
|
||||
NULL.
|
||||
* mmap.c (backtrace_alloc): Likewise.
|
||||
* internal.h: Update comments for backtrace_alloc and
|
||||
backtrace_free.
|
||||
|
||||
2015-09-08 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR other/67457
|
||||
* mmap.c (backtrace_alloc): Correct test for mmap failure.
|
||||
|
||||
2015-08-31 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
|
||||
|
||||
* configure.ac: For spu-*-* targets, set have_fcntl to no.
|
||||
* configure: Regenerate.
|
||||
|
||||
2015-08-27 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
|
||||
|
||||
* configure.ac: Remove [disable-shared] argument to LT_INIT.
|
||||
Remove setting PIC_FLAG when building as target library.
|
||||
* configure: Regenerate.
|
||||
|
||||
2015-08-26 Hans-Peter Nilsson <hp@axis.com>
|
||||
|
||||
* configure.ac: Only compile with -fPIC if the target
|
||||
supports it.
|
||||
* configure: Regenerate.
|
||||
|
||||
2015-08-24 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
|
||||
|
||||
* configure.ac: Set have_mmap to no on spu-*-* targets.
|
||||
* configure: Regenerate.
|
||||
|
||||
2015-08-13 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* dwarf.c (read_function_entry): Add vec_inlined parameter.
|
||||
Change all callers.
|
||||
|
||||
2015-06-11 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR sanitizer/65479
|
||||
* dwarf.c (struct line): Add new field idx.
|
||||
(line_compare): Use it.
|
||||
(add_line): Set it.
|
||||
(read_line_info): Reset it.
|
||||
|
||||
2015-05-29 Tristan Gingold <gingold@adacore.com>
|
||||
|
||||
* pecoff.c: New file.
|
||||
* Makefile.am (FORMAT_FILES): Add pecoff.c and dependencies.
|
||||
* Makefile.in: Regenerate.
|
||||
* filetype.awk: Detect pecoff.
|
||||
* configure.ac: Define BACKTRACE_SUPPORTS_DATA on elf platforms.
|
||||
Add pecoff.
|
||||
* btest.c (test5): Test enabled only if BACKTRACE_SUPPORTS_DATA is
|
||||
true.
|
||||
* backtrace-supported.h.in (BACKTRACE_SUPPORTS_DATA): Define.
|
||||
* configure: Regenerate.
|
||||
* pecoff.c: New file.
|
||||
|
||||
2015-05-13 Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>
|
||||
|
||||
* Makefile.in: Regenerated with automake-1.11.6.
|
||||
* aclocal.m4: Likewise.
|
||||
* configure: Likewise.
|
||||
|
||||
2015-01-24 Matthias Klose <doko@ubuntu.com>
|
||||
|
||||
* configure.ac: Move AM_ENABLE_MULTILIB before AC_PROG_CC.
|
||||
* configure: Regenerate.
|
||||
|
||||
2015-01-05 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
Update copyright years.
|
||||
|
||||
2014-11-21 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
PR bootstrap/63784
|
||||
* configure: Regenerated.
|
||||
|
||||
2014-11-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ChangeLog.jit: New.
|
||||
|
||||
2014-11-11 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
|
||||
|
||||
PR target/63610
|
||||
* configure: Regenerate.
|
||||
|
||||
2014-10-23 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* internal.h (backtrace_atomic_load_pointer) [no atomic or sync]:
|
||||
Fix to return void *.
|
||||
|
||||
2014-05-08 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* mmap.c (backtrace_free): If freeing a large aligned block of
|
||||
memory, call munmap rather than holding onto it.
|
||||
(backtrace_vector_grow): When growing a vector, double the number
|
||||
of pages requested. When releasing the old version of a grown
|
||||
vector, pass the correct size to backtrace_free.
|
||||
|
||||
2014-03-07 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* sort.c (backtrace_qsort): Use middle element as pivot.
|
||||
|
||||
2014-03-06 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* sort.c: New file.
|
||||
* stest.c: New file.
|
||||
* internal.h (backtrace_qsort): Declare.
|
||||
* dwarf.c (read_abbrevs): Call backtrace_qsort instead of qsort.
|
||||
(read_line_info, read_function_entry): Likewise.
|
||||
(read_function_info, build_dwarf_data): Likewise.
|
||||
* elf.c (elf_initialize_syminfo): Likewise.
|
||||
* Makefile.am (libbacktrace_la_SOURCES): Add sort.c.
|
||||
(stest_SOURCES, stest_LDADD): Define.
|
||||
(check_PROGRAMS): Add stest.
|
||||
|
||||
2014-02-07 Misty De Meo <misty@brew.sh>
|
||||
|
||||
PR target/58710
|
||||
* configure.ac: Use AC_LINK_IFELSE in check for
|
||||
_Unwind_GetIPInfo.
|
||||
* configure: Regenerate.
|
||||
|
||||
2014-01-02 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
Update copyright years
|
||||
|
||||
2013-12-06 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* elf.c (ET_DYN): Undefine and define again.
|
||||
(elf_add): Add exe argument, if true and ehdr.e_type is ET_DYN,
|
||||
return early -1 without closing the descriptor.
|
||||
(struct phdr_data): Add exe_descriptor.
|
||||
(phdr_callback): If pd->exe_descriptor is not -1, for very first
|
||||
call if dlpi_name is NULL just call elf_add with the exe_descriptor,
|
||||
otherwise backtrace_close the exe_descriptor if not -1. Adjust
|
||||
call to elf_add.
|
||||
(backtrace_initialize): Adjust call to elf_add. If it returns
|
||||
-1, set pd.exe_descriptor to descriptor, otherwise set it to -1.
|
||||
|
||||
2013-12-05 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* alloc.c (backtrace_vector_finish): Add error_callback and data
|
||||
parameters. Call backtrace_vector_release. Return address base.
|
||||
* mmap.c (backtrace_vector_finish): Add error_callback and data
|
||||
parameters. Return address base.
|
||||
* dwarf.c (read_function_info): Get new address base from
|
||||
backtrace_vector_finish.
|
||||
* internal.h (backtrace_vector_finish): Update declaration.
|
||||
|
||||
2013-11-27 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* dwarf.c (find_address_ranges): New static function, broken out
|
||||
of build_address_map.
|
||||
(build_address_map): Call it.
|
||||
* btest.c (check): Check for missing filename or function, rather
|
||||
than crashing.
|
||||
(f3): Check that enough frames were returned.
|
||||
|
||||
2013-11-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* backtrace.h (backtrace_syminfo_callback): Add symsize argument.
|
||||
* elf.c (elf_syminfo): Pass 0 or sym->size to the callback as
|
||||
last argument.
|
||||
* btest.c (struct symdata): Add size field.
|
||||
(callback_three): Add symsize argument. Copy it to the data->size
|
||||
field.
|
||||
(f23): Set symdata.size to 0.
|
||||
(test5): Likewise. If sizeof (int) > 1, lookup address of
|
||||
((uintptr_t) &global) + 1. Verify symdata.val and symdata.size
|
||||
values.
|
||||
|
||||
* atomic.c: Include sys/types.h.
|
||||
|
||||
2013-11-18 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* configure.ac: Check for support of __atomic extensions.
|
||||
* internal.h: Declare or #define atomic functions for use in
|
||||
backtrace code.
|
||||
* atomic.c: New file.
|
||||
* dwarf.c (dwarf_lookup_pc): Use atomic functions.
|
||||
(dwarf_fileline, backtrace_dwarf_add): Likewise.
|
||||
* elf.c (elf_add_syminfo_data, elf_syminfo): Likewise.
|
||||
(backtrace_initialize): Likewise.
|
||||
* fileline.c (fileline_initialize): Likewise.
|
||||
* Makefile.am (libbacktrace_la_SOURCES): Add atomic.c.
|
||||
* configure, config.h.in, Makefile.in: Rebuild.
|
||||
|
||||
2013-11-18 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* elf.c (SHN_UNDEF): Define.
|
||||
(elf_initialize_syminfo): Add base_address argument. Ignore symbols
|
||||
with st_shndx == SHN_UNDEF. Add base_address to address fields.
|
||||
(elf_add): Adjust caller.
|
||||
|
||||
* elf.c (phdr_callback): Process info->dlpi_addr == 0 normally.
|
||||
|
||||
2013-11-16 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* backtrace.h (backtrace_create_state): Correct comment about
|
||||
threading.
|
||||
|
||||
2013-11-15 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* backtrace.h (backtrace_syminfo): Update comment and parameter
|
||||
name to take any address, not just a PC value.
|
||||
* elf.c (STT_OBJECT): Define.
|
||||
(elf_nosyms): Rename parameter pc to addr.
|
||||
(elf_symbol_search): Rename local variable pc to addr.
|
||||
(elf_initialize_syminfo): Add STT_OBJECT symbols to elf_symbols.
|
||||
(elf_syminfo): Rename parameter pc to addr.
|
||||
* btest.c (global): New global variable.
|
||||
(test5): New test.
|
||||
(main): Call test5.
|
||||
|
||||
2013-10-17 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* elf.c (elf_add): Don't get the wrong offsets if a debug section
|
||||
is missing.
|
||||
|
||||
2013-10-15 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* configure.ac: Add --enable-host-shared, setting up
|
||||
pre-existing PIC_FLAG variable within Makefile.am et al.
|
||||
* configure: Regenerate.
|
||||
|
||||
2013-09-20 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* configure: Regenerate.
|
||||
|
||||
2013-07-23 Alexander Monakov <amonakov@ispras.ru>
|
||||
|
||||
* elf.c (elf_syminfo): Loop over the elf_syminfo_data chain.
|
||||
|
||||
2013-07-23 Alexander Monakov <amonakov@ispras.ru>
|
||||
|
||||
* elf.c (backtrace_initialize): Pass elf_fileline_fn to
|
||||
dl_iterate_phdr callbacks.
|
||||
|
||||
2013-03-25 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* alloc.c: #include <sys/types.h>.
|
||||
* mmap.c: Likewise.
|
||||
|
||||
2013-01-31 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* dwarf.c (read_function_info): Permit fvec parameter to be NULL.
|
||||
(dwarf_lookup_pc): Don't use ddata->fvec if threaded.
|
||||
|
||||
2013-01-25 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR other/56076
|
||||
* dwarf.c (read_line_header): Don't crash if DW_AT_comp_dir
|
||||
attribute was not seen.
|
||||
|
||||
2013-01-16 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* dwarf.c (struct unit): Add filename and abs_filename fields.
|
||||
(build_address_map): Set new fields when reading unit.
|
||||
(dwarf_lookup_pc): If we don't find an entry in the line table,
|
||||
just return the main file name.
|
||||
|
||||
2013-01-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
Update copyright years.
|
||||
|
||||
2013-01-01 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR bootstrap/54834
|
||||
* Makefile.am (AM_CPPFLAGS): Remove -I ../gcc/include and -I
|
||||
$(MULTIBUILDTOP)/../../gcc/include.
|
||||
* Makefile.in: Rebuild.
|
||||
|
||||
2013-01-01 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR other/55536
|
||||
* mmap.c (backtrace_alloc): Don't call sync functions if not
|
||||
threaded.
|
||||
(backtrace_free): Likewise.
|
||||
|
||||
2012-12-12 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
|
||||
|
||||
* mmapio.c: Define MAP_FAILED if not defined.
|
||||
|
||||
2012-12-11 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR bootstrap/54926
|
||||
* Makefile.am (AM_CFLAGS): Remove -frandom-seed=$@.
|
||||
* configure.ac: If --with-target-subdir, add -frandom-seed=$@
|
||||
to EXTRA_FLAGS unconditionally, otherwise check whether the compiler
|
||||
accepts it.
|
||||
* Makefile.in: Regenerated.
|
||||
* configure: Regenerated.
|
||||
|
||||
2012-12-07 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR bootstrap/54926
|
||||
* Makefile.am (AM_CFLAGS): Add -frandom-seed=$@.
|
||||
* Makefile.in: Regenerated.
|
||||
|
||||
2012-11-20 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* dwarf.c (read_attribute): Always clear val.
|
||||
|
||||
2012-11-13 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR other/55312
|
||||
* configure.ac: Only add -Werror if building a target library.
|
||||
* configure: Rebuild.
|
||||
|
||||
2012-11-12 Ian Lance Taylor <iant@google.com>
|
||||
Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
|
||||
Gerald Pfeifer <gerald@pfeifer.com>
|
||||
|
||||
* configure.ac: Check for getexecname.
|
||||
* fileline.c: #include <errno.h>. Define getexecname if not
|
||||
available.
|
||||
(fileline_initialize): Try to find the executable in a few
|
||||
different ways.
|
||||
* print.c (error_callback): Only print the filename if it came
|
||||
from the backtrace state.
|
||||
* configure, config.h.in: Rebuild.
|
||||
|
||||
2012-10-29 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* mmap.c (backtrace_vector_release): Correct last patch: add
|
||||
aligned, not size.
|
||||
|
||||
2012-10-29 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* mmap.c (backtrace_vector_release): Make sure freed block is
|
||||
aligned on 8-byte boundary.
|
||||
|
||||
2012-10-26 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR other/55087
|
||||
* posix.c (backtrace_open): Add does_not_exist parameter.
|
||||
* elf.c (phdr_callback): Do not warn if shared library could not
|
||||
be opened.
|
||||
* fileline.c (fileline_initialize): Update calls to
|
||||
backtrace_open.
|
||||
* internal.h (backtrace_open): Update declaration.
|
||||
|
||||
2012-10-26 Jack Howarth <howarth@bromo.med.uc.edu>
|
||||
|
||||
PR target/55061
|
||||
* configure.ac: Check for _Unwind_GetIPInfo function declaration.
|
||||
* configure: Regenerate.
|
||||
|
||||
2012-10-24 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR target/55061
|
||||
* configure.ac: Check whether -funwind-tables option works.
|
||||
* configure: Rebuild.
|
||||
|
||||
2012-10-11 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* configure.ac: Do not use dl_iterate_phdr on Solaris 10.
|
||||
* configure: Rebuild.
|
||||
|
||||
2012-10-10 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* elf.c: Rename all Elf typedefs to start with b_elf, and be all
|
||||
lower case.
|
||||
|
||||
2012-10-10 Hans-Peter Nilsson <hp@bitrange.com>
|
||||
|
||||
* elf.c (elf_add_syminfo_data): Add casts to avoid warning.
|
||||
|
||||
2012-10-09 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* dwarf.c (dwarf_fileline): Add cast to avoid warning.
|
||||
(backtrace_dwarf_add): Likewise.
|
||||
|
||||
2012-10-09 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
Add support for tracing through shared libraries.
|
||||
* configure.ac: Check for link.h and dl_iterate_phdr.
|
||||
* elf.c: #include <link.h> if system has dl_iterate_phdr. #undef
|
||||
ELF macros before #defining them.
|
||||
(dl_phdr_info, dl_iterate_phdr): Define if system does not have
|
||||
dl_iterate_phdr.
|
||||
(struct elf_syminfo_data): Add next field.
|
||||
(elf_initialize_syminfo): Initialize next field.
|
||||
(elf_add_syminfo_data): New static function.
|
||||
(elf_add): New static function, broken out of
|
||||
backtrace_initialize. Call backtrace_dwarf_add instead of
|
||||
backtrace_dwarf_initialize.
|
||||
(struct phdr_data): Define.
|
||||
(phdr_callback): New static function.
|
||||
(backtrace_initialize): Call elf_add.
|
||||
* dwarf.c (struct dwarf_data): Add next and base_address fields.
|
||||
(add_unit_addr): Add base_address parameter. Change all callers.
|
||||
(add_unit_ranges, build_address_map): Likewise.
|
||||
(add_line): Add ddata parameter. Change all callers.
|
||||
(read_line_program, add_function_range): Likewise.
|
||||
(dwarf_lookup_pc): New static function, broken out of
|
||||
dwarf_fileline.
|
||||
(dwarf_fileline): Call dwarf_lookup_pc.
|
||||
(build_dwarf_data): New static function.
|
||||
(backtrace_dwarf_add): New function.
|
||||
(backtrace_dwarf_initialize): Remove.
|
||||
* internal.h (backtrace_dwarf_initialize): Don't declare.
|
||||
(backtrace_dwarf_add): Declare.
|
||||
* configure, config.h.in: Rebuild.
|
||||
|
||||
2012-10-04 Gerald Pfeifer <gerald@pfeifer.com>
|
||||
|
||||
* btest.c (f23): Avoid uninitialized variable warning.
|
||||
|
||||
2012-10-04 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* dwarf.c: If the system header files do not declare strnlen,
|
||||
provide our own version.
|
||||
|
||||
2012-10-03 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* dwarf.c (read_uleb128): Fix overflow test.
|
||||
(read_sleb128): Likewise.
|
||||
(build_address_map): Don't change unit_buf.start.
|
||||
|
||||
2012-10-02 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
PR other/54761
|
||||
* configure.ac (EXTRA_FLAGS): New.
|
||||
* Makefile.am (AM_FLAGS): Add $(EXTRA_FLAGS).
|
||||
* configure, Makefile.in: Regenerate.
|
||||
|
||||
2012-09-29 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR other/54749
|
||||
* fileline.c (fileline_initialize): Pass errnum as -1 when
|
||||
reporting that we could not read executable information after a
|
||||
previous failure.
|
||||
|
||||
2012-09-27 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR bootstrap/54732
|
||||
* configure.ac: Add no-dependencies to AM_INIT_AUTOMAKE.
|
||||
* Makefile.am: Add dependencies for all objects.
|
||||
* configure, aclocal.m4, Makefile.in: Rebuild.
|
||||
|
||||
2012-09-27 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR other/54726
|
||||
* elf.c (backtrace_initialize): Set *fileln_fn, not
|
||||
state->fileln_fn.
|
||||
|
||||
2012-09-19 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* configure.ac: Only use GCC_CHECK_UNWIND_GETIPINFO when compiled
|
||||
as a target library.
|
||||
* configure: Rebuild.
|
||||
|
||||
2012-09-19 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
|
||||
Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* configure.ac (GCC_HEADER_STDINT): Invoke.
|
||||
* backtrace.h: If we can't find <stdint.h>, use "gstdint.h".
|
||||
* btest.c: Don't include <stdint.h>.
|
||||
* dwarf.c: Likewise.
|
||||
* configure, aclocal.m4, Makefile.in, config.h.in: Rebuild.
|
||||
|
||||
2012-09-18 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR bootstrap/54623
|
||||
* Makefile.am (AM_CPPFLAGS): Define.
|
||||
(AM_CFLAGS): Remove -I options.
|
||||
* Makefile.in: Rebuild.
|
||||
|
||||
2012-09-18 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* posix.c (O_BINARY): Define if not defined.
|
||||
(backtrace_open): Pass O_BINARY to open. Only call fcntl if
|
||||
HAVE_FCNTL is defined.
|
||||
* configure.ac: Test for the fcntl function.
|
||||
* configure, config.h.in: Rebuild.
|
||||
|
||||
2012-09-18 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* btest.c (test1, test2, test3, test4): Add the unused attribute.
|
||||
|
||||
2012-09-18 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* dwarf.c: Correct test of HAVE_DECL_STRNLEN.
|
||||
|
||||
2012-09-18 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* configure.ac: Add AC_USE_SYSTEM_EXTENSIONS.
|
||||
* mmapio.c: Don't define _GNU_SOURCE.
|
||||
* configure, config.h.in: Rebuild.
|
||||
|
||||
2012-09-18 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* configure.ac: Check whether strnlen is declared.
|
||||
* dwarf.c: Declare strnlen if not declared.
|
||||
* configure, config.h.in: Rebuild.
|
||||
|
||||
2012-09-18 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
|
||||
|
||||
* fileline.c: Include <stdlib.h>.
|
||||
* mmap.c: Likewise.
|
||||
|
||||
2012-09-17 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR bootstrap/54611
|
||||
* nounwind.c (backtrace_full): Rename from backtrace. Add state
|
||||
parameter.
|
||||
|
||||
2012-09-17 Gerald Pfeifer <gerald@pfeifer.com>
|
||||
|
||||
PR bootstrap/54611
|
||||
* nounwind.c (backtrace_simple): Add state parameter.
|
||||
|
||||
2012-09-17 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR bootstrap/54609
|
||||
* unknown.c (unknown_fileline): Add state parameter, remove
|
||||
fileline_data parameter, name error_callback parameter.
|
||||
(backtrace_initialize): Add state parameter.
|
||||
|
||||
2012-09-17 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* Initial implementation.
|
||||
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved.
|
|
@ -0,0 +1,14 @@
|
|||
2014-09-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ChangeLog.jit: Add copyright footer.
|
||||
|
||||
2013-10-03 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* configure.ac: Add --enable-host-shared.
|
||||
* configure: Regenerate.
|
||||
|
||||
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved.
|
|
@ -0,0 +1,136 @@
|
|||
# Makefile.am -- Backtrace Makefile.
|
||||
# Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
|
||||
# (1) Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
|
||||
# (2) Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
|
||||
# (3) The name of the author may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
ACLOCAL_AMFLAGS = -I .. -I ../config
|
||||
|
||||
AM_CPPFLAGS = -I $(top_srcdir)/../include -I $(top_srcdir)/../libgcc \
|
||||
-I ../libgcc
|
||||
|
||||
AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG)
|
||||
|
||||
noinst_LTLIBRARIES = libbacktrace.la
|
||||
|
||||
libbacktrace_la_SOURCES = \
|
||||
backtrace.h \
|
||||
atomic.c \
|
||||
dwarf.c \
|
||||
fileline.c \
|
||||
internal.h \
|
||||
posix.c \
|
||||
print.c \
|
||||
sort.c \
|
||||
state.c
|
||||
|
||||
BACKTRACE_FILES = \
|
||||
backtrace.c \
|
||||
simple.c \
|
||||
nounwind.c
|
||||
|
||||
FORMAT_FILES = \
|
||||
elf.c \
|
||||
pecoff.c \
|
||||
unknown.c
|
||||
|
||||
VIEW_FILES = \
|
||||
read.c \
|
||||
mmapio.c
|
||||
|
||||
ALLOC_FILES = \
|
||||
alloc.c \
|
||||
mmap.c
|
||||
|
||||
EXTRA_libbacktrace_la_SOURCES = \
|
||||
$(BACKTRACE_FILES) \
|
||||
$(FORMAT_FILES) \
|
||||
$(VIEW_FILES) \
|
||||
$(ALLOC_FILES)
|
||||
|
||||
libbacktrace_la_LIBADD = \
|
||||
$(BACKTRACE_FILE) \
|
||||
$(FORMAT_FILE) \
|
||||
$(VIEW_FILE) \
|
||||
$(ALLOC_FILE)
|
||||
|
||||
libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
|
||||
|
||||
# Testsuite.
|
||||
|
||||
check_PROGRAMS =
|
||||
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
if NATIVE
|
||||
|
||||
btest_SOURCES = btest.c
|
||||
btest_CFLAGS = $(AM_CFLAGS) -g -O
|
||||
btest_LDADD = libbacktrace.la
|
||||
|
||||
check_PROGRAMS += btest
|
||||
|
||||
stest_SOURCES = stest.c
|
||||
stest_LDADD = libbacktrace.la
|
||||
|
||||
check_PROGRAMS += stest
|
||||
|
||||
endif NATIVE
|
||||
|
||||
# We can't use automake's automatic dependency tracking, because it
|
||||
# breaks when using bootstrap-lean. Automatic dependency tracking
|
||||
# with GCC bootstrap will cause some of the objects to depend on
|
||||
# header files in prev-gcc/include, e.g., stddef.h and stdarg.h. When
|
||||
# using bootstrap-lean, prev-gcc is removed after each stage. When
|
||||
# running "make install", those header files will be gone, causing the
|
||||
# library to be rebuilt at install time. That may not succeed.
|
||||
|
||||
# These manual dependencies do not include dependencies on unwind.h,
|
||||
# even though that is part of GCC, because where to find it depends on
|
||||
# whether we are being built as a host library or a target library.
|
||||
|
||||
INCDIR = $(top_srcdir)/../include
|
||||
alloc.lo: config.h backtrace.h internal.h
|
||||
backtrace.lo: config.h backtrace.h internal.h
|
||||
btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h
|
||||
dwarf.lo: config.h $(INCDIR)/dwarf2.h $(INCDIR)/dwarf2.def \
|
||||
$(INCDIR)/filenames.h backtrace.h internal.h
|
||||
elf.lo: config.h backtrace.h internal.h
|
||||
fileline.lo: config.h backtrace.h internal.h
|
||||
mmap.lo: config.h backtrace.h internal.h
|
||||
mmapio.lo: config.h backtrace.h internal.h
|
||||
nounwind.lo: config.h internal.h
|
||||
pecoff.lo: config.h backtrace.h internal.h
|
||||
posix.lo: config.h backtrace.h internal.h
|
||||
print.lo: config.h backtrace.h internal.h
|
||||
read.lo: config.h backtrace.h internal.h
|
||||
simple.lo: config.h backtrace.h internal.h
|
||||
sort.lo: config.h backtrace.h internal.h
|
||||
stest.lo: config.h backtrace.h internal.h
|
||||
state.lo: config.h backtrace.h backtrace-supported.h internal.h
|
||||
unknown.lo: config.h backtrace.h internal.h
|
|
@ -0,0 +1,770 @@
|
|||
# Makefile.in generated by automake 1.11.6 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Makefile.am -- Backtrace Makefile.
|
||||
# Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
|
||||
# (1) Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
|
||||
# (2) Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
|
||||
# (3) The name of the author may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__make_dryrun = \
|
||||
{ \
|
||||
am__dry=no; \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
|
||||
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
|
||||
*) \
|
||||
for am__flg in $$MAKEFLAGS; do \
|
||||
case $$am__flg in \
|
||||
*=*|--*) ;; \
|
||||
*n*) am__dry=yes; break;; \
|
||||
esac; \
|
||||
done;; \
|
||||
esac; \
|
||||
test $$am__dry = yes; \
|
||||
}
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
check_PROGRAMS = $(am__EXEEXT_1)
|
||||
@NATIVE_TRUE@am__append_1 = btest stest
|
||||
subdir = .
|
||||
DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \
|
||||
$(srcdir)/Makefile.am $(top_srcdir)/configure \
|
||||
$(am__configure_deps) $(srcdir)/config.h.in \
|
||||
$(srcdir)/../mkinstalldirs $(srcdir)/backtrace-supported.h.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/../config/lead-dot.m4 \
|
||||
$(top_srcdir)/../config/multi.m4 \
|
||||
$(top_srcdir)/../config/override.m4 \
|
||||
$(top_srcdir)/../config/stdint.m4 \
|
||||
$(top_srcdir)/../config/unwind_ipinfo.m4 \
|
||||
$(top_srcdir)/../config/warnings.m4 \
|
||||
$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
|
||||
$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
|
||||
$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno config.status.lineno
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES = backtrace-supported.h
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
LTLIBRARIES = $(noinst_LTLIBRARIES)
|
||||
am__DEPENDENCIES_1 =
|
||||
am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \
|
||||
print.lo sort.lo state.lo
|
||||
libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS)
|
||||
@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT)
|
||||
@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT)
|
||||
btest_OBJECTS = $(am_btest_OBJECTS)
|
||||
@NATIVE_TRUE@btest_DEPENDENCIES = libbacktrace.la
|
||||
btest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
@NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
|
||||
stest_OBJECTS = $(am_stest_OBJECTS)
|
||||
@NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@
|
||||
depcomp =
|
||||
am__depfiles_maybe =
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
|
||||
$(btest_SOURCES) $(stest_SOURCES)
|
||||
MULTISRCTOP =
|
||||
MULTIBUILDTOP =
|
||||
MULTIDIRS =
|
||||
MULTISUBDIR =
|
||||
MULTIDO = true
|
||||
MULTICLEAN = true
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
am__tty_colors = \
|
||||
red=; grn=; lgn=; blu=; std=
|
||||
ACLOCAL = @ACLOCAL@
|
||||
ALLOC_FILE = @ALLOC_FILE@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
BACKTRACE_FILE = @BACKTRACE_FILE@
|
||||
BACKTRACE_SUPPORTED = @BACKTRACE_SUPPORTED@
|
||||
BACKTRACE_SUPPORTS_DATA = @BACKTRACE_SUPPORTS_DATA@
|
||||
BACKTRACE_SUPPORTS_THREADS = @BACKTRACE_SUPPORTS_THREADS@
|
||||
BACKTRACE_USES_MALLOC = @BACKTRACE_USES_MALLOC@
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
EXTRA_FLAGS = @EXTRA_FLAGS@
|
||||
FGREP = @FGREP@
|
||||
FORMAT_FILE = @FORMAT_FILE@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAINT = @MAINT@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PIC_FLAG = @PIC_FLAG@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
VIEW_FILE = @VIEW_FILE@
|
||||
WARN_FLAGS = @WARN_FLAGS@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
libtool_VERSION = @libtool_VERSION@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
multi_basedir = @multi_basedir@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
ACLOCAL_AMFLAGS = -I .. -I ../config
|
||||
AM_CPPFLAGS = -I $(top_srcdir)/../include -I $(top_srcdir)/../libgcc \
|
||||
-I ../libgcc
|
||||
|
||||
AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG)
|
||||
noinst_LTLIBRARIES = libbacktrace.la
|
||||
libbacktrace_la_SOURCES = \
|
||||
backtrace.h \
|
||||
atomic.c \
|
||||
dwarf.c \
|
||||
fileline.c \
|
||||
internal.h \
|
||||
posix.c \
|
||||
print.c \
|
||||
sort.c \
|
||||
state.c
|
||||
|
||||
BACKTRACE_FILES = \
|
||||
backtrace.c \
|
||||
simple.c \
|
||||
nounwind.c
|
||||
|
||||
FORMAT_FILES = \
|
||||
elf.c \
|
||||
pecoff.c \
|
||||
unknown.c
|
||||
|
||||
VIEW_FILES = \
|
||||
read.c \
|
||||
mmapio.c
|
||||
|
||||
ALLOC_FILES = \
|
||||
alloc.c \
|
||||
mmap.c
|
||||
|
||||
EXTRA_libbacktrace_la_SOURCES = \
|
||||
$(BACKTRACE_FILES) \
|
||||
$(FORMAT_FILES) \
|
||||
$(VIEW_FILES) \
|
||||
$(ALLOC_FILES)
|
||||
|
||||
libbacktrace_la_LIBADD = \
|
||||
$(BACKTRACE_FILE) \
|
||||
$(FORMAT_FILE) \
|
||||
$(VIEW_FILE) \
|
||||
$(ALLOC_FILE)
|
||||
|
||||
libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
|
||||
TESTS = $(check_PROGRAMS)
|
||||
@NATIVE_TRUE@btest_SOURCES = btest.c
|
||||
@NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O
|
||||
@NATIVE_TRUE@btest_LDADD = libbacktrace.la
|
||||
@NATIVE_TRUE@stest_SOURCES = stest.c
|
||||
@NATIVE_TRUE@stest_LDADD = libbacktrace.la
|
||||
|
||||
# We can't use automake's automatic dependency tracking, because it
|
||||
# breaks when using bootstrap-lean. Automatic dependency tracking
|
||||
# with GCC bootstrap will cause some of the objects to depend on
|
||||
# header files in prev-gcc/include, e.g., stddef.h and stdarg.h. When
|
||||
# using bootstrap-lean, prev-gcc is removed after each stage. When
|
||||
# running "make install", those header files will be gone, causing the
|
||||
# library to be rebuilt at install time. That may not succeed.
|
||||
|
||||
# These manual dependencies do not include dependencies on unwind.h,
|
||||
# even though that is part of GCC, because where to find it depends on
|
||||
# whether we are being built as a host library or a target library.
|
||||
INCDIR = $(top_srcdir)/../include
|
||||
all: config.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
am--refresh: Makefile
|
||||
@:
|
||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps'; \
|
||||
$(am__cd) $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign --ignore-deps Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
$(am__cd) $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
||||
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
config.h: stamp-h1
|
||||
@if test ! -f $@; then rm -f stamp-h1; else :; fi
|
||||
@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi
|
||||
|
||||
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
|
||||
@rm -f stamp-h1
|
||||
cd $(top_builddir) && $(SHELL) ./config.status config.h
|
||||
$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
|
||||
rm -f stamp-h1
|
||||
touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f config.h stamp-h1
|
||||
backtrace-supported.h: $(top_builddir)/config.status $(srcdir)/backtrace-supported.h.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@
|
||||
|
||||
clean-noinstLTLIBRARIES:
|
||||
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
|
||||
@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES)
|
||||
$(LINK) $(libbacktrace_la_OBJECTS) $(libbacktrace_la_LIBADD) $(LIBS)
|
||||
|
||||
clean-checkPROGRAMS:
|
||||
@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list || exit $$?; \
|
||||
test -n "$(EXEEXT)" || exit 0; \
|
||||
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list
|
||||
btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES)
|
||||
@rm -f btest$(EXEEXT)
|
||||
$(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
|
||||
stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES)
|
||||
@rm -f stest$(EXEEXT)
|
||||
$(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) -c $<
|
||||
|
||||
.c.obj:
|
||||
$(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
btest-btest.o: btest.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
|
||||
|
||||
btest-btest.obj: btest.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
distclean-libtool:
|
||||
-rm -f libtool config.lt
|
||||
|
||||
# GNU Make needs to see an explicit $(MAKE) variable in the command it
|
||||
# runs to enable its job server during parallel builds. Hence the
|
||||
# comments below.
|
||||
all-multi:
|
||||
$(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do # $(MAKE)
|
||||
install-multi:
|
||||
$(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do # $(MAKE)
|
||||
|
||||
mostlyclean-multi:
|
||||
$(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean # $(MAKE)
|
||||
clean-multi:
|
||||
$(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean # $(MAKE)
|
||||
distclean-multi:
|
||||
$(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean # $(MAKE)
|
||||
maintainer-clean-multi:
|
||||
$(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean # $(MAKE)
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
check-TESTS: $(TESTS)
|
||||
@failed=0; all=0; xfail=0; xpass=0; skip=0; \
|
||||
srcdir=$(srcdir); export srcdir; \
|
||||
list=' $(TESTS) '; \
|
||||
$(am__tty_colors); \
|
||||
if test -n "$$list"; then \
|
||||
for tst in $$list; do \
|
||||
if test -f ./$$tst; then dir=./; \
|
||||
elif test -f $$tst; then dir=; \
|
||||
else dir="$(srcdir)/"; fi; \
|
||||
if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
|
||||
all=`expr $$all + 1`; \
|
||||
case " $(XFAIL_TESTS) " in \
|
||||
*[\ \ ]$$tst[\ \ ]*) \
|
||||
xpass=`expr $$xpass + 1`; \
|
||||
failed=`expr $$failed + 1`; \
|
||||
col=$$red; res=XPASS; \
|
||||
;; \
|
||||
*) \
|
||||
col=$$grn; res=PASS; \
|
||||
;; \
|
||||
esac; \
|
||||
elif test $$? -ne 77; then \
|
||||
all=`expr $$all + 1`; \
|
||||
case " $(XFAIL_TESTS) " in \
|
||||
*[\ \ ]$$tst[\ \ ]*) \
|
||||
xfail=`expr $$xfail + 1`; \
|
||||
col=$$lgn; res=XFAIL; \
|
||||
;; \
|
||||
*) \
|
||||
failed=`expr $$failed + 1`; \
|
||||
col=$$red; res=FAIL; \
|
||||
;; \
|
||||
esac; \
|
||||
else \
|
||||
skip=`expr $$skip + 1`; \
|
||||
col=$$blu; res=SKIP; \
|
||||
fi; \
|
||||
echo "$${col}$$res$${std}: $$tst"; \
|
||||
done; \
|
||||
if test "$$all" -eq 1; then \
|
||||
tests="test"; \
|
||||
All=""; \
|
||||
else \
|
||||
tests="tests"; \
|
||||
All="All "; \
|
||||
fi; \
|
||||
if test "$$failed" -eq 0; then \
|
||||
if test "$$xfail" -eq 0; then \
|
||||
banner="$$All$$all $$tests passed"; \
|
||||
else \
|
||||
if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
|
||||
banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
|
||||
fi; \
|
||||
else \
|
||||
if test "$$xpass" -eq 0; then \
|
||||
banner="$$failed of $$all $$tests failed"; \
|
||||
else \
|
||||
if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
|
||||
banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
|
||||
fi; \
|
||||
fi; \
|
||||
dashes="$$banner"; \
|
||||
skipped=""; \
|
||||
if test "$$skip" -ne 0; then \
|
||||
if test "$$skip" -eq 1; then \
|
||||
skipped="($$skip test was not run)"; \
|
||||
else \
|
||||
skipped="($$skip tests were not run)"; \
|
||||
fi; \
|
||||
test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
|
||||
dashes="$$skipped"; \
|
||||
fi; \
|
||||
report=""; \
|
||||
if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
|
||||
report="Please report to $(PACKAGE_BUGREPORT)"; \
|
||||
test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
|
||||
dashes="$$report"; \
|
||||
fi; \
|
||||
dashes=`echo "$$dashes" | sed s/./=/g`; \
|
||||
if test "$$failed" -eq 0; then \
|
||||
col="$$grn"; \
|
||||
else \
|
||||
col="$$red"; \
|
||||
fi; \
|
||||
echo "$${col}$$dashes$${std}"; \
|
||||
echo "$${col}$$banner$${std}"; \
|
||||
test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
|
||||
test -z "$$report" || echo "$${col}$$report$${std}"; \
|
||||
echo "$${col}$$dashes$${std}"; \
|
||||
test "$$failed" -eq 0; \
|
||||
else :; fi
|
||||
check-am: all-am
|
||||
$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
|
||||
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES) all-multi config.h
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am clean-multi
|
||||
|
||||
clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
|
||||
clean-noinstLTLIBRARIES mostlyclean-am
|
||||
|
||||
distclean: distclean-am distclean-multi
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-hdr distclean-libtool distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am: install-multi
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am maintainer-clean-multi
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf $(top_srcdir)/autom4te.cache
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am mostlyclean-multi
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: all all-multi check-am clean-multi distclean-multi install-am \
|
||||
install-multi install-strip maintainer-clean-multi \
|
||||
mostlyclean-multi
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am all-multi am--refresh check check-TESTS \
|
||||
check-am clean clean-checkPROGRAMS clean-generic clean-libtool \
|
||||
clean-multi clean-noinstLTLIBRARIES ctags distclean \
|
||||
distclean-compile distclean-generic distclean-hdr \
|
||||
distclean-libtool distclean-multi distclean-tags dvi dvi-am \
|
||||
html html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-man install-multi install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic maintainer-clean-multi mostlyclean \
|
||||
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
|
||||
mostlyclean-multi pdf pdf-am ps ps-am tags uninstall \
|
||||
uninstall-am
|
||||
|
||||
alloc.lo: config.h backtrace.h internal.h
|
||||
backtrace.lo: config.h backtrace.h internal.h
|
||||
btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h
|
||||
dwarf.lo: config.h $(INCDIR)/dwarf2.h $(INCDIR)/dwarf2.def \
|
||||
$(INCDIR)/filenames.h backtrace.h internal.h
|
||||
elf.lo: config.h backtrace.h internal.h
|
||||
fileline.lo: config.h backtrace.h internal.h
|
||||
mmap.lo: config.h backtrace.h internal.h
|
||||
mmapio.lo: config.h backtrace.h internal.h
|
||||
nounwind.lo: config.h internal.h
|
||||
pecoff.lo: config.h backtrace.h internal.h
|
||||
posix.lo: config.h backtrace.h internal.h
|
||||
print.lo: config.h backtrace.h internal.h
|
||||
read.lo: config.h backtrace.h internal.h
|
||||
simple.lo: config.h backtrace.h internal.h
|
||||
sort.lo: config.h backtrace.h internal.h
|
||||
stest.lo: config.h backtrace.h internal.h
|
||||
state.lo: config.h backtrace.h backtrace-supported.h internal.h
|
||||
unknown.lo: config.h backtrace.h internal.h
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
|
@ -0,0 +1,23 @@
|
|||
The libbacktrace library
|
||||
Initially written by Ian Lance Taylor <iant@google.com>
|
||||
|
||||
The libbacktrace library may be linked into a program or library and
|
||||
used to produce symbolic backtraces. Sample uses would be to print a
|
||||
detailed backtrace when an error occurs or to gather detailed
|
||||
profiling information.
|
||||
|
||||
The libbacktrace library is provided under a BSD license. See the
|
||||
source files for the exact license text.
|
||||
|
||||
The public functions are declared and documented in the header file
|
||||
backtrace.h, which should be #include'd by a user of the library.
|
||||
|
||||
Building libbacktrace will generate a file backtrace-supported.h,
|
||||
which a user of the library may use to determine whether backtraces
|
||||
will work. See the source file backtrace-supported.h.in for the
|
||||
macros that it defines.
|
||||
|
||||
As of September 2012, libbacktrace only supports ELF executables with
|
||||
DWARF debugging information. The library is written to make it
|
||||
straightforward to add support for other object file and debugging
|
||||
formats.
|
|
@ -0,0 +1,683 @@
|
|||
# generated automatically by aclocal 1.11.6 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
|
||||
# Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
m4_ifndef([AC_AUTOCONF_VERSION],
|
||||
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.64],,
|
||||
[m4_warning([this file was generated for autoconf 2.64.
|
||||
You have another version of autoconf. It may work, but is not guaranteed to.
|
||||
If you have problems, you may need to regenerate the build system entirely.
|
||||
To do so, use the procedure documented by the package, typically `autoreconf'.])])
|
||||
|
||||
# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 1
|
||||
|
||||
# AM_AUTOMAKE_VERSION(VERSION)
|
||||
# ----------------------------
|
||||
# Automake X.Y traces this macro to ensure aclocal.m4 has been
|
||||
# generated from the m4 files accompanying Automake X.Y.
|
||||
# (This private macro should not be called outside this file.)
|
||||
AC_DEFUN([AM_AUTOMAKE_VERSION],
|
||||
[am__api_version='1.11'
|
||||
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
|
||||
dnl require some minimum version. Point them to the right macro.
|
||||
m4_if([$1], [1.11.6], [],
|
||||
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
|
||||
])
|
||||
|
||||
# _AM_AUTOCONF_VERSION(VERSION)
|
||||
# -----------------------------
|
||||
# aclocal traces this macro to find the Autoconf version.
|
||||
# This is a private macro too. Using m4_define simplifies
|
||||
# the logic in aclocal, which can simply ignore this definition.
|
||||
m4_define([_AM_AUTOCONF_VERSION], [])
|
||||
|
||||
# AM_SET_CURRENT_AUTOMAKE_VERSION
|
||||
# -------------------------------
|
||||
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
|
||||
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
|
||||
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||
[AM_AUTOMAKE_VERSION([1.11.6])dnl
|
||||
m4_ifndef([AC_AUTOCONF_VERSION],
|
||||
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
|
||||
|
||||
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 1
|
||||
|
||||
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
|
||||
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
|
||||
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
|
||||
#
|
||||
# Of course, Automake must honor this variable whenever it calls a
|
||||
# tool from the auxiliary directory. The problem is that $srcdir (and
|
||||
# therefore $ac_aux_dir as well) can be either absolute or relative,
|
||||
# depending on how configure is run. This is pretty annoying, since
|
||||
# it makes $ac_aux_dir quite unusable in subdirectories: in the top
|
||||
# source directory, any form will work fine, but in subdirectories a
|
||||
# relative path needs to be adjusted first.
|
||||
#
|
||||
# $ac_aux_dir/missing
|
||||
# fails when called from a subdirectory if $ac_aux_dir is relative
|
||||
# $top_srcdir/$ac_aux_dir/missing
|
||||
# fails if $ac_aux_dir is absolute,
|
||||
# fails when called from a subdirectory in a VPATH build with
|
||||
# a relative $ac_aux_dir
|
||||
#
|
||||
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
|
||||
# are both prefixed by $srcdir. In an in-source build this is usually
|
||||
# harmless because $srcdir is `.', but things will broke when you
|
||||
# start a VPATH build or use an absolute $srcdir.
|
||||
#
|
||||
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
|
||||
# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
|
||||
# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
|
||||
# and then we would define $MISSING as
|
||||
# MISSING="\${SHELL} $am_aux_dir/missing"
|
||||
# This will work as long as MISSING is not called from configure, because
|
||||
# unfortunately $(top_srcdir) has no meaning in configure.
|
||||
# However there are other variables, like CC, which are often used in
|
||||
# configure, and could therefore not use this "fixed" $ac_aux_dir.
|
||||
#
|
||||
# Another solution, used here, is to always expand $ac_aux_dir to an
|
||||
# absolute PATH. The drawback is that using absolute paths prevent a
|
||||
# configured tree to be moved without reconfiguration.
|
||||
|
||||
AC_DEFUN([AM_AUX_DIR_EXPAND],
|
||||
[dnl Rely on autoconf to set up CDPATH properly.
|
||||
AC_PREREQ([2.50])dnl
|
||||
# expand $ac_aux_dir to an absolute path
|
||||
am_aux_dir=`cd $ac_aux_dir && pwd`
|
||||
])
|
||||
|
||||
# AM_CONDITIONAL -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 9
|
||||
|
||||
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
|
||||
# -------------------------------------
|
||||
# Define a conditional.
|
||||
AC_DEFUN([AM_CONDITIONAL],
|
||||
[AC_PREREQ(2.52)dnl
|
||||
ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
|
||||
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
|
||||
AC_SUBST([$1_TRUE])dnl
|
||||
AC_SUBST([$1_FALSE])dnl
|
||||
_AM_SUBST_NOTMAKE([$1_TRUE])dnl
|
||||
_AM_SUBST_NOTMAKE([$1_FALSE])dnl
|
||||
m4_define([_AM_COND_VALUE_$1], [$2])dnl
|
||||
if $2; then
|
||||
$1_TRUE=
|
||||
$1_FALSE='#'
|
||||
else
|
||||
$1_TRUE='#'
|
||||
$1_FALSE=
|
||||
fi
|
||||
AC_CONFIG_COMMANDS_PRE(
|
||||
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
|
||||
AC_MSG_ERROR([[conditional "$1" was never defined.
|
||||
Usually this means the macro was only invoked conditionally.]])
|
||||
fi])])
|
||||
|
||||
# Do all the work for Automake. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 16
|
||||
|
||||
# This macro actually does too much. Some checks are only needed if
|
||||
# your package does certain things. But this isn't really a big deal.
|
||||
|
||||
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
|
||||
# AM_INIT_AUTOMAKE([OPTIONS])
|
||||
# -----------------------------------------------
|
||||
# The call with PACKAGE and VERSION arguments is the old style
|
||||
# call (pre autoconf-2.50), which is being phased out. PACKAGE
|
||||
# and VERSION should now be passed to AC_INIT and removed from
|
||||
# the call to AM_INIT_AUTOMAKE.
|
||||
# We support both call styles for the transition. After
|
||||
# the next Automake release, Autoconf can make the AC_INIT
|
||||
# arguments mandatory, and then we can depend on a new Autoconf
|
||||
# release and drop the old call support.
|
||||
AC_DEFUN([AM_INIT_AUTOMAKE],
|
||||
[AC_PREREQ([2.62])dnl
|
||||
dnl Autoconf wants to disallow AM_ names. We explicitly allow
|
||||
dnl the ones we care about.
|
||||
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
|
||||
AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
|
||||
AC_REQUIRE([AC_PROG_INSTALL])dnl
|
||||
if test "`cd $srcdir && pwd`" != "`pwd`"; then
|
||||
# Use -I$(srcdir) only when $(srcdir) != ., so that make's output
|
||||
# is not polluted with repeated "-I."
|
||||
AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
|
||||
# test to see if srcdir already configured
|
||||
if test -f $srcdir/config.status; then
|
||||
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
|
||||
fi
|
||||
fi
|
||||
|
||||
# test whether we have cygpath
|
||||
if test -z "$CYGPATH_W"; then
|
||||
if (cygpath --version) >/dev/null 2>/dev/null; then
|
||||
CYGPATH_W='cygpath -w'
|
||||
else
|
||||
CYGPATH_W=echo
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([CYGPATH_W])
|
||||
|
||||
# Define the identity of the package.
|
||||
dnl Distinguish between old-style and new-style calls.
|
||||
m4_ifval([$2],
|
||||
[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
|
||||
AC_SUBST([PACKAGE], [$1])dnl
|
||||
AC_SUBST([VERSION], [$2])],
|
||||
[_AM_SET_OPTIONS([$1])dnl
|
||||
dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
|
||||
m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
|
||||
[m4_fatal([AC_INIT should be called with package and version arguments])])dnl
|
||||
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
|
||||
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
|
||||
|
||||
_AM_IF_OPTION([no-define],,
|
||||
[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
|
||||
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
|
||||
|
||||
# Some tools Automake needs.
|
||||
AC_REQUIRE([AM_SANITY_CHECK])dnl
|
||||
AC_REQUIRE([AC_ARG_PROGRAM])dnl
|
||||
AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
|
||||
AM_MISSING_PROG(AUTOCONF, autoconf)
|
||||
AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
|
||||
AM_MISSING_PROG(AUTOHEADER, autoheader)
|
||||
AM_MISSING_PROG(MAKEINFO, makeinfo)
|
||||
AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
|
||||
AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
|
||||
AC_REQUIRE([AM_PROG_MKDIR_P])dnl
|
||||
# We need awk for the "check" target. The system "awk" is bad on
|
||||
# some platforms.
|
||||
AC_REQUIRE([AC_PROG_AWK])dnl
|
||||
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
|
||||
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
|
||||
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
|
||||
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
|
||||
[_AM_PROG_TAR([v7])])])
|
||||
_AM_IF_OPTION([no-dependencies],,
|
||||
[AC_PROVIDE_IFELSE([AC_PROG_CC],
|
||||
[_AM_DEPENDENCIES(CC)],
|
||||
[define([AC_PROG_CC],
|
||||
defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
|
||||
AC_PROVIDE_IFELSE([AC_PROG_CXX],
|
||||
[_AM_DEPENDENCIES(CXX)],
|
||||
[define([AC_PROG_CXX],
|
||||
defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
|
||||
AC_PROVIDE_IFELSE([AC_PROG_OBJC],
|
||||
[_AM_DEPENDENCIES(OBJC)],
|
||||
[define([AC_PROG_OBJC],
|
||||
defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
|
||||
])
|
||||
_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
|
||||
dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
|
||||
dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro
|
||||
dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
|
||||
AC_CONFIG_COMMANDS_PRE(dnl
|
||||
[m4_provide_if([_AM_COMPILER_EXEEXT],
|
||||
[AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
|
||||
])
|
||||
|
||||
dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
|
||||
dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
|
||||
dnl mangled by Autoconf and run in a shell conditional statement.
|
||||
m4_define([_AC_COMPILER_EXEEXT],
|
||||
m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
|
||||
|
||||
|
||||
# When config.status generates a header, we must update the stamp-h file.
|
||||
# This file resides in the same directory as the config header
|
||||
# that is generated. The stamp files are numbered to have different names.
|
||||
|
||||
# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
|
||||
# loop where config.status creates the headers, so we can generate
|
||||
# our stamp files there.
|
||||
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
|
||||
[# Compute $1's index in $config_headers.
|
||||
_am_arg=$1
|
||||
_am_stamp_count=1
|
||||
for _am_header in $config_headers :; do
|
||||
case $_am_header in
|
||||
$_am_arg | $_am_arg:* )
|
||||
break ;;
|
||||
* )
|
||||
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
|
||||
esac
|
||||
done
|
||||
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation,
|
||||
# Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 1
|
||||
|
||||
# AM_PROG_INSTALL_SH
|
||||
# ------------------
|
||||
# Define $install_sh.
|
||||
AC_DEFUN([AM_PROG_INSTALL_SH],
|
||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
if test x"${install_sh}" != xset; then
|
||||
case $am_aux_dir in
|
||||
*\ * | *\ *)
|
||||
install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
|
||||
*)
|
||||
install_sh="\${SHELL} $am_aux_dir/install-sh"
|
||||
esac
|
||||
fi
|
||||
AC_SUBST(install_sh)])
|
||||
|
||||
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
|
||||
# From Jim Meyering
|
||||
|
||||
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
|
||||
# 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 5
|
||||
|
||||
# AM_MAINTAINER_MODE([DEFAULT-MODE])
|
||||
# ----------------------------------
|
||||
# Control maintainer-specific portions of Makefiles.
|
||||
# Default is to disable them, unless `enable' is passed literally.
|
||||
# For symmetry, `disable' may be passed as well. Anyway, the user
|
||||
# can override the default with the --enable/--disable switch.
|
||||
AC_DEFUN([AM_MAINTAINER_MODE],
|
||||
[m4_case(m4_default([$1], [disable]),
|
||||
[enable], [m4_define([am_maintainer_other], [disable])],
|
||||
[disable], [m4_define([am_maintainer_other], [enable])],
|
||||
[m4_define([am_maintainer_other], [enable])
|
||||
m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
|
||||
AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
|
||||
dnl maintainer-mode's default is 'disable' unless 'enable' is passed
|
||||
AC_ARG_ENABLE([maintainer-mode],
|
||||
[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
|
||||
(and sometimes confusing) to the casual installer],
|
||||
[USE_MAINTAINER_MODE=$enableval],
|
||||
[USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
|
||||
AC_MSG_RESULT([$USE_MAINTAINER_MODE])
|
||||
AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
|
||||
MAINT=$MAINTAINER_MODE_TRUE
|
||||
AC_SUBST([MAINT])dnl
|
||||
]
|
||||
)
|
||||
|
||||
AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
|
||||
|
||||
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 6
|
||||
|
||||
# AM_MISSING_PROG(NAME, PROGRAM)
|
||||
# ------------------------------
|
||||
AC_DEFUN([AM_MISSING_PROG],
|
||||
[AC_REQUIRE([AM_MISSING_HAS_RUN])
|
||||
$1=${$1-"${am_missing_run}$2"}
|
||||
AC_SUBST($1)])
|
||||
|
||||
|
||||
# AM_MISSING_HAS_RUN
|
||||
# ------------------
|
||||
# Define MISSING if not defined so far and test if it supports --run.
|
||||
# If it does, set am_missing_run to use it, otherwise, to nothing.
|
||||
AC_DEFUN([AM_MISSING_HAS_RUN],
|
||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
AC_REQUIRE_AUX_FILE([missing])dnl
|
||||
if test x"${MISSING+set}" != xset; then
|
||||
case $am_aux_dir in
|
||||
*\ * | *\ *)
|
||||
MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
|
||||
*)
|
||||
MISSING="\${SHELL} $am_aux_dir/missing" ;;
|
||||
esac
|
||||
fi
|
||||
# Use eval to expand $SHELL
|
||||
if eval "$MISSING --run true"; then
|
||||
am_missing_run="$MISSING --run "
|
||||
else
|
||||
am_missing_run=
|
||||
AC_MSG_WARN([`missing' script is too old or missing])
|
||||
fi
|
||||
])
|
||||
|
||||
# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation,
|
||||
# Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 1
|
||||
|
||||
# AM_PROG_MKDIR_P
|
||||
# ---------------
|
||||
# Check for `mkdir -p'.
|
||||
AC_DEFUN([AM_PROG_MKDIR_P],
|
||||
[AC_PREREQ([2.60])dnl
|
||||
AC_REQUIRE([AC_PROG_MKDIR_P])dnl
|
||||
dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
|
||||
dnl while keeping a definition of mkdir_p for backward compatibility.
|
||||
dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
|
||||
dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
|
||||
dnl Makefile.ins that do not define MKDIR_P, so we do our own
|
||||
dnl adjustment using top_builddir (which is defined more often than
|
||||
dnl MKDIR_P).
|
||||
AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
|
||||
case $mkdir_p in
|
||||
[[\\/$]]* | ?:[[\\/]]*) ;;
|
||||
*/*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
|
||||
esac
|
||||
])
|
||||
|
||||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software
|
||||
# Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 5
|
||||
|
||||
# _AM_MANGLE_OPTION(NAME)
|
||||
# -----------------------
|
||||
AC_DEFUN([_AM_MANGLE_OPTION],
|
||||
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
# _AM_SET_OPTION(NAME)
|
||||
# --------------------
|
||||
# Set option NAME. Presently that only means defining a flag for this option.
|
||||
AC_DEFUN([_AM_SET_OPTION],
|
||||
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
|
||||
|
||||
# _AM_SET_OPTIONS(OPTIONS)
|
||||
# ------------------------
|
||||
# OPTIONS is a space-separated list of Automake options.
|
||||
AC_DEFUN([_AM_SET_OPTIONS],
|
||||
[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
|
||||
|
||||
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
|
||||
# -------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
AC_DEFUN([_AM_IF_OPTION],
|
||||
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
|
||||
|
||||
# Check to make sure that the build environment is sane. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 5
|
||||
|
||||
# AM_SANITY_CHECK
|
||||
# ---------------
|
||||
AC_DEFUN([AM_SANITY_CHECK],
|
||||
[AC_MSG_CHECKING([whether build environment is sane])
|
||||
# Just in case
|
||||
sleep 1
|
||||
echo timestamp > conftest.file
|
||||
# Reject unsafe characters in $srcdir or the absolute working directory
|
||||
# name. Accept space and tab only in the latter.
|
||||
am_lf='
|
||||
'
|
||||
case `pwd` in
|
||||
*[[\\\"\#\$\&\'\`$am_lf]]*)
|
||||
AC_MSG_ERROR([unsafe absolute working directory name]);;
|
||||
esac
|
||||
case $srcdir in
|
||||
*[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
|
||||
AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
|
||||
esac
|
||||
|
||||
# Do `set' in a subshell so we don't clobber the current shell's
|
||||
# arguments. Must try -L first in case configure is actually a
|
||||
# symlink; some systems play weird games with the mod time of symlinks
|
||||
# (eg FreeBSD returns the mod time of the symlink's containing
|
||||
# directory).
|
||||
if (
|
||||
set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
|
||||
if test "$[*]" = "X"; then
|
||||
# -L didn't work.
|
||||
set X `ls -t "$srcdir/configure" conftest.file`
|
||||
fi
|
||||
rm -f conftest.file
|
||||
if test "$[*]" != "X $srcdir/configure conftest.file" \
|
||||
&& test "$[*]" != "X conftest.file $srcdir/configure"; then
|
||||
|
||||
# If neither matched, then we have a broken ls. This can happen
|
||||
# if, for instance, CONFIG_SHELL is bash and it inherits a
|
||||
# broken ls alias from the environment. This has actually
|
||||
# happened. Such a system could not be considered "sane".
|
||||
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
|
||||
alias in your environment])
|
||||
fi
|
||||
|
||||
test "$[2]" = conftest.file
|
||||
)
|
||||
then
|
||||
# Ok.
|
||||
:
|
||||
else
|
||||
AC_MSG_ERROR([newly created file is older than distributed files!
|
||||
Check your system clock])
|
||||
fi
|
||||
AC_MSG_RESULT(yes)])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 1
|
||||
|
||||
# AM_PROG_INSTALL_STRIP
|
||||
# ---------------------
|
||||
# One issue with vendor `install' (even GNU) is that you can't
|
||||
# specify the program used to strip binaries. This is especially
|
||||
# annoying in cross-compiling environments, where the build's strip
|
||||
# is unlikely to handle the host's binaries.
|
||||
# Fortunately install-sh will honor a STRIPPROG variable, so we
|
||||
# always use install-sh in `make install-strip', and initialize
|
||||
# STRIPPROG with the value of the STRIP variable (set by the user).
|
||||
AC_DEFUN([AM_PROG_INSTALL_STRIP],
|
||||
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
|
||||
# Installed binaries are usually stripped using `strip' when the user
|
||||
# run `make install-strip'. However `strip' might not be the right
|
||||
# tool to use in cross-compilation environments, therefore Automake
|
||||
# will honor the `STRIP' environment variable to overrule this program.
|
||||
dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
|
||||
if test "$cross_compiling" != no; then
|
||||
AC_CHECK_TOOL([STRIP], [strip], :)
|
||||
fi
|
||||
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
|
||||
AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
||||
|
||||
# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 3
|
||||
|
||||
# _AM_SUBST_NOTMAKE(VARIABLE)
|
||||
# ---------------------------
|
||||
# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
|
||||
# This macro is traced by Automake.
|
||||
AC_DEFUN([_AM_SUBST_NOTMAKE])
|
||||
|
||||
# AM_SUBST_NOTMAKE(VARIABLE)
|
||||
# --------------------------
|
||||
# Public sister of _AM_SUBST_NOTMAKE.
|
||||
AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
|
||||
|
||||
# Check how to create a tarball. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 2
|
||||
|
||||
# _AM_PROG_TAR(FORMAT)
|
||||
# --------------------
|
||||
# Check how to create a tarball in format FORMAT.
|
||||
# FORMAT should be one of `v7', `ustar', or `pax'.
|
||||
#
|
||||
# Substitute a variable $(am__tar) that is a command
|
||||
# writing to stdout a FORMAT-tarball containing the directory
|
||||
# $tardir.
|
||||
# tardir=directory && $(am__tar) > result.tar
|
||||
#
|
||||
# Substitute a variable $(am__untar) that extract such
|
||||
# a tarball read from stdin.
|
||||
# $(am__untar) < result.tar
|
||||
AC_DEFUN([_AM_PROG_TAR],
|
||||
[# Always define AMTAR for backward compatibility. Yes, it's still used
|
||||
# in the wild :-( We should find a proper way to deprecate it ...
|
||||
AC_SUBST([AMTAR], ['$${TAR-tar}'])
|
||||
m4_if([$1], [v7],
|
||||
[am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
|
||||
[m4_case([$1], [ustar],, [pax],,
|
||||
[m4_fatal([Unknown tar format])])
|
||||
AC_MSG_CHECKING([how to create a $1 tar archive])
|
||||
# Loop over all known methods to create a tar archive until one works.
|
||||
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
|
||||
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
|
||||
# Do not fold the above two line into one, because Tru64 sh and
|
||||
# Solaris sh will not grok spaces in the rhs of `-'.
|
||||
for _am_tool in $_am_tools
|
||||
do
|
||||
case $_am_tool in
|
||||
gnutar)
|
||||
for _am_tar in tar gnutar gtar;
|
||||
do
|
||||
AM_RUN_LOG([$_am_tar --version]) && break
|
||||
done
|
||||
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
|
||||
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
|
||||
am__untar="$_am_tar -xf -"
|
||||
;;
|
||||
plaintar)
|
||||
# Must skip GNU tar: if it does not support --format= it doesn't create
|
||||
# ustar tarball either.
|
||||
(tar --version) >/dev/null 2>&1 && continue
|
||||
am__tar='tar chf - "$$tardir"'
|
||||
am__tar_='tar chf - "$tardir"'
|
||||
am__untar='tar xf -'
|
||||
;;
|
||||
pax)
|
||||
am__tar='pax -L -x $1 -w "$$tardir"'
|
||||
am__tar_='pax -L -x $1 -w "$tardir"'
|
||||
am__untar='pax -r'
|
||||
;;
|
||||
cpio)
|
||||
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
|
||||
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
|
||||
am__untar='cpio -i -H $1 -d'
|
||||
;;
|
||||
none)
|
||||
am__tar=false
|
||||
am__tar_=false
|
||||
am__untar=false
|
||||
;;
|
||||
esac
|
||||
|
||||
# If the value was cached, stop now. We just wanted to have am__tar
|
||||
# and am__untar set.
|
||||
test -n "${am_cv_prog_tar_$1}" && break
|
||||
|
||||
# tar/untar a dummy directory, and stop if the command works
|
||||
rm -rf conftest.dir
|
||||
mkdir conftest.dir
|
||||
echo GrepMe > conftest.dir/file
|
||||
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
|
||||
rm -rf conftest.dir
|
||||
if test -s conftest.tar; then
|
||||
AM_RUN_LOG([$am__untar <conftest.tar])
|
||||
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
|
||||
fi
|
||||
done
|
||||
rm -rf conftest.dir
|
||||
|
||||
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
|
||||
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
|
||||
AC_SUBST([am__tar])
|
||||
AC_SUBST([am__untar])
|
||||
]) # _AM_PROG_TAR
|
||||
|
||||
m4_include([../config/lead-dot.m4])
|
||||
m4_include([../config/multi.m4])
|
||||
m4_include([../config/override.m4])
|
||||
m4_include([../config/stdint.m4])
|
||||
m4_include([../config/unwind_ipinfo.m4])
|
||||
m4_include([../config/warnings.m4])
|
||||
m4_include([../libtool.m4])
|
||||
m4_include([../ltoptions.m4])
|
||||
m4_include([../ltsugar.m4])
|
||||
m4_include([../ltversion.m4])
|
||||
m4_include([../lt~obsolete.m4])
|
|
@ -0,0 +1,156 @@
|
|||
/* alloc.c -- Memory allocation without mmap.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Allocation routines to use on systems that do not support anonymous
|
||||
mmap. This implementation just uses malloc, which means that the
|
||||
backtrace functions may not be safely invoked from a signal
|
||||
handler. */
|
||||
|
||||
/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't
|
||||
report an error. */
|
||||
|
||||
void *
|
||||
backtrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
size_t size, backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
ret = malloc (size);
|
||||
if (ret == NULL)
|
||||
{
|
||||
if (error_callback)
|
||||
error_callback (data, "malloc", errno);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Free memory. */
|
||||
|
||||
void
|
||||
backtrace_free (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
void *p, size_t size ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
free (p);
|
||||
}
|
||||
|
||||
/* Grow VEC by SIZE bytes. */
|
||||
|
||||
void *
|
||||
backtrace_vector_grow (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
size_t size, backtrace_error_callback error_callback,
|
||||
void *data, struct backtrace_vector *vec)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (size > vec->alc)
|
||||
{
|
||||
size_t alc;
|
||||
void *base;
|
||||
|
||||
if (vec->size == 0)
|
||||
alc = 32 * size;
|
||||
else if (vec->size >= 4096)
|
||||
alc = vec->size + 4096;
|
||||
else
|
||||
alc = 2 * vec->size;
|
||||
|
||||
if (alc < vec->size + size)
|
||||
alc = vec->size + size;
|
||||
|
||||
base = realloc (vec->base, alc);
|
||||
if (base == NULL)
|
||||
{
|
||||
error_callback (data, "realloc", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec->base = base;
|
||||
vec->alc = alc - vec->size;
|
||||
}
|
||||
|
||||
ret = (char *) vec->base + vec->size;
|
||||
vec->size += size;
|
||||
vec->alc -= size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Finish the current allocation on VEC. */
|
||||
|
||||
void *
|
||||
backtrace_vector_finish (struct backtrace_state *state,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
/* With this allocator we call realloc in backtrace_vector_grow,
|
||||
which means we can't easily reuse the memory here. So just
|
||||
release it. */
|
||||
if (!backtrace_vector_release (state, vec, error_callback, data))
|
||||
return NULL;
|
||||
ret = vec->base;
|
||||
vec->base = NULL;
|
||||
vec->size = 0;
|
||||
vec->alc = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Release any extra space allocated for VEC. */
|
||||
|
||||
int
|
||||
backtrace_vector_release (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
vec->base = realloc (vec->base, vec->size);
|
||||
if (vec->base == NULL)
|
||||
{
|
||||
error_callback (data, "realloc", errno);
|
||||
return 0;
|
||||
}
|
||||
vec->alc = 0;
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,355 @@
|
|||
/* ANSI and traditional C compatability macros
|
||||
Copyright (C) 1991-2015 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* ANSI and traditional C compatibility macros
|
||||
|
||||
ANSI C is assumed if __STDC__ is #defined.
|
||||
|
||||
Macro ANSI C definition Traditional C definition
|
||||
----- ---- - ---------- ----------- - ----------
|
||||
PTR `void *' `char *'
|
||||
const not defined `'
|
||||
volatile not defined `'
|
||||
signed not defined `'
|
||||
|
||||
For ease of writing code which uses GCC extensions but needs to be
|
||||
portable to other compilers, we provide the GCC_VERSION macro that
|
||||
simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
|
||||
wrappers around __attribute__. Also, __extension__ will be #defined
|
||||
to nothing if it doesn't work. See below. */
|
||||
|
||||
#ifndef _ANSIDECL_H
|
||||
#define _ANSIDECL_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Every source file includes this file,
|
||||
so they will all get the switch for lint. */
|
||||
/* LINTLIBRARY */
|
||||
|
||||
/* Using MACRO(x,y) in cpp #if conditionals does not work with some
|
||||
older preprocessors. Thus we can't define something like this:
|
||||
|
||||
#define HAVE_GCC_VERSION(MAJOR, MINOR) \
|
||||
(__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
|
||||
|
||||
and then test "#if HAVE_GCC_VERSION(2,7)".
|
||||
|
||||
So instead we use the macro below and test it against specific values. */
|
||||
|
||||
/* This macro simplifies testing whether we are using gcc, and if it
|
||||
is of a particular minimum version. (Both major & minor numbers are
|
||||
significant.) This macro will evaluate to 0 if we are not using
|
||||
gcc at all. */
|
||||
#ifndef GCC_VERSION
|
||||
#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
|
||||
#endif /* GCC_VERSION */
|
||||
|
||||
#if defined (__STDC__) || defined(__cplusplus) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32)
|
||||
/* All known AIX compilers implement these things (but don't always
|
||||
define __STDC__). The RISC/OS MIPS compiler defines these things
|
||||
in SVR4 mode, but does not define __STDC__. */
|
||||
/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other
|
||||
C++ compilers, does not define __STDC__, though it acts as if this
|
||||
was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */
|
||||
|
||||
#define PTR void *
|
||||
|
||||
#undef const
|
||||
#undef volatile
|
||||
#undef signed
|
||||
|
||||
/* inline requires special treatment; it's in C99, and GCC >=2.7 supports
|
||||
it too, but it's not in C89. */
|
||||
#undef inline
|
||||
#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__))
|
||||
/* it's a keyword */
|
||||
#else
|
||||
# if GCC_VERSION >= 2007
|
||||
# define inline __inline__ /* __inline__ prevents -pedantic warnings */
|
||||
# else
|
||||
# define inline /* nothing */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#else /* Not ANSI C. */
|
||||
|
||||
#define PTR char *
|
||||
|
||||
/* some systems define these in header files for non-ansi mode */
|
||||
#undef const
|
||||
#undef volatile
|
||||
#undef signed
|
||||
#undef inline
|
||||
#define const
|
||||
#define volatile
|
||||
#define signed
|
||||
#define inline
|
||||
|
||||
#endif /* ANSI C. */
|
||||
|
||||
/* Define macros for some gcc attributes. This permits us to use the
|
||||
macros freely, and know that they will come into play for the
|
||||
version of gcc in which they are supported. */
|
||||
|
||||
#if (GCC_VERSION < 2007)
|
||||
# define __attribute__(x)
|
||||
#endif
|
||||
|
||||
/* Attribute __malloc__ on functions was valid as of gcc 2.96. */
|
||||
#ifndef ATTRIBUTE_MALLOC
|
||||
# if (GCC_VERSION >= 2096)
|
||||
# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
|
||||
# else
|
||||
# define ATTRIBUTE_MALLOC
|
||||
# endif /* GNUC >= 2.96 */
|
||||
#endif /* ATTRIBUTE_MALLOC */
|
||||
|
||||
/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5. For
|
||||
g++ an attribute on a label must be followed by a semicolon. */
|
||||
#ifndef ATTRIBUTE_UNUSED_LABEL
|
||||
# ifndef __cplusplus
|
||||
# if GCC_VERSION >= 2093
|
||||
# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
|
||||
# else
|
||||
# define ATTRIBUTE_UNUSED_LABEL
|
||||
# endif
|
||||
# else
|
||||
# if GCC_VERSION >= 4005
|
||||
# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ;
|
||||
# else
|
||||
# define ATTRIBUTE_UNUSED_LABEL
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Similarly to ARG_UNUSED below. Prior to GCC 3.4, the C++ frontend
|
||||
couldn't parse attributes placed after the identifier name, and now
|
||||
the entire compiler is built with C++. */
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
#if GCC_VERSION >= 3004
|
||||
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
|
||||
#else
|
||||
#define ATTRIBUTE_UNUSED
|
||||
#endif
|
||||
#endif /* ATTRIBUTE_UNUSED */
|
||||
|
||||
/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the
|
||||
identifier name. */
|
||||
#if ! defined(__cplusplus) || (GCC_VERSION >= 3004)
|
||||
# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED
|
||||
#else /* !__cplusplus || GNUC >= 3.4 */
|
||||
# define ARG_UNUSED(NAME) NAME
|
||||
#endif /* !__cplusplus || GNUC >= 3.4 */
|
||||
|
||||
#ifndef ATTRIBUTE_NORETURN
|
||||
#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
|
||||
#endif /* ATTRIBUTE_NORETURN */
|
||||
|
||||
/* Attribute `nonnull' was valid as of gcc 3.3. */
|
||||
#ifndef ATTRIBUTE_NONNULL
|
||||
# if (GCC_VERSION >= 3003)
|
||||
# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m)))
|
||||
# else
|
||||
# define ATTRIBUTE_NONNULL(m)
|
||||
# endif /* GNUC >= 3.3 */
|
||||
#endif /* ATTRIBUTE_NONNULL */
|
||||
|
||||
/* Attribute `returns_nonnull' was valid as of gcc 4.9. */
|
||||
#ifndef ATTRIBUTE_RETURNS_NONNULL
|
||||
# if (GCC_VERSION >= 4009)
|
||||
# define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__))
|
||||
# else
|
||||
# define ATTRIBUTE_RETURNS_NONNULL
|
||||
# endif /* GNUC >= 4.9 */
|
||||
#endif /* ATTRIBUTE_RETURNS_NONNULL */
|
||||
|
||||
/* Attribute `pure' was valid as of gcc 3.0. */
|
||||
#ifndef ATTRIBUTE_PURE
|
||||
# if (GCC_VERSION >= 3000)
|
||||
# define ATTRIBUTE_PURE __attribute__ ((__pure__))
|
||||
# else
|
||||
# define ATTRIBUTE_PURE
|
||||
# endif /* GNUC >= 3.0 */
|
||||
#endif /* ATTRIBUTE_PURE */
|
||||
|
||||
/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL.
|
||||
This was the case for the `printf' format attribute by itself
|
||||
before GCC 3.3, but as of 3.3 we need to add the `nonnull'
|
||||
attribute to retain this behavior. */
|
||||
#ifndef ATTRIBUTE_PRINTF
|
||||
#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m)
|
||||
#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
|
||||
#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
|
||||
#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
|
||||
#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
|
||||
#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
|
||||
#endif /* ATTRIBUTE_PRINTF */
|
||||
|
||||
/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on
|
||||
a function pointer. Format attributes were allowed on function
|
||||
pointers as of gcc 3.1. */
|
||||
#ifndef ATTRIBUTE_FPTR_PRINTF
|
||||
# if (GCC_VERSION >= 3001)
|
||||
# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n)
|
||||
# else
|
||||
# define ATTRIBUTE_FPTR_PRINTF(m, n)
|
||||
# endif /* GNUC >= 3.1 */
|
||||
# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2)
|
||||
# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3)
|
||||
# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4)
|
||||
# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5)
|
||||
# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6)
|
||||
#endif /* ATTRIBUTE_FPTR_PRINTF */
|
||||
|
||||
/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A
|
||||
NULL format specifier was allowed as of gcc 3.3. */
|
||||
#ifndef ATTRIBUTE_NULL_PRINTF
|
||||
# if (GCC_VERSION >= 3003)
|
||||
# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
|
||||
# else
|
||||
# define ATTRIBUTE_NULL_PRINTF(m, n)
|
||||
# endif /* GNUC >= 3.3 */
|
||||
# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2)
|
||||
# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3)
|
||||
# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4)
|
||||
# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5)
|
||||
# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
|
||||
#endif /* ATTRIBUTE_NULL_PRINTF */
|
||||
|
||||
/* Attribute `sentinel' was valid as of gcc 3.5. */
|
||||
#ifndef ATTRIBUTE_SENTINEL
|
||||
# if (GCC_VERSION >= 3005)
|
||||
# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__))
|
||||
# else
|
||||
# define ATTRIBUTE_SENTINEL
|
||||
# endif /* GNUC >= 3.5 */
|
||||
#endif /* ATTRIBUTE_SENTINEL */
|
||||
|
||||
|
||||
#ifndef ATTRIBUTE_ALIGNED_ALIGNOF
|
||||
# if (GCC_VERSION >= 3000)
|
||||
# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m))))
|
||||
# else
|
||||
# define ATTRIBUTE_ALIGNED_ALIGNOF(m)
|
||||
# endif /* GNUC >= 3.0 */
|
||||
#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */
|
||||
|
||||
/* Useful for structures whose layout must much some binary specification
|
||||
regardless of the alignment and padding qualities of the compiler. */
|
||||
#ifndef ATTRIBUTE_PACKED
|
||||
# define ATTRIBUTE_PACKED __attribute__ ((packed))
|
||||
#endif
|
||||
|
||||
/* Attribute `hot' and `cold' was valid as of gcc 4.3. */
|
||||
#ifndef ATTRIBUTE_COLD
|
||||
# if (GCC_VERSION >= 4003)
|
||||
# define ATTRIBUTE_COLD __attribute__ ((__cold__))
|
||||
# else
|
||||
# define ATTRIBUTE_COLD
|
||||
# endif /* GNUC >= 4.3 */
|
||||
#endif /* ATTRIBUTE_COLD */
|
||||
#ifndef ATTRIBUTE_HOT
|
||||
# if (GCC_VERSION >= 4003)
|
||||
# define ATTRIBUTE_HOT __attribute__ ((__hot__))
|
||||
# else
|
||||
# define ATTRIBUTE_HOT
|
||||
# endif /* GNUC >= 4.3 */
|
||||
#endif /* ATTRIBUTE_HOT */
|
||||
|
||||
/* Attribute 'no_sanitize_undefined' was valid as of gcc 4.9. */
|
||||
#ifndef ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
||||
# if (GCC_VERSION >= 4009)
|
||||
# define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize_undefined))
|
||||
# else
|
||||
# define ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
||||
# endif /* GNUC >= 4.9 */
|
||||
#endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */
|
||||
|
||||
/* We use __extension__ in some places to suppress -pedantic warnings
|
||||
about GCC extensions. This feature didn't work properly before
|
||||
gcc 2.8. */
|
||||
#if GCC_VERSION < 2008
|
||||
#define __extension__
|
||||
#endif
|
||||
|
||||
/* This is used to declare a const variable which should be visible
|
||||
outside of the current compilation unit. Use it as
|
||||
EXPORTED_CONST int i = 1;
|
||||
This is because the semantics of const are different in C and C++.
|
||||
"extern const" is permitted in C but it looks strange, and gcc
|
||||
warns about it when -Wc++-compat is not used. */
|
||||
#ifdef __cplusplus
|
||||
#define EXPORTED_CONST extern const
|
||||
#else
|
||||
#define EXPORTED_CONST const
|
||||
#endif
|
||||
|
||||
/* Be conservative and only use enum bitfields with C++ or GCC.
|
||||
FIXME: provide a complete autoconf test for buggy enum bitfields. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define ENUM_BITFIELD(TYPE) enum TYPE
|
||||
#elif (GCC_VERSION > 2000)
|
||||
#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
|
||||
#else
|
||||
#define ENUM_BITFIELD(TYPE) unsigned int
|
||||
#endif
|
||||
|
||||
/* C++11 adds the ability to add "override" after an implementation of a
|
||||
virtual function in a subclass, to:
|
||||
(A) document that this is an override of a virtual function
|
||||
(B) allow the compiler to issue a warning if it isn't (e.g. a mismatch
|
||||
of the type signature).
|
||||
|
||||
Similarly, it allows us to add a "final" to indicate that no subclass
|
||||
may subsequently override the vfunc.
|
||||
|
||||
Provide OVERRIDE and FINAL as macros, allowing us to get these benefits
|
||||
when compiling with C++11 support, but without requiring C++11.
|
||||
|
||||
For gcc, use "-std=c++11" to enable C++11 support; gcc 6 onwards enables
|
||||
this by default (actually GNU++14). */
|
||||
|
||||
#if __cplusplus >= 201103
|
||||
/* C++11 claims to be available: use it. final/override were only
|
||||
implemented in 4.7, though. */
|
||||
# if GCC_VERSION < 4007
|
||||
# define OVERRIDE
|
||||
# define FINAL
|
||||
# else
|
||||
# define OVERRIDE override
|
||||
# define FINAL final
|
||||
# endif
|
||||
#elif GCC_VERSION >= 4007
|
||||
/* G++ 4.7 supports __final in C++98. */
|
||||
# define OVERRIDE
|
||||
# define FINAL __final
|
||||
#else
|
||||
/* No C++11 support; leave the macros empty: */
|
||||
# define OVERRIDE
|
||||
# define FINAL
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ansidecl.h */
|
|
@ -0,0 +1,113 @@
|
|||
/* atomic.c -- Support for atomic functions if not present.
|
||||
Copyright (C) 2013-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "backtrace-supported.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* This file holds implementations of the atomic functions that are
|
||||
used if the host compiler has the sync functions but not the atomic
|
||||
functions, as is true of versions of GCC before 4.7. */
|
||||
|
||||
#if !defined (HAVE_ATOMIC_FUNCTIONS) && defined (HAVE_SYNC_FUNCTIONS)
|
||||
|
||||
/* Do an atomic load of a pointer. */
|
||||
|
||||
void *
|
||||
backtrace_atomic_load_pointer (void *arg)
|
||||
{
|
||||
void **pp;
|
||||
void *p;
|
||||
|
||||
pp = (void **) arg;
|
||||
p = *pp;
|
||||
while (!__sync_bool_compare_and_swap (pp, p, p))
|
||||
p = *pp;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Do an atomic load of an int. */
|
||||
|
||||
int
|
||||
backtrace_atomic_load_int (int *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = *p;
|
||||
while (!__sync_bool_compare_and_swap (p, i, i))
|
||||
i = *p;
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Do an atomic store of a pointer. */
|
||||
|
||||
void
|
||||
backtrace_atomic_store_pointer (void *arg, void *p)
|
||||
{
|
||||
void **pp;
|
||||
void *old;
|
||||
|
||||
pp = (void **) arg;
|
||||
old = *pp;
|
||||
while (!__sync_bool_compare_and_swap (pp, old, p))
|
||||
old = *pp;
|
||||
}
|
||||
|
||||
/* Do an atomic store of a size_t value. */
|
||||
|
||||
void
|
||||
backtrace_atomic_store_size_t (size_t *p, size_t v)
|
||||
{
|
||||
size_t old;
|
||||
|
||||
old = *p;
|
||||
while (!__sync_bool_compare_and_swap (p, old, v))
|
||||
old = *p;
|
||||
}
|
||||
|
||||
/* Do an atomic store of a int value. */
|
||||
|
||||
void
|
||||
backtrace_atomic_store_int (int *p, int v)
|
||||
{
|
||||
size_t old;
|
||||
|
||||
old = *p;
|
||||
while (!__sync_bool_compare_and_swap (p, old, v))
|
||||
old = *p;
|
||||
}
|
||||
|
||||
#endif
|
66
third_party/rust/backtrace-sys-0.1.10/src/libbacktrace/backtrace-supported.h.in
поставляемый
Normal file
66
third_party/rust/backtrace-sys-0.1.10/src/libbacktrace/backtrace-supported.h.in
поставляемый
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* backtrace-supported.h.in -- Whether stack backtrace is supported.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
/* The file backtrace-supported.h.in is used by configure to generate
|
||||
the file backtrace-supported.h. The file backtrace-supported.h may
|
||||
be #include'd to see whether the backtrace library will be able to
|
||||
get a backtrace and produce symbolic information. */
|
||||
|
||||
|
||||
/* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library
|
||||
should work, 0 if it will not. Libraries may #include this to make
|
||||
other arrangements. */
|
||||
|
||||
#define BACKTRACE_SUPPORTED @BACKTRACE_SUPPORTED@
|
||||
|
||||
/* BACKTRACE_USES_MALLOC will be #define'd as 1 if the backtrace
|
||||
library will call malloc as it works, 0 if it will call mmap
|
||||
instead. This may be used to determine whether it is safe to call
|
||||
the backtrace functions from a signal handler. In general this
|
||||
only applies to calls like backtrace and backtrace_pcinfo. It does
|
||||
not apply to backtrace_simple, which never calls malloc. It does
|
||||
not apply to backtrace_print, which always calls fprintf and
|
||||
therefore malloc. */
|
||||
|
||||
#define BACKTRACE_USES_MALLOC @BACKTRACE_USES_MALLOC@
|
||||
|
||||
/* BACKTRACE_SUPPORTS_THREADS will be #define'd as 1 if the backtrace
|
||||
library is configured with threading support, 0 if not. If this is
|
||||
0, the threaded parameter to backtrace_create_state must be passed
|
||||
as 0. */
|
||||
|
||||
#define BACKTRACE_SUPPORTS_THREADS @BACKTRACE_SUPPORTS_THREADS@
|
||||
|
||||
/* BACKTRACE_SUPPORTS_DATA will be #defined'd as 1 if the backtrace_syminfo
|
||||
will work for variables. It will always work for functions. */
|
||||
|
||||
#define BACKTRACE_SUPPORTS_DATA @BACKTRACE_SUPPORTS_DATA@
|
|
@ -0,0 +1,129 @@
|
|||
/* backtrace.c -- Entry point for stack backtrace library.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "unwind.h"
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* The main backtrace_full routine. */
|
||||
|
||||
/* Data passed through _Unwind_Backtrace. */
|
||||
|
||||
struct backtrace_data
|
||||
{
|
||||
/* Number of frames to skip. */
|
||||
int skip;
|
||||
/* Library state. */
|
||||
struct backtrace_state *state;
|
||||
/* Callback routine. */
|
||||
backtrace_full_callback callback;
|
||||
/* Error callback routine. */
|
||||
backtrace_error_callback error_callback;
|
||||
/* Data to pass to callback routines. */
|
||||
void *data;
|
||||
/* Value to return from backtrace_full. */
|
||||
int ret;
|
||||
/* Whether there is any memory available. */
|
||||
int can_alloc;
|
||||
};
|
||||
|
||||
/* Unwind library callback routine. This is passed to
|
||||
_Unwind_Backtrace. */
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
unwind (struct _Unwind_Context *context, void *vdata)
|
||||
{
|
||||
struct backtrace_data *bdata = (struct backtrace_data *) vdata;
|
||||
uintptr_t pc;
|
||||
int ip_before_insn = 0;
|
||||
|
||||
#ifdef HAVE_GETIPINFO
|
||||
pc = _Unwind_GetIPInfo (context, &ip_before_insn);
|
||||
#else
|
||||
pc = _Unwind_GetIP (context);
|
||||
#endif
|
||||
|
||||
if (bdata->skip > 0)
|
||||
{
|
||||
--bdata->skip;
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
if (!ip_before_insn)
|
||||
--pc;
|
||||
|
||||
if (!bdata->can_alloc)
|
||||
bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL);
|
||||
else
|
||||
bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback,
|
||||
bdata->error_callback, bdata->data);
|
||||
if (bdata->ret != 0)
|
||||
return _URC_END_OF_STACK;
|
||||
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
/* Get a stack backtrace. */
|
||||
|
||||
int
|
||||
backtrace_full (struct backtrace_state *state, int skip,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
struct backtrace_data bdata;
|
||||
void *p;
|
||||
|
||||
bdata.skip = skip + 1;
|
||||
bdata.state = state;
|
||||
bdata.callback = callback;
|
||||
bdata.error_callback = error_callback;
|
||||
bdata.data = data;
|
||||
bdata.ret = 0;
|
||||
|
||||
/* If we can't allocate any memory at all, don't try to produce
|
||||
file/line information. */
|
||||
p = backtrace_alloc (state, 4096, NULL, NULL);
|
||||
if (p == NULL)
|
||||
bdata.can_alloc = 0;
|
||||
else
|
||||
{
|
||||
backtrace_free (state, p, 4096, NULL, NULL);
|
||||
bdata.can_alloc = 1;
|
||||
}
|
||||
|
||||
_Unwind_Backtrace (unwind, &bdata);
|
||||
return bdata.ret;
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
/* backtrace.h -- Public header file for stack backtrace library.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#ifndef BACKTRACE_H
|
||||
#define BACKTRACE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* We want to get a definition for uintptr_t, but we still care about
|
||||
systems that don't have <stdint.h>. */
|
||||
#if defined(__GLIBC__) && __GLIBC__ >= 2
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#elif defined(HAVE_STDINT_H)
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#else
|
||||
|
||||
/* Systems that don't have <stdint.h> must provide gstdint.h, e.g.,
|
||||
from GCC_HEADER_STDINT in configure.ac. */
|
||||
#include "gstdint.h"
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The backtrace state. This struct is intentionally not defined in
|
||||
the public interface. */
|
||||
|
||||
struct backtrace_state;
|
||||
|
||||
/* The type of the error callback argument to backtrace functions.
|
||||
This function, if not NULL, will be called for certain error cases.
|
||||
The DATA argument is passed to the function that calls this one.
|
||||
The MSG argument is an error message. The ERRNUM argument, if
|
||||
greater than 0, holds an errno value. The MSG buffer may become
|
||||
invalid after this function returns.
|
||||
|
||||
As a special case, the ERRNUM argument will be passed as -1 if no
|
||||
debug info can be found for the executable, but the function
|
||||
requires debug info (e.g., backtrace_full, backtrace_pcinfo). The
|
||||
MSG in this case will be something along the lines of "no debug
|
||||
info". Similarly, ERRNUM will be passed as -1 if there is no
|
||||
symbol table, but the function requires a symbol table (e.g.,
|
||||
backtrace_syminfo). This may be used as a signal that some other
|
||||
approach should be tried. */
|
||||
|
||||
typedef void (*backtrace_error_callback) (void *data, const char *msg,
|
||||
int errnum);
|
||||
|
||||
/* Create state information for the backtrace routines. This must be
|
||||
called before any of the other routines, and its return value must
|
||||
be passed to all of the other routines. FILENAME is the path name
|
||||
of the executable file; if it is NULL the library will try
|
||||
system-specific path names. If not NULL, FILENAME must point to a
|
||||
permanent buffer. If THREADED is non-zero the state may be
|
||||
accessed by multiple threads simultaneously, and the library will
|
||||
use appropriate atomic operations. If THREADED is zero the state
|
||||
may only be accessed by one thread at a time. This returns a state
|
||||
pointer on success, NULL on error. If an error occurs, this will
|
||||
call the ERROR_CALLBACK routine. */
|
||||
|
||||
extern struct backtrace_state *backtrace_create_state (
|
||||
const char *filename, int threaded,
|
||||
backtrace_error_callback error_callback, void *data);
|
||||
|
||||
/* The type of the callback argument to the backtrace_full function.
|
||||
DATA is the argument passed to backtrace_full. PC is the program
|
||||
counter. FILENAME is the name of the file containing PC, or NULL
|
||||
if not available. LINENO is the line number in FILENAME containing
|
||||
PC, or 0 if not available. FUNCTION is the name of the function
|
||||
containing PC, or NULL if not available. This should return 0 to
|
||||
continuing tracing. The FILENAME and FUNCTION buffers may become
|
||||
invalid after this function returns. */
|
||||
|
||||
typedef int (*backtrace_full_callback) (void *data, uintptr_t pc,
|
||||
const char *filename, int lineno,
|
||||
const char *function);
|
||||
|
||||
/* Get a full stack backtrace. SKIP is the number of frames to skip;
|
||||
passing 0 will start the trace with the function calling
|
||||
backtrace_full. DATA is passed to the callback routine. If any
|
||||
call to CALLBACK returns a non-zero value, the stack backtrace
|
||||
stops, and backtrace returns that value; this may be used to limit
|
||||
the number of stack frames desired. If all calls to CALLBACK
|
||||
return 0, backtrace returns 0. The backtrace_full function will
|
||||
make at least one call to either CALLBACK or ERROR_CALLBACK. This
|
||||
function requires debug info for the executable. */
|
||||
|
||||
extern int backtrace_full (struct backtrace_state *state, int skip,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* The type of the callback argument to the backtrace_simple function.
|
||||
DATA is the argument passed to simple_backtrace. PC is the program
|
||||
counter. This should return 0 to continue tracing. */
|
||||
|
||||
typedef int (*backtrace_simple_callback) (void *data, uintptr_t pc);
|
||||
|
||||
/* Get a simple backtrace. SKIP is the number of frames to skip, as
|
||||
in backtrace. DATA is passed to the callback routine. If any call
|
||||
to CALLBACK returns a non-zero value, the stack backtrace stops,
|
||||
and backtrace_simple returns that value. Otherwise
|
||||
backtrace_simple returns 0. The backtrace_simple function will
|
||||
make at least one call to either CALLBACK or ERROR_CALLBACK. This
|
||||
function does not require any debug info for the executable. */
|
||||
|
||||
extern int backtrace_simple (struct backtrace_state *state, int skip,
|
||||
backtrace_simple_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* Print the current backtrace in a user readable format to a FILE.
|
||||
SKIP is the number of frames to skip, as in backtrace_full. Any
|
||||
error messages are printed to stderr. This function requires debug
|
||||
info for the executable. */
|
||||
|
||||
extern void backtrace_print (struct backtrace_state *state, int skip, FILE *);
|
||||
|
||||
/* Given PC, a program counter in the current program, call the
|
||||
callback function with filename, line number, and function name
|
||||
information. This will normally call the callback function exactly
|
||||
once. However, if the PC happens to describe an inlined call, and
|
||||
the debugging information contains the necessary information, then
|
||||
this may call the callback function multiple times. This will make
|
||||
at least one call to either CALLBACK or ERROR_CALLBACK. This
|
||||
returns the first non-zero value returned by CALLBACK, or 0. */
|
||||
|
||||
extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* The type of the callback argument to backtrace_syminfo. DATA and
|
||||
PC are the arguments passed to backtrace_syminfo. SYMNAME is the
|
||||
name of the symbol for the corresponding code. SYMVAL is the
|
||||
value and SYMSIZE is the size of the symbol. SYMNAME will be NULL
|
||||
if no error occurred but the symbol could not be found. */
|
||||
|
||||
typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc,
|
||||
const char *symname,
|
||||
uintptr_t symval,
|
||||
uintptr_t symsize);
|
||||
|
||||
/* Given ADDR, an address or program counter in the current program,
|
||||
call the callback information with the symbol name and value
|
||||
describing the function or variable in which ADDR may be found.
|
||||
This will call either CALLBACK or ERROR_CALLBACK exactly once.
|
||||
This returns 1 on success, 0 on failure. This function requires
|
||||
the symbol table but does not require the debug info. Note that if
|
||||
the symbol table is present but ADDR could not be found in the
|
||||
table, CALLBACK will be called with a NULL SYMNAME argument.
|
||||
Returns 1 on success, 0 on error. */
|
||||
|
||||
extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr,
|
||||
backtrace_syminfo_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End extern "C". */
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,721 @@
|
|||
/* btest.c -- Test for libbacktrace library
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
/* This program tests the externally visible interfaces of the
|
||||
libbacktrace library. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "filenames.h"
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "backtrace-supported.h"
|
||||
|
||||
/* Portable attribute syntax. Actually some of these tests probably
|
||||
won't work if the attributes are not recognized. */
|
||||
|
||||
#ifndef GCC_VERSION
|
||||
# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
|
||||
#endif
|
||||
|
||||
#if (GCC_VERSION < 2007)
|
||||
# define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
||||
/* Used to collect backtrace info. */
|
||||
|
||||
struct info
|
||||
{
|
||||
char *filename;
|
||||
int lineno;
|
||||
char *function;
|
||||
};
|
||||
|
||||
/* Passed to backtrace callback function. */
|
||||
|
||||
struct bdata
|
||||
{
|
||||
struct info *all;
|
||||
size_t index;
|
||||
size_t max;
|
||||
int failed;
|
||||
};
|
||||
|
||||
/* Passed to backtrace_simple callback function. */
|
||||
|
||||
struct sdata
|
||||
{
|
||||
uintptr_t *addrs;
|
||||
size_t index;
|
||||
size_t max;
|
||||
int failed;
|
||||
};
|
||||
|
||||
/* Passed to backtrace_syminfo callback function. */
|
||||
|
||||
struct symdata
|
||||
{
|
||||
const char *name;
|
||||
uintptr_t val, size;
|
||||
int failed;
|
||||
};
|
||||
|
||||
/* The backtrace state. */
|
||||
|
||||
static void *state;
|
||||
|
||||
/* The number of failures. */
|
||||
|
||||
static int failures;
|
||||
|
||||
/* Return the base name in a path. */
|
||||
|
||||
static const char *
|
||||
base (const char *p)
|
||||
{
|
||||
const char *last;
|
||||
const char *s;
|
||||
|
||||
last = NULL;
|
||||
for (s = p; *s != '\0'; ++s)
|
||||
{
|
||||
if (IS_DIR_SEPARATOR (*s))
|
||||
last = s + 1;
|
||||
}
|
||||
return last != NULL ? last : p;
|
||||
}
|
||||
|
||||
/* Check an entry in a struct info array. */
|
||||
|
||||
static void
|
||||
check (const char *name, int index, const struct info *all, int want_lineno,
|
||||
const char *want_function, int *failed)
|
||||
{
|
||||
if (*failed)
|
||||
return;
|
||||
if (all[index].filename == NULL || all[index].function == NULL)
|
||||
{
|
||||
fprintf (stderr, "%s: [%d]: missing file name or function name\n",
|
||||
name, index);
|
||||
*failed = 1;
|
||||
return;
|
||||
}
|
||||
if (strcmp (base (all[index].filename), "btest.c") != 0)
|
||||
{
|
||||
fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
|
||||
all[index].filename);
|
||||
*failed = 1;
|
||||
}
|
||||
if (all[index].lineno != want_lineno)
|
||||
{
|
||||
fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
|
||||
all[index].lineno, want_lineno);
|
||||
*failed = 1;
|
||||
}
|
||||
if (strcmp (all[index].function, want_function) != 0)
|
||||
{
|
||||
fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
|
||||
all[index].function, want_function);
|
||||
*failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The backtrace callback function. */
|
||||
|
||||
static int
|
||||
callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
|
||||
const char *filename, int lineno, const char *function)
|
||||
{
|
||||
struct bdata *data = (struct bdata *) vdata;
|
||||
struct info *p;
|
||||
|
||||
if (data->index >= data->max)
|
||||
{
|
||||
fprintf (stderr, "callback_one: callback called too many times\n");
|
||||
data->failed = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
p = &data->all[data->index];
|
||||
if (filename == NULL)
|
||||
p->filename = NULL;
|
||||
else
|
||||
{
|
||||
p->filename = strdup (filename);
|
||||
assert (p->filename != NULL);
|
||||
}
|
||||
p->lineno = lineno;
|
||||
if (function == NULL)
|
||||
p->function = NULL;
|
||||
else
|
||||
{
|
||||
p->function = strdup (function);
|
||||
assert (p->function != NULL);
|
||||
}
|
||||
++data->index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* An error callback passed to backtrace. */
|
||||
|
||||
static void
|
||||
error_callback_one (void *vdata, const char *msg, int errnum)
|
||||
{
|
||||
struct bdata *data = (struct bdata *) vdata;
|
||||
|
||||
fprintf (stderr, "%s", msg);
|
||||
if (errnum > 0)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
fprintf (stderr, "\n");
|
||||
data->failed = 1;
|
||||
}
|
||||
|
||||
/* The backtrace_simple callback function. */
|
||||
|
||||
static int
|
||||
callback_two (void *vdata, uintptr_t pc)
|
||||
{
|
||||
struct sdata *data = (struct sdata *) vdata;
|
||||
|
||||
if (data->index >= data->max)
|
||||
{
|
||||
fprintf (stderr, "callback_two: callback called too many times\n");
|
||||
data->failed = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
data->addrs[data->index] = pc;
|
||||
++data->index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* An error callback passed to backtrace_simple. */
|
||||
|
||||
static void
|
||||
error_callback_two (void *vdata, const char *msg, int errnum)
|
||||
{
|
||||
struct sdata *data = (struct sdata *) vdata;
|
||||
|
||||
fprintf (stderr, "%s", msg);
|
||||
if (errnum > 0)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
fprintf (stderr, "\n");
|
||||
data->failed = 1;
|
||||
}
|
||||
|
||||
/* The backtrace_syminfo callback function. */
|
||||
|
||||
static void
|
||||
callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
|
||||
const char *symname, uintptr_t symval,
|
||||
uintptr_t symsize)
|
||||
{
|
||||
struct symdata *data = (struct symdata *) vdata;
|
||||
|
||||
if (symname == NULL)
|
||||
data->name = NULL;
|
||||
else
|
||||
{
|
||||
data->name = strdup (symname);
|
||||
assert (data->name != NULL);
|
||||
}
|
||||
data->val = symval;
|
||||
data->size = symsize;
|
||||
}
|
||||
|
||||
/* The backtrace_syminfo error callback function. */
|
||||
|
||||
static void
|
||||
error_callback_three (void *vdata, const char *msg, int errnum)
|
||||
{
|
||||
struct symdata *data = (struct symdata *) vdata;
|
||||
|
||||
fprintf (stderr, "%s", msg);
|
||||
if (errnum > 0)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
fprintf (stderr, "\n");
|
||||
data->failed = 1;
|
||||
}
|
||||
|
||||
/* Test the backtrace function with non-inlined functions. */
|
||||
|
||||
static int test1 (void) __attribute__ ((noinline, unused));
|
||||
static int f2 (int) __attribute__ ((noinline));
|
||||
static int f3 (int, int) __attribute__ ((noinline));
|
||||
|
||||
static int
|
||||
test1 (void)
|
||||
{
|
||||
/* Returning a value here and elsewhere avoids a tailcall which
|
||||
would mess up the backtrace. */
|
||||
return f2 (__LINE__) + 1;
|
||||
}
|
||||
|
||||
static int
|
||||
f2 (int f1line)
|
||||
{
|
||||
return f3 (f1line, __LINE__) + 2;
|
||||
}
|
||||
|
||||
static int
|
||||
f3 (int f1line, int f2line)
|
||||
{
|
||||
struct info all[20];
|
||||
struct bdata data;
|
||||
int f3line;
|
||||
int i;
|
||||
|
||||
data.all = &all[0];
|
||||
data.index = 0;
|
||||
data.max = 20;
|
||||
data.failed = 0;
|
||||
|
||||
f3line = __LINE__ + 1;
|
||||
i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr, "test1: unexpected return value %d\n", i);
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
if (data.index < 3)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"test1: not enough frames; got %zu, expected at least 3\n",
|
||||
data.index);
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
check ("test1", 0, all, f3line, "f3", &data.failed);
|
||||
check ("test1", 1, all, f2line, "f2", &data.failed);
|
||||
check ("test1", 2, all, f1line, "test1", &data.failed);
|
||||
|
||||
printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
|
||||
|
||||
if (data.failed)
|
||||
++failures;
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
/* Test the backtrace function with inlined functions. */
|
||||
|
||||
static inline int test2 (void) __attribute__ ((always_inline, unused));
|
||||
static inline int f12 (int) __attribute__ ((always_inline));
|
||||
static inline int f13 (int, int) __attribute__ ((always_inline));
|
||||
|
||||
static inline int
|
||||
test2 (void)
|
||||
{
|
||||
return f12 (__LINE__) + 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
f12 (int f1line)
|
||||
{
|
||||
return f13 (f1line, __LINE__) + 2;
|
||||
}
|
||||
|
||||
static inline int
|
||||
f13 (int f1line, int f2line)
|
||||
{
|
||||
struct info all[20];
|
||||
struct bdata data;
|
||||
int f3line;
|
||||
int i;
|
||||
|
||||
data.all = &all[0];
|
||||
data.index = 0;
|
||||
data.max = 20;
|
||||
data.failed = 0;
|
||||
|
||||
f3line = __LINE__ + 1;
|
||||
i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr, "test2: unexpected return value %d\n", i);
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
check ("test2", 0, all, f3line, "f13", &data.failed);
|
||||
check ("test2", 1, all, f2line, "f12", &data.failed);
|
||||
check ("test2", 2, all, f1line, "test2", &data.failed);
|
||||
|
||||
printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
|
||||
|
||||
if (data.failed)
|
||||
++failures;
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
/* Test the backtrace_simple function with non-inlined functions. */
|
||||
|
||||
static int test3 (void) __attribute__ ((noinline, unused));
|
||||
static int f22 (int) __attribute__ ((noinline));
|
||||
static int f23 (int, int) __attribute__ ((noinline));
|
||||
|
||||
static int
|
||||
test3 (void)
|
||||
{
|
||||
return f22 (__LINE__) + 1;
|
||||
}
|
||||
|
||||
static int
|
||||
f22 (int f1line)
|
||||
{
|
||||
return f23 (f1line, __LINE__) + 2;
|
||||
}
|
||||
|
||||
static int
|
||||
f23 (int f1line, int f2line)
|
||||
{
|
||||
uintptr_t addrs[20];
|
||||
struct sdata data;
|
||||
int f3line;
|
||||
int i;
|
||||
|
||||
data.addrs = &addrs[0];
|
||||
data.index = 0;
|
||||
data.max = 20;
|
||||
data.failed = 0;
|
||||
|
||||
f3line = __LINE__ + 1;
|
||||
i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr, "test3: unexpected return value %d\n", i);
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
if (!data.failed)
|
||||
{
|
||||
struct info all[20];
|
||||
struct bdata bdata;
|
||||
int j;
|
||||
|
||||
bdata.all = &all[0];
|
||||
bdata.index = 0;
|
||||
bdata.max = 20;
|
||||
bdata.failed = 0;
|
||||
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
i = backtrace_pcinfo (state, addrs[j], callback_one,
|
||||
error_callback_one, &bdata);
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
("test3: unexpected return value "
|
||||
"from backtrace_pcinfo %d\n"),
|
||||
i);
|
||||
bdata.failed = 1;
|
||||
}
|
||||
if (!bdata.failed && bdata.index != (size_t) (j + 1))
|
||||
{
|
||||
fprintf (stderr,
|
||||
("wrong number of calls from backtrace_pcinfo "
|
||||
"got %u expected %d\n"),
|
||||
(unsigned int) bdata.index, j + 1);
|
||||
bdata.failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
check ("test3", 0, all, f3line, "f23", &bdata.failed);
|
||||
check ("test3", 1, all, f2line, "f22", &bdata.failed);
|
||||
check ("test3", 2, all, f1line, "test3", &bdata.failed);
|
||||
|
||||
if (bdata.failed)
|
||||
data.failed = 1;
|
||||
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
struct symdata symdata;
|
||||
|
||||
symdata.name = NULL;
|
||||
symdata.val = 0;
|
||||
symdata.size = 0;
|
||||
symdata.failed = 0;
|
||||
|
||||
i = backtrace_syminfo (state, addrs[j], callback_three,
|
||||
error_callback_three, &symdata);
|
||||
if (i == 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
("test3: [%d]: unexpected return value "
|
||||
"from backtrace_syminfo %d\n"),
|
||||
j, i);
|
||||
symdata.failed = 1;
|
||||
}
|
||||
|
||||
if (!symdata.failed)
|
||||
{
|
||||
const char *expected;
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0:
|
||||
expected = "f23";
|
||||
break;
|
||||
case 1:
|
||||
expected = "f22";
|
||||
break;
|
||||
case 2:
|
||||
expected = "test3";
|
||||
break;
|
||||
default:
|
||||
assert (0);
|
||||
}
|
||||
|
||||
if (symdata.name == NULL)
|
||||
{
|
||||
fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
|
||||
symdata.failed = 1;
|
||||
}
|
||||
/* Use strncmp, not strcmp, because GCC might create a
|
||||
clone. */
|
||||
else if (strncmp (symdata.name, expected, strlen (expected))
|
||||
!= 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
("test3: [%d]: unexpected syminfo name "
|
||||
"got %s expected %s\n"),
|
||||
j, symdata.name, expected);
|
||||
symdata.failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (symdata.failed)
|
||||
data.failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
|
||||
|
||||
if (data.failed)
|
||||
++failures;
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
/* Test the backtrace_simple function with inlined functions. */
|
||||
|
||||
static inline int test4 (void) __attribute__ ((always_inline, unused));
|
||||
static inline int f32 (int) __attribute__ ((always_inline));
|
||||
static inline int f33 (int, int) __attribute__ ((always_inline));
|
||||
|
||||
static inline int
|
||||
test4 (void)
|
||||
{
|
||||
return f32 (__LINE__) + 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
f32 (int f1line)
|
||||
{
|
||||
return f33 (f1line, __LINE__) + 2;
|
||||
}
|
||||
|
||||
static inline int
|
||||
f33 (int f1line, int f2line)
|
||||
{
|
||||
uintptr_t addrs[20];
|
||||
struct sdata data;
|
||||
int f3line;
|
||||
int i;
|
||||
|
||||
data.addrs = &addrs[0];
|
||||
data.index = 0;
|
||||
data.max = 20;
|
||||
data.failed = 0;
|
||||
|
||||
f3line = __LINE__ + 1;
|
||||
i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr, "test3: unexpected return value %d\n", i);
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
if (!data.failed)
|
||||
{
|
||||
struct info all[20];
|
||||
struct bdata bdata;
|
||||
|
||||
bdata.all = &all[0];
|
||||
bdata.index = 0;
|
||||
bdata.max = 20;
|
||||
bdata.failed = 0;
|
||||
|
||||
i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
|
||||
&bdata);
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
("test4: unexpected return value "
|
||||
"from backtrace_pcinfo %d\n"),
|
||||
i);
|
||||
bdata.failed = 1;
|
||||
}
|
||||
|
||||
check ("test4", 0, all, f3line, "f33", &bdata.failed);
|
||||
check ("test4", 1, all, f2line, "f32", &bdata.failed);
|
||||
check ("test4", 2, all, f1line, "test4", &bdata.failed);
|
||||
|
||||
if (bdata.failed)
|
||||
data.failed = 1;
|
||||
}
|
||||
|
||||
printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
|
||||
|
||||
if (data.failed)
|
||||
++failures;
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
#if BACKTRACE_SUPPORTS_DATA
|
||||
|
||||
int global = 1;
|
||||
|
||||
static int
|
||||
test5 (void)
|
||||
{
|
||||
struct symdata symdata;
|
||||
int i;
|
||||
uintptr_t addr = (uintptr_t) &global;
|
||||
|
||||
if (sizeof (global) > 1)
|
||||
addr += 1;
|
||||
|
||||
symdata.name = NULL;
|
||||
symdata.val = 0;
|
||||
symdata.size = 0;
|
||||
symdata.failed = 0;
|
||||
|
||||
i = backtrace_syminfo (state, addr, callback_three,
|
||||
error_callback_three, &symdata);
|
||||
if (i == 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"test5: unexpected return value from backtrace_syminfo %d\n",
|
||||
i);
|
||||
symdata.failed = 1;
|
||||
}
|
||||
|
||||
if (!symdata.failed)
|
||||
{
|
||||
if (symdata.name == NULL)
|
||||
{
|
||||
fprintf (stderr, "test5: NULL syminfo name\n");
|
||||
symdata.failed = 1;
|
||||
}
|
||||
else if (strcmp (symdata.name, "global") != 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"test5: unexpected syminfo name got %s expected %s\n",
|
||||
symdata.name, "global");
|
||||
symdata.failed = 1;
|
||||
}
|
||||
else if (symdata.val != (uintptr_t) &global)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"test5: unexpected syminfo value got %lx expected %lx\n",
|
||||
(unsigned long) symdata.val,
|
||||
(unsigned long) (uintptr_t) &global);
|
||||
symdata.failed = 1;
|
||||
}
|
||||
else if (symdata.size != sizeof (global))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"test5: unexpected syminfo size got %lx expected %lx\n",
|
||||
(unsigned long) symdata.size,
|
||||
(unsigned long) sizeof (global));
|
||||
symdata.failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf ("%s: backtrace_syminfo variable\n",
|
||||
symdata.failed ? "FAIL" : "PASS");
|
||||
|
||||
if (symdata.failed)
|
||||
++failures;
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
#endif /* BACKTRACE_SUPPORTS_DATA */
|
||||
|
||||
static void
|
||||
error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
|
||||
int errnum)
|
||||
{
|
||||
fprintf (stderr, "%s", msg);
|
||||
if (errnum > 0)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
fprintf (stderr, "\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Run all the tests. */
|
||||
|
||||
int
|
||||
main (int argc ATTRIBUTE_UNUSED, char **argv)
|
||||
{
|
||||
state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
|
||||
error_callback_create, NULL);
|
||||
|
||||
#if BACKTRACE_SUPPORTED
|
||||
test1 ();
|
||||
test2 ();
|
||||
test3 ();
|
||||
test4 ();
|
||||
#if BACKTRACE_SUPPORTS_DATA
|
||||
test5 ();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
1462
third_party/rust/backtrace-sys-0.1.10/src/libbacktrace/config.guess
поставляемый
Executable file
1462
third_party/rust/backtrace-sys-0.1.10/src/libbacktrace/config.guess
поставляемый
Executable file
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,134 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* ELF size: 32 or 64 */
|
||||
#undef BACKTRACE_ELF_SIZE
|
||||
|
||||
/* Define to 1 if you have the __atomic functions */
|
||||
#undef HAVE_ATOMIC_FUNCTIONS
|
||||
|
||||
/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_STRNLEN
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define if dl_iterate_phdr is available. */
|
||||
#undef HAVE_DL_ITERATE_PHDR
|
||||
|
||||
/* Define to 1 if you have the fcntl function */
|
||||
#undef HAVE_FCNTL
|
||||
|
||||
/* Define if getexecname is available. */
|
||||
#undef HAVE_GETEXECNAME
|
||||
|
||||
/* Define if _Unwind_GetIPInfo is available. */
|
||||
#undef HAVE_GETIPINFO
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <link.h> header file. */
|
||||
#undef HAVE_LINK_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the __sync functions */
|
||||
#undef HAVE_SYNC_FUNCTIONS
|
||||
|
||||
/* Define to 1 if you have the <sys/mman.h> header file. */
|
||||
#undef HAVE_SYS_MMAN_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* The size of `char', as computed by sizeof. */
|
||||
#undef SIZEOF_CHAR
|
||||
|
||||
/* The size of `int', as computed by sizeof. */
|
||||
#undef SIZEOF_INT
|
||||
|
||||
/* The size of `long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG
|
||||
|
||||
/* The size of `short', as computed by sizeof. */
|
||||
#undef SIZEOF_SHORT
|
||||
|
||||
/* The size of `void *', as computed by sizeof. */
|
||||
#undef SIZEOF_VOID_P
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
#undef _MINIX
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
#undef _POSIX_1_SOURCE
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,409 @@
|
|||
# configure.ac -- Backtrace configure script.
|
||||
# Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
|
||||
# (1) Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
|
||||
# (2) Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
|
||||
# (3) The name of the author may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
AC_PREREQ(2.64)
|
||||
AC_INIT(package-unused, version-unused,, libbacktrace)
|
||||
AC_CONFIG_SRCDIR(backtrace.h)
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
if test -n "${with_target_subdir}"; then
|
||||
AM_ENABLE_MULTILIB(, ..)
|
||||
fi
|
||||
|
||||
AC_CANONICAL_SYSTEM
|
||||
target_alias=${target_alias-$host_alias}
|
||||
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
libtool_VERSION=1:0:0
|
||||
AC_SUBST(libtool_VERSION)
|
||||
|
||||
# 1.11.1: Require that version of automake.
|
||||
# foreign: Don't require README, INSTALL, NEWS, etc.
|
||||
# no-define: Don't define PACKAGE and VERSION.
|
||||
# no-dependencies: Don't generate automatic dependencies.
|
||||
# (because it breaks when using bootstrap-lean, since some of the
|
||||
# headers are gone at "make install" time).
|
||||
# -Wall: Issue all automake warnings.
|
||||
# -Wno-portability: Don't warn about constructs supported by GNU make.
|
||||
# (because GCC requires GNU make anyhow).
|
||||
AM_INIT_AUTOMAKE([1.11.1 foreign no-dist no-define no-dependencies -Wall -Wno-portability])
|
||||
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
AC_ARG_WITH(target-subdir,
|
||||
[ --with-target-subdir=SUBDIR Configuring in a subdirectory for target])
|
||||
|
||||
# We must force CC to /not/ be precious variables; otherwise
|
||||
# the wrong, non-multilib-adjusted value will be used in multilibs.
|
||||
# As a side effect, we have to subst CFLAGS ourselves.
|
||||
m4_rename([_AC_ARG_VAR_PRECIOUS],[backtrace_PRECIOUS])
|
||||
m4_define([_AC_ARG_VAR_PRECIOUS],[])
|
||||
AC_PROG_CC
|
||||
m4_rename_force([backtrace_PRECIOUS],[_AC_ARG_VAR_PRECIOUS])
|
||||
|
||||
AC_SUBST(CFLAGS)
|
||||
|
||||
AC_PROG_RANLIB
|
||||
|
||||
AC_PROG_AWK
|
||||
case "$AWK" in
|
||||
"") AC_MSG_ERROR([can't build without awk]) ;;
|
||||
esac
|
||||
|
||||
LT_INIT
|
||||
AM_PROG_LIBTOOL
|
||||
|
||||
backtrace_supported=yes
|
||||
|
||||
if test -n "${with_target_subdir}"; then
|
||||
# We are compiling a GCC library. We can assume that the unwind
|
||||
# library exists.
|
||||
BACKTRACE_FILE="backtrace.lo simple.lo"
|
||||
else
|
||||
AC_CHECK_HEADER([unwind.h],
|
||||
[AC_CHECK_FUNC([_Unwind_Backtrace],
|
||||
[BACKTRACE_FILE="backtrace.lo simple.lo"],
|
||||
[BACKTRACE_FILE="nounwind.lo"
|
||||
backtrace_supported=no])],
|
||||
[BACKTRACE_FILE="nounwind.lo"
|
||||
backtrace_supported=no])
|
||||
fi
|
||||
AC_SUBST(BACKTRACE_FILE)
|
||||
|
||||
EXTRA_FLAGS=
|
||||
if test -n "${with_target_subdir}"; then
|
||||
EXTRA_FLAGS="-funwind-tables -frandom-seed=\$@"
|
||||
else
|
||||
AC_CACHE_CHECK([for -funwind-tables option],
|
||||
[libbacktrace_cv_c_unwind_tables],
|
||||
[CFLAGS_hold="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -funwind-tables"
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([static int f() { return 0; }], [return f();])],
|
||||
[libbacktrace_cv_c_unwind_tables=yes],
|
||||
[libbacktrace_cv_c_unwind_tables=no])
|
||||
CFLAGS="$CFLAGS_hold"])
|
||||
if test "$libbacktrace_cv_c_unwind_tables" = "yes"; then
|
||||
EXTRA_FLAGS=-funwind-tables
|
||||
fi
|
||||
AC_CACHE_CHECK([for -frandom-seed=string option],
|
||||
[libbacktrace_cv_c_random_seed_string],
|
||||
[CFLAGS_hold="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -frandom-seed=conftest.lo"
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([], [return 0;])],
|
||||
[libbacktrace_cv_c_random_seed_string=yes],
|
||||
[libbacktrace_cv_c_random_seed_string=no])
|
||||
CFLAGS="$CFLAGS_hold"])
|
||||
if test "$libbacktrace_cv_c_random_seed_string" = "yes"; then
|
||||
EXTRA_FLAGS="$EXTRA_FLAGS -frandom-seed=\$@"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(EXTRA_FLAGS)
|
||||
|
||||
ACX_PROG_CC_WARNING_OPTS([-W -Wall -Wwrite-strings -Wstrict-prototypes \
|
||||
-Wmissing-prototypes -Wold-style-definition \
|
||||
-Wmissing-format-attribute -Wcast-qual],
|
||||
[WARN_FLAGS])
|
||||
|
||||
if test -n "${with_target_subdir}"; then
|
||||
WARN_FLAGS="$WARN_FLAGS -Werror"
|
||||
fi
|
||||
|
||||
AC_SUBST(WARN_FLAGS)
|
||||
|
||||
if test -n "${with_target_subdir}"; then
|
||||
GCC_CHECK_UNWIND_GETIPINFO
|
||||
else
|
||||
ac_save_CFFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Werror-implicit-function-declaration"
|
||||
AC_MSG_CHECKING([for _Unwind_GetIPInfo])
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[#include "unwind.h"
|
||||
struct _Unwind_Context *context;
|
||||
int ip_before_insn = 0;],
|
||||
[return _Unwind_GetIPInfo (context, &ip_before_insn);])],
|
||||
[have_unwind_getipinfo=yes], [have_unwind_getipinfo=no])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
AC_MSG_RESULT([$have_unwind_getipinfo])
|
||||
if test "$have_unwind_getipinfo" = "yes"; then
|
||||
AC_DEFINE(HAVE_GETIPINFO, 1, [Define if _Unwind_GetIPInfo is available.])
|
||||
fi
|
||||
fi
|
||||
|
||||
# Enable --enable-host-shared.
|
||||
AC_ARG_ENABLE(host-shared,
|
||||
[AS_HELP_STRING([--enable-host-shared],
|
||||
[build host code as shared libraries])],
|
||||
[PIC_FLAG=-fPIC], [PIC_FLAG=])
|
||||
AC_SUBST(PIC_FLAG)
|
||||
|
||||
# Test for __sync support.
|
||||
AC_CACHE_CHECK([__sync extensions],
|
||||
[libbacktrace_cv_sys_sync],
|
||||
[if test -n "${with_target_subdir}"; then
|
||||
case "${host}" in
|
||||
hppa*-*-hpux*) libbacktrace_cv_sys_sync=no ;;
|
||||
*) libbacktrace_cv_sys_sync=yes ;;
|
||||
esac
|
||||
else
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([int i;],
|
||||
[__sync_bool_compare_and_swap (&i, i, i);
|
||||
__sync_lock_test_and_set (&i, 1);
|
||||
__sync_lock_release (&i);])],
|
||||
[libbacktrace_cv_sys_sync=yes],
|
||||
[libbacktrace_cv_sys_sync=no])
|
||||
fi])
|
||||
BACKTRACE_SUPPORTS_THREADS=0
|
||||
if test "$libbacktrace_cv_sys_sync" = "yes"; then
|
||||
BACKTRACE_SUPPORTS_THREADS=1
|
||||
AC_DEFINE([HAVE_SYNC_FUNCTIONS], 1,
|
||||
[Define to 1 if you have the __sync functions])
|
||||
fi
|
||||
AC_SUBST(BACKTRACE_SUPPORTS_THREADS)
|
||||
|
||||
# Test for __atomic support.
|
||||
AC_CACHE_CHECK([__atomic extensions],
|
||||
[libbacktrace_cv_sys_atomic],
|
||||
[if test -n "${with_target_subdir}"; then
|
||||
libbacktrace_cv_sys_atomic=yes
|
||||
else
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([int i;],
|
||||
[__atomic_load_n (&i, __ATOMIC_ACQUIRE);
|
||||
__atomic_store_n (&i, 1, __ATOMIC_RELEASE);])],
|
||||
[libbacktrace_cv_sys_atomic=yes],
|
||||
[libbacktrace_cv_sys_atomic=no])
|
||||
fi])
|
||||
if test "$libbacktrace_cv_sys_atomic" = "yes"; then
|
||||
AC_DEFINE([HAVE_ATOMIC_FUNCTIONS], 1,
|
||||
[Define to 1 if you have the __atomic functions])
|
||||
fi
|
||||
|
||||
# The library needs to be able to read the executable itself. Compile
|
||||
# a file to determine the executable format. The awk script
|
||||
# filetype.awk prints out the file type.
|
||||
AC_CACHE_CHECK([output filetype],
|
||||
[libbacktrace_cv_sys_filetype],
|
||||
[filetype=
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([int i;], [int j;])],
|
||||
[filetype=`${AWK} -f $srcdir/filetype.awk conftest.$ac_objext`],
|
||||
[AC_MSG_FAILURE([compiler failed])])
|
||||
libbacktrace_cv_sys_filetype=$filetype])
|
||||
|
||||
# Match the file type to decide what files to compile.
|
||||
FORMAT_FILE=
|
||||
backtrace_supports_data=yes
|
||||
case "$libbacktrace_cv_sys_filetype" in
|
||||
elf*) FORMAT_FILE="elf.lo" ;;
|
||||
pecoff) FORMAT_FILE="pecoff.lo"
|
||||
backtrace_supports_data=no
|
||||
;;
|
||||
*) AC_MSG_WARN([could not determine output file type])
|
||||
FORMAT_FILE="unknown.lo"
|
||||
backtrace_supported=no
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(FORMAT_FILE)
|
||||
|
||||
# ELF defines.
|
||||
elfsize=
|
||||
case "$libbacktrace_cv_sys_filetype" in
|
||||
elf32) elfsize=32 ;;
|
||||
elf64) elfsize=64 ;;
|
||||
*) elfsize=unused
|
||||
esac
|
||||
AC_DEFINE_UNQUOTED([BACKTRACE_ELF_SIZE], [$elfsize], [ELF size: 32 or 64])
|
||||
|
||||
BACKTRACE_SUPPORTED=0
|
||||
if test "$backtrace_supported" = "yes"; then
|
||||
BACKTRACE_SUPPORTED=1
|
||||
fi
|
||||
AC_SUBST(BACKTRACE_SUPPORTED)
|
||||
|
||||
BACKTRACE_SUPPORTS_DATA=0
|
||||
if test "$backtrace_supports_data" = "yes"; then
|
||||
BACKTRACE_SUPPORTS_DATA=1
|
||||
fi
|
||||
AC_SUBST(BACKTRACE_SUPPORTS_DATA)
|
||||
|
||||
GCC_HEADER_STDINT(gstdint.h)
|
||||
|
||||
AC_CHECK_HEADERS(sys/mman.h)
|
||||
if test "$ac_cv_header_sys_mman_h" = "no"; then
|
||||
have_mmap=no
|
||||
else
|
||||
if test -n "${with_target_subdir}"; then
|
||||
# When built as a GCC target library, we can't do a link test. We
|
||||
# simply assume that if we have mman.h, we have mmap.
|
||||
have_mmap=yes
|
||||
case "${host}" in
|
||||
spu-*-*|*-*-msdosdjgpp)
|
||||
# The SPU does not have mmap, but it has a sys/mman.h header file
|
||||
# containing "mmap_eaddr" and the mmap flags, confusing the test.
|
||||
# DJGPP also has sys/man.h, but no mmap
|
||||
have_mmap=no ;;
|
||||
esac
|
||||
else
|
||||
AC_CHECK_FUNC(mmap, [have_mmap=yes], [have_mmap=no])
|
||||
fi
|
||||
fi
|
||||
if test "$have_mmap" = "no"; then
|
||||
VIEW_FILE=read.lo
|
||||
ALLOC_FILE=alloc.lo
|
||||
else
|
||||
VIEW_FILE=mmapio.lo
|
||||
AC_PREPROC_IFELSE([
|
||||
#include <sys/mman.h>
|
||||
#if !defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
|
||||
#error no MAP_ANONYMOUS
|
||||
#endif
|
||||
], [ALLOC_FILE=mmap.lo], [ALLOC_FILE=alloc.lo])
|
||||
fi
|
||||
AC_SUBST(VIEW_FILE)
|
||||
AC_SUBST(ALLOC_FILE)
|
||||
|
||||
BACKTRACE_USES_MALLOC=0
|
||||
if test "$ALLOC_FILE" = "alloc.lo"; then
|
||||
BACKTRACE_USES_MALLOC=1
|
||||
fi
|
||||
AC_SUBST(BACKTRACE_USES_MALLOC)
|
||||
|
||||
# Check for dl_iterate_phdr.
|
||||
AC_CHECK_HEADERS(link.h)
|
||||
if test "$ac_cv_header_link_h" = "no"; then
|
||||
have_dl_iterate_phdr=no
|
||||
else
|
||||
if test -n "${with_target_subdir}"; then
|
||||
# When built as a GCC target library, we can't do a link test.
|
||||
AC_EGREP_HEADER([dl_iterate_phdr], [link.h], [have_dl_iterate_phdr=yes],
|
||||
[have_dl_iterate_phdr=no])
|
||||
case "${host}" in
|
||||
*-*-solaris2.10*)
|
||||
# Avoid dl_iterate_phdr on Solaris 10, where it is in the
|
||||
# header file but is only in -ldl.
|
||||
have_dl_iterate_phdr=no ;;
|
||||
esac
|
||||
else
|
||||
AC_CHECK_FUNC([dl_iterate_phdr], [have_dl_iterate_phdr=yes],
|
||||
[have_dl_iterate_phdr=no])
|
||||
fi
|
||||
fi
|
||||
if test "$have_dl_iterate_phdr" = "yes"; then
|
||||
AC_DEFINE(HAVE_DL_ITERATE_PHDR, 1, [Define if dl_iterate_phdr is available.])
|
||||
fi
|
||||
|
||||
# Check for the fcntl function.
|
||||
if test -n "${with_target_subdir}"; then
|
||||
case "${host}" in
|
||||
*-*-mingw*) have_fcntl=no ;;
|
||||
spu-*-*) have_fcntl=no ;;
|
||||
*) have_fcntl=yes ;;
|
||||
esac
|
||||
else
|
||||
AC_CHECK_FUNC(fcntl, [have_fcntl=yes], [have_fcntl=no])
|
||||
fi
|
||||
if test "$have_fcntl" = "yes"; then
|
||||
AC_DEFINE([HAVE_FCNTL], 1,
|
||||
[Define to 1 if you have the fcntl function])
|
||||
fi
|
||||
|
||||
AC_CHECK_DECLS(strnlen)
|
||||
|
||||
# Check for getexecname function.
|
||||
if test -n "${with_target_subdir}"; then
|
||||
case "${host}" in
|
||||
*-*-solaris2*) have_getexecname=yes ;;
|
||||
*) have_getexecname=no ;;
|
||||
esac
|
||||
else
|
||||
AC_CHECK_FUNC(getexecname, [have_getexecname=yes], [have_getexecname=no])
|
||||
fi
|
||||
if test "$have_getexecname" = "yes"; then
|
||||
AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether tests can run],
|
||||
[libbacktrace_cv_sys_native],
|
||||
[AC_RUN_IFELSE([AC_LANG_PROGRAM([], [return 0;])],
|
||||
[libbacktrace_cv_sys_native=yes],
|
||||
[libbacktrace_cv_sys_native=no],
|
||||
[libbacktrace_cv_sys_native=no])])
|
||||
AM_CONDITIONAL(NATIVE, test "$libbacktrace_cv_sys_native" = "yes")
|
||||
|
||||
if test "${multilib}" = "yes"; then
|
||||
multilib_arg="--enable-multilib"
|
||||
else
|
||||
multilib_arg=
|
||||
fi
|
||||
|
||||
AC_CONFIG_FILES(Makefile backtrace-supported.h)
|
||||
|
||||
# We need multilib support, but only if configuring for the target.
|
||||
AC_CONFIG_COMMANDS([default],
|
||||
[if test -n "$CONFIG_FILES"; then
|
||||
if test -n "${with_target_subdir}"; then
|
||||
# Multilibs need MULTISUBDIR defined correctly in certain makefiles so
|
||||
# that multilib installs will end up installed in the correct place.
|
||||
# The testsuite needs it for multilib-aware ABI baseline files.
|
||||
# To work around this not being passed down from config-ml.in ->
|
||||
# srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually
|
||||
# append it here. Only modify Makefiles that have just been created.
|
||||
#
|
||||
# Also, get rid of this simulated-VPATH thing that automake does.
|
||||
cat > vpsed << \_EOF
|
||||
s!`test -f '$<' || echo '$(srcdir)/'`!!
|
||||
_EOF
|
||||
for i in $SUBDIRS; do
|
||||
case $CONFIG_FILES in
|
||||
*${i}/Makefile*)
|
||||
#echo "Adding MULTISUBDIR to $i/Makefile"
|
||||
sed -f vpsed $i/Makefile > tmp
|
||||
grep '^MULTISUBDIR =' Makefile >> tmp
|
||||
mv tmp $i/Makefile
|
||||
;;
|
||||
esac
|
||||
done
|
||||
rm vpsed
|
||||
fi
|
||||
fi
|
||||
],
|
||||
[
|
||||
# Variables needed in config.status (file generation) which aren't already
|
||||
# passed by autoconf.
|
||||
SUBDIRS="$SUBDIRS"
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,773 @@
|
|||
/* -*- c -*-
|
||||
Declarations and definitions of codes relating to the DWARF2 and
|
||||
DWARF3 symbolic debugging information formats.
|
||||
Copyright (C) 1992-2015 Free Software Foundation, Inc.
|
||||
|
||||
Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
|
||||
Office (AJPO), Florida State University and Silicon Graphics Inc.
|
||||
provided support for this effort -- June 21, 1995.
|
||||
|
||||
Derived from the DWARF 1 implementation written by Ron Guilmette
|
||||
(rfg@netcom.com), November 1990.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This file is derived from the DWARF specification (a public document)
|
||||
Revision 2.0.0 (July 27, 1993) developed by the UNIX International
|
||||
Programming Languages Special Interest Group (UI/PLSIG) and distributed
|
||||
by UNIX International. Copies of this specification are available from
|
||||
UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
|
||||
|
||||
This file also now contains definitions from the DWARF 3 specification
|
||||
published Dec 20, 2005, available from: http://dwarf.freestandards.org.
|
||||
|
||||
This file also now contains definitions from the DWARF 4
|
||||
specification, available from: http://dwarfstd.org/ */
|
||||
|
||||
/* This file declares various DWARF-related constants using a set of
|
||||
macros which can be redefined by the including file.
|
||||
|
||||
The macros are in sections. Each section corresponds to a single
|
||||
set of DWARF constants and has a corresponding key. The key is
|
||||
used in all the macro names.
|
||||
|
||||
The sections are TAG (for DW_TAG_ constants), FORM (DW_FORM_), AT
|
||||
(DW_AT_), OP (DW_OP_), ATE (DW_ATE_), and CFA (DW_CFA_).
|
||||
|
||||
Using TAG as an example, the following macros may be used for each
|
||||
key:
|
||||
|
||||
DW_FIRST_TAG(name, value) - Introduce the first DW_TAG constant.
|
||||
|
||||
DW_TAG(name, value) - Define a subsequent constant.
|
||||
|
||||
DW_TAG_DUP(name, value) - Define a subsequent constant whose value
|
||||
is a duplicate of some other constant. Not all keys use the _DUP
|
||||
macro form. If more than one name shares a value, then the base
|
||||
(DW_TAG) form will be the preferred name and DW_TAG_DUP will hold
|
||||
any alternate names.
|
||||
|
||||
DW_END_TAG - Invoked at the end of the DW_TAG constants. */
|
||||
|
||||
DW_FIRST_TAG (DW_TAG_padding, 0x00)
|
||||
DW_TAG (DW_TAG_array_type, 0x01)
|
||||
DW_TAG (DW_TAG_class_type, 0x02)
|
||||
DW_TAG (DW_TAG_entry_point, 0x03)
|
||||
DW_TAG (DW_TAG_enumeration_type, 0x04)
|
||||
DW_TAG (DW_TAG_formal_parameter, 0x05)
|
||||
DW_TAG (DW_TAG_imported_declaration, 0x08)
|
||||
DW_TAG (DW_TAG_label, 0x0a)
|
||||
DW_TAG (DW_TAG_lexical_block, 0x0b)
|
||||
DW_TAG (DW_TAG_member, 0x0d)
|
||||
DW_TAG (DW_TAG_pointer_type, 0x0f)
|
||||
DW_TAG (DW_TAG_reference_type, 0x10)
|
||||
DW_TAG (DW_TAG_compile_unit, 0x11)
|
||||
DW_TAG (DW_TAG_string_type, 0x12)
|
||||
DW_TAG (DW_TAG_structure_type, 0x13)
|
||||
DW_TAG (DW_TAG_subroutine_type, 0x15)
|
||||
DW_TAG (DW_TAG_typedef, 0x16)
|
||||
DW_TAG (DW_TAG_union_type, 0x17)
|
||||
DW_TAG (DW_TAG_unspecified_parameters, 0x18)
|
||||
DW_TAG (DW_TAG_variant, 0x19)
|
||||
DW_TAG (DW_TAG_common_block, 0x1a)
|
||||
DW_TAG (DW_TAG_common_inclusion, 0x1b)
|
||||
DW_TAG (DW_TAG_inheritance, 0x1c)
|
||||
DW_TAG (DW_TAG_inlined_subroutine, 0x1d)
|
||||
DW_TAG (DW_TAG_module, 0x1e)
|
||||
DW_TAG (DW_TAG_ptr_to_member_type, 0x1f)
|
||||
DW_TAG (DW_TAG_set_type, 0x20)
|
||||
DW_TAG (DW_TAG_subrange_type, 0x21)
|
||||
DW_TAG (DW_TAG_with_stmt, 0x22)
|
||||
DW_TAG (DW_TAG_access_declaration, 0x23)
|
||||
DW_TAG (DW_TAG_base_type, 0x24)
|
||||
DW_TAG (DW_TAG_catch_block, 0x25)
|
||||
DW_TAG (DW_TAG_const_type, 0x26)
|
||||
DW_TAG (DW_TAG_constant, 0x27)
|
||||
DW_TAG (DW_TAG_enumerator, 0x28)
|
||||
DW_TAG (DW_TAG_file_type, 0x29)
|
||||
DW_TAG (DW_TAG_friend, 0x2a)
|
||||
DW_TAG (DW_TAG_namelist, 0x2b)
|
||||
DW_TAG (DW_TAG_namelist_item, 0x2c)
|
||||
DW_TAG (DW_TAG_packed_type, 0x2d)
|
||||
DW_TAG (DW_TAG_subprogram, 0x2e)
|
||||
DW_TAG (DW_TAG_template_type_param, 0x2f)
|
||||
DW_TAG (DW_TAG_template_value_param, 0x30)
|
||||
DW_TAG (DW_TAG_thrown_type, 0x31)
|
||||
DW_TAG (DW_TAG_try_block, 0x32)
|
||||
DW_TAG (DW_TAG_variant_part, 0x33)
|
||||
DW_TAG (DW_TAG_variable, 0x34)
|
||||
DW_TAG (DW_TAG_volatile_type, 0x35)
|
||||
/* DWARF 3. */
|
||||
DW_TAG (DW_TAG_dwarf_procedure, 0x36)
|
||||
DW_TAG (DW_TAG_restrict_type, 0x37)
|
||||
DW_TAG (DW_TAG_interface_type, 0x38)
|
||||
DW_TAG (DW_TAG_namespace, 0x39)
|
||||
DW_TAG (DW_TAG_imported_module, 0x3a)
|
||||
DW_TAG (DW_TAG_unspecified_type, 0x3b)
|
||||
DW_TAG (DW_TAG_partial_unit, 0x3c)
|
||||
DW_TAG (DW_TAG_imported_unit, 0x3d)
|
||||
DW_TAG (DW_TAG_condition, 0x3f)
|
||||
DW_TAG (DW_TAG_shared_type, 0x40)
|
||||
/* DWARF 4. */
|
||||
DW_TAG (DW_TAG_type_unit, 0x41)
|
||||
DW_TAG (DW_TAG_rvalue_reference_type, 0x42)
|
||||
DW_TAG (DW_TAG_template_alias, 0x43)
|
||||
/* DWARF 5. */
|
||||
DW_TAG (DW_TAG_coarray_type, 0x44)
|
||||
DW_TAG (DW_TAG_generic_subrange, 0x45)
|
||||
DW_TAG (DW_TAG_dynamic_type, 0x46)
|
||||
DW_TAG (DW_TAG_atomic_type, 0x47)
|
||||
DW_TAG (DW_TAG_call_site, 0x48)
|
||||
DW_TAG (DW_TAG_call_site_parameter, 0x49)
|
||||
DW_TAG (DW_TAG_skeleton_unit, 0x4a)
|
||||
DW_TAG (DW_TAG_immutable_type, 0x4b)
|
||||
|
||||
DW_TAG_DUP (DW_TAG_lo_user, 0x4080)
|
||||
DW_TAG_DUP (DW_TAG_hi_user, 0xffff)
|
||||
|
||||
/* SGI/MIPS Extensions. */
|
||||
DW_TAG (DW_TAG_MIPS_loop, 0x4081)
|
||||
|
||||
/* HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz . */
|
||||
DW_TAG (DW_TAG_HP_array_descriptor, 0x4090)
|
||||
DW_TAG (DW_TAG_HP_Bliss_field, 0x4091)
|
||||
DW_TAG (DW_TAG_HP_Bliss_field_set, 0x4092)
|
||||
|
||||
/* GNU extensions. */
|
||||
DW_TAG (DW_TAG_format_label, 0x4101) /* For FORTRAN 77 and Fortran 90. */
|
||||
DW_TAG (DW_TAG_function_template, 0x4102) /* For C++. */
|
||||
DW_TAG (DW_TAG_class_template, 0x4103) /* For C++. */
|
||||
DW_TAG (DW_TAG_GNU_BINCL, 0x4104)
|
||||
DW_TAG (DW_TAG_GNU_EINCL, 0x4105)
|
||||
/* Template template parameter.
|
||||
See http://gcc.gnu.org/wiki/TemplateParmsDwarf . */
|
||||
DW_TAG (DW_TAG_GNU_template_template_param, 0x4106)
|
||||
|
||||
/* Template parameter pack extension, specified at
|
||||
http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_Variadic_templates
|
||||
The values of these two TAGS are in the DW_TAG_GNU_* space until the tags
|
||||
are properly part of DWARF 5. */
|
||||
DW_TAG (DW_TAG_GNU_template_parameter_pack, 0x4107)
|
||||
DW_TAG (DW_TAG_GNU_formal_parameter_pack, 0x4108)
|
||||
/* The GNU call site extension, specified at
|
||||
http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .
|
||||
The values of these two TAGS are in the DW_TAG_GNU_* space until the tags
|
||||
are properly part of DWARF 5. */
|
||||
DW_TAG (DW_TAG_GNU_call_site, 0x4109)
|
||||
DW_TAG (DW_TAG_GNU_call_site_parameter, 0x410a)
|
||||
/* Extensions for UPC. See: http://dwarfstd.org/doc/DWARF4.pdf. */
|
||||
DW_TAG (DW_TAG_upc_shared_type, 0x8765)
|
||||
DW_TAG (DW_TAG_upc_strict_type, 0x8766)
|
||||
DW_TAG (DW_TAG_upc_relaxed_type, 0x8767)
|
||||
/* PGI (STMicroelectronics) extensions. No documentation available. */
|
||||
DW_TAG (DW_TAG_PGI_kanji_type, 0xA000)
|
||||
DW_TAG (DW_TAG_PGI_interface_block, 0xA020)
|
||||
DW_END_TAG
|
||||
|
||||
DW_FIRST_FORM (DW_FORM_addr, 0x01)
|
||||
DW_FORM (DW_FORM_block2, 0x03)
|
||||
DW_FORM (DW_FORM_block4, 0x04)
|
||||
DW_FORM (DW_FORM_data2, 0x05)
|
||||
DW_FORM (DW_FORM_data4, 0x06)
|
||||
DW_FORM (DW_FORM_data8, 0x07)
|
||||
DW_FORM (DW_FORM_string, 0x08)
|
||||
DW_FORM (DW_FORM_block, 0x09)
|
||||
DW_FORM (DW_FORM_block1, 0x0a)
|
||||
DW_FORM (DW_FORM_data1, 0x0b)
|
||||
DW_FORM (DW_FORM_flag, 0x0c)
|
||||
DW_FORM (DW_FORM_sdata, 0x0d)
|
||||
DW_FORM (DW_FORM_strp, 0x0e)
|
||||
DW_FORM (DW_FORM_udata, 0x0f)
|
||||
DW_FORM (DW_FORM_ref_addr, 0x10)
|
||||
DW_FORM (DW_FORM_ref1, 0x11)
|
||||
DW_FORM (DW_FORM_ref2, 0x12)
|
||||
DW_FORM (DW_FORM_ref4, 0x13)
|
||||
DW_FORM (DW_FORM_ref8, 0x14)
|
||||
DW_FORM (DW_FORM_ref_udata, 0x15)
|
||||
DW_FORM (DW_FORM_indirect, 0x16)
|
||||
/* DWARF 4. */
|
||||
DW_FORM (DW_FORM_sec_offset, 0x17)
|
||||
DW_FORM (DW_FORM_exprloc, 0x18)
|
||||
DW_FORM (DW_FORM_flag_present, 0x19)
|
||||
DW_FORM (DW_FORM_ref_sig8, 0x20)
|
||||
/* DWARF 5. */
|
||||
DW_FORM (DW_FORM_strx, 0x1a)
|
||||
DW_FORM (DW_FORM_addrx, 0x1b)
|
||||
DW_FORM (DW_FORM_ref_sup, 0x1c)
|
||||
DW_FORM (DW_FORM_strp_sup, 0x1d)
|
||||
DW_FORM (DW_FORM_data16, 0x1e)
|
||||
DW_FORM (DW_FORM_line_strp, 0x1f)
|
||||
DW_FORM (DW_FORM_implicit_const, 0x21)
|
||||
DW_FORM (DW_FORM_loclistx, 0x22)
|
||||
DW_FORM (DW_FORM_rnglistx, 0x23)
|
||||
/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
|
||||
DW_FORM (DW_FORM_GNU_addr_index, 0x1f01)
|
||||
DW_FORM (DW_FORM_GNU_str_index, 0x1f02)
|
||||
/* Extensions for DWZ multifile.
|
||||
See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open . */
|
||||
DW_FORM (DW_FORM_GNU_ref_alt, 0x1f20)
|
||||
DW_FORM (DW_FORM_GNU_strp_alt, 0x1f21)
|
||||
DW_END_FORM
|
||||
|
||||
DW_FIRST_AT (DW_AT_sibling, 0x01)
|
||||
DW_AT (DW_AT_location, 0x02)
|
||||
DW_AT (DW_AT_name, 0x03)
|
||||
DW_AT (DW_AT_ordering, 0x09)
|
||||
DW_AT (DW_AT_subscr_data, 0x0a)
|
||||
DW_AT (DW_AT_byte_size, 0x0b)
|
||||
DW_AT (DW_AT_bit_offset, 0x0c)
|
||||
DW_AT (DW_AT_bit_size, 0x0d)
|
||||
DW_AT (DW_AT_element_list, 0x0f)
|
||||
DW_AT (DW_AT_stmt_list, 0x10)
|
||||
DW_AT (DW_AT_low_pc, 0x11)
|
||||
DW_AT (DW_AT_high_pc, 0x12)
|
||||
DW_AT (DW_AT_language, 0x13)
|
||||
DW_AT (DW_AT_member, 0x14)
|
||||
DW_AT (DW_AT_discr, 0x15)
|
||||
DW_AT (DW_AT_discr_value, 0x16)
|
||||
DW_AT (DW_AT_visibility, 0x17)
|
||||
DW_AT (DW_AT_import, 0x18)
|
||||
DW_AT (DW_AT_string_length, 0x19)
|
||||
DW_AT (DW_AT_common_reference, 0x1a)
|
||||
DW_AT (DW_AT_comp_dir, 0x1b)
|
||||
DW_AT (DW_AT_const_value, 0x1c)
|
||||
DW_AT (DW_AT_containing_type, 0x1d)
|
||||
DW_AT (DW_AT_default_value, 0x1e)
|
||||
DW_AT (DW_AT_inline, 0x20)
|
||||
DW_AT (DW_AT_is_optional, 0x21)
|
||||
DW_AT (DW_AT_lower_bound, 0x22)
|
||||
DW_AT (DW_AT_producer, 0x25)
|
||||
DW_AT (DW_AT_prototyped, 0x27)
|
||||
DW_AT (DW_AT_return_addr, 0x2a)
|
||||
DW_AT (DW_AT_start_scope, 0x2c)
|
||||
DW_AT (DW_AT_bit_stride, 0x2e)
|
||||
DW_AT (DW_AT_upper_bound, 0x2f)
|
||||
DW_AT (DW_AT_abstract_origin, 0x31)
|
||||
DW_AT (DW_AT_accessibility, 0x32)
|
||||
DW_AT (DW_AT_address_class, 0x33)
|
||||
DW_AT (DW_AT_artificial, 0x34)
|
||||
DW_AT (DW_AT_base_types, 0x35)
|
||||
DW_AT (DW_AT_calling_convention, 0x36)
|
||||
DW_AT (DW_AT_count, 0x37)
|
||||
DW_AT (DW_AT_data_member_location, 0x38)
|
||||
DW_AT (DW_AT_decl_column, 0x39)
|
||||
DW_AT (DW_AT_decl_file, 0x3a)
|
||||
DW_AT (DW_AT_decl_line, 0x3b)
|
||||
DW_AT (DW_AT_declaration, 0x3c)
|
||||
DW_AT (DW_AT_discr_list, 0x3d)
|
||||
DW_AT (DW_AT_encoding, 0x3e)
|
||||
DW_AT (DW_AT_external, 0x3f)
|
||||
DW_AT (DW_AT_frame_base, 0x40)
|
||||
DW_AT (DW_AT_friend, 0x41)
|
||||
DW_AT (DW_AT_identifier_case, 0x42)
|
||||
DW_AT (DW_AT_macro_info, 0x43)
|
||||
DW_AT (DW_AT_namelist_items, 0x44)
|
||||
DW_AT (DW_AT_priority, 0x45)
|
||||
DW_AT (DW_AT_segment, 0x46)
|
||||
DW_AT (DW_AT_specification, 0x47)
|
||||
DW_AT (DW_AT_static_link, 0x48)
|
||||
DW_AT (DW_AT_type, 0x49)
|
||||
DW_AT (DW_AT_use_location, 0x4a)
|
||||
DW_AT (DW_AT_variable_parameter, 0x4b)
|
||||
DW_AT (DW_AT_virtuality, 0x4c)
|
||||
DW_AT (DW_AT_vtable_elem_location, 0x4d)
|
||||
/* DWARF 3 values. */
|
||||
DW_AT (DW_AT_allocated, 0x4e)
|
||||
DW_AT (DW_AT_associated, 0x4f)
|
||||
DW_AT (DW_AT_data_location, 0x50)
|
||||
DW_AT (DW_AT_byte_stride, 0x51)
|
||||
DW_AT (DW_AT_entry_pc, 0x52)
|
||||
DW_AT (DW_AT_use_UTF8, 0x53)
|
||||
DW_AT (DW_AT_extension, 0x54)
|
||||
DW_AT (DW_AT_ranges, 0x55)
|
||||
DW_AT (DW_AT_trampoline, 0x56)
|
||||
DW_AT (DW_AT_call_column, 0x57)
|
||||
DW_AT (DW_AT_call_file, 0x58)
|
||||
DW_AT (DW_AT_call_line, 0x59)
|
||||
DW_AT (DW_AT_description, 0x5a)
|
||||
DW_AT (DW_AT_binary_scale, 0x5b)
|
||||
DW_AT (DW_AT_decimal_scale, 0x5c)
|
||||
DW_AT (DW_AT_small, 0x5d)
|
||||
DW_AT (DW_AT_decimal_sign, 0x5e)
|
||||
DW_AT (DW_AT_digit_count, 0x5f)
|
||||
DW_AT (DW_AT_picture_string, 0x60)
|
||||
DW_AT (DW_AT_mutable, 0x61)
|
||||
DW_AT (DW_AT_threads_scaled, 0x62)
|
||||
DW_AT (DW_AT_explicit, 0x63)
|
||||
DW_AT (DW_AT_object_pointer, 0x64)
|
||||
DW_AT (DW_AT_endianity, 0x65)
|
||||
DW_AT (DW_AT_elemental, 0x66)
|
||||
DW_AT (DW_AT_pure, 0x67)
|
||||
DW_AT (DW_AT_recursive, 0x68)
|
||||
/* DWARF 4. */
|
||||
DW_AT (DW_AT_signature, 0x69)
|
||||
DW_AT (DW_AT_main_subprogram, 0x6a)
|
||||
DW_AT (DW_AT_data_bit_offset, 0x6b)
|
||||
DW_AT (DW_AT_const_expr, 0x6c)
|
||||
DW_AT (DW_AT_enum_class, 0x6d)
|
||||
DW_AT (DW_AT_linkage_name, 0x6e)
|
||||
/* DWARF 5. */
|
||||
DW_AT (DW_AT_string_length_bit_size, 0x6f)
|
||||
DW_AT (DW_AT_string_length_byte_size, 0x70)
|
||||
DW_AT (DW_AT_rank, 0x71)
|
||||
DW_AT (DW_AT_str_offsets_base, 0x72)
|
||||
DW_AT (DW_AT_addr_base, 0x73)
|
||||
DW_AT (DW_AT_rnglists_base, 0x74)
|
||||
DW_AT (DW_AT_dwo_name, 0x76)
|
||||
DW_AT (DW_AT_reference, 0x77)
|
||||
DW_AT (DW_AT_rvalue_reference, 0x78)
|
||||
DW_AT (DW_AT_macros, 0x79)
|
||||
DW_AT (DW_AT_call_all_calls, 0x7a)
|
||||
DW_AT (DW_AT_call_all_source_calls, 0x7b)
|
||||
DW_AT (DW_AT_call_all_tail_calls, 0x7c)
|
||||
DW_AT (DW_AT_call_return_pc, 0x7d)
|
||||
DW_AT (DW_AT_call_value, 0x7e)
|
||||
DW_AT (DW_AT_call_origin, 0x7f)
|
||||
DW_AT (DW_AT_call_parameter, 0x80)
|
||||
DW_AT (DW_AT_call_pc, 0x81)
|
||||
DW_AT (DW_AT_call_tail_call, 0x82)
|
||||
DW_AT (DW_AT_call_target, 0x83)
|
||||
DW_AT (DW_AT_call_target_clobbered, 0x84)
|
||||
DW_AT (DW_AT_call_data_location, 0x85)
|
||||
DW_AT (DW_AT_call_data_value, 0x86)
|
||||
DW_AT (DW_AT_noreturn, 0x87)
|
||||
DW_AT (DW_AT_alignment, 0x88)
|
||||
DW_AT (DW_AT_export_symbols, 0x89)
|
||||
DW_AT (DW_AT_deleted, 0x8a)
|
||||
DW_AT (DW_AT_defaulted, 0x8b)
|
||||
DW_AT (DW_AT_loclists_base, 0x8c)
|
||||
|
||||
DW_AT_DUP (DW_AT_lo_user, 0x2000) /* Implementation-defined range start. */
|
||||
DW_AT_DUP (DW_AT_hi_user, 0x3fff) /* Implementation-defined range end. */
|
||||
|
||||
/* SGI/MIPS extensions. */
|
||||
DW_AT (DW_AT_MIPS_fde, 0x2001)
|
||||
DW_AT (DW_AT_MIPS_loop_begin, 0x2002)
|
||||
DW_AT (DW_AT_MIPS_tail_loop_begin, 0x2003)
|
||||
DW_AT (DW_AT_MIPS_epilog_begin, 0x2004)
|
||||
DW_AT (DW_AT_MIPS_loop_unroll_factor, 0x2005)
|
||||
DW_AT (DW_AT_MIPS_software_pipeline_depth, 0x2006)
|
||||
DW_AT (DW_AT_MIPS_linkage_name, 0x2007)
|
||||
DW_AT (DW_AT_MIPS_stride, 0x2008)
|
||||
DW_AT (DW_AT_MIPS_abstract_name, 0x2009)
|
||||
DW_AT (DW_AT_MIPS_clone_origin, 0x200a)
|
||||
DW_AT (DW_AT_MIPS_has_inlines, 0x200b)
|
||||
/* HP extensions. */
|
||||
DW_AT (DW_AT_HP_block_index, 0x2000)
|
||||
DW_AT_DUP (DW_AT_HP_unmodifiable, 0x2001) /* Same as DW_AT_MIPS_fde. */
|
||||
DW_AT_DUP (DW_AT_HP_prologue, 0x2005) /* Same as DW_AT_MIPS_loop_unroll. */
|
||||
DW_AT_DUP (DW_AT_HP_epilogue, 0x2008) /* Same as DW_AT_MIPS_stride. */
|
||||
DW_AT (DW_AT_HP_actuals_stmt_list, 0x2010)
|
||||
DW_AT (DW_AT_HP_proc_per_section, 0x2011)
|
||||
DW_AT (DW_AT_HP_raw_data_ptr, 0x2012)
|
||||
DW_AT (DW_AT_HP_pass_by_reference, 0x2013)
|
||||
DW_AT (DW_AT_HP_opt_level, 0x2014)
|
||||
DW_AT (DW_AT_HP_prof_version_id, 0x2015)
|
||||
DW_AT (DW_AT_HP_opt_flags, 0x2016)
|
||||
DW_AT (DW_AT_HP_cold_region_low_pc, 0x2017)
|
||||
DW_AT (DW_AT_HP_cold_region_high_pc, 0x2018)
|
||||
DW_AT (DW_AT_HP_all_variables_modifiable, 0x2019)
|
||||
DW_AT (DW_AT_HP_linkage_name, 0x201a)
|
||||
DW_AT (DW_AT_HP_prof_flags, 0x201b) /* In comp unit of procs_info for -g. */
|
||||
DW_AT (DW_AT_HP_unit_name, 0x201f)
|
||||
DW_AT (DW_AT_HP_unit_size, 0x2020)
|
||||
DW_AT (DW_AT_HP_widened_byte_size, 0x2021)
|
||||
DW_AT (DW_AT_HP_definition_points, 0x2022)
|
||||
DW_AT (DW_AT_HP_default_location, 0x2023)
|
||||
DW_AT (DW_AT_HP_is_result_param, 0x2029)
|
||||
|
||||
/* GNU extensions. */
|
||||
DW_AT (DW_AT_sf_names, 0x2101)
|
||||
DW_AT (DW_AT_src_info, 0x2102)
|
||||
DW_AT (DW_AT_mac_info, 0x2103)
|
||||
DW_AT (DW_AT_src_coords, 0x2104)
|
||||
DW_AT (DW_AT_body_begin, 0x2105)
|
||||
DW_AT (DW_AT_body_end, 0x2106)
|
||||
DW_AT (DW_AT_GNU_vector, 0x2107)
|
||||
/* Thread-safety annotations.
|
||||
See http://gcc.gnu.org/wiki/ThreadSafetyAnnotation . */
|
||||
DW_AT (DW_AT_GNU_guarded_by, 0x2108)
|
||||
DW_AT (DW_AT_GNU_pt_guarded_by, 0x2109)
|
||||
DW_AT (DW_AT_GNU_guarded, 0x210a)
|
||||
DW_AT (DW_AT_GNU_pt_guarded, 0x210b)
|
||||
DW_AT (DW_AT_GNU_locks_excluded, 0x210c)
|
||||
DW_AT (DW_AT_GNU_exclusive_locks_required, 0x210d)
|
||||
DW_AT (DW_AT_GNU_shared_locks_required, 0x210e)
|
||||
/* One-definition rule violation detection.
|
||||
See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo . */
|
||||
DW_AT (DW_AT_GNU_odr_signature, 0x210f)
|
||||
/* Template template argument name.
|
||||
See http://gcc.gnu.org/wiki/TemplateParmsDwarf . */
|
||||
DW_AT (DW_AT_GNU_template_name, 0x2110)
|
||||
/* The GNU call site extension.
|
||||
See http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open . */
|
||||
DW_AT (DW_AT_GNU_call_site_value, 0x2111)
|
||||
DW_AT (DW_AT_GNU_call_site_data_value, 0x2112)
|
||||
DW_AT (DW_AT_GNU_call_site_target, 0x2113)
|
||||
DW_AT (DW_AT_GNU_call_site_target_clobbered, 0x2114)
|
||||
DW_AT (DW_AT_GNU_tail_call, 0x2115)
|
||||
DW_AT (DW_AT_GNU_all_tail_call_sites, 0x2116)
|
||||
DW_AT (DW_AT_GNU_all_call_sites, 0x2117)
|
||||
DW_AT (DW_AT_GNU_all_source_call_sites, 0x2118)
|
||||
/* Section offset into .debug_macro section. */
|
||||
DW_AT (DW_AT_GNU_macros, 0x2119)
|
||||
/* Attribute for C++ deleted special member functions (= delete;). */
|
||||
DW_AT (DW_AT_GNU_deleted, 0x211a)
|
||||
/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
|
||||
DW_AT (DW_AT_GNU_dwo_name, 0x2130)
|
||||
DW_AT (DW_AT_GNU_dwo_id, 0x2131)
|
||||
DW_AT (DW_AT_GNU_ranges_base, 0x2132)
|
||||
DW_AT (DW_AT_GNU_addr_base, 0x2133)
|
||||
DW_AT (DW_AT_GNU_pubnames, 0x2134)
|
||||
DW_AT (DW_AT_GNU_pubtypes, 0x2135)
|
||||
/* Attribute for discriminator.
|
||||
See http://gcc.gnu.org/wiki/Discriminator */
|
||||
DW_AT (DW_AT_GNU_discriminator, 0x2136)
|
||||
/* VMS extensions. */
|
||||
DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
|
||||
/* GNAT extensions. */
|
||||
/* GNAT descriptive type.
|
||||
See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type . */
|
||||
DW_AT (DW_AT_use_GNAT_descriptive_type, 0x2301)
|
||||
DW_AT (DW_AT_GNAT_descriptive_type, 0x2302)
|
||||
/* Rational constant extension.
|
||||
See https://gcc.gnu.org/wiki/DW_AT_GNU_numerator_denominator . */
|
||||
DW_TAG (DW_AT_GNU_numerator, 0x2303)
|
||||
DW_TAG (DW_AT_GNU_denominator, 0x2304)
|
||||
/* Biased integer extension.
|
||||
See https://gcc.gnu.org/wiki/DW_AT_GNU_bias . */
|
||||
DW_TAG (DW_AT_GNU_bias, 0x2305)
|
||||
/* UPC extension. */
|
||||
DW_AT (DW_AT_upc_threads_scaled, 0x3210)
|
||||
/* PGI (STMicroelectronics) extensions. */
|
||||
DW_AT (DW_AT_PGI_lbase, 0x3a00)
|
||||
DW_AT (DW_AT_PGI_soffset, 0x3a01)
|
||||
DW_AT (DW_AT_PGI_lstride, 0x3a02)
|
||||
/* Apple extensions. */
|
||||
DW_AT (DW_AT_APPLE_optimized, 0x3fe1)
|
||||
DW_AT (DW_AT_APPLE_flags, 0x3fe2)
|
||||
DW_AT (DW_AT_APPLE_isa, 0x3fe3)
|
||||
DW_AT (DW_AT_APPLE_block, 0x3fe4)
|
||||
DW_AT (DW_AT_APPLE_major_runtime_vers, 0x3fe5)
|
||||
DW_AT (DW_AT_APPLE_runtime_class, 0x3fe6)
|
||||
DW_AT (DW_AT_APPLE_omit_frame_ptr, 0x3fe7)
|
||||
DW_AT (DW_AT_APPLE_property_name, 0x3fe8)
|
||||
DW_AT (DW_AT_APPLE_property_getter, 0x3fe9)
|
||||
DW_AT (DW_AT_APPLE_property_setter, 0x3fea)
|
||||
DW_AT (DW_AT_APPLE_property_attribute, 0x3feb)
|
||||
DW_AT (DW_AT_APPLE_objc_complete_type, 0x3fec)
|
||||
DW_AT (DW_AT_APPLE_property, 0x3fed)
|
||||
DW_END_AT
|
||||
|
||||
DW_FIRST_OP (DW_OP_addr, 0x03)
|
||||
DW_OP (DW_OP_deref, 0x06)
|
||||
DW_OP (DW_OP_const1u, 0x08)
|
||||
DW_OP (DW_OP_const1s, 0x09)
|
||||
DW_OP (DW_OP_const2u, 0x0a)
|
||||
DW_OP (DW_OP_const2s, 0x0b)
|
||||
DW_OP (DW_OP_const4u, 0x0c)
|
||||
DW_OP (DW_OP_const4s, 0x0d)
|
||||
DW_OP (DW_OP_const8u, 0x0e)
|
||||
DW_OP (DW_OP_const8s, 0x0f)
|
||||
DW_OP (DW_OP_constu, 0x10)
|
||||
DW_OP (DW_OP_consts, 0x11)
|
||||
DW_OP (DW_OP_dup, 0x12)
|
||||
DW_OP (DW_OP_drop, 0x13)
|
||||
DW_OP (DW_OP_over, 0x14)
|
||||
DW_OP (DW_OP_pick, 0x15)
|
||||
DW_OP (DW_OP_swap, 0x16)
|
||||
DW_OP (DW_OP_rot, 0x17)
|
||||
DW_OP (DW_OP_xderef, 0x18)
|
||||
DW_OP (DW_OP_abs, 0x19)
|
||||
DW_OP (DW_OP_and, 0x1a)
|
||||
DW_OP (DW_OP_div, 0x1b)
|
||||
DW_OP (DW_OP_minus, 0x1c)
|
||||
DW_OP (DW_OP_mod, 0x1d)
|
||||
DW_OP (DW_OP_mul, 0x1e)
|
||||
DW_OP (DW_OP_neg, 0x1f)
|
||||
DW_OP (DW_OP_not, 0x20)
|
||||
DW_OP (DW_OP_or, 0x21)
|
||||
DW_OP (DW_OP_plus, 0x22)
|
||||
DW_OP (DW_OP_plus_uconst, 0x23)
|
||||
DW_OP (DW_OP_shl, 0x24)
|
||||
DW_OP (DW_OP_shr, 0x25)
|
||||
DW_OP (DW_OP_shra, 0x26)
|
||||
DW_OP (DW_OP_xor, 0x27)
|
||||
DW_OP (DW_OP_bra, 0x28)
|
||||
DW_OP (DW_OP_eq, 0x29)
|
||||
DW_OP (DW_OP_ge, 0x2a)
|
||||
DW_OP (DW_OP_gt, 0x2b)
|
||||
DW_OP (DW_OP_le, 0x2c)
|
||||
DW_OP (DW_OP_lt, 0x2d)
|
||||
DW_OP (DW_OP_ne, 0x2e)
|
||||
DW_OP (DW_OP_skip, 0x2f)
|
||||
DW_OP (DW_OP_lit0, 0x30)
|
||||
DW_OP (DW_OP_lit1, 0x31)
|
||||
DW_OP (DW_OP_lit2, 0x32)
|
||||
DW_OP (DW_OP_lit3, 0x33)
|
||||
DW_OP (DW_OP_lit4, 0x34)
|
||||
DW_OP (DW_OP_lit5, 0x35)
|
||||
DW_OP (DW_OP_lit6, 0x36)
|
||||
DW_OP (DW_OP_lit7, 0x37)
|
||||
DW_OP (DW_OP_lit8, 0x38)
|
||||
DW_OP (DW_OP_lit9, 0x39)
|
||||
DW_OP (DW_OP_lit10, 0x3a)
|
||||
DW_OP (DW_OP_lit11, 0x3b)
|
||||
DW_OP (DW_OP_lit12, 0x3c)
|
||||
DW_OP (DW_OP_lit13, 0x3d)
|
||||
DW_OP (DW_OP_lit14, 0x3e)
|
||||
DW_OP (DW_OP_lit15, 0x3f)
|
||||
DW_OP (DW_OP_lit16, 0x40)
|
||||
DW_OP (DW_OP_lit17, 0x41)
|
||||
DW_OP (DW_OP_lit18, 0x42)
|
||||
DW_OP (DW_OP_lit19, 0x43)
|
||||
DW_OP (DW_OP_lit20, 0x44)
|
||||
DW_OP (DW_OP_lit21, 0x45)
|
||||
DW_OP (DW_OP_lit22, 0x46)
|
||||
DW_OP (DW_OP_lit23, 0x47)
|
||||
DW_OP (DW_OP_lit24, 0x48)
|
||||
DW_OP (DW_OP_lit25, 0x49)
|
||||
DW_OP (DW_OP_lit26, 0x4a)
|
||||
DW_OP (DW_OP_lit27, 0x4b)
|
||||
DW_OP (DW_OP_lit28, 0x4c)
|
||||
DW_OP (DW_OP_lit29, 0x4d)
|
||||
DW_OP (DW_OP_lit30, 0x4e)
|
||||
DW_OP (DW_OP_lit31, 0x4f)
|
||||
DW_OP (DW_OP_reg0, 0x50)
|
||||
DW_OP (DW_OP_reg1, 0x51)
|
||||
DW_OP (DW_OP_reg2, 0x52)
|
||||
DW_OP (DW_OP_reg3, 0x53)
|
||||
DW_OP (DW_OP_reg4, 0x54)
|
||||
DW_OP (DW_OP_reg5, 0x55)
|
||||
DW_OP (DW_OP_reg6, 0x56)
|
||||
DW_OP (DW_OP_reg7, 0x57)
|
||||
DW_OP (DW_OP_reg8, 0x58)
|
||||
DW_OP (DW_OP_reg9, 0x59)
|
||||
DW_OP (DW_OP_reg10, 0x5a)
|
||||
DW_OP (DW_OP_reg11, 0x5b)
|
||||
DW_OP (DW_OP_reg12, 0x5c)
|
||||
DW_OP (DW_OP_reg13, 0x5d)
|
||||
DW_OP (DW_OP_reg14, 0x5e)
|
||||
DW_OP (DW_OP_reg15, 0x5f)
|
||||
DW_OP (DW_OP_reg16, 0x60)
|
||||
DW_OP (DW_OP_reg17, 0x61)
|
||||
DW_OP (DW_OP_reg18, 0x62)
|
||||
DW_OP (DW_OP_reg19, 0x63)
|
||||
DW_OP (DW_OP_reg20, 0x64)
|
||||
DW_OP (DW_OP_reg21, 0x65)
|
||||
DW_OP (DW_OP_reg22, 0x66)
|
||||
DW_OP (DW_OP_reg23, 0x67)
|
||||
DW_OP (DW_OP_reg24, 0x68)
|
||||
DW_OP (DW_OP_reg25, 0x69)
|
||||
DW_OP (DW_OP_reg26, 0x6a)
|
||||
DW_OP (DW_OP_reg27, 0x6b)
|
||||
DW_OP (DW_OP_reg28, 0x6c)
|
||||
DW_OP (DW_OP_reg29, 0x6d)
|
||||
DW_OP (DW_OP_reg30, 0x6e)
|
||||
DW_OP (DW_OP_reg31, 0x6f)
|
||||
DW_OP (DW_OP_breg0, 0x70)
|
||||
DW_OP (DW_OP_breg1, 0x71)
|
||||
DW_OP (DW_OP_breg2, 0x72)
|
||||
DW_OP (DW_OP_breg3, 0x73)
|
||||
DW_OP (DW_OP_breg4, 0x74)
|
||||
DW_OP (DW_OP_breg5, 0x75)
|
||||
DW_OP (DW_OP_breg6, 0x76)
|
||||
DW_OP (DW_OP_breg7, 0x77)
|
||||
DW_OP (DW_OP_breg8, 0x78)
|
||||
DW_OP (DW_OP_breg9, 0x79)
|
||||
DW_OP (DW_OP_breg10, 0x7a)
|
||||
DW_OP (DW_OP_breg11, 0x7b)
|
||||
DW_OP (DW_OP_breg12, 0x7c)
|
||||
DW_OP (DW_OP_breg13, 0x7d)
|
||||
DW_OP (DW_OP_breg14, 0x7e)
|
||||
DW_OP (DW_OP_breg15, 0x7f)
|
||||
DW_OP (DW_OP_breg16, 0x80)
|
||||
DW_OP (DW_OP_breg17, 0x81)
|
||||
DW_OP (DW_OP_breg18, 0x82)
|
||||
DW_OP (DW_OP_breg19, 0x83)
|
||||
DW_OP (DW_OP_breg20, 0x84)
|
||||
DW_OP (DW_OP_breg21, 0x85)
|
||||
DW_OP (DW_OP_breg22, 0x86)
|
||||
DW_OP (DW_OP_breg23, 0x87)
|
||||
DW_OP (DW_OP_breg24, 0x88)
|
||||
DW_OP (DW_OP_breg25, 0x89)
|
||||
DW_OP (DW_OP_breg26, 0x8a)
|
||||
DW_OP (DW_OP_breg27, 0x8b)
|
||||
DW_OP (DW_OP_breg28, 0x8c)
|
||||
DW_OP (DW_OP_breg29, 0x8d)
|
||||
DW_OP (DW_OP_breg30, 0x8e)
|
||||
DW_OP (DW_OP_breg31, 0x8f)
|
||||
DW_OP (DW_OP_regx, 0x90)
|
||||
DW_OP (DW_OP_fbreg, 0x91)
|
||||
DW_OP (DW_OP_bregx, 0x92)
|
||||
DW_OP (DW_OP_piece, 0x93)
|
||||
DW_OP (DW_OP_deref_size, 0x94)
|
||||
DW_OP (DW_OP_xderef_size, 0x95)
|
||||
DW_OP (DW_OP_nop, 0x96)
|
||||
/* DWARF 3 extensions. */
|
||||
DW_OP (DW_OP_push_object_address, 0x97)
|
||||
DW_OP (DW_OP_call2, 0x98)
|
||||
DW_OP (DW_OP_call4, 0x99)
|
||||
DW_OP (DW_OP_call_ref, 0x9a)
|
||||
DW_OP (DW_OP_form_tls_address, 0x9b)
|
||||
DW_OP (DW_OP_call_frame_cfa, 0x9c)
|
||||
DW_OP (DW_OP_bit_piece, 0x9d)
|
||||
|
||||
/* DWARF 4 extensions. */
|
||||
DW_OP (DW_OP_implicit_value, 0x9e)
|
||||
DW_OP (DW_OP_stack_value, 0x9f)
|
||||
|
||||
/* DWARF 5 extensions. */
|
||||
DW_OP (DW_OP_implicit_pointer, 0xa0)
|
||||
DW_OP (DW_OP_addrx, 0xa1)
|
||||
DW_OP (DW_OP_constx, 0xa2)
|
||||
DW_OP (DW_OP_entry_value, 0xa3)
|
||||
DW_OP (DW_OP_const_type, 0xa4)
|
||||
DW_OP (DW_OP_regval_type, 0xa5)
|
||||
DW_OP (DW_OP_deref_type, 0xa6)
|
||||
DW_OP (DW_OP_xderef_type, 0xa7)
|
||||
DW_OP (DW_OP_convert, 0xa8)
|
||||
DW_OP (DW_OP_reinterpret, 0xa9)
|
||||
|
||||
DW_OP_DUP (DW_OP_lo_user, 0xe0) /* Implementation-defined range start. */
|
||||
DW_OP_DUP (DW_OP_hi_user, 0xff) /* Implementation-defined range end. */
|
||||
|
||||
/* GNU extensions. */
|
||||
DW_OP (DW_OP_GNU_push_tls_address, 0xe0)
|
||||
/* The following is for marking variables that are uninitialized. */
|
||||
DW_OP (DW_OP_GNU_uninit, 0xf0)
|
||||
DW_OP (DW_OP_GNU_encoded_addr, 0xf1)
|
||||
/* The GNU implicit pointer extension.
|
||||
See http://www.dwarfstd.org/ShowIssue.php?issue=100831.1&type=open . */
|
||||
DW_OP (DW_OP_GNU_implicit_pointer, 0xf2)
|
||||
/* The GNU entry value extension.
|
||||
See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open . */
|
||||
DW_OP (DW_OP_GNU_entry_value, 0xf3)
|
||||
/* The GNU typed stack extension.
|
||||
See http://www.dwarfstd.org/doc/040408.1.html . */
|
||||
DW_OP (DW_OP_GNU_const_type, 0xf4)
|
||||
DW_OP (DW_OP_GNU_regval_type, 0xf5)
|
||||
DW_OP (DW_OP_GNU_deref_type, 0xf6)
|
||||
DW_OP (DW_OP_GNU_convert, 0xf7)
|
||||
DW_OP (DW_OP_GNU_reinterpret, 0xf9)
|
||||
/* The GNU parameter ref extension. */
|
||||
DW_OP (DW_OP_GNU_parameter_ref, 0xfa)
|
||||
/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
|
||||
DW_OP (DW_OP_GNU_addr_index, 0xfb)
|
||||
DW_OP (DW_OP_GNU_const_index, 0xfc)
|
||||
/* HP extensions. */
|
||||
DW_OP_DUP (DW_OP_HP_unknown, 0xe0) /* Ouch, the same as GNU_push_tls_address. */
|
||||
DW_OP (DW_OP_HP_is_value, 0xe1)
|
||||
DW_OP (DW_OP_HP_fltconst4, 0xe2)
|
||||
DW_OP (DW_OP_HP_fltconst8, 0xe3)
|
||||
DW_OP (DW_OP_HP_mod_range, 0xe4)
|
||||
DW_OP (DW_OP_HP_unmod_range, 0xe5)
|
||||
DW_OP (DW_OP_HP_tls, 0xe6)
|
||||
/* PGI (STMicroelectronics) extensions. */
|
||||
DW_OP (DW_OP_PGI_omp_thread_num, 0xf8)
|
||||
DW_END_OP
|
||||
|
||||
DW_FIRST_ATE (DW_ATE_void, 0x0)
|
||||
DW_ATE (DW_ATE_address, 0x1)
|
||||
DW_ATE (DW_ATE_boolean, 0x2)
|
||||
DW_ATE (DW_ATE_complex_float, 0x3)
|
||||
DW_ATE (DW_ATE_float, 0x4)
|
||||
DW_ATE (DW_ATE_signed, 0x5)
|
||||
DW_ATE (DW_ATE_signed_char, 0x6)
|
||||
DW_ATE (DW_ATE_unsigned, 0x7)
|
||||
DW_ATE (DW_ATE_unsigned_char, 0x8)
|
||||
/* DWARF 3. */
|
||||
DW_ATE (DW_ATE_imaginary_float, 0x9)
|
||||
DW_ATE (DW_ATE_packed_decimal, 0xa)
|
||||
DW_ATE (DW_ATE_numeric_string, 0xb)
|
||||
DW_ATE (DW_ATE_edited, 0xc)
|
||||
DW_ATE (DW_ATE_signed_fixed, 0xd)
|
||||
DW_ATE (DW_ATE_unsigned_fixed, 0xe)
|
||||
DW_ATE (DW_ATE_decimal_float, 0xf)
|
||||
/* DWARF 4. */
|
||||
DW_ATE (DW_ATE_UTF, 0x10)
|
||||
/* DWARF 5. */
|
||||
DW_ATE (DW_ATE_UCS, 0x11)
|
||||
DW_ATE (DW_ATE_ASCII, 0x12)
|
||||
|
||||
DW_ATE_DUP (DW_ATE_lo_user, 0x80)
|
||||
DW_ATE_DUP (DW_ATE_hi_user, 0xff)
|
||||
|
||||
/* HP extensions. */
|
||||
DW_ATE (DW_ATE_HP_float80, 0x80) /* Floating-point (80 bit). */
|
||||
DW_ATE (DW_ATE_HP_complex_float80, 0x81) /* Complex floating-point (80 bit). */
|
||||
DW_ATE (DW_ATE_HP_float128, 0x82) /* Floating-point (128 bit). */
|
||||
DW_ATE (DW_ATE_HP_complex_float128, 0x83) /* Complex fp (128 bit). */
|
||||
DW_ATE (DW_ATE_HP_floathpintel, 0x84) /* Floating-point (82 bit IA64). */
|
||||
DW_ATE (DW_ATE_HP_imaginary_float80, 0x85)
|
||||
DW_ATE (DW_ATE_HP_imaginary_float128, 0x86)
|
||||
DW_ATE (DW_ATE_HP_VAX_float, 0x88) /* F or G floating. */
|
||||
DW_ATE (DW_ATE_HP_VAX_float_d, 0x89) /* D floating. */
|
||||
DW_ATE (DW_ATE_HP_packed_decimal, 0x8a) /* Cobol. */
|
||||
DW_ATE (DW_ATE_HP_zoned_decimal, 0x8b) /* Cobol. */
|
||||
DW_ATE (DW_ATE_HP_edited, 0x8c) /* Cobol. */
|
||||
DW_ATE (DW_ATE_HP_signed_fixed, 0x8d) /* Cobol. */
|
||||
DW_ATE (DW_ATE_HP_unsigned_fixed, 0x8e) /* Cobol. */
|
||||
DW_ATE (DW_ATE_HP_VAX_complex_float, 0x8f) /* F or G floating complex. */
|
||||
DW_ATE (DW_ATE_HP_VAX_complex_float_d, 0x90) /* D floating complex. */
|
||||
|
||||
DW_END_ATE
|
||||
|
||||
DW_FIRST_CFA (DW_CFA_advance_loc, 0x40)
|
||||
DW_CFA (DW_CFA_offset, 0x80)
|
||||
DW_CFA (DW_CFA_restore, 0xc0)
|
||||
DW_CFA (DW_CFA_nop, 0x00)
|
||||
DW_CFA (DW_CFA_set_loc, 0x01)
|
||||
DW_CFA (DW_CFA_advance_loc1, 0x02)
|
||||
DW_CFA (DW_CFA_advance_loc2, 0x03)
|
||||
DW_CFA (DW_CFA_advance_loc4, 0x04)
|
||||
DW_CFA (DW_CFA_offset_extended, 0x05)
|
||||
DW_CFA (DW_CFA_restore_extended, 0x06)
|
||||
DW_CFA (DW_CFA_undefined, 0x07)
|
||||
DW_CFA (DW_CFA_same_value, 0x08)
|
||||
DW_CFA (DW_CFA_register, 0x09)
|
||||
DW_CFA (DW_CFA_remember_state, 0x0a)
|
||||
DW_CFA (DW_CFA_restore_state, 0x0b)
|
||||
DW_CFA (DW_CFA_def_cfa, 0x0c)
|
||||
DW_CFA (DW_CFA_def_cfa_register, 0x0d)
|
||||
DW_CFA (DW_CFA_def_cfa_offset, 0x0e)
|
||||
/* DWARF 3. */
|
||||
DW_CFA (DW_CFA_def_cfa_expression, 0x0f)
|
||||
DW_CFA (DW_CFA_expression, 0x10)
|
||||
DW_CFA (DW_CFA_offset_extended_sf, 0x11)
|
||||
DW_CFA (DW_CFA_def_cfa_sf, 0x12)
|
||||
DW_CFA (DW_CFA_def_cfa_offset_sf, 0x13)
|
||||
DW_CFA (DW_CFA_val_offset, 0x14)
|
||||
DW_CFA (DW_CFA_val_offset_sf, 0x15)
|
||||
DW_CFA (DW_CFA_val_expression, 0x16)
|
||||
|
||||
DW_CFA (DW_CFA_lo_user, 0x1c)
|
||||
DW_CFA (DW_CFA_hi_user, 0x3f)
|
||||
|
||||
/* SGI/MIPS specific. */
|
||||
DW_CFA (DW_CFA_MIPS_advance_loc8, 0x1d)
|
||||
/* GNU extensions. */
|
||||
DW_CFA (DW_CFA_GNU_window_save, 0x2d)
|
||||
DW_CFA (DW_CFA_GNU_args_size, 0x2e)
|
||||
DW_CFA (DW_CFA_GNU_negative_offset_extended, 0x2f)
|
||||
|
||||
DW_END_CFA
|
|
@ -0,0 +1,531 @@
|
|||
/* Declarations and definitions of codes relating to the DWARF2 and
|
||||
DWARF3 symbolic debugging information formats.
|
||||
Copyright (C) 1992-2016 Free Software Foundation, Inc.
|
||||
|
||||
Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
|
||||
Office (AJPO), Florida State University and Silicon Graphics Inc.
|
||||
provided support for this effort -- June 21, 1995.
|
||||
|
||||
Derived from the DWARF 1 implementation written by Ron Guilmette
|
||||
(rfg@netcom.com), November 1990.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This file is derived from the DWARF specification (a public document)
|
||||
Revision 2.0.0 (July 27, 1993) developed by the UNIX International
|
||||
Programming Languages Special Interest Group (UI/PLSIG) and distributed
|
||||
by UNIX International. Copies of this specification are available from
|
||||
UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
|
||||
|
||||
This file also now contains definitions from the DWARF 3 specification
|
||||
published Dec 20, 2005, available from: http://dwarf.freestandards.org. */
|
||||
|
||||
#ifndef _DWARF2_H
|
||||
#define _DWARF2_H
|
||||
|
||||
#define DW_TAG(name, value) , name = value
|
||||
#define DW_TAG_DUP(name, value) , name = value
|
||||
#define DW_FORM(name, value) , name = value
|
||||
#define DW_AT(name, value) , name = value
|
||||
#define DW_AT_DUP(name, value) , name = value
|
||||
#define DW_OP(name, value) , name = value
|
||||
#define DW_OP_DUP(name, value) , name = value
|
||||
#define DW_ATE(name, value) , name = value
|
||||
#define DW_ATE_DUP(name, value) , name = value
|
||||
#define DW_CFA(name, value) , name = value
|
||||
|
||||
#define DW_FIRST_TAG(name, value) enum dwarf_tag { \
|
||||
name = value
|
||||
#define DW_END_TAG };
|
||||
#define DW_FIRST_FORM(name, value) enum dwarf_form { \
|
||||
name = value
|
||||
#define DW_END_FORM };
|
||||
#define DW_FIRST_AT(name, value) enum dwarf_attribute { \
|
||||
name = value
|
||||
#define DW_END_AT };
|
||||
#define DW_FIRST_OP(name, value) enum dwarf_location_atom { \
|
||||
name = value
|
||||
#define DW_END_OP };
|
||||
#define DW_FIRST_ATE(name, value) enum dwarf_type { \
|
||||
name = value
|
||||
#define DW_END_ATE };
|
||||
#define DW_FIRST_CFA(name, value) enum dwarf_call_frame_info { \
|
||||
name = value
|
||||
#define DW_END_CFA };
|
||||
|
||||
#include "dwarf2.def"
|
||||
|
||||
#undef DW_FIRST_TAG
|
||||
#undef DW_END_TAG
|
||||
#undef DW_FIRST_FORM
|
||||
#undef DW_END_FORM
|
||||
#undef DW_FIRST_AT
|
||||
#undef DW_END_AT
|
||||
#undef DW_FIRST_OP
|
||||
#undef DW_END_OP
|
||||
#undef DW_FIRST_ATE
|
||||
#undef DW_END_ATE
|
||||
#undef DW_FIRST_CFA
|
||||
#undef DW_END_CFA
|
||||
|
||||
#undef DW_TAG
|
||||
#undef DW_TAG_DUP
|
||||
#undef DW_FORM
|
||||
#undef DW_AT
|
||||
#undef DW_AT_DUP
|
||||
#undef DW_OP
|
||||
#undef DW_OP_DUP
|
||||
#undef DW_ATE
|
||||
#undef DW_ATE_DUP
|
||||
#undef DW_CFA
|
||||
|
||||
/* Flag that tells whether entry has a child or not. */
|
||||
#define DW_children_no 0
|
||||
#define DW_children_yes 1
|
||||
|
||||
#define DW_AT_stride_size DW_AT_bit_stride /* Note: The use of DW_AT_stride_size is deprecated. */
|
||||
#define DW_AT_stride DW_AT_byte_stride /* Note: The use of DW_AT_stride is deprecated. */
|
||||
|
||||
/* Decimal sign encodings. */
|
||||
enum dwarf_decimal_sign_encoding
|
||||
{
|
||||
/* DWARF 3. */
|
||||
DW_DS_unsigned = 0x01,
|
||||
DW_DS_leading_overpunch = 0x02,
|
||||
DW_DS_trailing_overpunch = 0x03,
|
||||
DW_DS_leading_separate = 0x04,
|
||||
DW_DS_trailing_separate = 0x05
|
||||
};
|
||||
|
||||
/* Endianity encodings. */
|
||||
enum dwarf_endianity_encoding
|
||||
{
|
||||
/* DWARF 3. */
|
||||
DW_END_default = 0x00,
|
||||
DW_END_big = 0x01,
|
||||
DW_END_little = 0x02,
|
||||
|
||||
DW_END_lo_user = 0x40,
|
||||
DW_END_hi_user = 0xff
|
||||
};
|
||||
|
||||
/* Array ordering names and codes. */
|
||||
enum dwarf_array_dim_ordering
|
||||
{
|
||||
DW_ORD_row_major = 0,
|
||||
DW_ORD_col_major = 1
|
||||
};
|
||||
|
||||
/* Access attribute. */
|
||||
enum dwarf_access_attribute
|
||||
{
|
||||
DW_ACCESS_public = 1,
|
||||
DW_ACCESS_protected = 2,
|
||||
DW_ACCESS_private = 3
|
||||
};
|
||||
|
||||
/* Visibility. */
|
||||
enum dwarf_visibility_attribute
|
||||
{
|
||||
DW_VIS_local = 1,
|
||||
DW_VIS_exported = 2,
|
||||
DW_VIS_qualified = 3
|
||||
};
|
||||
|
||||
/* Virtuality. */
|
||||
enum dwarf_virtuality_attribute
|
||||
{
|
||||
DW_VIRTUALITY_none = 0,
|
||||
DW_VIRTUALITY_virtual = 1,
|
||||
DW_VIRTUALITY_pure_virtual = 2
|
||||
};
|
||||
|
||||
/* Case sensitivity. */
|
||||
enum dwarf_id_case
|
||||
{
|
||||
DW_ID_case_sensitive = 0,
|
||||
DW_ID_up_case = 1,
|
||||
DW_ID_down_case = 2,
|
||||
DW_ID_case_insensitive = 3
|
||||
};
|
||||
|
||||
/* Calling convention. */
|
||||
enum dwarf_calling_convention
|
||||
{
|
||||
DW_CC_normal = 0x1,
|
||||
DW_CC_program = 0x2,
|
||||
DW_CC_nocall = 0x3,
|
||||
|
||||
/* DWARF 5. */
|
||||
DW_CC_pass_by_reference = 0x4,
|
||||
DW_CC_pass_by_value = 0x5,
|
||||
|
||||
DW_CC_lo_user = 0x40,
|
||||
DW_CC_hi_user = 0xff,
|
||||
|
||||
DW_CC_GNU_renesas_sh = 0x40,
|
||||
DW_CC_GNU_borland_fastcall_i386 = 0x41,
|
||||
|
||||
/* This DW_CC_ value is not currently generated by any toolchain. It is
|
||||
used internally to GDB to indicate OpenCL C functions that have been
|
||||
compiled with the IBM XL C for OpenCL compiler and use a non-platform
|
||||
calling convention for passing OpenCL C vector types. This value may
|
||||
be changed freely as long as it does not conflict with any other DW_CC_
|
||||
value defined here. */
|
||||
DW_CC_GDB_IBM_OpenCL = 0xff
|
||||
};
|
||||
|
||||
/* Inline attribute. */
|
||||
enum dwarf_inline_attribute
|
||||
{
|
||||
DW_INL_not_inlined = 0,
|
||||
DW_INL_inlined = 1,
|
||||
DW_INL_declared_not_inlined = 2,
|
||||
DW_INL_declared_inlined = 3
|
||||
};
|
||||
|
||||
/* Discriminant lists. */
|
||||
enum dwarf_discrim_list
|
||||
{
|
||||
DW_DSC_label = 0,
|
||||
DW_DSC_range = 1
|
||||
};
|
||||
|
||||
/* Line number opcodes. */
|
||||
enum dwarf_line_number_ops
|
||||
{
|
||||
DW_LNS_extended_op = 0,
|
||||
DW_LNS_copy = 1,
|
||||
DW_LNS_advance_pc = 2,
|
||||
DW_LNS_advance_line = 3,
|
||||
DW_LNS_set_file = 4,
|
||||
DW_LNS_set_column = 5,
|
||||
DW_LNS_negate_stmt = 6,
|
||||
DW_LNS_set_basic_block = 7,
|
||||
DW_LNS_const_add_pc = 8,
|
||||
DW_LNS_fixed_advance_pc = 9,
|
||||
/* DWARF 3. */
|
||||
DW_LNS_set_prologue_end = 10,
|
||||
DW_LNS_set_epilogue_begin = 11,
|
||||
DW_LNS_set_isa = 12
|
||||
};
|
||||
|
||||
/* Line number extended opcodes. */
|
||||
enum dwarf_line_number_x_ops
|
||||
{
|
||||
DW_LNE_end_sequence = 1,
|
||||
DW_LNE_set_address = 2,
|
||||
DW_LNE_define_file = 3,
|
||||
DW_LNE_set_discriminator = 4,
|
||||
/* HP extensions. */
|
||||
DW_LNE_HP_negate_is_UV_update = 0x11,
|
||||
DW_LNE_HP_push_context = 0x12,
|
||||
DW_LNE_HP_pop_context = 0x13,
|
||||
DW_LNE_HP_set_file_line_column = 0x14,
|
||||
DW_LNE_HP_set_routine_name = 0x15,
|
||||
DW_LNE_HP_set_sequence = 0x16,
|
||||
DW_LNE_HP_negate_post_semantics = 0x17,
|
||||
DW_LNE_HP_negate_function_exit = 0x18,
|
||||
DW_LNE_HP_negate_front_end_logical = 0x19,
|
||||
DW_LNE_HP_define_proc = 0x20,
|
||||
DW_LNE_HP_source_file_correlation = 0x80,
|
||||
|
||||
DW_LNE_lo_user = 0x80,
|
||||
DW_LNE_hi_user = 0xff
|
||||
};
|
||||
|
||||
/* Sub-opcodes for DW_LNE_HP_source_file_correlation. */
|
||||
enum dwarf_line_number_hp_sfc_ops
|
||||
{
|
||||
DW_LNE_HP_SFC_formfeed = 1,
|
||||
DW_LNE_HP_SFC_set_listing_line = 2,
|
||||
DW_LNE_HP_SFC_associate = 3
|
||||
};
|
||||
|
||||
/* Content type codes in line table directory_entry_format
|
||||
and file_name_entry_format sequences. */
|
||||
enum dwarf_line_number_content_type
|
||||
{
|
||||
DW_LNCT_path = 0x1,
|
||||
DW_LNCT_directory_index = 0x2,
|
||||
DW_LNCT_timestamp = 0x3,
|
||||
DW_LNCT_size = 0x4,
|
||||
DW_LNCT_MD5 = 0x5,
|
||||
DW_LNCT_lo_user = 0x2000,
|
||||
DW_LNCT_hi_user = 0x3fff
|
||||
};
|
||||
|
||||
/* Type codes for location list entries. */
|
||||
enum dwarf_location_list_entry_type
|
||||
{
|
||||
DW_LLE_end_of_list = 0x00,
|
||||
DW_LLE_base_addressx = 0x01,
|
||||
DW_LLE_startx_endx = 0x02,
|
||||
DW_LLE_startx_length = 0x03,
|
||||
DW_LLE_offset_pair = 0x04,
|
||||
DW_LLE_default_location = 0x05,
|
||||
DW_LLE_base_address = 0x06,
|
||||
DW_LLE_start_end = 0x07,
|
||||
DW_LLE_start_length = 0x08,
|
||||
|
||||
/* Former extension for Fission.
|
||||
See http://gcc.gnu.org/wiki/DebugFission. */
|
||||
DW_LLE_GNU_end_of_list_entry = 0x00,
|
||||
DW_LLE_GNU_base_address_selection_entry = 0x01,
|
||||
DW_LLE_GNU_start_end_entry = 0x02,
|
||||
DW_LLE_GNU_start_length_entry = 0x03
|
||||
};
|
||||
|
||||
#define DW_CIE_ID 0xffffffff
|
||||
#define DW64_CIE_ID 0xffffffffffffffffULL
|
||||
#define DW_CIE_VERSION 1
|
||||
|
||||
#define DW_CFA_extended 0
|
||||
|
||||
#define DW_CHILDREN_no 0x00
|
||||
#define DW_CHILDREN_yes 0x01
|
||||
|
||||
#define DW_ADDR_none 0
|
||||
|
||||
/* Source language names and codes. */
|
||||
enum dwarf_source_language
|
||||
{
|
||||
DW_LANG_C89 = 0x0001,
|
||||
DW_LANG_C = 0x0002,
|
||||
DW_LANG_Ada83 = 0x0003,
|
||||
DW_LANG_C_plus_plus = 0x0004,
|
||||
DW_LANG_Cobol74 = 0x0005,
|
||||
DW_LANG_Cobol85 = 0x0006,
|
||||
DW_LANG_Fortran77 = 0x0007,
|
||||
DW_LANG_Fortran90 = 0x0008,
|
||||
DW_LANG_Pascal83 = 0x0009,
|
||||
DW_LANG_Modula2 = 0x000a,
|
||||
/* DWARF 3. */
|
||||
DW_LANG_Java = 0x000b,
|
||||
DW_LANG_C99 = 0x000c,
|
||||
DW_LANG_Ada95 = 0x000d,
|
||||
DW_LANG_Fortran95 = 0x000e,
|
||||
DW_LANG_PLI = 0x000f,
|
||||
DW_LANG_ObjC = 0x0010,
|
||||
DW_LANG_ObjC_plus_plus = 0x0011,
|
||||
DW_LANG_UPC = 0x0012,
|
||||
DW_LANG_D = 0x0013,
|
||||
/* DWARF 4. */
|
||||
DW_LANG_Python = 0x0014,
|
||||
/* DWARF 5. */
|
||||
DW_LANG_OpenCL = 0x0015,
|
||||
DW_LANG_Go = 0x0016,
|
||||
DW_LANG_Modula3 = 0x0017,
|
||||
DW_LANG_Haskell = 0x0018,
|
||||
DW_LANG_C_plus_plus_03 = 0x0019,
|
||||
DW_LANG_C_plus_plus_11 = 0x001a,
|
||||
DW_LANG_OCaml = 0x001b,
|
||||
DW_LANG_Rust = 0x001c,
|
||||
DW_LANG_C11 = 0x001d,
|
||||
DW_LANG_Swift = 0x001e,
|
||||
DW_LANG_Julia = 0x001f,
|
||||
DW_LANG_Dylan = 0x0020,
|
||||
DW_LANG_C_plus_plus_14 = 0x0021,
|
||||
DW_LANG_Fortran03 = 0x0022,
|
||||
DW_LANG_Fortran08 = 0x0023,
|
||||
DW_LANG_RenderScript = 0x0024,
|
||||
|
||||
DW_LANG_lo_user = 0x8000, /* Implementation-defined range start. */
|
||||
DW_LANG_hi_user = 0xffff, /* Implementation-defined range start. */
|
||||
|
||||
/* MIPS. */
|
||||
DW_LANG_Mips_Assembler = 0x8001,
|
||||
/* UPC. */
|
||||
DW_LANG_Upc = 0x8765,
|
||||
/* HP extensions. */
|
||||
DW_LANG_HP_Bliss = 0x8003,
|
||||
DW_LANG_HP_Basic91 = 0x8004,
|
||||
DW_LANG_HP_Pascal91 = 0x8005,
|
||||
DW_LANG_HP_IMacro = 0x8006,
|
||||
DW_LANG_HP_Assembler = 0x8007,
|
||||
|
||||
/* Rust extension, but replaced in DWARF 5. */
|
||||
DW_LANG_Rust_old = 0x9000
|
||||
};
|
||||
|
||||
/* Names and codes for macro information. */
|
||||
enum dwarf_macinfo_record_type
|
||||
{
|
||||
DW_MACINFO_define = 1,
|
||||
DW_MACINFO_undef = 2,
|
||||
DW_MACINFO_start_file = 3,
|
||||
DW_MACINFO_end_file = 4,
|
||||
DW_MACINFO_vendor_ext = 255
|
||||
};
|
||||
|
||||
/* DW_TAG_defaulted/DW_TAG_GNU_defaulted attributes. */
|
||||
enum dwarf_defaulted_attribute
|
||||
{
|
||||
DW_DEFAULTED_no = 0x00,
|
||||
DW_DEFAULTED_in_class = 0x01,
|
||||
DW_DEFAULTED_out_of_class = 0x02
|
||||
};
|
||||
|
||||
/* Names and codes for new style macro information. */
|
||||
enum dwarf_macro_record_type
|
||||
{
|
||||
DW_MACRO_define = 0x01,
|
||||
DW_MACRO_undef = 0x02,
|
||||
DW_MACRO_start_file = 0x03,
|
||||
DW_MACRO_end_file = 0x04,
|
||||
DW_MACRO_define_strp = 0x05,
|
||||
DW_MACRO_undef_strp = 0x06,
|
||||
DW_MACRO_import = 0x07,
|
||||
DW_MACRO_define_sup = 0x08,
|
||||
DW_MACRO_undef_sup = 0x09,
|
||||
DW_MACRO_import_sup = 0x0a,
|
||||
DW_MACRO_define_strx = 0x0b,
|
||||
DW_MACRO_undef_strx = 0x0c,
|
||||
DW_MACRO_lo_user = 0xe0,
|
||||
DW_MACRO_hi_user = 0xff,
|
||||
|
||||
/* Compatibility macros for the GNU .debug_macro extension. */
|
||||
DW_MACRO_GNU_define = 0x01,
|
||||
DW_MACRO_GNU_undef = 0x02,
|
||||
DW_MACRO_GNU_start_file = 0x03,
|
||||
DW_MACRO_GNU_end_file = 0x04,
|
||||
DW_MACRO_GNU_define_indirect = 0x05,
|
||||
DW_MACRO_GNU_undef_indirect = 0x06,
|
||||
DW_MACRO_GNU_transparent_include = 0x07,
|
||||
/* Extensions for DWZ multifile.
|
||||
See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open . */
|
||||
DW_MACRO_GNU_define_indirect_alt = 0x08,
|
||||
DW_MACRO_GNU_undef_indirect_alt = 0x09,
|
||||
DW_MACRO_GNU_transparent_include_alt = 0x0a,
|
||||
DW_MACRO_GNU_lo_user = 0xe0,
|
||||
DW_MACRO_GNU_hi_user = 0xff
|
||||
};
|
||||
|
||||
/* Index attributes in the Abbreviations Table. */
|
||||
enum dwarf_name_index_attribute
|
||||
{
|
||||
DW_IDX_compile_unit = 1,
|
||||
DW_IDX_type_unit = 2,
|
||||
DW_IDX_die_offset = 3,
|
||||
DW_IDX_parent = 4,
|
||||
DW_IDX_type_hash = 5,
|
||||
DW_IDX_lo_user = 0x2000,
|
||||
DW_IDX_hi_user = 0x3fff
|
||||
};
|
||||
|
||||
/* Range list entry kinds in .debug_rnglists* section. */
|
||||
enum dwarf_range_list_entry
|
||||
{
|
||||
DW_RLE_end_of_list = 0x00,
|
||||
DW_RLE_base_addressx = 0x01,
|
||||
DW_RLE_startx_endx = 0x02,
|
||||
DW_RLE_startx_length = 0x03,
|
||||
DW_RLE_offset_pair = 0x04,
|
||||
DW_RLE_base_address = 0x05,
|
||||
DW_RLE_start_end = 0x06,
|
||||
DW_RLE_start_length = 0x07
|
||||
};
|
||||
|
||||
/* Unit types in unit_type unit header field. */
|
||||
enum dwarf_unit_type
|
||||
{
|
||||
DW_UT_compile = 0x01,
|
||||
DW_UT_type = 0x02,
|
||||
DW_UT_partial = 0x03,
|
||||
DW_UT_skeleton = 0x04,
|
||||
DW_UT_split_compile = 0x05,
|
||||
DW_UT_split_type = 0x06,
|
||||
DW_UT_lo_user = 0x80,
|
||||
DW_UT_hi_user = 0xff
|
||||
};
|
||||
|
||||
/* @@@ For use with GNU frame unwind information. */
|
||||
|
||||
#define DW_EH_PE_absptr 0x00
|
||||
#define DW_EH_PE_omit 0xff
|
||||
|
||||
#define DW_EH_PE_uleb128 0x01
|
||||
#define DW_EH_PE_udata2 0x02
|
||||
#define DW_EH_PE_udata4 0x03
|
||||
#define DW_EH_PE_udata8 0x04
|
||||
#define DW_EH_PE_sleb128 0x09
|
||||
#define DW_EH_PE_sdata2 0x0A
|
||||
#define DW_EH_PE_sdata4 0x0B
|
||||
#define DW_EH_PE_sdata8 0x0C
|
||||
#define DW_EH_PE_signed 0x08
|
||||
|
||||
#define DW_EH_PE_pcrel 0x10
|
||||
#define DW_EH_PE_textrel 0x20
|
||||
#define DW_EH_PE_datarel 0x30
|
||||
#define DW_EH_PE_funcrel 0x40
|
||||
#define DW_EH_PE_aligned 0x50
|
||||
|
||||
#define DW_EH_PE_indirect 0x80
|
||||
|
||||
/* Codes for the debug sections in a dwarf package (.dwp) file.
|
||||
Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFissionDWP. */
|
||||
enum dwarf_sect
|
||||
{
|
||||
DW_SECT_INFO = 1,
|
||||
DW_SECT_TYPES = 2,
|
||||
DW_SECT_ABBREV = 3,
|
||||
DW_SECT_LINE = 4,
|
||||
DW_SECT_LOC = 5,
|
||||
DW_SECT_STR_OFFSETS = 6,
|
||||
DW_SECT_MACINFO = 7,
|
||||
DW_SECT_MACRO = 8,
|
||||
DW_SECT_MAX = 8
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Return the name of a DW_TAG_ constant, or NULL if the value is not
|
||||
recognized. */
|
||||
extern const char *get_DW_TAG_name (unsigned int tag);
|
||||
|
||||
/* Return the name of a DW_AT_ constant, or NULL if the value is not
|
||||
recognized. */
|
||||
extern const char *get_DW_AT_name (unsigned int attr);
|
||||
|
||||
/* Return the name of a DW_FORM_ constant, or NULL if the value is not
|
||||
recognized. */
|
||||
extern const char *get_DW_FORM_name (unsigned int form);
|
||||
|
||||
/* Return the name of a DW_OP_ constant, or NULL if the value is not
|
||||
recognized. */
|
||||
extern const char *get_DW_OP_name (unsigned int op);
|
||||
|
||||
/* Return the name of a DW_ATE_ constant, or NULL if the value is not
|
||||
recognized. */
|
||||
extern const char *get_DW_ATE_name (unsigned int enc);
|
||||
|
||||
/* Return the name of a DW_CFA_ constant, or NULL if the value is not
|
||||
recognized. */
|
||||
extern const char *get_DW_CFA_name (unsigned int opc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _DWARF2_H */
|
|
@ -0,0 +1,979 @@
|
|||
/* elf.c -- Get debug data from an ELF file for backtraces.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_DL_ITERATE_PHDR
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef HAVE_DL_ITERATE_PHDR
|
||||
|
||||
/* Dummy version of dl_iterate_phdr for systems that don't have it. */
|
||||
|
||||
#define dl_phdr_info x_dl_phdr_info
|
||||
#define dl_iterate_phdr x_dl_iterate_phdr
|
||||
|
||||
struct dl_phdr_info
|
||||
{
|
||||
uintptr_t dlpi_addr;
|
||||
const char *dlpi_name;
|
||||
};
|
||||
|
||||
static int
|
||||
dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
|
||||
size_t, void *) ATTRIBUTE_UNUSED,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */
|
||||
|
||||
/* The configure script must tell us whether we are 32-bit or 64-bit
|
||||
ELF. We could make this code test and support either possibility,
|
||||
but there is no point. This code only works for the currently
|
||||
running executable, which means that we know the ELF mode at
|
||||
configure mode. */
|
||||
|
||||
#if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64
|
||||
#error "Unknown BACKTRACE_ELF_SIZE"
|
||||
#endif
|
||||
|
||||
/* <link.h> might #include <elf.h> which might define our constants
|
||||
with slightly different values. Undefine them to be safe. */
|
||||
|
||||
#undef EI_NIDENT
|
||||
#undef EI_MAG0
|
||||
#undef EI_MAG1
|
||||
#undef EI_MAG2
|
||||
#undef EI_MAG3
|
||||
#undef EI_CLASS
|
||||
#undef EI_DATA
|
||||
#undef EI_VERSION
|
||||
#undef ELF_MAG0
|
||||
#undef ELF_MAG1
|
||||
#undef ELF_MAG2
|
||||
#undef ELF_MAG3
|
||||
#undef ELFCLASS32
|
||||
#undef ELFCLASS64
|
||||
#undef ELFDATA2LSB
|
||||
#undef ELFDATA2MSB
|
||||
#undef EV_CURRENT
|
||||
#undef ET_DYN
|
||||
#undef SHN_LORESERVE
|
||||
#undef SHN_XINDEX
|
||||
#undef SHN_UNDEF
|
||||
#undef SHT_SYMTAB
|
||||
#undef SHT_STRTAB
|
||||
#undef SHT_DYNSYM
|
||||
#undef STT_OBJECT
|
||||
#undef STT_FUNC
|
||||
|
||||
/* Basic types. */
|
||||
|
||||
typedef uint16_t b_elf_half; /* Elf_Half. */
|
||||
typedef uint32_t b_elf_word; /* Elf_Word. */
|
||||
typedef int32_t b_elf_sword; /* Elf_Sword. */
|
||||
|
||||
#if BACKTRACE_ELF_SIZE == 32
|
||||
|
||||
typedef uint32_t b_elf_addr; /* Elf_Addr. */
|
||||
typedef uint32_t b_elf_off; /* Elf_Off. */
|
||||
|
||||
typedef uint32_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */
|
||||
|
||||
#else
|
||||
|
||||
typedef uint64_t b_elf_addr; /* Elf_Addr. */
|
||||
typedef uint64_t b_elf_off; /* Elf_Off. */
|
||||
typedef uint64_t b_elf_xword; /* Elf_Xword. */
|
||||
typedef int64_t b_elf_sxword; /* Elf_Sxword. */
|
||||
|
||||
typedef uint64_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */
|
||||
|
||||
#endif
|
||||
|
||||
/* Data structures and associated constants. */
|
||||
|
||||
#define EI_NIDENT 16
|
||||
|
||||
typedef struct {
|
||||
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
|
||||
b_elf_half e_type; /* Identifies object file type */
|
||||
b_elf_half e_machine; /* Specifies required architecture */
|
||||
b_elf_word e_version; /* Identifies object file version */
|
||||
b_elf_addr e_entry; /* Entry point virtual address */
|
||||
b_elf_off e_phoff; /* Program header table file offset */
|
||||
b_elf_off e_shoff; /* Section header table file offset */
|
||||
b_elf_word e_flags; /* Processor-specific flags */
|
||||
b_elf_half e_ehsize; /* ELF header size in bytes */
|
||||
b_elf_half e_phentsize; /* Program header table entry size */
|
||||
b_elf_half e_phnum; /* Program header table entry count */
|
||||
b_elf_half e_shentsize; /* Section header table entry size */
|
||||
b_elf_half e_shnum; /* Section header table entry count */
|
||||
b_elf_half e_shstrndx; /* Section header string table index */
|
||||
} b_elf_ehdr; /* Elf_Ehdr. */
|
||||
|
||||
#define EI_MAG0 0
|
||||
#define EI_MAG1 1
|
||||
#define EI_MAG2 2
|
||||
#define EI_MAG3 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define EI_VERSION 6
|
||||
|
||||
#define ELFMAG0 0x7f
|
||||
#define ELFMAG1 'E'
|
||||
#define ELFMAG2 'L'
|
||||
#define ELFMAG3 'F'
|
||||
|
||||
#define ELFCLASS32 1
|
||||
#define ELFCLASS64 2
|
||||
|
||||
#define ELFDATA2LSB 1
|
||||
#define ELFDATA2MSB 2
|
||||
|
||||
#define EV_CURRENT 1
|
||||
|
||||
#define ET_DYN 3
|
||||
|
||||
typedef struct {
|
||||
b_elf_word sh_name; /* Section name, index in string tbl */
|
||||
b_elf_word sh_type; /* Type of section */
|
||||
b_elf_wxword sh_flags; /* Miscellaneous section attributes */
|
||||
b_elf_addr sh_addr; /* Section virtual addr at execution */
|
||||
b_elf_off sh_offset; /* Section file offset */
|
||||
b_elf_wxword sh_size; /* Size of section in bytes */
|
||||
b_elf_word sh_link; /* Index of another section */
|
||||
b_elf_word sh_info; /* Additional section information */
|
||||
b_elf_wxword sh_addralign; /* Section alignment */
|
||||
b_elf_wxword sh_entsize; /* Entry size if section holds table */
|
||||
} b_elf_shdr; /* Elf_Shdr. */
|
||||
|
||||
#define SHN_UNDEF 0x0000 /* Undefined section */
|
||||
#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
|
||||
#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */
|
||||
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_DYNSYM 11
|
||||
|
||||
#if BACKTRACE_ELF_SIZE == 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
b_elf_word st_name; /* Symbol name, index in string tbl */
|
||||
b_elf_addr st_value; /* Symbol value */
|
||||
b_elf_word st_size; /* Symbol size */
|
||||
unsigned char st_info; /* Symbol binding and type */
|
||||
unsigned char st_other; /* Visibility and other data */
|
||||
b_elf_half st_shndx; /* Symbol section index */
|
||||
} b_elf_sym; /* Elf_Sym. */
|
||||
|
||||
#else /* BACKTRACE_ELF_SIZE != 32 */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
b_elf_word st_name; /* Symbol name, index in string tbl */
|
||||
unsigned char st_info; /* Symbol binding and type */
|
||||
unsigned char st_other; /* Visibility and other data */
|
||||
b_elf_half st_shndx; /* Symbol section index */
|
||||
b_elf_addr st_value; /* Symbol value */
|
||||
b_elf_xword st_size; /* Symbol size */
|
||||
} b_elf_sym; /* Elf_Sym. */
|
||||
|
||||
#endif /* BACKTRACE_ELF_SIZE != 32 */
|
||||
|
||||
#define STT_OBJECT 1
|
||||
#define STT_FUNC 2
|
||||
|
||||
/* An index of ELF sections we care about. */
|
||||
|
||||
enum debug_section
|
||||
{
|
||||
DEBUG_INFO,
|
||||
DEBUG_LINE,
|
||||
DEBUG_ABBREV,
|
||||
DEBUG_RANGES,
|
||||
DEBUG_STR,
|
||||
DEBUG_MAX
|
||||
};
|
||||
|
||||
/* Names of sections, indexed by enum elf_section. */
|
||||
|
||||
static const char * const debug_section_names[DEBUG_MAX] =
|
||||
{
|
||||
".debug_info",
|
||||
".debug_line",
|
||||
".debug_abbrev",
|
||||
".debug_ranges",
|
||||
".debug_str"
|
||||
};
|
||||
|
||||
/* Information we gather for the sections we care about. */
|
||||
|
||||
struct debug_section_info
|
||||
{
|
||||
/* Section file offset. */
|
||||
off_t offset;
|
||||
/* Section size. */
|
||||
size_t size;
|
||||
/* Section contents, after read from file. */
|
||||
const unsigned char *data;
|
||||
};
|
||||
|
||||
/* Information we keep for an ELF symbol. */
|
||||
|
||||
struct elf_symbol
|
||||
{
|
||||
/* The name of the symbol. */
|
||||
const char *name;
|
||||
/* The address of the symbol. */
|
||||
uintptr_t address;
|
||||
/* The size of the symbol. */
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* Information to pass to elf_syminfo. */
|
||||
|
||||
struct elf_syminfo_data
|
||||
{
|
||||
/* Symbols for the next module. */
|
||||
struct elf_syminfo_data *next;
|
||||
/* The ELF symbols, sorted by address. */
|
||||
struct elf_symbol *symbols;
|
||||
/* The number of symbols. */
|
||||
size_t count;
|
||||
};
|
||||
|
||||
/* A dummy callback function used when we can't find any debug info. */
|
||||
|
||||
static int
|
||||
elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
uintptr_t pc ATTRIBUTE_UNUSED,
|
||||
backtrace_full_callback callback ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
error_callback (data, "no debug info in ELF executable", -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A dummy callback function used when we can't find a symbol
|
||||
table. */
|
||||
|
||||
static void
|
||||
elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
uintptr_t addr ATTRIBUTE_UNUSED,
|
||||
backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
error_callback (data, "no symbol table in ELF executable", -1);
|
||||
}
|
||||
|
||||
/* Compare struct elf_symbol for qsort. */
|
||||
|
||||
static int
|
||||
elf_symbol_compare (const void *v1, const void *v2)
|
||||
{
|
||||
const struct elf_symbol *e1 = (const struct elf_symbol *) v1;
|
||||
const struct elf_symbol *e2 = (const struct elf_symbol *) v2;
|
||||
|
||||
if (e1->address < e2->address)
|
||||
return -1;
|
||||
else if (e1->address > e2->address)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare an ADDR against an elf_symbol for bsearch. We allocate one
|
||||
extra entry in the array so that this can look safely at the next
|
||||
entry. */
|
||||
|
||||
static int
|
||||
elf_symbol_search (const void *vkey, const void *ventry)
|
||||
{
|
||||
const uintptr_t *key = (const uintptr_t *) vkey;
|
||||
const struct elf_symbol *entry = (const struct elf_symbol *) ventry;
|
||||
uintptr_t addr;
|
||||
|
||||
addr = *key;
|
||||
if (addr < entry->address)
|
||||
return -1;
|
||||
else if (addr >= entry->address + entry->size)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize the symbol table info for elf_syminfo. */
|
||||
|
||||
static int
|
||||
elf_initialize_syminfo (struct backtrace_state *state,
|
||||
uintptr_t base_address,
|
||||
const unsigned char *symtab_data, size_t symtab_size,
|
||||
const unsigned char *strtab, size_t strtab_size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, struct elf_syminfo_data *sdata)
|
||||
{
|
||||
size_t sym_count;
|
||||
const b_elf_sym *sym;
|
||||
size_t elf_symbol_count;
|
||||
size_t elf_symbol_size;
|
||||
struct elf_symbol *elf_symbols;
|
||||
size_t i;
|
||||
unsigned int j;
|
||||
|
||||
sym_count = symtab_size / sizeof (b_elf_sym);
|
||||
|
||||
/* We only care about function symbols. Count them. */
|
||||
sym = (const b_elf_sym *) symtab_data;
|
||||
elf_symbol_count = 0;
|
||||
for (i = 0; i < sym_count; ++i, ++sym)
|
||||
{
|
||||
int info;
|
||||
|
||||
info = sym->st_info & 0xf;
|
||||
if ((info == STT_FUNC || info == STT_OBJECT)
|
||||
&& sym->st_shndx != SHN_UNDEF)
|
||||
++elf_symbol_count;
|
||||
}
|
||||
|
||||
elf_symbol_size = elf_symbol_count * sizeof (struct elf_symbol);
|
||||
elf_symbols = ((struct elf_symbol *)
|
||||
backtrace_alloc (state, elf_symbol_size, error_callback,
|
||||
data));
|
||||
if (elf_symbols == NULL)
|
||||
return 0;
|
||||
|
||||
sym = (const b_elf_sym *) symtab_data;
|
||||
j = 0;
|
||||
for (i = 0; i < sym_count; ++i, ++sym)
|
||||
{
|
||||
int info;
|
||||
|
||||
info = sym->st_info & 0xf;
|
||||
if (info != STT_FUNC && info != STT_OBJECT)
|
||||
continue;
|
||||
if (sym->st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
if (sym->st_name >= strtab_size)
|
||||
{
|
||||
error_callback (data, "symbol string index out of range", 0);
|
||||
backtrace_free (state, elf_symbols, elf_symbol_size, error_callback,
|
||||
data);
|
||||
return 0;
|
||||
}
|
||||
elf_symbols[j].name = (const char *) strtab + sym->st_name;
|
||||
elf_symbols[j].address = sym->st_value + base_address;
|
||||
elf_symbols[j].size = sym->st_size;
|
||||
++j;
|
||||
}
|
||||
|
||||
backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol),
|
||||
elf_symbol_compare);
|
||||
|
||||
sdata->next = NULL;
|
||||
sdata->symbols = elf_symbols;
|
||||
sdata->count = elf_symbol_count;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Add EDATA to the list in STATE. */
|
||||
|
||||
static void
|
||||
elf_add_syminfo_data (struct backtrace_state *state,
|
||||
struct elf_syminfo_data *edata)
|
||||
{
|
||||
if (!state->threaded)
|
||||
{
|
||||
struct elf_syminfo_data **pp;
|
||||
|
||||
for (pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
|
||||
*pp != NULL;
|
||||
pp = &(*pp)->next)
|
||||
;
|
||||
*pp = edata;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
struct elf_syminfo_data **pp;
|
||||
|
||||
pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct elf_syminfo_data *p;
|
||||
|
||||
p = backtrace_atomic_load_pointer (pp);
|
||||
|
||||
if (p == NULL)
|
||||
break;
|
||||
|
||||
pp = &p->next;
|
||||
}
|
||||
|
||||
if (__sync_bool_compare_and_swap (pp, NULL, edata))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the symbol name and value for an ADDR. */
|
||||
|
||||
static void
|
||||
elf_syminfo (struct backtrace_state *state, uintptr_t addr,
|
||||
backtrace_syminfo_callback callback,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data)
|
||||
{
|
||||
struct elf_syminfo_data *edata;
|
||||
struct elf_symbol *sym = NULL;
|
||||
|
||||
if (!state->threaded)
|
||||
{
|
||||
for (edata = (struct elf_syminfo_data *) state->syminfo_data;
|
||||
edata != NULL;
|
||||
edata = edata->next)
|
||||
{
|
||||
sym = ((struct elf_symbol *)
|
||||
bsearch (&addr, edata->symbols, edata->count,
|
||||
sizeof (struct elf_symbol), elf_symbol_search));
|
||||
if (sym != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct elf_syminfo_data **pp;
|
||||
|
||||
pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
|
||||
while (1)
|
||||
{
|
||||
edata = backtrace_atomic_load_pointer (pp);
|
||||
if (edata == NULL)
|
||||
break;
|
||||
|
||||
sym = ((struct elf_symbol *)
|
||||
bsearch (&addr, edata->symbols, edata->count,
|
||||
sizeof (struct elf_symbol), elf_symbol_search));
|
||||
if (sym != NULL)
|
||||
break;
|
||||
|
||||
pp = &edata->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (sym == NULL)
|
||||
callback (data, addr, NULL, 0, 0);
|
||||
else
|
||||
callback (data, addr, sym->name, sym->address, sym->size);
|
||||
}
|
||||
|
||||
/* Add the backtrace data for one ELF file. Returns 1 on success,
|
||||
0 on failure (in both cases descriptor is closed) or -1 if exe
|
||||
is non-zero and the ELF file is ET_DYN, which tells the caller that
|
||||
elf_add will need to be called on the descriptor again after
|
||||
base_address is determined. */
|
||||
|
||||
static int
|
||||
elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
|
||||
backtrace_error_callback error_callback, void *data,
|
||||
fileline *fileline_fn, int *found_sym, int *found_dwarf, int exe)
|
||||
{
|
||||
struct backtrace_view ehdr_view;
|
||||
b_elf_ehdr ehdr;
|
||||
off_t shoff;
|
||||
unsigned int shnum;
|
||||
unsigned int shstrndx;
|
||||
struct backtrace_view shdrs_view;
|
||||
int shdrs_view_valid;
|
||||
const b_elf_shdr *shdrs;
|
||||
const b_elf_shdr *shstrhdr;
|
||||
size_t shstr_size;
|
||||
off_t shstr_off;
|
||||
struct backtrace_view names_view;
|
||||
int names_view_valid;
|
||||
const char *names;
|
||||
unsigned int symtab_shndx;
|
||||
unsigned int dynsym_shndx;
|
||||
unsigned int i;
|
||||
struct debug_section_info sections[DEBUG_MAX];
|
||||
struct backtrace_view symtab_view;
|
||||
int symtab_view_valid;
|
||||
struct backtrace_view strtab_view;
|
||||
int strtab_view_valid;
|
||||
off_t min_offset;
|
||||
off_t max_offset;
|
||||
struct backtrace_view debug_view;
|
||||
int debug_view_valid;
|
||||
|
||||
*found_sym = 0;
|
||||
*found_dwarf = 0;
|
||||
|
||||
shdrs_view_valid = 0;
|
||||
names_view_valid = 0;
|
||||
symtab_view_valid = 0;
|
||||
strtab_view_valid = 0;
|
||||
debug_view_valid = 0;
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback,
|
||||
data, &ehdr_view))
|
||||
goto fail;
|
||||
|
||||
memcpy (&ehdr, ehdr_view.data, sizeof ehdr);
|
||||
|
||||
backtrace_release_view (state, &ehdr_view, error_callback, data);
|
||||
|
||||
if (ehdr.e_ident[EI_MAG0] != ELFMAG0
|
||||
|| ehdr.e_ident[EI_MAG1] != ELFMAG1
|
||||
|| ehdr.e_ident[EI_MAG2] != ELFMAG2
|
||||
|| ehdr.e_ident[EI_MAG3] != ELFMAG3)
|
||||
{
|
||||
error_callback (data, "executable file is not ELF", 0);
|
||||
goto fail;
|
||||
}
|
||||
if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)
|
||||
{
|
||||
error_callback (data, "executable file is unrecognized ELF version", 0);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#if BACKTRACE_ELF_SIZE == 32
|
||||
#define BACKTRACE_ELFCLASS ELFCLASS32
|
||||
#else
|
||||
#define BACKTRACE_ELFCLASS ELFCLASS64
|
||||
#endif
|
||||
|
||||
if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS)
|
||||
{
|
||||
error_callback (data, "executable file is unexpected ELF class", 0);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB
|
||||
&& ehdr.e_ident[EI_DATA] != ELFDATA2MSB)
|
||||
{
|
||||
error_callback (data, "executable file has unknown endianness", 0);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* If the executable is ET_DYN, it is either a PIE, or we are running
|
||||
directly a shared library with .interp. We need to wait for
|
||||
dl_iterate_phdr in that case to determine the actual base_address. */
|
||||
if (exe && ehdr.e_type == ET_DYN)
|
||||
return -1;
|
||||
|
||||
shoff = ehdr.e_shoff;
|
||||
shnum = ehdr.e_shnum;
|
||||
shstrndx = ehdr.e_shstrndx;
|
||||
|
||||
if ((shnum == 0 || shstrndx == SHN_XINDEX)
|
||||
&& shoff != 0)
|
||||
{
|
||||
struct backtrace_view shdr_view;
|
||||
const b_elf_shdr *shdr;
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr,
|
||||
error_callback, data, &shdr_view))
|
||||
goto fail;
|
||||
|
||||
shdr = (const b_elf_shdr *) shdr_view.data;
|
||||
|
||||
if (shnum == 0)
|
||||
shnum = shdr->sh_size;
|
||||
|
||||
if (shstrndx == SHN_XINDEX)
|
||||
{
|
||||
shstrndx = shdr->sh_link;
|
||||
|
||||
/* Versions of the GNU binutils between 2.12 and 2.18 did
|
||||
not handle objects with more than SHN_LORESERVE sections
|
||||
correctly. All large section indexes were offset by
|
||||
0x100. There is more information at
|
||||
http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
|
||||
Fortunately these object files are easy to detect, as the
|
||||
GNU binutils always put the section header string table
|
||||
near the end of the list of sections. Thus if the
|
||||
section header string table index is larger than the
|
||||
number of sections, then we know we have to subtract
|
||||
0x100 to get the real section index. */
|
||||
if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100)
|
||||
shstrndx -= 0x100;
|
||||
}
|
||||
|
||||
backtrace_release_view (state, &shdr_view, error_callback, data);
|
||||
}
|
||||
|
||||
/* To translate PC to file/line when using DWARF, we need to find
|
||||
the .debug_info and .debug_line sections. */
|
||||
|
||||
/* Read the section headers, skipping the first one. */
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr),
|
||||
(shnum - 1) * sizeof (b_elf_shdr),
|
||||
error_callback, data, &shdrs_view))
|
||||
goto fail;
|
||||
shdrs_view_valid = 1;
|
||||
shdrs = (const b_elf_shdr *) shdrs_view.data;
|
||||
|
||||
/* Read the section names. */
|
||||
|
||||
shstrhdr = &shdrs[shstrndx - 1];
|
||||
shstr_size = shstrhdr->sh_size;
|
||||
shstr_off = shstrhdr->sh_offset;
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, shstr_off, shstr_size,
|
||||
error_callback, data, &names_view))
|
||||
goto fail;
|
||||
names_view_valid = 1;
|
||||
names = (const char *) names_view.data;
|
||||
|
||||
symtab_shndx = 0;
|
||||
dynsym_shndx = 0;
|
||||
|
||||
memset (sections, 0, sizeof sections);
|
||||
|
||||
/* Look for the symbol table. */
|
||||
for (i = 1; i < shnum; ++i)
|
||||
{
|
||||
const b_elf_shdr *shdr;
|
||||
unsigned int sh_name;
|
||||
const char *name;
|
||||
int j;
|
||||
|
||||
shdr = &shdrs[i - 1];
|
||||
|
||||
if (shdr->sh_type == SHT_SYMTAB)
|
||||
symtab_shndx = i;
|
||||
else if (shdr->sh_type == SHT_DYNSYM)
|
||||
dynsym_shndx = i;
|
||||
|
||||
sh_name = shdr->sh_name;
|
||||
if (sh_name >= shstr_size)
|
||||
{
|
||||
error_callback (data, "ELF section name out of range", 0);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
name = names + sh_name;
|
||||
|
||||
for (j = 0; j < (int) DEBUG_MAX; ++j)
|
||||
{
|
||||
if (strcmp (name, debug_section_names[j]) == 0)
|
||||
{
|
||||
sections[j].offset = shdr->sh_offset;
|
||||
sections[j].size = shdr->sh_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (symtab_shndx == 0)
|
||||
symtab_shndx = dynsym_shndx;
|
||||
if (symtab_shndx != 0)
|
||||
{
|
||||
const b_elf_shdr *symtab_shdr;
|
||||
unsigned int strtab_shndx;
|
||||
const b_elf_shdr *strtab_shdr;
|
||||
struct elf_syminfo_data *sdata;
|
||||
|
||||
symtab_shdr = &shdrs[symtab_shndx - 1];
|
||||
strtab_shndx = symtab_shdr->sh_link;
|
||||
if (strtab_shndx >= shnum)
|
||||
{
|
||||
error_callback (data,
|
||||
"ELF symbol table strtab link out of range", 0);
|
||||
goto fail;
|
||||
}
|
||||
strtab_shdr = &shdrs[strtab_shndx - 1];
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, symtab_shdr->sh_offset,
|
||||
symtab_shdr->sh_size, error_callback, data,
|
||||
&symtab_view))
|
||||
goto fail;
|
||||
symtab_view_valid = 1;
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, strtab_shdr->sh_offset,
|
||||
strtab_shdr->sh_size, error_callback, data,
|
||||
&strtab_view))
|
||||
goto fail;
|
||||
strtab_view_valid = 1;
|
||||
|
||||
sdata = ((struct elf_syminfo_data *)
|
||||
backtrace_alloc (state, sizeof *sdata, error_callback, data));
|
||||
if (sdata == NULL)
|
||||
goto fail;
|
||||
|
||||
if (!elf_initialize_syminfo (state, base_address,
|
||||
symtab_view.data, symtab_shdr->sh_size,
|
||||
strtab_view.data, strtab_shdr->sh_size,
|
||||
error_callback, data, sdata))
|
||||
{
|
||||
backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* We no longer need the symbol table, but we hold on to the
|
||||
string table permanently. */
|
||||
backtrace_release_view (state, &symtab_view, error_callback, data);
|
||||
|
||||
*found_sym = 1;
|
||||
|
||||
elf_add_syminfo_data (state, sdata);
|
||||
}
|
||||
|
||||
/* FIXME: Need to handle compressed debug sections. */
|
||||
|
||||
backtrace_release_view (state, &shdrs_view, error_callback, data);
|
||||
shdrs_view_valid = 0;
|
||||
backtrace_release_view (state, &names_view, error_callback, data);
|
||||
names_view_valid = 0;
|
||||
|
||||
/* Read all the debug sections in a single view, since they are
|
||||
probably adjacent in the file. We never release this view. */
|
||||
|
||||
min_offset = 0;
|
||||
max_offset = 0;
|
||||
for (i = 0; i < (int) DEBUG_MAX; ++i)
|
||||
{
|
||||
off_t end;
|
||||
|
||||
if (sections[i].size == 0)
|
||||
continue;
|
||||
if (min_offset == 0 || sections[i].offset < min_offset)
|
||||
min_offset = sections[i].offset;
|
||||
end = sections[i].offset + sections[i].size;
|
||||
if (end > max_offset)
|
||||
max_offset = end;
|
||||
}
|
||||
if (min_offset == 0 || max_offset == 0)
|
||||
{
|
||||
if (!backtrace_close (descriptor, error_callback, data))
|
||||
goto fail;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, min_offset,
|
||||
max_offset - min_offset,
|
||||
error_callback, data, &debug_view))
|
||||
goto fail;
|
||||
debug_view_valid = 1;
|
||||
|
||||
/* We've read all we need from the executable. */
|
||||
if (!backtrace_close (descriptor, error_callback, data))
|
||||
goto fail;
|
||||
descriptor = -1;
|
||||
|
||||
for (i = 0; i < (int) DEBUG_MAX; ++i)
|
||||
{
|
||||
if (sections[i].size == 0)
|
||||
sections[i].data = NULL;
|
||||
else
|
||||
sections[i].data = ((const unsigned char *) debug_view.data
|
||||
+ (sections[i].offset - min_offset));
|
||||
}
|
||||
|
||||
if (!backtrace_dwarf_add (state, base_address,
|
||||
sections[DEBUG_INFO].data,
|
||||
sections[DEBUG_INFO].size,
|
||||
sections[DEBUG_LINE].data,
|
||||
sections[DEBUG_LINE].size,
|
||||
sections[DEBUG_ABBREV].data,
|
||||
sections[DEBUG_ABBREV].size,
|
||||
sections[DEBUG_RANGES].data,
|
||||
sections[DEBUG_RANGES].size,
|
||||
sections[DEBUG_STR].data,
|
||||
sections[DEBUG_STR].size,
|
||||
ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
|
||||
error_callback, data, fileline_fn))
|
||||
goto fail;
|
||||
|
||||
*found_dwarf = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (shdrs_view_valid)
|
||||
backtrace_release_view (state, &shdrs_view, error_callback, data);
|
||||
if (names_view_valid)
|
||||
backtrace_release_view (state, &names_view, error_callback, data);
|
||||
if (symtab_view_valid)
|
||||
backtrace_release_view (state, &symtab_view, error_callback, data);
|
||||
if (strtab_view_valid)
|
||||
backtrace_release_view (state, &strtab_view, error_callback, data);
|
||||
if (debug_view_valid)
|
||||
backtrace_release_view (state, &debug_view, error_callback, data);
|
||||
if (descriptor != -1)
|
||||
backtrace_close (descriptor, error_callback, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Data passed to phdr_callback. */
|
||||
|
||||
struct phdr_data
|
||||
{
|
||||
struct backtrace_state *state;
|
||||
backtrace_error_callback error_callback;
|
||||
void *data;
|
||||
fileline *fileline_fn;
|
||||
int *found_sym;
|
||||
int *found_dwarf;
|
||||
int exe_descriptor;
|
||||
};
|
||||
|
||||
/* Callback passed to dl_iterate_phdr. Load debug info from shared
|
||||
libraries. */
|
||||
|
||||
static int
|
||||
#ifdef __i386__
|
||||
__attribute__ ((__force_align_arg_pointer__))
|
||||
#endif
|
||||
phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
|
||||
void *pdata)
|
||||
{
|
||||
struct phdr_data *pd = (struct phdr_data *) pdata;
|
||||
int descriptor;
|
||||
int does_not_exist;
|
||||
fileline elf_fileline_fn;
|
||||
int found_dwarf;
|
||||
|
||||
/* There is not much we can do if we don't have the module name,
|
||||
unless executable is ET_DYN, where we expect the very first
|
||||
phdr_callback to be for the PIE. */
|
||||
if (info->dlpi_name == NULL || info->dlpi_name[0] == '\0')
|
||||
{
|
||||
if (pd->exe_descriptor == -1)
|
||||
return 0;
|
||||
descriptor = pd->exe_descriptor;
|
||||
pd->exe_descriptor = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pd->exe_descriptor != -1)
|
||||
{
|
||||
backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data);
|
||||
pd->exe_descriptor = -1;
|
||||
}
|
||||
|
||||
descriptor = backtrace_open (info->dlpi_name, pd->error_callback,
|
||||
pd->data, &does_not_exist);
|
||||
if (descriptor < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback,
|
||||
pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf, 0))
|
||||
{
|
||||
if (found_dwarf)
|
||||
{
|
||||
*pd->found_dwarf = 1;
|
||||
*pd->fileline_fn = elf_fileline_fn;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize the backtrace data we need from an ELF executable. At
|
||||
the ELF level, all we need to do is find the debug info
|
||||
sections. */
|
||||
|
||||
int
|
||||
backtrace_initialize (struct backtrace_state *state, int descriptor,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, fileline *fileline_fn)
|
||||
{
|
||||
int ret;
|
||||
int found_sym;
|
||||
int found_dwarf;
|
||||
fileline elf_fileline_fn = elf_nodebug;
|
||||
struct phdr_data pd;
|
||||
|
||||
ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
|
||||
&found_sym, &found_dwarf, 1);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
pd.state = state;
|
||||
pd.error_callback = error_callback;
|
||||
pd.data = data;
|
||||
pd.fileline_fn = &elf_fileline_fn;
|
||||
pd.found_sym = &found_sym;
|
||||
pd.found_dwarf = &found_dwarf;
|
||||
pd.exe_descriptor = ret < 0 ? descriptor : -1;
|
||||
|
||||
dl_iterate_phdr (phdr_callback, (void *) &pd);
|
||||
|
||||
if (!state->threaded)
|
||||
{
|
||||
if (found_sym)
|
||||
state->syminfo_fn = elf_syminfo;
|
||||
else if (state->syminfo_fn == NULL)
|
||||
state->syminfo_fn = elf_nosyms;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found_sym)
|
||||
backtrace_atomic_store_pointer (&state->syminfo_fn, elf_syminfo);
|
||||
else
|
||||
(void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
|
||||
elf_nosyms);
|
||||
}
|
||||
|
||||
if (!state->threaded)
|
||||
{
|
||||
if (state->fileline_fn == NULL || state->fileline_fn == elf_nodebug)
|
||||
*fileline_fn = elf_fileline_fn;
|
||||
}
|
||||
else
|
||||
{
|
||||
fileline current_fn;
|
||||
|
||||
current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
|
||||
if (current_fn == NULL || current_fn == elf_nodebug)
|
||||
*fileline_fn = elf_fileline_fn;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/* fileline.c -- Get file and line number information in a backtrace.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef HAVE_GETEXECNAME
|
||||
#define getexecname() NULL
|
||||
#endif
|
||||
|
||||
/* Initialize the fileline information from the executable. Returns 1
|
||||
on success, 0 on failure. */
|
||||
|
||||
static int
|
||||
fileline_initialize (struct backtrace_state *state,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
int failed;
|
||||
fileline fileline_fn;
|
||||
int pass;
|
||||
int called_error_callback;
|
||||
int descriptor;
|
||||
|
||||
if (!state->threaded)
|
||||
failed = state->fileline_initialization_failed;
|
||||
else
|
||||
failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
|
||||
|
||||
if (failed)
|
||||
{
|
||||
error_callback (data, "failed to read executable information", -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!state->threaded)
|
||||
fileline_fn = state->fileline_fn;
|
||||
else
|
||||
fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
|
||||
if (fileline_fn != NULL)
|
||||
return 1;
|
||||
|
||||
/* We have not initialized the information. Do it now. */
|
||||
|
||||
descriptor = -1;
|
||||
called_error_callback = 0;
|
||||
for (pass = 0; pass < 4; ++pass)
|
||||
{
|
||||
const char *filename;
|
||||
int does_not_exist;
|
||||
|
||||
switch (pass)
|
||||
{
|
||||
case 0:
|
||||
filename = state->filename;
|
||||
break;
|
||||
case 1:
|
||||
filename = getexecname ();
|
||||
break;
|
||||
case 2:
|
||||
filename = "/proc/self/exe";
|
||||
break;
|
||||
case 3:
|
||||
filename = "/proc/curproc/file";
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (filename == NULL)
|
||||
continue;
|
||||
|
||||
descriptor = backtrace_open (filename, error_callback, data,
|
||||
&does_not_exist);
|
||||
if (descriptor < 0 && !does_not_exist)
|
||||
{
|
||||
called_error_callback = 1;
|
||||
break;
|
||||
}
|
||||
if (descriptor >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (descriptor < 0)
|
||||
{
|
||||
if (!called_error_callback)
|
||||
{
|
||||
if (state->filename != NULL)
|
||||
error_callback (data, state->filename, ENOENT);
|
||||
else
|
||||
error_callback (data,
|
||||
"libbacktrace could not find executable to open",
|
||||
0);
|
||||
}
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
if (!failed)
|
||||
{
|
||||
if (!backtrace_initialize (state, descriptor, error_callback, data,
|
||||
&fileline_fn))
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
if (failed)
|
||||
{
|
||||
if (!state->threaded)
|
||||
state->fileline_initialization_failed = 1;
|
||||
else
|
||||
backtrace_atomic_store_int (&state->fileline_initialization_failed, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!state->threaded)
|
||||
state->fileline_fn = fileline_fn;
|
||||
else
|
||||
{
|
||||
backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn);
|
||||
|
||||
/* Note that if two threads initialize at once, one of the data
|
||||
sets may be leaked. */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Given a PC, find the file name, line number, and function name. */
|
||||
|
||||
int
|
||||
backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
if (!fileline_initialize (state, error_callback, data))
|
||||
return 0;
|
||||
|
||||
if (state->fileline_initialization_failed)
|
||||
return 0;
|
||||
|
||||
return state->fileline_fn (state, pc, callback, error_callback, data);
|
||||
}
|
||||
|
||||
/* Given a PC, find the symbol for it, and its value. */
|
||||
|
||||
int
|
||||
backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_syminfo_callback callback,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
if (!fileline_initialize (state, error_callback, data))
|
||||
return 0;
|
||||
|
||||
if (state->fileline_initialization_failed)
|
||||
return 0;
|
||||
|
||||
state->syminfo_fn (state, pc, callback, error_callback, data);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* Macros for taking apart, interpreting and processing file names.
|
||||
|
||||
These are here because some non-Posix (a.k.a. DOSish) systems have
|
||||
drive letter brain-damage at the beginning of an absolute file name,
|
||||
use forward- and back-slash in path names interchangeably, and
|
||||
some of them have case-insensitive file names.
|
||||
|
||||
Copyright (C) 2000-2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of BFD, the Binary File Descriptor library.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef FILENAMES_H
|
||||
#define FILENAMES_H
|
||||
|
||||
#include "hashtab.h" /* for hashval_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__)
|
||||
# ifndef HAVE_DOS_BASED_FILE_SYSTEM
|
||||
# define HAVE_DOS_BASED_FILE_SYSTEM 1
|
||||
# endif
|
||||
# ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
|
||||
# define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1
|
||||
# endif
|
||||
# define HAS_DRIVE_SPEC(f) HAS_DOS_DRIVE_SPEC (f)
|
||||
# define IS_DIR_SEPARATOR(c) IS_DOS_DIR_SEPARATOR (c)
|
||||
# define IS_ABSOLUTE_PATH(f) IS_DOS_ABSOLUTE_PATH (f)
|
||||
#else /* not DOSish */
|
||||
# if defined(__APPLE__)
|
||||
# ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
|
||||
# define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1
|
||||
# endif
|
||||
# endif /* __APPLE__ */
|
||||
# define HAS_DRIVE_SPEC(f) (0)
|
||||
# define IS_DIR_SEPARATOR(c) IS_UNIX_DIR_SEPARATOR (c)
|
||||
# define IS_ABSOLUTE_PATH(f) IS_UNIX_ABSOLUTE_PATH (f)
|
||||
#endif
|
||||
|
||||
#define IS_DIR_SEPARATOR_1(dos_based, c) \
|
||||
(((c) == '/') \
|
||||
|| (((c) == '\\') && (dos_based)))
|
||||
|
||||
#define HAS_DRIVE_SPEC_1(dos_based, f) \
|
||||
((f)[0] && ((f)[1] == ':') && (dos_based))
|
||||
|
||||
/* Remove the drive spec from F, assuming HAS_DRIVE_SPEC (f).
|
||||
The result is a pointer to the remainder of F. */
|
||||
#define STRIP_DRIVE_SPEC(f) ((f) + 2)
|
||||
|
||||
#define IS_DOS_DIR_SEPARATOR(c) IS_DIR_SEPARATOR_1 (1, c)
|
||||
#define IS_DOS_ABSOLUTE_PATH(f) IS_ABSOLUTE_PATH_1 (1, f)
|
||||
#define HAS_DOS_DRIVE_SPEC(f) HAS_DRIVE_SPEC_1 (1, f)
|
||||
|
||||
#define IS_UNIX_DIR_SEPARATOR(c) IS_DIR_SEPARATOR_1 (0, c)
|
||||
#define IS_UNIX_ABSOLUTE_PATH(f) IS_ABSOLUTE_PATH_1 (0, f)
|
||||
|
||||
/* Note that when DOS_BASED is true, IS_ABSOLUTE_PATH accepts d:foo as
|
||||
well, although it is only semi-absolute. This is because the users
|
||||
of IS_ABSOLUTE_PATH want to know whether to prepend the current
|
||||
working directory to a file name, which should not be done with a
|
||||
name like d:foo. */
|
||||
#define IS_ABSOLUTE_PATH_1(dos_based, f) \
|
||||
(IS_DIR_SEPARATOR_1 (dos_based, (f)[0]) \
|
||||
|| HAS_DRIVE_SPEC_1 (dos_based, f))
|
||||
|
||||
extern int filename_cmp (const char *s1, const char *s2);
|
||||
#define FILENAME_CMP(s1, s2) filename_cmp(s1, s2)
|
||||
|
||||
extern int filename_ncmp (const char *s1, const char *s2,
|
||||
size_t n);
|
||||
|
||||
extern hashval_t filename_hash (const void *s);
|
||||
|
||||
extern int filename_eq (const void *s1, const void *s2);
|
||||
|
||||
extern int canonical_filename_eq (const char *a, const char *b);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FILENAMES_H */
|
|
@ -0,0 +1,5 @@
|
|||
# An awk script to determine the type of a file.
|
||||
/\177ELF\001/ { if (NR == 1) { print "elf32"; exit } }
|
||||
/\177ELF\002/ { if (NR == 1) { print "elf64"; exit } }
|
||||
/\114\001/ { if (NR == 1) { print "pecoff"; exit } }
|
||||
/\144\206/ { if (NR == 1) { print "pecoff"; exit } }
|
|
@ -0,0 +1,204 @@
|
|||
/* An expandable hash tables datatype.
|
||||
Copyright (C) 1999-2015 Free Software Foundation, Inc.
|
||||
Contributed by Vladimir Makarov (vmakarov@cygnus.com).
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* This package implements basic hash table functionality. It is possible
|
||||
to search for an entry, create an entry and destroy an entry.
|
||||
|
||||
Elements in the table are generic pointers.
|
||||
|
||||
The size of the table is not fixed; if the occupancy of the table
|
||||
grows too high the hash table will be expanded.
|
||||
|
||||
The abstract data implementation is based on generalized Algorithm D
|
||||
from Knuth's book "The art of computer programming". Hash table is
|
||||
expanded by creation of new hash table and transferring elements from
|
||||
the old table to the new table. */
|
||||
|
||||
#ifndef __HASHTAB_H__
|
||||
#define __HASHTAB_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include "ansidecl.h"
|
||||
|
||||
/* The type for a hash code. */
|
||||
typedef unsigned int hashval_t;
|
||||
|
||||
/* Callback function pointer types. */
|
||||
|
||||
/* Calculate hash of a table entry. */
|
||||
typedef hashval_t (*htab_hash) (const void *);
|
||||
|
||||
/* Compare a table entry with a possible entry. The entry already in
|
||||
the table always comes first, so the second element can be of a
|
||||
different type (but in this case htab_find and htab_find_slot
|
||||
cannot be used; instead the variants that accept a hash value
|
||||
must be used). */
|
||||
typedef int (*htab_eq) (const void *, const void *);
|
||||
|
||||
/* Cleanup function called whenever a live element is removed from
|
||||
the hash table. */
|
||||
typedef void (*htab_del) (void *);
|
||||
|
||||
/* Function called by htab_traverse for each live element. The first
|
||||
arg is the slot of the element (which can be passed to htab_clear_slot
|
||||
if desired), the second arg is the auxiliary pointer handed to
|
||||
htab_traverse. Return 1 to continue scan, 0 to stop. */
|
||||
typedef int (*htab_trav) (void **, void *);
|
||||
|
||||
/* Memory-allocation function, with the same functionality as calloc().
|
||||
Iff it returns NULL, the hash table implementation will pass an error
|
||||
code back to the user, so if your code doesn't handle errors,
|
||||
best if you use xcalloc instead. */
|
||||
typedef void *(*htab_alloc) (size_t, size_t);
|
||||
|
||||
/* We also need a free() routine. */
|
||||
typedef void (*htab_free) (void *);
|
||||
|
||||
/* Memory allocation and deallocation; variants which take an extra
|
||||
argument. */
|
||||
typedef void *(*htab_alloc_with_arg) (void *, size_t, size_t);
|
||||
typedef void (*htab_free_with_arg) (void *, void *);
|
||||
|
||||
/* This macro defines reserved value for empty table entry. */
|
||||
|
||||
#define HTAB_EMPTY_ENTRY ((PTR) 0)
|
||||
|
||||
/* This macro defines reserved value for table entry which contained
|
||||
a deleted element. */
|
||||
|
||||
#define HTAB_DELETED_ENTRY ((PTR) 1)
|
||||
|
||||
/* Hash tables are of the following type. The structure
|
||||
(implementation) of this type is not needed for using the hash
|
||||
tables. All work with hash table should be executed only through
|
||||
functions mentioned below. The size of this structure is subject to
|
||||
change. */
|
||||
|
||||
struct htab {
|
||||
/* Pointer to hash function. */
|
||||
htab_hash hash_f;
|
||||
|
||||
/* Pointer to comparison function. */
|
||||
htab_eq eq_f;
|
||||
|
||||
/* Pointer to cleanup function. */
|
||||
htab_del del_f;
|
||||
|
||||
/* Table itself. */
|
||||
void **entries;
|
||||
|
||||
/* Current size (in entries) of the hash table. */
|
||||
size_t size;
|
||||
|
||||
/* Current number of elements including also deleted elements. */
|
||||
size_t n_elements;
|
||||
|
||||
/* Current number of deleted elements in the table. */
|
||||
size_t n_deleted;
|
||||
|
||||
/* The following member is used for debugging. Its value is number
|
||||
of all calls of `htab_find_slot' for the hash table. */
|
||||
unsigned int searches;
|
||||
|
||||
/* The following member is used for debugging. Its value is number
|
||||
of collisions fixed for time of work with the hash table. */
|
||||
unsigned int collisions;
|
||||
|
||||
/* Pointers to allocate/free functions. */
|
||||
htab_alloc alloc_f;
|
||||
htab_free free_f;
|
||||
|
||||
/* Alternate allocate/free functions, which take an extra argument. */
|
||||
void *alloc_arg;
|
||||
htab_alloc_with_arg alloc_with_arg_f;
|
||||
htab_free_with_arg free_with_arg_f;
|
||||
|
||||
/* Current size (in entries) of the hash table, as an index into the
|
||||
table of primes. */
|
||||
unsigned int size_prime_index;
|
||||
};
|
||||
|
||||
typedef struct htab *htab_t;
|
||||
|
||||
/* An enum saying whether we insert into the hash table or not. */
|
||||
enum insert_option {NO_INSERT, INSERT};
|
||||
|
||||
/* The prototypes of the package functions. */
|
||||
|
||||
extern htab_t htab_create_alloc (size_t, htab_hash,
|
||||
htab_eq, htab_del,
|
||||
htab_alloc, htab_free);
|
||||
|
||||
extern htab_t htab_create_alloc_ex (size_t, htab_hash,
|
||||
htab_eq, htab_del,
|
||||
void *, htab_alloc_with_arg,
|
||||
htab_free_with_arg);
|
||||
|
||||
extern htab_t htab_create_typed_alloc (size_t, htab_hash, htab_eq, htab_del,
|
||||
htab_alloc, htab_alloc, htab_free);
|
||||
|
||||
/* Backward-compatibility functions. */
|
||||
extern htab_t htab_create (size_t, htab_hash, htab_eq, htab_del);
|
||||
extern htab_t htab_try_create (size_t, htab_hash, htab_eq, htab_del);
|
||||
|
||||
extern void htab_set_functions_ex (htab_t, htab_hash,
|
||||
htab_eq, htab_del,
|
||||
void *, htab_alloc_with_arg,
|
||||
htab_free_with_arg);
|
||||
|
||||
extern void htab_delete (htab_t);
|
||||
extern void htab_empty (htab_t);
|
||||
|
||||
extern void * htab_find (htab_t, const void *);
|
||||
extern void ** htab_find_slot (htab_t, const void *, enum insert_option);
|
||||
extern void * htab_find_with_hash (htab_t, const void *, hashval_t);
|
||||
extern void ** htab_find_slot_with_hash (htab_t, const void *,
|
||||
hashval_t, enum insert_option);
|
||||
extern void htab_clear_slot (htab_t, void **);
|
||||
extern void htab_remove_elt (htab_t, void *);
|
||||
extern void htab_remove_elt_with_hash (htab_t, void *, hashval_t);
|
||||
|
||||
extern void htab_traverse (htab_t, htab_trav, void *);
|
||||
extern void htab_traverse_noresize (htab_t, htab_trav, void *);
|
||||
|
||||
extern size_t htab_size (htab_t);
|
||||
extern size_t htab_elements (htab_t);
|
||||
extern double htab_collisions (htab_t);
|
||||
|
||||
/* A hash function for pointers. */
|
||||
extern htab_hash htab_hash_pointer;
|
||||
|
||||
/* An equality function for pointers. */
|
||||
extern htab_eq htab_eq_pointer;
|
||||
|
||||
/* A hash function for null-terminated strings. */
|
||||
extern hashval_t htab_hash_string (const void *);
|
||||
|
||||
/* An iterative hash function for arbitrary data. */
|
||||
extern hashval_t iterative_hash (const void *, size_t, hashval_t);
|
||||
/* Shorthand for hashing something with an intrinsic size. */
|
||||
#define iterative_hash_object(OB,INIT) iterative_hash (&OB, sizeof (OB), INIT)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __HASHTAB_H */
|
|
@ -0,0 +1,501 @@
|
|||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2013-12-25.23; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,294 @@
|
|||
/* internal.h -- Internal header file for stack backtrace library.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#ifndef BACKTRACE_INTERNAL_H
|
||||
#define BACKTRACE_INTERNAL_H
|
||||
|
||||
/* We assume that <sys/types.h> and "backtrace.h" have already been
|
||||
included. */
|
||||
|
||||
#ifndef GCC_VERSION
|
||||
# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
|
||||
#endif
|
||||
|
||||
#if (GCC_VERSION < 2007)
|
||||
# define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_MALLOC
|
||||
# if (GCC_VERSION >= 2096)
|
||||
# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
|
||||
# else
|
||||
# define ATTRIBUTE_MALLOC
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SYNC_FUNCTIONS
|
||||
|
||||
/* Define out the sync functions. These should never be called if
|
||||
they are not available. */
|
||||
|
||||
#define __sync_bool_compare_and_swap(A, B, C) (abort(), 1)
|
||||
#define __sync_lock_test_and_set(A, B) (abort(), 0)
|
||||
#define __sync_lock_release(A) abort()
|
||||
|
||||
#endif /* !defined (HAVE_SYNC_FUNCTIONS) */
|
||||
|
||||
#ifdef HAVE_ATOMIC_FUNCTIONS
|
||||
|
||||
/* We have the atomic builtin functions. */
|
||||
|
||||
#define backtrace_atomic_load_pointer(p) \
|
||||
__atomic_load_n ((p), __ATOMIC_ACQUIRE)
|
||||
#define backtrace_atomic_load_int(p) \
|
||||
__atomic_load_n ((p), __ATOMIC_ACQUIRE)
|
||||
#define backtrace_atomic_store_pointer(p, v) \
|
||||
__atomic_store_n ((p), (v), __ATOMIC_RELEASE)
|
||||
#define backtrace_atomic_store_size_t(p, v) \
|
||||
__atomic_store_n ((p), (v), __ATOMIC_RELEASE)
|
||||
#define backtrace_atomic_store_int(p, v) \
|
||||
__atomic_store_n ((p), (v), __ATOMIC_RELEASE)
|
||||
|
||||
#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */
|
||||
#ifdef HAVE_SYNC_FUNCTIONS
|
||||
|
||||
/* We have the sync functions but not the atomic functions. Define
|
||||
the atomic ones in terms of the sync ones. */
|
||||
|
||||
extern void *backtrace_atomic_load_pointer (void *);
|
||||
extern int backtrace_atomic_load_int (int *);
|
||||
extern void backtrace_atomic_store_pointer (void *, void *);
|
||||
extern void backtrace_atomic_store_size_t (size_t *, size_t);
|
||||
extern void backtrace_atomic_store_int (int *, int);
|
||||
|
||||
#else /* !defined (HAVE_SYNC_FUNCTIONS) */
|
||||
|
||||
/* We have neither the sync nor the atomic functions. These will
|
||||
never be called. */
|
||||
|
||||
#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL)
|
||||
#define backtrace_atomic_load_int(p) (abort(), 0)
|
||||
#define backtrace_atomic_store_pointer(p, v) abort()
|
||||
#define backtrace_atomic_store_size_t(p, v) abort()
|
||||
#define backtrace_atomic_store_int(p, v) abort()
|
||||
|
||||
#endif /* !defined (HAVE_SYNC_FUNCTIONS) */
|
||||
#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */
|
||||
|
||||
/* The type of the function that collects file/line information. This
|
||||
is like backtrace_pcinfo. */
|
||||
|
||||
typedef int (*fileline) (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback, void *data);
|
||||
|
||||
/* The type of the function that collects symbol information. This is
|
||||
like backtrace_syminfo. */
|
||||
|
||||
typedef void (*syminfo) (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_syminfo_callback callback,
|
||||
backtrace_error_callback error_callback, void *data);
|
||||
|
||||
/* What the backtrace state pointer points to. */
|
||||
|
||||
struct backtrace_state
|
||||
{
|
||||
/* The name of the executable. */
|
||||
const char *filename;
|
||||
/* Non-zero if threaded. */
|
||||
int threaded;
|
||||
/* The master lock for fileline_fn, fileline_data, syminfo_fn,
|
||||
syminfo_data, fileline_initialization_failed and everything the
|
||||
data pointers point to. */
|
||||
void *lock;
|
||||
/* The function that returns file/line information. */
|
||||
fileline fileline_fn;
|
||||
/* The data to pass to FILELINE_FN. */
|
||||
void *fileline_data;
|
||||
/* The function that returns symbol information. */
|
||||
syminfo syminfo_fn;
|
||||
/* The data to pass to SYMINFO_FN. */
|
||||
void *syminfo_data;
|
||||
/* Whether initializing the file/line information failed. */
|
||||
int fileline_initialization_failed;
|
||||
/* The lock for the freelist. */
|
||||
int lock_alloc;
|
||||
/* The freelist when using mmap. */
|
||||
struct backtrace_freelist_struct *freelist;
|
||||
};
|
||||
|
||||
/* Open a file for reading. Returns -1 on error. If DOES_NOT_EXIST
|
||||
is not NULL, *DOES_NOT_EXIST will be set to 0 normally and set to 1
|
||||
if the file does not exist. If the file does not exist and
|
||||
DOES_NOT_EXIST is not NULL, the function will return -1 and will
|
||||
not call ERROR_CALLBACK. On other errors, or if DOES_NOT_EXIST is
|
||||
NULL, the function will call ERROR_CALLBACK before returning. */
|
||||
extern int backtrace_open (const char *filename,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data,
|
||||
int *does_not_exist);
|
||||
|
||||
/* A view of the contents of a file. This supports mmap when
|
||||
available. A view will remain in memory even after backtrace_close
|
||||
is called on the file descriptor from which the view was
|
||||
obtained. */
|
||||
|
||||
struct backtrace_view
|
||||
{
|
||||
/* The data that the caller requested. */
|
||||
const void *data;
|
||||
/* The base of the view. */
|
||||
void *base;
|
||||
/* The total length of the view. */
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. Store the
|
||||
result in *VIEW. Returns 1 on success, 0 on error. */
|
||||
extern int backtrace_get_view (struct backtrace_state *state, int descriptor,
|
||||
off_t offset, size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, struct backtrace_view *view);
|
||||
|
||||
/* Release a view created by backtrace_get_view. */
|
||||
extern void backtrace_release_view (struct backtrace_state *state,
|
||||
struct backtrace_view *view,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* Close a file opened by backtrace_open. Returns 1 on success, 0 on
|
||||
error. */
|
||||
|
||||
extern int backtrace_close (int descriptor,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* Sort without using memory. */
|
||||
|
||||
extern void backtrace_qsort (void *base, size_t count, size_t size,
|
||||
int (*compar) (const void *, const void *));
|
||||
|
||||
/* Allocate memory. This is like malloc. If ERROR_CALLBACK is NULL,
|
||||
this does not report an error, it just returns NULL. */
|
||||
|
||||
extern void *backtrace_alloc (struct backtrace_state *state, size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data) ATTRIBUTE_MALLOC;
|
||||
|
||||
/* Free memory allocated by backtrace_alloc. If ERROR_CALLBACK is
|
||||
NULL, this does not report an error. */
|
||||
|
||||
extern void backtrace_free (struct backtrace_state *state, void *mem,
|
||||
size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* A growable vector of some struct. This is used for more efficient
|
||||
allocation when we don't know the final size of some group of data
|
||||
that we want to represent as an array. */
|
||||
|
||||
struct backtrace_vector
|
||||
{
|
||||
/* The base of the vector. */
|
||||
void *base;
|
||||
/* The number of bytes in the vector. */
|
||||
size_t size;
|
||||
/* The number of bytes available at the current allocation. */
|
||||
size_t alc;
|
||||
};
|
||||
|
||||
/* Grow VEC by SIZE bytes. Return a pointer to the newly allocated
|
||||
bytes. Note that this may move the entire vector to a new memory
|
||||
location. Returns NULL on failure. */
|
||||
|
||||
extern void *backtrace_vector_grow (struct backtrace_state *state, size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data,
|
||||
struct backtrace_vector *vec);
|
||||
|
||||
/* Finish the current allocation on VEC. Prepare to start a new
|
||||
allocation. The finished allocation will never be freed. Returns
|
||||
a pointer to the base of the finished entries, or NULL on
|
||||
failure. */
|
||||
|
||||
extern void* backtrace_vector_finish (struct backtrace_state *state,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* Release any extra space allocated for VEC. This may change
|
||||
VEC->base. Returns 1 on success, 0 on failure. */
|
||||
|
||||
extern int backtrace_vector_release (struct backtrace_state *state,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* Read initial debug data from a descriptor, and set the
|
||||
fileline_data, syminfo_fn, and syminfo_data fields of STATE.
|
||||
Return the fileln_fn field in *FILELN_FN--this is done this way so
|
||||
that the synchronization code is only implemented once. This is
|
||||
called after the descriptor has first been opened. It will close
|
||||
the descriptor if it is no longer needed. Returns 1 on success, 0
|
||||
on error. There will be multiple implementations of this function,
|
||||
for different file formats. Each system will compile the
|
||||
appropriate one. */
|
||||
|
||||
extern int backtrace_initialize (struct backtrace_state *state,
|
||||
int descriptor,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data,
|
||||
fileline *fileline_fn);
|
||||
|
||||
/* Add file/line information for a DWARF module. */
|
||||
|
||||
extern int backtrace_dwarf_add (struct backtrace_state *state,
|
||||
uintptr_t base_address,
|
||||
const unsigned char* dwarf_info,
|
||||
size_t dwarf_info_size,
|
||||
const unsigned char *dwarf_line,
|
||||
size_t dwarf_line_size,
|
||||
const unsigned char *dwarf_abbrev,
|
||||
size_t dwarf_abbrev_size,
|
||||
const unsigned char *dwarf_ranges,
|
||||
size_t dwarf_range_size,
|
||||
const unsigned char *dwarf_str,
|
||||
size_t dwarf_str_size,
|
||||
int is_bigendian,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, fileline *fileline_fn);
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,215 @@
|
|||
#! /bin/sh
|
||||
# Common wrapper for a few potentially missing GNU programs.
|
||||
|
||||
scriptversion=2013-10-28.13; # UTC
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
|
||||
--is-lightweight)
|
||||
# Used by our autoconf macros to check whether the available missing
|
||||
# script is modern enough.
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--run)
|
||||
# Back-compat with the calling convention used by older automake.
|
||||
shift
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
|
||||
to PROGRAM being missing or too old.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal autoconf autoheader autom4te automake makeinfo
|
||||
bison yacc flex lex help2man
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
|
||||
'g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: unknown '$1' option"
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Run the given program, remember its exit status.
|
||||
"$@"; st=$?
|
||||
|
||||
# If it succeeded, we are done.
|
||||
test $st -eq 0 && exit 0
|
||||
|
||||
# Also exit now if we it failed (or wasn't found), and '--version' was
|
||||
# passed; such an option is passed most likely to detect whether the
|
||||
# program is present and works.
|
||||
case $2 in --version|--help) exit $st;; esac
|
||||
|
||||
# Exit code 63 means version mismatch. This often happens when the user
|
||||
# tries to use an ancient version of a tool on a file that requires a
|
||||
# minimum version.
|
||||
if test $st -eq 63; then
|
||||
msg="probably too old"
|
||||
elif test $st -eq 127; then
|
||||
# Program was missing.
|
||||
msg="missing on your system"
|
||||
else
|
||||
# Program was found and executed, but failed. Give up.
|
||||
exit $st
|
||||
fi
|
||||
|
||||
perl_URL=http://www.perl.org/
|
||||
flex_URL=http://flex.sourceforge.net/
|
||||
gnu_software_URL=http://www.gnu.org/software
|
||||
|
||||
program_details ()
|
||||
{
|
||||
case $1 in
|
||||
aclocal|automake)
|
||||
echo "The '$1' program is part of the GNU Automake package:"
|
||||
echo "<$gnu_software_URL/automake>"
|
||||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/autoconf>"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
autoconf|autom4te|autoheader)
|
||||
echo "The '$1' program is part of the GNU Autoconf package:"
|
||||
echo "<$gnu_software_URL/autoconf/>"
|
||||
echo "It also requires GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice ()
|
||||
{
|
||||
# Normalize program name to check for.
|
||||
normalized_program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
printf '%s\n' "'$1' is $msg."
|
||||
|
||||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
|
||||
case $normalized_program in
|
||||
autoconf*)
|
||||
echo "You should only need it if you modified 'configure.ac',"
|
||||
echo "or m4 files included by it."
|
||||
program_details 'autoconf'
|
||||
;;
|
||||
autoheader*)
|
||||
echo "You should only need it if you modified 'acconfig.h' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'autoheader'
|
||||
;;
|
||||
automake*)
|
||||
echo "You should only need it if you modified 'Makefile.am' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'automake'
|
||||
;;
|
||||
aclocal*)
|
||||
echo "You should only need it if you modified 'acinclude.m4' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'aclocal'
|
||||
;;
|
||||
autom4te*)
|
||||
echo "You might have modified some maintainer files that require"
|
||||
echo "the 'autom4te' program to be rebuilt."
|
||||
program_details 'autom4te'
|
||||
;;
|
||||
bison*|yacc*)
|
||||
echo "You should only need it if you modified a '.y' file."
|
||||
echo "You may want to install the GNU Bison package:"
|
||||
echo "<$gnu_software_URL/bison/>"
|
||||
;;
|
||||
lex*|flex*)
|
||||
echo "You should only need it if you modified a '.l' file."
|
||||
echo "You may want to install the Fast Lexical Analyzer package:"
|
||||
echo "<$flex_URL>"
|
||||
;;
|
||||
help2man*)
|
||||
echo "You should only need it if you modified a dependency" \
|
||||
"of a man page."
|
||||
echo "You may want to install the GNU Help2man package:"
|
||||
echo "<$gnu_software_URL/help2man/>"
|
||||
;;
|
||||
makeinfo*)
|
||||
echo "You should only need it if you modified a '.texi' file, or"
|
||||
echo "any other file indirectly affecting the aspect of the manual."
|
||||
echo "You might want to install the Texinfo package:"
|
||||
echo "<$gnu_software_URL/texinfo/>"
|
||||
echo "The spurious makeinfo call might also be the consequence of"
|
||||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
|
||||
echo "want to install GNU make:"
|
||||
echo "<$gnu_software_URL/make/>"
|
||||
;;
|
||||
*)
|
||||
echo "You might have modified some files without having the proper"
|
||||
echo "tools for further handling them. Check the 'README' file, it"
|
||||
echo "often tells you about the needed prerequisites for installing"
|
||||
echo "this package. You may also peek at any GNU archive site, in"
|
||||
echo "case some other package contains this missing '$1' program."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice "$1" | sed -e '1s/^/WARNING: /' \
|
||||
-e '2,$s/^/ /' >&2
|
||||
|
||||
# Propagate the correct exit status (expected to be 127 for a program
|
||||
# not found, 63 for a program that failed due to version mismatch).
|
||||
exit $st
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,303 @@
|
|||
/* mmap.c -- Memory allocation with mmap.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Memory allocation on systems that provide anonymous mmap. This
|
||||
permits the backtrace functions to be invoked from a signal
|
||||
handler, assuming that mmap is async-signal safe. */
|
||||
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED ((void *)-1)
|
||||
#endif
|
||||
|
||||
/* A list of free memory blocks. */
|
||||
|
||||
struct backtrace_freelist_struct
|
||||
{
|
||||
/* Next on list. */
|
||||
struct backtrace_freelist_struct *next;
|
||||
/* Size of this block, including this structure. */
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* Free memory allocated by backtrace_alloc. */
|
||||
|
||||
static void
|
||||
backtrace_free_locked (struct backtrace_state *state, void *addr, size_t size)
|
||||
{
|
||||
/* Just leak small blocks. We don't have to be perfect. */
|
||||
if (size >= sizeof (struct backtrace_freelist_struct))
|
||||
{
|
||||
struct backtrace_freelist_struct *p;
|
||||
|
||||
p = (struct backtrace_freelist_struct *) addr;
|
||||
p->next = state->freelist;
|
||||
p->size = size;
|
||||
state->freelist = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't
|
||||
report an error. */
|
||||
|
||||
void *
|
||||
backtrace_alloc (struct backtrace_state *state,
|
||||
size_t size, backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
void *ret;
|
||||
int locked;
|
||||
struct backtrace_freelist_struct **pp;
|
||||
size_t pagesize;
|
||||
size_t asksize;
|
||||
void *page;
|
||||
|
||||
ret = NULL;
|
||||
|
||||
/* If we can acquire the lock, then see if there is space on the
|
||||
free list. If we can't acquire the lock, drop straight into
|
||||
using mmap. __sync_lock_test_and_set returns the old state of
|
||||
the lock, so we have acquired it if it returns 0. */
|
||||
|
||||
if (!state->threaded)
|
||||
locked = 1;
|
||||
else
|
||||
locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0;
|
||||
|
||||
if (locked)
|
||||
{
|
||||
for (pp = &state->freelist; *pp != NULL; pp = &(*pp)->next)
|
||||
{
|
||||
if ((*pp)->size >= size)
|
||||
{
|
||||
struct backtrace_freelist_struct *p;
|
||||
|
||||
p = *pp;
|
||||
*pp = p->next;
|
||||
|
||||
/* Round for alignment; we assume that no type we care about
|
||||
is more than 8 bytes. */
|
||||
size = (size + 7) & ~ (size_t) 7;
|
||||
if (size < p->size)
|
||||
backtrace_free_locked (state, (char *) p + size,
|
||||
p->size - size);
|
||||
|
||||
ret = (void *) p;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->threaded)
|
||||
__sync_lock_release (&state->lock_alloc);
|
||||
}
|
||||
|
||||
if (ret == NULL)
|
||||
{
|
||||
/* Allocate a new page. */
|
||||
|
||||
pagesize = getpagesize ();
|
||||
asksize = (size + pagesize - 1) & ~ (pagesize - 1);
|
||||
page = mmap (NULL, asksize, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (page == MAP_FAILED)
|
||||
{
|
||||
if (error_callback)
|
||||
error_callback (data, "mmap", errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
size = (size + 7) & ~ (size_t) 7;
|
||||
if (size < asksize)
|
||||
backtrace_free (state, (char *) page + size, asksize - size,
|
||||
error_callback, data);
|
||||
|
||||
ret = page;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Free memory allocated by backtrace_alloc. */
|
||||
|
||||
void
|
||||
backtrace_free (struct backtrace_state *state, void *addr, size_t size,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
int locked;
|
||||
|
||||
/* If we are freeing a large aligned block, just release it back to
|
||||
the system. This case arises when growing a vector for a large
|
||||
binary with lots of debug info. Calling munmap here may cause us
|
||||
to call mmap again if there is also a large shared library; we
|
||||
just live with that. */
|
||||
if (size >= 16 * 4096)
|
||||
{
|
||||
size_t pagesize;
|
||||
|
||||
pagesize = getpagesize ();
|
||||
if (((uintptr_t) addr & (pagesize - 1)) == 0
|
||||
&& (size & (pagesize - 1)) == 0)
|
||||
{
|
||||
/* If munmap fails for some reason, just add the block to
|
||||
the freelist. */
|
||||
if (munmap (addr, size) == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we can acquire the lock, add the new space to the free list.
|
||||
If we can't acquire the lock, just leak the memory.
|
||||
__sync_lock_test_and_set returns the old state of the lock, so we
|
||||
have acquired it if it returns 0. */
|
||||
|
||||
if (!state->threaded)
|
||||
locked = 1;
|
||||
else
|
||||
locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0;
|
||||
|
||||
if (locked)
|
||||
{
|
||||
backtrace_free_locked (state, addr, size);
|
||||
|
||||
if (state->threaded)
|
||||
__sync_lock_release (&state->lock_alloc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Grow VEC by SIZE bytes. */
|
||||
|
||||
void *
|
||||
backtrace_vector_grow (struct backtrace_state *state,size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, struct backtrace_vector *vec)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (size > vec->alc)
|
||||
{
|
||||
size_t pagesize;
|
||||
size_t alc;
|
||||
void *base;
|
||||
|
||||
pagesize = getpagesize ();
|
||||
alc = vec->size + size;
|
||||
if (vec->size == 0)
|
||||
alc = 16 * size;
|
||||
else if (alc < pagesize)
|
||||
{
|
||||
alc *= 2;
|
||||
if (alc > pagesize)
|
||||
alc = pagesize;
|
||||
}
|
||||
else
|
||||
{
|
||||
alc *= 2;
|
||||
alc = (alc + pagesize - 1) & ~ (pagesize - 1);
|
||||
}
|
||||
base = backtrace_alloc (state, alc, error_callback, data);
|
||||
if (base == NULL)
|
||||
return NULL;
|
||||
if (vec->base != NULL)
|
||||
{
|
||||
memcpy (base, vec->base, vec->size);
|
||||
backtrace_free (state, vec->base, vec->size + vec->alc,
|
||||
error_callback, data);
|
||||
}
|
||||
vec->base = base;
|
||||
vec->alc = alc - vec->size;
|
||||
}
|
||||
|
||||
ret = (char *) vec->base + vec->size;
|
||||
vec->size += size;
|
||||
vec->alc -= size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Finish the current allocation on VEC. */
|
||||
|
||||
void *
|
||||
backtrace_vector_finish (
|
||||
struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
ret = vec->base;
|
||||
vec->base = (char *) vec->base + vec->size;
|
||||
vec->size = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Release any extra space allocated for VEC. */
|
||||
|
||||
int
|
||||
backtrace_vector_release (struct backtrace_state *state,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
size_t size;
|
||||
size_t alc;
|
||||
size_t aligned;
|
||||
|
||||
/* Make sure that the block that we free is aligned on an 8-byte
|
||||
boundary. */
|
||||
size = vec->size;
|
||||
alc = vec->alc;
|
||||
aligned = (size + 7) & ~ (size_t) 7;
|
||||
alc -= aligned - size;
|
||||
|
||||
backtrace_free (state, (char *) vec->base + aligned, alc,
|
||||
error_callback, data);
|
||||
vec->alc = 0;
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/* mmapio.c -- File views using mmap.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED ((void *)-1)
|
||||
#endif
|
||||
|
||||
/* This file implements file views and memory allocation when mmap is
|
||||
available. */
|
||||
|
||||
/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */
|
||||
|
||||
int
|
||||
backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
int descriptor, off_t offset, size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, struct backtrace_view *view)
|
||||
{
|
||||
size_t pagesize;
|
||||
unsigned int inpage;
|
||||
off_t pageoff;
|
||||
void *map;
|
||||
|
||||
pagesize = getpagesize ();
|
||||
inpage = offset % pagesize;
|
||||
pageoff = offset - inpage;
|
||||
|
||||
size += inpage;
|
||||
size = (size + (pagesize - 1)) & ~ (pagesize - 1);
|
||||
|
||||
map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff);
|
||||
if (map == MAP_FAILED)
|
||||
{
|
||||
error_callback (data, "mmap", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
view->data = (char *) map + inpage;
|
||||
view->base = map;
|
||||
view->len = size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Release a view read by backtrace_get_view. */
|
||||
|
||||
void
|
||||
backtrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
struct backtrace_view *view,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
union {
|
||||
const void *cv;
|
||||
void *v;
|
||||
} const_cast;
|
||||
|
||||
const_cast.cv = view->base;
|
||||
if (munmap (const_cast.v, view->len) < 0)
|
||||
error_callback (data, "munmap", errno);
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/* backtrace.c -- Entry point for stack backtrace library.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/* This source file is compiled if the unwind library is not
|
||||
available. */
|
||||
|
||||
int
|
||||
backtrace_full (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
int skip ATTRIBUTE_UNUSED,
|
||||
backtrace_full_callback callback ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
error_callback (data,
|
||||
"no stack trace because unwind library not available",
|
||||
0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
backtrace_simple (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
int skip ATTRIBUTE_UNUSED,
|
||||
backtrace_simple_callback callback ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
error_callback (data,
|
||||
"no stack trace because unwind library not available",
|
||||
0);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,937 @@
|
|||
/* pecoff.c -- Get debug data from a PE/COFFF file for backtraces.
|
||||
Copyright (C) 2015-2016 Free Software Foundation, Inc.
|
||||
Adapted from elf.c by Tristan Gingold, AdaCore.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Coff file header. */
|
||||
|
||||
typedef struct {
|
||||
uint16_t machine;
|
||||
uint16_t number_of_sections;
|
||||
uint32_t time_date_stamp;
|
||||
uint32_t pointer_to_symbol_table;
|
||||
uint32_t number_of_symbols;
|
||||
uint16_t size_of_optional_header;
|
||||
uint16_t characteristics;
|
||||
} b_coff_file_header;
|
||||
|
||||
/* Coff optional header. */
|
||||
|
||||
typedef struct {
|
||||
uint16_t magic;
|
||||
uint8_t major_linker_version;
|
||||
uint8_t minor_linker_version;
|
||||
uint32_t size_of_code;
|
||||
uint32_t size_of_initialized_data;
|
||||
uint32_t size_of_uninitialized_data;
|
||||
uint32_t address_of_entry_point;
|
||||
uint32_t base_of_code;
|
||||
union {
|
||||
struct {
|
||||
uint32_t base_of_data;
|
||||
uint32_t image_base;
|
||||
} pe;
|
||||
struct {
|
||||
uint64_t image_base;
|
||||
} pep;
|
||||
} u;
|
||||
} b_coff_optional_header;
|
||||
|
||||
/* Values of magic in optional header. */
|
||||
|
||||
#define PE_MAGIC 0x10b /* PE32 executable. */
|
||||
#define PEP_MAGIC 0x20b /* PE32+ executable (for 64bit targets). */
|
||||
|
||||
/* Coff section header. */
|
||||
|
||||
typedef struct {
|
||||
char name[8];
|
||||
uint32_t virtual_size;
|
||||
uint32_t virtual_address;
|
||||
uint32_t size_of_raw_data;
|
||||
uint32_t pointer_to_raw_data;
|
||||
uint32_t pointer_to_relocations;
|
||||
uint32_t pointer_to_line_numbers;
|
||||
uint16_t number_of_relocations;
|
||||
uint16_t number_of_line_numbers;
|
||||
uint32_t characteristics;
|
||||
} b_coff_section_header;
|
||||
|
||||
/* Coff symbol name. */
|
||||
|
||||
typedef union {
|
||||
char short_name[8];
|
||||
struct {
|
||||
unsigned char zeroes[4];
|
||||
unsigned char off[4];
|
||||
} long_name;
|
||||
} b_coff_name;
|
||||
|
||||
/* Coff symbol (external representation which is unaligned). */
|
||||
|
||||
typedef struct {
|
||||
b_coff_name name;
|
||||
unsigned char value[4];
|
||||
unsigned char section_number[2];
|
||||
unsigned char type[2];
|
||||
unsigned char storage_class;
|
||||
unsigned char number_of_aux_symbols;
|
||||
} b_coff_external_symbol;
|
||||
|
||||
/* Symbol types. */
|
||||
|
||||
#define N_TBSHFT 4 /* Shift for the derived type. */
|
||||
#define IMAGE_SYM_DTYPE_FUNCTION 2 /* Function derived type. */
|
||||
|
||||
/* Size of a coff symbol. */
|
||||
|
||||
#define SYM_SZ 18
|
||||
|
||||
/* Coff symbol, internal representation (aligned). */
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
uint32_t value;
|
||||
int16_t sec;
|
||||
uint16_t type;
|
||||
uint16_t sc;
|
||||
} b_coff_internal_symbol;
|
||||
|
||||
/* An index of sections we care about. */
|
||||
|
||||
enum debug_section
|
||||
{
|
||||
DEBUG_INFO,
|
||||
DEBUG_LINE,
|
||||
DEBUG_ABBREV,
|
||||
DEBUG_RANGES,
|
||||
DEBUG_STR,
|
||||
DEBUG_MAX
|
||||
};
|
||||
|
||||
/* Names of sections, indexed by enum debug_section. */
|
||||
|
||||
static const char * const debug_section_names[DEBUG_MAX] =
|
||||
{
|
||||
".debug_info",
|
||||
".debug_line",
|
||||
".debug_abbrev",
|
||||
".debug_ranges",
|
||||
".debug_str"
|
||||
};
|
||||
|
||||
/* Information we gather for the sections we care about. */
|
||||
|
||||
struct debug_section_info
|
||||
{
|
||||
/* Section file offset. */
|
||||
off_t offset;
|
||||
/* Section size. */
|
||||
size_t size;
|
||||
/* Section contents, after read from file. */
|
||||
const unsigned char *data;
|
||||
};
|
||||
|
||||
/* Information we keep for an coff symbol. */
|
||||
|
||||
struct coff_symbol
|
||||
{
|
||||
/* The name of the symbol. */
|
||||
const char *name;
|
||||
/* The address of the symbol. */
|
||||
uintptr_t address;
|
||||
};
|
||||
|
||||
/* Information to pass to coff_syminfo. */
|
||||
|
||||
struct coff_syminfo_data
|
||||
{
|
||||
/* Symbols for the next module. */
|
||||
struct coff_syminfo_data *next;
|
||||
/* The COFF symbols, sorted by address. */
|
||||
struct coff_symbol *symbols;
|
||||
/* The number of symbols. */
|
||||
size_t count;
|
||||
};
|
||||
|
||||
/* A dummy callback function used when we can't find any debug info. */
|
||||
|
||||
static int
|
||||
coff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
uintptr_t pc ATTRIBUTE_UNUSED,
|
||||
backtrace_full_callback callback ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
error_callback (data, "no debug info in PE/COFF executable", -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A dummy callback function used when we can't find a symbol
|
||||
table. */
|
||||
|
||||
static void
|
||||
coff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
uintptr_t addr ATTRIBUTE_UNUSED,
|
||||
backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
error_callback (data, "no symbol table in PE/COFF executable", -1);
|
||||
}
|
||||
|
||||
/* Read a potentially unaligned 4 byte word at P, using native endianness. */
|
||||
|
||||
static uint32_t
|
||||
coff_read4 (const unsigned char *p)
|
||||
{
|
||||
uint32_t res;
|
||||
|
||||
memcpy (&res, p, 4);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Read a potentially unaligned 2 byte word at P, using native endianness.
|
||||
All 2 byte word in symbols are always aligned, but for coherency all
|
||||
fields are declared as char arrays. */
|
||||
|
||||
static uint16_t
|
||||
coff_read2 (const unsigned char *p)
|
||||
{
|
||||
uint16_t res;
|
||||
|
||||
memcpy (&res, p, sizeof (res));
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Return the length (without the trailing 0) of a COFF short name. */
|
||||
|
||||
static size_t
|
||||
coff_short_name_len (const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
if (name[i] == 0)
|
||||
return i;
|
||||
return 8;
|
||||
}
|
||||
|
||||
/* Return true iff COFF short name CNAME is the same as NAME (a NUL-terminated
|
||||
string). */
|
||||
|
||||
static int
|
||||
coff_short_name_eq (const char *name, const char *cname)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (name[i] != cname[i])
|
||||
return 0;
|
||||
if (name[i] == 0)
|
||||
return 1;
|
||||
}
|
||||
return name[8] == 0;
|
||||
}
|
||||
|
||||
/* Return true iff NAME is the same as string at offset OFF. */
|
||||
|
||||
static int
|
||||
coff_long_name_eq (const char *name, unsigned int off,
|
||||
struct backtrace_view *str_view)
|
||||
{
|
||||
if (off >= str_view->len)
|
||||
return 0;
|
||||
return strcmp (name, (const char *)str_view->data + off) == 0;
|
||||
}
|
||||
|
||||
/* Compare struct coff_symbol for qsort. */
|
||||
|
||||
static int
|
||||
coff_symbol_compare (const void *v1, const void *v2)
|
||||
{
|
||||
const struct coff_symbol *e1 = (const struct coff_symbol *) v1;
|
||||
const struct coff_symbol *e2 = (const struct coff_symbol *) v2;
|
||||
|
||||
if (e1->address < e2->address)
|
||||
return -1;
|
||||
else if (e1->address > e2->address)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert SYM to internal (and aligned) format ISYM, using string table
|
||||
from STRTAB and STRTAB_SIZE, and number of sections SECTS_NUM.
|
||||
Return -1 in case of error (invalid section number or string index). */
|
||||
|
||||
static int
|
||||
coff_expand_symbol (b_coff_internal_symbol *isym,
|
||||
const b_coff_external_symbol *sym,
|
||||
uint16_t sects_num,
|
||||
const unsigned char *strtab, size_t strtab_size)
|
||||
{
|
||||
isym->type = coff_read2 (sym->type);
|
||||
isym->sec = coff_read2 (sym->section_number);
|
||||
isym->sc = sym->storage_class;
|
||||
|
||||
if (isym->sec > 0 && (uint16_t) isym->sec > sects_num)
|
||||
return -1;
|
||||
if (sym->name.short_name[0] != 0)
|
||||
isym->name = sym->name.short_name;
|
||||
else
|
||||
{
|
||||
uint32_t off = coff_read4 (sym->name.long_name.off);
|
||||
|
||||
if (off >= strtab_size)
|
||||
return -1;
|
||||
isym->name = (const char *) strtab + off;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return true iff SYM is a defined symbol for a function. Data symbols
|
||||
aren't considered because they aren't easily identified (same type as
|
||||
section names, presence of symbols defined by the linker script). */
|
||||
|
||||
static int
|
||||
coff_is_function_symbol (const b_coff_internal_symbol *isym)
|
||||
{
|
||||
return (isym->type >> N_TBSHFT) == IMAGE_SYM_DTYPE_FUNCTION
|
||||
&& isym->sec > 0;
|
||||
}
|
||||
|
||||
/* Initialize the symbol table info for coff_syminfo. */
|
||||
|
||||
static int
|
||||
coff_initialize_syminfo (struct backtrace_state *state,
|
||||
uintptr_t base_address,
|
||||
const b_coff_section_header *sects, size_t sects_num,
|
||||
const b_coff_external_symbol *syms, size_t syms_size,
|
||||
const unsigned char *strtab, size_t strtab_size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, struct coff_syminfo_data *sdata)
|
||||
{
|
||||
size_t syms_count;
|
||||
char *coff_symstr;
|
||||
size_t coff_symstr_len;
|
||||
size_t coff_symbol_count;
|
||||
size_t coff_symbol_size;
|
||||
struct coff_symbol *coff_symbols;
|
||||
struct coff_symbol *coff_sym;
|
||||
char *coff_str;
|
||||
size_t i;
|
||||
|
||||
syms_count = syms_size / SYM_SZ;
|
||||
|
||||
/* We only care about function symbols. Count them. Also count size of
|
||||
strings for in-symbol names. */
|
||||
coff_symbol_count = 0;
|
||||
coff_symstr_len = 0;
|
||||
for (i = 0; i < syms_count; ++i)
|
||||
{
|
||||
const b_coff_external_symbol *asym = &syms[i];
|
||||
b_coff_internal_symbol isym;
|
||||
|
||||
if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size) < 0)
|
||||
{
|
||||
error_callback (data, "invalid section or offset in coff symbol", 0);
|
||||
return 0;
|
||||
}
|
||||
if (coff_is_function_symbol (&isym))
|
||||
{
|
||||
++coff_symbol_count;
|
||||
if (asym->name.short_name[0] != 0)
|
||||
coff_symstr_len += coff_short_name_len (asym->name.short_name) + 1;
|
||||
}
|
||||
|
||||
i += asym->number_of_aux_symbols;
|
||||
}
|
||||
|
||||
coff_symbol_size = (coff_symbol_count + 1) * sizeof (struct coff_symbol);
|
||||
coff_symbols = ((struct coff_symbol *)
|
||||
backtrace_alloc (state, coff_symbol_size, error_callback,
|
||||
data));
|
||||
if (coff_symbols == NULL)
|
||||
return 0;
|
||||
|
||||
/* Allocate memory for symbols strings. */
|
||||
if (coff_symstr_len > 0)
|
||||
{
|
||||
coff_symstr = ((char *)
|
||||
backtrace_alloc (state, coff_symstr_len, error_callback,
|
||||
data));
|
||||
if (coff_symstr == NULL)
|
||||
{
|
||||
backtrace_free (state, coff_symbols, coff_symbol_size,
|
||||
error_callback, data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
coff_symstr = NULL;
|
||||
|
||||
/* Copy symbols. */
|
||||
coff_sym = coff_symbols;
|
||||
coff_str = coff_symstr;
|
||||
for (i = 0; i < syms_count; ++i)
|
||||
{
|
||||
const b_coff_external_symbol *asym = &syms[i];
|
||||
b_coff_internal_symbol isym;
|
||||
|
||||
if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size))
|
||||
{
|
||||
/* Should not fail, as it was already tested in the previous
|
||||
loop. */
|
||||
abort ();
|
||||
}
|
||||
if (coff_is_function_symbol (&isym))
|
||||
{
|
||||
const char *name;
|
||||
int16_t secnum;
|
||||
|
||||
if (asym->name.short_name[0] != 0)
|
||||
{
|
||||
size_t len = coff_short_name_len (isym.name);
|
||||
name = coff_str;
|
||||
memcpy (coff_str, isym.name, len);
|
||||
coff_str[len] = 0;
|
||||
coff_str += len + 1;
|
||||
}
|
||||
else
|
||||
name = isym.name;
|
||||
|
||||
/* Strip leading '_'. */
|
||||
if (name[0] == '_')
|
||||
name++;
|
||||
|
||||
/* Symbol value is section relative, so we need to read the address
|
||||
of its section. */
|
||||
secnum = coff_read2 (asym->section_number);
|
||||
|
||||
coff_sym->name = name;
|
||||
coff_sym->address = (coff_read4 (asym->value)
|
||||
+ sects[secnum - 1].virtual_address
|
||||
+ base_address);
|
||||
coff_sym++;
|
||||
}
|
||||
|
||||
i += asym->number_of_aux_symbols;
|
||||
}
|
||||
|
||||
/* End of symbols marker. */
|
||||
coff_sym->name = NULL;
|
||||
coff_sym->address = -1;
|
||||
|
||||
backtrace_qsort (coff_symbols, coff_symbol_count,
|
||||
sizeof (struct coff_symbol), coff_symbol_compare);
|
||||
|
||||
sdata->next = NULL;
|
||||
sdata->symbols = coff_symbols;
|
||||
sdata->count = coff_symbol_count;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Add EDATA to the list in STATE. */
|
||||
|
||||
static void
|
||||
coff_add_syminfo_data (struct backtrace_state *state,
|
||||
struct coff_syminfo_data *sdata)
|
||||
{
|
||||
if (!state->threaded)
|
||||
{
|
||||
struct coff_syminfo_data **pp;
|
||||
|
||||
for (pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
|
||||
*pp != NULL;
|
||||
pp = &(*pp)->next)
|
||||
;
|
||||
*pp = sdata;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
struct coff_syminfo_data **pp;
|
||||
|
||||
pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct coff_syminfo_data *p;
|
||||
|
||||
p = backtrace_atomic_load_pointer (pp);
|
||||
|
||||
if (p == NULL)
|
||||
break;
|
||||
|
||||
pp = &p->next;
|
||||
}
|
||||
|
||||
if (__sync_bool_compare_and_swap (pp, NULL, sdata))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compare an ADDR against an elf_symbol for bsearch. We allocate one
|
||||
extra entry in the array so that this can look safely at the next
|
||||
entry. */
|
||||
|
||||
static int
|
||||
coff_symbol_search (const void *vkey, const void *ventry)
|
||||
{
|
||||
const uintptr_t *key = (const uintptr_t *) vkey;
|
||||
const struct coff_symbol *entry = (const struct coff_symbol *) ventry;
|
||||
uintptr_t addr;
|
||||
|
||||
addr = *key;
|
||||
if (addr < entry->address)
|
||||
return -1;
|
||||
else if (addr >= entry[1].address)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the symbol name and value for an ADDR. */
|
||||
|
||||
static void
|
||||
coff_syminfo (struct backtrace_state *state, uintptr_t addr,
|
||||
backtrace_syminfo_callback callback,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data)
|
||||
{
|
||||
struct coff_syminfo_data *sdata;
|
||||
struct coff_symbol *sym = NULL;
|
||||
|
||||
if (!state->threaded)
|
||||
{
|
||||
for (sdata = (struct coff_syminfo_data *) state->syminfo_data;
|
||||
sdata != NULL;
|
||||
sdata = sdata->next)
|
||||
{
|
||||
sym = ((struct coff_symbol *)
|
||||
bsearch (&addr, sdata->symbols, sdata->count,
|
||||
sizeof (struct coff_symbol), coff_symbol_search));
|
||||
if (sym != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct coff_syminfo_data **pp;
|
||||
|
||||
pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
|
||||
while (1)
|
||||
{
|
||||
sdata = backtrace_atomic_load_pointer (pp);
|
||||
if (sdata == NULL)
|
||||
break;
|
||||
|
||||
sym = ((struct coff_symbol *)
|
||||
bsearch (&addr, sdata->symbols, sdata->count,
|
||||
sizeof (struct coff_symbol), coff_symbol_search));
|
||||
if (sym != NULL)
|
||||
break;
|
||||
|
||||
pp = &sdata->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (sym == NULL)
|
||||
callback (data, addr, NULL, 0, 0);
|
||||
else
|
||||
callback (data, addr, sym->name, sym->address, 0);
|
||||
}
|
||||
|
||||
/* Add the backtrace data for one PE/COFF file. Returns 1 on success,
|
||||
0 on failure (in both cases descriptor is closed). */
|
||||
|
||||
static int
|
||||
coff_add (struct backtrace_state *state, int descriptor,
|
||||
backtrace_error_callback error_callback, void *data,
|
||||
fileline *fileline_fn, int *found_sym, int *found_dwarf)
|
||||
{
|
||||
struct backtrace_view fhdr_view;
|
||||
off_t fhdr_off;
|
||||
int magic_ok;
|
||||
b_coff_file_header fhdr;
|
||||
off_t opt_sects_off;
|
||||
size_t opt_sects_size;
|
||||
unsigned int sects_num;
|
||||
struct backtrace_view sects_view;
|
||||
int sects_view_valid;
|
||||
const b_coff_optional_header *opt_hdr;
|
||||
const b_coff_section_header *sects;
|
||||
struct backtrace_view str_view;
|
||||
int str_view_valid;
|
||||
size_t str_size;
|
||||
off_t str_off;
|
||||
struct backtrace_view syms_view;
|
||||
off_t syms_off;
|
||||
size_t syms_size;
|
||||
int syms_view_valid;
|
||||
unsigned int syms_num;
|
||||
unsigned int i;
|
||||
struct debug_section_info sections[DEBUG_MAX];
|
||||
off_t min_offset;
|
||||
off_t max_offset;
|
||||
struct backtrace_view debug_view;
|
||||
int debug_view_valid;
|
||||
uintptr_t image_base;
|
||||
|
||||
*found_sym = 0;
|
||||
*found_dwarf = 0;
|
||||
|
||||
sects_view_valid = 0;
|
||||
syms_view_valid = 0;
|
||||
str_view_valid = 0;
|
||||
debug_view_valid = 0;
|
||||
|
||||
/* Map the MS-DOS stub (if any) and extract file header offset. */
|
||||
if (!backtrace_get_view (state, descriptor, 0, 0x40, error_callback,
|
||||
data, &fhdr_view))
|
||||
goto fail;
|
||||
|
||||
{
|
||||
const char *vptr = (const char *)fhdr_view.data;
|
||||
|
||||
if (vptr[0] == 'M' && vptr[1] == 'Z')
|
||||
memcpy (&fhdr_off, vptr + 0x3c, 4);
|
||||
else
|
||||
fhdr_off = 0;
|
||||
}
|
||||
|
||||
backtrace_release_view (state, &fhdr_view, error_callback, data);
|
||||
|
||||
/* Map the coff file header. */
|
||||
if (!backtrace_get_view (state, descriptor, fhdr_off,
|
||||
sizeof (b_coff_file_header) + 4,
|
||||
error_callback, data, &fhdr_view))
|
||||
goto fail;
|
||||
|
||||
if (fhdr_off != 0)
|
||||
{
|
||||
const char *magic = (const char *) fhdr_view.data;
|
||||
magic_ok = memcmp (magic, "PE\0", 4) == 0;
|
||||
fhdr_off += 4;
|
||||
|
||||
memcpy (&fhdr, fhdr_view.data + 4, sizeof fhdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (&fhdr, fhdr_view.data, sizeof fhdr);
|
||||
/* TODO: test fhdr.machine for coff but non-PE platforms. */
|
||||
magic_ok = 0;
|
||||
}
|
||||
backtrace_release_view (state, &fhdr_view, error_callback, data);
|
||||
|
||||
if (!magic_ok)
|
||||
{
|
||||
error_callback (data, "executable file is not COFF", 0);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sects_num = fhdr.number_of_sections;
|
||||
syms_num = fhdr.number_of_symbols;
|
||||
|
||||
opt_sects_off = fhdr_off + sizeof (fhdr);
|
||||
opt_sects_size = (fhdr.size_of_optional_header
|
||||
+ sects_num * sizeof (b_coff_section_header));
|
||||
|
||||
/* To translate PC to file/line when using DWARF, we need to find
|
||||
the .debug_info and .debug_line sections. */
|
||||
|
||||
/* Read the optional header and the section headers. */
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, opt_sects_off, opt_sects_size,
|
||||
error_callback, data, §s_view))
|
||||
goto fail;
|
||||
sects_view_valid = 1;
|
||||
opt_hdr = (const b_coff_optional_header *) sects_view.data;
|
||||
sects = (const b_coff_section_header *)
|
||||
(sects_view.data + fhdr.size_of_optional_header);
|
||||
|
||||
if (fhdr.size_of_optional_header > sizeof (*opt_hdr))
|
||||
{
|
||||
if (opt_hdr->magic == PE_MAGIC)
|
||||
image_base = opt_hdr->u.pe.image_base;
|
||||
else if (opt_hdr->magic == PEP_MAGIC)
|
||||
image_base = opt_hdr->u.pep.image_base;
|
||||
else
|
||||
{
|
||||
error_callback (data, "bad magic in PE optional header", 0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else
|
||||
image_base = 0;
|
||||
|
||||
/* Read the symbol table and the string table. */
|
||||
|
||||
if (fhdr.pointer_to_symbol_table == 0)
|
||||
{
|
||||
/* No symbol table, no string table. */
|
||||
str_off = 0;
|
||||
str_size = 0;
|
||||
syms_num = 0;
|
||||
syms_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Symbol table is followed by the string table. The string table
|
||||
starts with its length (on 4 bytes).
|
||||
Map the symbol table and the length of the string table. */
|
||||
syms_off = fhdr.pointer_to_symbol_table;
|
||||
syms_size = syms_num * SYM_SZ;
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, syms_off, syms_size + 4,
|
||||
error_callback, data, &syms_view))
|
||||
goto fail;
|
||||
syms_view_valid = 1;
|
||||
|
||||
memcpy (&str_size, syms_view.data + syms_size, 4);
|
||||
|
||||
str_off = syms_off + syms_size;
|
||||
|
||||
if (str_size > 4)
|
||||
{
|
||||
/* Map string table (including the length word). */
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, str_off, str_size,
|
||||
error_callback, data, &str_view))
|
||||
goto fail;
|
||||
str_view_valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
memset (sections, 0, sizeof sections);
|
||||
|
||||
/* Look for the symbol table. */
|
||||
for (i = 0; i < sects_num; ++i)
|
||||
{
|
||||
const b_coff_section_header *s = sects + i;
|
||||
unsigned int str_off;
|
||||
int j;
|
||||
|
||||
if (s->name[0] == '/')
|
||||
{
|
||||
/* Extended section name. */
|
||||
str_off = atoi (s->name + 1);
|
||||
}
|
||||
else
|
||||
str_off = 0;
|
||||
|
||||
for (j = 0; j < (int) DEBUG_MAX; ++j)
|
||||
{
|
||||
const char *dbg_name = debug_section_names[j];
|
||||
int match;
|
||||
|
||||
if (str_off != 0)
|
||||
match = coff_long_name_eq (dbg_name, str_off, &str_view);
|
||||
else
|
||||
match = coff_short_name_eq (dbg_name, s->name);
|
||||
if (match)
|
||||
{
|
||||
sections[j].offset = s->pointer_to_raw_data;
|
||||
sections[j].size = s->virtual_size <= s->size_of_raw_data ?
|
||||
s->virtual_size : s->size_of_raw_data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (syms_num != 0)
|
||||
{
|
||||
struct coff_syminfo_data *sdata;
|
||||
|
||||
sdata = ((struct coff_syminfo_data *)
|
||||
backtrace_alloc (state, sizeof *sdata, error_callback, data));
|
||||
if (sdata == NULL)
|
||||
goto fail;
|
||||
|
||||
if (!coff_initialize_syminfo (state, image_base,
|
||||
sects, sects_num,
|
||||
syms_view.data, syms_size,
|
||||
str_view.data, str_size,
|
||||
error_callback, data, sdata))
|
||||
{
|
||||
backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*found_sym = 1;
|
||||
|
||||
coff_add_syminfo_data (state, sdata);
|
||||
}
|
||||
|
||||
backtrace_release_view (state, §s_view, error_callback, data);
|
||||
sects_view_valid = 0;
|
||||
backtrace_release_view (state, &syms_view, error_callback, data);
|
||||
syms_view_valid = 0;
|
||||
|
||||
/* Read all the debug sections in a single view, since they are
|
||||
probably adjacent in the file. We never release this view. */
|
||||
|
||||
min_offset = 0;
|
||||
max_offset = 0;
|
||||
for (i = 0; i < (int) DEBUG_MAX; ++i)
|
||||
{
|
||||
off_t end;
|
||||
|
||||
if (sections[i].size == 0)
|
||||
continue;
|
||||
if (min_offset == 0 || sections[i].offset < min_offset)
|
||||
min_offset = sections[i].offset;
|
||||
end = sections[i].offset + sections[i].size;
|
||||
if (end > max_offset)
|
||||
max_offset = end;
|
||||
}
|
||||
if (min_offset == 0 || max_offset == 0)
|
||||
{
|
||||
if (!backtrace_close (descriptor, error_callback, data))
|
||||
goto fail;
|
||||
*fileline_fn = coff_nodebug;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!backtrace_get_view (state, descriptor, min_offset,
|
||||
max_offset - min_offset,
|
||||
error_callback, data, &debug_view))
|
||||
goto fail;
|
||||
debug_view_valid = 1;
|
||||
|
||||
/* We've read all we need from the executable. */
|
||||
if (!backtrace_close (descriptor, error_callback, data))
|
||||
goto fail;
|
||||
descriptor = -1;
|
||||
|
||||
for (i = 0; i < (int) DEBUG_MAX; ++i)
|
||||
{
|
||||
if (sections[i].size == 0)
|
||||
sections[i].data = NULL;
|
||||
else
|
||||
sections[i].data = ((const unsigned char *) debug_view.data
|
||||
+ (sections[i].offset - min_offset));
|
||||
}
|
||||
|
||||
if (!backtrace_dwarf_add (state, /* base_address */ 0,
|
||||
sections[DEBUG_INFO].data,
|
||||
sections[DEBUG_INFO].size,
|
||||
sections[DEBUG_LINE].data,
|
||||
sections[DEBUG_LINE].size,
|
||||
sections[DEBUG_ABBREV].data,
|
||||
sections[DEBUG_ABBREV].size,
|
||||
sections[DEBUG_RANGES].data,
|
||||
sections[DEBUG_RANGES].size,
|
||||
sections[DEBUG_STR].data,
|
||||
sections[DEBUG_STR].size,
|
||||
0, /* FIXME */
|
||||
error_callback, data, fileline_fn))
|
||||
goto fail;
|
||||
|
||||
*found_dwarf = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (sects_view_valid)
|
||||
backtrace_release_view (state, §s_view, error_callback, data);
|
||||
if (str_view_valid)
|
||||
backtrace_release_view (state, &str_view, error_callback, data);
|
||||
if (syms_view_valid)
|
||||
backtrace_release_view (state, &syms_view, error_callback, data);
|
||||
if (debug_view_valid)
|
||||
backtrace_release_view (state, &debug_view, error_callback, data);
|
||||
if (descriptor != -1)
|
||||
backtrace_close (descriptor, error_callback, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize the backtrace data we need from an ELF executable. At
|
||||
the ELF level, all we need to do is find the debug info
|
||||
sections. */
|
||||
|
||||
int
|
||||
backtrace_initialize (struct backtrace_state *state, int descriptor,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, fileline *fileline_fn)
|
||||
{
|
||||
int ret;
|
||||
int found_sym;
|
||||
int found_dwarf;
|
||||
fileline coff_fileline_fn;
|
||||
|
||||
ret = coff_add (state, descriptor, error_callback, data,
|
||||
&coff_fileline_fn, &found_sym, &found_dwarf);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
if (!state->threaded)
|
||||
{
|
||||
if (found_sym)
|
||||
state->syminfo_fn = coff_syminfo;
|
||||
else if (state->syminfo_fn == NULL)
|
||||
state->syminfo_fn = coff_nosyms;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found_sym)
|
||||
backtrace_atomic_store_pointer (&state->syminfo_fn, coff_syminfo);
|
||||
else
|
||||
__sync_bool_compare_and_swap (&state->syminfo_fn, NULL, coff_nosyms);
|
||||
}
|
||||
|
||||
if (!state->threaded)
|
||||
{
|
||||
if (state->fileline_fn == NULL || state->fileline_fn == coff_nodebug)
|
||||
*fileline_fn = coff_fileline_fn;
|
||||
}
|
||||
else
|
||||
{
|
||||
fileline current_fn;
|
||||
|
||||
current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
|
||||
if (current_fn == NULL || current_fn == coff_nodebug)
|
||||
*fileline_fn = coff_fileline_fn;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/* posix.c -- POSIX file I/O routines for the backtrace library.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
#ifndef FD_CLOEXEC
|
||||
#define FD_CLOEXEC 1
|
||||
#endif
|
||||
|
||||
/* Open a file for reading. */
|
||||
|
||||
int
|
||||
backtrace_open (const char *filename, backtrace_error_callback error_callback,
|
||||
void *data, int *does_not_exist)
|
||||
{
|
||||
int descriptor;
|
||||
|
||||
if (does_not_exist != NULL)
|
||||
*does_not_exist = 0;
|
||||
|
||||
descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC));
|
||||
if (descriptor < 0)
|
||||
{
|
||||
if (does_not_exist != NULL && errno == ENOENT)
|
||||
*does_not_exist = 1;
|
||||
else
|
||||
error_callback (data, filename, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FCNTL
|
||||
/* Set FD_CLOEXEC just in case the kernel does not support
|
||||
O_CLOEXEC. It doesn't matter if this fails for some reason.
|
||||
FIXME: At some point it should be safe to only do this if
|
||||
O_CLOEXEC == 0. */
|
||||
fcntl (descriptor, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/* Close DESCRIPTOR. */
|
||||
|
||||
int
|
||||
backtrace_close (int descriptor, backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
if (close (descriptor) < 0)
|
||||
{
|
||||
error_callback (data, "close", errno);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/* print.c -- Print the current backtrace.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Passed to callbacks. */
|
||||
|
||||
struct print_data
|
||||
{
|
||||
struct backtrace_state *state;
|
||||
FILE *f;
|
||||
};
|
||||
|
||||
/* Print one level of a backtrace. */
|
||||
|
||||
static int
|
||||
print_callback (void *data, uintptr_t pc, const char *filename, int lineno,
|
||||
const char *function)
|
||||
{
|
||||
struct print_data *pdata = (struct print_data *) data;
|
||||
|
||||
fprintf (pdata->f, "0x%lx %s\n\t%s:%d\n",
|
||||
(unsigned long) pc,
|
||||
function == NULL ? "???" : function,
|
||||
filename == NULL ? "???" : filename,
|
||||
lineno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Print errors to stderr. */
|
||||
|
||||
static void
|
||||
error_callback (void *data, const char *msg, int errnum)
|
||||
{
|
||||
struct print_data *pdata = (struct print_data *) data;
|
||||
|
||||
if (pdata->state->filename != NULL)
|
||||
fprintf (stderr, "%s: ", pdata->state->filename);
|
||||
fprintf (stderr, "libbacktrace: %s", msg);
|
||||
if (errnum > 0)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
|
||||
/* Print a backtrace. */
|
||||
|
||||
void
|
||||
backtrace_print (struct backtrace_state *state, int skip, FILE *f)
|
||||
{
|
||||
struct print_data data;
|
||||
|
||||
data.state = state;
|
||||
data.f = f;
|
||||
backtrace_full (state, skip + 1, print_callback, error_callback,
|
||||
(void *) &data);
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/* read.c -- File views without mmap.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* This file implements file views when mmap is not available. */
|
||||
|
||||
/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */
|
||||
|
||||
int
|
||||
backtrace_get_view (struct backtrace_state *state, int descriptor,
|
||||
off_t offset, size_t size,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data, struct backtrace_view *view)
|
||||
{
|
||||
ssize_t got;
|
||||
|
||||
if (lseek (descriptor, offset, SEEK_SET) < 0)
|
||||
{
|
||||
error_callback (data, "lseek", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
view->base = backtrace_alloc (state, size, error_callback, data);
|
||||
if (view->base == NULL)
|
||||
return 0;
|
||||
view->data = view->base;
|
||||
view->len = size;
|
||||
|
||||
got = read (descriptor, view->base, size);
|
||||
if (got < 0)
|
||||
{
|
||||
error_callback (data, "read", errno);
|
||||
free (view->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((size_t) got < size)
|
||||
{
|
||||
error_callback (data, "file too short", 0);
|
||||
free (view->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Release a view read by backtrace_get_view. */
|
||||
|
||||
void
|
||||
backtrace_release_view (struct backtrace_state *state,
|
||||
struct backtrace_view *view,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
backtrace_free (state, view->base, view->len, error_callback, data);
|
||||
view->data = NULL;
|
||||
view->base = NULL;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/* simple.c -- The backtrace_simple function.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "unwind.h"
|
||||
#include "backtrace.h"
|
||||
|
||||
/* The simple_backtrace routine. */
|
||||
|
||||
/* Data passed through _Unwind_Backtrace. */
|
||||
|
||||
struct backtrace_simple_data
|
||||
{
|
||||
/* Number of frames to skip. */
|
||||
int skip;
|
||||
/* Library state. */
|
||||
struct backtrace_state *state;
|
||||
/* Callback routine. */
|
||||
backtrace_simple_callback callback;
|
||||
/* Error callback routine. */
|
||||
backtrace_error_callback error_callback;
|
||||
/* Data to pass to callback routine. */
|
||||
void *data;
|
||||
/* Value to return from backtrace. */
|
||||
int ret;
|
||||
};
|
||||
|
||||
/* Unwind library callback routine. This is passd to
|
||||
_Unwind_Backtrace. */
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
simple_unwind (struct _Unwind_Context *context, void *vdata)
|
||||
{
|
||||
struct backtrace_simple_data *bdata = (struct backtrace_simple_data *) vdata;
|
||||
uintptr_t pc;
|
||||
int ip_before_insn = 0;
|
||||
|
||||
#ifdef HAVE_GETIPINFO
|
||||
pc = _Unwind_GetIPInfo (context, &ip_before_insn);
|
||||
#else
|
||||
pc = _Unwind_GetIP (context);
|
||||
#endif
|
||||
|
||||
if (bdata->skip > 0)
|
||||
{
|
||||
--bdata->skip;
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
if (!ip_before_insn)
|
||||
--pc;
|
||||
|
||||
bdata->ret = bdata->callback (bdata->data, pc);
|
||||
|
||||
if (bdata->ret != 0)
|
||||
return _URC_END_OF_STACK;
|
||||
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
/* Get a simple stack backtrace. */
|
||||
|
||||
int
|
||||
backtrace_simple (struct backtrace_state *state, int skip,
|
||||
backtrace_simple_callback callback,
|
||||
backtrace_error_callback error_callback, void *data)
|
||||
{
|
||||
struct backtrace_simple_data bdata;
|
||||
|
||||
bdata.skip = skip + 1;
|
||||
bdata.state = state;
|
||||
bdata.callback = callback;
|
||||
bdata.error_callback = error_callback;
|
||||
bdata.data = data;
|
||||
bdata.ret = 0;
|
||||
_Unwind_Backtrace (simple_unwind, &bdata);
|
||||
return bdata.ret;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/* sort.c -- Sort without allocating memory
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* The GNU glibc version of qsort allocates memory, which we must not
|
||||
do if we are invoked by a signal handler. So provide our own
|
||||
sort. */
|
||||
|
||||
static void
|
||||
swap (char *a, char *b, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < size; i++, a++, b++)
|
||||
{
|
||||
char t;
|
||||
|
||||
t = *a;
|
||||
*a = *b;
|
||||
*b = t;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
backtrace_qsort (void *basearg, size_t count, size_t size,
|
||||
int (*compar) (const void *, const void *))
|
||||
{
|
||||
char *base = (char *) basearg;
|
||||
size_t i;
|
||||
size_t mid;
|
||||
|
||||
tail_recurse:
|
||||
if (count < 2)
|
||||
return;
|
||||
|
||||
/* The symbol table and DWARF tables, which is all we use this
|
||||
routine for, tend to be roughly sorted. Pick the middle element
|
||||
in the array as our pivot point, so that we are more likely to
|
||||
cut the array in half for each recursion step. */
|
||||
swap (base, base + (count / 2) * size, size);
|
||||
|
||||
mid = 0;
|
||||
for (i = 1; i < count; i++)
|
||||
{
|
||||
if ((*compar) (base, base + i * size) > 0)
|
||||
{
|
||||
++mid;
|
||||
if (i != mid)
|
||||
swap (base + mid * size, base + i * size, size);
|
||||
}
|
||||
}
|
||||
|
||||
if (mid > 0)
|
||||
swap (base, base + mid * size, size);
|
||||
|
||||
/* Recurse with the smaller array, loop with the larger one. That
|
||||
ensures that our maximum stack depth is log count. */
|
||||
if (2 * mid < count)
|
||||
{
|
||||
backtrace_qsort (base, mid, size, compar);
|
||||
base += (mid + 1) * size;
|
||||
count -= mid + 1;
|
||||
goto tail_recurse;
|
||||
}
|
||||
else
|
||||
{
|
||||
backtrace_qsort (base + (mid + 1) * size, count - (mid + 1),
|
||||
size, compar);
|
||||
count = mid;
|
||||
goto tail_recurse;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* state.c -- Create the backtrace state.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "backtrace-supported.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Create the backtrace state. This will then be passed to all the
|
||||
other routines. */
|
||||
|
||||
struct backtrace_state *
|
||||
backtrace_create_state (const char *filename, int threaded,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data)
|
||||
{
|
||||
struct backtrace_state init_state;
|
||||
struct backtrace_state *state;
|
||||
|
||||
#ifndef HAVE_SYNC_FUNCTIONS
|
||||
if (threaded)
|
||||
{
|
||||
error_callback (data, "backtrace library does not support threads", 0);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset (&init_state, 0, sizeof init_state);
|
||||
init_state.filename = filename;
|
||||
init_state.threaded = threaded;
|
||||
|
||||
state = ((struct backtrace_state *)
|
||||
backtrace_alloc (&init_state, sizeof *state, error_callback, data));
|
||||
if (state == NULL)
|
||||
return NULL;
|
||||
*state = init_state;
|
||||
|
||||
return state;
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/* stest.c -- Test for libbacktrace internal sort function
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Test the local qsort implementation. */
|
||||
|
||||
#define MAX 10
|
||||
|
||||
struct test
|
||||
{
|
||||
size_t count;
|
||||
int input[MAX];
|
||||
int output[MAX];
|
||||
};
|
||||
|
||||
static struct test tests[] =
|
||||
{
|
||||
{
|
||||
10,
|
||||
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
|
||||
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
|
||||
},
|
||||
{
|
||||
9,
|
||||
{ 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }
|
||||
},
|
||||
{
|
||||
10,
|
||||
{ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 },
|
||||
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
|
||||
},
|
||||
{
|
||||
9,
|
||||
{ 9, 8, 7, 6, 5, 4, 3, 2, 1 },
|
||||
{ 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
},
|
||||
{
|
||||
10,
|
||||
{ 2, 4, 6, 8, 10, 1, 3, 5, 7, 9 },
|
||||
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
|
||||
},
|
||||
{
|
||||
5,
|
||||
{ 4, 5, 3, 1, 2 },
|
||||
{ 1, 2, 3, 4, 5 },
|
||||
},
|
||||
{
|
||||
5,
|
||||
{ 1, 1, 1, 1, 1 },
|
||||
{ 1, 1, 1, 1, 1 },
|
||||
},
|
||||
{
|
||||
5,
|
||||
{ 1, 1, 2, 1, 1 },
|
||||
{ 1, 1, 1, 1, 2 },
|
||||
},
|
||||
{
|
||||
5,
|
||||
{ 2, 1, 1, 1, 1 },
|
||||
{ 1, 1, 1, 1, 2 },
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
compare (const void *a, const void *b)
|
||||
{
|
||||
const int *ai = (const int *) a;
|
||||
const int *bi = (const int *) b;
|
||||
|
||||
return *ai - *bi;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
|
||||
{
|
||||
int failures;
|
||||
size_t i;
|
||||
int a[MAX];
|
||||
|
||||
failures = 0;
|
||||
for (i = 0; i < sizeof tests / sizeof tests[0]; i++)
|
||||
{
|
||||
memcpy (a, tests[i].input, tests[i].count * sizeof (int));
|
||||
backtrace_qsort (a, tests[i].count, sizeof (int), compare);
|
||||
if (memcmp (a, tests[i].output, tests[i].count * sizeof (int)) != 0)
|
||||
{
|
||||
size_t j;
|
||||
|
||||
fprintf (stderr, "test %d failed:", (int) i);
|
||||
for (j = 0; j < tests[i].count; j++)
|
||||
fprintf (stderr, " %d", a[j]);
|
||||
fprintf (stderr, "\n");
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
|
||||
exit (failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/* unknown.c -- used when backtrace configury does not know file format.
|
||||
Copyright (C) 2012-2016 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* A trivial routine that always fails to find fileline data. */
|
||||
|
||||
static int
|
||||
unknown_fileline (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
uintptr_t pc, backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data)
|
||||
|
||||
{
|
||||
return callback (data, pc, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
/* Initialize the backtrace data when we don't know how to read the
|
||||
debug info. */
|
||||
|
||||
int
|
||||
backtrace_initialize (struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
int descriptor ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data ATTRIBUTE_UNUSED, fileline *fileline_fn)
|
||||
{
|
||||
state->fileline_data = NULL;
|
||||
*fileline_fn = unknown_fileline;
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
backtrace_full __rbt_backtrace_full
|
||||
backtrace_dwarf_add __rbt_backtrace_dwarf_add
|
||||
backtrace_initialize __rbt_backtrace_initialize
|
||||
backtrace_pcinfo __rbt_backtrace_pcinfo
|
||||
backtrace_syminfo __rbt_backtrace_syminfo
|
||||
backtrace_get_view __rbt_backtrace_get_view
|
||||
backtrace_release_view __rbt_backtrace_release_view
|
||||
backtrace_alloc __rbt_backtrace_alloc
|
||||
backtrace_free __rbt_backtrace_free
|
||||
backtrace_vector_finish __rbt_backtrace_vector_finish
|
||||
backtrace_vector_grow __rbt_backtrace_vector_grow
|
||||
backtrace_vector_release __rbt_backtrace_vector_release
|
||||
backtrace_close __rbt_backtrace_close
|
||||
backtrace_open __rbt_backtrace_open
|
||||
backtrace_print __rbt_backtrace_print
|
||||
backtrace_simple __rbt_backtrace_simple
|
||||
backtrace_qsort __rbt_backtrace_qsort
|
||||
backtrace_create_state __rbt_backtrace_create_state
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"749f043da5cdbd988e2068e94feb3e75ed326945a99cf288c94ae444f5328680","build.rs":"2cf7c28f03f85c8e68969bcb5b076c8effa8543d39a12fe651ff332ac6a394c7","src/lib.rs":"cb45ba047240bceac6ea74da50c2f48ae81a965b578c833a766a3ea0db1075f3","src/libbacktrace/ChangeLog":"ad6f9058524b950aed734db83419e0624df55a48af8091c8bcad7a125aeeffdd","src/libbacktrace/ChangeLog.jit":"ee143b5c9dc571d9aca006be246a83b1f019c39a3fd7b0025eb37463e30200ce","src/libbacktrace/Makefile.am":"74d0036c9715cb7fa6c749cead794ba96283f47d243cf2b25bc6fac8f04667d5","src/libbacktrace/Makefile.in":"9ca92df95c8d62b8a0e106357a796ef4d2c5ec7fd02ab133fd0a65de1984e096","src/libbacktrace/README":"3d1a15714583197945df8db054da6f30613316ec311c5ec2d68b92fab12364a2","src/libbacktrace/aclocal.m4":"e3a6dfa4ce929624ac289b260987a7fa9b512cfbf3ff6f39c5d1e38cbad1a0ea","src/libbacktrace/alloc.c":"829ceab369210fc60758f339807fe0bf55832c77adb3a4450fae586a90a9673d","src/libbacktrace/ansidecl.h":"14acfcd6c044bc73de85b120cbc3e626771a01712911ee1f6137585fd710fb1e","src/libbacktrace/atomic.c":"3e1882a520e0e1115107e194fbd97daa8d3feef15a70047969f4976e7542c263","src/libbacktrace/backtrace-supported.h.in":"42277f3c383386b6cfa3d3d889336e92303fac0ae1a9fb8a6a56737245dfb8f3","src/libbacktrace/backtrace.c":"76bdabddc4eb8a46a7eec98ce610c86909c89c629eb850a0cde98f5a78c9b99d","src/libbacktrace/backtrace.h":"cd2db6474556b655e42c0a973b871c1b6cb4796809490bf59cc8d3d0e8c083f5","src/libbacktrace/btest.c":"fff55e4acf6ad02a6f719046fc4e3f8bf795166ed9956122a79e17c6be266738","src/libbacktrace/config.guess":"8131853dbc8c3be5171fa96353de7a884a79d3f1d6b3fbf48f99037f5f95fe27","src/libbacktrace/config.h.in":"9b0d30416c93906e5c0ce36c95a7426bfd41228114f381949e89d263305b5b65","src/libbacktrace/config.sub":"3b739084e4b409aacf8531f87b57efa602eccdd17b5cddbc4ae1313a2c866f34","src/libbacktrace/configure":"2b45c89d06809c6ed49d70bfdf51a93e44370fc81f689169a073f47b14b366e5","src/libbacktrace/configure.ac":"360b1a033e33d2c58d2f36aaa6644a2aac0dd8960417df6d64202cc099a1c3f3","src/libbacktrace/dwarf.c":"b969c3abb07a09aa4ac5094dba5777d2c23fee77ade4ec0934142d6b81049785","src/libbacktrace/dwarf2.def":"d947302d8b259f0abdd9dd2f50a0713f4e7395c05ce88ddfdb37a7145b045d82","src/libbacktrace/dwarf2.h":"b3b13fa412a1573e3ee8dcb1d603ec33de7140f00b3bbbaa5292724f0087ace3","src/libbacktrace/elf.c":"728d7e47bf077de4dad6eecc76c134b4b4898dc5866572587692848f29aaec5c","src/libbacktrace/fileline.c":"bae25b6662bfd01a43bccc645206e00aeea27f18a51f6303f00f4fa1d9f2e861","src/libbacktrace/filenames.h":"bce400200dbc7452ca2a7f27dd36516949c4c94a135a6a322f011f3ce7817377","src/libbacktrace/filetype.awk":"9dd5352f288c3737fccd24a2c7583f4d0dbca2b95b2735a90a26b644478018af","src/libbacktrace/hashtab.h":"4cb7f68db5c2e8ff1190ecf859e7feb58447ea20bd9818bb1f447b46e2813c58","src/libbacktrace/install-sh":"d7c113e5484fce8b48f9a34a7a91e385ec279247d415b0b7d749bd56ad8ee8a2","src/libbacktrace/internal.h":"ed657e14aa33b4b5217919435e69019c5a677a00a9c134bf0297f000f146b093","src/libbacktrace/ltmain.sh":"ee4019f80b993cdb1bd13bf39434ad4f1ef15ae57a97594c53fb7b1d76d776a4","src/libbacktrace/missing":"b1a337b731bbb58846d31ca2f5143c293a455fa41b481e236e89a9016d96b034","src/libbacktrace/mmap.c":"fec72286a2d8a0c53fd56ea61b3766b87031f6f803f6de6c3c656e39bc85cdc2","src/libbacktrace/mmapio.c":"32a672fd2b8b3395c8a16ef11d839437ca35570fbc235bb0e2e70ef8097a12fc","src/libbacktrace/nounwind.c":"7694636af38ef488c814ab9b71854d6a259c1f3f635bd4c3ed99a88ca2beb5f1","src/libbacktrace/pecoff.c":"00cf6976cfc1e018f5e5473d4fbef4ae86de825dd2749897c45dfcebcefc6abf","src/libbacktrace/posix.c":"73754fcfa0a5b0342e8fe32166e7228b61e022699a8a3c9a2ef8e46260736704","src/libbacktrace/print.c":"ec1e80e17e27130bf9412470e8dc9155a0dc9ca3a78125081f5073b438b54157","src/libbacktrace/read.c":"399458fb06389aa4bd5ce376c4620cf733b5555d1dabe7ef19f185da1e37e614","src/libbacktrace/simple.c":"686d976c2bdb1a074f9be05af026d4b4c7a4978c2602268747d492563f18e0dc","src/libbacktrace/sort.c":"1a1e44af4e4d02fc568b318aa1517792edd6972a27029ba78e938856ef8ba1a0","src/libbacktrace/state.c":"49d547f5622b0ea0c39bc873b09a7dce276fdc6469118f5ab2e72c55bd0457fb","src/libbacktrace/stest.c":"aa1b90fe2d6dc8ac65ac0168776c2d242efc6460ac596deb14ac1e72bf764871","src/libbacktrace/unknown.c":"914aa113cd17ed678d40927391b35f6027e87b3a02e36e9f1822ec1efe9c0e20","symbol-map":"b941b2516efbb9e46521eeb166c60b31d52b2a4aaaf35d7f9af24946bbe1328a"},"package":"d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842"}
|
||||
{"files":{"Cargo.toml":"744f124e8a67a644dfee3665baad89b5f98ac93d79034aca685e0ac79802a5d6","build.rs":"dd3a9eeb5f071ebf073657b691593aa9432a5280d3c7719bd8357e20e6ccdf7f","src/lib.rs":"cb45ba047240bceac6ea74da50c2f48ae81a965b578c833a766a3ea0db1075f3","src/libbacktrace/ChangeLog":"ad6f9058524b950aed734db83419e0624df55a48af8091c8bcad7a125aeeffdd","src/libbacktrace/ChangeLog.jit":"ee143b5c9dc571d9aca006be246a83b1f019c39a3fd7b0025eb37463e30200ce","src/libbacktrace/Makefile.am":"74d0036c9715cb7fa6c749cead794ba96283f47d243cf2b25bc6fac8f04667d5","src/libbacktrace/Makefile.in":"9ca92df95c8d62b8a0e106357a796ef4d2c5ec7fd02ab133fd0a65de1984e096","src/libbacktrace/README":"3d1a15714583197945df8db054da6f30613316ec311c5ec2d68b92fab12364a2","src/libbacktrace/aclocal.m4":"e3a6dfa4ce929624ac289b260987a7fa9b512cfbf3ff6f39c5d1e38cbad1a0ea","src/libbacktrace/alloc.c":"829ceab369210fc60758f339807fe0bf55832c77adb3a4450fae586a90a9673d","src/libbacktrace/ansidecl.h":"14acfcd6c044bc73de85b120cbc3e626771a01712911ee1f6137585fd710fb1e","src/libbacktrace/atomic.c":"3e1882a520e0e1115107e194fbd97daa8d3feef15a70047969f4976e7542c263","src/libbacktrace/backtrace-supported.h.in":"42277f3c383386b6cfa3d3d889336e92303fac0ae1a9fb8a6a56737245dfb8f3","src/libbacktrace/backtrace.c":"76bdabddc4eb8a46a7eec98ce610c86909c89c629eb850a0cde98f5a78c9b99d","src/libbacktrace/backtrace.h":"cd2db6474556b655e42c0a973b871c1b6cb4796809490bf59cc8d3d0e8c083f5","src/libbacktrace/btest.c":"fff55e4acf6ad02a6f719046fc4e3f8bf795166ed9956122a79e17c6be266738","src/libbacktrace/config.guess":"8131853dbc8c3be5171fa96353de7a884a79d3f1d6b3fbf48f99037f5f95fe27","src/libbacktrace/config.h.in":"9b0d30416c93906e5c0ce36c95a7426bfd41228114f381949e89d263305b5b65","src/libbacktrace/config.sub":"3b739084e4b409aacf8531f87b57efa602eccdd17b5cddbc4ae1313a2c866f34","src/libbacktrace/configure":"2b45c89d06809c6ed49d70bfdf51a93e44370fc81f689169a073f47b14b366e5","src/libbacktrace/configure.ac":"360b1a033e33d2c58d2f36aaa6644a2aac0dd8960417df6d64202cc099a1c3f3","src/libbacktrace/dwarf.c":"b969c3abb07a09aa4ac5094dba5777d2c23fee77ade4ec0934142d6b81049785","src/libbacktrace/dwarf2.def":"d947302d8b259f0abdd9dd2f50a0713f4e7395c05ce88ddfdb37a7145b045d82","src/libbacktrace/dwarf2.h":"b3b13fa412a1573e3ee8dcb1d603ec33de7140f00b3bbbaa5292724f0087ace3","src/libbacktrace/elf.c":"728d7e47bf077de4dad6eecc76c134b4b4898dc5866572587692848f29aaec5c","src/libbacktrace/fileline.c":"bae25b6662bfd01a43bccc645206e00aeea27f18a51f6303f00f4fa1d9f2e861","src/libbacktrace/filenames.h":"bce400200dbc7452ca2a7f27dd36516949c4c94a135a6a322f011f3ce7817377","src/libbacktrace/filetype.awk":"9dd5352f288c3737fccd24a2c7583f4d0dbca2b95b2735a90a26b644478018af","src/libbacktrace/hashtab.h":"4cb7f68db5c2e8ff1190ecf859e7feb58447ea20bd9818bb1f447b46e2813c58","src/libbacktrace/install-sh":"d7c113e5484fce8b48f9a34a7a91e385ec279247d415b0b7d749bd56ad8ee8a2","src/libbacktrace/internal.h":"ed657e14aa33b4b5217919435e69019c5a677a00a9c134bf0297f000f146b093","src/libbacktrace/ltmain.sh":"ee4019f80b993cdb1bd13bf39434ad4f1ef15ae57a97594c53fb7b1d76d776a4","src/libbacktrace/missing":"b1a337b731bbb58846d31ca2f5143c293a455fa41b481e236e89a9016d96b034","src/libbacktrace/mmap.c":"fec72286a2d8a0c53fd56ea61b3766b87031f6f803f6de6c3c656e39bc85cdc2","src/libbacktrace/mmapio.c":"32a672fd2b8b3395c8a16ef11d839437ca35570fbc235bb0e2e70ef8097a12fc","src/libbacktrace/nounwind.c":"7694636af38ef488c814ab9b71854d6a259c1f3f635bd4c3ed99a88ca2beb5f1","src/libbacktrace/pecoff.c":"00cf6976cfc1e018f5e5473d4fbef4ae86de825dd2749897c45dfcebcefc6abf","src/libbacktrace/posix.c":"73754fcfa0a5b0342e8fe32166e7228b61e022699a8a3c9a2ef8e46260736704","src/libbacktrace/print.c":"ec1e80e17e27130bf9412470e8dc9155a0dc9ca3a78125081f5073b438b54157","src/libbacktrace/read.c":"399458fb06389aa4bd5ce376c4620cf733b5555d1dabe7ef19f185da1e37e614","src/libbacktrace/simple.c":"686d976c2bdb1a074f9be05af026d4b4c7a4978c2602268747d492563f18e0dc","src/libbacktrace/sort.c":"1a1e44af4e4d02fc568b318aa1517792edd6972a27029ba78e938856ef8ba1a0","src/libbacktrace/state.c":"49d547f5622b0ea0c39bc873b09a7dce276fdc6469118f5ab2e72c55bd0457fb","src/libbacktrace/stest.c":"aa1b90fe2d6dc8ac65ac0168776c2d242efc6460ac596deb14ac1e72bf764871","src/libbacktrace/unknown.c":"914aa113cd17ed678d40927391b35f6027e87b3a02e36e9f1822ec1efe9c0e20","symbol-map":"b941b2516efbb9e46521eeb166c60b31d52b2a4aaaf35d7f9af24946bbe1328a"},"package":"afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c"}
|
|
@ -1,18 +1,26 @@
|
|||
# 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 = "backtrace-sys"
|
||||
version = "0.1.10"
|
||||
version = "0.1.12"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
build = "build.rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/alexcrichton/backtrace-rs"
|
||||
description = "Bindings to the libbacktrace gcc library\n"
|
||||
homepage = "https://github.com/alexcrichton/backtrace-rs"
|
||||
documentation = "http://alexcrichton.com/backtrace-rs"
|
||||
description = """
|
||||
Bindings to the libbacktrace gcc library
|
||||
"""
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3"
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/alexcrichton/backtrace-rs"
|
||||
[dependencies.libc]
|
||||
version = "0.2"
|
||||
[build-dependencies.gcc]
|
||||
version = "0.3"
|
||||
|
|
|
@ -35,6 +35,7 @@ fn find_tool(compiler: &gcc::Tool, cc: &str, tool: &str) -> PathBuf {
|
|||
}
|
||||
let tool_suffix = format!("-{}", tool);
|
||||
try_tool(compiler, cc, "-gcc", &tool_suffix)
|
||||
.or_else(|| try_tool(compiler, cc, "-clang", &tool_suffix))
|
||||
.or_else(|| try_tool(compiler, cc, "-cc", &tool_suffix))
|
||||
.unwrap_or_else(|| PathBuf::from(tool))
|
||||
}
|
||||
|
@ -60,6 +61,32 @@ fn main() {
|
|||
return
|
||||
}
|
||||
|
||||
let mut make = "make";
|
||||
|
||||
// host BSDs has GNU-make as gmake
|
||||
if host.contains("bitrig") || host.contains("dragonfly") ||
|
||||
host.contains("freebsd") || host.contains("netbsd") ||
|
||||
host.contains("openbsd") {
|
||||
|
||||
make = "gmake"
|
||||
}
|
||||
|
||||
let configure = src.join("src/libbacktrace/configure").into_os_string();
|
||||
|
||||
// When cross-compiling on Windows, this path will contain backslashes,
|
||||
// but configure doesn't like that. Replace them with forward slashes.
|
||||
#[cfg(windows)]
|
||||
let configure = {
|
||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
let mut chars: Vec<u16> = configure.encode_wide().collect();
|
||||
for c in chars.iter_mut() {
|
||||
if *c == '\\' as u16 {
|
||||
*c = '/' as u16;
|
||||
}
|
||||
}
|
||||
OsString::from_wide(&chars)
|
||||
};
|
||||
|
||||
let cfg = gcc::Config::new();
|
||||
let compiler = cfg.get_compiler();
|
||||
let cc = compiler.path().file_name().unwrap().to_str().unwrap();
|
||||
|
@ -71,18 +98,26 @@ fn main() {
|
|||
flags.push(flag);
|
||||
}
|
||||
let ar = find_tool(&compiler, cc, "ar");
|
||||
run(Command::new(src.join("src/libbacktrace/configure"))
|
||||
.current_dir(&dst)
|
||||
.env("CC", compiler.path())
|
||||
.env("CFLAGS", flags)
|
||||
.arg("--with-pic")
|
||||
.arg("--disable-multilib")
|
||||
.arg("--disable-shared")
|
||||
.arg("--disable-host-shared")
|
||||
.arg(format!("--target={}", target))
|
||||
.arg(format!("--host={}", host)),
|
||||
"sh");
|
||||
run(Command::new("make")
|
||||
let mut cmd = Command::new("sh");
|
||||
|
||||
cmd.arg(configure)
|
||||
.current_dir(&dst)
|
||||
.env("AR", &ar)
|
||||
.env("CC", compiler.path())
|
||||
.env("CFLAGS", flags)
|
||||
.arg("--with-pic")
|
||||
.arg("--disable-multilib")
|
||||
.arg("--disable-shared")
|
||||
.arg("--disable-host-shared")
|
||||
.arg(format!("--host={}", target));
|
||||
|
||||
// Apparently passing this flag causes problems on Windows
|
||||
if !host.contains("windows") {
|
||||
cmd.arg(format!("--build={}", host));
|
||||
}
|
||||
|
||||
run(&mut cmd, "sh");
|
||||
run(Command::new(make)
|
||||
.current_dir(&dst)
|
||||
.arg(format!("INCDIR={}",
|
||||
src.join("src/libbacktrace").display())),
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{".travis.yml":"6f11d19317924088c90d605e1d13e4af230b10e289c5df6139c40a62409eabd9","Cargo.toml":"f893b7b701611e48ab80db25670342084b11d8d4ed3f3471b68842c490d247b8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"11061a4c1e27fde148b5b1fb6df553f8eb464e279be0f5e278d262bf35d7b0f8","appveyor.yml":"29d9f44137560479a75b02a7953cfa0c378c2577ed1925f579b400295c7937e3","examples/backtrace.rs":"fd6e1cc6c3378ec7d41cd03b2bef187051298dceb01147e71f207dbb8a0c4867","examples/raw.rs":"f07be26d1f97cd7ac79290ac99d19c4eec5d27031fe270ab5364c25d9c2ad9e0","src/backtrace/dbghelp.rs":"45c5052763857d4a3727c3082be1b2f6c28f7973afd66706657defda5d97c6ec","src/backtrace/libunwind.rs":"cc9cdc1d389571cdedf43dfc2d39b8c3af85531a3965ed700c724f436afb213e","src/backtrace/mod.rs":"d00f4a574fae44df81b1d40bf44acea84addb70b4c76c85bfaa1f3ab0bcd7f0d","src/backtrace/noop.rs":"dc4a6602e9852b945c382194402314d3d68c8ca90199af9a8159419fb91a3c99","src/backtrace/unix_backtrace.rs":"1bb4a4a2f1e56f8ac04002dd77411116d8b4920f905d1ddfcb289e242f939a86","src/capture.rs":"de3250fcb9ff941391dea24decc8166d058f17abe77d25ff82b766ac384f00ea","src/dylib.rs":"09f3d7f32849cf0daa4de9df48f8e4a4d5ba62e20723c79578201bd271dc4777","src/lib.rs":"7ccd8cc3679435f0e39efd26f23d9d7a01094ab09ba6d411c6587b2420c6886b","src/symbolize/coresymbolication.rs":"99280684791694f560824b39291ee7ad78a2b53f82e5972ff3d9b77b43671f60","src/symbolize/dbghelp.rs":"d743545bb3e64eafc4903e3e7aec115b64da2174e75afd7b465bc0b89573b88a","src/symbolize/dladdr.rs":"8287cbca440a9e92e74d88c5a7b920f6b4cf6d8f50bc8b0f61aca5ba42d5b5ec","src/symbolize/libbacktrace.rs":"0cdad7de2501baef9da193ee6aab21c453d26348a2071c805a133efe1209eaa1","src/symbolize/mod.rs":"7f2efe54ce40f42ba38673614cff2a510632123cb6d1bc3da88566f12bcba588","src/symbolize/noop.rs":"b622fcecb4e22b42c3d3e2ef5dc5a6ab14601fec83c7797ee1fbbacc12fe6ca1","tests/smoke.rs":"fc882d7db0f4842e4415e3319774a33ba27c4d6412a62f8ee194a5dafd8a6128"},"package":"72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"}
|
||||
{"files":{".travis.yml":"7c4c8bd9d72ba4186b6ff777a5168a1eacb5b2245bb675ab8f4abd5859ec906f","Cargo.toml":"e4c5543dd4144dec207c77df49246b1fec9dfcecde2b4ee50d2f016fd11d9a1b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"11061a4c1e27fde148b5b1fb6df553f8eb464e279be0f5e278d262bf35d7b0f8","appveyor.yml":"29d9f44137560479a75b02a7953cfa0c378c2577ed1925f579b400295c7937e3","examples/backtrace.rs":"fd6e1cc6c3378ec7d41cd03b2bef187051298dceb01147e71f207dbb8a0c4867","examples/raw.rs":"f07be26d1f97cd7ac79290ac99d19c4eec5d27031fe270ab5364c25d9c2ad9e0","src/backtrace/dbghelp.rs":"45c5052763857d4a3727c3082be1b2f6c28f7973afd66706657defda5d97c6ec","src/backtrace/libunwind.rs":"cc9cdc1d389571cdedf43dfc2d39b8c3af85531a3965ed700c724f436afb213e","src/backtrace/mod.rs":"91a544bd9e89da6b580e2580ab15ead354f13243bca50516ff5cefe68a8cd199","src/backtrace/noop.rs":"dc4a6602e9852b945c382194402314d3d68c8ca90199af9a8159419fb91a3c99","src/backtrace/unix_backtrace.rs":"31204989a8852428792a1c99d36717559aad14d93526e8a37744214adf188268","src/capture.rs":"a6f379300f6a578c52fce5927461fb0d084b2eb080113561a2e0cc11aa1f5c73","src/dylib.rs":"09f3d7f32849cf0daa4de9df48f8e4a4d5ba62e20723c79578201bd271dc4777","src/lib.rs":"20006ff65d1e9fd7f8fea52ae5515f99be99ffcc90b988f22d6cf276062cc9a0","src/symbolize/coresymbolication.rs":"99280684791694f560824b39291ee7ad78a2b53f82e5972ff3d9b77b43671f60","src/symbolize/dbghelp.rs":"6557ef254bb146609efd1534c4ac698e0278c4ce0b5f005108c6c8cd834f7250","src/symbolize/dladdr.rs":"8287cbca440a9e92e74d88c5a7b920f6b4cf6d8f50bc8b0f61aca5ba42d5b5ec","src/symbolize/gimli.rs":"44abf9436f53ed38e053d324548509731234577445eb5d2fe17f0adbb5834c03","src/symbolize/libbacktrace.rs":"0cdad7de2501baef9da193ee6aab21c453d26348a2071c805a133efe1209eaa1","src/symbolize/mod.rs":"5cce6abcdebe8f5766b0697fc47fdfa119afd231b99048d0b9c67af3a295b4ae","src/symbolize/noop.rs":"b622fcecb4e22b42c3d3e2ef5dc5a6ab14601fec83c7797ee1fbbacc12fe6ca1","tests/long_fn_name.rs":"1291e92a2dceab9ad3d424a26dd32bd8a3b77e86c2409ab8930c56918c3d961f","tests/smoke.rs":"85b5de78290cb1b247494fa2f118096c1fda2f249db47f3d94dd52446c5f0d7d"},"package":"99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983"}
|
|
@ -1,11 +1,28 @@
|
|||
language: rust
|
||||
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
sudo: false
|
||||
|
||||
dist: trusty
|
||||
|
||||
addons:
|
||||
sources:
|
||||
# Provides clang-3.9
|
||||
- llvm-toolchain-trusty-3.9
|
||||
apt:
|
||||
packages:
|
||||
# Required for `bindgen`, which is required by `findshlibs`, which is
|
||||
# required by the `gimli` feature.
|
||||
- clang-3.9
|
||||
|
||||
before_script:
|
||||
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
|
||||
- export LIBCLANG_PATH=/usr/lib/llvm-3.9/lib
|
||||
|
||||
script:
|
||||
- cargo test
|
||||
- cargo test --no-default-features
|
||||
|
@ -19,15 +36,19 @@ script:
|
|||
- cargo test --no-default-features --features 'serialize-rustc'
|
||||
- cargo test --no-default-features --features 'serialize-rustc serialize-serde'
|
||||
- cargo test --no-default-features --features 'cpp_demangle'
|
||||
- cargo test --no-default-features --features 'gimli-symbolize'
|
||||
- cd ./cpp_smoke_test && cargo test && cd ..
|
||||
- cargo clean && cargo build
|
||||
- rustdoc --test README.md -L target/debug/deps -L target/debug
|
||||
- cargo doc --no-deps
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
|
||||
after_success:
|
||||
- travis-cargo --only nightly doc-upload
|
||||
|
||||
env:
|
||||
global:
|
||||
# serde-codegen has historically needed a large stack to expand
|
||||
|
|
|
@ -1,87 +1,81 @@
|
|||
# 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 = "backtrace"
|
||||
version = "0.3.2"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>",
|
||||
"The Rust Project Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/alexcrichton/backtrace-rs"
|
||||
version = "0.3.3"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>", "The Rust Project Developers"]
|
||||
description = "A library to acquire a stack trace (backtrace) at runtime in a Rust program.\n"
|
||||
homepage = "https://github.com/alexcrichton/backtrace-rs"
|
||||
documentation = "http://alexcrichton.com/backtrace-rs"
|
||||
description = """
|
||||
A library to acquire a stack trace (backtrace) at runtime in a Rust program.
|
||||
"""
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
cfg-if = "0.1"
|
||||
rustc-demangle = "0.1.4"
|
||||
readme = "README.md"
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/alexcrichton/backtrace-rs"
|
||||
[dependencies.cpp_demangle]
|
||||
version = "0.2.3"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
# Optionally enable the ability to serialize a `Backtrace`
|
||||
serde = { version = "1.0", optional = true }
|
||||
serde_derive = { version = "1.0", optional = true }
|
||||
rustc-serialize = { version = "0.3", optional = true }
|
||||
[dependencies.serde_derive]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
# Optionally demangle C++ frames' symbols in backtraces.
|
||||
cpp_demangle = { default-features = false, version = "0.2.3", optional = true }
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
dbghelp-sys = { version = "0.2", optional = true }
|
||||
kernel32-sys = { version = "0.2", optional = true }
|
||||
winapi = { version = "0.2.5", optional = true }
|
||||
[dependencies.rustc-demangle]
|
||||
version = "0.1.4"
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "emscripten"), not(target_os = "macos"), not(target_os = "ios")))'.dependencies]
|
||||
backtrace-sys = { path = "backtrace-sys", version = "0.1.3", optional = true }
|
||||
[dependencies.cfg-if]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.findshlibs]
|
||||
version = "0.3.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.rustc-serialize]
|
||||
version = "0.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.addr2line]
|
||||
version = "0.5.0"
|
||||
optional = true
|
||||
|
||||
# Each feature controls the two phases of finding a backtrace: getting a
|
||||
# backtrace and then resolving instruction pointers to symbols. The default
|
||||
# feature enables all the necessary features for each platform this library
|
||||
# supports, but it can be disabled to have finer grained control over the
|
||||
# dependencies.
|
||||
#
|
||||
# Note that not all features are available on all platforms, so even though a
|
||||
# feature is enabled some other feature may be used instead.
|
||||
[features]
|
||||
gimli-symbolize = ["addr2line", "findshlibs"]
|
||||
coresymbolication = []
|
||||
dladdr = []
|
||||
kernel32 = []
|
||||
unix-backtrace = []
|
||||
dbghelp = ["kernel32-sys", "winapi", "dbghelp-sys"]
|
||||
default = ["libunwind", "libbacktrace", "coresymbolication", "dladdr", "dbghelp"]
|
||||
libunwind = []
|
||||
serialize-rustc = ["rustc-serialize"]
|
||||
libbacktrace = ["backtrace-sys"]
|
||||
serialize-serde = ["serde", "serde_derive"]
|
||||
[target."cfg(windows)".dependencies.dbghelp-sys]
|
||||
version = "0.2"
|
||||
optional = true
|
||||
|
||||
#=======================================
|
||||
# Methods of acquiring a backtrace
|
||||
#
|
||||
# - libunwind: when using this the libgcc library is linked against to get
|
||||
# the unwinding support. This is generally the most reliable method to get
|
||||
# a backtrace on unix.
|
||||
# - unix-backtrace: this uses the backtrace(3) function to acquire a
|
||||
# backtrace, but is not as reliable as libunwind. It is, however,
|
||||
# generally found in more locations.
|
||||
# - dbghelp: on windows this enables usage of dbghelp.dll to find a
|
||||
# backtrace at runtime
|
||||
# - kernel32: on windows this enables using RtlCaptureStackBackTrace as the
|
||||
# function to acquire a backtrace
|
||||
libunwind = []
|
||||
unix-backtrace = []
|
||||
dbghelp = ["kernel32-sys", "winapi", "dbghelp-sys"]
|
||||
kernel32 = []
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.2.5"
|
||||
optional = true
|
||||
|
||||
#=======================================
|
||||
# Methods of resolving symbols
|
||||
#
|
||||
# - libbacktrace: this feature activates the `backtrace-sys` dependency,
|
||||
# building the libbacktrace library found in gcc repos. This library
|
||||
# parses the DWARF info of ELF executables to find symbol names, and it
|
||||
# can also provide filename/line number information if debuginfo is
|
||||
# compiled in. This library currently only primarily works on unixes that
|
||||
# are not OSX, however.
|
||||
# - dladdr: this feature uses the dladdr(3) function (a glibc extension) to
|
||||
# resolve symbol names. This is fairly unreliable on linux, but works well
|
||||
# enough on OSX.
|
||||
# - coresymbolication: this feature uses the undocumented core symbolication
|
||||
# framework on OS X to symbolize.
|
||||
libbacktrace = ["backtrace-sys"]
|
||||
dladdr = []
|
||||
coresymbolication = []
|
||||
|
||||
#=======================================
|
||||
# Methods of serialization
|
||||
#
|
||||
# Various features used for enabling rustc-serialize or syntex codegen.
|
||||
serialize-rustc = ["rustc-serialize"]
|
||||
serialize-serde = ["serde", "serde_derive"]
|
||||
[target."cfg(windows)".dependencies.kernel32-sys]
|
||||
version = "0.2"
|
||||
optional = true
|
||||
[target."cfg(all(unix, not(target_os = \"emscripten\"), not(target_os = \"macos\"), not(target_os = \"ios\")))".dependencies.backtrace-sys]
|
||||
version = "0.1.3"
|
||||
optional = true
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2"
|
||||
|
|
|
@ -36,7 +36,7 @@ use std::os::raw::c_void;
|
|||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
#[inline(never)] // if this is never inlined then the first frame can be konwn
|
||||
#[inline(never)] // if this is never inlined then the first frame can be known
|
||||
// to be skipped
|
||||
pub fn trace<F: FnMut(&Frame) -> bool>(mut cb: F) {
|
||||
trace_imp(&mut cb)
|
||||
|
@ -90,6 +90,7 @@ impl fmt::Debug for Frame {
|
|||
cfg_if! {
|
||||
if #[cfg(all(unix,
|
||||
not(target_os = "emscripten"),
|
||||
not(all(target_os = "ios", target_arch = "arm")),
|
||||
feature = "libunwind"))] {
|
||||
mod libunwind;
|
||||
use self::libunwind::trace as trace_imp;
|
||||
|
|
|
@ -25,7 +25,7 @@ extern {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn trace(mut cb: &mut FnMut(&super::Frame) -> bool) {
|
||||
pub fn trace(cb: &mut FnMut(&super::Frame) -> bool) {
|
||||
const SIZE: usize = 100;
|
||||
|
||||
let mut buf: [*mut c_void; SIZE];
|
||||
|
|
|
@ -26,7 +26,7 @@ pub struct Backtrace {
|
|||
pub struct BacktraceFrame {
|
||||
ip: usize,
|
||||
symbol_address: usize,
|
||||
symbols: Vec<BacktraceSymbol>,
|
||||
symbols: Option<Vec<BacktraceSymbol>>,
|
||||
}
|
||||
|
||||
/// Captured version of a symbol in a backtrace.
|
||||
|
@ -49,7 +49,7 @@ impl Backtrace {
|
|||
///
|
||||
/// This function is useful for representing a backtrace as an object in
|
||||
/// Rust. This returned value can be sent across threads and printed
|
||||
/// elsewhere, and thie purpose of this value is to be entirely self
|
||||
/// elsewhere, and the purpose of this value is to be entirely self
|
||||
/// contained.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -60,21 +60,36 @@ impl Backtrace {
|
|||
/// let current_backtrace = Backtrace::new();
|
||||
/// ```
|
||||
pub fn new() -> Backtrace {
|
||||
let mut bt = Backtrace::new_unresolved();
|
||||
bt.resolve();
|
||||
return bt
|
||||
}
|
||||
|
||||
/// Similar to `new` except that this does not resolve any symbols, this
|
||||
/// simply captures the backtrace as a list of addresses.
|
||||
///
|
||||
/// At a later time the `resolve` function can be called to resolve this
|
||||
/// backtrace's symbols into readable names. This function exists because
|
||||
/// the resolution process can sometimes take a significant amount of time
|
||||
/// whereas any one backtrace may only be rarely printed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use backtrace::Backtrace;
|
||||
///
|
||||
/// let mut current_backtrace = Backtrace::new_unresolved();
|
||||
/// println!("{:?}", current_backtrace); // no symbol names
|
||||
/// current_backtrace.resolve();
|
||||
/// println!("{:?}", current_backtrace); // symbol names now present
|
||||
/// ```
|
||||
pub fn new_unresolved() -> Backtrace {
|
||||
let mut frames = Vec::new();
|
||||
trace(|frame| {
|
||||
let mut symbols = Vec::new();
|
||||
resolve(frame.ip(), |symbol| {
|
||||
symbols.push(BacktraceSymbol {
|
||||
name: symbol.name().map(|m| m.as_bytes().to_vec()),
|
||||
addr: symbol.addr().map(|a| a as usize),
|
||||
filename: symbol.filename().map(|m| m.to_path_buf()),
|
||||
lineno: symbol.lineno(),
|
||||
});
|
||||
});
|
||||
frames.push(BacktraceFrame {
|
||||
ip: frame.ip() as usize,
|
||||
symbol_address: frame.symbol_address() as usize,
|
||||
symbols: symbols,
|
||||
symbols: None,
|
||||
});
|
||||
true
|
||||
});
|
||||
|
@ -90,6 +105,26 @@ impl Backtrace {
|
|||
pub fn frames(&self) -> &[BacktraceFrame] {
|
||||
&self.frames
|
||||
}
|
||||
|
||||
/// If this backtrace was created from `new_unresolved` then this function
|
||||
/// will resolve all addresses in the backtrace to their symbolic names.
|
||||
///
|
||||
/// If this backtrace has been previously resolved or was created through
|
||||
/// `new`, this function does nothing.
|
||||
pub fn resolve(&mut self) {
|
||||
for frame in self.frames.iter_mut().filter(|f| f.symbols.is_none()) {
|
||||
let mut symbols = Vec::new();
|
||||
resolve(frame.ip as *mut _, |symbol| {
|
||||
symbols.push(BacktraceSymbol {
|
||||
name: symbol.name().map(|m| m.as_bytes().to_vec()),
|
||||
addr: symbol.addr().map(|a| a as usize),
|
||||
filename: symbol.filename().map(|m| m.to_path_buf()),
|
||||
lineno: symbol.lineno(),
|
||||
});
|
||||
});
|
||||
frame.symbols = Some(symbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<BacktraceFrame>> for Backtrace {
|
||||
|
@ -116,17 +151,18 @@ impl BacktraceFrame {
|
|||
pub fn symbol_address(&self) -> *mut c_void {
|
||||
self.symbol_address as *mut c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl BacktraceFrame {
|
||||
/// Returns the list of symbols that this frame corresponds to.
|
||||
///
|
||||
/// Normally there is only one symbol per frame, but sometimes if a number
|
||||
/// of functions are inlined into one frame then multiple symbols will be
|
||||
/// returned. The first symbol listed is the "innermost function", whereas
|
||||
/// the last symbol is the outermost (last caller).
|
||||
///
|
||||
/// Note that if this frame came from an unresolved backtrace then this will
|
||||
/// return an empty list.
|
||||
pub fn symbols(&self) -> &[BacktraceSymbol] {
|
||||
&self.symbols
|
||||
self.symbols.as_ref().map(|s| &s[..]).unwrap_or(&[])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,11 +198,18 @@ impl fmt::Debug for Backtrace {
|
|||
let ip = frame.ip();
|
||||
try!(write!(fmt, "\n{:4}: {:2$?}", idx, ip, hex_width));
|
||||
|
||||
if frame.symbols.len() == 0 {
|
||||
let symbols = match frame.symbols {
|
||||
Some(ref s) => s,
|
||||
None => {
|
||||
try!(write!(fmt, " - <unresolved>"));
|
||||
continue
|
||||
}
|
||||
};
|
||||
if symbols.len() == 0 {
|
||||
try!(write!(fmt, " - <no info>"));
|
||||
}
|
||||
|
||||
for (idx, symbol) in frame.symbols().iter().enumerate() {
|
||||
for (idx, symbol) in symbols.iter().enumerate() {
|
||||
if idx != 0 {
|
||||
try!(write!(fmt, "\n {:1$}", "", hex_width));
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
//!
|
||||
//! # API Principles
|
||||
//!
|
||||
//! This library attempts to be as flexible as possible to accomodate different
|
||||
//! This library attempts to be as flexible as possible to accommodate different
|
||||
//! backend implementations of acquiring a backtrace. Consequently the currently
|
||||
//! exported functions are closure-based as opposed to the likely expected
|
||||
//! iterator-based versions. This is done due to limitations of the underlying
|
||||
|
@ -69,14 +69,12 @@
|
|||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
|
||||
#[cfg(unix)]
|
||||
extern crate libc;
|
||||
#[cfg(all(windows, feature = "kernel32-sys"))] extern crate kernel32;
|
||||
#[cfg(all(windows, feature = "winapi"))] extern crate winapi;
|
||||
#[cfg(all(windows, feature = "dbghelp"))] extern crate dbghelp;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
extern crate serde;
|
||||
|
||||
#[cfg(feature = "serde_derive")]
|
||||
#[cfg_attr(feature = "serde_derive", macro_use)]
|
||||
extern crate serde_derive;
|
||||
|
@ -92,6 +90,15 @@ extern crate rustc_demangle;
|
|||
#[cfg(feature = "cpp_demangle")]
|
||||
extern crate cpp_demangle;
|
||||
|
||||
#[cfg(all(feature = "gimli-symbolize",
|
||||
unix,
|
||||
target_os = "linux"))]
|
||||
extern crate addr2line;
|
||||
#[cfg(all(feature = "gimli-symbolize",
|
||||
unix,
|
||||
target_os = "linux"))]
|
||||
extern crate findshlibs;
|
||||
|
||||
#[allow(dead_code)] // not used everywhere
|
||||
#[cfg(unix)]
|
||||
#[macro_use]
|
||||
|
|
|
@ -70,8 +70,15 @@ pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {
|
|||
if ret != TRUE {
|
||||
return
|
||||
}
|
||||
|
||||
// If the symbol name is greater than MaxNameLen, SymFromAddrW will
|
||||
// give a buffer of (MaxNameLen - 1) characters and set NameLen to
|
||||
// the real value.
|
||||
let name_len = ::std::cmp::min(info.NameLen as usize,
|
||||
info.MaxNameLen as usize - 1);
|
||||
|
||||
let name = slice::from_raw_parts(info.Name.as_ptr() as *const u16,
|
||||
info.NameLen as usize);
|
||||
name_len);
|
||||
let name = OsString::from_wide(name);
|
||||
|
||||
let mut line = mem::zeroed::<IMAGEHLP_LINEW64>();
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
use addr2line;
|
||||
use findshlibs::{self, Segment, SharedLibrary};
|
||||
use std::cell::RefCell;
|
||||
use std::env;
|
||||
use std::os::raw::c_void;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::u32;
|
||||
|
||||
use SymbolName;
|
||||
|
||||
const MAPPINGS_CACHE_SIZE: usize = 4;
|
||||
|
||||
thread_local! {
|
||||
// A very small, very simple LRU cache for debug info mappings.
|
||||
//
|
||||
// The hit rate should be very high, since the typical stack doesn't cross
|
||||
// between many shared libraries.
|
||||
//
|
||||
// The `addr2line::Mapping` structures are pretty expensive to create. Its
|
||||
// cost is expected to be amortized by subsequent `locate` queries, which
|
||||
// leverage the structures built when constructing `addr2line::Mapping`s to
|
||||
// get nice speedups. If we didn't have this cache, that amortization would
|
||||
// never happen, and symbolicating backtraces would be ssssllllooooowwww.
|
||||
static MAPPINGS_CACHE: RefCell<Vec<(PathBuf, addr2line::Mapping)>>
|
||||
= RefCell::new(Vec::with_capacity(MAPPINGS_CACHE_SIZE));
|
||||
}
|
||||
|
||||
fn with_mapping_for_path<F>(path: PathBuf, mut f: F)
|
||||
where
|
||||
F: FnMut(&mut addr2line::Mapping)
|
||||
{
|
||||
MAPPINGS_CACHE.with(|cache| {
|
||||
let mut cache = cache.borrow_mut();
|
||||
|
||||
let idx = cache.iter().position(|&(ref p, _)| p == &path);
|
||||
|
||||
// Invariant: after this conditional completes without early returning
|
||||
// from an error, the cache entry for this path is at index 0.
|
||||
|
||||
if let Some(idx) = idx {
|
||||
// When the mapping is already in the cache, move it to the front.
|
||||
if idx != 0 {
|
||||
let entry = cache.remove(idx);
|
||||
cache.insert(0, entry);
|
||||
}
|
||||
} else {
|
||||
// When the mapping is not in the cache, create a new mapping,
|
||||
// insert it into the front of the cache, and evict the oldest cache
|
||||
// entry if necessary.
|
||||
let opts = addr2line::Options::default()
|
||||
.with_functions();
|
||||
|
||||
let mapping = match opts.build(&path) {
|
||||
Err(_) => return,
|
||||
Ok(m) => m,
|
||||
};
|
||||
|
||||
if cache.len() == MAPPINGS_CACHE_SIZE {
|
||||
cache.pop();
|
||||
}
|
||||
|
||||
cache.insert(0, (path, mapping));
|
||||
}
|
||||
|
||||
f(&mut cache[0].1);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {
|
||||
// First, find the file containing the segment that the given AVMA (after
|
||||
// relocation) address falls within. Use the containing segment to compute
|
||||
// the SVMA (before relocation) address.
|
||||
//
|
||||
// Note that the OS APIs that `SharedLibrary::each` is implemented with hold
|
||||
// a lock for the duration of the `each` call, so we want to keep this
|
||||
// section as short as possible to avoid contention with other threads
|
||||
// capturing backtraces.
|
||||
let addr = findshlibs::Avma(addr as *mut u8 as *const u8);
|
||||
let mut so_info = None;
|
||||
findshlibs::TargetSharedLibrary::each(|so| {
|
||||
use findshlibs::IterationControl::*;
|
||||
|
||||
for segment in so.segments() {
|
||||
if segment.contains_avma(so, addr) {
|
||||
let addr = so.avma_to_svma(addr);
|
||||
let path = so.name().to_string_lossy();
|
||||
so_info = Some((addr, path.to_string()));
|
||||
return Break;
|
||||
}
|
||||
}
|
||||
|
||||
Continue
|
||||
});
|
||||
let (addr, path) = match so_info {
|
||||
None => return,
|
||||
Some((a, p)) => (a, p),
|
||||
};
|
||||
|
||||
// Second, fixup the path. Empty path means that this address falls within
|
||||
// the main executable, not a shared library.
|
||||
let path = if path.is_empty() {
|
||||
match env::current_exe() {
|
||||
Err(_) => return,
|
||||
Ok(p) => p,
|
||||
}
|
||||
} else {
|
||||
PathBuf::from(path)
|
||||
};
|
||||
|
||||
// Finally, get a cached mapping or create a new mapping for this file, and
|
||||
// evaluate the DWARF info to find the file/line/name for this address.
|
||||
with_mapping_for_path(path, |mapping| {
|
||||
let (file, line, func) = match mapping.locate(addr.0 as u64) {
|
||||
Ok(None) | Err(_) => return,
|
||||
Ok(Some((file, line, func))) => (file, line, func),
|
||||
};
|
||||
|
||||
let sym = super::Symbol {
|
||||
inner: Symbol::new(addr.0 as usize,
|
||||
file,
|
||||
line,
|
||||
func.map(|f| f.to_string()))
|
||||
};
|
||||
|
||||
cb(&sym);
|
||||
});
|
||||
}
|
||||
|
||||
pub struct Symbol {
|
||||
addr: usize,
|
||||
file: PathBuf,
|
||||
line: Option<u64>,
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
fn new(addr: usize,
|
||||
file: PathBuf,
|
||||
line: Option<u64>,
|
||||
name: Option<String>)
|
||||
-> Symbol {
|
||||
Symbol {
|
||||
addr,
|
||||
file,
|
||||
line,
|
||||
name,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Option<SymbolName> {
|
||||
self.name.as_ref().map(|s| SymbolName::new(s.as_bytes()))
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Option<*mut c_void> {
|
||||
Some(self.addr as *mut c_void)
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> Option<&Path> {
|
||||
Some(self.file.as_ref())
|
||||
}
|
||||
|
||||
pub fn lineno(&self) -> Option<u32> {
|
||||
self.line
|
||||
.and_then(|l| if l > (u32::MAX as u64) {
|
||||
None
|
||||
} else {
|
||||
Some(l as u32)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ use rustc_demangle::{try_demangle, Demangle};
|
|||
/// also may be called more than once in the case of inlined functions.
|
||||
///
|
||||
/// Symbols yielded represent the execution at the specified `addr`, returning
|
||||
/// file/line pairs for that addres (if available).
|
||||
/// file/line pairs for that address (if available).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -46,7 +46,7 @@ pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, mut cb: F) {
|
|||
/// `backtrace::resolve` function, and it is virtually dispatched as it's
|
||||
/// unknown which implementation is behind it.
|
||||
///
|
||||
/// A symbol can give contextual information about a funciton, for example the
|
||||
/// A symbol can give contextual information about a function, for example the
|
||||
/// name, filename, line number, precise address, etc. Not all information is
|
||||
/// always available in a symbol, however, so all methods return an `Option`.
|
||||
pub struct Symbol {
|
||||
|
@ -255,6 +255,12 @@ cfg_if! {
|
|||
mod dbghelp;
|
||||
use self::dbghelp::resolve as resolve_imp;
|
||||
use self::dbghelp::Symbol as SymbolImp;
|
||||
} else if #[cfg(all(feature = "gimli-symbolize",
|
||||
unix,
|
||||
target_os = "linux"))] {
|
||||
mod gimli;
|
||||
use self::gimli::resolve as resolve_imp;
|
||||
use self::gimli::Symbol as SymbolImp;
|
||||
} else if #[cfg(all(feature = "libbacktrace",
|
||||
unix,
|
||||
not(target_os = "emscripten"),
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
extern crate backtrace;
|
||||
|
||||
#[cfg(all(windows, feature = "dbghelp"))]
|
||||
extern crate winapi;
|
||||
|
||||
use backtrace::Backtrace;
|
||||
|
||||
// 50-character module name
|
||||
mod _234567890_234567890_234567890_234567890_234567890 {
|
||||
// 50-character struct name
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct _234567890_234567890_234567890_234567890_234567890<T>(T);
|
||||
impl<T> _234567890_234567890_234567890_234567890_234567890<T> {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> ::Backtrace {
|
||||
::Backtrace::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Long function names must be truncated to (MAX_SYM_NAME - 1) characters.
|
||||
// Only run this test for msvc, since gnu prints "<no info>" for all frames.
|
||||
#[test]
|
||||
#[cfg(all(windows, feature = "dbghelp", target_env = "msvc"))]
|
||||
fn test_long_fn_name() {
|
||||
use _234567890_234567890_234567890_234567890_234567890::
|
||||
_234567890_234567890_234567890_234567890_234567890 as S;
|
||||
|
||||
// 10 repetitions of struct name, so fully qualified function name is
|
||||
// atleast 10 * (50 + 50) * 2 = 2000 characters long.
|
||||
// It's actually longer since it also includes `::`, `<>` and the
|
||||
// name of the current module
|
||||
let bt = S::<S<S<S<S<S<S<S<S<S<i32>>>>>>>>>>::new();
|
||||
println!("{:?}", bt);
|
||||
|
||||
let mut found_long_name_frame = false;
|
||||
|
||||
for frame in bt.frames() {
|
||||
let symbols = frame.symbols();
|
||||
if symbols.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(function_name) = symbols[0].name() {
|
||||
let function_name = function_name.as_str().unwrap();
|
||||
if function_name.contains(
|
||||
"::_234567890_234567890_234567890_234567890_234567890")
|
||||
{
|
||||
found_long_name_frame = true;
|
||||
assert_eq!(function_name.len(), winapi::MAX_SYM_NAME - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert!(found_long_name_frame);
|
||||
}
|
|
@ -12,6 +12,9 @@ static CORESYMBOLICATION: bool = cfg!(all(any(target_os = "macos", target_os = "
|
|||
static DLADDR: bool = cfg!(all(unix, feature = "dladdr"));
|
||||
static DBGHELP: bool = cfg!(all(windows, feature = "dbghelp"));
|
||||
static MSVC: bool = cfg!(target_env = "msvc");
|
||||
static GIMLI_SYMBOLIZE: bool = cfg!(all(feature = "gimli-symbolize",
|
||||
unix,
|
||||
target_os = "linux"));
|
||||
|
||||
#[test]
|
||||
fn smoke_test_frames() {
|
||||
|
@ -71,7 +74,7 @@ fn smoke_test_frames() {
|
|||
}
|
||||
|
||||
let mut resolved = 0;
|
||||
let can_resolve = DLADDR || LIBBACKTRACE || CORESYMBOLICATION || DBGHELP;
|
||||
let can_resolve = DLADDR || LIBBACKTRACE || CORESYMBOLICATION || DBGHELP || GIMLI_SYMBOLIZE;
|
||||
|
||||
let mut name = None;
|
||||
let mut addr = None;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"79fbb792e6c1d05c44188c808ef7120c592e50291a706fe0f669b8ac9a2ad5e5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7","README.md":"b2da2fd61c4f3abf45127d183b61eb2dabc1c97cd191854987aa0328549a663f","benches/benchmarks.rs":"f0469f65f901c3e92fa506c0deb277fd136a7f968cae7cc4f030c0c15e52322f","examples/make_tables.rs":"3c80f2a8cdb204168cc1b60f8904d544b2da067b9e6a7b40ade5fb4a994b4175","src/lib.rs":"a3ac363513ae99a9b0049c19c92bc46b57ac9a0ebfd3317b7b387c5fbaa16a8a","src/tables.rs":"378743892907cde87c1a92e6afee2df36ce590311e61381b2cc0404b3e018039","tests/tests.rs":"dc2c293bae576cc596bdfb6ef783dc1d24d3bf992bf532caaebe1738cb0608cc"},"package":"30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557"}
|
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
name = "base64"
|
||||
version = "0.5.2"
|
||||
authors = ["Alice Maz <alice@alicemaz.com>", "Marshall Pierce <marshall@mpierce.org>"]
|
||||
description = "encodes and decodes base64 as bytes or utf8"
|
||||
repository = "https://github.com/alicemaz/rust-base64"
|
||||
documentation = "https://github.com/alicemaz/rust-base64/blob/master/README.md"
|
||||
readme = "README.md"
|
||||
keywords = ["base64", "utf8", "encode", "decode"]
|
||||
categories = ["encoding"]
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "=0.3.15"
|
||||
|
||||
[profile.bench]
|
||||
# Uncomment when using `perf record`
|
||||
#debug = true
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Alice Maz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,112 @@
|
|||
[base64](https://crates.io/crates/base64)
|
||||
===
|
||||
|
||||
It's base64. What more could anyone want?
|
||||
|
||||
Example
|
||||
---
|
||||
|
||||
In Cargo.toml: `base64 = "~0.5.0"`
|
||||
|
||||
```rust
|
||||
extern crate base64;
|
||||
|
||||
use base64::{encode, decode};
|
||||
|
||||
fn main() {
|
||||
let a = b"hello world";
|
||||
let b = "aGVsbG8gd29ybGQ=";
|
||||
|
||||
assert_eq!(encode(a), b);
|
||||
assert_eq!(a, &decode(b).unwrap()[..]);
|
||||
}
|
||||
```
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
base64 exposes six functions:
|
||||
|
||||
```rust
|
||||
fn encode<T: ?Sized + AsRef<[u8]>>(&T) -> String;
|
||||
fn decode<T: ?Sized + AsRef<[u8]>>(&T) -> Result<Vec<u8>, DecodeError>;
|
||||
fn encode_config<T: ?Sized + AsRef<[u8]>>(&T, Config) -> String;
|
||||
fn encode_config_buf<T: ?Sized + AsRef<[u8]>>(&T, Config, &mut String);
|
||||
fn decode_config<T: ?Sized + AsRef<[u8]>>(&T, Config) -> Result<Vec<u8>, DecodeError>;
|
||||
fn decode_config_buf<T: ?Sized + AsRef<[u8]>>(&T, Config, &mut Vec<u8>) -> Result<(), DecodeError>;
|
||||
```
|
||||
|
||||
`STANDARD`, `URL_SAFE`, `URL_SAFE_NO_PAD`, and `MIME` configuation structs are provided for convenience. `encode` and `decode` are convenience wrappers for the `_config` functions called with the `STANDARD` config, and they are themselves wrappers of the `_buf` functions that allocate on the user's behalf. Encode produces valid padding absent a config that states otherwise; decode produces the same output for valid or omitted padding in all cases, but errors on invalid (superfluous) padding. Whitespace in the input to decode is an error for all modes except `MIME`, which disregards it ("whitespace" according to POSIX-locale `isspace`, meaning \n \r \f \t \v and space).
|
||||
|
||||
`Config` exposes a constructor to allow custom combinations of character set, output padding, input whitespace permissiveness, linewrapping, and line ending character(s). The vast majority of usecases should be covered by the four provided, however.
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
||||
I have a fondness for small dependency footprints, ecosystems where you can pick and choose what functionality you need, and no more. Unix philosophy sort of thing I guess, many tiny utilities interoperating across a common interface. One time making a Twitter bot, I ran into the need to correctly pluralize arbitrary words. I found on npm a module that did nothing but pluralize words. Nothing else, just a couple of functions. I'd like for this to be that "just a couple of functions."
|
||||
|
||||
Developing
|
||||
---
|
||||
|
||||
Benchmarks are in `benches/`. Running them requires nightly rust, but `rustup` makes it easy:
|
||||
|
||||
```
|
||||
rustup run nightly cargo bench
|
||||
```
|
||||
|
||||
Decoding is aided by some pre-calculated tables, which are generated by:
|
||||
|
||||
```
|
||||
cargo run --example make_tables > src/tables.rs.tmp && mv src/tables.rs.tmp src/tables.rs
|
||||
```
|
||||
|
||||
Profiling
|
||||
---
|
||||
|
||||
On Linux, you can use [perf](https://perf.wiki.kernel.org/index.php/Main_Page) for profiling. First, enable debug symbols in Cargo.toml. Don't commit this change, though, since it's usually not what you want (and costs some performance):
|
||||
|
||||
```
|
||||
[profile.release]
|
||||
debug = true
|
||||
```
|
||||
|
||||
Then compile the benchmarks. (Just re-run them and ^C once the benchmarks start running; all that's needed is to recompile them.)
|
||||
|
||||
Run the benchmark binary with `perf` (shown here filtering to one particular benchmark, which will make the results easier to read). `perf` is only available to the root user on most systems as it fiddles with event counters in your CPU, so use `sudo`. We need to run the actual benchmark binary, hence the path into `target`. You can see the actual full path with `rustup run nightly cargo bench -v`; it will print out the commands it runs. If you use the exact path that `bench` outputs, make sure you get the one that's for the benchmarks, not the tests. You may also want to `cargo clean` so you have only one `benchmarks-` binary (they tend to accumulate).
|
||||
|
||||
```
|
||||
sudo perf record target/release/deps/benchmarks-* --bench decode_10mib_reuse
|
||||
```
|
||||
|
||||
Then analyze the results, again with perf:
|
||||
|
||||
```
|
||||
sudo perf annotate -l
|
||||
```
|
||||
|
||||
You'll see a bunch of interleaved rust source and assembly like this. The section with `lib.rs:327` is telling us that 4.02% of samples saw the `movzbl` aka bit shift as the active instruction. However, this percentage is not as exact as it seems due to a phenomenon called *skid*. Basically, a consequence of how fancy modern CPUs are is that this sort of instruction profiling is inherently inaccurate, especially in branch-heavy code.
|
||||
|
||||
```
|
||||
lib.rs:322 0.70 : 10698: mov %rdi,%rax
|
||||
2.82 : 1069b: shr $0x38,%rax
|
||||
: if morsel == decode_tables::INVALID_VALUE {
|
||||
: bad_byte_index = input_index;
|
||||
: break;
|
||||
: };
|
||||
: accum = (morsel as u64) << 58;
|
||||
lib.rs:327 4.02 : 1069f: movzbl (%r9,%rax,1),%r15d
|
||||
: // fast loop of 8 bytes at a time
|
||||
: while input_index < length_of_full_chunks {
|
||||
: let mut accum: u64;
|
||||
:
|
||||
: let input_chunk = BigEndian::read_u64(&input_bytes[input_index..(input_index + 8)]);
|
||||
: morsel = decode_table[(input_chunk >> 56) as usize];
|
||||
lib.rs:322 3.68 : 106a4: cmp $0xff,%r15
|
||||
: if morsel == decode_tables::INVALID_VALUE {
|
||||
0.00 : 106ab: je 1090e <base64::decode_config_buf::hbf68a45fefa299c1+0x46e>
|
||||
```
|
||||
|
||||
License
|
||||
---
|
||||
|
||||
This project is dual-licensed under MIT and Apache 2.0.
|
|
@ -0,0 +1,230 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate base64;
|
||||
extern crate test;
|
||||
extern crate rand;
|
||||
|
||||
use base64::{decode, decode_config_buf, encode, encode_config_buf, STANDARD};
|
||||
|
||||
use test::Bencher;
|
||||
use rand::Rng;
|
||||
|
||||
#[bench]
|
||||
fn encode_3b(b: &mut Bencher) {
|
||||
do_encode_bench(b, 3)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 3)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_50b(b: &mut Bencher) {
|
||||
do_encode_bench(b, 50)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_50b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 50)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_100b(b: &mut Bencher) {
|
||||
do_encode_bench(b, 100)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_100b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 100)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_500b(b: &mut Bencher) {
|
||||
do_encode_bench(b, 500)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_500b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 500)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3kib(b: &mut Bencher) {
|
||||
do_encode_bench(b, 3 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3kib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 3 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3mib(b: &mut Bencher) {
|
||||
do_encode_bench(b, 3 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3mib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 3 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_10mib(b: &mut Bencher) {
|
||||
do_encode_bench(b, 10 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_10mib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 10 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_30mib(b: &mut Bencher) {
|
||||
do_encode_bench(b, 30 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_30mib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 30 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3b(b: &mut Bencher) {
|
||||
do_decode_bench(b, 3)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3b_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 3)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_50b(b: &mut Bencher) {
|
||||
do_decode_bench(b, 50)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_50b_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 50)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_100b(b: &mut Bencher) {
|
||||
do_decode_bench(b, 100)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_100b_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 100)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_500b(b: &mut Bencher) {
|
||||
do_decode_bench(b, 500)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_500b_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 500)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3kib(b: &mut Bencher) {
|
||||
do_decode_bench(b, 3 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3kib_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 3 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3mib(b: &mut Bencher) {
|
||||
do_decode_bench(b, 3 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3mib_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 3 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_10mib(b: &mut Bencher) {
|
||||
do_decode_bench(b, 10 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_10mib_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 10 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_30mib(b: &mut Bencher) {
|
||||
do_decode_bench(b, 30 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_30mib_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 30 * 1024 * 1024)
|
||||
}
|
||||
|
||||
fn do_decode_bench(b: &mut Bencher, size: usize) {
|
||||
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
|
||||
fill(&mut v);
|
||||
let encoded = encode(&v);
|
||||
|
||||
b.bytes = encoded.len() as u64;
|
||||
b.iter(|| {
|
||||
let orig = decode(&encoded);
|
||||
test::black_box(&orig);
|
||||
});
|
||||
}
|
||||
|
||||
fn do_decode_bench_reuse_buf(b: &mut Bencher, size: usize) {
|
||||
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
|
||||
fill(&mut v);
|
||||
let encoded = encode(&v);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
b.bytes = encoded.len() as u64;
|
||||
b.iter(|| {
|
||||
decode_config_buf(&encoded, STANDARD, &mut buf).unwrap();
|
||||
test::black_box(&buf);
|
||||
buf.clear();
|
||||
});
|
||||
}
|
||||
|
||||
fn do_encode_bench(b: &mut Bencher, size: usize) {
|
||||
let mut v: Vec<u8> = Vec::with_capacity(size);
|
||||
fill(&mut v);
|
||||
|
||||
b.bytes = v.len() as u64;
|
||||
b.iter(|| {
|
||||
let e = encode(&v);
|
||||
test::black_box(&e);
|
||||
});
|
||||
}
|
||||
|
||||
fn do_encode_bench_reuse_buf(b: &mut Bencher, size: usize) {
|
||||
let mut v: Vec<u8> = Vec::with_capacity(size);
|
||||
fill(&mut v);
|
||||
|
||||
let mut buf = String::new();
|
||||
|
||||
b.bytes = v.len() as u64;
|
||||
b.iter(|| {
|
||||
let e = encode_config_buf(&v, STANDARD, &mut buf);
|
||||
test::black_box(&e);
|
||||
buf.clear();
|
||||
});
|
||||
}
|
||||
|
||||
fn fill(v: &mut Vec<u8>) {
|
||||
let cap = v.capacity();
|
||||
// weak randomness is plenty; we just want to not be completely friendly to the branch predictor
|
||||
let mut r = rand::weak_rng();
|
||||
while v.len() < cap {
|
||||
v.push(r.gen::<u8>());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
use std::collections::HashMap;
|
||||
use std::iter::Iterator;
|
||||
|
||||
fn main() {
|
||||
println!("pub const INVALID_VALUE: u8 = 255;");
|
||||
|
||||
// A-Z
|
||||
let standard_alphabet: Vec<u8> = (0x41..0x5B)
|
||||
// a-z
|
||||
.chain(0x61..0x7B)
|
||||
// 0-9
|
||||
.chain(0x30..0x3A)
|
||||
// +
|
||||
.chain(0x2B..0x2C)
|
||||
// /
|
||||
.chain(0x2F..0x30)
|
||||
.collect();
|
||||
print_encode_table(&standard_alphabet, "STANDARD_ENCODE", 0);
|
||||
print_decode_table(&standard_alphabet, "STANDARD_DECODE", 0);
|
||||
|
||||
// A-Z
|
||||
let url_alphabet: Vec<u8> = (0x41..0x5B)
|
||||
// a-z
|
||||
.chain(0x61..0x7B)
|
||||
// 0-9
|
||||
.chain(0x30..0x3A)
|
||||
// -
|
||||
.chain(0x2D..0x2E)
|
||||
// _s
|
||||
.chain(0x5F..0x60)
|
||||
.collect();
|
||||
print_encode_table(&url_alphabet, "URL_SAFE_ENCODE", 0);
|
||||
print_decode_table(&url_alphabet, "URL_SAFE_DECODE", 0);
|
||||
|
||||
}
|
||||
|
||||
fn print_encode_table(alphabet: &[u8], const_name: &str, indent_depth: usize) {
|
||||
println!("{:width$}pub const {}: &'static [u8; 64] = &[", "", const_name, width=indent_depth);
|
||||
|
||||
for (i, b) in alphabet.iter().enumerate() {
|
||||
println!("{:width$}{}, // input {} (0x{:X}) => '{}' (0x{:X})", "",
|
||||
b, i, i, String::from_utf8(vec!(*b as u8)).unwrap(), b, width=indent_depth + 4);
|
||||
}
|
||||
|
||||
println!("{:width$}];", "", width=indent_depth);
|
||||
}
|
||||
|
||||
fn print_decode_table(alphabet: &[u8], const_name: &str, indent_depth: usize) {
|
||||
// map of alphabet bytes to 6-bit morsels
|
||||
let mut input_to_morsel = HashMap::<u8, u8>::new();
|
||||
|
||||
// standard base64 alphabet bytes, in order
|
||||
for (morsel, ascii_byte) in alphabet.iter().enumerate() {
|
||||
// truncation cast is fine here
|
||||
let _ = input_to_morsel.insert(*ascii_byte, morsel as u8);
|
||||
}
|
||||
|
||||
println!("{:width$}pub const {}: &'static [u8; 256] = &[", "", const_name, width=indent_depth);
|
||||
for ascii_byte in 0..256 {
|
||||
let (value, comment) = match input_to_morsel.get(&(ascii_byte as u8)) {
|
||||
None => ("INVALID_VALUE".to_string(),
|
||||
format!("input {} (0x{:X})", ascii_byte, ascii_byte)),
|
||||
Some(v) => (format!("{}", *v),
|
||||
format!("input {} (0x{:X} char '{}') => {} (0x{:X})",
|
||||
ascii_byte,
|
||||
ascii_byte,
|
||||
String::from_utf8(vec!(ascii_byte as u8)).unwrap(), *v, *v))
|
||||
};
|
||||
|
||||
println!("{:width$}{}, // {}", "", value, comment, width=indent_depth + 4);
|
||||
}
|
||||
println!("{:width$}];", "", width=indent_depth);
|
||||
}
|
|
@ -0,0 +1,675 @@
|
|||
extern crate byteorder;
|
||||
|
||||
use std::{fmt, error, str};
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
mod tables;
|
||||
|
||||
/// Available encoding character sets
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CharacterSet {
|
||||
/// The standard character set (uses `+` and `/`)
|
||||
Standard,
|
||||
/// The URL safe character set (uses `-` and `_`)
|
||||
UrlSafe
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum LineEnding {
|
||||
LF,
|
||||
CRLF,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum LineWrap {
|
||||
NoWrap,
|
||||
Wrap(usize, LineEnding)
|
||||
}
|
||||
|
||||
/// Contains configuration parameters for base64 encoding
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Config {
|
||||
/// Character set to use
|
||||
char_set: CharacterSet,
|
||||
/// True to pad output with `=` characters
|
||||
pad: bool,
|
||||
/// Remove whitespace before decoding, at the cost of an allocation
|
||||
strip_whitespace: bool,
|
||||
/// ADT signifying whether to linewrap output, and if so by how many characters and with what ending
|
||||
line_wrap: LineWrap,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(char_set: CharacterSet,
|
||||
pad: bool,
|
||||
strip_whitespace: bool,
|
||||
input_line_wrap: LineWrap) -> Config {
|
||||
let line_wrap = match input_line_wrap {
|
||||
LineWrap::Wrap(0, _) => LineWrap::NoWrap,
|
||||
_ => input_line_wrap,
|
||||
};
|
||||
|
||||
Config {
|
||||
char_set: char_set,
|
||||
pad: pad,
|
||||
strip_whitespace: strip_whitespace,
|
||||
line_wrap: line_wrap,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static STANDARD: Config = Config {
|
||||
char_set: CharacterSet::Standard,
|
||||
pad: true,
|
||||
strip_whitespace: false,
|
||||
line_wrap: LineWrap::NoWrap,
|
||||
};
|
||||
|
||||
pub static MIME: Config = Config {
|
||||
char_set: CharacterSet::Standard,
|
||||
pad: true,
|
||||
strip_whitespace: true,
|
||||
line_wrap: LineWrap::Wrap(76, LineEnding::CRLF),
|
||||
};
|
||||
|
||||
pub static URL_SAFE: Config = Config {
|
||||
char_set: CharacterSet::UrlSafe,
|
||||
pad: true,
|
||||
strip_whitespace: false,
|
||||
line_wrap: LineWrap::NoWrap,
|
||||
};
|
||||
|
||||
pub static URL_SAFE_NO_PAD: Config = Config {
|
||||
char_set: CharacterSet::UrlSafe,
|
||||
pad: false,
|
||||
strip_whitespace: false,
|
||||
line_wrap: LineWrap::NoWrap,
|
||||
};
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum DecodeError {
|
||||
InvalidByte(usize, u8),
|
||||
InvalidLength,
|
||||
}
|
||||
|
||||
impl fmt::Display for DecodeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
DecodeError::InvalidByte(index, byte) =>
|
||||
write!(f, "Invalid byte {}, offset {}.", byte, index),
|
||||
DecodeError::InvalidLength =>
|
||||
write!(f, "Encoded text cannot have a 6-bit remainder.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for DecodeError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
DecodeError::InvalidByte(_, _) => "invalid byte",
|
||||
DecodeError::InvalidLength => "invalid length"
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
///Encode arbitrary octets as base64.
|
||||
///Returns a String.
|
||||
///Convenience for `encode_config(input, base64::STANDARD);`.
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let b64 = base64::encode(b"hello world");
|
||||
/// println!("{}", b64);
|
||||
///}
|
||||
///```
|
||||
pub fn encode<T: ?Sized + AsRef<[u8]>>(input: &T) -> String {
|
||||
encode_config(input, STANDARD)
|
||||
}
|
||||
|
||||
///Decode from string reference as octets.
|
||||
///Returns a Result containing a Vec<u8>.
|
||||
///Convenience `decode_config(input, base64::STANDARD);`.
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let bytes = base64::decode("aGVsbG8gd29ybGQ=").unwrap();
|
||||
/// println!("{:?}", bytes);
|
||||
///}
|
||||
///```
|
||||
pub fn decode<T: ?Sized + AsRef<[u8]>>(input: &T) -> Result<Vec<u8>, DecodeError> {
|
||||
decode_config(input, STANDARD)
|
||||
}
|
||||
|
||||
///Encode arbitrary octets as base64.
|
||||
///Returns a String.
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let b64 = base64::encode_config(b"hello world~", base64::STANDARD);
|
||||
/// println!("{}", b64);
|
||||
///
|
||||
/// let b64_url = base64::encode_config(b"hello internet~", base64::URL_SAFE);
|
||||
/// println!("{}", b64_url);
|
||||
///}
|
||||
///```
|
||||
pub fn encode_config<T: ?Sized + AsRef<[u8]>>(input: &T, config: Config) -> String {
|
||||
let mut buf = match encoded_size(input.as_ref().len(), config) {
|
||||
Some(n) => String::with_capacity(n),
|
||||
None => panic!("integer overflow when calculating buffer size")
|
||||
};
|
||||
|
||||
encode_config_buf(input, config, &mut buf);
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
/// calculate the base64 encoded string size, including padding
|
||||
fn encoded_size(bytes_len: usize, config: Config) -> Option<usize> {
|
||||
let printing_output_chars = bytes_len
|
||||
.checked_add(2)
|
||||
.map(|x| x / 3)
|
||||
.and_then(|x| x.checked_mul(4));
|
||||
|
||||
//TODO this is subtly wrong but in a not dangerous way
|
||||
//pushing patch with identical to previous behavior, then fixing
|
||||
let line_ending_output_chars = match config.line_wrap {
|
||||
LineWrap::NoWrap => Some(0),
|
||||
LineWrap::Wrap(n, LineEnding::CRLF) =>
|
||||
printing_output_chars.map(|y| y / n).and_then(|y| y.checked_mul(2)),
|
||||
LineWrap::Wrap(n, LineEnding::LF) =>
|
||||
printing_output_chars.map(|y| y / n),
|
||||
};
|
||||
|
||||
printing_output_chars.and_then(|x|
|
||||
line_ending_output_chars.and_then(|y| x.checked_add(y))
|
||||
)
|
||||
}
|
||||
|
||||
///Encode arbitrary octets as base64.
|
||||
///Writes into the supplied buffer to avoid allocations.
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let mut buf = String::new();
|
||||
/// base64::encode_config_buf(b"hello world~", base64::STANDARD, &mut buf);
|
||||
/// println!("{}", buf);
|
||||
///
|
||||
/// buf.clear();
|
||||
/// base64::encode_config_buf(b"hello internet~", base64::URL_SAFE, &mut buf);
|
||||
/// println!("{}", buf);
|
||||
///}
|
||||
///```
|
||||
pub fn encode_config_buf<T: ?Sized + AsRef<[u8]>>(input: &T, config: Config, buf: &mut String) {
|
||||
let input_bytes = input.as_ref();
|
||||
let ref charset = match config.char_set {
|
||||
CharacterSet::Standard => tables::STANDARD_ENCODE,
|
||||
CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE,
|
||||
};
|
||||
|
||||
// reserve to make sure the memory we'll be writing to with unsafe is allocated
|
||||
let resv_size = match encoded_size(input_bytes.len(), config) {
|
||||
Some(n) => n,
|
||||
None => panic!("integer overflow when calculating buffer size"),
|
||||
};
|
||||
buf.reserve(resv_size);
|
||||
|
||||
let orig_buf_len = buf.len();
|
||||
let mut fast_loop_output_buf_len = orig_buf_len;
|
||||
|
||||
let input_chunk_len = 6;
|
||||
|
||||
let last_fast_index = input_bytes.len().saturating_sub(8);
|
||||
|
||||
// we're only going to insert valid utf8
|
||||
let mut raw = unsafe { buf.as_mut_vec() };
|
||||
// start at the first free part of the output buf
|
||||
let mut output_ptr = unsafe { raw.as_mut_ptr().offset(orig_buf_len as isize) };
|
||||
let mut input_index: usize = 0;
|
||||
if input_bytes.len() >= 8 {
|
||||
while input_index <= last_fast_index {
|
||||
let input_chunk = BigEndian::read_u64(&input_bytes[input_index..(input_index + 8)]);
|
||||
|
||||
// strip off 6 bits at a time for the first 6 bytes
|
||||
unsafe {
|
||||
std::ptr::write(output_ptr, charset[((input_chunk >> 58) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(1), charset[((input_chunk >> 52) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(2), charset[((input_chunk >> 46) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(3), charset[((input_chunk >> 40) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(4), charset[((input_chunk >> 34) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(5), charset[((input_chunk >> 28) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(6), charset[((input_chunk >> 22) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(7), charset[((input_chunk >> 16) & 0x3F) as usize]);
|
||||
output_ptr = output_ptr.offset(8);
|
||||
}
|
||||
|
||||
input_index += input_chunk_len;
|
||||
fast_loop_output_buf_len += 8;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// expand len to include the bytes we just wrote
|
||||
raw.set_len(fast_loop_output_buf_len);
|
||||
}
|
||||
|
||||
// encode the 0 to 7 bytes left after the fast loop
|
||||
|
||||
let rem = input_bytes.len() % 3;
|
||||
let start_of_rem = input_bytes.len() - rem;
|
||||
|
||||
// start at the first index not handled by fast loop, which may be 0.
|
||||
let mut leftover_index = input_index;
|
||||
|
||||
while leftover_index < start_of_rem {
|
||||
raw.push(charset[(input_bytes[leftover_index] >> 2) as usize]);
|
||||
raw.push(charset[((input_bytes[leftover_index] << 4 | input_bytes[leftover_index + 1] >> 4) & 0x3f) as usize]);
|
||||
raw.push(charset[((input_bytes[leftover_index + 1] << 2 | input_bytes[leftover_index + 2] >> 6) & 0x3f) as usize]);
|
||||
raw.push(charset[(input_bytes[leftover_index + 2] & 0x3f) as usize]);
|
||||
|
||||
leftover_index += 3;
|
||||
}
|
||||
|
||||
if rem == 2 {
|
||||
raw.push(charset[(input_bytes[start_of_rem] >> 2) as usize]);
|
||||
raw.push(charset[((input_bytes[start_of_rem] << 4 | input_bytes[start_of_rem + 1] >> 4) & 0x3f) as usize]);
|
||||
raw.push(charset[(input_bytes[start_of_rem + 1] << 2 & 0x3f) as usize]);
|
||||
} else if rem == 1 {
|
||||
raw.push(charset[(input_bytes[start_of_rem] >> 2) as usize]);
|
||||
raw.push(charset[(input_bytes[start_of_rem] << 4 & 0x3f) as usize]);
|
||||
}
|
||||
|
||||
if config.pad {
|
||||
for _ in 0..((3 - rem) % 3) {
|
||||
raw.push(0x3d);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO FIXME this does the wrong thing for nonempty buffers
|
||||
if orig_buf_len == 0 {
|
||||
if let LineWrap::Wrap(line_size, line_end) = config.line_wrap {
|
||||
let len = raw.len();
|
||||
let mut i = 0;
|
||||
let mut j = 0;
|
||||
|
||||
while i < len {
|
||||
if i > 0 && i % line_size == 0 {
|
||||
match line_end {
|
||||
LineEnding::LF => { raw.insert(j, b'\n'); j += 1; }
|
||||
LineEnding::CRLF => { raw.insert(j, b'\r'); raw.insert(j + 1, b'\n'); j += 2; }
|
||||
}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Decode from string reference as octets.
|
||||
///Returns a Result containing a Vec<u8>.
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let bytes = base64::decode_config("aGVsbG8gd29ybGR+Cg==", base64::STANDARD).unwrap();
|
||||
/// println!("{:?}", bytes);
|
||||
///
|
||||
/// let bytes_url = base64::decode_config("aGVsbG8gaW50ZXJuZXR-Cg==", base64::URL_SAFE).unwrap();
|
||||
/// println!("{:?}", bytes_url);
|
||||
///}
|
||||
///```
|
||||
pub fn decode_config<T: ?Sized + AsRef<[u8]>>(input: &T, config: Config) -> Result<Vec<u8>, DecodeError> {
|
||||
let mut buffer = Vec::<u8>::with_capacity(input.as_ref().len() * 4 / 3);
|
||||
|
||||
decode_config_buf(input, config, &mut buffer).map(|_| buffer)
|
||||
}
|
||||
|
||||
///Decode from string reference as octets.
|
||||
///Writes into the supplied buffer to avoid allocation.
|
||||
///Returns a Result containing an empty tuple, aka ().
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let mut buffer = Vec::<u8>::new();
|
||||
/// base64::decode_config_buf("aGVsbG8gd29ybGR+Cg==", base64::STANDARD, &mut buffer).unwrap();
|
||||
/// println!("{:?}", buffer);
|
||||
///
|
||||
/// buffer.clear();
|
||||
///
|
||||
/// base64::decode_config_buf("aGVsbG8gaW50ZXJuZXR-Cg==", base64::URL_SAFE, &mut buffer).unwrap();
|
||||
/// println!("{:?}", buffer);
|
||||
///}
|
||||
///```
|
||||
pub fn decode_config_buf<T: ?Sized + AsRef<[u8]>>(input: &T,
|
||||
config: Config,
|
||||
buffer: &mut Vec<u8>)
|
||||
-> Result<(), DecodeError> {
|
||||
let mut input_copy;
|
||||
let input_bytes = if config.strip_whitespace {
|
||||
input_copy = Vec::<u8>::with_capacity(input.as_ref().len());
|
||||
input_copy.extend(input.as_ref().iter().filter(|b| !b" \n\t\r\x0b\x0c".contains(b)));
|
||||
|
||||
input_copy.as_ref()
|
||||
} else {
|
||||
input.as_ref()
|
||||
};
|
||||
|
||||
let ref decode_table = match config.char_set {
|
||||
CharacterSet::Standard => tables::STANDARD_DECODE,
|
||||
CharacterSet::UrlSafe => tables::URL_SAFE_DECODE,
|
||||
};
|
||||
|
||||
buffer.reserve(input_bytes.len() * 3 / 4);
|
||||
|
||||
// the fast loop only handles complete chunks of 8 input bytes without padding
|
||||
let chunk_len = 8;
|
||||
let decoded_chunk_len = 6;
|
||||
let remainder_len = input_bytes.len() % chunk_len;
|
||||
let trailing_bytes_to_skip = if remainder_len == 0 {
|
||||
// if input is a multiple of the chunk size, ignore the last chunk as it may have padding
|
||||
chunk_len
|
||||
} else {
|
||||
remainder_len
|
||||
};
|
||||
|
||||
let length_of_full_chunks = input_bytes.len().saturating_sub(trailing_bytes_to_skip);
|
||||
|
||||
let starting_output_index = buffer.len();
|
||||
// Resize to hold decoded output from fast loop. Need the extra two bytes because
|
||||
// we write a full 8 bytes for the last 6-byte decoded chunk and then truncate off two
|
||||
let new_size = starting_output_index
|
||||
+ length_of_full_chunks / chunk_len * decoded_chunk_len
|
||||
+ (chunk_len - decoded_chunk_len);
|
||||
buffer.resize(new_size, 0);
|
||||
|
||||
let mut output_index = starting_output_index;
|
||||
|
||||
{
|
||||
let buffer_slice = buffer.as_mut_slice();
|
||||
|
||||
let mut input_index = 0;
|
||||
// initial value is never used; always set if fast loop breaks
|
||||
let mut bad_byte_index: usize = 0;
|
||||
// a non-invalid value means it's not an error if fast loop never runs
|
||||
let mut morsel: u8 = 0;
|
||||
|
||||
// fast loop of 8 bytes at a time
|
||||
while input_index < length_of_full_chunks {
|
||||
let mut accum: u64;
|
||||
|
||||
let input_chunk = BigEndian::read_u64(&input_bytes[input_index..(input_index + 8)]);
|
||||
morsel = decode_table[(input_chunk >> 56) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index;
|
||||
break;
|
||||
};
|
||||
accum = (morsel as u64) << 58;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 48 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 1;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 52;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 40 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 2;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 46;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 32 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 3;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 40;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 24 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 4;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 34;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 16 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 5;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 28;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 8 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 6;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 22;
|
||||
|
||||
morsel = decode_table[(input_chunk & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 7;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 16;
|
||||
|
||||
BigEndian::write_u64(&mut buffer_slice[(output_index)..(output_index + 8)],
|
||||
accum);
|
||||
|
||||
output_index += 6;
|
||||
input_index += chunk_len;
|
||||
};
|
||||
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
// we got here from a break
|
||||
return Err(DecodeError::InvalidByte(bad_byte_index, input_bytes[bad_byte_index]));
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate off the last two bytes from writing the last u64.
|
||||
// Unconditional because we added on the extra 2 bytes in the resize before the loop,
|
||||
// so it will never underflow.
|
||||
let new_len = buffer.len() - (chunk_len - decoded_chunk_len);
|
||||
buffer.truncate(new_len);
|
||||
|
||||
// handle leftovers (at most 8 bytes, decoded to 6).
|
||||
// Use a u64 as a stack-resident 8 bytes buffer.
|
||||
let mut leftover_bits: u64 = 0;
|
||||
let mut morsels_in_leftover = 0;
|
||||
let mut padding_bytes = 0;
|
||||
let mut first_padding_index: usize = 0;
|
||||
for (i, b) in input_bytes[length_of_full_chunks..].iter().enumerate() {
|
||||
// '=' padding
|
||||
if *b == 0x3D {
|
||||
// There can be bad padding in a few ways:
|
||||
// 1 - Padding with non-padding characters after it
|
||||
// 2 - Padding after zero or one non-padding characters before it
|
||||
// in the current quad.
|
||||
// 3 - More than two characters of padding. If 3 or 4 padding chars
|
||||
// are in the same quad, that implies it will be caught by #2.
|
||||
// If it spreads from one quad to another, it will be caught by
|
||||
// #2 in the second quad.
|
||||
|
||||
if i % 4 < 2 {
|
||||
// Check for case #2.
|
||||
// TODO InvalidPadding error
|
||||
return Err(DecodeError::InvalidByte(length_of_full_chunks + i, *b));
|
||||
};
|
||||
|
||||
if padding_bytes == 0 {
|
||||
first_padding_index = i;
|
||||
};
|
||||
|
||||
padding_bytes += 1;
|
||||
continue;
|
||||
};
|
||||
|
||||
// Check for case #1.
|
||||
// To make '=' handling consistent with the main loop, don't allow
|
||||
// non-suffix '=' in trailing chunk either. Report error as first
|
||||
// erroneous padding.
|
||||
if padding_bytes > 0 {
|
||||
return Err(DecodeError::InvalidByte(
|
||||
length_of_full_chunks + first_padding_index, 0x3D));
|
||||
};
|
||||
|
||||
// can use up to 8 * 6 = 48 bits of the u64, if last chunk has no padding.
|
||||
// To minimize shifts, pack the leftovers from left to right.
|
||||
let shift = 64 - (morsels_in_leftover + 1) * 6;
|
||||
// tables are all 256 elements, cannot overflow from a u8 index
|
||||
let morsel = decode_table[*b as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
return Err(DecodeError::InvalidByte(length_of_full_chunks + i, *b));
|
||||
};
|
||||
|
||||
leftover_bits |= (morsel as u64) << shift;
|
||||
morsels_in_leftover += 1;
|
||||
};
|
||||
|
||||
let leftover_bits_ready_to_append = match morsels_in_leftover {
|
||||
0 => 0,
|
||||
1 => return Err(DecodeError::InvalidLength),
|
||||
2 => 8,
|
||||
3 => 16,
|
||||
4 => 24,
|
||||
5 => return Err(DecodeError::InvalidLength),
|
||||
6 => 32,
|
||||
7 => 40,
|
||||
8 => 48,
|
||||
_ => panic!("Impossible: must only have 0 to 4 input bytes in last quad")
|
||||
};
|
||||
|
||||
let mut leftover_bits_appended_to_buf = 0;
|
||||
while leftover_bits_appended_to_buf < leftover_bits_ready_to_append {
|
||||
// `as` simply truncates the higher bits, which is what we want here
|
||||
let selected_bits = (leftover_bits >> (56 - leftover_bits_appended_to_buf)) as u8;
|
||||
buffer.push(selected_bits);
|
||||
|
||||
leftover_bits_appended_to_buf += 8;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn encoded_size_correct() {
|
||||
assert_eq!(Some(0), encoded_size(0, STANDARD));
|
||||
|
||||
assert_eq!(Some(4), encoded_size(1, STANDARD));
|
||||
assert_eq!(Some(4), encoded_size(2, STANDARD));
|
||||
assert_eq!(Some(4), encoded_size(3, STANDARD));
|
||||
|
||||
assert_eq!(Some(8), encoded_size(4, STANDARD));
|
||||
assert_eq!(Some(8), encoded_size(5, STANDARD));
|
||||
assert_eq!(Some(8), encoded_size(6, STANDARD));
|
||||
|
||||
assert_eq!(Some(12), encoded_size(7, STANDARD));
|
||||
assert_eq!(Some(12), encoded_size(8, STANDARD));
|
||||
assert_eq!(Some(12), encoded_size(9, STANDARD));
|
||||
|
||||
assert_eq!(Some(72), encoded_size(54, STANDARD));
|
||||
|
||||
assert_eq!(Some(76), encoded_size(55, STANDARD));
|
||||
assert_eq!(Some(76), encoded_size(56, STANDARD));
|
||||
assert_eq!(Some(76), encoded_size(57, STANDARD));
|
||||
|
||||
assert_eq!(Some(80), encoded_size(58, STANDARD));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoded_size_correct_mime() {
|
||||
assert_eq!(Some(0), encoded_size(0, MIME));
|
||||
|
||||
assert_eq!(Some(4), encoded_size(1, MIME));
|
||||
assert_eq!(Some(4), encoded_size(2, MIME));
|
||||
assert_eq!(Some(4), encoded_size(3, MIME));
|
||||
|
||||
assert_eq!(Some(8), encoded_size(4, MIME));
|
||||
assert_eq!(Some(8), encoded_size(5, MIME));
|
||||
assert_eq!(Some(8), encoded_size(6, MIME));
|
||||
|
||||
assert_eq!(Some(12), encoded_size(7, MIME));
|
||||
assert_eq!(Some(12), encoded_size(8, MIME));
|
||||
assert_eq!(Some(12), encoded_size(9, MIME));
|
||||
|
||||
assert_eq!(Some(72), encoded_size(54, MIME));
|
||||
|
||||
assert_eq!(Some(78), encoded_size(55, MIME));
|
||||
assert_eq!(Some(78), encoded_size(56, MIME));
|
||||
assert_eq!(Some(78), encoded_size(57, MIME));
|
||||
|
||||
assert_eq!(Some(82), encoded_size(58, MIME));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoded_size_correct_lf() {
|
||||
let config = Config::new(
|
||||
CharacterSet::Standard,
|
||||
true,
|
||||
false,
|
||||
LineWrap::Wrap(76, LineEnding::LF)
|
||||
);
|
||||
|
||||
assert_eq!(Some(0), encoded_size(0, config));
|
||||
|
||||
assert_eq!(Some(4), encoded_size(1, config));
|
||||
assert_eq!(Some(4), encoded_size(2, config));
|
||||
assert_eq!(Some(4), encoded_size(3, config));
|
||||
|
||||
assert_eq!(Some(8), encoded_size(4, config));
|
||||
assert_eq!(Some(8), encoded_size(5, config));
|
||||
assert_eq!(Some(8), encoded_size(6, config));
|
||||
|
||||
assert_eq!(Some(12), encoded_size(7, config));
|
||||
assert_eq!(Some(12), encoded_size(8, config));
|
||||
assert_eq!(Some(12), encoded_size(9, config));
|
||||
|
||||
assert_eq!(Some(72), encoded_size(54, config));
|
||||
|
||||
assert_eq!(Some(77), encoded_size(55, config));
|
||||
assert_eq!(Some(77), encoded_size(56, config));
|
||||
assert_eq!(Some(77), encoded_size(57, config));
|
||||
|
||||
assert_eq!(Some(81), encoded_size(58, config));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoded_size_overflow() {
|
||||
assert_eq!(None, encoded_size(std::usize::MAX, STANDARD));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,649 @@
|
|||
pub const INVALID_VALUE: u8 = 255;
|
||||
pub const STANDARD_ENCODE: &'static [u8; 64] = &[
|
||||
65, // input 0 (0x0) => 'A' (0x41)
|
||||
66, // input 1 (0x1) => 'B' (0x42)
|
||||
67, // input 2 (0x2) => 'C' (0x43)
|
||||
68, // input 3 (0x3) => 'D' (0x44)
|
||||
69, // input 4 (0x4) => 'E' (0x45)
|
||||
70, // input 5 (0x5) => 'F' (0x46)
|
||||
71, // input 6 (0x6) => 'G' (0x47)
|
||||
72, // input 7 (0x7) => 'H' (0x48)
|
||||
73, // input 8 (0x8) => 'I' (0x49)
|
||||
74, // input 9 (0x9) => 'J' (0x4A)
|
||||
75, // input 10 (0xA) => 'K' (0x4B)
|
||||
76, // input 11 (0xB) => 'L' (0x4C)
|
||||
77, // input 12 (0xC) => 'M' (0x4D)
|
||||
78, // input 13 (0xD) => 'N' (0x4E)
|
||||
79, // input 14 (0xE) => 'O' (0x4F)
|
||||
80, // input 15 (0xF) => 'P' (0x50)
|
||||
81, // input 16 (0x10) => 'Q' (0x51)
|
||||
82, // input 17 (0x11) => 'R' (0x52)
|
||||
83, // input 18 (0x12) => 'S' (0x53)
|
||||
84, // input 19 (0x13) => 'T' (0x54)
|
||||
85, // input 20 (0x14) => 'U' (0x55)
|
||||
86, // input 21 (0x15) => 'V' (0x56)
|
||||
87, // input 22 (0x16) => 'W' (0x57)
|
||||
88, // input 23 (0x17) => 'X' (0x58)
|
||||
89, // input 24 (0x18) => 'Y' (0x59)
|
||||
90, // input 25 (0x19) => 'Z' (0x5A)
|
||||
97, // input 26 (0x1A) => 'a' (0x61)
|
||||
98, // input 27 (0x1B) => 'b' (0x62)
|
||||
99, // input 28 (0x1C) => 'c' (0x63)
|
||||
100, // input 29 (0x1D) => 'd' (0x64)
|
||||
101, // input 30 (0x1E) => 'e' (0x65)
|
||||
102, // input 31 (0x1F) => 'f' (0x66)
|
||||
103, // input 32 (0x20) => 'g' (0x67)
|
||||
104, // input 33 (0x21) => 'h' (0x68)
|
||||
105, // input 34 (0x22) => 'i' (0x69)
|
||||
106, // input 35 (0x23) => 'j' (0x6A)
|
||||
107, // input 36 (0x24) => 'k' (0x6B)
|
||||
108, // input 37 (0x25) => 'l' (0x6C)
|
||||
109, // input 38 (0x26) => 'm' (0x6D)
|
||||
110, // input 39 (0x27) => 'n' (0x6E)
|
||||
111, // input 40 (0x28) => 'o' (0x6F)
|
||||
112, // input 41 (0x29) => 'p' (0x70)
|
||||
113, // input 42 (0x2A) => 'q' (0x71)
|
||||
114, // input 43 (0x2B) => 'r' (0x72)
|
||||
115, // input 44 (0x2C) => 's' (0x73)
|
||||
116, // input 45 (0x2D) => 't' (0x74)
|
||||
117, // input 46 (0x2E) => 'u' (0x75)
|
||||
118, // input 47 (0x2F) => 'v' (0x76)
|
||||
119, // input 48 (0x30) => 'w' (0x77)
|
||||
120, // input 49 (0x31) => 'x' (0x78)
|
||||
121, // input 50 (0x32) => 'y' (0x79)
|
||||
122, // input 51 (0x33) => 'z' (0x7A)
|
||||
48, // input 52 (0x34) => '0' (0x30)
|
||||
49, // input 53 (0x35) => '1' (0x31)
|
||||
50, // input 54 (0x36) => '2' (0x32)
|
||||
51, // input 55 (0x37) => '3' (0x33)
|
||||
52, // input 56 (0x38) => '4' (0x34)
|
||||
53, // input 57 (0x39) => '5' (0x35)
|
||||
54, // input 58 (0x3A) => '6' (0x36)
|
||||
55, // input 59 (0x3B) => '7' (0x37)
|
||||
56, // input 60 (0x3C) => '8' (0x38)
|
||||
57, // input 61 (0x3D) => '9' (0x39)
|
||||
43, // input 62 (0x3E) => '+' (0x2B)
|
||||
47, // input 63 (0x3F) => '/' (0x2F)
|
||||
];
|
||||
pub const STANDARD_DECODE: &'static [u8; 256] = &[
|
||||
INVALID_VALUE, // input 0 (0x0)
|
||||
INVALID_VALUE, // input 1 (0x1)
|
||||
INVALID_VALUE, // input 2 (0x2)
|
||||
INVALID_VALUE, // input 3 (0x3)
|
||||
INVALID_VALUE, // input 4 (0x4)
|
||||
INVALID_VALUE, // input 5 (0x5)
|
||||
INVALID_VALUE, // input 6 (0x6)
|
||||
INVALID_VALUE, // input 7 (0x7)
|
||||
INVALID_VALUE, // input 8 (0x8)
|
||||
INVALID_VALUE, // input 9 (0x9)
|
||||
INVALID_VALUE, // input 10 (0xA)
|
||||
INVALID_VALUE, // input 11 (0xB)
|
||||
INVALID_VALUE, // input 12 (0xC)
|
||||
INVALID_VALUE, // input 13 (0xD)
|
||||
INVALID_VALUE, // input 14 (0xE)
|
||||
INVALID_VALUE, // input 15 (0xF)
|
||||
INVALID_VALUE, // input 16 (0x10)
|
||||
INVALID_VALUE, // input 17 (0x11)
|
||||
INVALID_VALUE, // input 18 (0x12)
|
||||
INVALID_VALUE, // input 19 (0x13)
|
||||
INVALID_VALUE, // input 20 (0x14)
|
||||
INVALID_VALUE, // input 21 (0x15)
|
||||
INVALID_VALUE, // input 22 (0x16)
|
||||
INVALID_VALUE, // input 23 (0x17)
|
||||
INVALID_VALUE, // input 24 (0x18)
|
||||
INVALID_VALUE, // input 25 (0x19)
|
||||
INVALID_VALUE, // input 26 (0x1A)
|
||||
INVALID_VALUE, // input 27 (0x1B)
|
||||
INVALID_VALUE, // input 28 (0x1C)
|
||||
INVALID_VALUE, // input 29 (0x1D)
|
||||
INVALID_VALUE, // input 30 (0x1E)
|
||||
INVALID_VALUE, // input 31 (0x1F)
|
||||
INVALID_VALUE, // input 32 (0x20)
|
||||
INVALID_VALUE, // input 33 (0x21)
|
||||
INVALID_VALUE, // input 34 (0x22)
|
||||
INVALID_VALUE, // input 35 (0x23)
|
||||
INVALID_VALUE, // input 36 (0x24)
|
||||
INVALID_VALUE, // input 37 (0x25)
|
||||
INVALID_VALUE, // input 38 (0x26)
|
||||
INVALID_VALUE, // input 39 (0x27)
|
||||
INVALID_VALUE, // input 40 (0x28)
|
||||
INVALID_VALUE, // input 41 (0x29)
|
||||
INVALID_VALUE, // input 42 (0x2A)
|
||||
62, // input 43 (0x2B char '+') => 62 (0x3E)
|
||||
INVALID_VALUE, // input 44 (0x2C)
|
||||
INVALID_VALUE, // input 45 (0x2D)
|
||||
INVALID_VALUE, // input 46 (0x2E)
|
||||
63, // input 47 (0x2F char '/') => 63 (0x3F)
|
||||
52, // input 48 (0x30 char '0') => 52 (0x34)
|
||||
53, // input 49 (0x31 char '1') => 53 (0x35)
|
||||
54, // input 50 (0x32 char '2') => 54 (0x36)
|
||||
55, // input 51 (0x33 char '3') => 55 (0x37)
|
||||
56, // input 52 (0x34 char '4') => 56 (0x38)
|
||||
57, // input 53 (0x35 char '5') => 57 (0x39)
|
||||
58, // input 54 (0x36 char '6') => 58 (0x3A)
|
||||
59, // input 55 (0x37 char '7') => 59 (0x3B)
|
||||
60, // input 56 (0x38 char '8') => 60 (0x3C)
|
||||
61, // input 57 (0x39 char '9') => 61 (0x3D)
|
||||
INVALID_VALUE, // input 58 (0x3A)
|
||||
INVALID_VALUE, // input 59 (0x3B)
|
||||
INVALID_VALUE, // input 60 (0x3C)
|
||||
INVALID_VALUE, // input 61 (0x3D)
|
||||
INVALID_VALUE, // input 62 (0x3E)
|
||||
INVALID_VALUE, // input 63 (0x3F)
|
||||
INVALID_VALUE, // input 64 (0x40)
|
||||
0, // input 65 (0x41 char 'A') => 0 (0x0)
|
||||
1, // input 66 (0x42 char 'B') => 1 (0x1)
|
||||
2, // input 67 (0x43 char 'C') => 2 (0x2)
|
||||
3, // input 68 (0x44 char 'D') => 3 (0x3)
|
||||
4, // input 69 (0x45 char 'E') => 4 (0x4)
|
||||
5, // input 70 (0x46 char 'F') => 5 (0x5)
|
||||
6, // input 71 (0x47 char 'G') => 6 (0x6)
|
||||
7, // input 72 (0x48 char 'H') => 7 (0x7)
|
||||
8, // input 73 (0x49 char 'I') => 8 (0x8)
|
||||
9, // input 74 (0x4A char 'J') => 9 (0x9)
|
||||
10, // input 75 (0x4B char 'K') => 10 (0xA)
|
||||
11, // input 76 (0x4C char 'L') => 11 (0xB)
|
||||
12, // input 77 (0x4D char 'M') => 12 (0xC)
|
||||
13, // input 78 (0x4E char 'N') => 13 (0xD)
|
||||
14, // input 79 (0x4F char 'O') => 14 (0xE)
|
||||
15, // input 80 (0x50 char 'P') => 15 (0xF)
|
||||
16, // input 81 (0x51 char 'Q') => 16 (0x10)
|
||||
17, // input 82 (0x52 char 'R') => 17 (0x11)
|
||||
18, // input 83 (0x53 char 'S') => 18 (0x12)
|
||||
19, // input 84 (0x54 char 'T') => 19 (0x13)
|
||||
20, // input 85 (0x55 char 'U') => 20 (0x14)
|
||||
21, // input 86 (0x56 char 'V') => 21 (0x15)
|
||||
22, // input 87 (0x57 char 'W') => 22 (0x16)
|
||||
23, // input 88 (0x58 char 'X') => 23 (0x17)
|
||||
24, // input 89 (0x59 char 'Y') => 24 (0x18)
|
||||
25, // input 90 (0x5A char 'Z') => 25 (0x19)
|
||||
INVALID_VALUE, // input 91 (0x5B)
|
||||
INVALID_VALUE, // input 92 (0x5C)
|
||||
INVALID_VALUE, // input 93 (0x5D)
|
||||
INVALID_VALUE, // input 94 (0x5E)
|
||||
INVALID_VALUE, // input 95 (0x5F)
|
||||
INVALID_VALUE, // input 96 (0x60)
|
||||
26, // input 97 (0x61 char 'a') => 26 (0x1A)
|
||||
27, // input 98 (0x62 char 'b') => 27 (0x1B)
|
||||
28, // input 99 (0x63 char 'c') => 28 (0x1C)
|
||||
29, // input 100 (0x64 char 'd') => 29 (0x1D)
|
||||
30, // input 101 (0x65 char 'e') => 30 (0x1E)
|
||||
31, // input 102 (0x66 char 'f') => 31 (0x1F)
|
||||
32, // input 103 (0x67 char 'g') => 32 (0x20)
|
||||
33, // input 104 (0x68 char 'h') => 33 (0x21)
|
||||
34, // input 105 (0x69 char 'i') => 34 (0x22)
|
||||
35, // input 106 (0x6A char 'j') => 35 (0x23)
|
||||
36, // input 107 (0x6B char 'k') => 36 (0x24)
|
||||
37, // input 108 (0x6C char 'l') => 37 (0x25)
|
||||
38, // input 109 (0x6D char 'm') => 38 (0x26)
|
||||
39, // input 110 (0x6E char 'n') => 39 (0x27)
|
||||
40, // input 111 (0x6F char 'o') => 40 (0x28)
|
||||
41, // input 112 (0x70 char 'p') => 41 (0x29)
|
||||
42, // input 113 (0x71 char 'q') => 42 (0x2A)
|
||||
43, // input 114 (0x72 char 'r') => 43 (0x2B)
|
||||
44, // input 115 (0x73 char 's') => 44 (0x2C)
|
||||
45, // input 116 (0x74 char 't') => 45 (0x2D)
|
||||
46, // input 117 (0x75 char 'u') => 46 (0x2E)
|
||||
47, // input 118 (0x76 char 'v') => 47 (0x2F)
|
||||
48, // input 119 (0x77 char 'w') => 48 (0x30)
|
||||
49, // input 120 (0x78 char 'x') => 49 (0x31)
|
||||
50, // input 121 (0x79 char 'y') => 50 (0x32)
|
||||
51, // input 122 (0x7A char 'z') => 51 (0x33)
|
||||
INVALID_VALUE, // input 123 (0x7B)
|
||||
INVALID_VALUE, // input 124 (0x7C)
|
||||
INVALID_VALUE, // input 125 (0x7D)
|
||||
INVALID_VALUE, // input 126 (0x7E)
|
||||
INVALID_VALUE, // input 127 (0x7F)
|
||||
INVALID_VALUE, // input 128 (0x80)
|
||||
INVALID_VALUE, // input 129 (0x81)
|
||||
INVALID_VALUE, // input 130 (0x82)
|
||||
INVALID_VALUE, // input 131 (0x83)
|
||||
INVALID_VALUE, // input 132 (0x84)
|
||||
INVALID_VALUE, // input 133 (0x85)
|
||||
INVALID_VALUE, // input 134 (0x86)
|
||||
INVALID_VALUE, // input 135 (0x87)
|
||||
INVALID_VALUE, // input 136 (0x88)
|
||||
INVALID_VALUE, // input 137 (0x89)
|
||||
INVALID_VALUE, // input 138 (0x8A)
|
||||
INVALID_VALUE, // input 139 (0x8B)
|
||||
INVALID_VALUE, // input 140 (0x8C)
|
||||
INVALID_VALUE, // input 141 (0x8D)
|
||||
INVALID_VALUE, // input 142 (0x8E)
|
||||
INVALID_VALUE, // input 143 (0x8F)
|
||||
INVALID_VALUE, // input 144 (0x90)
|
||||
INVALID_VALUE, // input 145 (0x91)
|
||||
INVALID_VALUE, // input 146 (0x92)
|
||||
INVALID_VALUE, // input 147 (0x93)
|
||||
INVALID_VALUE, // input 148 (0x94)
|
||||
INVALID_VALUE, // input 149 (0x95)
|
||||
INVALID_VALUE, // input 150 (0x96)
|
||||
INVALID_VALUE, // input 151 (0x97)
|
||||
INVALID_VALUE, // input 152 (0x98)
|
||||
INVALID_VALUE, // input 153 (0x99)
|
||||
INVALID_VALUE, // input 154 (0x9A)
|
||||
INVALID_VALUE, // input 155 (0x9B)
|
||||
INVALID_VALUE, // input 156 (0x9C)
|
||||
INVALID_VALUE, // input 157 (0x9D)
|
||||
INVALID_VALUE, // input 158 (0x9E)
|
||||
INVALID_VALUE, // input 159 (0x9F)
|
||||
INVALID_VALUE, // input 160 (0xA0)
|
||||
INVALID_VALUE, // input 161 (0xA1)
|
||||
INVALID_VALUE, // input 162 (0xA2)
|
||||
INVALID_VALUE, // input 163 (0xA3)
|
||||
INVALID_VALUE, // input 164 (0xA4)
|
||||
INVALID_VALUE, // input 165 (0xA5)
|
||||
INVALID_VALUE, // input 166 (0xA6)
|
||||
INVALID_VALUE, // input 167 (0xA7)
|
||||
INVALID_VALUE, // input 168 (0xA8)
|
||||
INVALID_VALUE, // input 169 (0xA9)
|
||||
INVALID_VALUE, // input 170 (0xAA)
|
||||
INVALID_VALUE, // input 171 (0xAB)
|
||||
INVALID_VALUE, // input 172 (0xAC)
|
||||
INVALID_VALUE, // input 173 (0xAD)
|
||||
INVALID_VALUE, // input 174 (0xAE)
|
||||
INVALID_VALUE, // input 175 (0xAF)
|
||||
INVALID_VALUE, // input 176 (0xB0)
|
||||
INVALID_VALUE, // input 177 (0xB1)
|
||||
INVALID_VALUE, // input 178 (0xB2)
|
||||
INVALID_VALUE, // input 179 (0xB3)
|
||||
INVALID_VALUE, // input 180 (0xB4)
|
||||
INVALID_VALUE, // input 181 (0xB5)
|
||||
INVALID_VALUE, // input 182 (0xB6)
|
||||
INVALID_VALUE, // input 183 (0xB7)
|
||||
INVALID_VALUE, // input 184 (0xB8)
|
||||
INVALID_VALUE, // input 185 (0xB9)
|
||||
INVALID_VALUE, // input 186 (0xBA)
|
||||
INVALID_VALUE, // input 187 (0xBB)
|
||||
INVALID_VALUE, // input 188 (0xBC)
|
||||
INVALID_VALUE, // input 189 (0xBD)
|
||||
INVALID_VALUE, // input 190 (0xBE)
|
||||
INVALID_VALUE, // input 191 (0xBF)
|
||||
INVALID_VALUE, // input 192 (0xC0)
|
||||
INVALID_VALUE, // input 193 (0xC1)
|
||||
INVALID_VALUE, // input 194 (0xC2)
|
||||
INVALID_VALUE, // input 195 (0xC3)
|
||||
INVALID_VALUE, // input 196 (0xC4)
|
||||
INVALID_VALUE, // input 197 (0xC5)
|
||||
INVALID_VALUE, // input 198 (0xC6)
|
||||
INVALID_VALUE, // input 199 (0xC7)
|
||||
INVALID_VALUE, // input 200 (0xC8)
|
||||
INVALID_VALUE, // input 201 (0xC9)
|
||||
INVALID_VALUE, // input 202 (0xCA)
|
||||
INVALID_VALUE, // input 203 (0xCB)
|
||||
INVALID_VALUE, // input 204 (0xCC)
|
||||
INVALID_VALUE, // input 205 (0xCD)
|
||||
INVALID_VALUE, // input 206 (0xCE)
|
||||
INVALID_VALUE, // input 207 (0xCF)
|
||||
INVALID_VALUE, // input 208 (0xD0)
|
||||
INVALID_VALUE, // input 209 (0xD1)
|
||||
INVALID_VALUE, // input 210 (0xD2)
|
||||
INVALID_VALUE, // input 211 (0xD3)
|
||||
INVALID_VALUE, // input 212 (0xD4)
|
||||
INVALID_VALUE, // input 213 (0xD5)
|
||||
INVALID_VALUE, // input 214 (0xD6)
|
||||
INVALID_VALUE, // input 215 (0xD7)
|
||||
INVALID_VALUE, // input 216 (0xD8)
|
||||
INVALID_VALUE, // input 217 (0xD9)
|
||||
INVALID_VALUE, // input 218 (0xDA)
|
||||
INVALID_VALUE, // input 219 (0xDB)
|
||||
INVALID_VALUE, // input 220 (0xDC)
|
||||
INVALID_VALUE, // input 221 (0xDD)
|
||||
INVALID_VALUE, // input 222 (0xDE)
|
||||
INVALID_VALUE, // input 223 (0xDF)
|
||||
INVALID_VALUE, // input 224 (0xE0)
|
||||
INVALID_VALUE, // input 225 (0xE1)
|
||||
INVALID_VALUE, // input 226 (0xE2)
|
||||
INVALID_VALUE, // input 227 (0xE3)
|
||||
INVALID_VALUE, // input 228 (0xE4)
|
||||
INVALID_VALUE, // input 229 (0xE5)
|
||||
INVALID_VALUE, // input 230 (0xE6)
|
||||
INVALID_VALUE, // input 231 (0xE7)
|
||||
INVALID_VALUE, // input 232 (0xE8)
|
||||
INVALID_VALUE, // input 233 (0xE9)
|
||||
INVALID_VALUE, // input 234 (0xEA)
|
||||
INVALID_VALUE, // input 235 (0xEB)
|
||||
INVALID_VALUE, // input 236 (0xEC)
|
||||
INVALID_VALUE, // input 237 (0xED)
|
||||
INVALID_VALUE, // input 238 (0xEE)
|
||||
INVALID_VALUE, // input 239 (0xEF)
|
||||
INVALID_VALUE, // input 240 (0xF0)
|
||||
INVALID_VALUE, // input 241 (0xF1)
|
||||
INVALID_VALUE, // input 242 (0xF2)
|
||||
INVALID_VALUE, // input 243 (0xF3)
|
||||
INVALID_VALUE, // input 244 (0xF4)
|
||||
INVALID_VALUE, // input 245 (0xF5)
|
||||
INVALID_VALUE, // input 246 (0xF6)
|
||||
INVALID_VALUE, // input 247 (0xF7)
|
||||
INVALID_VALUE, // input 248 (0xF8)
|
||||
INVALID_VALUE, // input 249 (0xF9)
|
||||
INVALID_VALUE, // input 250 (0xFA)
|
||||
INVALID_VALUE, // input 251 (0xFB)
|
||||
INVALID_VALUE, // input 252 (0xFC)
|
||||
INVALID_VALUE, // input 253 (0xFD)
|
||||
INVALID_VALUE, // input 254 (0xFE)
|
||||
INVALID_VALUE, // input 255 (0xFF)
|
||||
];
|
||||
pub const URL_SAFE_ENCODE: &'static [u8; 64] = &[
|
||||
65, // input 0 (0x0) => 'A' (0x41)
|
||||
66, // input 1 (0x1) => 'B' (0x42)
|
||||
67, // input 2 (0x2) => 'C' (0x43)
|
||||
68, // input 3 (0x3) => 'D' (0x44)
|
||||
69, // input 4 (0x4) => 'E' (0x45)
|
||||
70, // input 5 (0x5) => 'F' (0x46)
|
||||
71, // input 6 (0x6) => 'G' (0x47)
|
||||
72, // input 7 (0x7) => 'H' (0x48)
|
||||
73, // input 8 (0x8) => 'I' (0x49)
|
||||
74, // input 9 (0x9) => 'J' (0x4A)
|
||||
75, // input 10 (0xA) => 'K' (0x4B)
|
||||
76, // input 11 (0xB) => 'L' (0x4C)
|
||||
77, // input 12 (0xC) => 'M' (0x4D)
|
||||
78, // input 13 (0xD) => 'N' (0x4E)
|
||||
79, // input 14 (0xE) => 'O' (0x4F)
|
||||
80, // input 15 (0xF) => 'P' (0x50)
|
||||
81, // input 16 (0x10) => 'Q' (0x51)
|
||||
82, // input 17 (0x11) => 'R' (0x52)
|
||||
83, // input 18 (0x12) => 'S' (0x53)
|
||||
84, // input 19 (0x13) => 'T' (0x54)
|
||||
85, // input 20 (0x14) => 'U' (0x55)
|
||||
86, // input 21 (0x15) => 'V' (0x56)
|
||||
87, // input 22 (0x16) => 'W' (0x57)
|
||||
88, // input 23 (0x17) => 'X' (0x58)
|
||||
89, // input 24 (0x18) => 'Y' (0x59)
|
||||
90, // input 25 (0x19) => 'Z' (0x5A)
|
||||
97, // input 26 (0x1A) => 'a' (0x61)
|
||||
98, // input 27 (0x1B) => 'b' (0x62)
|
||||
99, // input 28 (0x1C) => 'c' (0x63)
|
||||
100, // input 29 (0x1D) => 'd' (0x64)
|
||||
101, // input 30 (0x1E) => 'e' (0x65)
|
||||
102, // input 31 (0x1F) => 'f' (0x66)
|
||||
103, // input 32 (0x20) => 'g' (0x67)
|
||||
104, // input 33 (0x21) => 'h' (0x68)
|
||||
105, // input 34 (0x22) => 'i' (0x69)
|
||||
106, // input 35 (0x23) => 'j' (0x6A)
|
||||
107, // input 36 (0x24) => 'k' (0x6B)
|
||||
108, // input 37 (0x25) => 'l' (0x6C)
|
||||
109, // input 38 (0x26) => 'm' (0x6D)
|
||||
110, // input 39 (0x27) => 'n' (0x6E)
|
||||
111, // input 40 (0x28) => 'o' (0x6F)
|
||||
112, // input 41 (0x29) => 'p' (0x70)
|
||||
113, // input 42 (0x2A) => 'q' (0x71)
|
||||
114, // input 43 (0x2B) => 'r' (0x72)
|
||||
115, // input 44 (0x2C) => 's' (0x73)
|
||||
116, // input 45 (0x2D) => 't' (0x74)
|
||||
117, // input 46 (0x2E) => 'u' (0x75)
|
||||
118, // input 47 (0x2F) => 'v' (0x76)
|
||||
119, // input 48 (0x30) => 'w' (0x77)
|
||||
120, // input 49 (0x31) => 'x' (0x78)
|
||||
121, // input 50 (0x32) => 'y' (0x79)
|
||||
122, // input 51 (0x33) => 'z' (0x7A)
|
||||
48, // input 52 (0x34) => '0' (0x30)
|
||||
49, // input 53 (0x35) => '1' (0x31)
|
||||
50, // input 54 (0x36) => '2' (0x32)
|
||||
51, // input 55 (0x37) => '3' (0x33)
|
||||
52, // input 56 (0x38) => '4' (0x34)
|
||||
53, // input 57 (0x39) => '5' (0x35)
|
||||
54, // input 58 (0x3A) => '6' (0x36)
|
||||
55, // input 59 (0x3B) => '7' (0x37)
|
||||
56, // input 60 (0x3C) => '8' (0x38)
|
||||
57, // input 61 (0x3D) => '9' (0x39)
|
||||
45, // input 62 (0x3E) => '-' (0x2D)
|
||||
95, // input 63 (0x3F) => '_' (0x5F)
|
||||
];
|
||||
pub const URL_SAFE_DECODE: &'static [u8; 256] = &[
|
||||
INVALID_VALUE, // input 0 (0x0)
|
||||
INVALID_VALUE, // input 1 (0x1)
|
||||
INVALID_VALUE, // input 2 (0x2)
|
||||
INVALID_VALUE, // input 3 (0x3)
|
||||
INVALID_VALUE, // input 4 (0x4)
|
||||
INVALID_VALUE, // input 5 (0x5)
|
||||
INVALID_VALUE, // input 6 (0x6)
|
||||
INVALID_VALUE, // input 7 (0x7)
|
||||
INVALID_VALUE, // input 8 (0x8)
|
||||
INVALID_VALUE, // input 9 (0x9)
|
||||
INVALID_VALUE, // input 10 (0xA)
|
||||
INVALID_VALUE, // input 11 (0xB)
|
||||
INVALID_VALUE, // input 12 (0xC)
|
||||
INVALID_VALUE, // input 13 (0xD)
|
||||
INVALID_VALUE, // input 14 (0xE)
|
||||
INVALID_VALUE, // input 15 (0xF)
|
||||
INVALID_VALUE, // input 16 (0x10)
|
||||
INVALID_VALUE, // input 17 (0x11)
|
||||
INVALID_VALUE, // input 18 (0x12)
|
||||
INVALID_VALUE, // input 19 (0x13)
|
||||
INVALID_VALUE, // input 20 (0x14)
|
||||
INVALID_VALUE, // input 21 (0x15)
|
||||
INVALID_VALUE, // input 22 (0x16)
|
||||
INVALID_VALUE, // input 23 (0x17)
|
||||
INVALID_VALUE, // input 24 (0x18)
|
||||
INVALID_VALUE, // input 25 (0x19)
|
||||
INVALID_VALUE, // input 26 (0x1A)
|
||||
INVALID_VALUE, // input 27 (0x1B)
|
||||
INVALID_VALUE, // input 28 (0x1C)
|
||||
INVALID_VALUE, // input 29 (0x1D)
|
||||
INVALID_VALUE, // input 30 (0x1E)
|
||||
INVALID_VALUE, // input 31 (0x1F)
|
||||
INVALID_VALUE, // input 32 (0x20)
|
||||
INVALID_VALUE, // input 33 (0x21)
|
||||
INVALID_VALUE, // input 34 (0x22)
|
||||
INVALID_VALUE, // input 35 (0x23)
|
||||
INVALID_VALUE, // input 36 (0x24)
|
||||
INVALID_VALUE, // input 37 (0x25)
|
||||
INVALID_VALUE, // input 38 (0x26)
|
||||
INVALID_VALUE, // input 39 (0x27)
|
||||
INVALID_VALUE, // input 40 (0x28)
|
||||
INVALID_VALUE, // input 41 (0x29)
|
||||
INVALID_VALUE, // input 42 (0x2A)
|
||||
INVALID_VALUE, // input 43 (0x2B)
|
||||
INVALID_VALUE, // input 44 (0x2C)
|
||||
62, // input 45 (0x2D char '-') => 62 (0x3E)
|
||||
INVALID_VALUE, // input 46 (0x2E)
|
||||
INVALID_VALUE, // input 47 (0x2F)
|
||||
52, // input 48 (0x30 char '0') => 52 (0x34)
|
||||
53, // input 49 (0x31 char '1') => 53 (0x35)
|
||||
54, // input 50 (0x32 char '2') => 54 (0x36)
|
||||
55, // input 51 (0x33 char '3') => 55 (0x37)
|
||||
56, // input 52 (0x34 char '4') => 56 (0x38)
|
||||
57, // input 53 (0x35 char '5') => 57 (0x39)
|
||||
58, // input 54 (0x36 char '6') => 58 (0x3A)
|
||||
59, // input 55 (0x37 char '7') => 59 (0x3B)
|
||||
60, // input 56 (0x38 char '8') => 60 (0x3C)
|
||||
61, // input 57 (0x39 char '9') => 61 (0x3D)
|
||||
INVALID_VALUE, // input 58 (0x3A)
|
||||
INVALID_VALUE, // input 59 (0x3B)
|
||||
INVALID_VALUE, // input 60 (0x3C)
|
||||
INVALID_VALUE, // input 61 (0x3D)
|
||||
INVALID_VALUE, // input 62 (0x3E)
|
||||
INVALID_VALUE, // input 63 (0x3F)
|
||||
INVALID_VALUE, // input 64 (0x40)
|
||||
0, // input 65 (0x41 char 'A') => 0 (0x0)
|
||||
1, // input 66 (0x42 char 'B') => 1 (0x1)
|
||||
2, // input 67 (0x43 char 'C') => 2 (0x2)
|
||||
3, // input 68 (0x44 char 'D') => 3 (0x3)
|
||||
4, // input 69 (0x45 char 'E') => 4 (0x4)
|
||||
5, // input 70 (0x46 char 'F') => 5 (0x5)
|
||||
6, // input 71 (0x47 char 'G') => 6 (0x6)
|
||||
7, // input 72 (0x48 char 'H') => 7 (0x7)
|
||||
8, // input 73 (0x49 char 'I') => 8 (0x8)
|
||||
9, // input 74 (0x4A char 'J') => 9 (0x9)
|
||||
10, // input 75 (0x4B char 'K') => 10 (0xA)
|
||||
11, // input 76 (0x4C char 'L') => 11 (0xB)
|
||||
12, // input 77 (0x4D char 'M') => 12 (0xC)
|
||||
13, // input 78 (0x4E char 'N') => 13 (0xD)
|
||||
14, // input 79 (0x4F char 'O') => 14 (0xE)
|
||||
15, // input 80 (0x50 char 'P') => 15 (0xF)
|
||||
16, // input 81 (0x51 char 'Q') => 16 (0x10)
|
||||
17, // input 82 (0x52 char 'R') => 17 (0x11)
|
||||
18, // input 83 (0x53 char 'S') => 18 (0x12)
|
||||
19, // input 84 (0x54 char 'T') => 19 (0x13)
|
||||
20, // input 85 (0x55 char 'U') => 20 (0x14)
|
||||
21, // input 86 (0x56 char 'V') => 21 (0x15)
|
||||
22, // input 87 (0x57 char 'W') => 22 (0x16)
|
||||
23, // input 88 (0x58 char 'X') => 23 (0x17)
|
||||
24, // input 89 (0x59 char 'Y') => 24 (0x18)
|
||||
25, // input 90 (0x5A char 'Z') => 25 (0x19)
|
||||
INVALID_VALUE, // input 91 (0x5B)
|
||||
INVALID_VALUE, // input 92 (0x5C)
|
||||
INVALID_VALUE, // input 93 (0x5D)
|
||||
INVALID_VALUE, // input 94 (0x5E)
|
||||
63, // input 95 (0x5F char '_') => 63 (0x3F)
|
||||
INVALID_VALUE, // input 96 (0x60)
|
||||
26, // input 97 (0x61 char 'a') => 26 (0x1A)
|
||||
27, // input 98 (0x62 char 'b') => 27 (0x1B)
|
||||
28, // input 99 (0x63 char 'c') => 28 (0x1C)
|
||||
29, // input 100 (0x64 char 'd') => 29 (0x1D)
|
||||
30, // input 101 (0x65 char 'e') => 30 (0x1E)
|
||||
31, // input 102 (0x66 char 'f') => 31 (0x1F)
|
||||
32, // input 103 (0x67 char 'g') => 32 (0x20)
|
||||
33, // input 104 (0x68 char 'h') => 33 (0x21)
|
||||
34, // input 105 (0x69 char 'i') => 34 (0x22)
|
||||
35, // input 106 (0x6A char 'j') => 35 (0x23)
|
||||
36, // input 107 (0x6B char 'k') => 36 (0x24)
|
||||
37, // input 108 (0x6C char 'l') => 37 (0x25)
|
||||
38, // input 109 (0x6D char 'm') => 38 (0x26)
|
||||
39, // input 110 (0x6E char 'n') => 39 (0x27)
|
||||
40, // input 111 (0x6F char 'o') => 40 (0x28)
|
||||
41, // input 112 (0x70 char 'p') => 41 (0x29)
|
||||
42, // input 113 (0x71 char 'q') => 42 (0x2A)
|
||||
43, // input 114 (0x72 char 'r') => 43 (0x2B)
|
||||
44, // input 115 (0x73 char 's') => 44 (0x2C)
|
||||
45, // input 116 (0x74 char 't') => 45 (0x2D)
|
||||
46, // input 117 (0x75 char 'u') => 46 (0x2E)
|
||||
47, // input 118 (0x76 char 'v') => 47 (0x2F)
|
||||
48, // input 119 (0x77 char 'w') => 48 (0x30)
|
||||
49, // input 120 (0x78 char 'x') => 49 (0x31)
|
||||
50, // input 121 (0x79 char 'y') => 50 (0x32)
|
||||
51, // input 122 (0x7A char 'z') => 51 (0x33)
|
||||
INVALID_VALUE, // input 123 (0x7B)
|
||||
INVALID_VALUE, // input 124 (0x7C)
|
||||
INVALID_VALUE, // input 125 (0x7D)
|
||||
INVALID_VALUE, // input 126 (0x7E)
|
||||
INVALID_VALUE, // input 127 (0x7F)
|
||||
INVALID_VALUE, // input 128 (0x80)
|
||||
INVALID_VALUE, // input 129 (0x81)
|
||||
INVALID_VALUE, // input 130 (0x82)
|
||||
INVALID_VALUE, // input 131 (0x83)
|
||||
INVALID_VALUE, // input 132 (0x84)
|
||||
INVALID_VALUE, // input 133 (0x85)
|
||||
INVALID_VALUE, // input 134 (0x86)
|
||||
INVALID_VALUE, // input 135 (0x87)
|
||||
INVALID_VALUE, // input 136 (0x88)
|
||||
INVALID_VALUE, // input 137 (0x89)
|
||||
INVALID_VALUE, // input 138 (0x8A)
|
||||
INVALID_VALUE, // input 139 (0x8B)
|
||||
INVALID_VALUE, // input 140 (0x8C)
|
||||
INVALID_VALUE, // input 141 (0x8D)
|
||||
INVALID_VALUE, // input 142 (0x8E)
|
||||
INVALID_VALUE, // input 143 (0x8F)
|
||||
INVALID_VALUE, // input 144 (0x90)
|
||||
INVALID_VALUE, // input 145 (0x91)
|
||||
INVALID_VALUE, // input 146 (0x92)
|
||||
INVALID_VALUE, // input 147 (0x93)
|
||||
INVALID_VALUE, // input 148 (0x94)
|
||||
INVALID_VALUE, // input 149 (0x95)
|
||||
INVALID_VALUE, // input 150 (0x96)
|
||||
INVALID_VALUE, // input 151 (0x97)
|
||||
INVALID_VALUE, // input 152 (0x98)
|
||||
INVALID_VALUE, // input 153 (0x99)
|
||||
INVALID_VALUE, // input 154 (0x9A)
|
||||
INVALID_VALUE, // input 155 (0x9B)
|
||||
INVALID_VALUE, // input 156 (0x9C)
|
||||
INVALID_VALUE, // input 157 (0x9D)
|
||||
INVALID_VALUE, // input 158 (0x9E)
|
||||
INVALID_VALUE, // input 159 (0x9F)
|
||||
INVALID_VALUE, // input 160 (0xA0)
|
||||
INVALID_VALUE, // input 161 (0xA1)
|
||||
INVALID_VALUE, // input 162 (0xA2)
|
||||
INVALID_VALUE, // input 163 (0xA3)
|
||||
INVALID_VALUE, // input 164 (0xA4)
|
||||
INVALID_VALUE, // input 165 (0xA5)
|
||||
INVALID_VALUE, // input 166 (0xA6)
|
||||
INVALID_VALUE, // input 167 (0xA7)
|
||||
INVALID_VALUE, // input 168 (0xA8)
|
||||
INVALID_VALUE, // input 169 (0xA9)
|
||||
INVALID_VALUE, // input 170 (0xAA)
|
||||
INVALID_VALUE, // input 171 (0xAB)
|
||||
INVALID_VALUE, // input 172 (0xAC)
|
||||
INVALID_VALUE, // input 173 (0xAD)
|
||||
INVALID_VALUE, // input 174 (0xAE)
|
||||
INVALID_VALUE, // input 175 (0xAF)
|
||||
INVALID_VALUE, // input 176 (0xB0)
|
||||
INVALID_VALUE, // input 177 (0xB1)
|
||||
INVALID_VALUE, // input 178 (0xB2)
|
||||
INVALID_VALUE, // input 179 (0xB3)
|
||||
INVALID_VALUE, // input 180 (0xB4)
|
||||
INVALID_VALUE, // input 181 (0xB5)
|
||||
INVALID_VALUE, // input 182 (0xB6)
|
||||
INVALID_VALUE, // input 183 (0xB7)
|
||||
INVALID_VALUE, // input 184 (0xB8)
|
||||
INVALID_VALUE, // input 185 (0xB9)
|
||||
INVALID_VALUE, // input 186 (0xBA)
|
||||
INVALID_VALUE, // input 187 (0xBB)
|
||||
INVALID_VALUE, // input 188 (0xBC)
|
||||
INVALID_VALUE, // input 189 (0xBD)
|
||||
INVALID_VALUE, // input 190 (0xBE)
|
||||
INVALID_VALUE, // input 191 (0xBF)
|
||||
INVALID_VALUE, // input 192 (0xC0)
|
||||
INVALID_VALUE, // input 193 (0xC1)
|
||||
INVALID_VALUE, // input 194 (0xC2)
|
||||
INVALID_VALUE, // input 195 (0xC3)
|
||||
INVALID_VALUE, // input 196 (0xC4)
|
||||
INVALID_VALUE, // input 197 (0xC5)
|
||||
INVALID_VALUE, // input 198 (0xC6)
|
||||
INVALID_VALUE, // input 199 (0xC7)
|
||||
INVALID_VALUE, // input 200 (0xC8)
|
||||
INVALID_VALUE, // input 201 (0xC9)
|
||||
INVALID_VALUE, // input 202 (0xCA)
|
||||
INVALID_VALUE, // input 203 (0xCB)
|
||||
INVALID_VALUE, // input 204 (0xCC)
|
||||
INVALID_VALUE, // input 205 (0xCD)
|
||||
INVALID_VALUE, // input 206 (0xCE)
|
||||
INVALID_VALUE, // input 207 (0xCF)
|
||||
INVALID_VALUE, // input 208 (0xD0)
|
||||
INVALID_VALUE, // input 209 (0xD1)
|
||||
INVALID_VALUE, // input 210 (0xD2)
|
||||
INVALID_VALUE, // input 211 (0xD3)
|
||||
INVALID_VALUE, // input 212 (0xD4)
|
||||
INVALID_VALUE, // input 213 (0xD5)
|
||||
INVALID_VALUE, // input 214 (0xD6)
|
||||
INVALID_VALUE, // input 215 (0xD7)
|
||||
INVALID_VALUE, // input 216 (0xD8)
|
||||
INVALID_VALUE, // input 217 (0xD9)
|
||||
INVALID_VALUE, // input 218 (0xDA)
|
||||
INVALID_VALUE, // input 219 (0xDB)
|
||||
INVALID_VALUE, // input 220 (0xDC)
|
||||
INVALID_VALUE, // input 221 (0xDD)
|
||||
INVALID_VALUE, // input 222 (0xDE)
|
||||
INVALID_VALUE, // input 223 (0xDF)
|
||||
INVALID_VALUE, // input 224 (0xE0)
|
||||
INVALID_VALUE, // input 225 (0xE1)
|
||||
INVALID_VALUE, // input 226 (0xE2)
|
||||
INVALID_VALUE, // input 227 (0xE3)
|
||||
INVALID_VALUE, // input 228 (0xE4)
|
||||
INVALID_VALUE, // input 229 (0xE5)
|
||||
INVALID_VALUE, // input 230 (0xE6)
|
||||
INVALID_VALUE, // input 231 (0xE7)
|
||||
INVALID_VALUE, // input 232 (0xE8)
|
||||
INVALID_VALUE, // input 233 (0xE9)
|
||||
INVALID_VALUE, // input 234 (0xEA)
|
||||
INVALID_VALUE, // input 235 (0xEB)
|
||||
INVALID_VALUE, // input 236 (0xEC)
|
||||
INVALID_VALUE, // input 237 (0xED)
|
||||
INVALID_VALUE, // input 238 (0xEE)
|
||||
INVALID_VALUE, // input 239 (0xEF)
|
||||
INVALID_VALUE, // input 240 (0xF0)
|
||||
INVALID_VALUE, // input 241 (0xF1)
|
||||
INVALID_VALUE, // input 242 (0xF2)
|
||||
INVALID_VALUE, // input 243 (0xF3)
|
||||
INVALID_VALUE, // input 244 (0xF4)
|
||||
INVALID_VALUE, // input 245 (0xF5)
|
||||
INVALID_VALUE, // input 246 (0xF6)
|
||||
INVALID_VALUE, // input 247 (0xF7)
|
||||
INVALID_VALUE, // input 248 (0xF8)
|
||||
INVALID_VALUE, // input 249 (0xF9)
|
||||
INVALID_VALUE, // input 250 (0xFA)
|
||||
INVALID_VALUE, // input 251 (0xFB)
|
||||
INVALID_VALUE, // input 252 (0xFC)
|
||||
INVALID_VALUE, // input 253 (0xFD)
|
||||
INVALID_VALUE, // input 254 (0xFE)
|
||||
INVALID_VALUE, // input 255 (0xFF)
|
||||
];
|
|
@ -0,0 +1,696 @@
|
|||
extern crate base64;
|
||||
extern crate rand;
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
use base64::*;
|
||||
|
||||
fn compare_encode(expected: &str, target: &[u8]) {
|
||||
assert_eq!(expected, encode(target));
|
||||
}
|
||||
|
||||
fn compare_decode(expected: &str, target: &str) {
|
||||
assert_eq!(expected, String::from_utf8(decode(target).unwrap()).unwrap());
|
||||
assert_eq!(expected, String::from_utf8(decode(target.as_bytes()).unwrap()).unwrap());
|
||||
}
|
||||
|
||||
fn compare_decode_mime(expected: &str, target: &str) {
|
||||
assert_eq!(expected, String::from_utf8(decode_config(target, MIME).unwrap()).unwrap());
|
||||
}
|
||||
|
||||
fn push_rand(buf: &mut Vec<u8>, len: usize) {
|
||||
let mut r = rand::weak_rng();
|
||||
|
||||
for _ in 0..len {
|
||||
buf.push(r.gen::<u8>());
|
||||
}
|
||||
}
|
||||
|
||||
// generate every possible byte string recursively and test encode/decode roundtrip
|
||||
fn roundtrip_append_recurse(byte_buf: &mut Vec<u8>, str_buf: &mut String, remaining_bytes: usize) {
|
||||
let orig_length = byte_buf.len();
|
||||
for b in 0..256 {
|
||||
byte_buf.push(b as u8);
|
||||
|
||||
if remaining_bytes > 1 {
|
||||
roundtrip_append_recurse(byte_buf, str_buf, remaining_bytes - 1)
|
||||
} else {
|
||||
encode_config_buf(&byte_buf, STANDARD, str_buf);
|
||||
let roundtrip_bytes = decode_config(&str_buf, STANDARD).unwrap();
|
||||
assert_eq!(*byte_buf, roundtrip_bytes);
|
||||
|
||||
str_buf.clear();
|
||||
|
||||
}
|
||||
|
||||
byte_buf.truncate(orig_length);
|
||||
}
|
||||
}
|
||||
|
||||
// generate every possible byte string recursively and test encode/decode roundtrip with
|
||||
// padding removed
|
||||
fn roundtrip_append_recurse_strip_padding(byte_buf: &mut Vec<u8>, str_buf: &mut String,
|
||||
remaining_bytes: usize) {
|
||||
let orig_length = byte_buf.len();
|
||||
for b in 0..256 {
|
||||
byte_buf.push(b as u8);
|
||||
|
||||
if remaining_bytes > 1 {
|
||||
roundtrip_append_recurse_strip_padding(byte_buf, str_buf, remaining_bytes - 1)
|
||||
} else {
|
||||
encode_config_buf(&byte_buf, STANDARD, str_buf);
|
||||
{
|
||||
let trimmed = str_buf.trim_right_matches('=');
|
||||
let roundtrip_bytes = decode_config(&trimmed, STANDARD).unwrap();
|
||||
assert_eq!(*byte_buf, roundtrip_bytes);
|
||||
}
|
||||
str_buf.clear();
|
||||
}
|
||||
|
||||
byte_buf.truncate(orig_length);
|
||||
}
|
||||
}
|
||||
|
||||
// generate random contents of the specified length and test encode/decode roundtrip
|
||||
fn roundtrip_random(byte_buf: &mut Vec<u8>, str_buf: &mut String, byte_len: usize,
|
||||
approx_values_per_byte: u8, max_rounds: u64) {
|
||||
let num_rounds = calculate_number_of_rounds(byte_len, approx_values_per_byte, max_rounds);
|
||||
let mut r = rand::weak_rng();
|
||||
|
||||
for _ in 0..num_rounds {
|
||||
byte_buf.clear();
|
||||
str_buf.clear();
|
||||
while byte_buf.len() < byte_len {
|
||||
byte_buf.push(r.gen::<u8>());
|
||||
}
|
||||
|
||||
encode_config_buf(&byte_buf, STANDARD, str_buf);
|
||||
let roundtrip_bytes = decode_config(&str_buf, STANDARD).unwrap();
|
||||
|
||||
assert_eq!(*byte_buf, roundtrip_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// generate random contents of the specified length and test encode/decode roundtrip
|
||||
fn roundtrip_random_strip_padding(byte_buf: &mut Vec<u8>, str_buf: &mut String, byte_len: usize,
|
||||
approx_values_per_byte: u8, max_rounds: u64) {
|
||||
// let the short ones be short but don't let it get too crazy large
|
||||
let num_rounds = calculate_number_of_rounds(byte_len, approx_values_per_byte, max_rounds);
|
||||
let mut r = rand::weak_rng();
|
||||
|
||||
for _ in 0..num_rounds {
|
||||
byte_buf.clear();
|
||||
str_buf.clear();
|
||||
while byte_buf.len() < byte_len {
|
||||
byte_buf.push(r.gen::<u8>());
|
||||
}
|
||||
|
||||
encode_config_buf(&byte_buf, STANDARD, str_buf);
|
||||
let trimmed = str_buf.trim_right_matches('=');
|
||||
let roundtrip_bytes = decode_config(&trimmed, STANDARD).unwrap();
|
||||
|
||||
assert_eq!(*byte_buf, roundtrip_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_number_of_rounds(byte_len: usize, approx_values_per_byte: u8, max: u64) -> u64 {
|
||||
// don't overflow
|
||||
let mut prod = approx_values_per_byte as u64;
|
||||
|
||||
for _ in 0..byte_len {
|
||||
if prod > max {
|
||||
return max;
|
||||
}
|
||||
|
||||
prod = prod.saturating_mul(prod);
|
||||
}
|
||||
|
||||
return prod;
|
||||
}
|
||||
|
||||
//-------
|
||||
//decode
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_0() {
|
||||
compare_decode("", "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_1() {
|
||||
compare_decode("f", "Zg==");
|
||||
}
|
||||
#[test]
|
||||
fn decode_rfc4648_1_just_a_bit_of_padding() {
|
||||
// allows less padding than required
|
||||
compare_decode("f", "Zg=");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_1_no_padding() {
|
||||
compare_decode("f", "Zg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_2() {
|
||||
compare_decode("fo", "Zm8=");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_2_no_padding() {
|
||||
compare_decode("fo", "Zm8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_3() {
|
||||
compare_decode("foo", "Zm9v");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_4() {
|
||||
compare_decode("foob", "Zm9vYg==");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_4_no_padding() {
|
||||
compare_decode("foob", "Zm9vYg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_5() {
|
||||
compare_decode("fooba", "Zm9vYmE=");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_5_no_padding() {
|
||||
compare_decode("fooba", "Zm9vYmE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_6() {
|
||||
compare_decode("foobar", "Zm9vYmFy");
|
||||
}
|
||||
|
||||
//this is a MAY in the rfc: https://tools.ietf.org/html/rfc4648#section-3.3
|
||||
#[test]
|
||||
fn decode_pad_inside_fast_loop_chunk_error() {
|
||||
// can't PartialEq Base64Error, so we do this the hard way
|
||||
match decode("YWxpY2U=====").unwrap_err() {
|
||||
DecodeError::InvalidByte(offset, byte) => {
|
||||
// since the first 8 bytes are handled in the fast loop, the
|
||||
// padding is an error. Could argue that the *next* padding
|
||||
// byte is technically the first erroneous one, but reporting
|
||||
// that accurately is more complex and probably nobody cares
|
||||
assert_eq!(7, offset);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_extra_pad_after_fast_loop_chunk_error() {
|
||||
match decode("YWxpY2UABB===").unwrap_err() {
|
||||
DecodeError::InvalidByte(offset, byte) => {
|
||||
// extraneous third padding byte
|
||||
assert_eq!(12, offset);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//same
|
||||
#[test]
|
||||
fn decode_absurd_pad_error() {
|
||||
match decode("==Y=Wx===pY=2U=====").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
assert_eq!(0, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_starts_with_padding_single_quad_error() {
|
||||
match decode("====").unwrap_err() {
|
||||
DecodeError::InvalidByte(offset, byte) => {
|
||||
// with no real input, first padding byte is bogus
|
||||
assert_eq!(0, offset);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_extra_padding_in_trailing_quad_returns_error() {
|
||||
match decode("zzz==").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
// first unneeded padding byte
|
||||
assert_eq!(4, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_extra_padding_in_trailing_quad_2_returns_error() {
|
||||
match decode("zz===").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
// first unneeded padding byte
|
||||
assert_eq!(4, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn decode_start_second_quad_with_padding_returns_error() {
|
||||
match decode("zzzz=").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
// first unneeded padding byte
|
||||
assert_eq!(4, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_padding_in_last_quad_followed_by_non_padding_returns_error() {
|
||||
match decode("zzzz==z").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
assert_eq!(4, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_too_short_with_padding_error() {
|
||||
match decode("z==").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
// first unneeded padding byte
|
||||
assert_eq!(1, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_too_short_without_padding_error() {
|
||||
match decode("z").unwrap_err() {
|
||||
DecodeError::InvalidLength => {}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_too_short_second_quad_without_padding_error() {
|
||||
match decode("zzzzX").unwrap_err() {
|
||||
DecodeError::InvalidLength => {}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_error_for_bogus_char_in_right_position() {
|
||||
for length in 1..25 {
|
||||
for error_position in 0_usize..length {
|
||||
let prefix: String = std::iter::repeat("A").take(error_position).collect();
|
||||
let suffix: String = std::iter::repeat("B").take(length - error_position - 1).collect();
|
||||
|
||||
let input = prefix + "%" + &suffix;
|
||||
assert_eq!(length, input.len(),
|
||||
"length {} error position {}", length, error_position);
|
||||
|
||||
match decode(&input).unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
assert_eq!(error_position, size,
|
||||
"length {} error position {}", length, error_position);
|
||||
assert_eq!(0x25, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_into_nonempty_buffer_doesnt_clobber_existing_contents() {
|
||||
let mut orig_data = Vec::new();
|
||||
let mut encoded_data = String::new();
|
||||
let mut decoded_with_prefix = Vec::new();
|
||||
let mut decoded_without_prefix = Vec::new();
|
||||
let mut prefix = Vec::new();
|
||||
for encoded_length in 0_usize..26 {
|
||||
if encoded_length % 4 == 1 {
|
||||
// can't have a lone byte in a quad of input
|
||||
continue;
|
||||
};
|
||||
|
||||
let raw_data_byte_triples = encoded_length / 4;
|
||||
// 4 base64 bytes -> 3 input bytes, 3 -> 2, 2 -> 1, 0 -> 0
|
||||
let raw_data_byte_leftovers = (encoded_length % 4).saturating_sub(1);
|
||||
|
||||
// we'll borrow buf to make some data to encode
|
||||
orig_data.clear();
|
||||
push_rand(&mut orig_data, raw_data_byte_triples * 3 + raw_data_byte_leftovers);
|
||||
|
||||
encoded_data.clear();
|
||||
encode_config_buf(&orig_data, STANDARD, &mut encoded_data);
|
||||
|
||||
assert_eq!(encoded_length, encoded_data.trim_right_matches('=').len());
|
||||
|
||||
for prefix_length in 1..26 {
|
||||
decoded_with_prefix.clear();
|
||||
decoded_without_prefix.clear();
|
||||
prefix.clear();
|
||||
|
||||
// fill the buf with a prefix
|
||||
push_rand(&mut prefix, prefix_length);
|
||||
decoded_with_prefix.resize(prefix_length, 0);
|
||||
decoded_with_prefix.copy_from_slice(&prefix);
|
||||
|
||||
// decode into the non-empty buf
|
||||
decode_config_buf(&encoded_data, STANDARD, &mut decoded_with_prefix).unwrap();
|
||||
// also decode into the empty buf
|
||||
decode_config_buf(&encoded_data, STANDARD, &mut decoded_without_prefix).unwrap();
|
||||
|
||||
assert_eq!(prefix_length + decoded_without_prefix.len(), decoded_with_prefix.len());
|
||||
|
||||
// append plain decode onto prefix
|
||||
prefix.append(&mut decoded_without_prefix);
|
||||
|
||||
assert_eq!(prefix, decoded_with_prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_random_no_fast_loop() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
|
||||
for input_len in 0..9 {
|
||||
roundtrip_random(&mut byte_buf, &mut str_buf, input_len, 4, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_random_with_fast_loop() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
|
||||
for input_len in 9..26 {
|
||||
roundtrip_random(&mut byte_buf, &mut str_buf, input_len, 4, 100000);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_random_no_fast_loop_no_padding() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
|
||||
for input_len in 0..9 {
|
||||
roundtrip_random_strip_padding(&mut byte_buf, &mut str_buf, input_len, 4, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_random_with_fast_loop_no_padding() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
|
||||
for input_len in 9..26 {
|
||||
roundtrip_random_strip_padding(&mut byte_buf, &mut str_buf, input_len, 4, 100000);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_1_byte() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
roundtrip_append_recurse(&mut byte_buf, &mut str_buf, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_1_byte_no_padding() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
roundtrip_append_recurse_strip_padding(&mut byte_buf, &mut str_buf, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_2_byte() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
roundtrip_append_recurse(&mut byte_buf, &mut str_buf, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_2_byte_no_padding() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
roundtrip_append_recurse_strip_padding(&mut byte_buf, &mut str_buf, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_3_byte() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
roundtrip_append_recurse(&mut byte_buf, &mut str_buf, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_random_4_byte() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
|
||||
roundtrip_random(&mut byte_buf, &mut str_buf, 4, 48, 10000);
|
||||
}
|
||||
|
||||
//TODO like, write a thing to test every ascii val lol
|
||||
//prolly just yankput the 64 array and a 256 one later
|
||||
//is there a way to like, not have to write a fn every time
|
||||
//"hi test harness this should panic 192 times" would be nice
|
||||
//oh well whatever this is better done by a fuzzer
|
||||
|
||||
//strip yr whitespace kids
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_space() {
|
||||
assert!(decode("YWx pY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_tab() {
|
||||
assert!(decode("YWx\tpY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_ff() {
|
||||
assert!(decode("YWx\x0cpY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_vtab() {
|
||||
assert!(decode("YWx\x0bpY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_nl() {
|
||||
assert!(decode("YWx\npY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_crnl() {
|
||||
assert!(decode("YWx\r\npY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_null() {
|
||||
assert!(decode("YWx\0pY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_space() {
|
||||
assert!(decode_config("YWx pY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_tab() {
|
||||
assert!(decode_config("YWx\tpY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_ff() {
|
||||
assert!(decode_config("YWx\x0cpY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_vtab() {
|
||||
assert!(decode_config("YWx\x0bpY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_nl() {
|
||||
assert!(decode_config("YWx\npY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_crnl() {
|
||||
assert!(decode_config("YWx\r\npY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_mime_reject_null() {
|
||||
assert!(decode_config("YWx\0pY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_absurd_whitespace() {
|
||||
compare_decode_mime("how could you let this happen",
|
||||
"\n aG93I\n\nG\x0bNvd\r\nWxkI HlvdSB \tsZXQgdGh\rpcyBo\x0cYXBwZW4 = ");
|
||||
}
|
||||
|
||||
//-------
|
||||
//encode
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_0() {
|
||||
compare_encode("", b"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_1() {
|
||||
compare_encode("Zg==", b"f");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_2() {
|
||||
compare_encode("Zm8=", b"fo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_3() {
|
||||
compare_encode("Zm9v", b"foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_4() {
|
||||
compare_encode("Zm9vYg==", b"foob");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_5() {
|
||||
compare_encode("Zm9vYmE=", b"fooba");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_6() {
|
||||
compare_encode("Zm9vYmFy", b"foobar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_all_ascii() {
|
||||
let mut ascii = Vec::<u8>::with_capacity(128);
|
||||
|
||||
for i in 0..128 {
|
||||
ascii.push(i);
|
||||
}
|
||||
|
||||
compare_encode("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=", &ascii);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_all_bytes() {
|
||||
let mut bytes = Vec::<u8>::with_capacity(256);
|
||||
|
||||
for i in 0..255 {
|
||||
bytes.push(i);
|
||||
}
|
||||
bytes.push(255); //bug with "overflowing" ranges?
|
||||
|
||||
compare_encode("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==", &bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_all_bytes_url() {
|
||||
let mut bytes = Vec::<u8>::with_capacity(256);
|
||||
|
||||
for i in 0..255 {
|
||||
bytes.push(i);
|
||||
}
|
||||
bytes.push(255); //bug with "overflowing" ranges?
|
||||
|
||||
assert_eq!("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w==", encode_config(&bytes, URL_SAFE));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_into_nonempty_buffer_doesnt_clobber_existing_contents() {
|
||||
let mut orig_data = Vec::new();
|
||||
let mut encoded_with_prefix = String::new();
|
||||
let mut encoded_without_prefix = String::new();
|
||||
let mut prefix = String::new();
|
||||
for orig_data_length in 0_usize..26 {
|
||||
// we'll borrow buf to make some data to encode
|
||||
orig_data.clear();
|
||||
push_rand(&mut orig_data, orig_data_length);
|
||||
|
||||
for prefix_length in 1..26 {
|
||||
encoded_with_prefix.clear();
|
||||
encoded_without_prefix.clear();
|
||||
prefix.clear();
|
||||
|
||||
for _ in 0..prefix_length {
|
||||
prefix.push('~');
|
||||
}
|
||||
|
||||
encoded_with_prefix.push_str(&prefix);
|
||||
|
||||
// encode into the non-empty buf
|
||||
encode_config_buf(&orig_data, STANDARD, &mut encoded_with_prefix);
|
||||
// also encode into the empty buf
|
||||
encode_config_buf(&orig_data, STANDARD, &mut encoded_without_prefix);
|
||||
|
||||
assert_eq!(prefix_length + encoded_without_prefix.len(), encoded_with_prefix.len());
|
||||
|
||||
// append plain decode onto prefix
|
||||
prefix.push_str(&mut encoded_without_prefix);
|
||||
|
||||
assert_eq!(prefix, encoded_with_prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn because_we_can() {
|
||||
compare_decode("alice", "YWxpY2U=");
|
||||
compare_decode("alice", &encode(b"alice"));
|
||||
compare_decode("alice", &encode(&decode(&encode(b"alice")).unwrap()));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn encode_url_safe_without_padding() {
|
||||
let encoded = encode_config(b"alice", URL_SAFE_NO_PAD);
|
||||
assert_eq!(&encoded, "YWxpY2U");
|
||||
assert_eq!(String::from_utf8(decode(&encoded).unwrap()).unwrap(), "alice");
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"79fbb792e6c1d05c44188c808ef7120c592e50291a706fe0f669b8ac9a2ad5e5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7","README.md":"b2da2fd61c4f3abf45127d183b61eb2dabc1c97cd191854987aa0328549a663f","benches/benchmarks.rs":"f0469f65f901c3e92fa506c0deb277fd136a7f968cae7cc4f030c0c15e52322f","examples/make_tables.rs":"3c80f2a8cdb204168cc1b60f8904d544b2da067b9e6a7b40ade5fb4a994b4175","src/lib.rs":"a3ac363513ae99a9b0049c19c92bc46b57ac9a0ebfd3317b7b387c5fbaa16a8a","src/tables.rs":"378743892907cde87c1a92e6afee2df36ce590311e61381b2cc0404b3e018039","tests/tests.rs":"dc2c293bae576cc596bdfb6ef783dc1d24d3bf992bf532caaebe1738cb0608cc"},"package":"30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557"}
|
||||
{"files":{"Cargo.toml":"6f4dcaea19fa469551f91670c673d9e240fee726ea78c0ab46ba7b779b3a0d31","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7","README.md":"ac936d8d62e3aab7294e077901010ed0daf99b5f1df0569ffe197859955338c1","benches/benchmarks.rs":"9a7167a38f6f42be4ac32e723aeedcdfd8740a90775c461170a4203809e768f3","examples/make_tables.rs":"3c80f2a8cdb204168cc1b60f8904d544b2da067b9e6a7b40ade5fb4a994b4175","src/lib.rs":"cc226627c531a6d84c95f7b41dc024a26bb0b2341554b4b937baac4b591adf77","src/line_wrap.rs":"3a8f8fb96e3f63d80b87a94e8d4a235ad4e18bd3ee6413c2fd9dcd70354177b6","src/tables.rs":"378743892907cde87c1a92e6afee2df36ce590311e61381b2cc0404b3e018039","src/tests.rs":"61a54ba78255fd360f8b39ca47cefae2e5cb568b525ca1bef7e92dc127a0a485","tests/tests.rs":"80b9b3a44517baaf9bf584cf02fe521594f7993270dffeed3d1e743cf617206c"},"package":"96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "base64"
|
||||
version = "0.5.2"
|
||||
version = "0.6.0"
|
||||
authors = ["Alice Maz <alice@alicemaz.com>", "Marshall Pierce <marshall@mpierce.org>"]
|
||||
description = "encodes and decodes base64 as bytes or utf8"
|
||||
repository = "https://github.com/alicemaz/rust-base64"
|
||||
|
@ -8,10 +8,11 @@ documentation = "https://github.com/alicemaz/rust-base64/blob/master/README.md"
|
|||
readme = "README.md"
|
||||
keywords = ["base64", "utf8", "encode", "decode"]
|
||||
categories = ["encoding"]
|
||||
license = "MIT"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.0.0"
|
||||
safemem = "0.2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "=0.3.15"
|
||||
|
|
|
@ -6,7 +6,7 @@ It's base64. What more could anyone want?
|
|||
Example
|
||||
---
|
||||
|
||||
In Cargo.toml: `base64 = "~0.5.0"`
|
||||
In Cargo.toml: `base64 = "~0.6.0"`
|
||||
|
||||
```rust
|
||||
extern crate base64;
|
||||
|
@ -106,6 +106,20 @@ You'll see a bunch of interleaved rust source and assembly like this. The sectio
|
|||
0.00 : 106ab: je 1090e <base64::decode_config_buf::hbf68a45fefa299c1+0x46e>
|
||||
```
|
||||
|
||||
|
||||
Fuzzing
|
||||
---
|
||||
|
||||
This uses [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz). See `fuzz/fuzzers` for the available fuzzing scripts. To run, use an invocation like these:
|
||||
|
||||
```
|
||||
rustup run nightly cargo fuzz run roundtrip
|
||||
rustup run nightly cargo fuzz run roundtrip_no_pad
|
||||
rustup run nightly cargo fuzz run roundtrip_mime -- -max_len=10240
|
||||
rustup run nightly cargo fuzz run roundtrip_random_config -- -max_len=10240
|
||||
```
|
||||
|
||||
|
||||
License
|
||||
---
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ extern crate base64;
|
|||
extern crate test;
|
||||
extern crate rand;
|
||||
|
||||
use base64::{decode, decode_config_buf, encode, encode_config_buf, STANDARD};
|
||||
use base64::{decode, decode_config_buf, encode, encode_config_buf, Config, MIME, STANDARD};
|
||||
|
||||
use test::Bencher;
|
||||
use rand::Rng;
|
||||
|
@ -16,7 +16,7 @@ fn encode_3b(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn encode_3b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 3)
|
||||
do_encode_bench_reuse_buf(b, 3, STANDARD)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -26,7 +26,7 @@ fn encode_50b(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn encode_50b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 50)
|
||||
do_encode_bench_reuse_buf(b, 50, STANDARD)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -36,7 +36,7 @@ fn encode_100b(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn encode_100b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 100)
|
||||
do_encode_bench_reuse_buf(b, 100, STANDARD)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -46,7 +46,12 @@ fn encode_500b(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn encode_500b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 500)
|
||||
do_encode_bench_reuse_buf(b, 500, STANDARD)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_500b_reuse_buf_mime(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 500, MIME)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -56,7 +61,12 @@ fn encode_3kib(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn encode_3kib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 3 * 1024)
|
||||
do_encode_bench_reuse_buf(b, 3 * 1024, STANDARD)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3kib_reuse_buf_mime(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 3 * 1024, MIME)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -66,7 +76,7 @@ fn encode_3mib(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn encode_3mib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 3 * 1024 * 1024)
|
||||
do_encode_bench_reuse_buf(b, 3 * 1024 * 1024, STANDARD)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -76,7 +86,7 @@ fn encode_10mib(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn encode_10mib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 10 * 1024 * 1024)
|
||||
do_encode_bench_reuse_buf(b, 10 * 1024 * 1024, STANDARD)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -86,7 +96,7 @@ fn encode_30mib(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn encode_30mib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 30 * 1024 * 1024)
|
||||
do_encode_bench_reuse_buf(b, 30 * 1024 * 1024, STANDARD)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -206,7 +216,7 @@ fn do_encode_bench(b: &mut Bencher, size: usize) {
|
|||
});
|
||||
}
|
||||
|
||||
fn do_encode_bench_reuse_buf(b: &mut Bencher, size: usize) {
|
||||
fn do_encode_bench_reuse_buf(b: &mut Bencher, size: usize, config: Config) {
|
||||
let mut v: Vec<u8> = Vec::with_capacity(size);
|
||||
fill(&mut v);
|
||||
|
||||
|
@ -214,8 +224,7 @@ fn do_encode_bench_reuse_buf(b: &mut Bencher, size: usize) {
|
|||
|
||||
b.bytes = v.len() as u64;
|
||||
b.iter(|| {
|
||||
let e = encode_config_buf(&v, STANDARD, &mut buf);
|
||||
test::black_box(&e);
|
||||
encode_config_buf(&v, config, &mut buf);
|
||||
buf.clear();
|
||||
});
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче