Skip to content

Add data info for superh #198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 7, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 148 additions & 1 deletion objdiff-core/src/arch/superh/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use alloc::{string::String, vec::Vec};
use std::collections::HashMap;

use anyhow::{Result, bail};
use object::elf;
@@ -20,6 +21,11 @@ impl ArchSuperH {
pub fn new(_file: &object::File) -> Result<Self> { Ok(Self {}) }
}

struct DataInfo {
address: u64,
size: u32,
}

impl Arch for ArchSuperH {
fn scan_instructions(
&self,
@@ -31,6 +37,7 @@ impl Arch for ArchSuperH {
) -> Result<Vec<ScannedInstruction>> {
let mut ops = Vec::<ScannedInstruction>::with_capacity(code.len() / 2);
let mut offset = address;

for chunk in code.chunks_exact(2) {
let opcode = u16::from_be_bytes(chunk.try_into().unwrap());
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 mut parts: Vec<InstructionPart> = vec![];
let mut branch_dest: Option<u64> = None;

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 {
cb(part)?;
}
@@ -153,7 +212,7 @@ mod test {
use std::fmt::{self, Display};

use super::*;
use crate::obj::InstructionArg;
use crate::obj::{InstructionArg, Section, SectionData, Symbol};

impl Display for InstructionPart<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -634,4 +693,92 @@ mod test {
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());
}
}
}
5 changes: 5 additions & 0 deletions objdiff-core/src/obj/mod.rs
Original file line number Diff line number Diff line change
@@ -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.
pub fn combined_alignment(&self) -> u64 {
const MIN_ALIGNMENT: u64 = 4;