From 219fc1e0bc446c1bf4c9c18a9d4a605b7e4adfc4 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Wed, 3 Apr 2024 10:35:05 +0100 Subject: [PATCH] Extract gwilym_encoding into its own file --- agb-addr2line/src/gwilym_encoding.rs | 91 ++++++++++++++++++++++++++++ agb-addr2line/src/main.rs | 81 +------------------------ 2 files changed, 94 insertions(+), 78 deletions(-) create mode 100644 agb-addr2line/src/gwilym_encoding.rs diff --git a/agb-addr2line/src/gwilym_encoding.rs b/agb-addr2line/src/gwilym_encoding.rs new file mode 100644 index 00000000..ae006582 --- /dev/null +++ b/agb-addr2line/src/gwilym_encoding.rs @@ -0,0 +1,91 @@ +use std::{slice::ChunksExact, sync::OnceLock}; + +const ALPHABET: &[u8] = b"0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; + +// pub fn encode_16(input: u16) -> [u8; 3] { +// let input = input as usize; +// [ +// ALPHABET[input >> (16 - 5)], +// ALPHABET[(input >> (16 - 10)) & 0b11111], +// ALPHABET[input & 0b111111], +// ] +// } + +// pub fn encode_32(input: u32) -> [u8; 6] { +// let input = input as usize; +// let output_16 = encode_16(input as u16); +// [ +// ALPHABET[(input >> (32 - 5)) | 0b100000], +// ALPHABET[(input >> (32 - 10)) & 0b11111], +// ALPHABET[(input >> (32 - 16)) & 0b111111], +// output_16[0], +// output_16[1], +// output_16[2], +// ] +// } + +pub fn gwilym_decode(input: &str) -> anyhow::Result> { + GwilymDecodeIter::new(input) +} + +pub struct GwilymDecodeIter<'a> { + chunks: ChunksExact<'a, u8>, +} + +impl<'a> GwilymDecodeIter<'a> { + fn new(input: &'a str) -> anyhow::Result { + let Some((input, version)) = input.rsplit_once('v') else { + anyhow::bail!("Does not contain version"); + }; + + if version != "1" { + anyhow::bail!("Only version 1 is supported"); + } + + if input.len() % 3 != 0 { + anyhow::bail!("Input string must have length a multiple of 3"); + } + + Ok(Self { + chunks: input.as_bytes().chunks_exact(3), + }) + } +} + +impl<'a> Iterator for GwilymDecodeIter<'a> { + type Item = u32; + + fn next(&mut self) -> Option { + let Some(chunk) = self.chunks.next() else { + return None; + }; + + let value = decode_chunk(chunk); + if value & (1 << 17) != 0 { + return Some(self.next().unwrap_or(0) | (value << 16)); + } + + Some(value | 0x0800_0000) + } +} + +fn decode_chunk(chunk: &[u8]) -> u32 { + let a = get_value_for_char(chunk[0]); + let b = get_value_for_char(chunk[1]); + let c = get_value_for_char(chunk[2]); + + (a << (16 - 5)) | (b << (16 - 10)) | c +} + +fn get_value_for_char(input: u8) -> u32 { + static REVERSE_ALHPABET: OnceLock<[u8; 128]> = OnceLock::new(); + + REVERSE_ALHPABET.get_or_init(|| { + let mut result = [0; 128]; + for (i, &c) in ALPHABET.iter().enumerate() { + result[c as usize] = i as u8; + } + + result + })[input as usize] as u32 +} diff --git a/agb-addr2line/src/main.rs b/agb-addr2line/src/main.rs index cd667cf0..35f5bc3b 100644 --- a/agb-addr2line/src/main.rs +++ b/agb-addr2line/src/main.rs @@ -10,6 +10,8 @@ use addr2line::{gimli, object}; use clap::Parser; use colored::Colorize; +mod gwilym_encoding; + #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { @@ -48,7 +50,7 @@ fn main() -> anyhow::Result<()> { let ctx = addr2line::Context::new(&object)?; - for (i, address) in gwilym_encoding::decode(&cli.dump)?.into_iter().enumerate() { + for (i, address) in gwilym_encoding::gwilym_decode(&cli.dump)?.enumerate() { print_address(&ctx, i, address.into(), modification_time)?; } @@ -179,80 +181,3 @@ fn is_interesting_function(function_name: &str, path: &str) -> bool { true } - -mod gwilym_encoding { - use std::sync::OnceLock; - - const ALPHABET: &[u8] = b"0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; - - // pub fn encode_16(input: u16) -> [u8; 3] { - // let input = input as usize; - // [ - // ALPHABET[input >> (16 - 5)], - // ALPHABET[(input >> (16 - 10)) & 0b11111], - // ALPHABET[input & 0b111111], - // ] - // } - - // pub fn encode_32(input: u32) -> [u8; 6] { - // let input = input as usize; - // let output_16 = encode_16(input as u16); - // [ - // ALPHABET[(input >> (32 - 5)) | 0b100000], - // ALPHABET[(input >> (32 - 10)) & 0b11111], - // ALPHABET[(input >> (32 - 16)) & 0b111111], - // output_16[0], - // output_16[1], - // output_16[2], - // ] - // } - - pub fn decode(input: &str) -> anyhow::Result> { - let Some((input, version)) = input.rsplit_once('v') else { - anyhow::bail!("Does not contain version"); - }; - - if version != "1" { - anyhow::bail!("Only version 1 is supported"); - } - - let mut result = vec![]; - - let mut previous_value = None; - for chunk in input.as_bytes().chunks_exact(3) { - let value = decode_chunk(chunk); - - if value & (1 << 17) != 0 { - previous_value = Some(value << 16); - } else if let Some(upper_bits) = previous_value { - result.push(upper_bits | value); - previous_value = None; - } else { - result.push(value | 0x0800_0000); - } - } - - Ok(result) - } - - fn decode_chunk(chunk: &[u8]) -> u32 { - let a = get_value_for_char(chunk[0]); - let b = get_value_for_char(chunk[1]); - let c = get_value_for_char(chunk[2]); - - (a << (16 - 5)) | (b << (16 - 10)) | c - } - - fn get_value_for_char(input: u8) -> u32 { - static REVERSE_ALHPABET: OnceLock<[u8; 128]> = OnceLock::new(); - - REVERSE_ALHPABET.get_or_init(|| { - let mut result = [0; 128]; - for (i, &c) in ALPHABET.iter().enumerate() { - result[c as usize] = i as u8; - } - - result - })[input as usize] as u32 - } -}