Skip to content

Commit 504d8bc

Browse files
committed
Guess reloc data type based on the instruction.
Adds an entry to the reloc tooltip to show the inferred data type and value.
1 parent 2379853 commit 504d8bc

File tree

5 files changed

+151
-2
lines changed

5 files changed

+151
-2
lines changed

objdiff-core/src/arch/mod.rs

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use std::{borrow::Cow, collections::BTreeMap};
1+
use std::{borrow::Cow, collections::BTreeMap, ffi::CStr};
22

33
use anyhow::{bail, Result};
4+
use byteorder::ByteOrder;
45
use object::{Architecture, File, Object, ObjectSymbol, Relocation, RelocationFlags, Symbol};
56

67
use crate::{
78
diff::DiffObjConfig,
89
obj::{ObjIns, ObjReloc, ObjSection},
10+
util::ReallySigned,
911
};
1012

1113
#[cfg(feature = "arm")]
@@ -17,6 +19,97 @@ pub mod ppc;
1719
#[cfg(feature = "x86")]
1820
pub mod x86;
1921

22+
/// Represents the type of data associated with an instruction
23+
pub enum DataType {
24+
Int8,
25+
Int16,
26+
Int32,
27+
Int64,
28+
Int128,
29+
Float,
30+
Double,
31+
Bytes,
32+
String,
33+
}
34+
35+
impl DataType {
36+
pub fn display_bytes<Endian: ByteOrder>(&self, bytes: &[u8]) -> Option<String> {
37+
if self.required_len().is_some_and(|l| bytes.len() < l) {
38+
return None;
39+
}
40+
41+
match self {
42+
DataType::Int8 => {
43+
let i = i8::from_ne_bytes(bytes.try_into().unwrap());
44+
if i < 0 {
45+
format!("Int8: {:#x} ({:#x})", i, ReallySigned(i))
46+
} else {
47+
format!("Int8: {:#x}", i)
48+
}
49+
}
50+
DataType::Int16 => {
51+
let i = Endian::read_i16(bytes);
52+
if i < 0 {
53+
format!("Int16: {:#x} ({:#x})", i, ReallySigned(i))
54+
} else {
55+
format!("Int16: {:#x}", i)
56+
}
57+
}
58+
DataType::Int32 => {
59+
let i = Endian::read_i32(bytes);
60+
if i < 0 {
61+
format!("Int32: {:#x} ({:#x})", i, ReallySigned(i))
62+
} else {
63+
format!("Int32: {:#x}", i)
64+
}
65+
}
66+
DataType::Int64 => {
67+
let i = Endian::read_i64(bytes);
68+
if i < 0 {
69+
format!("Int64: {:#x} ({:#x})", i, ReallySigned(i))
70+
} else {
71+
format!("Int64: {:#x}", i)
72+
}
73+
}
74+
DataType::Int128 => {
75+
let i = Endian::read_i128(bytes);
76+
if i < 0 {
77+
format!("Int128: {:#x} ({:#x})", i, ReallySigned(i))
78+
} else {
79+
format!("Int128: {:#x}", i)
80+
}
81+
}
82+
DataType::Float => {
83+
format!("Float: {}", Endian::read_f32(bytes))
84+
}
85+
DataType::Double => {
86+
format!("Double: {}", Endian::read_f64(bytes))
87+
}
88+
DataType::Bytes => {
89+
format!("Bytes: {:#?}", bytes)
90+
}
91+
DataType::String => {
92+
format!("String: {:?}", CStr::from_bytes_until_nul(bytes).ok()?)
93+
}
94+
}
95+
.into()
96+
}
97+
98+
fn required_len(&self) -> Option<usize> {
99+
match self {
100+
DataType::Int8 => Some(1),
101+
DataType::Int16 => Some(2),
102+
DataType::Int32 => Some(4),
103+
DataType::Int64 => Some(8),
104+
DataType::Int128 => Some(16),
105+
DataType::Float => Some(4),
106+
DataType::Double => Some(8),
107+
DataType::Bytes => None,
108+
DataType::String => None,
109+
}
110+
}
111+
}
112+
20113
pub trait ObjArch: Send + Sync {
21114
fn process_code(
22115
&self,
@@ -42,6 +135,12 @@ pub trait ObjArch: Send + Sync {
42135

43136
fn symbol_address(&self, symbol: &Symbol) -> u64 { symbol.address() }
44137

138+
fn guess_data_type(&self, _instruction: &ObjIns) -> Option<DataType> { None }
139+
140+
fn display_data_type(&self, _ty: DataType, bytes: &[u8]) -> Option<String> {
141+
Some(format!("Bytes: {:#x?}", bytes))
142+
}
143+
45144
// Downcast methods
46145
#[cfg(feature = "ppc")]
47146
fn ppc(&self) -> Option<&ppc::ObjArchPpc> { None }

objdiff-core/src/arch/ppc.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{borrow::Cow, collections::BTreeMap};
22

33
use anyhow::{bail, ensure, Result};
4+
use byteorder::BigEndian;
45
use cwextab::{decode_extab, ExceptionTableData};
56
use object::{
67
elf, File, Object, ObjectSection, ObjectSymbol, Relocation, RelocationFlags, RelocationTarget,
@@ -9,7 +10,7 @@ use object::{
910
use ppc750cl::{Argument, InsIter, GPR};
1011

1112
use crate::{
12-
arch::{ObjArch, ProcessCodeResult},
13+
arch::{DataType, ObjArch, ProcessCodeResult},
1314
diff::DiffObjConfig,
1415
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection, ObjSymbol},
1516
};
@@ -186,6 +187,34 @@ impl ObjArch for ObjArchPpc {
186187
}
187188
}
188189

190+
fn guess_data_type(&self, instruction: &ObjIns) -> Option<super::DataType> {
191+
// Always shows the first string of the table. Not ideal, but it's really hard to find
192+
// the actual string being referenced.
193+
if instruction.reloc.as_ref().is_some_and(|r| r.target.name.starts_with("@stringBase")) {
194+
return Some(DataType::String);
195+
}
196+
197+
match instruction.mnemonic.as_str() {
198+
"lbz" | "lbzu" | "lbzux" | "lbzx" => Some(DataType::Int8),
199+
"lhz" | "lhzu" | "lhzux" | "lhzx" => Some(DataType::Int16),
200+
"lha" | "lhau" | "lhaux" | "lhax" => Some(DataType::Int16),
201+
"lwz" | "lwzu" | "lwzux" | "lwzx" => Some(DataType::Int32),
202+
"lfs" | "lfsu" | "lfsux" | "lfsx" => Some(DataType::Float),
203+
"lfd" | "lfdu" | "lfdux" | "lfdx" => Some(DataType::Double),
204+
205+
"stb" | "stbu" | "stbux" | "stbx" => Some(DataType::Int8),
206+
"sth" | "sthu" | "sthux" | "sthx" => Some(DataType::Int16),
207+
"stw" | "stwu" | "stwux" | "stwx" => Some(DataType::Int32),
208+
"stfs" | "stfsu" | "stfsux" | "stfsx" => Some(DataType::Float),
209+
"stfd" | "stfdu" | "stfdux" | "stfdx" => Some(DataType::Double),
210+
_ => None,
211+
}
212+
}
213+
214+
fn display_data_type(&self, ty: DataType, bytes: &[u8]) -> Option<String> {
215+
ty.display_bytes::<BigEndian>(bytes)
216+
}
217+
189218
fn ppc(&self) -> Option<&ObjArchPpc> { Some(self) }
190219
}
191220

objdiff-core/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ pub struct ObjSymbol {
126126
pub virtual_address: Option<u64>,
127127
/// Original index in object symbol table
128128
pub original_index: Option<usize>,
129+
pub bytes: Vec<u8>,
129130
}
130131

131132
pub struct ObjInfo {

objdiff-core/src/obj/read.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ fn to_obj_symbol(
7878
let virtual_address = split_meta
7979
.and_then(|m| m.virtual_addresses.as_ref())
8080
.and_then(|v| v.get(symbol.index().0).cloned());
81+
82+
let bytes = symbol
83+
.section_index()
84+
.and_then(|idx| obj_file.section_by_index(idx).ok())
85+
.and_then(|section| section.data().ok())
86+
.and_then(|data| {
87+
data.get(section_address as usize..(section_address + symbol.size()) as usize)
88+
})
89+
.unwrap_or(&[]);
90+
8191
Ok(ObjSymbol {
8292
name: name.to_string(),
8393
demangled_name,
@@ -89,6 +99,7 @@ fn to_obj_symbol(
8999
addend,
90100
virtual_address,
91101
original_index: Some(symbol.index().0),
102+
bytes: bytes.to_vec(),
92103
})
93104
}
94105

@@ -179,6 +190,7 @@ fn symbols_by_section(
179190
addend: 0,
180191
virtual_address: None,
181192
original_index: None,
193+
bytes: Vec::new(),
182194
});
183195
}
184196
Ok(result)
@@ -239,6 +251,7 @@ fn find_section_symbol(
239251
addend: offset_addr as i64,
240252
virtual_address: None,
241253
original_index: None,
254+
bytes: Vec::new(),
242255
})
243256
}
244257

@@ -521,6 +534,7 @@ fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result<ObjS
521534
None
522535
},
523536
original_index: symbol.original_index,
537+
bytes: symbol.bytes,
524538
})
525539
}
526540

objdiff-gui/src/views/function_diff.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ fn ins_hover_ui(
7979
appearance.highlight_color,
8080
format!("Size: {:x}", reloc.target.size),
8181
);
82+
if let Some(s) = arch
83+
.guess_data_type(&ins)
84+
.and_then(|ty| arch.display_data_type(ty, &reloc.target.bytes))
85+
{
86+
ui.colored_label(appearance.highlight_color, s);
87+
}
8288
} else {
8389
ui.colored_label(appearance.highlight_color, "Extern".to_string());
8490
}

0 commit comments

Comments
 (0)