@@ -8,6 +8,7 @@ use crate::pe::{PeSections, PeUnwinderError, PeUnwinding};
88use crate :: unwind_result:: UnwindResult ;
99use std:: ops:: ControlFlow ;
1010
11+ use crate :: FrameAddress ;
1112use 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}
0 commit comments