Initial Commit
This commit is contained in:
parent
a05c5b18b8
commit
d765c01039
18 changed files with 1001 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/target
|
||||||
|
/bin
|
||||||
|
/build.ninja
|
||||||
|
/build
|
||||||
|
.ninja_log
|
281
Cargo.lock
generated
Normal file
281
Cargo.lock
generated
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486"
|
||||||
|
|
||||||
|
[[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 = "bitflags"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "2.33.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
|
"atty",
|
||||||
|
"bitflags",
|
||||||
|
"strsim",
|
||||||
|
"textwrap",
|
||||||
|
"unicode-width",
|
||||||
|
"vec_map",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv"
|
||||||
|
version = "1.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
|
||||||
|
dependencies = [
|
||||||
|
"bstr",
|
||||||
|
"csv-core",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv-core"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "donut-decomp"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"clap",
|
||||||
|
"csv",
|
||||||
|
"goblin",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "goblin"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b1800b95efee8ad4ef04517d4d69f8e209e763b1668f1179aeeedd0e454da55"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"plain",
|
||||||
|
"scroll",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||||
|
|
||||||
|
[[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.98"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plain"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scroll"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec"
|
||||||
|
dependencies = [
|
||||||
|
"scroll_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scroll_derive"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.127"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.74"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "donut-decomp"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
default-run = "buildgen"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.42"
|
||||||
|
goblin = "0.4.2"
|
||||||
|
clap = "2.33.3"
|
||||||
|
csv = "1.1.6"
|
15
README.md
Normal file
15
README.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# Kirby's 20th Anniversary Special Edition Decompilation Project
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- Rust
|
||||||
|
- Ninja
|
||||||
|
- On Linux: Wine with 32 bit support
|
||||||
|
- On Macos: Docker
|
||||||
|
- llvm (any recent version)
|
||||||
|
- donut.dol from the NTSC version (sha256 92a9f3662d85e440f2c0d6ea0d30ead1e7bf0eb51be279320b5e9aac6e5216e5), placed in bin/donut/donut.dol
|
||||||
|
- donut.MAP from the NTSC version (sha256 d26fab6e6a58d3dd5abc0c2ba1b745c1095d4b2887b44b3ea7128258a0ec8666), placed in bin/donut/donut.MAP
|
||||||
|
- The following files from "CW for Wii v1.7": license.dat, mwasmeppc.exe, mwcceppc.exe, mwldeppc.exe, all placed in bin/mwcc
|
||||||
|
- The following file from the misc directory: lmgr8c.dll
|
||||||
|
|
||||||
|
## Building
|
||||||
|
You can build by running `cargo run` in the root directory.
|
13
data/objects.txt
Normal file
13
data/objects.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
./build/obj/init_80004000_80006728.o
|
||||||
|
./build/obj/extab_80006740_800068cc.o
|
||||||
|
./build/obj/extabindex_800068e0_800069e4.o
|
||||||
|
./build/obj/text_80006a00_80406244.o
|
||||||
|
./build/obj/ctors_80406260_80406530.o
|
||||||
|
./build/obj/dtors_80406540_8040654c.o
|
||||||
|
./build/obj/rodata_80406560_80421030.o
|
||||||
|
./build/obj/data_80421040_804966fc.o
|
||||||
|
./build/obj/bss_80496700_8055640c.o
|
||||||
|
./build/obj/sdata_80556420_8055c6d0.o
|
||||||
|
./build/obj/sbss_8055c6e0_8055df74.o
|
||||||
|
./build/obj/sdata2_8055df80_805643b0.o
|
||||||
|
./build/obj/sbss2_805643c0_805643fc.o
|
1
data/ranges.csv
Normal file
1
data/ranges.csv
Normal file
|
@ -0,0 +1 @@
|
||||||
|
StartAddress,EndAddress,Section,File,function
|
|
2
data/symbols.csv
Normal file
2
data/symbols.csv
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Address,SymbolName
|
||||||
|
80006310,__start
|
|
BIN
misc/lmgr8c.dll
Executable file
BIN
misc/lmgr8c.dll
Executable file
Binary file not shown.
7
misc/lmgr8c.dll.c
Normal file
7
misc/lmgr8c.dll.c
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// Implmeentation of lmgr8c which hopefully is enough to run mw(asm|cc|ld)eppc
|
||||||
|
|
||||||
|
__declspec(dllexport) void __cdecl lp_checkin(void) {}
|
||||||
|
__declspec(dllexport) int __cdecl lp_checkout(void) { return 0; }
|
||||||
|
__declspec(dllexport) const char *__cdecl lp_errstring(void) {
|
||||||
|
return "no error";
|
||||||
|
}
|
5
misc/lmgr8c.dll.def
Normal file
5
misc/lmgr8c.dll.def
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
LIBRARY lmgr8c
|
||||||
|
EXPORTS
|
||||||
|
lp_checkin @ 189
|
||||||
|
lp_checkout @ 190
|
||||||
|
lp_errstring @ 191
|
12
rules.ninja
Normal file
12
rules.ninja
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
rule extract-object
|
||||||
|
command = cargo run --quiet --release --bin extract-dol -- $in $out $start $end
|
||||||
|
|
||||||
|
rule directory
|
||||||
|
command = mkdir $out
|
||||||
|
|
||||||
|
rule genlcf
|
||||||
|
command = cargo run --quiet --release --bin genlcf -- $out
|
||||||
|
|
||||||
|
rule ccld
|
||||||
|
command = ./run-exe.sh bin/mwcc/mwldeppc.exe $in -o $out -lcf $lcf -fp hard -linkmode moreram -map $map
|
||||||
|
|
14
run-exe.sh
Executable file
14
run-exe.sh
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
#if [[ $(uname -m) != 'x86_64' ]]; then
|
||||||
|
# echo "Can currently only run on x86_64"
|
||||||
|
# exit 1
|
||||||
|
#fi
|
||||||
|
|
||||||
|
#if [[ $OSTYPE == 'darwin' ]]; then
|
||||||
|
# docker run -it --rm --volume $PWD/build/wine:/home/wineuser/.wine --volume $PWD:$PWD -w $PWD scottyhardy/docker-wine wine "$@"
|
||||||
|
#else
|
||||||
|
wine "$@"
|
||||||
|
#fi
|
72
src/bin/buildgen.rs
Normal file
72
src/bin/buildgen.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{BufReader, BufWriter, Write},
|
||||||
|
num::ParseIntError,
|
||||||
|
process::Command,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use donut_decomp::{dol::Dol, range::Ranges};
|
||||||
|
|
||||||
|
fn parse_hex(s: &str) -> Result<u32, ParseIntError> {
|
||||||
|
u32::from_str_radix(s.trim_start_matches("0x"), 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let mut ninja = donut_decomp::ninja::NinjaFile::new("build.ninja")?;
|
||||||
|
let mut ranges = Ranges::new();
|
||||||
|
let dolfile = Dol::new(BufReader::new(File::open("bin/donut/donut.dol")?))?;
|
||||||
|
ranges
|
||||||
|
.add_range(0x80004000, 0x80006728)
|
||||||
|
.add_range(0x80006740, 0x800068cc)
|
||||||
|
.add_range(0x800068e0, 0x800069e4)
|
||||||
|
.add_range(0x80006a00, 0x80406244)
|
||||||
|
.add_range(0x80406260, 0x80406530)
|
||||||
|
.add_range(0x80406540, 0x8040654c)
|
||||||
|
.add_range(0x80406560, 0x80421030)
|
||||||
|
.add_range(0x80421040, 0x804966fc)
|
||||||
|
.add_range(0x80496700, 0x8055640c)
|
||||||
|
.add_range(0x80556420, 0x8055c6d0)
|
||||||
|
.add_range(0x8055c6e0, 0x8055df74)
|
||||||
|
.add_range(0x8055df80, 0x805643b0)
|
||||||
|
.add_range(0x805643c0, 0x805643fc);
|
||||||
|
|
||||||
|
let mut rdr = csv::Reader::from_reader(BufReader::new(File::open("data/ranges.csv")?));
|
||||||
|
|
||||||
|
for result in rdr.records() {
|
||||||
|
let result = result?;
|
||||||
|
ranges.remove_range(
|
||||||
|
parse_hex(result.get(0).unwrap())?,
|
||||||
|
parse_hex(result.get(1).unwrap())?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut objs = vec![];
|
||||||
|
|
||||||
|
for (start, end) in ranges.into_iter() {
|
||||||
|
let objfile = format!(
|
||||||
|
"build/obj/{}_{:08x}_{:08x}.o",
|
||||||
|
dolfile.get_section_name(start),
|
||||||
|
start,
|
||||||
|
end
|
||||||
|
);
|
||||||
|
ninja.emit_extract("bin/donut/donut.dol", &objfile, start, end)?;
|
||||||
|
objs.push(objfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
ninja.emit_genlcf("build/donut.lcf")?;
|
||||||
|
ninja.emit_ccld("build/donut.elf", "build/donut.lcf", &objs)?;
|
||||||
|
|
||||||
|
let mut obj_list = BufWriter::new(File::create("data/objects.txt")?);
|
||||||
|
for obj in objs.iter() {
|
||||||
|
obj_list.write_all(b"./")?;
|
||||||
|
obj_list.write_all(obj.as_bytes())?;
|
||||||
|
obj_list.write_all(b"\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::new("ninja")
|
||||||
|
.arg("build/donut.elf")
|
||||||
|
.spawn()?
|
||||||
|
.wait()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
50
src/bin/extract-dol.rs
Normal file
50
src/bin/extract-dol.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use std::{fs::File, io::BufReader, num::ParseIntError};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use clap::{App, Arg};
|
||||||
|
|
||||||
|
fn parse_hex(s: &str) -> Result<u32, ParseIntError> {
|
||||||
|
u32::from_str_radix(s.trim_start_matches("0x"), 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let matches = App::new("DOL file extractor")
|
||||||
|
.version("0.0")
|
||||||
|
.author("Charlotte D. <darkkirb@darkkirb.de>")
|
||||||
|
.about("Extracts part of a DOL file section")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("INPUT")
|
||||||
|
.help("Input DOL file")
|
||||||
|
.required(true)
|
||||||
|
.index(1),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("OUTPUT")
|
||||||
|
.help("Output ELF file")
|
||||||
|
.required(true)
|
||||||
|
.index(2),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("START_ADDRESS")
|
||||||
|
.help("Start Address")
|
||||||
|
.required(true)
|
||||||
|
.index(3),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("END_ADDRESS")
|
||||||
|
.help("End Address")
|
||||||
|
.required(true)
|
||||||
|
.index(4),
|
||||||
|
)
|
||||||
|
.get_matches();
|
||||||
|
let input = matches.value_of("INPUT").unwrap();
|
||||||
|
let output = matches.value_of("OUTPUT").unwrap();
|
||||||
|
let start_address = parse_hex(matches.value_of("START_ADDRESS").unwrap())?;
|
||||||
|
let end_address = parse_hex(matches.value_of("END_ADDRESS").unwrap())?;
|
||||||
|
donut_decomp::dol::Dol::new(BufReader::new(File::open(input)?))?.extract_from_to(
|
||||||
|
start_address,
|
||||||
|
end_address,
|
||||||
|
output,
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
90
src/bin/genlcf.rs
Normal file
90
src/bin/genlcf.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{BufRead, BufReader, BufWriter, Write},
|
||||||
|
num::ParseIntError,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use clap::{App, Arg};
|
||||||
|
|
||||||
|
fn parse_hex(s: &str) -> Result<u32, ParseIntError> {
|
||||||
|
u32::from_str_radix(s.trim_start_matches("0x"), 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let matches = App::new("LCF generator")
|
||||||
|
.version("0.0")
|
||||||
|
.author("Charlotte D. <darkkirb@darkkirb.de>")
|
||||||
|
.about("Generates an LCF file")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("OUTPUT")
|
||||||
|
.help("Output LCF file")
|
||||||
|
.required(true)
|
||||||
|
.index(1),
|
||||||
|
)
|
||||||
|
.get_matches();
|
||||||
|
let output = matches.value_of("OUTPUT").unwrap();
|
||||||
|
let mut out = BufWriter::new(File::create(output)?);
|
||||||
|
out.write_all(
|
||||||
|
r#"ENTRY(__start)
|
||||||
|
MEMORY {
|
||||||
|
text : origin = 0x80004000
|
||||||
|
// Dummy address
|
||||||
|
binary_blobs : origin = 0xA0000000
|
||||||
|
}
|
||||||
|
SECTIONS {
|
||||||
|
GROUP:{
|
||||||
|
.init ALIGN(0x20):{}
|
||||||
|
extab_ ALIGN(0x20):{}
|
||||||
|
extabindex_ ALIGN(0x20):{}
|
||||||
|
.text ALIGN(0x20):{}
|
||||||
|
.ctors ALIGN(0x20):{}
|
||||||
|
.dtors ALIGN(0x20):{}
|
||||||
|
.rodata ALIGN(0x20):{}
|
||||||
|
.data ALIGN(0x20):{}
|
||||||
|
.bss ALIGN(0x80):{}
|
||||||
|
.sdata ALIGN(0x20):{}
|
||||||
|
.sbss ALIGN(0x20):{}
|
||||||
|
.sdata2 ALIGN(0x20):{}
|
||||||
|
.sbss2 ALIGN(0x20):{}
|
||||||
|
.stack ALIGN(0x100):{}
|
||||||
|
} > text
|
||||||
|
GROUP:{
|
||||||
|
binary_blobs ALIGN(0x20):{}
|
||||||
|
} > binary_blobs
|
||||||
|
|
||||||
|
_stack_addr = (_f_sbss2 + SIZEOF(.sbss2) + 65536 + 0x7) & ~0x7;
|
||||||
|
_stack_end = _f_sbss2 + SIZEOF(.sbss2);
|
||||||
|
_db_stack_addr = (_stack_addr + 0x2000);
|
||||||
|
_db_stack_end = _stack_addr;
|
||||||
|
__ArenaLo = (_db_stack_addr + 0x1f) & ~0x1f;
|
||||||
|
__ArenaHi = 0x81700000;
|
||||||
|
"#
|
||||||
|
.as_bytes(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut rdr = csv::Reader::from_reader(BufReader::new(File::open("data/symbols.csv")?));
|
||||||
|
|
||||||
|
for result in rdr.records() {
|
||||||
|
let result = result?;
|
||||||
|
out.write_all(
|
||||||
|
format!(
|
||||||
|
" {} = 0x{:08x};\n",
|
||||||
|
result.get(1).unwrap(),
|
||||||
|
parse_hex(result.get(0).unwrap())?
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
out.write_all(b"}\n")?;
|
||||||
|
|
||||||
|
let reader = BufReader::new(File::open("data/objects.txt")?);
|
||||||
|
out.write_all(b"FORCEFILES { \n")?;
|
||||||
|
for line in reader.lines() {
|
||||||
|
let line = line?;
|
||||||
|
out.write_all(format!("\"{}\"\n", line).as_bytes())?;
|
||||||
|
}
|
||||||
|
out.write_all(b"}\n")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
222
src/dol/mod.rs
Normal file
222
src/dol/mod.rs
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
//! DOL utilities
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs::{self, File},
|
||||||
|
io::{Read, Seek, SeekFrom, Write},
|
||||||
|
process::Command,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
pub const SECTION_NAMES: &[&str] = &[
|
||||||
|
".init",
|
||||||
|
".text",
|
||||||
|
".text2",
|
||||||
|
".text3",
|
||||||
|
".text4",
|
||||||
|
".text5",
|
||||||
|
".text6",
|
||||||
|
"extab",
|
||||||
|
"extabindex",
|
||||||
|
".ctors",
|
||||||
|
".dtors",
|
||||||
|
".rodata",
|
||||||
|
".data",
|
||||||
|
".sdata",
|
||||||
|
".sdata2",
|
||||||
|
".data8",
|
||||||
|
".data9",
|
||||||
|
".data10",
|
||||||
|
".bss",
|
||||||
|
".sbss",
|
||||||
|
".sbss2",
|
||||||
|
];
|
||||||
|
|
||||||
|
pub const SECTION_BITS: &[&str] = &[
|
||||||
|
"alloc,readonly,load,code",
|
||||||
|
"alloc,readonly,load,code",
|
||||||
|
"alloc,readonly,load,code",
|
||||||
|
"alloc,readonly,load,code",
|
||||||
|
"alloc,readonly,load,code",
|
||||||
|
"alloc,readonly,load,code",
|
||||||
|
"alloc,readonly,load,code",
|
||||||
|
"alloc,readonly,load",
|
||||||
|
"alloc,readonly,load",
|
||||||
|
"alloc,readonly,load",
|
||||||
|
"alloc,readonly,load",
|
||||||
|
"alloc,readonly,load",
|
||||||
|
"alloc,load",
|
||||||
|
"alloc,load",
|
||||||
|
"alloc,load",
|
||||||
|
"alloc,load",
|
||||||
|
"alloc,load",
|
||||||
|
"alloc,load",
|
||||||
|
"alloc",
|
||||||
|
"alloc",
|
||||||
|
"alloc",
|
||||||
|
];
|
||||||
|
|
||||||
|
pub const SECTION_FILE_NAMES: &[&str] = &[
|
||||||
|
"init",
|
||||||
|
"text",
|
||||||
|
"text2",
|
||||||
|
"text3",
|
||||||
|
"text4",
|
||||||
|
"text5",
|
||||||
|
"text6",
|
||||||
|
"extab",
|
||||||
|
"extabindex",
|
||||||
|
"ctors",
|
||||||
|
"dtors",
|
||||||
|
"rodata",
|
||||||
|
"data",
|
||||||
|
"sdata",
|
||||||
|
"sdata2",
|
||||||
|
"data8",
|
||||||
|
"data9",
|
||||||
|
"data10",
|
||||||
|
"bss",
|
||||||
|
"sbss",
|
||||||
|
"sbss2",
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Dol<R: Read + Seek + ?Sized> {
|
||||||
|
file_offsets: [u32; 18],
|
||||||
|
loading_addresses: [u32; 18],
|
||||||
|
section_sizes: [u32; 18],
|
||||||
|
bss_address: u32,
|
||||||
|
bss_size: u32,
|
||||||
|
entry_point: u32,
|
||||||
|
reader: R,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Read + Seek> Dol<R> {
|
||||||
|
pub fn new(mut reader: R) -> Result<Self> {
|
||||||
|
let mut file_offsets: [u32; 18] = [0; 18];
|
||||||
|
let mut loading_addresses: [u32; 18] = [0; 18];
|
||||||
|
let mut section_sizes: [u32; 18] = [0; 18];
|
||||||
|
|
||||||
|
for file_offset in file_offsets.iter_mut() {
|
||||||
|
let mut u32_buf = [0u8; 4];
|
||||||
|
reader.read_exact(&mut u32_buf)?;
|
||||||
|
*file_offset = u32::from_be_bytes(u32_buf);
|
||||||
|
}
|
||||||
|
for loading_address in loading_addresses.iter_mut() {
|
||||||
|
let mut u32_buf = [0u8; 4];
|
||||||
|
reader.read_exact(&mut u32_buf)?;
|
||||||
|
*loading_address = u32::from_be_bytes(u32_buf);
|
||||||
|
}
|
||||||
|
for section_size in section_sizes.iter_mut() {
|
||||||
|
let mut u32_buf = [0u8; 4];
|
||||||
|
reader.read_exact(&mut u32_buf)?;
|
||||||
|
*section_size = u32::from_be_bytes(u32_buf);
|
||||||
|
}
|
||||||
|
let mut u32_buf = [0u8; 4];
|
||||||
|
reader.read_exact(&mut u32_buf)?;
|
||||||
|
let bss_address = u32::from_be_bytes(u32_buf);
|
||||||
|
reader.read_exact(&mut u32_buf)?;
|
||||||
|
let bss_size = u32::from_be_bytes(u32_buf);
|
||||||
|
reader.read_exact(&mut u32_buf)?;
|
||||||
|
let entry_point = u32::from_be_bytes(u32_buf);
|
||||||
|
Ok(Self {
|
||||||
|
file_offsets,
|
||||||
|
loading_addresses,
|
||||||
|
section_sizes,
|
||||||
|
bss_address,
|
||||||
|
bss_size,
|
||||||
|
entry_point,
|
||||||
|
reader,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn is_in_bss(&self, address: u32) -> Option<usize> {
|
||||||
|
if address >= self.loading_addresses[13] + self.section_sizes[13]
|
||||||
|
&& address < self.loading_addresses[14]
|
||||||
|
{
|
||||||
|
return Some(19); // SBSS
|
||||||
|
}
|
||||||
|
if address >= self.loading_addresses[14] + self.section_sizes[14] {
|
||||||
|
return Some(20); // SBSS2
|
||||||
|
}
|
||||||
|
if address >= self.bss_address && address < self.bss_address + self.bss_size {
|
||||||
|
return Some(18);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
pub fn read_va_block(&mut self, address: u32, block: &mut [u8]) -> Result<usize> {
|
||||||
|
for i in 0..18 {
|
||||||
|
if address < self.loading_addresses[i]
|
||||||
|
|| address >= self.loading_addresses[i] + self.section_sizes[i]
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
self.reader.seek(SeekFrom::Start(
|
||||||
|
(self.file_offsets[i] + (address - self.loading_addresses[i])) as u64,
|
||||||
|
))?;
|
||||||
|
self.reader.read_exact(block)?;
|
||||||
|
return Ok(i);
|
||||||
|
}
|
||||||
|
if let Some(v) = self.is_in_bss(address) {
|
||||||
|
for c in block.iter_mut() {
|
||||||
|
*c = 0;
|
||||||
|
}
|
||||||
|
return Ok(v);
|
||||||
|
}
|
||||||
|
anyhow::bail!("Unknown virtual address!");
|
||||||
|
}
|
||||||
|
pub fn extract_range(&mut self, address: u32, size: u32, outname: &str) -> Result<()> {
|
||||||
|
let mut data = vec![0u8; size as usize];
|
||||||
|
let binfile_name = format!("{}.bin", outname);
|
||||||
|
let section = self.read_va_block(address, &mut data)?;
|
||||||
|
{
|
||||||
|
let mut binfile = File::create(&binfile_name)?;
|
||||||
|
binfile.write_all(&data)?;
|
||||||
|
}
|
||||||
|
Command::new("objcopy")
|
||||||
|
.arg("-I")
|
||||||
|
.arg("binary")
|
||||||
|
.arg("-O")
|
||||||
|
.arg("elf32-big")
|
||||||
|
.arg(&binfile_name)
|
||||||
|
.arg(outname)
|
||||||
|
.arg("--rename-section")
|
||||||
|
.arg(format!(
|
||||||
|
".data={},{}",
|
||||||
|
SECTION_NAMES[section], SECTION_BITS[section]
|
||||||
|
))
|
||||||
|
.arg("--change-section-address")
|
||||||
|
.arg(format!(".data={}", address))
|
||||||
|
.arg("--strip-all")
|
||||||
|
.spawn()?
|
||||||
|
.wait()?;
|
||||||
|
fs::remove_file(&binfile_name)?;
|
||||||
|
Command::new("objcopy")
|
||||||
|
.arg("--format")
|
||||||
|
.arg("elf32-big")
|
||||||
|
.arg("--add-symbol")
|
||||||
|
.arg(format!(
|
||||||
|
"_LOC_{:08x}={}:0x{:08x},global",
|
||||||
|
address, SECTION_NAMES[section], address
|
||||||
|
))
|
||||||
|
.arg(outname)
|
||||||
|
.spawn()?
|
||||||
|
.wait()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn extract_from_to(&mut self, start: u32, end: u32, outname: &str) -> Result<()> {
|
||||||
|
self.extract_range(start, end - start, outname)
|
||||||
|
}
|
||||||
|
pub fn get_section_name(&self, addr: u32) -> &str {
|
||||||
|
for i in 0..18 {
|
||||||
|
if addr >= self.loading_addresses[i]
|
||||||
|
&& addr < self.loading_addresses[i] + self.section_sizes[i]
|
||||||
|
{
|
||||||
|
return SECTION_FILE_NAMES[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(section) = self.is_in_bss(addr) {
|
||||||
|
return SECTION_FILE_NAMES[section];
|
||||||
|
}
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
130
src/ninja/mod.rs
Normal file
130
src/ninja/mod.rs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
//! Ninja file generator
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufWriter, Write};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NinjaFile {
|
||||||
|
emitted_targets: HashSet<PathBuf>,
|
||||||
|
writer: BufWriter<File>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NinjaFile {
|
||||||
|
pub fn new(path: impl AsRef<Path>) -> Result<Self> {
|
||||||
|
let mut this = Self {
|
||||||
|
emitted_targets: HashSet::new(),
|
||||||
|
writer: BufWriter::new(File::create(path)?),
|
||||||
|
};
|
||||||
|
this.writer.write_all(b"include rules.ninja\n")?;
|
||||||
|
Ok(this)
|
||||||
|
}
|
||||||
|
pub fn emit_mkdir(&mut self, dir: impl AsRef<Path>) -> Result<()> {
|
||||||
|
let dir = dir.as_ref();
|
||||||
|
if self.emitted_targets.contains(dir) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
self.emitted_targets.insert(dir.to_owned());
|
||||||
|
match dir.parent() {
|
||||||
|
Some(parent) if parent.to_string_lossy() != "" => {
|
||||||
|
self.writer.write_all(
|
||||||
|
format!(
|
||||||
|
"build {}: directory || {}\n",
|
||||||
|
dir.display(),
|
||||||
|
parent.display()
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)?;
|
||||||
|
self.emit_mkdir(parent)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.writer
|
||||||
|
.write_all(format!("build {}: directory\n", dir.display()).as_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn emit_extract(
|
||||||
|
&mut self,
|
||||||
|
dolfile: impl AsRef<Path>,
|
||||||
|
objfile: impl AsRef<Path>,
|
||||||
|
start_addr: u32,
|
||||||
|
end_addr: u32,
|
||||||
|
) -> Result<()> {
|
||||||
|
let dolfile = dolfile.as_ref();
|
||||||
|
let objfile = objfile.as_ref();
|
||||||
|
if self.emitted_targets.contains(objfile) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
self.emitted_targets.insert(objfile.to_owned());
|
||||||
|
let parent = objfile.parent().unwrap();
|
||||||
|
self.writer.write_all(
|
||||||
|
format!(
|
||||||
|
r#"build {}: extract-object {} || {}
|
||||||
|
start = {:08x}
|
||||||
|
end = {:08x}
|
||||||
|
"#,
|
||||||
|
objfile.display(),
|
||||||
|
dolfile.display(),
|
||||||
|
parent.display(),
|
||||||
|
start_addr,
|
||||||
|
end_addr
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)?;
|
||||||
|
self.emit_mkdir(parent)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn emit_genlcf(&mut self, outfile: impl AsRef<Path>) -> Result<()> {
|
||||||
|
let outfile = outfile.as_ref();
|
||||||
|
if self.emitted_targets.contains(outfile) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
self.emitted_targets.insert(outfile.to_owned());
|
||||||
|
let parent = outfile.parent().unwrap();
|
||||||
|
self.writer.write_all(
|
||||||
|
format!(
|
||||||
|
"build {}: genlcf data/symbols.csv || {}\n",
|
||||||
|
outfile.display(),
|
||||||
|
parent.display()
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)?;
|
||||||
|
self.emit_mkdir(parent)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn emit_ccld(
|
||||||
|
&mut self,
|
||||||
|
outfile: impl AsRef<Path>,
|
||||||
|
lcffile: impl AsRef<Path>,
|
||||||
|
objects: &[impl AsRef<Path>],
|
||||||
|
) -> Result<()> {
|
||||||
|
let outfile = outfile.as_ref();
|
||||||
|
let lcffile = lcffile.as_ref();
|
||||||
|
if self.emitted_targets.contains(outfile) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
self.emitted_targets.insert(outfile.to_owned());
|
||||||
|
let parent = outfile.parent().unwrap();
|
||||||
|
self.writer
|
||||||
|
.write_all(format!("build {}: ccld ", outfile.display()).as_bytes())?;
|
||||||
|
for object in objects.iter() {
|
||||||
|
self.writer
|
||||||
|
.write_all(format!("{} ", object.as_ref().display()).as_bytes())?;
|
||||||
|
}
|
||||||
|
self.writer.write_all(
|
||||||
|
format!(
|
||||||
|
"| {} data/objects.txt || {}\n lcf={}\n map=build/donut.map\n",
|
||||||
|
lcffile.display(),
|
||||||
|
parent.display(),
|
||||||
|
lcffile.display()
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)?;
|
||||||
|
self.emit_mkdir(parent)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
69
src/range.rs
Normal file
69
src/range.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Ranges {
|
||||||
|
range_list: BTreeMap<u32, u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ranges {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
range_list: BTreeMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn add_range(&mut self, start: u32, end: u32) -> &mut Self {
|
||||||
|
self.range_list.insert(start, end);
|
||||||
|
self.merge_ranges();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn remove_range(&mut self, start: u32, end: u32) -> &mut Self {
|
||||||
|
let mut range_start = 0;
|
||||||
|
let mut range_end = 0;
|
||||||
|
// Find the range it is part of
|
||||||
|
for (curr_start, curr_end) in self.range_list.iter() {
|
||||||
|
if *curr_start > start || *curr_end < end {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
range_start = *curr_start;
|
||||||
|
range_end = *curr_end;
|
||||||
|
}
|
||||||
|
self.split_range(range_start, start);
|
||||||
|
self.split_range(start, end);
|
||||||
|
self.split_range(end, range_end);
|
||||||
|
self.range_list.remove(&start);
|
||||||
|
self.merge_ranges();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn merge_ranges(&mut self) {
|
||||||
|
let mut last_start = 0;
|
||||||
|
let mut last_end = 0;
|
||||||
|
let mut block_gc_list = vec![];
|
||||||
|
let mut block_updates = BTreeMap::new();
|
||||||
|
for (curr_start, curr_end) in self.range_list.iter() {
|
||||||
|
if *curr_start == *curr_end {
|
||||||
|
block_gc_list.push(*curr_start);
|
||||||
|
} else if *curr_start <= last_end {
|
||||||
|
block_gc_list.push(*curr_start);
|
||||||
|
last_end = *curr_end;
|
||||||
|
block_updates.insert(last_start, last_end);
|
||||||
|
} else {
|
||||||
|
last_start = *curr_start;
|
||||||
|
last_end = *curr_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (block_start, block_end) in block_updates.into_iter() {
|
||||||
|
self.range_list.insert(block_start, block_end);
|
||||||
|
}
|
||||||
|
for block_start in block_gc_list.into_iter() {
|
||||||
|
self.range_list.remove(&block_start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn split_range(&mut self, start: u32, new_end: u32) {
|
||||||
|
let end_addr = self.range_list[&start];
|
||||||
|
self.range_list.insert(start, new_end);
|
||||||
|
self.range_list.insert(new_end, end_addr);
|
||||||
|
}
|
||||||
|
pub fn into_iter(self) -> impl Iterator<Item = (u32, u32)> {
|
||||||
|
self.range_list.into_iter()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue