Skip to content
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

Properly handle DW_CFA_GNU_args_size #319

Merged
merged 3 commits into from
Aug 7, 2018
Merged
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions examples/dwarfdump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,9 @@ fn dump_cfi_instructions<R: Reader, W: Write>(
RestoreState => {
writeln!(w, " DW_CFA_restore_state")?;
}
ArgsSize { size } => {
writeln!(w, " DW_CFA_GNU_args_size ({})", size)?;
}
Nop => {
writeln!(w, " DW_CFA_nop")?;
}
Expand Down
43 changes: 42 additions & 1 deletion src/cfi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2283,6 +2283,12 @@ where
self.ctx.set_start_address(start_address);
}

// GNU Extension. Save the size somewhere so the unwinder can use
// it when restoring IP
ArgsSize { size } => {
self.ctx.row_mut().saved_args_size = size;
}

// No operation.
Nop => {}
};
Expand Down Expand Up @@ -2439,6 +2445,7 @@ impl<'iter, R: Reader> Iterator for RegisterRuleIter<'iter, R> {
pub struct UnwindTableRow<R: Reader> {
start_address: u64,
end_address: u64,
saved_args_size: u64,
cfa: CfaRule<R>,
registers: RegisterRuleMap<R>,
}
Expand All @@ -2448,6 +2455,7 @@ impl<R: Reader> Default for UnwindTableRow<R> {
UnwindTableRow {
start_address: 0,
end_address: 0,
saved_args_size: 0,
cfa: Default::default(),
registers: Default::default(),
}
Expand Down Expand Up @@ -2482,6 +2490,14 @@ impl<R: Reader> UnwindTableRow<R> {
self.start_address <= address && address < self.end_address
}

/// Returns the amount of args currently on the stack.
///
/// When unwinding, if the personality function requested a change in IP,
/// the SP needs to be adjusted by saved_args_size.
pub fn saved_args_size(&self) -> u64 {
self.saved_args_size
}

/// Get the canonical frame address (CFA) recovery rule for this row.
pub fn cfa(&self) -> &CfaRule<R> {
&self.cfa
Expand Down Expand Up @@ -2905,6 +2921,19 @@ pub enum CallFrameInstruction<R: Reader> {
/// > them in the current row.
RestoreState,


/// > DW_CFA_GNU_args_size
/// >
/// > GNU Extension
/// >
/// > The DW_CFA_GNU_args_size instruction takes an unsigned LEB128 operand
/// > representing an argument size. This instruction specifies the total of
/// > the size of the arguments which have been pushed onto the stack.
ArgsSize {
/// The size of the arguments which have been pushed onto the stack
size: u64
},

// 6.4.2.5 Padding Instruction
/// > 1. DW_CFA_nop
/// >
Expand Down Expand Up @@ -3099,6 +3128,13 @@ impl<R: Reader> CallFrameInstruction<R> {
})
}

constants::DW_CFA_GNU_args_size => {
let size = input.read_uleb128()?;
Ok(CallFrameInstruction::ArgsSize {
size
})
}

otherwise => Err(Error::UnknownCallFrameInstruction(otherwise)),
}
}
Expand Down Expand Up @@ -5196,6 +5232,7 @@ mod tests {
let expected = UnwindTableRow {
start_address: 0,
end_address: 1,
saved_args_size: 0,
cfa: CfaRule::RegisterAndOffset {
register: 4,
offset: -12,
Expand All @@ -5212,6 +5249,7 @@ mod tests {
let expected = UnwindTableRow {
start_address: 1,
end_address: 33,
saved_args_size: 0,
cfa: CfaRule::RegisterAndOffset {
register: 4,
offset: -12,
Expand All @@ -5228,6 +5266,7 @@ mod tests {
let expected = UnwindTableRow {
start_address: 33,
end_address: 97,
saved_args_size: 0,
cfa: CfaRule::RegisterAndOffset {
register: 4,
offset: -12,
Expand All @@ -5246,6 +5285,7 @@ mod tests {
let expected = UnwindTableRow {
start_address: 97,
end_address: 100,
saved_args_size: 0,
cfa: CfaRule::RegisterAndOffset {
register: 4,
offset: -12,
Expand Down Expand Up @@ -5376,6 +5416,7 @@ mod tests {
UnwindTableRow {
start_address: fde1.initial_address() + 100,
end_address: fde1.initial_address() + fde1.len(),
saved_args_size: 0,
cfa: CfaRule::RegisterAndOffset {
register: 4,
offset: -12,
Expand Down Expand Up @@ -6163,7 +6204,7 @@ mod tests {
mem::size_of::<
UnwindContext<EhFrame<EndianSlice<NativeEndian>>, EndianSlice<NativeEndian>>,
>(),
5384
5416
);
}

Expand Down