mirror of
https://github.com/encounter/objdiff.git
synced 2025-06-07 15:13:47 +00:00
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:
parent
a1499f475d
commit
1d782243e0
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user