Messages in this thread | | | Subject | Re: [PATCH v2] objtool,ftrace: Implement UNWIND_HINT_RET_OFFSET | From | Julien Thierry <> | Date | Thu, 2 Apr 2020 07:41:46 +0100 |
| |
On 4/1/20 6:09 PM, Peter Zijlstra wrote: > On Wed, Apr 01, 2020 at 04:43:35PM +0100, Julien Thierry wrote: > >>> +static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state) >>> { >>> + u8 ret_offset = insn->ret_offset; >>> int i; >>> >>> - if (state->cfa.base != initial_func_cfi.cfa.base || >>> - state->cfa.offset != initial_func_cfi.cfa.offset || >>> - state->stack_size != initial_func_cfi.cfa.offset || >>> - state->drap) >>> + if (state->cfa.base != initial_func_cfi.cfa.base || state->drap) >>> + return true; >>> + >>> + if (state->cfa.offset != initial_func_cfi.cfa.offset && >>> + !(ret_offset && state->cfa.offset == initial_func_cfi.cfa.offset + ret_offset)) >> >> Isn't that the same thing as "state->cfa.offset != >> initial_func_cfi.cfa.offset + ret_offset" ? > > I'm confused on what cfa.offset is, sometimes it increase with > stack_size, sometimes it doesn't. >
Steven already replied for me about that :) .
> ISTR that for the ftrace case it was indeed cfa.offset + 8, but for the > IRET case below (where it is now not used anymore) it was cfa.offset > (not cfa.offset + 40, which I was expecting). > >>> + return true; >>> + >>> + if (state->stack_size != initial_func_cfi.cfa.offset + ret_offset) >>> return true; >>> >>> - for (i = 0; i < CFI_NUM_REGS; i++) >>> + for (i = 0; i < CFI_NUM_REGS; i++) { >>> if (state->regs[i].base != initial_func_cfi.regs[i].base || >>> state->regs[i].offset != initial_func_cfi.regs[i].offset) >>> return true; >>> + } >>> >>> return false; >>> } > >>> @@ -2185,6 +2148,13 @@ static int validate_branch(struct objtoo >>> >>> break; >>> >>> + case INSN_EXCEPTION_RETURN: >>> + if (func) { >>> + state.stack_size -= arch_exception_frame_size; >>> + break; >> >> Why break instead of returning? Shouldn't an exception return mark the end >> of a branch (whether inside or outside a function) ? >> >> Here it seems it will continue to the next instruction which might have been >> unreachable. > > The code in question (x86's sync_core()), is an exception return to > self. It pushes an exception frame that points to right after the > exception return instruction. > > This is the only usage of IRET in STT_FUNC symbols. > > So rather than teaching objtool how to interpret the whole > push;push;push;push;push;iret sequence, teach it how big the frame is > (arch_exception_frame_size) and let it continue. > > All the other (real) IRETs are in STT_NOTYPE in the entry assembly. >
Right, I see.. However I'm not completely convinced by this. I must admit I haven't followed the whole conversation, but what was the issue with the HINT_IRET_SELF? It seemed more elegant, but I might be missing some context.
Otherwise, it might be worth having a comment in the code to point that this only handles the sync_core() case.
Also, instead of adding a special "arch_exception_frame_size", I could suggest: - Picking this patch [1] from a completely arbitrary source - Getting rid of INSN_STACK type, any instruction could then include stack ops on top of their existing semantics, they can just have an empty list if they don't touch SP/BP - x86 decoder adds a stack_op to the iret to modify the stack pointer by the right amount
[1] https://www.spinics.net/lists/kernel/msg3453725.html
Thanks,
-- Julien Thierry
| |