mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-06-26 16:33:30 +00:00
Migrate argh to argp, topological-sort to petgraph
This commit is contained in:
parent
8660984d40
commit
bd0422e92a
77
Cargo.lock
generated
77
Cargo.lock
generated
@ -79,6 +79,27 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f"
|
checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argp"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84c16c577a1a3b720a90eb2127bd0ae61530a71064d1a6babaaaa87f6174b9f1"
|
||||||
|
dependencies = [
|
||||||
|
"argp_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argp_derive"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe3763c8b5e0ef2f7d0df26daa671808cc75e2d81547f63ccca96bf045e41799"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"pulldown-cmark",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.107",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -197,7 +218,7 @@ version = "0.3.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ar",
|
"ar",
|
||||||
"argh",
|
"argp",
|
||||||
"base16ct",
|
"base16ct",
|
||||||
"base64",
|
"base64",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
@ -219,6 +240,7 @@ dependencies = [
|
|||||||
"num_enum",
|
"num_enum",
|
||||||
"object 0.31.1",
|
"object 0.31.1",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"petgraph",
|
||||||
"ppc750cl",
|
"ppc750cl",
|
||||||
"regex",
|
"regex",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
@ -227,7 +249,6 @@ dependencies = [
|
|||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"sha-1",
|
"sha-1",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"topological-sort",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -343,6 +364,15 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getopts"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.27.0"
|
version = "0.27.0"
|
||||||
@ -577,6 +607,16 @@ version = "1.0.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
|
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap 1.9.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppc750cl"
|
name = "ppc750cl"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -606,6 +646,18 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pulldown-cmark"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"getopts",
|
||||||
|
"memchr",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.29"
|
version = "1.0.29"
|
||||||
@ -822,24 +874,33 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "topological-sort"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicase"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||||
|
dependencies = [
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unsafe-libyaml"
|
name = "unsafe-libyaml"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "decomp-toolkit"
|
name = "decomp-toolkit"
|
||||||
description = "GameCube/Wii decompilation project tools."
|
description = "Yet another GameCube/Wii decompilation toolkit."
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -23,7 +23,7 @@ strip = "debuginfo"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { version = "1.0.71", features = ["backtrace"] }
|
anyhow = { version = "1.0.71", features = ["backtrace"] }
|
||||||
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "write_symbol_table" }
|
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "write_symbol_table" }
|
||||||
argh = "0.1.10"
|
argp = "0.3.0"
|
||||||
base16ct = "0.2.0"
|
base16ct = "0.2.0"
|
||||||
base64 = "0.21.2"
|
base64 = "0.21.2"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
@ -45,6 +45,7 @@ multimap = "0.9.0"
|
|||||||
num_enum = "0.6.1"
|
num_enum = "0.6.1"
|
||||||
object = { version = "0.31.1", features = ["read_core", "std", "elf", "write_std"], default-features = false }
|
object = { version = "0.31.1", features = ["read_core", "std", "elf", "write_std"], default-features = false }
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.18.0"
|
||||||
|
petgraph = "0.6.3"
|
||||||
ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "5f6e991bf495388c4104f188d2e90c79da9f78de" }
|
ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "5f6e991bf495388c4104f188d2e90c79da9f78de" }
|
||||||
regex = "1.9.0"
|
regex = "1.9.0"
|
||||||
serde = "1.0.166"
|
serde = "1.0.166"
|
||||||
@ -52,8 +53,6 @@ serde_repr = "0.1.14"
|
|||||||
serde_yaml = "0.9.22"
|
serde_yaml = "0.9.22"
|
||||||
sha-1 = "0.10.1"
|
sha-1 = "0.10.1"
|
||||||
smallvec = "1.11.0"
|
smallvec = "1.11.0"
|
||||||
topological-sort = "0.2.2"
|
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
anyhow = { version = "1.0.71", features = ["backtrace"] }
|
anyhow = { version = "1.0.71", features = ["backtrace"] }
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
// 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!("CARGO_PKG_VERSION"),
|
|
||||||
env!("GIT_COMMIT_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!(
|
|
||||||
"{help} -V, --version print version information and exit"
|
|
||||||
),
|
|
||||||
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
|
|
||||||
}
|
|
61
src/argp_version.rs
Normal file
61
src/argp_version.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Originally from https://gist.github.com/suluke/e0c672492126be0a4f3b4f0e1115d77c
|
||||||
|
//! Extend `argp` to be better integrated with the `cargo` ecosystem
|
||||||
|
//!
|
||||||
|
//! For now, this only adds a --version/-V option which causes early-exit.
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
|
use argp::{parser::ParseGlobalOptions, EarlyExit, 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: &[&OsStr],
|
||||||
|
parent: Option<&mut dyn ParseGlobalOptions>,
|
||||||
|
) -> Result<Self, EarlyExit> {
|
||||||
|
/// Also use argp for catching `--version`-only invocations
|
||||||
|
#[derive(FromArgs)]
|
||||||
|
struct Version {
|
||||||
|
/// Print version information and exit.
|
||||||
|
#[argp(switch, short = 'V')]
|
||||||
|
pub version: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
match Version::from_args(command_name, args) {
|
||||||
|
Ok(v) => {
|
||||||
|
if v.version {
|
||||||
|
println!(
|
||||||
|
"{} {} {}",
|
||||||
|
command_name.first().unwrap_or(&""),
|
||||||
|
env!("CARGO_PKG_VERSION"),
|
||||||
|
env!("GIT_COMMIT_SHA"),
|
||||||
|
);
|
||||||
|
std::process::exit(0);
|
||||||
|
} else {
|
||||||
|
// Pass through empty arguments
|
||||||
|
T::_from_args(command_name, args, parent).map(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(exit) => match exit {
|
||||||
|
EarlyExit::Help(_help) => {
|
||||||
|
// TODO: Chain help info from Version
|
||||||
|
// For now, we just put the switch on T as well
|
||||||
|
T::from_args(command_name, &["--help"]).map(Self)
|
||||||
|
}
|
||||||
|
EarlyExit::Err(_) => T::_from_args(command_name, args, parent).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 {
|
||||||
|
argp::parse_args_or_exit::<ArgsOrVersion<T>>(argp::DEFAULT).0
|
||||||
|
}
|
@ -6,33 +6,33 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
use object::{Object, ObjectSymbol, SymbolScope};
|
use object::{Object, ObjectSymbol, SymbolScope};
|
||||||
|
|
||||||
use crate::util::file::{map_file, process_rsp};
|
use crate::util::file::{map_file, process_rsp};
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
/// Commands for processing static libraries.
|
/// Commands for processing static libraries.
|
||||||
#[argh(subcommand, name = "ar")]
|
#[argp(subcommand, name = "ar")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
command: SubCommand,
|
command: SubCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
enum SubCommand {
|
enum SubCommand {
|
||||||
Create(CreateArgs),
|
Create(CreateArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Creates a static library.
|
/// Creates a static library.
|
||||||
#[argh(subcommand, name = "create")]
|
#[argp(subcommand, name = "create")]
|
||||||
pub struct CreateArgs {
|
pub struct CreateArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// output file
|
/// output file
|
||||||
out: PathBuf,
|
out: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// input files
|
/// input files
|
||||||
files: Vec<PathBuf>,
|
files: Vec<PathBuf>,
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
use cwdemangle::{demangle, DemangleOptions};
|
use cwdemangle::{demangle, DemangleOptions};
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Demangle a CodeWarrior C++ symbol.
|
/// Demangle a CodeWarrior C++ symbol.
|
||||||
#[argh(subcommand, name = "demangle")]
|
#[argp(subcommand, name = "demangle")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// symbol to demangle
|
/// symbol to demangle
|
||||||
symbol: String,
|
symbol: String,
|
||||||
#[argh(switch)]
|
#[argp(switch)]
|
||||||
/// disable replacing `(void)` with `()`
|
/// disable replacing `(void)` with `()`
|
||||||
keep_void: bool,
|
keep_void: bool,
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
analysis::{
|
analysis::{
|
||||||
@ -33,14 +33,14 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
/// Commands for processing DOL files.
|
/// Commands for processing DOL files.
|
||||||
#[argh(subcommand, name = "dol")]
|
#[argp(subcommand, name = "dol")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
command: SubCommand,
|
command: SubCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
enum SubCommand {
|
enum SubCommand {
|
||||||
Info(InfoArgs),
|
Info(InfoArgs),
|
||||||
Split(SplitArgs),
|
Split(SplitArgs),
|
||||||
@ -48,30 +48,30 @@ enum SubCommand {
|
|||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Views DOL file information.
|
/// Views DOL file information.
|
||||||
#[argh(subcommand, name = "info")]
|
#[argp(subcommand, name = "info")]
|
||||||
pub struct InfoArgs {
|
pub struct InfoArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// DOL file
|
/// DOL file
|
||||||
dol_file: PathBuf,
|
dol_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Splits a DOL into relocatable objects.
|
/// Splits a DOL into relocatable objects.
|
||||||
#[argh(subcommand, name = "split")]
|
#[argp(subcommand, name = "split")]
|
||||||
pub struct SplitArgs {
|
pub struct SplitArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// input file
|
/// input file
|
||||||
in_file: PathBuf,
|
in_file: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// output directory
|
/// output directory
|
||||||
out_dir: PathBuf,
|
out_dir: PathBuf,
|
||||||
#[argh(option, short = 's')]
|
#[argp(option, short = 's')]
|
||||||
/// path to symbols file
|
/// path to symbols file
|
||||||
symbols_file: Option<PathBuf>,
|
symbols_file: Option<PathBuf>,
|
||||||
#[argh(option, short = 'p')]
|
#[argp(option, short = 'p')]
|
||||||
/// path to splits file
|
/// path to splits file
|
||||||
splits_file: Option<PathBuf>,
|
splits_file: Option<PathBuf>,
|
||||||
#[argh(option, short = 'e')]
|
#[argp(option, short = 'e')]
|
||||||
/// ELF file to validate against (debugging only)
|
/// ELF file to validate against (debugging only)
|
||||||
elf_file: Option<PathBuf>,
|
elf_file: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
use object::{elf, Object, ObjectSection, ObjectSymbol, RelocationKind, RelocationTarget, Section};
|
use object::{elf, Object, ObjectSection, ObjectSymbol, RelocationKind, RelocationTarget, Section};
|
||||||
|
|
||||||
use crate::util::{
|
use crate::util::{
|
||||||
@ -18,28 +18,28 @@ use crate::util::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
/// process DWARF 1.1 information
|
/// Commands for processing DWARF 1.1 information.
|
||||||
#[argh(subcommand, name = "dwarf")]
|
#[argp(subcommand, name = "dwarf")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
command: SubCommand,
|
command: SubCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
enum SubCommand {
|
enum SubCommand {
|
||||||
Dump(DumpArgs),
|
Dump(DumpArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// dumps DWARF 1.1 info from an object or archive
|
/// Dumps DWARF 1.1 info from an object or archive.
|
||||||
#[argh(subcommand, name = "dump")]
|
#[argp(subcommand, name = "dump")]
|
||||||
pub struct DumpArgs {
|
pub struct DumpArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// input object (ELF or archive)
|
/// Input object. (ELF or archive)
|
||||||
in_file: PathBuf,
|
in_file: PathBuf,
|
||||||
#[argh(option, short = 'o')]
|
#[argp(option, short = 'o')]
|
||||||
/// output file (or directory, for archive)
|
/// Output file. (Or directory, for archive)
|
||||||
out: Option<PathBuf>,
|
out: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, ensure, Context, Result};
|
use anyhow::{anyhow, bail, ensure, Context, Result};
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
use object::{
|
use object::{
|
||||||
elf,
|
elf,
|
||||||
write::{Mangling, SectionId, SymbolId},
|
write::{Mangling, SectionId, SymbolId},
|
||||||
@ -31,14 +31,14 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
/// Commands for processing ELF files.
|
/// Commands for processing ELF files.
|
||||||
#[argh(subcommand, name = "elf")]
|
#[argp(subcommand, name = "elf")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
command: SubCommand,
|
command: SubCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
enum SubCommand {
|
enum SubCommand {
|
||||||
Config(ConfigArgs),
|
Config(ConfigArgs),
|
||||||
Disasm(DisasmArgs),
|
Disasm(DisasmArgs),
|
||||||
@ -49,63 +49,63 @@ enum SubCommand {
|
|||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Disassembles an ELF file.
|
/// Disassembles an ELF file.
|
||||||
#[argh(subcommand, name = "disasm")]
|
#[argp(subcommand, name = "disasm")]
|
||||||
pub struct DisasmArgs {
|
pub struct DisasmArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// input file
|
/// input file
|
||||||
elf_file: PathBuf,
|
elf_file: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// output file (.o) or directory (.elf)
|
/// output file (.o) or directory (.elf)
|
||||||
out: PathBuf,
|
out: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Fixes issues with GNU assembler built object files.
|
/// Fixes issues with GNU assembler built object files.
|
||||||
#[argh(subcommand, name = "fixup")]
|
#[argp(subcommand, name = "fixup")]
|
||||||
pub struct FixupArgs {
|
pub struct FixupArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// input file
|
/// input file
|
||||||
in_file: PathBuf,
|
in_file: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// output file
|
/// output file
|
||||||
out_file: PathBuf,
|
out_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Splits an executable ELF into relocatable objects.
|
/// Splits an executable ELF into relocatable objects.
|
||||||
#[argh(subcommand, name = "split")]
|
#[argp(subcommand, name = "split")]
|
||||||
pub struct SplitArgs {
|
pub struct SplitArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// input file
|
/// input file
|
||||||
in_file: PathBuf,
|
in_file: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// output directory
|
/// output directory
|
||||||
out_dir: PathBuf,
|
out_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Generates configuration files from an executable ELF.
|
/// Generates configuration files from an executable ELF.
|
||||||
#[argh(subcommand, name = "config")]
|
#[argp(subcommand, name = "config")]
|
||||||
pub struct ConfigArgs {
|
pub struct ConfigArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// input file
|
/// input file
|
||||||
in_file: PathBuf,
|
in_file: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// output directory
|
/// output directory
|
||||||
out_dir: PathBuf,
|
out_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Builds function signatures from an ELF file.
|
/// Builds function signatures from an ELF file.
|
||||||
#[argh(subcommand, name = "sigs")]
|
#[argp(subcommand, name = "sigs")]
|
||||||
pub struct SignaturesArgs {
|
pub struct SignaturesArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// input file(s)
|
/// input file(s)
|
||||||
files: Vec<PathBuf>,
|
files: Vec<PathBuf>,
|
||||||
#[argh(option, short = 's')]
|
#[argp(option, short = 's')]
|
||||||
/// symbol name
|
/// symbol name
|
||||||
symbol: String,
|
symbol: String,
|
||||||
#[argh(option, short = 'o')]
|
#[argp(option, short = 'o')]
|
||||||
/// output yml
|
/// output yml
|
||||||
out_file: PathBuf,
|
out_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -5,19 +5,19 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, ensure, Context, Result};
|
use anyhow::{anyhow, bail, ensure, Context, Result};
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
use object::{Architecture, Endianness, Object, ObjectKind, ObjectSection, SectionKind};
|
use object::{Architecture, Endianness, Object, ObjectKind, ObjectSection, SectionKind};
|
||||||
|
|
||||||
use crate::util::file::map_file;
|
use crate::util::file::map_file;
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Converts an ELF file to a DOL file.
|
/// Converts an ELF file to a DOL file.
|
||||||
#[argh(subcommand, name = "elf2dol")]
|
#[argp(subcommand, name = "elf2dol")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// path to input ELF
|
/// path to input ELF
|
||||||
elf_file: PathBuf,
|
elf_file: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// path to output DOL
|
/// path to output DOL
|
||||||
dol_file: PathBuf,
|
dol_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
use cwdemangle::{demangle, DemangleOptions};
|
use cwdemangle::{demangle, DemangleOptions};
|
||||||
|
|
||||||
use crate::util::{
|
use crate::util::{
|
||||||
@ -12,14 +12,14 @@ use crate::util::{
|
|||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
/// Commands for processing CodeWarrior maps.
|
/// Commands for processing CodeWarrior maps.
|
||||||
#[argh(subcommand, name = "map")]
|
#[argp(subcommand, name = "map")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
command: SubCommand,
|
command: SubCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
enum SubCommand {
|
enum SubCommand {
|
||||||
Entries(EntriesArgs),
|
Entries(EntriesArgs),
|
||||||
Symbol(SymbolArgs),
|
Symbol(SymbolArgs),
|
||||||
@ -30,51 +30,51 @@ enum SubCommand {
|
|||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Displays all entries for a particular TU.
|
/// Displays all entries for a particular TU.
|
||||||
#[argh(subcommand, name = "entries")]
|
#[argp(subcommand, name = "entries")]
|
||||||
pub struct EntriesArgs {
|
pub struct EntriesArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// path to input map
|
/// path to input map
|
||||||
map_file: PathBuf,
|
map_file: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// TU to display entries for
|
/// TU to display entries for
|
||||||
unit: String,
|
unit: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Displays all references to a symbol.
|
/// Displays all references to a symbol.
|
||||||
#[argh(subcommand, name = "symbol")]
|
#[argp(subcommand, name = "symbol")]
|
||||||
pub struct SymbolArgs {
|
pub struct SymbolArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// path to input map
|
/// path to input map
|
||||||
map_file: PathBuf,
|
map_file: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// symbol to display references for
|
/// symbol to display references for
|
||||||
symbol: String,
|
symbol: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Attempts to resolve global link order.
|
/// Attempts to resolve global link order.
|
||||||
#[argh(subcommand, name = "order")]
|
#[argp(subcommand, name = "order")]
|
||||||
pub struct OrderArgs {
|
pub struct OrderArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// path to input map
|
/// path to input map
|
||||||
map_file: PathBuf,
|
map_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Emits a slices.yml for ppcdis. (WIP)
|
/// Emits a slices.yml for ppcdis. (WIP)
|
||||||
#[argh(subcommand, name = "slices")]
|
#[argp(subcommand, name = "slices")]
|
||||||
pub struct SlicesArgs {
|
pub struct SlicesArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// path to input map
|
/// path to input map
|
||||||
map_file: PathBuf,
|
map_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Emits a symbols.yml for ppcdis. (WIP)
|
/// Emits a symbols.yml for ppcdis. (WIP)
|
||||||
#[argh(subcommand, name = "symbols")]
|
#[argp(subcommand, name = "symbols")]
|
||||||
pub struct SymbolsArgs {
|
pub struct SymbolsArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// path to input map
|
/// path to input map
|
||||||
map_file: PathBuf,
|
map_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::{bail, ensure, Context, Result};
|
use anyhow::{bail, ensure, Context, Result};
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
use memchr::memmem;
|
use memchr::memmem;
|
||||||
use memmap2::MmapOptions;
|
use memmap2::MmapOptions;
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Sets the MetroidBuildInfo tag value in a given binary.
|
/// Sets the MetroidBuildInfo tag value in a given binary.
|
||||||
#[argh(subcommand, name = "metroidbuildinfo")]
|
#[argp(subcommand, name = "metroidbuildinfo")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// path to source binary
|
/// path to source binary
|
||||||
binary: PathBuf,
|
binary: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// path to build info string
|
/// path to build info string
|
||||||
build_info: PathBuf,
|
build_info: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{bail, ensure, Context, Result};
|
use anyhow::{bail, ensure, Context, Result};
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
analysis::{
|
analysis::{
|
||||||
@ -28,14 +28,14 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
/// Commands for processing REL files.
|
/// Commands for processing REL files.
|
||||||
#[argh(subcommand, name = "rel")]
|
#[argp(subcommand, name = "rel")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
command: SubCommand,
|
command: SubCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
enum SubCommand {
|
enum SubCommand {
|
||||||
Info(InfoArgs),
|
Info(InfoArgs),
|
||||||
Merge(MergeArgs),
|
Merge(MergeArgs),
|
||||||
@ -43,24 +43,24 @@ enum SubCommand {
|
|||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Views REL file information.
|
/// Views REL file information.
|
||||||
#[argh(subcommand, name = "info")]
|
#[argp(subcommand, name = "info")]
|
||||||
pub struct InfoArgs {
|
pub struct InfoArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// REL file
|
/// REL file
|
||||||
rel_file: PathBuf,
|
rel_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Merges a DOL + REL(s) into an ELF.
|
/// Merges a DOL + REL(s) into an ELF.
|
||||||
#[argh(subcommand, name = "merge")]
|
#[argp(subcommand, name = "merge")]
|
||||||
pub struct MergeArgs {
|
pub struct MergeArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// DOL file
|
/// DOL file
|
||||||
dol_file: PathBuf,
|
dol_file: PathBuf,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// REL file(s)
|
/// REL file(s)
|
||||||
rel_files: Vec<PathBuf>,
|
rel_files: Vec<PathBuf>,
|
||||||
#[argh(option, short = 'o')]
|
#[argp(option, short = 'o')]
|
||||||
/// output ELF
|
/// output ELF
|
||||||
out_file: PathBuf,
|
out_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
|
|
||||||
use crate::util::rso::process_rso;
|
use crate::util::rso::process_rso;
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
/// Commands for processing RSO files.
|
/// Commands for processing RSO files.
|
||||||
#[argh(subcommand, name = "rso")]
|
#[argp(subcommand, name = "rso")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
command: SubCommand,
|
command: SubCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand)]
|
#[argp(subcommand)]
|
||||||
enum SubCommand {
|
enum SubCommand {
|
||||||
Info(InfoArgs),
|
Info(InfoArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Views RSO file information.
|
/// Views RSO file information.
|
||||||
#[argh(subcommand, name = "info")]
|
#[argp(subcommand, name = "info")]
|
||||||
pub struct InfoArgs {
|
pub struct InfoArgs {
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// RSO file
|
/// RSO file
|
||||||
rso_file: PathBuf,
|
rso_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use argh::FromArgs;
|
use argp::FromArgs;
|
||||||
use filetime::{set_file_mtime, FileTime};
|
use filetime::{set_file_mtime, FileTime};
|
||||||
use sha1::{Digest, Sha1};
|
use sha1::{Digest, Sha1};
|
||||||
|
|
||||||
@ -13,15 +13,15 @@ use crate::util::file::process_rsp;
|
|||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Print or check SHA1 (160-bit) checksums.
|
/// Print or check SHA1 (160-bit) checksums.
|
||||||
#[argh(subcommand, name = "shasum")]
|
#[argp(subcommand, name = "shasum")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argh(switch, short = 'c')]
|
#[argp(switch, short = 'c')]
|
||||||
/// check SHA sums against given list
|
/// check SHA sums against given list
|
||||||
check: bool,
|
check: bool,
|
||||||
#[argh(positional)]
|
#[argp(positional)]
|
||||||
/// path to input file(s)
|
/// path to input file(s)
|
||||||
files: Vec<PathBuf>,
|
files: Vec<PathBuf>,
|
||||||
#[argh(option, short = 'o')]
|
#[argp(option, short = 'o')]
|
||||||
/// touch output file on successful check
|
/// touch output file on successful check
|
||||||
output: Option<PathBuf>,
|
output: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
93
src/main.rs
93
src/main.rs
@ -1,22 +1,76 @@
|
|||||||
use std::io::Write;
|
use std::{ffi::OsStr, io::Write, path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use argh::FromArgs;
|
use argp::{FromArgValue, FromArgs};
|
||||||
|
|
||||||
pub mod analysis;
|
pub mod analysis;
|
||||||
pub mod argh_version;
|
pub mod argp_version;
|
||||||
pub mod cmd;
|
pub mod cmd;
|
||||||
pub mod obj;
|
pub mod obj;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
/// GameCube/Wii decompilation project tools.
|
enum LogLevel {
|
||||||
struct TopLevel {
|
Error,
|
||||||
#[argh(subcommand)]
|
Warn,
|
||||||
command: SubCommand,
|
Info,
|
||||||
|
Debug,
|
||||||
|
Trace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for LogLevel {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(match s {
|
||||||
|
"error" => Self::Error,
|
||||||
|
"warn" => Self::Warn,
|
||||||
|
"info" => Self::Info,
|
||||||
|
"debug" => Self::Debug,
|
||||||
|
"trace" => Self::Trace,
|
||||||
|
_ => return Err(()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for LogLevel {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
LogLevel::Error => "error",
|
||||||
|
LogLevel::Warn => "warn",
|
||||||
|
LogLevel::Info => "info",
|
||||||
|
LogLevel::Debug => "debug",
|
||||||
|
LogLevel::Trace => "trace",
|
||||||
|
}
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromArgValue for LogLevel {
|
||||||
|
fn from_arg_value(value: &OsStr) -> Result<Self, String> {
|
||||||
|
String::from_arg_value(value)
|
||||||
|
.and_then(|s| Self::from_str(&s).map_err(|_| format!("Invalid log level")))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand)]
|
/// Yet another GameCube/Wii decompilation toolkit.
|
||||||
|
struct TopLevel {
|
||||||
|
#[argp(subcommand)]
|
||||||
|
command: SubCommand,
|
||||||
|
#[argp(option, short = 'C')]
|
||||||
|
/// Change working directory.
|
||||||
|
chdir: Option<PathBuf>,
|
||||||
|
#[argp(option, short = 'L', default = "LogLevel::Info")]
|
||||||
|
/// Minimum logging level. (Default: info)
|
||||||
|
/// Possible values: error, warn, info, debug, trace
|
||||||
|
log_level: LogLevel,
|
||||||
|
/// Print version information and exit.
|
||||||
|
#[argp(switch, short = 'V')]
|
||||||
|
version: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
#[argp(subcommand)]
|
||||||
enum SubCommand {
|
enum SubCommand {
|
||||||
Ar(cmd::ar::Args),
|
Ar(cmd::ar::Args),
|
||||||
Demangle(cmd::demangle::Args),
|
Demangle(cmd::demangle::Args),
|
||||||
@ -32,12 +86,21 @@ enum SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info"))
|
let args: TopLevel = argp_version::from_env();
|
||||||
.format(|f, r| writeln!(f, "[{}] {}", r.level(), r.args()))
|
env_logger::Builder::from_env(
|
||||||
.init();
|
env_logger::Env::default().default_filter_or(args.log_level.to_string()),
|
||||||
|
)
|
||||||
|
.format(|f, r| writeln!(f, "[{}] {}", r.level(), r.args()))
|
||||||
|
.init();
|
||||||
|
|
||||||
let args: TopLevel = argh_version::from_env();
|
let mut result = Ok(());
|
||||||
let result = match args.command {
|
if let Some(dir) = &args.chdir {
|
||||||
|
result = std::env::set_current_dir(dir).map_err(|e| {
|
||||||
|
anyhow::Error::new(e)
|
||||||
|
.context(format!("Failed to change working directory to '{}'", dir.display()))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
result = result.and_then(|_| match args.command {
|
||||||
SubCommand::Ar(c_args) => cmd::ar::run(c_args),
|
SubCommand::Ar(c_args) => cmd::ar::run(c_args),
|
||||||
SubCommand::Demangle(c_args) => cmd::demangle::run(c_args),
|
SubCommand::Demangle(c_args) => cmd::demangle::run(c_args),
|
||||||
SubCommand::Dol(c_args) => cmd::dol::run(c_args),
|
SubCommand::Dol(c_args) => cmd::dol::run(c_args),
|
||||||
@ -49,7 +112,7 @@ fn main() {
|
|||||||
SubCommand::Rel(c_args) => cmd::rel::run(c_args),
|
SubCommand::Rel(c_args) => cmd::rel::run(c_args),
|
||||||
SubCommand::Rso(c_args) => cmd::rso::run(c_args),
|
SubCommand::Rso(c_args) => cmd::rso::run(c_args),
|
||||||
SubCommand::Shasum(c_args) => cmd::shasum::run(c_args),
|
SubCommand::Shasum(c_args) => cmd::shasum::run(c_args),
|
||||||
};
|
});
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
eprintln!("Failed: {e:?}");
|
eprintln!("Failed: {e:?}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
|
@ -5,7 +5,7 @@ use std::{
|
|||||||
|
|
||||||
use anyhow::{anyhow, bail, ensure, Result};
|
use anyhow::{anyhow, bail, ensure, Result};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use topological_sort::TopologicalSort;
|
use petgraph::{graph::NodeIndex, Graph};
|
||||||
|
|
||||||
use crate::obj::{
|
use crate::obj::{
|
||||||
ObjArchitecture, ObjInfo, ObjKind, ObjReloc, ObjSection, ObjSectionKind, ObjSplit, ObjSymbol,
|
ObjArchitecture, ObjInfo, ObjKind, ObjReloc, ObjSection, ObjSectionKind, ObjSplit, ObjSymbol,
|
||||||
@ -376,8 +376,23 @@ pub fn update_splits(obj: &mut ObjInfo) -> Result<()> {
|
|||||||
/// There can be ambiguities, but any solution that satisfies the link order
|
/// There can be ambiguities, but any solution that satisfies the link order
|
||||||
/// constraints is considered valid.
|
/// constraints is considered valid.
|
||||||
fn resolve_link_order(obj: &ObjInfo) -> Result<Vec<String>> {
|
fn resolve_link_order(obj: &ObjInfo) -> Result<Vec<String>> {
|
||||||
let mut global_unit_order = Vec::<String>::new();
|
#[allow(dead_code)]
|
||||||
let mut t_sort = TopologicalSort::<String>::new();
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
struct SplitEdge {
|
||||||
|
from: u32,
|
||||||
|
to: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut graph = Graph::<String, SplitEdge>::new();
|
||||||
|
let mut unit_to_index_map = BTreeMap::<String, NodeIndex>::new();
|
||||||
|
for (_, split) in obj.splits_for_range(..) {
|
||||||
|
unit_to_index_map.insert(split.unit.clone(), NodeIndex::new(0));
|
||||||
|
}
|
||||||
|
for (unit, index) in unit_to_index_map.iter_mut() {
|
||||||
|
let new_index = graph.add_node(unit.clone());
|
||||||
|
*index = new_index;
|
||||||
|
}
|
||||||
|
|
||||||
for section in &obj.sections {
|
for section in &obj.sections {
|
||||||
let mut iter = obj
|
let mut iter = obj
|
||||||
.splits_for_range(section.address as u32..(section.address + section.size) as u32)
|
.splits_for_range(section.address as u32..(section.address + section.size) as u32)
|
||||||
@ -387,38 +402,46 @@ fn resolve_link_order(obj: &ObjInfo) -> Result<Vec<String>> {
|
|||||||
let skipped = iter.next();
|
let skipped = iter.next();
|
||||||
log::debug!("Skipping split {:?} (next: {:?})", skipped, iter.peek());
|
log::debug!("Skipping split {:?} (next: {:?})", skipped, iter.peek());
|
||||||
}
|
}
|
||||||
loop {
|
while let (Some((a_addr, a)), Some(&(b_addr, b))) = (iter.next(), iter.peek()) {
|
||||||
match (iter.next(), iter.peek()) {
|
if a.unit != b.unit {
|
||||||
(Some((a_addr, a)), Some((b_addr, b))) => {
|
log::debug!(
|
||||||
if a.unit != b.unit {
|
"Adding dependency {} ({:#010X}) -> {} ({:#010X})",
|
||||||
log::debug!(
|
a.unit,
|
||||||
"Adding dependency {} ({:#010X}) -> {} ({:#010X})",
|
a_addr,
|
||||||
a.unit,
|
b.unit,
|
||||||
a_addr,
|
b_addr
|
||||||
b.unit,
|
);
|
||||||
b_addr
|
let a_index = *unit_to_index_map.get(&a.unit).unwrap();
|
||||||
);
|
let b_index = *unit_to_index_map.get(&b.unit).unwrap();
|
||||||
t_sort.add_dependency(a.unit.clone(), b.unit.clone());
|
graph.add_edge(a_index, b_index, SplitEdge { from: a_addr, to: b_addr });
|
||||||
}
|
|
||||||
}
|
|
||||||
(Some((_, a)), None) => {
|
|
||||||
t_sort.insert(a.unit.clone());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => break,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for unit in &mut t_sort {
|
|
||||||
global_unit_order.push(unit);
|
// use petgraph::{
|
||||||
|
// dot::{Config, Dot},
|
||||||
|
// graph::EdgeReference,
|
||||||
|
// };
|
||||||
|
// let get_edge_attributes = |_, e: EdgeReference<SplitEdge>| {
|
||||||
|
// let &SplitEdge { from, to } = e.weight();
|
||||||
|
// let section_name = &obj.section_at(from).unwrap().name;
|
||||||
|
// format!("label=\"{} {:#010X} -> {:#010X}\"", section_name, from, to)
|
||||||
|
// };
|
||||||
|
// let dot = Dot::with_attr_getters(
|
||||||
|
// &graph,
|
||||||
|
// &[Config::EdgeNoLabel, Config::NodeNoLabel],
|
||||||
|
// &get_edge_attributes,
|
||||||
|
// &|_, (_, s)| format!("label=\"{}\"", s),
|
||||||
|
// );
|
||||||
|
// println!("{:?}", dot);
|
||||||
|
|
||||||
|
match petgraph::algo::toposort(&graph, None) {
|
||||||
|
Ok(vec) => Ok(vec.iter().map(|&idx| graph[idx].clone()).collect_vec()),
|
||||||
|
Err(e) => Err(anyhow!(
|
||||||
|
"Cyclic dependency (involving {}) encountered while resolving link order",
|
||||||
|
graph[e.node_id()]
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
// An incomplete topological sort indicates that a cyclic dependency was encountered.
|
|
||||||
ensure!(t_sort.is_empty(), "Cyclic dependency encountered while resolving link order");
|
|
||||||
// Sanity check, did we get all TUs in the final order?
|
|
||||||
for unit in obj.splits.values().flatten().map(|s| &s.unit) {
|
|
||||||
ensure!(global_unit_order.contains(unit), "Failed to find an order for {unit}");
|
|
||||||
}
|
|
||||||
Ok(global_unit_order)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split an executable object into relocatable objects.
|
/// Split an executable object into relocatable objects.
|
||||||
|
@ -12,7 +12,6 @@ use cwdemangle::{demangle, DemangleOptions};
|
|||||||
use multimap::MultiMap;
|
use multimap::MultiMap;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::{Captures, Regex};
|
use regex::{Captures, Regex};
|
||||||
use topological_sort::TopologicalSort;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
obj::{
|
obj::{
|
||||||
@ -144,43 +143,6 @@ fn resolve_section_order(
|
|||||||
Ok(ordering)
|
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
|
|
||||||
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 = order.clone();
|
|
||||||
if matches!(section.as_str(), ".ctors" | ".dtors" | "extab") {
|
|
||||||
continue;
|
|
||||||
// if 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..].to_vec();
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
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.
|
|
||||||
ensure!(t_sort.is_empty(), "Cyclic dependency encountered while resolving link order");
|
|
||||||
// Sanity check, did we get all TUs in the final order?
|
|
||||||
for (_, order) in section_unit_order {
|
|
||||||
for unit in order {
|
|
||||||
ensure!(global_unit_order.contains(unit), "Failed to find an order for {unit}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(global_unit_order)
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! static_regex {
|
macro_rules! static_regex {
|
||||||
($name:ident, $str:expr) => {
|
($name:ident, $str:expr) => {
|
||||||
static $name: Lazy<Regex> = Lazy::new(|| Regex::new($str).unwrap());
|
static $name: Lazy<Regex> = Lazy::new(|| Regex::new($str).unwrap());
|
||||||
@ -752,7 +714,8 @@ pub fn apply_map(result: &MapInfo, obj: &mut ObjInfo) -> Result<()> {
|
|||||||
section_order.push((section.clone(), units));
|
section_order.push((section.clone(), units));
|
||||||
}
|
}
|
||||||
log::info!("Section order: {:#?}", section_order);
|
log::info!("Section order: {:#?}", section_order);
|
||||||
obj.link_order = resolve_link_order(§ion_order)?;
|
// TODO
|
||||||
|
// obj.link_order = resolve_link_order(§ion_order)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user