Skip to content

Commit

Permalink
fix tilib struct alignment padding
Browse files Browse the repository at this point in the history
  • Loading branch information
rbran committed Jan 22, 2025
1 parent 69f2b0c commit ee65c36
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 32 deletions.
30 changes: 21 additions & 9 deletions src/til/size_calculator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ impl<'a> TILTypeSizeSolver<'a> {
self.inner_type_size_bytes(&first.member_type)?
}
};
if !til_struct.is_unaligned {
let align = match (
let align = if !til_struct.is_unaligned {
match (
first_member.alignment.map(|x| x.get().into()),
self.inner_type_align_bytes(
&first_member.member_type,
Expand All @@ -142,14 +142,16 @@ impl<'a> TILTypeSizeSolver<'a> {
(Some(a), Some(b)) => a.max(b),
(Some(a), None) | (None, Some(a)) => a,
(None, None) => align,
};
let align = align.max(1);
let align_diff = sum % align;
if align_diff != 0 {
sum += align - align_diff;
}
}
sum += field_size;
} else {
1
};
// align the current offset
sum = align_mem(sum, align);
// get the type size with padding
let field_size_padded = align_mem(field_size, align);
// add the size to the current offset, and do the next udt member
sum += field_size_padded;
}
sum
}
Expand Down Expand Up @@ -298,3 +300,13 @@ fn condensate_bitfields_from_struct(
}
field_bytes
}

pub fn align_mem(value: u64, align: u64) -> u64 {
let mut result = value;
let align = align.max(1);
let align_diff = result % align;
if align_diff != 0 {
result += align - align_diff;
}
result
}
51 changes: 28 additions & 23 deletions src/tools/tilib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1424,11 +1424,14 @@ fn print_til_type_len(
if let TypeVariant::Function(_function) = &tinfo.type_variant {
write!(fmt, "FFFFFFFF")?;
} else {
// if the type is unknown it just prints "FFFFFFF"
let len = size_solver
.type_size_bytes(idx, tinfo)
.unwrap_or(0xFFFF_FFFF);
write!(fmt, "{len:08X}")?;
let Some(len) = size_solver.type_size_bytes(idx, tinfo) else {
// if the type is unknown it just prints "FFFFFFF"
write!(fmt, "FFFFFFFF")?;
return Ok(());
};
let align = size_solver.type_align_bytes(idx, tinfo, len).unwrap_or(1);
let padded_size = idb_rs::til::align_mem(len, align);
write!(fmt, "{padded_size:08X}")?;
}
Ok(())
}
Expand Down Expand Up @@ -1586,16 +1589,17 @@ fn print_til_type_struct_layout(
til_struct: &Struct,
solver: &mut TILTypeSizeSolver<'_>,
) -> Result<()> {
let total_size = solver
let unpadded_size = solver
.type_size_bytes(Some(type_idx), til_type)
.unwrap_or(0xFFFF);
let struct_align = if til_struct.is_unaligned {
1
} else {
solver
.type_align_bytes(Some(type_idx), til_type, total_size)
.type_align_bytes(Some(type_idx), til_type, unpadded_size)
.unwrap_or(1)
};
let padded_size = idb_rs::til::align_mem(unpadded_size, struct_align);
let mut offset_calc = StructOffset::default();
for (i, member) in til_struct.members.iter().enumerate() {
write!(fmt, "//{i:>3}. ")?;
Expand All @@ -1610,6 +1614,8 @@ fn print_til_type_struct_layout(
.or(member.alignment.map(NonZeroU8::get).map(u64::from))
.unwrap_or(1)
};
let member_size_padded =
idb_rs::til::align_mem(member_size, member_align);
if let TypeVariant::Bitfield(bitfield) =
&member.member_type.type_variant
{
Expand All @@ -1621,8 +1627,9 @@ fn print_til_type_struct_layout(
bitfield.width
)?;
} else {
let offset = offset_calc.next_field(member_size, member_align);
write!(fmt, "{offset:04X} {member_size:04X}")?;
let offset =
offset_calc.next_field(member_size_padded, member_align);
write!(fmt, "{offset:04X} {member_size_padded:04X}")?;
}
use idb_rs::til::flag::tattr_field::*;
let bits = (member.is_vft as u16) << TAFLD_VFTABLE.trailing_zeros()
Expand Down Expand Up @@ -1689,7 +1696,11 @@ fn print_til_type_struct_layout(
| (til_struct.is_unaligned as u16) << TAUDT_UNALIGNED.trailing_zeros()
| (til_struct.is_cppobj() as u16) << TAUDT_CPPOBJ.trailing_zeros()
| (til_struct.is_vft as u16) << TAUDT_VFTABLE.trailing_zeros();
write!(fmt, "// {total_size:04X} effalign({struct_align}) sda={sda} bits={bits:04X} ")?;

if padded_size != unpadded_size {
writeln!(fmt, "// {unpadded_size:04X} unpadded_size")?;
}
write!(fmt, "// {padded_size:04X} effalign({struct_align}) sda={sda} bits={bits:04X} ")?;
if let Some(name) = name {
fmt.write_all(name)?;
write!(fmt, " ")?;
Expand Down Expand Up @@ -1802,15 +1813,6 @@ struct StructOffset {
}

impl StructOffset {
fn align_byte(&mut self, align: u64) {
// offset alignment
let calc_align = align.max(1);
let align_diff = self.offset % calc_align;
if align_diff != 0 {
self.offset += calc_align - align_diff;
}
}

fn next_field(&mut self, size: u64, align: u64) -> u64 {
// if any bitfield left, advance to the next field
if let Some(bit_field) = self.bit_field {
Expand All @@ -1819,7 +1821,7 @@ impl StructOffset {
self.bit_field = None;
self.bit_offset = 0;

self.align_byte(align);
self.offset = idb_rs::til::align_mem(self.offset, align);

let current_offset = self.offset;
self.offset += size;
Expand All @@ -1831,7 +1833,8 @@ impl StructOffset {
match (self.bit_field, bitfield.nbytes) {
// not in a bitfield, start one
(None, bytes) => {
self.align_byte(bytes.get().into());
self.offset =
idb_rs::til::align_mem(self.offset, bytes.get().into());

self.bit_field = Some(bytes);
start_bit_offset = 0;
Expand All @@ -1842,7 +1845,8 @@ impl StructOffset {
if self.bit_offset + bitfield.width > (bytes.get() * 8).into() {
// don't fit, start a new byte_field
self.offset += u64::from(bytes.get());
self.align_byte(bytes.get().into());
self.offset =
idb_rs::til::align_mem(self.offset, bytes.get().into());

self.bit_field = Some(bytes);
start_bit_offset = 0;
Expand All @@ -1857,7 +1861,8 @@ impl StructOffset {
(Some(old_bit_field), bytes) => {
// skip the previous byte-field
self.offset += u64::from(old_bit_field.get());
self.align_byte(bytes.get().into());
self.offset =
idb_rs::til::align_mem(self.offset, bytes.get().into());

// start this bitfield
self.bit_field = Some(bytes);
Expand Down

0 comments on commit ee65c36

Please sign in to comment.