@@ -8,6 +8,7 @@ use crate::pe::{PeSections, PeUnwinderError, PeUnwinding};
8
8
use crate :: unwind_result:: UnwindResult ;
9
9
use std:: ops:: ControlFlow ;
10
10
11
+ use crate :: FrameAddress ;
11
12
use pe_unwind_info:: x86_64:: {
12
13
FunctionEpilogInstruction , FunctionTableEntries , Register , UnwindInfo , UnwindInfoTrailer ,
13
14
UnwindOperation , UnwindState ,
@@ -97,6 +98,7 @@ impl PeUnwinding for ArchX86_64 {
97
98
sections : PeSections < D > ,
98
99
address : u32 ,
99
100
regs : & mut Self :: UnwindRegs ,
101
+ is_first_frame : bool ,
100
102
read_stack : & mut F ,
101
103
) -> Result < UnwindResult < Self :: UnwindRule > , PeUnwinderError >
102
104
where
@@ -117,51 +119,55 @@ impl PeUnwinding for ArchX86_64 {
117
119
UnwindInfo :: parse ( sections. unwind_info_memory_at_rva ( unwind_info_address) ?)
118
120
. ok_or ( PeUnwinderError :: UnwindInfoParseError ) ?;
119
121
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 ( ) )
133
131
{
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
+ }
136
139
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
+ }
156
160
}
157
161
}
158
- }
159
162
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 ) ;
163
166
164
- return Ok ( UnwindResult :: Uncacheable ( ra) ) ;
167
+ return Ok ( UnwindResult :: Uncacheable (
168
+ FrameAddress :: from_return_address ( ra) ,
169
+ ) ) ;
170
+ }
165
171
}
166
172
167
173
// Get all chained UnwindInfo and resolve errors when collecting.
@@ -207,14 +213,18 @@ impl PeUnwinding for ArchX86_64 {
207
213
. resolve_operation ( & mut state, & op)
208
214
. ok_or ( PeUnwinderError :: MissingStackData ( None ) ) ?
209
215
{
210
- return Ok ( UnwindResult :: Uncacheable ( ra) ) ;
216
+ return Ok ( UnwindResult :: Uncacheable ( Some (
217
+ FrameAddress :: from_instruction_pointer ( ra) ,
218
+ ) ) ) ;
211
219
}
212
220
}
213
221
214
222
let rsp = regs. get ( Reg :: RSP ) ;
215
223
let ra = read_stack_err ( read_stack, rsp) ?;
216
224
regs. set ( Reg :: RSP , rsp + 8 ) ;
217
225
218
- Ok ( UnwindResult :: Uncacheable ( ra) )
226
+ Ok ( UnwindResult :: Uncacheable (
227
+ FrameAddress :: from_return_address ( ra) ,
228
+ ) )
219
229
}
220
230
}
0 commit comments