objtool: Support stack-swizzle
Natively support the stack swizzle pattern: mov %rsp, (%[tos]) mov %[tos], %rsp ... pop %rsp It uses the vals[] array to link the first two stack-ops, and detect the SP to SP_INDIRECT swizzle. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Miroslav Benes <mbenes@suse.cz> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
This commit is contained in:
parent
2a51282984
commit
aafeb14e9d
|
@ -1945,6 +1945,38 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
|
||||||
cfa->offset = -cfi->vals[op->src.reg].offset;
|
cfa->offset = -cfi->vals[op->src.reg].offset;
|
||||||
cfi->stack_size = cfa->offset;
|
cfi->stack_size = cfa->offset;
|
||||||
|
|
||||||
|
} else if (cfa->base == CFI_SP &&
|
||||||
|
cfi->vals[op->src.reg].base == CFI_SP_INDIRECT &&
|
||||||
|
cfi->vals[op->src.reg].offset == cfa->offset) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stack swizzle:
|
||||||
|
*
|
||||||
|
* 1: mov %rsp, (%[tos])
|
||||||
|
* 2: mov %[tos], %rsp
|
||||||
|
* ...
|
||||||
|
* 3: pop %rsp
|
||||||
|
*
|
||||||
|
* Where:
|
||||||
|
*
|
||||||
|
* 1 - places a pointer to the previous
|
||||||
|
* stack at the Top-of-Stack of the
|
||||||
|
* new stack.
|
||||||
|
*
|
||||||
|
* 2 - switches to the new stack.
|
||||||
|
*
|
||||||
|
* 3 - pops the Top-of-Stack to restore
|
||||||
|
* the original stack.
|
||||||
|
*
|
||||||
|
* Note: we set base to SP_INDIRECT
|
||||||
|
* here and preserve offset. Therefore
|
||||||
|
* when the unwinder reaches ToS it
|
||||||
|
* will dereference SP and then add the
|
||||||
|
* offset to find the next frame, IOW:
|
||||||
|
* (%rsp) + offset.
|
||||||
|
*/
|
||||||
|
cfa->base = CFI_SP_INDIRECT;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
cfa->base = CFI_UNDEFINED;
|
cfa->base = CFI_UNDEFINED;
|
||||||
cfa->offset = 0;
|
cfa->offset = 0;
|
||||||
|
@ -2047,6 +2079,13 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
|
||||||
|
|
||||||
case OP_SRC_POP:
|
case OP_SRC_POP:
|
||||||
case OP_SRC_POPF:
|
case OP_SRC_POPF:
|
||||||
|
if (op->dest.reg == CFI_SP && cfa->base == CFI_SP_INDIRECT) {
|
||||||
|
|
||||||
|
/* pop %rsp; # restore from a stack swizzle */
|
||||||
|
cfa->base = CFI_SP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!cfi->drap && op->dest.reg == cfa->base) {
|
if (!cfi->drap && op->dest.reg == cfa->base) {
|
||||||
|
|
||||||
/* pop %rbp */
|
/* pop %rbp */
|
||||||
|
@ -2193,6 +2232,12 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
|
||||||
/* mov reg, disp(%rsp) */
|
/* mov reg, disp(%rsp) */
|
||||||
save_reg(cfi, op->src.reg, CFI_CFA,
|
save_reg(cfi, op->src.reg, CFI_CFA,
|
||||||
op->dest.offset - cfi->stack_size);
|
op->dest.offset - cfi->stack_size);
|
||||||
|
|
||||||
|
} else if (op->src.reg == CFI_SP && op->dest.offset == 0) {
|
||||||
|
|
||||||
|
/* mov %rsp, (%reg); # setup a stack swizzle. */
|
||||||
|
cfi->vals[op->dest.reg].base = CFI_SP_INDIRECT;
|
||||||
|
cfi->vals[op->dest.reg].offset = cfa->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue