Add data info for superh (#198)

* Add data info for superh

* fmt

* Fetch symbol data dynamically from resolved.section

* Remove unused var

---------

Co-authored-by: Luke Street <luke@street.dev>
This commit is contained in:
sozud 2025-05-06 21:30:53 -07:00 committed by GitHub
parent a1499f475d
commit 1d782243e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 153 additions and 1 deletions

View File

@ -1,4 +1,5 @@
use alloc::{string::String, vec::Vec}; use alloc::{string::String, vec::Vec};
use std::collections::HashMap;
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use object::elf; use object::elf;
@ -20,6 +21,11 @@ impl ArchSuperH {
pub fn new(_file: &object::File) -> Result<Self> { Ok(Self {}) } pub fn new(_file: &object::File) -> Result<Self> { Ok(Self {}) }
} }
struct DataInfo {
address: u64,
size: u32,
}
impl Arch for ArchSuperH { impl Arch for ArchSuperH {
fn scan_instructions( fn scan_instructions(
&self, &self,
@ -31,6 +37,7 @@ impl Arch for ArchSuperH {
) -> Result<Vec<ScannedInstruction>> { ) -> Result<Vec<ScannedInstruction>> {
let mut ops = Vec::<ScannedInstruction>::with_capacity(code.len() / 2); let mut ops = Vec::<ScannedInstruction>::with_capacity(code.len() / 2);
let mut offset = address; let mut offset = address;
for chunk in code.chunks_exact(2) { for chunk in code.chunks_exact(2) {
let opcode = u16::from_be_bytes(chunk.try_into().unwrap()); let opcode = u16::from_be_bytes(chunk.try_into().unwrap());
let mut parts: Vec<InstructionPart> = vec![]; let mut parts: Vec<InstructionPart> = vec![];
@ -67,8 +74,60 @@ impl Arch for ArchSuperH {
let opcode = u16::from_be_bytes(resolved.code.try_into().unwrap()); let opcode = u16::from_be_bytes(resolved.code.try_into().unwrap());
let mut parts: Vec<InstructionPart> = vec![]; let mut parts: Vec<InstructionPart> = vec![];
let mut branch_dest: Option<u64> = None; let mut branch_dest: Option<u64> = None;
sh2_disasm(0, opcode, true, &mut parts, &resolved, &mut branch_dest); sh2_disasm(0, opcode, true, &mut parts, &resolved, &mut branch_dest);
if let Some(symbol_data) = resolved.section.symbol_data(resolved.symbol) {
// scan for data
// map of instruction offsets to data target offsets
let mut data_offsets: HashMap<u64, DataInfo> = HashMap::<u64, DataInfo>::new();
let mut pos: u64 = 0;
for chunk in symbol_data.chunks_exact(2) {
let opcode = u16::from_be_bytes(chunk.try_into().unwrap());
// mov.w
if (opcode & 0xf000) == 0x9000 {
let target = (opcode as u64 & 0xff) * 2 + 4 + pos;
let data_info = DataInfo { address: target, size: 2 };
data_offsets.insert(pos, data_info);
}
// mov.l
else if (opcode & 0xf000) == 0xd000 {
let target = ((opcode as u64 & 0xff) * 4 + 4 + pos) & 0xfffffffc;
let data_info = DataInfo { address: target, size: 4 };
data_offsets.insert(pos, data_info);
}
pos += 2;
}
let pos = resolved.ins_ref.address - resolved.symbol.address;
// add the data info
if let Some(value) = data_offsets.get(&pos) {
if value.size == 2 && value.address as usize + 1 < symbol_data.len() {
let data = u16::from_be_bytes(
symbol_data[value.address as usize..value.address as usize + 2]
.try_into()
.unwrap(),
);
parts.push(InstructionPart::basic(" /* "));
parts.push(InstructionPart::basic("0x"));
parts.push(InstructionPart::basic(format!("{:04X}", data)));
parts.push(InstructionPart::basic(" */"));
} else if value.size == 4 && value.address as usize + 3 < symbol_data.len() {
let data = u32::from_be_bytes(
symbol_data[value.address as usize..value.address as usize + 4]
.try_into()
.unwrap(),
);
parts.push(InstructionPart::basic(" /* "));
parts.push(InstructionPart::basic("0x"));
parts.push(InstructionPart::basic(format!("{:08X}", data)));
parts.push(InstructionPart::basic(" */"));
}
}
}
for part in parts { for part in parts {
cb(part)?; cb(part)?;
} }
@ -153,7 +212,7 @@ mod test {
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use super::*; use super::*;
use crate::obj::InstructionArg; use crate::obj::{InstructionArg, Section, SectionData, Symbol};
impl Display for InstructionPart<'_> { impl Display for InstructionPart<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -634,4 +693,92 @@ mod test {
assert_eq!(joined_str, expected_str.to_string()); assert_eq!(joined_str, expected_str.to_string());
} }
} }
#[test]
fn test_func_0606_f378_mov_w_data_labeling() {
let arch = ArchSuperH {};
let ops: &[(u16, u32, &str)] = &[(0x9000, 0x0606F378, "mov.w @(0x4, pc), r0 /* 0x00B0 */")];
let mut code = Vec::new();
code.extend_from_slice(&0x9000_u16.to_be_bytes());
code.extend_from_slice(&0x0009_u16.to_be_bytes());
code.extend_from_slice(&0x00B0_u16.to_be_bytes());
for &(opcode, addr, expected_str) in ops {
let mut parts = Vec::new();
arch.display_instruction(
ResolvedInstructionRef {
ins_ref: InstructionRef { address: addr as u64, size: 2, opcode },
code: &opcode.to_be_bytes(),
symbol: &Symbol {
address: 0x0606F378, // func base address
size: code.len() as u64,
..Default::default()
},
section: &Section {
address: 0x0606F378,
size: code.len() as u64,
data: SectionData(code.clone()),
..Default::default()
},
..Default::default()
},
&DiffObjConfig::default(),
&mut |part| {
parts.push(part.into_static());
Ok(())
},
)
.unwrap();
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
assert_eq!(joined_str, expected_str.to_string());
}
}
#[test]
fn test_func_0606_f378_mov_l_data_labeling() {
let arch = ArchSuperH {};
let ops: &[(u16, u32, &str)] =
&[(0xd000, 0x0606F378, "mov.l @(0x4, pc), r0 /* 0x00B000B0 */")];
let mut code = Vec::new();
code.extend_from_slice(&0xd000_u16.to_be_bytes());
code.extend_from_slice(&0x0009_u16.to_be_bytes());
code.extend_from_slice(&0x00B0_u16.to_be_bytes());
code.extend_from_slice(&0x00B0_u16.to_be_bytes());
for &(opcode, addr, expected_str) in ops {
let mut parts = Vec::new();
arch.display_instruction(
ResolvedInstructionRef {
ins_ref: InstructionRef { address: addr as u64, size: 2, opcode },
code: &opcode.to_be_bytes(),
symbol: &Symbol {
address: 0x0606F378, // func base address
size: code.len() as u64,
..Default::default()
},
section: &Section {
address: 0x0606F378,
size: code.len() as u64,
data: SectionData(code.clone()),
..Default::default()
},
..Default::default()
},
&DiffObjConfig::default(),
&mut |part| {
parts.push(part.into_static());
Ok(())
},
)
.unwrap();
let joined_str: String = parts.iter().map(|part| format!("{}", part)).collect();
assert_eq!(joined_str, expected_str.to_string());
}
}
} }

View File

@ -109,6 +109,11 @@ impl Section {
} }
} }
pub fn symbol_data(&self, symbol: &Symbol) -> Option<&[u8]> {
let offset = symbol.address.checked_sub(self.address)?;
self.data.get(offset as usize..offset as usize + symbol.size as usize)
}
// The alignment to use when "Combine data/text sections" is enabled. // The alignment to use when "Combine data/text sections" is enabled.
pub fn combined_alignment(&self) -> u64 { pub fn combined_alignment(&self) -> u64 {
const MIN_ALIGNMENT: u64 = 4; const MIN_ALIGNMENT: u64 = 4;