Commit 857f1268 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 6972633c 00c8f01c
......@@ -385,7 +385,14 @@ SYM_CODE_END(xen_error_entry)
*/
.macro idtentry vector asmsym cfunc has_error_code:req
SYM_CODE_START(\asmsym)
.if \vector == X86_TRAP_BP
/* #BP advances %rip to the next instruction */
UNWIND_HINT_IRET_REGS offset=\has_error_code*8 signal=0
.else
UNWIND_HINT_IRET_REGS offset=\has_error_code*8
.endif
ENDBR
ASM_CLAC
cld
......
......@@ -261,7 +261,7 @@
.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req ftr2=ALT_NOT(X86_FEATURE_ALWAYS)
ALTERNATIVE_2 "jmp .Lskip_rsb_\@", \
__stringify(__FILL_RETURN_BUFFER(\reg,\nr)), \ftr, \
__stringify(__FILL_ONE_RETURN), \ftr2
__stringify(nop;nop;__FILL_ONE_RETURN), \ftr2
.Lskip_rsb_\@:
.endm
......
......@@ -57,12 +57,14 @@ struct orc_entry {
unsigned sp_reg:4;
unsigned bp_reg:4;
unsigned type:2;
unsigned signal:1;
unsigned end:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned bp_reg:4;
unsigned sp_reg:4;
unsigned unused:5;
unsigned unused:4;
unsigned end:1;
unsigned signal:1;
unsigned type:2;
#endif
} __packed;
......
......@@ -15,7 +15,7 @@
UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1
.endm
.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0
.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 signal=1
.if \base == %rsp
.if \indirect
.set sp_reg, ORC_REG_SP_INDIRECT
......@@ -45,11 +45,11 @@
.set type, UNWIND_HINT_TYPE_REGS
.endif
UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type
UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type signal=\signal
.endm
.macro UNWIND_HINT_IRET_REGS base=%rsp offset=0
UNWIND_HINT_REGS base=\base offset=\offset partial=1
.macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 signal=1
UNWIND_HINT_REGS base=\base offset=\offset partial=1 signal=\signal
.endm
.macro UNWIND_HINT_FUNC
......@@ -67,7 +67,7 @@
#else
#define UNWIND_HINT_FUNC \
UNWIND_HINT(ORC_REG_SP, 8, UNWIND_HINT_TYPE_FUNC, 0)
UNWIND_HINT(ORC_REG_SP, 8, UNWIND_HINT_TYPE_FUNC, 0, 0)
#endif /* __ASSEMBLY__ */
......
......@@ -484,6 +484,8 @@ bool unwind_next_frame(struct unwind_state *state)
goto the_end;
}
state->signal = orc->signal;
/* Find the previous frame's stack: */
switch (orc->sp_reg) {
case ORC_REG_SP:
......@@ -563,7 +565,6 @@ bool unwind_next_frame(struct unwind_state *state)
state->sp = sp;
state->regs = NULL;
state->prev_regs = NULL;
state->signal = false;
break;
case UNWIND_HINT_TYPE_REGS:
......@@ -587,7 +588,6 @@ bool unwind_next_frame(struct unwind_state *state)
state->regs = (struct pt_regs *)sp;
state->prev_regs = NULL;
state->full_regs = true;
state->signal = true;
break;
case UNWIND_HINT_TYPE_REGS_PARTIAL:
......@@ -604,7 +604,6 @@ bool unwind_next_frame(struct unwind_state *state)
state->prev_regs = state->regs;
state->regs = (void *)sp - IRET_FRAME_OFFSET;
state->full_regs = false;
state->signal = true;
break;
default:
......
......@@ -15,6 +15,7 @@ struct unwind_hint {
s16 sp_offset;
u8 sp_reg;
u8 type;
u8 signal;
u8 end;
};
#endif
......@@ -49,7 +50,7 @@ struct unwind_hint {
#ifndef __ASSEMBLY__
#define UNWIND_HINT(sp_reg, sp_offset, type, end) \
#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \
"987: \n\t" \
".pushsection .discard.unwind_hints\n\t" \
/* struct unwind_hint */ \
......@@ -57,6 +58,7 @@ struct unwind_hint {
".short " __stringify(sp_offset) "\n\t" \
".byte " __stringify(sp_reg) "\n\t" \
".byte " __stringify(type) "\n\t" \
".byte " __stringify(signal) "\n\t" \
".byte " __stringify(end) "\n\t" \
".balign 4 \n\t" \
".popsection\n\t"
......@@ -129,7 +131,7 @@ struct unwind_hint {
* the debuginfo as necessary. It will also warn if it sees any
* inconsistencies.
*/
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
.Lunwind_hint_ip_\@:
.pushsection .discard.unwind_hints
/* struct unwind_hint */
......@@ -137,6 +139,7 @@ struct unwind_hint {
.short \sp_offset
.byte \sp_reg
.byte \type
.byte \signal
.byte \end
.balign 4
.popsection
......@@ -174,7 +177,7 @@ struct unwind_hint {
#ifndef __ASSEMBLY__
#define UNWIND_HINT(sp_reg, sp_offset, type, end) \
#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \
"\n\t"
#define STACK_FRAME_NON_STANDARD(func)
#define STACK_FRAME_NON_STANDARD_FP(func)
......@@ -182,7 +185,7 @@ struct unwind_hint {
#define ASM_REACHABLE
#else
#define ANNOTATE_INTRA_FUNCTION_CALL
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
.endm
.macro STACK_FRAME_NON_STANDARD func:req
.endm
......
......@@ -57,12 +57,14 @@ struct orc_entry {
unsigned sp_reg:4;
unsigned bp_reg:4;
unsigned type:2;
unsigned signal:1;
unsigned end:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned bp_reg:4;
unsigned sp_reg:4;
unsigned unused:5;
unsigned unused:4;
unsigned end:1;
unsigned signal:1;
unsigned type:2;
#endif
} __packed;
......
......@@ -15,6 +15,7 @@ struct unwind_hint {
s16 sp_offset;
u8 sp_reg;
u8 type;
u8 signal;
u8 end;
};
#endif
......@@ -49,7 +50,7 @@ struct unwind_hint {
#ifndef __ASSEMBLY__
#define UNWIND_HINT(sp_reg, sp_offset, type, end) \
#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \
"987: \n\t" \
".pushsection .discard.unwind_hints\n\t" \
/* struct unwind_hint */ \
......@@ -57,6 +58,7 @@ struct unwind_hint {
".short " __stringify(sp_offset) "\n\t" \
".byte " __stringify(sp_reg) "\n\t" \
".byte " __stringify(type) "\n\t" \
".byte " __stringify(signal) "\n\t" \
".byte " __stringify(end) "\n\t" \
".balign 4 \n\t" \
".popsection\n\t"
......@@ -129,7 +131,7 @@ struct unwind_hint {
* the debuginfo as necessary. It will also warn if it sees any
* inconsistencies.
*/
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
.Lunwind_hint_ip_\@:
.pushsection .discard.unwind_hints
/* struct unwind_hint */
......@@ -137,6 +139,7 @@ struct unwind_hint {
.short \sp_offset
.byte \sp_reg
.byte \type
.byte \signal
.byte \end
.balign 4
.popsection
......@@ -174,7 +177,7 @@ struct unwind_hint {
#ifndef __ASSEMBLY__
#define UNWIND_HINT(sp_reg, sp_offset, type, end) \
#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \
"\n\t"
#define STACK_FRAME_NON_STANDARD(func)
#define STACK_FRAME_NON_STANDARD_FP(func)
......@@ -182,7 +185,7 @@ struct unwind_hint {
#define ASM_REACHABLE
#else
#define ANNOTATE_INTRA_FUNCTION_CALL
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
.endm
.macro STACK_FRAME_NON_STANDARD func:req
.endm
......
......@@ -2,3 +2,4 @@
arch/x86/lib/inat-tables.c
/objtool
fixdep
libsubcmd/
......@@ -16,8 +16,6 @@ objtool-y += libctype.o
objtool-y += str_error_r.o
objtool-y += librbtree.o
CFLAGS += -I$(srctree)/tools/lib
$(OUTPUT)libstring.o: ../lib/string.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
......
......@@ -410,6 +410,14 @@ the objtool maintainers.
can remove this warning by putting the ANNOTATE_INTRA_FUNCTION_CALL
directive right before the call.
12. file.o: warning: func(): not an indirect call target
This means that objtool is running with --ibt and a function expected
to be an indirect call target is not. In particular, this happens for
init_module() or cleanup_module() if a module relies on these special
names and does not use module_init() / module_exit() macros to create
them.
If the error doesn't seem to make sense, it could be a bug in objtool.
Feel free to ask the objtool maintainer for help.
......
......@@ -2,19 +2,18 @@
include ../scripts/Makefile.include
include ../scripts/Makefile.arch
# always use the host compiler
AR = $(HOSTAR)
CC = $(HOSTCC)
LD = $(HOSTLD)
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
endif
SUBCMD_SRCDIR = $(srctree)/tools/lib/subcmd/
LIBSUBCMD_OUTPUT = $(or $(OUTPUT),$(CURDIR)/)
LIBSUBCMD = $(LIBSUBCMD_OUTPUT)libsubcmd.a
LIBSUBCMD_DIR = $(srctree)/tools/lib/subcmd/
ifneq ($(OUTPUT),)
LIBSUBCMD_OUTPUT = $(abspath $(OUTPUT))/libsubcmd
else
LIBSUBCMD_OUTPUT = $(CURDIR)/libsubcmd
endif
LIBSUBCMD = $(LIBSUBCMD_OUTPUT)/libsubcmd.a
OBJTOOL := $(OUTPUT)objtool
OBJTOOL_IN := $(OBJTOOL)-in.o
......@@ -28,16 +27,29 @@ INCLUDES := -I$(srctree)/tools/include \
-I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \
-I$(srctree)/tools/arch/$(SRCARCH)/include \
-I$(srctree)/tools/objtool/include \
-I$(srctree)/tools/objtool/arch/$(SRCARCH)/include
-I$(srctree)/tools/objtool/arch/$(SRCARCH)/include \
-I$(LIBSUBCMD_OUTPUT)/include
# Note, EXTRA_WARNINGS here was determined for CC and not HOSTCC, it
# is passed here to match a legacy behavior.
WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed -Wno-nested-externs
CFLAGS := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS)
LDFLAGS += $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS)
OBJTOOL_CFLAGS := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS)
OBJTOOL_LDFLAGS := $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS)
# Allow old libelf to be used:
elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr)
CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)
elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - | grep elf_getshdr)
OBJTOOL_CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)
# Always want host compilation.
HOST_OVERRIDES := CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)"
AWK = awk
MKDIR = mkdir
ifeq ($(V),1)
Q =
else
Q = @
endif
BUILD_ORC := n
......@@ -49,21 +61,33 @@ export BUILD_ORC
export srctree OUTPUT CFLAGS SRCARCH AWK
include $(srctree)/tools/build/Makefile.include
$(OBJTOOL_IN): fixdep FORCE
@$(CONFIG_SHELL) ./sync-check.sh
@$(MAKE) $(build)=objtool
$(OBJTOOL_IN): fixdep $(LIBSUBCMD) FORCE
$(Q)$(CONFIG_SHELL) ./sync-check.sh
$(Q)$(MAKE) $(build)=objtool $(HOST_OVERRIDES) CFLAGS="$(OBJTOOL_CFLAGS)" \
LDFLAGS="$(OBJTOOL_LDFLAGS)"
$(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN)
$(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@
$(QUIET_LINK)$(HOSTCC) $(OBJTOOL_IN) $(OBJTOOL_LDFLAGS) -o $@
$(LIBSUBCMD_OUTPUT):
$(Q)$(MKDIR) -p $@
$(LIBSUBCMD): fixdep $(LIBSUBCMD_OUTPUT) FORCE
$(Q)$(MAKE) -C $(LIBSUBCMD_DIR) O=$(LIBSUBCMD_OUTPUT) \
DESTDIR=$(LIBSUBCMD_OUTPUT) prefix= subdir= \
$(HOST_OVERRIDES) EXTRA_CFLAGS="$(OBJTOOL_CFLAGS)" \
$@ install_headers
$(LIBSUBCMD): fixdep FORCE
$(Q)$(MAKE) -C $(SUBCMD_SRCDIR) OUTPUT=$(LIBSUBCMD_OUTPUT)
$(LIBSUBCMD)-clean:
$(call QUIET_CLEAN, libsubcmd)
$(Q)$(RM) -r -- $(LIBSUBCMD_OUTPUT)
clean:
clean: $(LIBSUBCMD)-clean
$(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL)
$(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
$(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep $(LIBSUBCMD)
$(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep
FORCE:
......
......@@ -41,38 +41,36 @@ const char *arch_ret_insn(int len)
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)
{
unsigned int opcode;
enum insn_type typ;
unsigned long imm;
u32 insn;
u32 ins;
insn = bswap_if_needed(file->elf, *(u32 *)(sec->data->d_buf + offset));
opcode = insn >> 26;
ins = bswap_if_needed(file->elf, *(u32 *)(sec->data->d_buf + offset));
opcode = ins >> 26;
typ = INSN_OTHER;
imm = 0;
switch (opcode) {
case 18: /* b[l][a] */
if ((insn & 3) == 1) /* bl */
if ((ins & 3) == 1) /* bl */
typ = INSN_CALL;
imm = insn & 0x3fffffc;
imm = ins & 0x3fffffc;
if (imm & 0x2000000)
imm -= 0x4000000;
break;
}
if (opcode == 1)
*len = 8;
insn->len = 8;
else
*len = 4;
insn->len = 4;
*type = typ;
*immediate = imm;
insn->type = typ;
insn->immediate = imm;
return 0;
}
......
......@@ -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;
}
......
......@@ -65,7 +65,7 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)
return found ? 0 : -1;
}
const struct option check_options[] = {
static const struct option check_options[] = {
OPT_GROUP("Actions:"),
OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake", "patch toolchain bugs/limitations", parse_hacks),
OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
......
This diff is collapsed.
......@@ -284,13 +284,13 @@ static int read_sections(struct elf *elf)
!elf_alloc_hash(section_name, sections_nr))
return -1;
for (i = 0; i < sections_nr; i++) {
sec = malloc(sizeof(*sec));
if (!sec) {
perror("malloc");
elf->section_data = calloc(sections_nr, sizeof(*sec));
if (!elf->section_data) {
perror("calloc");
return -1;
}
memset(sec, 0, sizeof(*sec));
for (i = 0; i < sections_nr; i++) {
sec = &elf->section_data[i];
INIT_LIST_HEAD(&sec->symbol_list);
INIT_LIST_HEAD(&sec->reloc_list);
......@@ -422,13 +422,13 @@ static int read_symbols(struct elf *elf)
!elf_alloc_hash(symbol_name, symbols_nr))
return -1;
for (i = 0; i < symbols_nr; i++) {
sym = malloc(sizeof(*sym));
if (!sym) {
perror("malloc");
elf->symbol_data = calloc(symbols_nr, sizeof(*sym));
if (!elf->symbol_data) {
perror("calloc");
return -1;
}
memset(sym, 0, sizeof(*sym));
for (i = 0; i < symbols_nr; i++) {
sym = &elf->symbol_data[i];
sym->idx = i;
......@@ -918,13 +918,13 @@ static int read_relocs(struct elf *elf)
sec->base->reloc = sec;
nr_reloc = 0;
for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
reloc = malloc(sizeof(*reloc));
if (!reloc) {
perror("malloc");
sec->reloc_data = calloc(sec->sh.sh_size / sec->sh.sh_entsize, sizeof(*reloc));
if (!sec->reloc_data) {
perror("calloc");
return -1;
}
memset(reloc, 0, sizeof(*reloc));
for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
reloc = &sec->reloc_data[i];
switch (sec->sh.sh_type) {
case SHT_REL:
if (read_rel_reloc(sec, i, reloc, &symndx))
......@@ -1453,16 +1453,16 @@ void elf_close(struct elf *elf)
list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
list_del(&sym->list);
hash_del(&sym->hash);
free(sym);
}
list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) {
list_del(&reloc->list);
hash_del(&reloc->hash);
free(reloc);
}
list_del(&sec->list);
free(sec);
free(sec->reloc_data);
}
free(elf->symbol_data);
free(elf->section_data);
free(elf);
}
......@@ -62,9 +62,9 @@ struct op_src {
};
struct stack_op {
struct stack_op *next;
struct op_dest dest;
struct op_src src;
struct list_head list;
};
struct instruction;
......@@ -75,9 +75,7 @@ void arch_initial_func_cfi_state(struct cfi_init_state *state);
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);
bool arch_callee_saved_reg(unsigned char reg);
......
......@@ -7,8 +7,6 @@
#include <subcmd/parse-options.h>
extern const struct option check_options[];
struct opts {
/* actions: */
bool dump_orc;
......
......@@ -34,6 +34,7 @@ struct cfi_state {
unsigned char type;
bool bp_scratch;
bool drap;
bool signal;
bool end;
};
......
......@@ -27,7 +27,7 @@ struct alt_group {
struct alt_group *orig_group;
/* First and last instructions in the group */
struct instruction *first_insn, *last_insn;
struct instruction *first_insn, *last_insn, *nop;
/*
* Byte-offset-addressed len-sized array of pointers to CFI structs.
......@@ -36,17 +36,24 @@ struct alt_group {
struct cfi_state **cfi;
};
#define INSN_CHUNK_BITS 8
#define INSN_CHUNK_SIZE (1 << INSN_CHUNK_BITS)
#define INSN_CHUNK_MAX (INSN_CHUNK_SIZE - 1)
struct instruction {
struct list_head list;
struct hlist_node hash;
struct list_head call_node;
struct section *sec;
unsigned long offset;
unsigned int len;
enum insn_type type;
unsigned long immediate;
u16 dead_end : 1,
u8 len;
u8 prev_len;
u8 type;
s8 instr;
u32 idx : INSN_CHUNK_BITS,
dead_end : 1,
ignore : 1,
ignore_alts : 1,
hint : 1,
......@@ -54,21 +61,21 @@ struct instruction {
restore : 1,
retpoline_safe : 1,
noendbr : 1,
entry : 1;
/* 7 bit hole */
s8 instr;
u8 visited;
entry : 1,
visited : 4,
no_reloc : 1;
/* 10 bit hole */
struct alt_group *alt_group;
struct symbol *call_dest;
struct instruction *jump_dest;
struct instruction *first_jump_src;
struct reloc *jump_table;
struct reloc *reloc;
struct list_head alts;
union {
struct symbol *_call_dest;
struct reloc *_jump_table;
};
struct alternative *alts;
struct symbol *sym;
struct list_head stack_ops;
struct stack_op *stack_ops;
struct cfi_state *cfi;
};
......@@ -107,13 +114,11 @@ static inline bool is_jump(struct instruction *insn)
struct instruction *find_insn(struct objtool_file *file,
struct section *sec, unsigned long offset);
#define for_each_insn(file, insn) \
list_for_each_entry(insn, &file->insn_list, list)
struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruction *insn);
#define sec_for_each_insn(file, sec, insn) \
for (insn = find_insn(file, sec, 0); \
insn && &insn->list != &file->insn_list && \
insn->sec == sec; \
insn = list_next_entry(insn, list))
#define sec_for_each_insn(file, _sec, insn) \
for (insn = find_insn(file, _sec, 0); \
insn && insn->sec == _sec; \
insn = next_insn_same_sec(file, insn))
#endif /* _CHECK_H */
......@@ -39,6 +39,7 @@ struct section {
char *name;
int idx;
bool changed, text, rodata, noinstr, init, truncate;
struct reloc *reloc_data;
};
struct symbol {
......@@ -49,12 +50,11 @@ struct symbol {
GElf_Sym sym;
struct section *sec;
char *name;
unsigned int idx;
unsigned char bind, type;
unsigned int idx, len;
unsigned long offset;
unsigned int len;
unsigned long __subtree_last;
struct symbol *pfunc, *cfunc, *alias;
unsigned char bind, type;
u8 uaccess_safe : 1;
u8 static_call_tramp : 1;
u8 retpoline_thunk : 1;
......@@ -104,6 +104,9 @@ struct elf {
struct hlist_head *section_hash;
struct hlist_head *section_name_hash;
struct hlist_head *reloc_hash;
struct section *section_data;
struct symbol *symbol_data;
};
#define OFFSET_STRIDE_BITS 4
......
......@@ -21,7 +21,6 @@ struct pv_state {
struct objtool_file {
struct elf *elf;
struct list_head insn_list;
DECLARE_HASHTABLE(insn_hash, 20);
struct list_head retpoline_call_list;
struct list_head return_thunk_list;
......
......@@ -19,6 +19,7 @@ struct special_alt {
bool skip_orig;
bool skip_alt;
bool jump_or_nop;
u8 key_addend;
struct section *orig_sec;
unsigned long orig_off;
......@@ -27,7 +28,6 @@ struct special_alt {
unsigned long new_off;
unsigned int orig_len, new_len; /* group only */
u8 key_addend;
};
int special_get_alts(struct elf *elf, struct list_head *alts);
......
......@@ -99,7 +99,6 @@ struct objtool_file *objtool_open_read(const char *_objname)
return NULL;
}
INIT_LIST_HEAD(&file.insn_list);
hash_init(file.insn_hash);
INIT_LIST_HEAD(&file.retpoline_call_list);
INIT_LIST_HEAD(&file.return_thunk_list);
......
......@@ -211,8 +211,8 @@ int orc_dump(const char *_objname)
print_reg(orc[i].bp_reg, bswap_if_needed(&dummy_elf, orc[i].bp_offset));
printf(" type:%s end:%d\n",
orc_type_name(orc[i].type), orc[i].end);
printf(" type:%s signal:%d end:%d\n",
orc_type_name(orc[i].type), orc[i].signal, orc[i].end);
}
elf_end(elf);
......
......@@ -27,6 +27,7 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,
}
orc->end = cfi->end;
orc->signal = cfi->signal;
if (cfi->cfa.base == CFI_UNDEFINED) {
orc->sp_reg = ORC_REG_UNDEFINED;
......
......@@ -26,7 +26,7 @@ struct special_entry {
unsigned char key; /* jump_label key */
};
struct special_entry entries[] = {
static const struct special_entry entries[] = {
{
.sec = ".altinstructions",
.group = true,
......@@ -65,7 +65,7 @@ static void reloc_to_sec_off(struct reloc *reloc, struct section **sec,
*off = reloc->sym->offset + reloc->addend;
}
static int get_alt_entry(struct elf *elf, struct special_entry *entry,
static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
struct section *sec, int idx,
struct special_alt *alt)
{
......@@ -139,7 +139,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry,
*/
int special_get_alts(struct elf *elf, struct list_head *alts)
{
struct special_entry *entry;
const struct special_entry *entry;
struct section *sec;
unsigned int nr_entries;
struct special_alt *alt;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment