Skip to content

Commit b564260

Browse files
committed
wip: Implement is_first_frame for PE
1 parent 6240ca0 commit b564260

File tree

11 files changed

+130
-91
lines changed

11 files changed

+130
-91
lines changed

src/aarch64/dwarf.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::dwarf::{
1111
eval_cfa_rule, eval_register_rule, ConversionError, DwarfUnwindRegs, DwarfUnwinderError,
1212
DwarfUnwinding,
1313
};
14+
use crate::FrameAddress;
1415

1516
impl DwarfUnwindRegs for UnwindRegsAarch64 {
1617
fn get(&self, register: Register) -> Option<u64> {
@@ -79,7 +80,9 @@ impl DwarfUnwinding for ArchAarch64 {
7980
regs.set_sp(cfa);
8081
regs.set_lr(lr);
8182

82-
Ok(UnwindResult::Uncacheable(lr))
83+
Ok(UnwindResult::Uncacheable(
84+
FrameAddress::from_return_address(lr),
85+
))
8386
}
8487

8588
fn rule_if_uncovered_by_fde() -> Self::UnwindRule {

src/aarch64/pe.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ impl PeUnwinding for ArchAarch64 {
77
_sections: PeSections<D>,
88
_address: u32,
99
_regs: &mut Self::UnwindRegs,
10+
_is_first_frame: bool,
1011
_read_stack: &mut F,
1112
) -> Result<UnwindResult<Self::UnwindRule>, PeUnwinderError>
1213
where

src/aarch64/unwinder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> Unwinder for UnwinderAarch
5454
regs: &mut UnwindRegsAarch64,
5555
cache: &mut CacheAarch64<D, P>,
5656
read_stack: &mut F,
57-
) -> Result<Option<u64>, Error>
57+
) -> Result<Option<FrameAddress>, Error>
5858
where
5959
F: FnMut(u64) -> Result<u64, ()>,
6060
{

src/pe.rs

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub trait PeUnwinding: Arch {
7171
sections: PeSections<D>,
7272
address: u32,
7373
regs: &mut Self::UnwindRegs,
74+
is_first_frame: bool,
7475
read_stack: &mut F,
7576
) -> Result<UnwindResult<Self::UnwindRule>, PeUnwinderError>
7677
where

src/unwind_result.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
use crate::FrameAddress;
2+
13
#[derive(Debug, Clone)]
24
pub enum UnwindResult<R> {
35
ExecRule(R),
4-
Uncacheable(u64),
6+
Uncacheable(Option<FrameAddress>),
57
}

src/unwinder.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub trait Unwinder {
6666
regs: &mut Self::UnwindRegs,
6767
cache: &mut Self::Cache,
6868
read_stack: &mut F,
69-
) -> Result<Option<u64>, Error>
69+
) -> Result<Option<FrameAddress>, Error>
7070
where
7171
F: FnMut(u64) -> Result<u64, ()>;
7272

@@ -164,8 +164,6 @@ impl<'u, 'c, 'r, U: Unwinder + ?Sized, F: FnMut(u64) -> Result<u64, ()>>
164164
};
165165
match next {
166166
Some(return_address) => {
167-
let return_address = FrameAddress::from_return_address(return_address)
168-
.ok_or(Error::ReturnAddressIsNull)?;
169167
self.state = UnwindIteratorState::Unwinding(return_address);
170168
Ok(Some(return_address))
171169
}
@@ -308,7 +306,7 @@ impl<
308306
cache: &mut Cache<D, A::UnwindRule, P>,
309307
read_stack: &mut F,
310308
callback: G,
311-
) -> Result<Option<u64>, Error>
309+
) -> Result<Option<FrameAddress>, Error>
312310
where
313311
F: FnMut(u64) -> Result<u64, ()>,
314312
G: FnOnce(
@@ -327,7 +325,9 @@ impl<
327325
.lookup(lookup_address, self.modules_generation)
328326
{
329327
CacheResult::Hit(unwind_rule) => {
330-
return unwind_rule.exec(is_first_frame, regs, read_stack);
328+
return Ok(unwind_rule
329+
.exec(is_first_frame, regs, read_stack)?
330+
.and_then(FrameAddress::from_return_address));
331331
}
332332
CacheResult::Miss(handle) => handle,
333333
};
@@ -345,9 +345,7 @@ impl<
345345
read_stack,
346346
) {
347347
Ok(UnwindResult::ExecRule(rule)) => rule,
348-
Ok(UnwindResult::Uncacheable(return_address)) => {
349-
return Ok(Some(return_address))
350-
}
348+
Ok(UnwindResult::Uncacheable(return_address)) => return Ok(return_address),
351349
Err(_err) => {
352350
// eprintln!("Unwinder error: {}", err);
353351
A::UnwindRule::fallback_rule()
@@ -356,7 +354,9 @@ impl<
356354
}
357355
};
358356
cache.rule_cache.insert(cache_handle, unwind_rule);
359-
unwind_rule.exec(is_first_frame, regs, read_stack)
357+
Ok(unwind_rule
358+
.exec(is_first_frame, regs, read_stack)?
359+
.and_then(FrameAddress::from_return_address))
360360
}
361361

362362
pub fn unwind_frame<F>(
@@ -365,7 +365,7 @@ impl<
365365
regs: &mut A::UnwindRegs,
366366
cache: &mut Cache<D, A::UnwindRule, P>,
367367
read_stack: &mut F,
368-
) -> Result<Option<u64>, Error>
368+
) -> Result<Option<FrameAddress>, Error>
369369
where
370370
F: FnMut(u64) -> Result<u64, ()>,
371371
{
@@ -538,6 +538,7 @@ impl<
538538
},
539539
rel_lookup_address,
540540
regs,
541+
is_first_frame,
541542
read_stack,
542543
)?,
543544
ModuleUnwindDataInternal::None => return Err(UnwinderError::NoModuleUnwindData),

src/x86_64/dwarf.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::dwarf::{
99
DwarfUnwinding,
1010
};
1111
use crate::unwind_result::UnwindResult;
12+
use crate::FrameAddress;
1213

1314
impl DwarfUnwindRegs for UnwindRegsX86_64 {
1415
fn get(&self, register: Register) -> Option<u64> {
@@ -74,7 +75,9 @@ impl DwarfUnwinding for ArchX86_64 {
7475
regs.set_bp(new_bp);
7576
regs.set_sp(cfa);
7677

77-
Ok(UnwindResult::Uncacheable(return_address))
78+
Ok(UnwindResult::Uncacheable(
79+
FrameAddress::from_return_address(return_address),
80+
))
7881
}
7982

8083
fn rule_if_uncovered_by_fde() -> Self::UnwindRule {

src/x86_64/pe.rs

+51-41
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::pe::{PeSections, PeUnwinderError, PeUnwinding};
88
use crate::unwind_result::UnwindResult;
99
use std::ops::ControlFlow;
1010

11+
use crate::FrameAddress;
1112
use pe_unwind_info::x86_64::{
1213
FunctionEpilogInstruction, FunctionTableEntries, Register, UnwindInfo, UnwindInfoTrailer,
1314
UnwindOperation, UnwindState,
@@ -97,6 +98,7 @@ impl PeUnwinding for ArchX86_64 {
9798
sections: PeSections<D>,
9899
address: u32,
99100
regs: &mut Self::UnwindRegs,
101+
is_first_frame: bool,
100102
read_stack: &mut F,
101103
) -> Result<UnwindResult<Self::UnwindRule>, PeUnwinderError>
102104
where
@@ -117,51 +119,55 @@ impl PeUnwinding for ArchX86_64 {
117119
UnwindInfo::parse(sections.unwind_info_memory_at_rva(unwind_info_address)?)
118120
.ok_or(PeUnwinderError::UnwindInfoParseError)?;
119121

120-
// Check whether the address is in the function epilog. If so, we need to
121-
// simulate the remaining epilog instructions (unwind codes don't account for
122-
// unwinding from the epilog). We only need to check this for the first unwind info (if
123-
// there are chained infos).
124-
let bytes = (function.end_address.get() - address) as usize;
125-
let instruction = &sections.text_memory_at_rva(address)?[..bytes];
126-
if let Ok(epilog_instructions) =
127-
FunctionEpilogInstruction::parse_sequence(instruction, unwind_info.frame_register())
128-
{
129-
// If the epilog is an optional AddSP followed by Pops, we can return a cache
130-
// rule.
131-
if let Some(rule) =
132-
UnwindRuleX86_64::for_sequence_of_offset_or_pop(epilog_instructions.iter())
122+
if is_first_frame {
123+
// Check whether the address is in the function epilog. If so, we need to
124+
// simulate the remaining epilog instructions (unwind codes don't account for
125+
// unwinding from the epilog). We only need to check this for the first unwind info (if
126+
// there are chained infos).
127+
let bytes = (function.end_address.get() - address) as usize;
128+
let instruction = &sections.text_memory_at_rva(address)?[..bytes];
129+
if let Ok(epilog_instructions) =
130+
FunctionEpilogInstruction::parse_sequence(instruction, unwind_info.frame_register())
133131
{
134-
return Ok(UnwindResult::ExecRule(rule));
135-
}
132+
// If the epilog is an optional AddSP followed by Pops, we can return a cache
133+
// rule.
134+
if let Some(rule) =
135+
UnwindRuleX86_64::for_sequence_of_offset_or_pop(epilog_instructions.iter())
136+
{
137+
return Ok(UnwindResult::ExecRule(rule));
138+
}
136139

137-
for instruction in epilog_instructions.iter() {
138-
match instruction {
139-
FunctionEpilogInstruction::AddSP(offset) => {
140-
let rsp = regs.get(Reg::RSP);
141-
regs.set(Reg::RSP, rsp + *offset as u64);
142-
}
143-
FunctionEpilogInstruction::AddSPFromFP(offset) => {
144-
let fp = unwind_info
145-
.frame_register()
146-
.expect("invalid fp register offset");
147-
let fp = convert_pe_register(fp);
148-
let fp = regs.get(fp);
149-
regs.set(Reg::RSP, fp + *offset as u64);
150-
}
151-
FunctionEpilogInstruction::Pop(reg) => {
152-
let rsp = regs.get(Reg::RSP);
153-
let val = read_stack_err(read_stack, rsp)?;
154-
regs.set(convert_pe_register(*reg), val);
155-
regs.set(Reg::RSP, rsp + 8);
140+
for instruction in epilog_instructions.iter() {
141+
match instruction {
142+
FunctionEpilogInstruction::AddSP(offset) => {
143+
let rsp = regs.get(Reg::RSP);
144+
regs.set(Reg::RSP, rsp + *offset as u64);
145+
}
146+
FunctionEpilogInstruction::AddSPFromFP(offset) => {
147+
let fp = unwind_info
148+
.frame_register()
149+
.expect("invalid fp register offset");
150+
let fp = convert_pe_register(fp);
151+
let fp = regs.get(fp);
152+
regs.set(Reg::RSP, fp + *offset as u64);
153+
}
154+
FunctionEpilogInstruction::Pop(reg) => {
155+
let rsp = regs.get(Reg::RSP);
156+
let val = read_stack_err(read_stack, rsp)?;
157+
regs.set(convert_pe_register(*reg), val);
158+
regs.set(Reg::RSP, rsp + 8);
159+
}
156160
}
157161
}
158-
}
159162

160-
let rsp = regs.get(Reg::RSP);
161-
let ra = read_stack_err(read_stack, rsp)?;
162-
regs.set(Reg::RSP, rsp + 8);
163+
let rsp = regs.get(Reg::RSP);
164+
let ra = read_stack_err(read_stack, rsp)?;
165+
regs.set(Reg::RSP, rsp + 8);
163166

164-
return Ok(UnwindResult::Uncacheable(ra));
167+
return Ok(UnwindResult::Uncacheable(
168+
FrameAddress::from_return_address(ra),
169+
));
170+
}
165171
}
166172

167173
// Get all chained UnwindInfo and resolve errors when collecting.
@@ -207,14 +213,18 @@ impl PeUnwinding for ArchX86_64 {
207213
.resolve_operation(&mut state, &op)
208214
.ok_or(PeUnwinderError::MissingStackData(None))?
209215
{
210-
return Ok(UnwindResult::Uncacheable(ra));
216+
return Ok(UnwindResult::Uncacheable(Some(
217+
FrameAddress::from_instruction_pointer(ra),
218+
)));
211219
}
212220
}
213221

214222
let rsp = regs.get(Reg::RSP);
215223
let ra = read_stack_err(read_stack, rsp)?;
216224
regs.set(Reg::RSP, rsp + 8);
217225

218-
Ok(UnwindResult::Uncacheable(ra))
226+
Ok(UnwindResult::Uncacheable(
227+
FrameAddress::from_return_address(ra),
228+
))
219229
}
220230
}

src/x86_64/unwinder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> Unwinder for UnwinderX86_6
5555
regs: &mut UnwindRegsX86_64,
5656
cache: &mut CacheX86_64<D, P>,
5757
read_stack: &mut F,
58-
) -> Result<Option<u64>, Error>
58+
) -> Result<Option<FrameAddress>, Error>
5959
where
6060
F: FnMut(u64) -> Result<u64, ()>,
6161
{

0 commit comments

Comments
 (0)