Initial commit
This commit is contained in:
commit
636cbea59c
|
@ -0,0 +1,5 @@
|
||||||
|
[target.aarch64-unknown-linux-gnu]
|
||||||
|
linker = "aarch64-linux-gnu-gcc"
|
||||||
|
|
||||||
|
[target.armv7-unknown-linux-gnueabihf]
|
||||||
|
linker = "arm-linux-gnueabihf-gcc"
|
|
@ -0,0 +1,132 @@
|
||||||
|
name: Build
|
||||||
|
|
||||||
|
on: [ push, pull_request ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_BIN_NAME: dtk
|
||||||
|
CARGO_TARGET_DIR: target
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
name: Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: -D warnings
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Setup Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
components: rustfmt, clippy
|
||||||
|
- name: Cargo check
|
||||||
|
run: cargo check --all-features
|
||||||
|
- name: Cargo clippy
|
||||||
|
run: cargo clippy --all-features
|
||||||
|
|
||||||
|
deny:
|
||||||
|
name: Deny
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
checks:
|
||||||
|
- advisories
|
||||||
|
- bans licenses sources
|
||||||
|
# Prevent new advisories from failing CI
|
||||||
|
continue-on-error: ${{ matrix.checks == 'advisories' }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: EmbarkStudios/cargo-deny-action@v1
|
||||||
|
with:
|
||||||
|
command: check ${{ matrix.checks }}
|
||||||
|
|
||||||
|
test:
|
||||||
|
name: Test
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
platform: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ${{ matrix.platform }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Setup Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
- name: Cargo test
|
||||||
|
run: cargo test --release --all-features
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- platform: ubuntu-latest
|
||||||
|
target: x86_64-unknown-linux-gnu
|
||||||
|
name: linux-x86_64
|
||||||
|
- platform: ubuntu-latest
|
||||||
|
target: aarch64-unknown-linux-gnu
|
||||||
|
name: linux-aarch64
|
||||||
|
packages: gcc-aarch64-linux-gnu
|
||||||
|
- platform: ubuntu-latest
|
||||||
|
target: armv7-unknown-linux-gnueabihf
|
||||||
|
name: linux-armv7l
|
||||||
|
packages: gcc-arm-linux-gnueabihf
|
||||||
|
- platform: windows-latest
|
||||||
|
target: x86_64-pc-windows-msvc
|
||||||
|
name: windows-x86_64
|
||||||
|
- platform: windows-latest
|
||||||
|
target: aarch64-pc-windows-msvc
|
||||||
|
name: windows-arm64
|
||||||
|
- platform: macos-latest
|
||||||
|
target: x86_64-apple-darwin
|
||||||
|
name: macos-x86_64
|
||||||
|
- platform: macos-latest
|
||||||
|
target: aarch64-apple-darwin
|
||||||
|
name: macos-arm64
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ${{ matrix.platform }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Install dependencies
|
||||||
|
if: matrix.packages != ''
|
||||||
|
run: sudo apt-get -y install ${{ matrix.packages }}
|
||||||
|
- name: Setup Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: ${{ matrix.target }}
|
||||||
|
- name: Cargo build
|
||||||
|
run: cargo build --release --all-features --target ${{ matrix.target }} --bin ${{ env.CARGO_BIN_NAME }}
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.name }}
|
||||||
|
path: |
|
||||||
|
${{ env.CARGO_TARGET_DIR }}/release/${{ env.CARGO_BIN_NAME }}
|
||||||
|
${{ env.CARGO_TARGET_DIR }}/release/${{ env.CARGO_BIN_NAME }}.exe
|
||||||
|
${{ env.CARGO_TARGET_DIR }}/${{ matrix.target }}/release/${{ env.CARGO_BIN_NAME }}
|
||||||
|
${{ env.CARGO_TARGET_DIR }}/${{ matrix.target }}/release/${{ env.CARGO_BIN_NAME }}.exe
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
release:
|
||||||
|
name: Release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [ build ]
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: artifacts
|
||||||
|
- name: Rename artifacts
|
||||||
|
working-directory: artifacts
|
||||||
|
run: |
|
||||||
|
mkdir ../out
|
||||||
|
for i in */*/release/$CARGO_BIN_NAME*; do
|
||||||
|
mv "$i" "../out/$(sed -E "s/([^/]+)\/[^/]+\/release\/($CARGO_BIN_NAME)/\2-\1/" <<< "$i")"
|
||||||
|
done
|
||||||
|
ls -R ../out
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
files: out/*
|
|
@ -0,0 +1,2 @@
|
||||||
|
/build
|
||||||
|
/.idea
|
|
@ -0,0 +1,659 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.7.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.66"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argh"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c375edecfd2074d5edcc31396860b6e54b6f928714d0e097b983053fac0cabe3"
|
||||||
|
dependencies = [
|
||||||
|
"argh_derive",
|
||||||
|
"argh_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argh_derive"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa013479b80109a1bf01a039412b0f0013d716f36921226d86c6709032fb7a03"
|
||||||
|
dependencies = [
|
||||||
|
"argh_shared",
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argh_shared"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "149f75bbec1827618262e0855a68f0f9a7f2edc13faebf33c4f16d6725edb6a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base16ct"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.77"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
||||||
|
dependencies = [
|
||||||
|
"jobserver",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cwdemangle"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e411efa4ed072fa5bdb637c945ea7f618ebd416748cecc255b00968c1db81e68"
|
||||||
|
dependencies = [
|
||||||
|
"argh",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "decomp-toolkit"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"argh",
|
||||||
|
"base16ct",
|
||||||
|
"cwdemangle",
|
||||||
|
"hex",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"memchr",
|
||||||
|
"memmap2",
|
||||||
|
"multimap",
|
||||||
|
"object",
|
||||||
|
"pretty_env_logger",
|
||||||
|
"regex",
|
||||||
|
"sha-1",
|
||||||
|
"topological-sort",
|
||||||
|
"vergen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum-iterator"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45a0ac4aeb3a18f92eaf09c6bb9b3ac30ff61ca95514fc58cbead1c9a6bf5401"
|
||||||
|
dependencies = [
|
||||||
|
"enum-iterator-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum-iterator-derive"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "828de45d0ca18782232dfb8f3ea9cc428e8ced380eb26a520baaacfc70de39ce"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
"termcolor",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "form_urlencoded"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
|
||||||
|
dependencies = [
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getset"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "git2"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0155506aab710a86160ddb504a480d2964d7ab5b9e62419be69e0032bc5931c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libc",
|
||||||
|
"libgit2-sys",
|
||||||
|
"log",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
||||||
|
dependencies = [
|
||||||
|
"quick-error",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.137"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libgit2-sys"
|
||||||
|
version = "0.13.4+1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0fa6563431ede25f5cc7f6d803c6afbc1c5d3ad3d4925d12c882bf2b526f5d1"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"libz-sys",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libz-sys"
|
||||||
|
version = "1.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memmap2"
|
||||||
|
version = "0.5.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multimap"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "percent-encoding"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_env_logger"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
|
||||||
|
dependencies = [
|
||||||
|
"env_logger",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.47"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "1.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.147"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha-1"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.103"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"serde",
|
||||||
|
"time-core",
|
||||||
|
"time-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
|
||||||
|
dependencies = [
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "topological-sort"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-bidi"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-normalization"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "url"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
|
||||||
|
dependencies = [
|
||||||
|
"form_urlencoded",
|
||||||
|
"idna",
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vergen"
|
||||||
|
version = "7.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73ba753d713ec3844652ad2cb7eb56bc71e34213a14faddac7852a10ba88f61e"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"cfg-if",
|
||||||
|
"enum-iterator",
|
||||||
|
"getset",
|
||||||
|
"git2",
|
||||||
|
"rustversion",
|
||||||
|
"thiserror",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
@ -0,0 +1,38 @@
|
||||||
|
[package]
|
||||||
|
name = "decomp-toolkit"
|
||||||
|
description = "GameCube/Wii decompilation project tools."
|
||||||
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
build = "build.rs"
|
||||||
|
repository = "https://github.com/encounter/decomp-toolkit"
|
||||||
|
readme = "README.md"
|
||||||
|
categories = ["command-line-utilities"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "dtk"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.64"
|
||||||
|
argh = "0.1.8"
|
||||||
|
base16ct = "0.1.1"
|
||||||
|
cwdemangle = "0.1.3"
|
||||||
|
hex = "0.4.3"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
log = "0.4.17"
|
||||||
|
memchr = "2.5.0"
|
||||||
|
memmap2 = "0.5.7"
|
||||||
|
multimap = "0.8.3"
|
||||||
|
object = { version = "0.30.0", features = ["read_core", "std", "elf"], default-features = false }
|
||||||
|
pretty_env_logger = "0.4.0"
|
||||||
|
regex = "1.6.0"
|
||||||
|
sha-1 = "0.10.0"
|
||||||
|
topological-sort = "0.2.2"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
anyhow = "1.0.64"
|
||||||
|
vergen = { version = "7.4.2", features = ["build", "git"], default-features = false }
|
||||||
|
|
|
@ -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 2021 Luke Street.
|
||||||
|
|
||||||
|
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 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright 2021 Luke Street.
|
||||||
|
|
||||||
|
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,58 @@
|
||||||
|
# decomp-toolkit [![Build Status]][actions]
|
||||||
|
|
||||||
|
[Build Status]: https://github.com/encounter/decomp-toolkit/actions/workflows/build.yaml/badge.svg
|
||||||
|
[actions]: https://github.com/encounter/decomp-toolkit/actions
|
||||||
|
|
||||||
|
GameCube/Wii decompilation project tools.
|
||||||
|
|
||||||
|
This provides various commands that assist with creating a build system that works
|
||||||
|
across all major platforms without dealing with platform-specific C compilers,
|
||||||
|
UNIX compatibility layers like msys2, or other idiosyncrasies.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### demangle
|
||||||
|
|
||||||
|
Demangles CodeWarrior C++ symbols. A thin wrapper for [cwdemangle](https://github.com/encounter/cwdemangle).
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ dtk demangle 'BuildLight__9CGuiLightCFv'
|
||||||
|
CGuiLight::BuildLight() const
|
||||||
|
```
|
||||||
|
|
||||||
|
### elf2dol
|
||||||
|
|
||||||
|
Creates a DOL file from the provided ELF file.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ dtk elf2dol input.elf output.dol
|
||||||
|
```
|
||||||
|
|
||||||
|
### map
|
||||||
|
|
||||||
|
Processes CodeWarrior map files and provides information about symbols and TUs.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ dtk map entries Game.MAP 'Unit.o'
|
||||||
|
# Outputs all symbols that are referenced by Unit.o
|
||||||
|
# This is useful for finding deduplicated weak functions,
|
||||||
|
# which only show on first use in the link map.
|
||||||
|
|
||||||
|
$ dtk map symbol Game.MAP 'Function__5ClassFv'
|
||||||
|
# Outputs reference information for Function__5ClassFv
|
||||||
|
# CodeWarrior link maps can get very deeply nested,
|
||||||
|
# so this is useful for emitting direct references
|
||||||
|
# in a readable format.
|
||||||
|
```
|
||||||
|
|
||||||
|
### shasum
|
||||||
|
|
||||||
|
Calculate and verify SHA-1 hashes.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ dtk shasum baserom.dol
|
||||||
|
949c5ed7368aef547e0b0db1c3678f466e2afbff baserom.dol
|
||||||
|
|
||||||
|
$ dtk shasum -c baserom.sha1
|
||||||
|
baserom.dol: OK
|
||||||
|
```
|
|
@ -0,0 +1,4 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use vergen::{vergen, Config};
|
||||||
|
|
||||||
|
fn main() -> Result<()> { vergen(Config::default()) }
|
|
@ -0,0 +1,205 @@
|
||||||
|
# This template contains all of the possible sections and their default values
|
||||||
|
|
||||||
|
# Note that all fields that take a lint level have these possible values:
|
||||||
|
# * deny - An error will be produced and the check will fail
|
||||||
|
# * warn - A warning will be produced, but the check will not fail
|
||||||
|
# * allow - No warning or error will be produced, though in some cases a note
|
||||||
|
# will be
|
||||||
|
|
||||||
|
# The values provided in this template are the default values that will be used
|
||||||
|
# when any section or field is not specified in your own configuration
|
||||||
|
|
||||||
|
# If 1 or more target triples (and optionally, target_features) are specified,
|
||||||
|
# only the specified targets will be checked when running `cargo deny check`.
|
||||||
|
# This means, if a particular package is only ever used as a target specific
|
||||||
|
# dependency, such as, for example, the `nix` crate only being used via the
|
||||||
|
# `target_family = "unix"` configuration, that only having windows targets in
|
||||||
|
# this list would mean the nix crate, as well as any of its exclusive
|
||||||
|
# dependencies not shared by any other crates, would be ignored, as the target
|
||||||
|
# list here is effectively saying which targets you are building for.
|
||||||
|
targets = [
|
||||||
|
# The triple can be any string, but only the target triples built in to
|
||||||
|
# rustc (as of 1.40) can be checked against actual config expressions
|
||||||
|
#{ triple = "x86_64-unknown-linux-musl" },
|
||||||
|
# You can also specify which target_features you promise are enabled for a
|
||||||
|
# particular target. target_features are currently not validated against
|
||||||
|
# the actual valid features supported by the target architecture.
|
||||||
|
#{ triple = "wasm32-unknown-unknown", features = ["atomics"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
# This section is considered when running `cargo deny check advisories`
|
||||||
|
# More documentation for the advisories section can be found here:
|
||||||
|
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
|
||||||
|
[advisories]
|
||||||
|
# The path where the advisory database is cloned/fetched into
|
||||||
|
db-path = "~/.cargo/advisory-db"
|
||||||
|
# The url(s) of the advisory databases to use
|
||||||
|
db-urls = ["https://github.com/rustsec/advisory-db"]
|
||||||
|
# The lint level for security vulnerabilities
|
||||||
|
vulnerability = "deny"
|
||||||
|
# The lint level for unmaintained crates
|
||||||
|
unmaintained = "warn"
|
||||||
|
# The lint level for crates that have been yanked from their source registry
|
||||||
|
yanked = "warn"
|
||||||
|
# The lint level for crates with security notices. Note that as of
|
||||||
|
# 2019-12-17 there are no security notice advisories in
|
||||||
|
# https://github.com/rustsec/advisory-db
|
||||||
|
notice = "warn"
|
||||||
|
# A list of advisory IDs to ignore. Note that ignored advisories will still
|
||||||
|
# output a note when they are encountered.
|
||||||
|
ignore = [
|
||||||
|
#"RUSTSEC-0000-0000",
|
||||||
|
]
|
||||||
|
# Threshold for security vulnerabilities, any vulnerability with a CVSS score
|
||||||
|
# lower than the range specified will be ignored. Note that ignored advisories
|
||||||
|
# will still output a note when they are encountered.
|
||||||
|
# * None - CVSS Score 0.0
|
||||||
|
# * Low - CVSS Score 0.1 - 3.9
|
||||||
|
# * Medium - CVSS Score 4.0 - 6.9
|
||||||
|
# * High - CVSS Score 7.0 - 8.9
|
||||||
|
# * Critical - CVSS Score 9.0 - 10.0
|
||||||
|
#severity-threshold =
|
||||||
|
|
||||||
|
# This section is considered when running `cargo deny check licenses`
|
||||||
|
# More documentation for the licenses section can be found here:
|
||||||
|
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
|
||||||
|
[licenses]
|
||||||
|
# The lint level for crates which do not have a detectable license
|
||||||
|
unlicensed = "deny"
|
||||||
|
# List of explictly allowed licenses
|
||||||
|
# See https://spdx.org/licenses/ for list of possible licenses
|
||||||
|
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
|
||||||
|
allow = [
|
||||||
|
"MIT",
|
||||||
|
"Apache-2.0",
|
||||||
|
"BSD-3-Clause",
|
||||||
|
"Unicode-DFS-2016",
|
||||||
|
"0BSD",
|
||||||
|
]
|
||||||
|
# List of explictly disallowed licenses
|
||||||
|
# See https://spdx.org/licenses/ for list of possible licenses
|
||||||
|
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
|
||||||
|
deny = [
|
||||||
|
#"Nokia",
|
||||||
|
]
|
||||||
|
# Lint level for licenses considered copyleft
|
||||||
|
copyleft = "warn"
|
||||||
|
# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses
|
||||||
|
# * both - The license will be approved if it is both OSI-approved *AND* FSF
|
||||||
|
# * either - The license will be approved if it is either OSI-approved *OR* FSF
|
||||||
|
# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF
|
||||||
|
# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved
|
||||||
|
# * neither - This predicate is ignored and the default lint level is used
|
||||||
|
allow-osi-fsf-free = "neither"
|
||||||
|
# Lint level used when no other predicates are matched
|
||||||
|
# 1. License isn't in the allow or deny lists
|
||||||
|
# 2. License isn't copyleft
|
||||||
|
# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither"
|
||||||
|
default = "deny"
|
||||||
|
# The confidence threshold for detecting a license from license text.
|
||||||
|
# The higher the value, the more closely the license text must be to the
|
||||||
|
# canonical license text of a valid SPDX license file.
|
||||||
|
# [possible values: any between 0.0 and 1.0].
|
||||||
|
confidence-threshold = 0.8
|
||||||
|
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
|
||||||
|
# aren't accepted for every possible crate as with the normal allow list
|
||||||
|
exceptions = [
|
||||||
|
# Each entry is the crate and version constraint, and its specific allow
|
||||||
|
# list
|
||||||
|
#{ allow = ["Zlib"], name = "adler32", version = "*" },
|
||||||
|
]
|
||||||
|
|
||||||
|
# Some crates don't have (easily) machine readable licensing information,
|
||||||
|
# adding a clarification entry for it allows you to manually specify the
|
||||||
|
# licensing information
|
||||||
|
[[licenses.clarify]]
|
||||||
|
# The name of the crate the clarification applies to
|
||||||
|
name = "encoding_rs"
|
||||||
|
# The optional version constraint for the crate
|
||||||
|
#version = "*"
|
||||||
|
# The SPDX expression for the license requirements of the crate
|
||||||
|
expression = "(Apache-2.0 OR MIT) AND BSD-3-Clause"
|
||||||
|
# One or more files in the crate's source used as the "source of truth" for
|
||||||
|
# the license expression. If the contents match, the clarification will be used
|
||||||
|
# when running the license check, otherwise the clarification will be ignored
|
||||||
|
# and the crate will be checked normally, which may produce warnings or errors
|
||||||
|
# depending on the rest of your configuration
|
||||||
|
license-files = [
|
||||||
|
# Each entry is a crate relative path, and the (opaque) hash of its contents
|
||||||
|
{ path = "COPYRIGHT", hash = 0x39f8ad31 }
|
||||||
|
]
|
||||||
|
|
||||||
|
[licenses.private]
|
||||||
|
# If true, ignores workspace crates that aren't published, or are only
|
||||||
|
# published to private registries
|
||||||
|
ignore = false
|
||||||
|
# One or more private registries that you might publish crates to, if a crate
|
||||||
|
# is only published to private registries, and ignore is true, the crate will
|
||||||
|
# not have its license(s) checked
|
||||||
|
registries = [
|
||||||
|
#"https://sekretz.com/registry
|
||||||
|
]
|
||||||
|
|
||||||
|
# This section is considered when running `cargo deny check bans`.
|
||||||
|
# More documentation about the 'bans' section can be found here:
|
||||||
|
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
|
||||||
|
[bans]
|
||||||
|
# Lint level for when multiple versions of the same crate are detected
|
||||||
|
multiple-versions = "warn"
|
||||||
|
# Lint level for when a crate version requirement is `*`
|
||||||
|
wildcards = "allow"
|
||||||
|
# The graph highlighting used when creating dotgraphs for crates
|
||||||
|
# with multiple versions
|
||||||
|
# * lowest-version - The path to the lowest versioned duplicate is highlighted
|
||||||
|
# * simplest-path - The path to the version with the fewest edges is highlighted
|
||||||
|
# * all - Both lowest-version and simplest-path are used
|
||||||
|
highlight = "all"
|
||||||
|
# List of crates that are allowed. Use with care!
|
||||||
|
allow = [
|
||||||
|
#{ name = "ansi_term", version = "=0.11.0" },
|
||||||
|
]
|
||||||
|
# List of crates to deny
|
||||||
|
deny = [
|
||||||
|
# Each entry the name of a crate and a version range. If version is
|
||||||
|
# not specified, all versions will be matched.
|
||||||
|
#{ name = "ansi_term", version = "=0.11.0" },
|
||||||
|
#
|
||||||
|
# Wrapper crates can optionally be specified to allow the crate when it
|
||||||
|
# is a direct dependency of the otherwise banned crate
|
||||||
|
#{ name = "ansi_term", version = "=0.11.0", wrappers = [] },
|
||||||
|
]
|
||||||
|
# Certain crates/versions that will be skipped when doing duplicate detection.
|
||||||
|
skip = [
|
||||||
|
#{ name = "ansi_term", version = "=0.11.0" },
|
||||||
|
]
|
||||||
|
# Similarly to `skip` allows you to skip certain crates during duplicate
|
||||||
|
# detection. Unlike skip, it also includes the entire tree of transitive
|
||||||
|
# dependencies starting at the specified crate, up to a certain depth, which is
|
||||||
|
# by default infinite
|
||||||
|
skip-tree = [
|
||||||
|
#{ name = "ansi_term", version = "=0.11.0", depth = 20 },
|
||||||
|
]
|
||||||
|
|
||||||
|
# This section is considered when running `cargo deny check sources`.
|
||||||
|
# More documentation about the 'sources' section can be found here:
|
||||||
|
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
|
||||||
|
[sources]
|
||||||
|
# Lint level for what to happen when a crate from a crate registry that is not
|
||||||
|
# in the allow list is encountered
|
||||||
|
unknown-registry = "warn"
|
||||||
|
# Lint level for what to happen when a crate from a git repository that is not
|
||||||
|
# in the allow list is encountered
|
||||||
|
unknown-git = "warn"
|
||||||
|
# List of URLs for allowed crate registries. Defaults to the crates.io index
|
||||||
|
# if not specified. If it is specified but empty, no registries are allowed.
|
||||||
|
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||||
|
# List of URLs for allowed Git repositories
|
||||||
|
allow-git = []
|
||||||
|
|
||||||
|
[sources.allow-org]
|
||||||
|
# 1 or more github.com organizations to allow git sources for
|
||||||
|
#github = [""]
|
||||||
|
# 1 or more gitlab.com organizations to allow git sources for
|
||||||
|
#gitlab = [""]
|
||||||
|
# 1 or more bitbucket.org organizations to allow git sources for
|
||||||
|
#bitbucket = [""]
|
|
@ -0,0 +1,8 @@
|
||||||
|
fn_single_line = true
|
||||||
|
group_imports = "StdExternalCrate"
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
overflow_delimited_expr = true
|
||||||
|
reorder_impl_items = true
|
||||||
|
use_field_init_shorthand = true
|
||||||
|
use_small_heuristics = "Max"
|
||||||
|
where_single_line = true
|
|
@ -0,0 +1,65 @@
|
||||||
|
// From https://gist.github.com/suluke/e0c672492126be0a4f3b4f0e1115d77c
|
||||||
|
//! Extend `argh` to be better integrated with the `cargo` ecosystem
|
||||||
|
//!
|
||||||
|
//! For now, this only adds a --version/-V option which causes early-exit.
|
||||||
|
use argh::{FromArgs, TopLevelCommand};
|
||||||
|
|
||||||
|
struct ArgsOrVersion<T: FromArgs>(T);
|
||||||
|
impl<T> TopLevelCommand for ArgsOrVersion<T> where T: FromArgs {}
|
||||||
|
impl<T> FromArgs for ArgsOrVersion<T>
|
||||||
|
where T: FromArgs
|
||||||
|
{
|
||||||
|
fn from_args(command_name: &[&str], args: &[&str]) -> Result<Self, argh::EarlyExit> {
|
||||||
|
/// Also use argh for catching `--version`-only invocations
|
||||||
|
#[derive(FromArgs)]
|
||||||
|
struct Version {
|
||||||
|
/// print version information and exit
|
||||||
|
#[argh(switch, short = 'V')]
|
||||||
|
pub version: bool,
|
||||||
|
}
|
||||||
|
match Version::from_args(command_name, args) {
|
||||||
|
Ok(v) => {
|
||||||
|
if v.version {
|
||||||
|
Err(argh::EarlyExit {
|
||||||
|
output: format!(
|
||||||
|
"{} {} {}",
|
||||||
|
command_name.first().unwrap_or(&""),
|
||||||
|
env!("VERGEN_BUILD_SEMVER"),
|
||||||
|
env!("VERGEN_GIT_SHA"),
|
||||||
|
),
|
||||||
|
status: Ok(()),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// seems args are empty
|
||||||
|
T::from_args(command_name, args).map(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(exit) => match exit.status {
|
||||||
|
Ok(()) => {
|
||||||
|
// must have been --help
|
||||||
|
let help = match T::from_args(command_name, &["--help"]) {
|
||||||
|
Ok(_) => unreachable!(),
|
||||||
|
Err(exit) => exit.output,
|
||||||
|
};
|
||||||
|
Err(argh::EarlyExit {
|
||||||
|
output: format!(
|
||||||
|
"{} -V, --version print version information and exit",
|
||||||
|
help
|
||||||
|
),
|
||||||
|
status: Ok(()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Err(()) => T::from_args(command_name, args).map(Self),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a `FromArgs` type from the current process’s `env::args`.
|
||||||
|
///
|
||||||
|
/// This function will exit early from the current process if argument parsing was unsuccessful or if information like `--help` was requested.
|
||||||
|
/// Error messages will be printed to stderr, and `--help` output to stdout.
|
||||||
|
pub fn from_env<T>() -> T
|
||||||
|
where T: TopLevelCommand {
|
||||||
|
argh::from_env::<ArgsOrVersion<T>>().0
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
use anyhow::{Error, Result};
|
||||||
|
use argh::FromArgs;
|
||||||
|
use cwdemangle::{demangle, DemangleOptions};
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
|
/// Demangle a CodeWarrior C++ symbol.
|
||||||
|
#[argh(subcommand, name = "demangle")]
|
||||||
|
pub struct Args {
|
||||||
|
#[argh(positional)]
|
||||||
|
/// symbol to demangle
|
||||||
|
symbol: String,
|
||||||
|
#[argh(switch)]
|
||||||
|
/// disable replacing `(void)` with `()`
|
||||||
|
keep_void: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(args: Args) -> Result<()> {
|
||||||
|
let options = DemangleOptions { omit_empty_parameters: !args.keep_void };
|
||||||
|
match demangle(args.symbol.as_str(), &options) {
|
||||||
|
Some(symbol) => {
|
||||||
|
println!("{}", symbol);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => Err(Error::msg("Failed to demangle symbol")),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{BufWriter, Seek, SeekFrom, Write},
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::{Context, Error, Result};
|
||||||
|
use argh::FromArgs;
|
||||||
|
use memmap2::MmapOptions;
|
||||||
|
use object::{Architecture, Object, ObjectKind, ObjectSection, SectionKind};
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
|
/// Converts an ELF file to a DOL file.
|
||||||
|
#[argh(subcommand, name = "elf2dol")]
|
||||||
|
pub struct Args {
|
||||||
|
#[argh(positional)]
|
||||||
|
/// path to input ELF
|
||||||
|
elf_file: String,
|
||||||
|
#[argh(positional)]
|
||||||
|
/// path to output DOL
|
||||||
|
dol_file: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct DolSection {
|
||||||
|
pub offset: u32,
|
||||||
|
pub address: u32,
|
||||||
|
pub size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct DolHeader {
|
||||||
|
pub text_sections: Vec<DolSection>,
|
||||||
|
pub data_sections: Vec<DolSection>,
|
||||||
|
pub bss_address: u32,
|
||||||
|
pub bss_size: u32,
|
||||||
|
pub entry_point: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_TEXT_SECTIONS: usize = 7;
|
||||||
|
const MAX_DATA_SECTIONS: usize = 11;
|
||||||
|
const ZERO_BUF: [u8; 32] = [0u8; 32];
|
||||||
|
|
||||||
|
pub fn run(args: Args) -> Result<()> {
|
||||||
|
let elf_file = File::open(&args.elf_file)
|
||||||
|
.with_context(|| format!("Failed to open ELF file '{}'", args.elf_file))?;
|
||||||
|
let map = unsafe { MmapOptions::new().map(&elf_file) }
|
||||||
|
.with_context(|| format!("Failed to mmap binary: '{}'", args.elf_file))?;
|
||||||
|
let obj_file = object::read::File::parse(&*map)?;
|
||||||
|
match obj_file.architecture() {
|
||||||
|
Architecture::PowerPc => {}
|
||||||
|
arch => return Err(Error::msg(format!("Unexpected architecture: {:?}", arch))),
|
||||||
|
};
|
||||||
|
if obj_file.is_little_endian() {
|
||||||
|
return Err(Error::msg("Expected big endian"));
|
||||||
|
}
|
||||||
|
match obj_file.kind() {
|
||||||
|
ObjectKind::Executable => {}
|
||||||
|
kind => return Err(Error::msg(format!("Unexpected ELF type: {:?}", kind))),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut out = BufWriter::new(
|
||||||
|
File::create(&args.dol_file)
|
||||||
|
.with_context(|| format!("Failed to create DOL file '{}'", args.dol_file))?,
|
||||||
|
);
|
||||||
|
let mut header = DolHeader { entry_point: obj_file.entry() as u32, ..Default::default() };
|
||||||
|
let mut offset = 0x100u32;
|
||||||
|
|
||||||
|
// Text sections
|
||||||
|
for section in obj_file.sections() {
|
||||||
|
if section.kind() != SectionKind::Text {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let address = section.address() as u32;
|
||||||
|
let size = align32(section.size() as u32);
|
||||||
|
header.text_sections.push(DolSection { offset, address, size });
|
||||||
|
out.seek(SeekFrom::Start(offset as u64))?;
|
||||||
|
write_aligned(&mut out, section.data()?)?;
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data sections
|
||||||
|
for section in obj_file.sections() {
|
||||||
|
if section.kind() != SectionKind::Data && section.kind() != SectionKind::ReadOnlyData {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let address = section.address() as u32;
|
||||||
|
let size = align32(section.size() as u32);
|
||||||
|
header.data_sections.push(DolSection { offset, address, size });
|
||||||
|
out.seek(SeekFrom::Start(offset as u64))?;
|
||||||
|
write_aligned(&mut out, section.data()?)?;
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSS sections
|
||||||
|
for section in obj_file.sections() {
|
||||||
|
if section.kind() != SectionKind::UninitializedData {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let address = section.address() as u32;
|
||||||
|
let size = section.size() as u32;
|
||||||
|
if header.bss_address == 0 {
|
||||||
|
header.bss_address = address;
|
||||||
|
}
|
||||||
|
header.bss_size = (address + size) - header.bss_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
if header.text_sections.len() > MAX_TEXT_SECTIONS {
|
||||||
|
return Err(Error::msg(format!(
|
||||||
|
"Too many text sections: {} / {}",
|
||||||
|
header.text_sections.len(),
|
||||||
|
MAX_TEXT_SECTIONS
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
if header.data_sections.len() > MAX_DATA_SECTIONS {
|
||||||
|
return Err(Error::msg(format!(
|
||||||
|
"Too many data sections: {} / {}",
|
||||||
|
header.data_sections.len(),
|
||||||
|
MAX_DATA_SECTIONS
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offsets
|
||||||
|
out.rewind()?;
|
||||||
|
for section in &header.text_sections {
|
||||||
|
out.write_all(§ion.offset.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
out.seek(SeekFrom::Start(0x1c))?;
|
||||||
|
for section in &header.data_sections {
|
||||||
|
out.write_all(§ion.offset.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addresses
|
||||||
|
out.seek(SeekFrom::Start(0x48))?;
|
||||||
|
for section in &header.text_sections {
|
||||||
|
out.write_all(§ion.address.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
out.seek(SeekFrom::Start(0x64))?;
|
||||||
|
for section in &header.data_sections {
|
||||||
|
out.write_all(§ion.address.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sizes
|
||||||
|
out.seek(SeekFrom::Start(0x90))?;
|
||||||
|
for section in &header.text_sections {
|
||||||
|
out.write_all(§ion.size.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
out.seek(SeekFrom::Start(0xac))?;
|
||||||
|
for section in &header.data_sections {
|
||||||
|
out.write_all(§ion.size.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSS + entry
|
||||||
|
out.seek(SeekFrom::Start(0xd8))?;
|
||||||
|
out.write_all(&header.bss_address.to_be_bytes())?;
|
||||||
|
out.write_all(&header.bss_size.to_be_bytes())?;
|
||||||
|
out.write_all(&header.entry_point.to_be_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn align32(x: u32) -> u32 { (x + 31) & !31 }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write_aligned<T: Write>(out: &mut T, bytes: &[u8]) -> std::io::Result<()> {
|
||||||
|
let len = bytes.len() as u32;
|
||||||
|
let padding = align32(len) - len;
|
||||||
|
out.write_all(bytes)?;
|
||||||
|
if padding > 0 {
|
||||||
|
out.write_all(&ZERO_BUF[0..padding as usize])?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
use std::{fs::File, io::BufReader};
|
||||||
|
|
||||||
|
use anyhow::{Context, Error, Result};
|
||||||
|
use argh::FromArgs;
|
||||||
|
|
||||||
|
use crate::util::map::{process_map, SymbolEntry, SymbolRef};
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
/// Commands for processing CodeWarrior maps.
|
||||||
|
#[argh(subcommand, name = "map")]
|
||||||
|
pub struct Args {
|
||||||
|
#[argh(subcommand)]
|
||||||
|
command: SubCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
#[argh(subcommand)]
|
||||||
|
enum SubCommand {
|
||||||
|
Entries(EntriesArgs),
|
||||||
|
Symbol(SymbolArgs),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
|
/// Displays all entries for a particular TU.
|
||||||
|
#[argh(subcommand, name = "entries")]
|
||||||
|
pub struct EntriesArgs {
|
||||||
|
#[argh(positional)]
|
||||||
|
/// path to input map
|
||||||
|
map_file: String,
|
||||||
|
#[argh(positional)]
|
||||||
|
/// TU to display entries for
|
||||||
|
unit: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
|
/// Displays all references to a symbol.
|
||||||
|
#[argh(subcommand, name = "symbol")]
|
||||||
|
pub struct SymbolArgs {
|
||||||
|
#[argh(positional)]
|
||||||
|
/// path to input map
|
||||||
|
map_file: String,
|
||||||
|
#[argh(positional)]
|
||||||
|
/// symbol to display references for
|
||||||
|
symbol: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(args: Args) -> Result<()> {
|
||||||
|
match args.command {
|
||||||
|
SubCommand::Entries(c_args) => entries(c_args),
|
||||||
|
SubCommand::Symbol(c_args) => symbol(c_args),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn entries(args: EntriesArgs) -> Result<()> {
|
||||||
|
let reader = BufReader::new(
|
||||||
|
File::open(&args.map_file)
|
||||||
|
.with_context(|| format!("Failed to open file '{}'", args.map_file))?,
|
||||||
|
);
|
||||||
|
let entries = process_map(reader)?;
|
||||||
|
match entries.unit_entries.get_vec(&args.unit) {
|
||||||
|
Some(vec) => {
|
||||||
|
for symbol_ref in vec {
|
||||||
|
if symbol_ref.name.starts_with('@') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(symbol) = entries.symbols.get(symbol_ref) {
|
||||||
|
println!("{}", symbol.demangled.as_ref().unwrap_or(&symbol.name));
|
||||||
|
} else {
|
||||||
|
println!("Symbol not found: {}", symbol_ref.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(Error::msg(format!(
|
||||||
|
"Failed to find entries for TU '{}' in map",
|
||||||
|
args.unit
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn symbol(args: SymbolArgs) -> Result<()> {
|
||||||
|
let reader = BufReader::new(
|
||||||
|
File::open(&args.map_file)
|
||||||
|
.with_context(|| format!("Failed to open file '{}'", args.map_file))?,
|
||||||
|
);
|
||||||
|
let entries = process_map(reader)?;
|
||||||
|
let mut opt_ref: Option<(SymbolRef, SymbolEntry)> = None;
|
||||||
|
for (symbol_ref, entry) in &entries.symbols {
|
||||||
|
if symbol_ref.name == args.symbol {
|
||||||
|
if opt_ref.is_some() {
|
||||||
|
return Err(Error::msg(format!("Symbol '{}' found in multiple TUs", args.symbol)));
|
||||||
|
}
|
||||||
|
opt_ref = Some((symbol_ref.clone(), entry.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match opt_ref {
|
||||||
|
Some((symbol_ref, symbol)) => {
|
||||||
|
println!("Located symbol {}", symbol.demangled.as_ref().unwrap_or(&symbol.name));
|
||||||
|
if let Some(vec) = entries.entry_references.get_vec(&symbol_ref) {
|
||||||
|
println!("\nReferences:");
|
||||||
|
for x in vec {
|
||||||
|
if let Some(reference) = entries.symbols.get(x) {
|
||||||
|
println!(
|
||||||
|
">>> {} ({:?},{:?}) [{}]",
|
||||||
|
reference.demangled.as_ref().unwrap_or(&reference.name),
|
||||||
|
reference.kind,
|
||||||
|
reference.visibility,
|
||||||
|
reference.unit
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!(">>> {} (NOT FOUND)", x.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(vec) = entries.entry_referenced_from.get_vec(&symbol_ref) {
|
||||||
|
println!("\nReferenced from:");
|
||||||
|
for x in vec {
|
||||||
|
if let Some(reference) = entries.symbols.get(x) {
|
||||||
|
println!(
|
||||||
|
">>> {} ({:?}, {:?}) [{}]",
|
||||||
|
reference.demangled.as_ref().unwrap_or(&reference.name),
|
||||||
|
reference.kind,
|
||||||
|
reference.visibility,
|
||||||
|
reference.unit
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!(">>> {} (NOT FOUND)", x.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("\n");
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(Error::msg(format!("Failed to find symbol '{}' in map", args.symbol)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
use anyhow::{Context, Error, Result};
|
||||||
|
use argh::FromArgs;
|
||||||
|
use memchr::memmem;
|
||||||
|
use memmap2::MmapOptions;
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
|
/// Sets the MetroidBuildInfo tag value in a given binary.
|
||||||
|
#[argh(subcommand, name = "metroidbuildinfo")]
|
||||||
|
pub struct Args {
|
||||||
|
#[argh(positional)]
|
||||||
|
/// path to source binary
|
||||||
|
binary: String,
|
||||||
|
#[argh(positional)]
|
||||||
|
/// path to build info string
|
||||||
|
build_info: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const BUILD_STRING_MAX: usize = 35;
|
||||||
|
const BUILD_STRING_TAG: &str = "!#$MetroidBuildInfo!#$";
|
||||||
|
|
||||||
|
pub fn run(args: Args) -> Result<()> {
|
||||||
|
let build_string = std::fs::read_to_string(&args.build_info)
|
||||||
|
.with_context(|| format!("Failed to read build info string from '{}'", args.build_info))?;
|
||||||
|
let build_string_trim = build_string.trim_end();
|
||||||
|
if build_string_trim.as_bytes().len() > BUILD_STRING_MAX {
|
||||||
|
return Err(Error::msg(format!(
|
||||||
|
"Build string '{}' is greater than maximum size of {}",
|
||||||
|
build_string_trim, BUILD_STRING_MAX
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let binary_file = std::fs::File::options()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.open(&args.binary)
|
||||||
|
.with_context(|| format!("Failed to open binary for writing: '{}'", args.binary))?;
|
||||||
|
let mut map = unsafe { MmapOptions::new().map_mut(&binary_file) }
|
||||||
|
.with_context(|| format!("Failed to mmap binary: '{}'", args.binary))?;
|
||||||
|
let start = match memmem::find(&map, BUILD_STRING_TAG.as_bytes()) {
|
||||||
|
Some(idx) => idx + BUILD_STRING_TAG.as_bytes().len(),
|
||||||
|
None => return Err(Error::msg("Failed to find build string tag in binary")),
|
||||||
|
};
|
||||||
|
let end = start + build_string_trim.as_bytes().len();
|
||||||
|
map[start..end].copy_from_slice(build_string_trim.as_bytes());
|
||||||
|
map[end] = 0;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
pub(crate) mod demangle;
|
||||||
|
pub(crate) mod elf2dol;
|
||||||
|
pub(crate) mod map;
|
||||||
|
pub(crate) mod metroidbuildinfo;
|
||||||
|
pub(crate) mod shasum;
|
|
@ -0,0 +1,88 @@
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{BufRead, BufReader, Read},
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::{Context, Error, Result};
|
||||||
|
use argh::FromArgs;
|
||||||
|
use sha1::{Digest, Sha1};
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
|
/// Print or check SHA1 (160-bit) checksums.
|
||||||
|
#[argh(subcommand, name = "shasum")]
|
||||||
|
pub struct Args {
|
||||||
|
#[argh(switch, short = 'c')]
|
||||||
|
/// check SHA sums against given list
|
||||||
|
check: bool,
|
||||||
|
#[argh(positional)]
|
||||||
|
/// path to file
|
||||||
|
file: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_BUF_SIZE: usize = 8192;
|
||||||
|
|
||||||
|
pub fn run(args: Args) -> Result<()> {
|
||||||
|
let file =
|
||||||
|
File::open(&args.file).with_context(|| format!("Failed to open file '{}'", args.file))?;
|
||||||
|
if args.check {
|
||||||
|
check(args, file)
|
||||||
|
} else {
|
||||||
|
hash(args, file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check(_args: Args, file: File) -> Result<()> {
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
let mut mismatches = 0usize;
|
||||||
|
for line in reader.lines() {
|
||||||
|
let line = match line {
|
||||||
|
Ok(line) => line,
|
||||||
|
Err(e) => return Err(Error::msg(format!("File read failed: {}", e))),
|
||||||
|
};
|
||||||
|
let (hash, file_name) =
|
||||||
|
line.split_once(' ').ok_or_else(|| Error::msg(format!("Invalid line: {}", line)))?;
|
||||||
|
let file_name = match file_name.chars().next() {
|
||||||
|
Some(' ') | Some('*') => &file_name[1..],
|
||||||
|
_ => return Err(Error::msg(format!("Invalid line: {}", line))),
|
||||||
|
};
|
||||||
|
let mut hash_bytes = [0u8; 20];
|
||||||
|
hex::decode_to_slice(hash, &mut hash_bytes)
|
||||||
|
.with_context(|| format!("Invalid line: {}", line))?;
|
||||||
|
|
||||||
|
let file = File::open(file_name)
|
||||||
|
.with_context(|| format!("Failed to open file '{}'", file_name))?;
|
||||||
|
let found_hash = file_sha1(file)?;
|
||||||
|
if hash_bytes == found_hash.as_ref() {
|
||||||
|
println!("{}: OK", file_name);
|
||||||
|
} else {
|
||||||
|
println!("{}: FAILED", file_name);
|
||||||
|
mismatches += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mismatches != 0 {
|
||||||
|
eprintln!("WARNING: {} computed checksum did NOT match", mismatches);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash(args: Args, file: File) -> Result<()> {
|
||||||
|
let hash = file_sha1(file)?;
|
||||||
|
let mut hash_buf = [0u8; 40];
|
||||||
|
let hash_str = base16ct::lower::encode_str(&hash, &mut hash_buf)
|
||||||
|
.map_err(|e| Error::msg(format!("Failed to encode hash: {}", e)))?;
|
||||||
|
println!("{} {}", hash_str, args.file);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file_sha1(mut file: File) -> Result<sha1::digest::Output<Sha1>> {
|
||||||
|
let mut buf = [0u8; DEFAULT_BUF_SIZE];
|
||||||
|
let mut hasher = Sha1::new();
|
||||||
|
Ok(loop {
|
||||||
|
let read = file.read(&mut buf).context("File read failed")?;
|
||||||
|
if read == 0 {
|
||||||
|
break hasher.finalize();
|
||||||
|
}
|
||||||
|
hasher.update(&buf[0..read]);
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
|
use argh::FromArgs;
|
||||||
|
|
||||||
|
mod argh_version;
|
||||||
|
mod cmd;
|
||||||
|
mod util;
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
/// GameCube/Wii decompilation project tools.
|
||||||
|
struct TopLevel {
|
||||||
|
#[argh(subcommand)]
|
||||||
|
command: SubCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
#[argh(subcommand)]
|
||||||
|
enum SubCommand {
|
||||||
|
Demangle(cmd::demangle::Args),
|
||||||
|
Elf2Dol(cmd::elf2dol::Args),
|
||||||
|
Map(cmd::map::Args),
|
||||||
|
MetroidBuildInfo(cmd::metroidbuildinfo::Args),
|
||||||
|
Shasum(cmd::shasum::Args),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args: TopLevel = argh_version::from_env();
|
||||||
|
let result = match args.command {
|
||||||
|
SubCommand::Demangle(c_args) => cmd::demangle::run(c_args),
|
||||||
|
SubCommand::Elf2Dol(c_args) => cmd::elf2dol::run(c_args),
|
||||||
|
SubCommand::Map(c_args) => cmd::map::run(c_args),
|
||||||
|
SubCommand::MetroidBuildInfo(c_args) => cmd::metroidbuildinfo::run(c_args),
|
||||||
|
SubCommand::Shasum(c_args) => cmd::shasum::run(c_args),
|
||||||
|
};
|
||||||
|
if let Err(e) = result {
|
||||||
|
eprintln!("{:?}", e);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,485 @@
|
||||||
|
use std::{
|
||||||
|
collections::{btree_map::Entry, BTreeMap, HashMap},
|
||||||
|
io::BufRead,
|
||||||
|
ops::Range,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::{Error, Result};
|
||||||
|
use cwdemangle::{demangle, DemangleOptions};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use multimap::MultiMap;
|
||||||
|
use regex::Regex;
|
||||||
|
use topological_sort::TopologicalSort;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum SymbolKind {
|
||||||
|
Function,
|
||||||
|
Object,
|
||||||
|
Section,
|
||||||
|
NoType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum SymbolVisibility {
|
||||||
|
Global,
|
||||||
|
Local,
|
||||||
|
Weak,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SymbolEntry {
|
||||||
|
pub name: String,
|
||||||
|
pub demangled: Option<String>,
|
||||||
|
pub kind: SymbolKind,
|
||||||
|
pub visibility: SymbolVisibility,
|
||||||
|
pub unit: String,
|
||||||
|
pub address: u32,
|
||||||
|
pub size: u32,
|
||||||
|
pub section: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
|
pub struct SymbolRef {
|
||||||
|
pub name: String,
|
||||||
|
pub unit: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct SectionOrder {
|
||||||
|
symbol_order: Vec<SymbolRef>,
|
||||||
|
unit_order: Vec<(String, Vec<String>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_code_section(section: &str) -> bool { section == ".text" || section == ".init" }
|
||||||
|
|
||||||
|
/// Iterate over the BTreeMap and generate an ordered list of symbols and TUs by address.
|
||||||
|
fn resolve_section_order(
|
||||||
|
address_to_symbol: &BTreeMap<u32, SymbolRef>,
|
||||||
|
symbol_entries: &mut HashMap<SymbolRef, SymbolEntry>,
|
||||||
|
) -> Result<SectionOrder> {
|
||||||
|
let mut ordering = SectionOrder::default();
|
||||||
|
|
||||||
|
let mut last_unit = String::new();
|
||||||
|
let mut unit_override = String::new();
|
||||||
|
let mut last_section = String::new();
|
||||||
|
let mut section_unit_idx = 0usize;
|
||||||
|
for symbol_ref in address_to_symbol.values() {
|
||||||
|
if let Some(symbol) = symbol_entries.get_mut(symbol_ref) {
|
||||||
|
if last_unit != symbol.unit {
|
||||||
|
unit_override.clear();
|
||||||
|
|
||||||
|
if last_section != symbol.section {
|
||||||
|
ordering.unit_order.push((symbol.section.clone(), vec![]));
|
||||||
|
section_unit_idx = ordering.unit_order.len() - 1;
|
||||||
|
last_section = symbol.section.clone();
|
||||||
|
}
|
||||||
|
let unit_order = &mut ordering.unit_order[section_unit_idx];
|
||||||
|
if unit_order.1.contains(&symbol.unit) {
|
||||||
|
// With -common on, .bss is split into two parts. The TU order repeats
|
||||||
|
// at the end with all globally-deduplicated BSS symbols. Once we detect
|
||||||
|
// a duplicate inside of .bss, we create a new section and start again.
|
||||||
|
// TODO the first entry in .comm *could* be a TU without regular .bss
|
||||||
|
if symbol.section == ".bss" {
|
||||||
|
log::debug!(".comm section detected, duplicate {}", symbol.unit);
|
||||||
|
ordering.unit_order.push((".comm".to_string(), vec![symbol.unit.clone()]));
|
||||||
|
section_unit_idx = ordering.unit_order.len() - 1;
|
||||||
|
} else {
|
||||||
|
// Since the map doesn't contain file paths, it's likely that
|
||||||
|
// a TU name conflict is simply a separate file.
|
||||||
|
// TODO need to resolve and split unit in other sections as well
|
||||||
|
unit_override =
|
||||||
|
format!("{}_{}_{:X}", symbol.unit, symbol.section, symbol.address);
|
||||||
|
log::warn!(
|
||||||
|
"TU order conflict: {} exists multiple times in {}. Renaming to {}.",
|
||||||
|
symbol.unit,
|
||||||
|
symbol.section,
|
||||||
|
unit_override,
|
||||||
|
);
|
||||||
|
unit_order.1.push(unit_override.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unit_order.1.push(symbol.unit.clone());
|
||||||
|
}
|
||||||
|
last_unit = symbol.unit.clone();
|
||||||
|
}
|
||||||
|
// For ASM-generated objects, notype,local symbols in .text
|
||||||
|
// are usually local jump labels, and should be ignored.
|
||||||
|
if is_code_section(&symbol.section)
|
||||||
|
&& symbol.size == 0
|
||||||
|
&& symbol.kind == SymbolKind::NoType
|
||||||
|
&& symbol.visibility == SymbolVisibility::Local
|
||||||
|
{
|
||||||
|
// Being named something other than lbl_* could indicate
|
||||||
|
// that it's actually a local function, but let's just
|
||||||
|
// make the user resolve that if necessary.
|
||||||
|
if !symbol.name.starts_with("lbl_") {
|
||||||
|
log::warn!("Skipping local text symbol {}", symbol.name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Guess the symbol type if necessary.
|
||||||
|
if symbol.kind == SymbolKind::NoType {
|
||||||
|
if is_code_section(&symbol.section) {
|
||||||
|
symbol.kind = SymbolKind::Function;
|
||||||
|
} else {
|
||||||
|
symbol.kind = SymbolKind::Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we're renaming this TU, replace it in the symbol.
|
||||||
|
if !unit_override.is_empty() {
|
||||||
|
symbol.unit = unit_override.clone();
|
||||||
|
}
|
||||||
|
ordering.symbol_order.push(symbol_ref.clone());
|
||||||
|
} else {
|
||||||
|
return Err(Error::msg(format!("Symbol has address but no entry: {:?}", symbol_ref)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for iter in ordering.symbol_order.windows(2) {
|
||||||
|
let next_address = symbol_entries.get(&iter[1]).unwrap().address;
|
||||||
|
let symbol = symbol_entries.get_mut(&iter[0]).unwrap();
|
||||||
|
// For ASM-generated objects, we need to guess the symbol size.
|
||||||
|
if symbol.size == 0 {
|
||||||
|
symbol.size = next_address - symbol.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ordering)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The ordering of TUs inside of each section represents a directed edge in a DAG.
|
||||||
|
/// We can use a topological sort to determine a valid global TU order.
|
||||||
|
/// There can be ambiguities, but any solution that satisfies the link order
|
||||||
|
/// constraints is considered valid.
|
||||||
|
// TODO account for library ordering
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn resolve_link_order(section_unit_order: &[(String, Vec<String>)]) -> Result<Vec<String>> {
|
||||||
|
let mut global_unit_order = Vec::<String>::new();
|
||||||
|
let mut t_sort = TopologicalSort::<String>::new();
|
||||||
|
for (section, order) in section_unit_order {
|
||||||
|
let mut order: &[String] = order;
|
||||||
|
if (section == ".ctors" || section == ".dtors") && order.len() > 1 {
|
||||||
|
// __init_cpp_exceptions.o has symbols that get ordered to the beginning of
|
||||||
|
// .ctors and .dtors, so our topological sort would fail if we added them.
|
||||||
|
// Always skip the first TU of .ctors and .dtors.
|
||||||
|
order = &order[1..];
|
||||||
|
}
|
||||||
|
for iter in order.windows(2) {
|
||||||
|
t_sort.add_dependency(iter[0].clone(), iter[1].clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for unit in &mut t_sort {
|
||||||
|
global_unit_order.push(unit);
|
||||||
|
}
|
||||||
|
// An incomplete topological sort indicates that a cyclic dependency was encountered.
|
||||||
|
if !t_sort.is_empty() {
|
||||||
|
return Err(Error::msg("Cyclic dependency encountered!"));
|
||||||
|
}
|
||||||
|
// Sanity check, did we get all TUs in the final order?
|
||||||
|
for (_, order) in section_unit_order {
|
||||||
|
for unit in order {
|
||||||
|
if !global_unit_order.contains(unit) {
|
||||||
|
return Err(Error::msg(format!("Failed to find an order for {}", unit)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(global_unit_order)
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref LINK_MAP_START: Regex = Regex::new("^Link map of (.*)$").unwrap();
|
||||||
|
static ref LINK_MAP_ENTRY: Regex = Regex::new(
|
||||||
|
"^\\s*(?P<depth>\\d+)] (?P<sym>.*) \\((?P<type>.*),(?P<vis>.*)\\) found in (?P<tu>.*)$",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
static ref LINK_MAP_ENTRY_GENERATED: Regex =
|
||||||
|
Regex::new("^\\s*(?P<depth>\\d+)] (?P<sym>.*) found as linker generated symbol$").unwrap();
|
||||||
|
static ref LINK_MAP_ENTRY_DUPLICATE: Regex =
|
||||||
|
Regex::new("^\\s*(?P<depth>\\d+)] >>> UNREFERENCED DUPLICATE (?P<sym>.*)$").unwrap();
|
||||||
|
static ref SECTION_LAYOUT_START: Regex = Regex::new("^(?P<section>.*) section layout$").unwrap();
|
||||||
|
static ref SECTION_LAYOUT_SYMBOL: Regex = Regex::new(
|
||||||
|
"^\\s*(?P<rom_addr>[0-9A-Fa-f]+|UNUSED)\\s+(?P<size>[0-9A-Fa-f]+)\\s+(?P<addr>[0-9A-Fa-f]+|\\.{8})\\s+(?P<align>\\d+)?\\s*(?P<sym>.*?)(?:\\s+\\(entry of (?P<entry_of>.*?)\\))?\\s+(?P<tu>.*)$",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
static ref SECTION_LAYOUT_HEADER: Regex = Regex::new(
|
||||||
|
"^(\\s*Starting\\s+Virtual\\s*|\\s*address\\s+Size\\s+address\\s*|\\s*-----------------------\\s*)$",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
static ref MEMORY_MAP_HEADER: Regex = Regex::new("^\\s*Memory map:\\s*$").unwrap();
|
||||||
|
static ref EXTERN_SYMBOL: Regex = Regex::new("^\\s*>>> SYMBOL NOT FOUND: (.*)$").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MapEntries {
|
||||||
|
pub symbols: HashMap<SymbolRef, SymbolEntry>,
|
||||||
|
pub unit_entries: MultiMap<String, SymbolRef>,
|
||||||
|
pub entry_references: MultiMap<SymbolRef, SymbolRef>,
|
||||||
|
pub entry_referenced_from: MultiMap<SymbolRef, SymbolRef>,
|
||||||
|
pub address_to_symbol: BTreeMap<u32, SymbolRef>,
|
||||||
|
pub unit_section_ranges: HashMap<String, Range<u32>>,
|
||||||
|
pub symbol_order: Vec<SymbolRef>,
|
||||||
|
pub unit_order: Vec<(String, Vec<String>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_map<R: BufRead>(reader: R) -> Result<MapEntries> {
|
||||||
|
let mut entries = MapEntries::default();
|
||||||
|
|
||||||
|
let mut symbol_stack = Vec::<SymbolRef>::new();
|
||||||
|
let mut current_section = String::new();
|
||||||
|
let mut last_name = String::new();
|
||||||
|
let mut last_unit = String::new();
|
||||||
|
let mut has_link_map = false;
|
||||||
|
let mut relative_offset = 0u32;
|
||||||
|
let mut last_section_end = 0u32;
|
||||||
|
for result in reader.lines() {
|
||||||
|
match result {
|
||||||
|
Ok(line) => {
|
||||||
|
if let Some(captures) = LINK_MAP_START.captures(&line) {
|
||||||
|
log::debug!("Entry point: {}", &captures[1]);
|
||||||
|
has_link_map = true;
|
||||||
|
} else if let Some(captures) = LINK_MAP_ENTRY.captures(&line) {
|
||||||
|
if captures["sym"].starts_with('.') {
|
||||||
|
last_name.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let is_duplicate = &captures["sym"] == ">>>";
|
||||||
|
let unit = captures["tu"].trim().to_string();
|
||||||
|
let name = if is_duplicate {
|
||||||
|
if last_name.is_empty() {
|
||||||
|
return Err(Error::msg("Last name empty?"));
|
||||||
|
}
|
||||||
|
last_name.clone()
|
||||||
|
} else {
|
||||||
|
captures["sym"].to_string()
|
||||||
|
};
|
||||||
|
let symbol_ref = SymbolRef { name: name.clone(), unit: unit.clone() };
|
||||||
|
let depth: usize = captures["depth"].parse()?;
|
||||||
|
if depth > symbol_stack.len() {
|
||||||
|
symbol_stack.push(symbol_ref.clone());
|
||||||
|
} else if depth <= symbol_stack.len() {
|
||||||
|
symbol_stack.truncate(depth - 1);
|
||||||
|
symbol_stack.push(symbol_ref.clone());
|
||||||
|
}
|
||||||
|
// println!("Entry: {} ({})", name, tu);
|
||||||
|
let kind = match &captures["type"] {
|
||||||
|
"func" => SymbolKind::Function,
|
||||||
|
"object" => SymbolKind::Object,
|
||||||
|
"section" => SymbolKind::Section,
|
||||||
|
"notype" => SymbolKind::NoType,
|
||||||
|
_ => {
|
||||||
|
return Err(Error::msg(format!(
|
||||||
|
"Unknown symbol type: {}",
|
||||||
|
&captures["type"],
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let visibility = match &captures["vis"] {
|
||||||
|
"global" => SymbolVisibility::Global,
|
||||||
|
"local" => SymbolVisibility::Local,
|
||||||
|
"weak" => SymbolVisibility::Weak,
|
||||||
|
_ => {
|
||||||
|
return Err(Error::msg(format!(
|
||||||
|
"Unknown symbol visibility: {}",
|
||||||
|
&captures["vis"],
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !is_duplicate && symbol_stack.len() > 1 {
|
||||||
|
let from = &symbol_stack[symbol_stack.len() - 2];
|
||||||
|
entries.entry_referenced_from.insert(symbol_ref.clone(), from.clone());
|
||||||
|
entries.entry_references.insert(from.clone(), symbol_ref.clone());
|
||||||
|
}
|
||||||
|
let mut should_insert = true;
|
||||||
|
if let Some(symbol) = entries.symbols.get(&symbol_ref) {
|
||||||
|
if symbol.kind != kind {
|
||||||
|
log::warn!(
|
||||||
|
"Kind mismatch for {}: was {:?}, now {:?}",
|
||||||
|
symbol.name,
|
||||||
|
symbol.kind,
|
||||||
|
kind
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if symbol.visibility != visibility {
|
||||||
|
log::warn!(
|
||||||
|
"Visibility mismatch for {}: was {:?}, now {:?}",
|
||||||
|
symbol.name,
|
||||||
|
symbol.visibility,
|
||||||
|
visibility
|
||||||
|
);
|
||||||
|
}
|
||||||
|
entries.unit_entries.insert(unit.clone(), symbol_ref.clone());
|
||||||
|
should_insert = false;
|
||||||
|
}
|
||||||
|
if should_insert {
|
||||||
|
let demangled =
|
||||||
|
demangle(&name, &DemangleOptions { omit_empty_parameters: true });
|
||||||
|
entries.symbols.insert(symbol_ref.clone(), SymbolEntry {
|
||||||
|
name: name.clone(),
|
||||||
|
demangled,
|
||||||
|
kind,
|
||||||
|
visibility,
|
||||||
|
unit: unit.clone(),
|
||||||
|
address: 0,
|
||||||
|
size: 0,
|
||||||
|
section: String::new(),
|
||||||
|
});
|
||||||
|
last_name = name.clone();
|
||||||
|
entries.unit_entries.insert(unit, symbol_ref.clone());
|
||||||
|
}
|
||||||
|
} else if let Some(captures) = LINK_MAP_ENTRY_GENERATED.captures(&line) {
|
||||||
|
let name = captures["sym"].to_string();
|
||||||
|
let demangled =
|
||||||
|
demangle(&name, &DemangleOptions { omit_empty_parameters: true });
|
||||||
|
let symbol_ref =
|
||||||
|
SymbolRef { name: name.clone(), unit: "[generated]".to_string() };
|
||||||
|
entries.symbols.insert(symbol_ref, SymbolEntry {
|
||||||
|
name,
|
||||||
|
demangled,
|
||||||
|
kind: SymbolKind::NoType,
|
||||||
|
visibility: SymbolVisibility::Global,
|
||||||
|
unit: "[generated]".to_string(),
|
||||||
|
address: 0,
|
||||||
|
size: 0,
|
||||||
|
section: String::new(),
|
||||||
|
});
|
||||||
|
} else if line.trim().is_empty()
|
||||||
|
|| LINK_MAP_ENTRY_DUPLICATE.is_match(&line)
|
||||||
|
|| SECTION_LAYOUT_HEADER.is_match(&line)
|
||||||
|
|| EXTERN_SYMBOL.is_match(&line)
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
} else if let Some(captures) = SECTION_LAYOUT_START.captures(&line) {
|
||||||
|
current_section = captures["section"].trim().to_string();
|
||||||
|
last_unit.clear();
|
||||||
|
log::debug!("Processing section layout for {}", current_section);
|
||||||
|
} else if let Some(captures) = SECTION_LAYOUT_SYMBOL.captures(&line) {
|
||||||
|
if captures["rom_addr"].trim() == "UNUSED" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let sym_name = captures["sym"].trim();
|
||||||
|
let tu = captures["tu"].trim();
|
||||||
|
let mut address = u32::from_str_radix(captures["addr"].trim(), 16)?;
|
||||||
|
let mut size = u32::from_str_radix(captures["size"].trim(), 16)?;
|
||||||
|
|
||||||
|
// For RELs, the each section starts at address 0. For our purposes
|
||||||
|
// we'll create "fake" addresses by simply starting at the end of the
|
||||||
|
// previous section.
|
||||||
|
if last_unit.is_empty() {
|
||||||
|
if address == 0 {
|
||||||
|
relative_offset = last_section_end;
|
||||||
|
} else {
|
||||||
|
relative_offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
address += relative_offset;
|
||||||
|
|
||||||
|
// Section symbol (i.e. ".data") indicates section size for a TU
|
||||||
|
if sym_name == current_section {
|
||||||
|
// Skip empty sections
|
||||||
|
if size == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let end = address + size;
|
||||||
|
entries.unit_section_ranges.insert(tu.to_string(), address..end);
|
||||||
|
last_unit = tu.to_string();
|
||||||
|
last_section_end = end;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, for ASM-generated objects, the first section symbol in a TU
|
||||||
|
// has the full size of the section.
|
||||||
|
if tu != last_unit {
|
||||||
|
if size == 0 {
|
||||||
|
return Err(Error::msg(format!(
|
||||||
|
"No section size for {} in {}",
|
||||||
|
sym_name, tu
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let end = address + size;
|
||||||
|
entries.unit_section_ranges.insert(tu.to_string(), address..end);
|
||||||
|
last_unit = tu.to_string();
|
||||||
|
last_section_end = end;
|
||||||
|
|
||||||
|
// Clear it, so that we guess the "real" symbol size later.
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore ...data.0 and similar
|
||||||
|
if sym_name.starts_with("...") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let symbol_ref = SymbolRef { name: sym_name.to_string(), unit: tu.to_string() };
|
||||||
|
if let Some(symbol) = entries.symbols.get_mut(&symbol_ref) {
|
||||||
|
symbol.address = address;
|
||||||
|
symbol.size = size;
|
||||||
|
symbol.section = current_section.clone();
|
||||||
|
match entries.address_to_symbol.entry(address) {
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
entry.insert(symbol_ref.clone());
|
||||||
|
}
|
||||||
|
Entry::Occupied(entry) => {
|
||||||
|
log::warn!(
|
||||||
|
"Symbol overridden @ {:X} from {} to {} in {}",
|
||||||
|
symbol.address,
|
||||||
|
entry.get().name,
|
||||||
|
sym_name,
|
||||||
|
tu
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let visibility = if has_link_map {
|
||||||
|
log::warn!(
|
||||||
|
"Symbol not in link map: {} ({}). Type and visibility unknown.",
|
||||||
|
sym_name,
|
||||||
|
tu,
|
||||||
|
);
|
||||||
|
SymbolVisibility::Local
|
||||||
|
} else {
|
||||||
|
SymbolVisibility::Global
|
||||||
|
};
|
||||||
|
entries.symbols.insert(symbol_ref.clone(), SymbolEntry {
|
||||||
|
name: sym_name.to_string(),
|
||||||
|
demangled: None,
|
||||||
|
kind: SymbolKind::NoType,
|
||||||
|
visibility,
|
||||||
|
unit: tu.to_string(),
|
||||||
|
address,
|
||||||
|
size,
|
||||||
|
section: current_section.clone(),
|
||||||
|
});
|
||||||
|
match entries.address_to_symbol.entry(address) {
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
entry.insert(symbol_ref.clone());
|
||||||
|
}
|
||||||
|
Entry::Occupied(entry) => {
|
||||||
|
log::warn!(
|
||||||
|
"Symbol overridden @ {:X} from {} to {} in {}",
|
||||||
|
address,
|
||||||
|
entry.get().name,
|
||||||
|
sym_name,
|
||||||
|
tu
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if MEMORY_MAP_HEADER.is_match(&line) {
|
||||||
|
// log::debug!("Done");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
todo!("{}", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(Error::from(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let section_order = resolve_section_order(&entries.address_to_symbol, &mut entries.symbols)?;
|
||||||
|
entries.symbol_order = section_order.symbol_order;
|
||||||
|
entries.unit_order = section_order.unit_order;
|
||||||
|
|
||||||
|
Ok(entries)
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
pub(crate) mod map;
|
Loading…
Reference in New Issue