Compare commits

...

3 Commits

Author SHA1 Message Date
Benjamin Moir 97fa992742 Skip anonymous unions with less than 2 members. 2024-01-10 18:49:27 +10:00
Benjamin Moir 046ea15f36 Change union offset validation 2024-01-10 18:11:14 +10:00
Benjamin Moir c7fb8c79fc Handle some more anonymous union edge cases 2024-01-10 18:06:08 +10:00
1 changed files with 26 additions and 23 deletions

View File

@ -1421,9 +1421,9 @@ struct AnonUnionGroup {
} }
fn get_anon_unions(info: &DwarfInfo, members: &[StructureMember]) -> Result<Vec<AnonUnion>> { fn get_anon_unions(info: &DwarfInfo, members: &[StructureMember]) -> Result<Vec<AnonUnion>> {
let mut unions = Vec::new(); let mut unions = Vec::<AnonUnion>::new();
let mut offset = u32::MAX; let mut offset = u32::MAX;
for (prev, member) in members.iter().skip(1).enumerate() { 'member: for (prev, member) in members.iter().skip(1).enumerate() {
if let Some(bit) = &member.bit { if let Some(bit) = &member.bit {
if bit.bit_offset != 0 { if bit.bit_offset != 0 {
continue; continue;
@ -1433,6 +1433,11 @@ fn get_anon_unions(info: &DwarfInfo, members: &[StructureMember]) -> Result<Vec<
offset = member.offset; offset = member.offset;
for (i, member) in members.iter().enumerate() { for (i, member) in members.iter().enumerate() {
if member.offset == offset { if member.offset == offset {
for anon in &unions {
if anon.member_index == i {
continue 'member;
}
}
unions.push(AnonUnion { offset, member_index: i, member_count: 0 }); unions.push(AnonUnion { offset, member_index: i, member_count: 0 });
break; break;
} }
@ -1450,8 +1455,7 @@ fn get_anon_unions(info: &DwarfInfo, members: &[StructureMember]) -> Result<Vec<
anon.member_count = i; anon.member_count = i;
} }
} }
let mut cur_size = 0; let mut max_offset = 0;
let mut max_size = 0;
for member in members.iter().skip(anon.member_index).take(anon.member_count + 1) { for member in members.iter().skip(anon.member_index).take(anon.member_count + 1) {
if let Some(bit) = &member.bit { if let Some(bit) = &member.bit {
if bit.bit_offset != 0 { if bit.bit_offset != 0 {
@ -1460,24 +1464,15 @@ fn get_anon_unions(info: &DwarfInfo, members: &[StructureMember]) -> Result<Vec<
} }
let size = let size =
if let Some(size) = member.byte_size { size } else { member.kind.size(info)? }; if let Some(size) = member.byte_size { size } else { member.kind.size(info)? };
if member.offset == anon.offset { max_offset = max(max_offset, member.offset + size);
cur_size = size;
} else {
cur_size += size;
}
max_size = max(max_size, cur_size);
} }
cur_size = 0;
for member in members.iter().skip(anon.member_index + anon.member_count) { for member in members.iter().skip(anon.member_index + anon.member_count) {
if let Some(bit) = &member.bit { if let Some(bit) = &member.bit {
if bit.bit_offset != 0 { if bit.bit_offset != 0 {
continue; continue;
} }
} }
let size = if member.offset >= max_offset || member.offset < anon.offset {
if let Some(size) = member.byte_size { size } else { member.kind.size(info)? };
cur_size += size;
if cur_size > max_size {
break; break;
} }
anon.member_count += 1; anon.member_count += 1;
@ -1569,8 +1564,8 @@ pub fn struct_def_string(
let mut indent = 4; let mut indent = 4;
let unions = get_anon_unions(info, &t.members)?; let unions = get_anon_unions(info, &t.members)?;
let groups = get_anon_union_groups(&t.members, &unions); let groups = get_anon_union_groups(&t.members, &unions);
let mut in_union = false; let mut in_union = 0;
let mut in_group = false; let mut in_group = 0;
for (i, member) in t.members.iter().enumerate() { for (i, member) in t.members.iter().enumerate() {
if vis != member.visibility { if vis != member.visibility {
vis = member.visibility; vis = member.visibility;
@ -1584,28 +1579,34 @@ pub fn struct_def_string(
if i == anon.member_index + anon.member_count { if i == anon.member_index + anon.member_count {
indent -= 4; indent -= 4;
out.push_str(&indent_all_by(indent, "};\n")); out.push_str(&indent_all_by(indent, "};\n"));
in_group = false; in_group -= 1;
} }
} }
for anon in &unions { for anon in &unions {
if anon.member_count < 2 {
continue;
}
if i == anon.member_index + anon.member_count { if i == anon.member_index + anon.member_count {
indent -= 4; indent -= 4;
out.push_str(&indent_all_by(indent, "};\n")); out.push_str(&indent_all_by(indent, "};\n"));
in_union = false; in_union -= 1;
} }
} }
for anon in &unions { for anon in &unions {
if anon.member_count < 2 {
continue;
}
if i == anon.member_index { if i == anon.member_index {
out.push_str(&indent_all_by(indent, "union { // inferred\n")); out.push_str(&indent_all_by(indent, "union { // inferred\n"));
indent += 4; indent += 4;
in_union = true; in_union += 1;
} }
} }
for anon in &groups { for anon in &groups {
if i == anon.member_index { if i == anon.member_index {
out.push_str(&indent_all_by(indent, "struct { // inferred\n")); out.push_str(&indent_all_by(indent, "struct { // inferred\n"));
indent += 4; indent += 4;
in_group = true; in_group += 1;
} }
} }
let mut var_out = String::new(); let mut var_out = String::new();
@ -1618,13 +1619,15 @@ pub fn struct_def_string(
writeln!(var_out, "; // offset {:#X}, size {:#X}", member.offset, size)?; writeln!(var_out, "; // offset {:#X}, size {:#X}", member.offset, size)?;
out.push_str(&indent_all_by(indent, var_out)); out.push_str(&indent_all_by(indent, var_out));
} }
if in_group { while in_group > 0 {
indent -= 4; indent -= 4;
out.push_str(&indent_all_by(indent, "};\n")); out.push_str(&indent_all_by(indent, "};\n"));
in_group -= 1;
} }
if in_union { while in_union > 0 {
indent -= 4; indent -= 4;
out.push_str(&indent_all_by(indent, "};\n")); out.push_str(&indent_all_by(indent, "};\n"));
in_union -= 1;
} }
out.push('}'); out.push('}');
Ok(out) Ok(out)