diff --git a/agb-gbafix/Cargo.lock b/agb-gbafix/Cargo.lock index aa5da1ab..74b92ff4 100644 --- a/agb-gbafix/Cargo.lock +++ b/agb-gbafix/Cargo.lock @@ -9,6 +9,7 @@ dependencies = [ "anyhow", "clap", "elf", + "rmp-serde", ] [[package]] @@ -65,6 +66,18 @@ version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "clap" version = "4.5.3" @@ -104,12 +117,104 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rmp" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "strsim" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +[[package]] +name = "syn" +version = "2.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + [[package]] name = "utf8parse" version = "0.2.1" diff --git a/agb-gbafix/Cargo.toml b/agb-gbafix/Cargo.toml index c27d2b7b..153466f3 100644 --- a/agb-gbafix/Cargo.toml +++ b/agb-gbafix/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/agbrs/agb" elf = "0.7" anyhow = "1" clap = "4" +rmp-serde = "1" [profile.dev] opt-level = 3 diff --git a/agb-gbafix/src/lib.rs b/agb-gbafix/src/lib.rs index 36b0389f..ed86b1db 100644 --- a/agb-gbafix/src/lib.rs +++ b/agb-gbafix/src/lib.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, bail, ensure, Result}; -use std::io::Write; +use std::{collections::HashMap, io::Write}; const GBA_HEADER_SIZE: usize = 192; @@ -71,6 +71,7 @@ pub fn write_gba_file( input: &[u8], mut header: GbaHeader, padding_behaviour: PaddingBehaviour, + include_debug: bool, output: &mut W, ) -> Result<()> { let elf_file = elf::ElfBytes::::minimal_parse(input)?; @@ -80,7 +81,7 @@ pub fn write_gba_file( .ok_or_else(|| anyhow!("Failed to parse as elf file"))?; let mut bytes_written = 0; - for section_header in section_headers.iter() { + for section_header in section_headers { const SHT_NOBITS: u32 = 8; const SHT_NULL: u32 = 0; const SHF_ALLOC: u64 = 2; @@ -123,6 +124,10 @@ pub fn write_gba_file( bytes_written += data.len() as u64; } + if include_debug { + bytes_written += write_debug(&elf_file, output)?; + } + if !bytes_written.is_power_of_two() && padding_behaviour == PaddingBehaviour::Pad { let required_padding = bytes_written.next_power_of_two() - bytes_written; @@ -133,3 +138,38 @@ pub fn write_gba_file( Ok(()) } + +fn write_debug( + elf_file: &elf::ElfBytes<'_, elf::endian::AnyEndian>, + output: &mut W, +) -> Result { + let (Some(section_headers), Some(string_table)) = elf_file.section_headers_with_strtab()? + else { + bail!("Could not find either the section headers or the string table"); + }; + + let mut debug_sections = HashMap::new(); + + for section_header in section_headers { + let section_name = string_table.get(section_header.sh_name as usize)?; + if !section_name.starts_with(".debug") { + continue; + } + + let (data, compression) = elf_file.section_data(§ion_header)?; + if compression.is_some() { + bail!("Do not support compression in elf files, section {section_name} was compressed"); + } + + debug_sections.insert(section_name.to_owned(), data); + } + + let mut debug_data = vec![]; + rmp_serde::encode::write(&mut debug_data, &debug_sections)?; + + output.write_all(&debug_data)?; + output.write_all(&(debug_data.len() as u32).to_le_bytes())?; + output.write_all(&(1u32).to_le_bytes())?; + + Ok(debug_data.len() as u64 + 4) +} diff --git a/agb-gbafix/src/main.rs b/agb-gbafix/src/main.rs index 3ae0f25c..8b2db41d 100644 --- a/agb-gbafix/src/main.rs +++ b/agb-gbafix/src/main.rs @@ -19,6 +19,7 @@ fn main() -> Result<()> { .arg(arg!(-m --makercode "Set the maker code, 2 bytes")) .arg(arg!(-r --gameversion "Set the version of the game, 0-255").value_parser(value_parser!(u8))) .arg(arg!(-p --padding "Pad the ROM to the next power of 2 in size")) + .arg(arg!(-g --debug "Include debug information directly in the ROM")) .get_matches(); let input = matches.get_one::("INPUT").unwrap(); @@ -70,6 +71,8 @@ fn main() -> Result<()> { } } + let include_debug = matches.get_flag("debug"); + let pad = matches.get_flag("padding"); let pad = if pad { PaddingBehaviour::Pad @@ -80,7 +83,13 @@ fn main() -> Result<()> { let mut output = BufWriter::new(fs::File::create(output)?); let file_data = fs::read(input)?; - write_gba_file(file_data.as_slice(), header, pad, &mut output)?; + write_gba_file( + file_data.as_slice(), + header, + pad, + include_debug, + &mut output, + )?; output.flush()?;