diff options
author | 2023-03-02 09:45:34 -0800 | |
---|---|---|
committer | 2023-03-02 09:45:34 -0800 | |
commit | 857f1268a591147f7be7509f249dbb3aba6fc65c (patch) | |
tree | 90ba64cb2eee5ee7226ab18c80b43a348fb420a5 /tools/objtool/arch/x86/decode.c | |
parent | Merge tag 'auxdisplay-6.3' of https://github.com/ojeda/linux (diff) | |
parent | objtool: Fix ORC 'signal' propagation (diff) | |
download | linux-857f1268a591147f7be7509f249dbb3aba6fc65c.tar.gz linux-857f1268a591147f7be7509f249dbb3aba6fc65c.tar.bz2 linux-857f1268a591147f7be7509f249dbb3aba6fc65c.zip |
Merge tag 'objtool-core-2023-03-02' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull objtool updates from Ingo Molnar:
- Shrink 'struct instruction', to improve objtool performance & memory
footprint
- Other maximum memory usage reductions - this makes the build both
faster, and fixes kernel build OOM failures on allyesconfig and
similar configs when they try to build the final (large) vmlinux.o
- Fix ORC unwinding when a kprobe (INT3) is set on a stack-modifying
single-byte instruction (PUSH/POP or LEAVE). This requires the
extension of the ORC metadata structure with a 'signal' field
- Misc fixes & cleanups
* tag 'objtool-core-2023-03-02' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (22 commits)
objtool: Fix ORC 'signal' propagation
objtool: Remove instruction::list
x86: Fix FILL_RETURN_BUFFER
objtool: Fix overlapping alternatives
objtool: Union instruction::{call_dest,jump_table}
objtool: Remove instruction::reloc
objtool: Shrink instruction::{type,visited}
objtool: Make instruction::alts a single-linked list
objtool: Make instruction::stack_ops a single-linked list
objtool: Change arch_decode_instruction() signature
x86/entry: Fix unwinding from kprobe on PUSH/POP instruction
x86/unwind/orc: Add 'signal' field to ORC metadata
objtool: Optimize layout of struct special_alt
objtool: Optimize layout of struct symbol
objtool: Allocate multiple structures with calloc()
objtool: Make struct check_options static
objtool: Make struct entries[] static and const
objtool: Fix HOSTCC flag usage
objtool: Properly support make V=1
objtool: Install libsubcmd in build
...
Diffstat (limited to 'tools/objtool/arch/x86/decode.c')
-rw-r--r-- | tools/objtool/arch/x86/decode.c | 107 |
1 files changed, 53 insertions, 54 deletions
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index e7b030f7e2a5..9ef024fd648c 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -105,7 +105,7 @@ bool arch_pc_relative_reloc(struct reloc *reloc) #define ADD_OP(op) \ if (!(op = calloc(1, sizeof(*op)))) \ return -1; \ - else for (list_add_tail(&op->list, ops_list); op; op = NULL) + else for (*ops_list = op, ops_list = &op->next; op; op = NULL) /* * Helpers to decode ModRM/SIB: @@ -146,12 +146,11 @@ static bool has_notrack_prefix(struct insn *insn) int arch_decode_instruction(struct objtool_file *file, const struct section *sec, unsigned long offset, unsigned int maxlen, - unsigned int *len, enum insn_type *type, - unsigned long *immediate, - struct list_head *ops_list) + struct instruction *insn) { + struct stack_op **ops_list = &insn->stack_ops; const struct elf *elf = file->elf; - struct insn insn; + struct insn ins; int x86_64, ret; unsigned char op1, op2, op3, prefix, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0, @@ -165,42 +164,42 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec if (x86_64 == -1) return -1; - ret = insn_decode(&insn, sec->data->d_buf + offset, maxlen, + ret = insn_decode(&ins, sec->data->d_buf + offset, maxlen, x86_64 ? INSN_MODE_64 : INSN_MODE_32); if (ret < 0) { WARN("can't decode instruction at %s:0x%lx", sec->name, offset); return -1; } - *len = insn.length; - *type = INSN_OTHER; + insn->len = ins.length; + insn->type = INSN_OTHER; - if (insn.vex_prefix.nbytes) + if (ins.vex_prefix.nbytes) return 0; - prefix = insn.prefixes.bytes[0]; + prefix = ins.prefixes.bytes[0]; - op1 = insn.opcode.bytes[0]; - op2 = insn.opcode.bytes[1]; - op3 = insn.opcode.bytes[2]; + op1 = ins.opcode.bytes[0]; + op2 = ins.opcode.bytes[1]; + op3 = ins.opcode.bytes[2]; - if (insn.rex_prefix.nbytes) { - rex = insn.rex_prefix.bytes[0]; + if (ins.rex_prefix.nbytes) { + rex = ins.rex_prefix.bytes[0]; rex_w = X86_REX_W(rex) >> 3; rex_r = X86_REX_R(rex) >> 2; rex_x = X86_REX_X(rex) >> 1; rex_b = X86_REX_B(rex); } - if (insn.modrm.nbytes) { - modrm = insn.modrm.bytes[0]; + if (ins.modrm.nbytes) { + modrm = ins.modrm.bytes[0]; modrm_mod = X86_MODRM_MOD(modrm); modrm_reg = X86_MODRM_REG(modrm) + 8*rex_r; modrm_rm = X86_MODRM_RM(modrm) + 8*rex_b; } - if (insn.sib.nbytes) { - sib = insn.sib.bytes[0]; + if (ins.sib.nbytes) { + sib = ins.sib.bytes[0]; /* sib_scale = X86_SIB_SCALE(sib); */ sib_index = X86_SIB_INDEX(sib) + 8*rex_x; sib_base = X86_SIB_BASE(sib) + 8*rex_b; @@ -254,7 +253,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec break; case 0x70 ... 0x7f: - *type = INSN_JUMP_CONDITIONAL; + insn->type = INSN_JUMP_CONDITIONAL; break; case 0x80 ... 0x83: @@ -278,7 +277,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec if (!rm_is_reg(CFI_SP)) break; - imm = insn.immediate.value; + imm = ins.immediate.value; if (op1 & 2) { /* sign extend */ if (op1 & 1) { /* imm32 */ imm <<= 32; @@ -309,7 +308,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ADD_OP(op) { op->src.type = OP_SRC_AND; op->src.reg = CFI_SP; - op->src.offset = insn.immediate.value; + op->src.offset = ins.immediate.value; op->dest.type = OP_DEST_REG; op->dest.reg = CFI_SP; } @@ -356,7 +355,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec op->src.reg = CFI_SP; op->dest.type = OP_DEST_REG_INDIRECT; op->dest.reg = modrm_rm; - op->dest.offset = insn.displacement.value; + op->dest.offset = ins.displacement.value; } break; } @@ -389,7 +388,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec op->src.reg = modrm_reg; op->dest.type = OP_DEST_REG_INDIRECT; op->dest.reg = CFI_BP; - op->dest.offset = insn.displacement.value; + op->dest.offset = ins.displacement.value; } break; } @@ -402,7 +401,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec op->src.reg = modrm_reg; op->dest.type = OP_DEST_REG_INDIRECT; op->dest.reg = CFI_SP; - op->dest.offset = insn.displacement.value; + op->dest.offset = ins.displacement.value; } break; } @@ -419,7 +418,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ADD_OP(op) { op->src.type = OP_SRC_REG_INDIRECT; op->src.reg = CFI_BP; - op->src.offset = insn.displacement.value; + op->src.offset = ins.displacement.value; op->dest.type = OP_DEST_REG; op->dest.reg = modrm_reg; } @@ -432,7 +431,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ADD_OP(op) { op->src.type = OP_SRC_REG_INDIRECT; op->src.reg = CFI_SP; - op->src.offset = insn.displacement.value; + op->src.offset = ins.displacement.value; op->dest.type = OP_DEST_REG; op->dest.reg = modrm_reg; } @@ -464,7 +463,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec /* lea disp(%src), %dst */ ADD_OP(op) { - op->src.offset = insn.displacement.value; + op->src.offset = ins.displacement.value; if (!op->src.offset) { /* lea (%src), %dst */ op->src.type = OP_SRC_REG; @@ -487,7 +486,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec break; case 0x90: - *type = INSN_NOP; + insn->type = INSN_NOP; break; case 0x9c: @@ -511,39 +510,39 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec if (op2 == 0x01) { if (modrm == 0xca) - *type = INSN_CLAC; + insn->type = INSN_CLAC; else if (modrm == 0xcb) - *type = INSN_STAC; + insn->type = INSN_STAC; } else if (op2 >= 0x80 && op2 <= 0x8f) { - *type = INSN_JUMP_CONDITIONAL; + insn->type = INSN_JUMP_CONDITIONAL; } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || op2 == 0x35) { /* sysenter, sysret */ - *type = INSN_CONTEXT_SWITCH; + insn->type = INSN_CONTEXT_SWITCH; } else if (op2 == 0x0b || op2 == 0xb9) { /* ud2 */ - *type = INSN_BUG; + insn->type = INSN_BUG; } else if (op2 == 0x0d || op2 == 0x1f) { /* nopl/nopw */ - *type = INSN_NOP; + insn->type = INSN_NOP; } else if (op2 == 0x1e) { if (prefix == 0xf3 && (modrm == 0xfa || modrm == 0xfb)) - *type = INSN_ENDBR; + insn->type = INSN_ENDBR; } else if (op2 == 0x38 && op3 == 0xf8) { - if (insn.prefixes.nbytes == 1 && - insn.prefixes.bytes[0] == 0xf2) { + if (ins.prefixes.nbytes == 1 && + ins.prefixes.bytes[0] == 0xf2) { /* ENQCMD cannot be used in the kernel. */ WARN("ENQCMD instruction at %s:%lx", sec->name, offset); @@ -591,29 +590,29 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec case 0xcc: /* int3 */ - *type = INSN_TRAP; + insn->type = INSN_TRAP; break; case 0xe3: /* jecxz/jrcxz */ - *type = INSN_JUMP_CONDITIONAL; + insn->type = INSN_JUMP_CONDITIONAL; break; case 0xe9: case 0xeb: - *type = INSN_JUMP_UNCONDITIONAL; + insn->type = INSN_JUMP_UNCONDITIONAL; break; case 0xc2: case 0xc3: - *type = INSN_RETURN; + insn->type = INSN_RETURN; break; case 0xc7: /* mov imm, r/m */ if (!opts.noinstr) break; - if (insn.length == 3+4+4 && !strncmp(sec->name, ".init.text", 10)) { + if (ins.length == 3+4+4 && !strncmp(sec->name, ".init.text", 10)) { struct reloc *immr, *disp; struct symbol *func; int idx; @@ -661,17 +660,17 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec case 0xca: /* retf */ case 0xcb: /* retf */ - *type = INSN_CONTEXT_SWITCH; + insn->type = INSN_CONTEXT_SWITCH; break; case 0xe0: /* loopne */ case 0xe1: /* loope */ case 0xe2: /* loop */ - *type = INSN_JUMP_CONDITIONAL; + insn->type = INSN_JUMP_CONDITIONAL; break; case 0xe8: - *type = INSN_CALL; + insn->type = INSN_CALL; /* * For the impact on the stack, a CALL behaves like * a PUSH of an immediate value (the return address). @@ -683,30 +682,30 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec break; case 0xfc: - *type = INSN_CLD; + insn->type = INSN_CLD; break; case 0xfd: - *type = INSN_STD; + insn->type = INSN_STD; break; case 0xff: if (modrm_reg == 2 || modrm_reg == 3) { - *type = INSN_CALL_DYNAMIC; - if (has_notrack_prefix(&insn)) + insn->type = INSN_CALL_DYNAMIC; + if (has_notrack_prefix(&ins)) WARN("notrack prefix found at %s:0x%lx", sec->name, offset); } else if (modrm_reg == 4) { - *type = INSN_JUMP_DYNAMIC; - if (has_notrack_prefix(&insn)) + insn->type = INSN_JUMP_DYNAMIC; + if (has_notrack_prefix(&ins)) WARN("notrack prefix found at %s:0x%lx", sec->name, offset); } else if (modrm_reg == 5) { /* jmpf */ - *type = INSN_CONTEXT_SWITCH; + insn->type = INSN_CONTEXT_SWITCH; } else if (modrm_reg == 6) { @@ -723,7 +722,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec break; } - *immediate = insn.immediate.nbytes ? insn.immediate.value : 0; + insn->immediate = ins.immediate.nbytes ? ins.immediate.value : 0; return 0; } |