From e21d06994f7c750c7fe7448b28408076eb9cf4ce Mon Sep 17 00:00:00 2001 From: Gwilym Inzani <email@gwilym.dev> Date: Wed, 3 Apr 2024 10:57:34 +0100 Subject: [PATCH] Add some tests which showed issues with the decoder --- agb-addr2line/src/gwilym_encoding.rs | 77 +++++++++++++++++++++++++++- agb/src/backtrace.rs | 15 +++--- 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/agb-addr2line/src/gwilym_encoding.rs b/agb-addr2line/src/gwilym_encoding.rs index ae006582..fca9896c 100644 --- a/agb-addr2line/src/gwilym_encoding.rs +++ b/agb-addr2line/src/gwilym_encoding.rs @@ -61,8 +61,11 @@ impl<'a> Iterator for GwilymDecodeIter<'a> { }; let value = decode_chunk(chunk); - if value & (1 << 17) != 0 { - return Some(self.next().unwrap_or(0) | (value << 16)); + if value & (1 << 16) != 0 { + let upper_bits = value << 16; + let lower_bits = self.next().unwrap_or(0) & 0xffff; + + return Some(upper_bits | lower_bits); } Some(value | 0x0800_0000) @@ -89,3 +92,73 @@ fn get_value_for_char(input: u8) -> u32 { result })[input as usize] as u32 } + +#[cfg(test)] +mod test { + use super::{gwilym_decode, ALPHABET}; + use std::fmt::Write; + + #[test] + fn should_correctly_decode_16s() -> anyhow::Result<()> { + assert_eq!( + &gwilym_decode("2QI65Q69306Kv1")?.collect::<Vec<_>>(), + &[0x0800_16d3, 0x0800_315b, 0x0800_3243, 0x0800_0195] + ); + + Ok(()) + } + + fn encode_16(input: u16) -> [u8; 3] { + let input = input as usize; + [ + ALPHABET[input >> (16 - 5)], + ALPHABET[(input >> (16 - 10)) & 0b11111], + ALPHABET[input & 0b111111], + ] + } + + fn encode_32(input: u32) -> [u8; 6] { + let input = input as usize; + let output_lower_16 = encode_16(input as u16); + let input_upper_16 = input >> 16; + [ + ALPHABET[(input_upper_16 >> (16 - 5)) | (1 << 5)], + ALPHABET[(input_upper_16 >> (16 - 10)) & 0b11111], + ALPHABET[input_upper_16 & 0b111111], + output_lower_16[0], + output_lower_16[1], + output_lower_16[2], + ] + } + + #[test] + fn should_correctly_decode_16s_and_32s() -> anyhow::Result<()> { + let trace: &[u32] = &[ + 0x0300_2990, + 0x0800_3289, + 0x0500_2993, + 0x3829_2910, + 0xffff_ffff, + 0x0000_0000, + ]; + + let mut result = String::new(); + for &ip in trace { + if ip & 0xFFFF_0000 == 0x0800_0000 { + let encoded = encode_16(ip as u16); + let encoded_s = std::str::from_utf8(&encoded)?; + write!(&mut result, "{encoded_s}")? + } else { + let encoded = encode_32(ip); + let encoded_s = std::str::from_utf8(&encoded)?; + write!(&mut result, "{encoded_s}")? + } + } + + write!(&mut result, "v1")?; + + assert_eq!(&gwilym_decode(&result)?.collect::<Vec<_>>(), trace); + + Ok(()) + } +} diff --git a/agb/src/backtrace.rs b/agb/src/backtrace.rs index 1e3ea241..f65e55e6 100644 --- a/agb/src/backtrace.rs +++ b/agb/src/backtrace.rs @@ -120,14 +120,15 @@ mod gwilym_encoding { pub fn encode_32(input: u32) -> [u8; 6] { let input = input as usize; - let output_16 = encode_16(input as u16); + let output_lower_16 = encode_16(input as u16); + let input_upper_16 = input >> 16; [ - ALPHABET[(input >> (32 - 5)) | 0b100000], - ALPHABET[(input >> (32 - 10)) & 0b11111], - ALPHABET[(input >> (32 - 16)) & 0b111111], - output_16[0], - output_16[1], - output_16[2], + ALPHABET[(input_upper_16 >> (16 - 5)) | (1 << 5)], + ALPHABET[(input_upper_16 >> (16 - 10)) & 0b11111], + ALPHABET[input_upper_16 & 0b111111], + output_lower_16[0], + output_lower_16[1], + output_lower_16[2], ] } }