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) ...@@ -385,7 +385,14 @@ SYM_CODE_END(xen_error_entry)
*/ */
.macro idtentry vector asmsym cfunc has_error_code:req .macro idtentry vector asmsym cfunc has_error_code:req
SYM_CODE_START(\asmsym) SYM_CODE_START(\asmsym)
UNWIND_HINT_IRET_REGS offset=\has_error_code*8
.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 ENDBR
ASM_CLAC ASM_CLAC
cld cld
......
...@@ -261,7 +261,7 @@ ...@@ -261,7 +261,7 @@
.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req ftr2=ALT_NOT(X86_FEATURE_ALWAYS) .macro FILL_RETURN_BUFFER reg:req nr:req ftr:req ftr2=ALT_NOT(X86_FEATURE_ALWAYS)
ALTERNATIVE_2 "jmp .Lskip_rsb_\@", \ ALTERNATIVE_2 "jmp .Lskip_rsb_\@", \
__stringify(__FILL_RETURN_BUFFER(\reg,\nr)), \ftr, \ __stringify(__FILL_RETURN_BUFFER(\reg,\nr)), \ftr, \
__stringify(__FILL_ONE_RETURN), \ftr2 __stringify(nop;nop;__FILL_ONE_RETURN), \ftr2
.Lskip_rsb_\@: .Lskip_rsb_\@:
.endm .endm
......
...@@ -57,12 +57,14 @@ struct orc_entry { ...@@ -57,12 +57,14 @@ struct orc_entry {
unsigned sp_reg:4; unsigned sp_reg:4;
unsigned bp_reg:4; unsigned bp_reg:4;
unsigned type:2; unsigned type:2;
unsigned signal:1;
unsigned end:1; unsigned end:1;
#elif defined(__BIG_ENDIAN_BITFIELD) #elif defined(__BIG_ENDIAN_BITFIELD)
unsigned bp_reg:4; unsigned bp_reg:4;
unsigned sp_reg:4; unsigned sp_reg:4;
unsigned unused:5; unsigned unused:4;
unsigned end:1; unsigned end:1;
unsigned signal:1;
unsigned type:2; unsigned type:2;
#endif #endif
} __packed; } __packed;
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1 UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1
.endm .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 \base == %rsp
.if \indirect .if \indirect
.set sp_reg, ORC_REG_SP_INDIRECT .set sp_reg, ORC_REG_SP_INDIRECT
...@@ -45,11 +45,11 @@ ...@@ -45,11 +45,11 @@
.set type, UNWIND_HINT_TYPE_REGS .set type, UNWIND_HINT_TYPE_REGS
.endif .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 .endm
.macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 .macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 signal=1
UNWIND_HINT_REGS base=\base offset=\offset partial=1 UNWIND_HINT_REGS base=\base offset=\offset partial=1 signal=\signal
.endm .endm
.macro UNWIND_HINT_FUNC .macro UNWIND_HINT_FUNC
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
#else #else
#define UNWIND_HINT_FUNC \ #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__ */ #endif /* __ASSEMBLY__ */
......
...@@ -484,6 +484,8 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -484,6 +484,8 @@ bool unwind_next_frame(struct unwind_state *state)
goto the_end; goto the_end;
} }
state->signal = orc->signal;
/* Find the previous frame's stack: */ /* Find the previous frame's stack: */
switch (orc->sp_reg) { switch (orc->sp_reg) {
case ORC_REG_SP: case ORC_REG_SP:
...@@ -563,7 +565,6 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -563,7 +565,6 @@ bool unwind_next_frame(struct unwind_state *state)
state->sp = sp; state->sp = sp;
state->regs = NULL; state->regs = NULL;
state->prev_regs = NULL; state->prev_regs = NULL;
state->signal = false;
break; break;
case UNWIND_HINT_TYPE_REGS: case UNWIND_HINT_TYPE_REGS:
...@@ -587,7 +588,6 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -587,7 +588,6 @@ bool unwind_next_frame(struct unwind_state *state)
state->regs = (struct pt_regs *)sp; state->regs = (struct pt_regs *)sp;
state->prev_regs = NULL; state->prev_regs = NULL;
state->full_regs = true; state->full_regs = true;
state->signal = true;
break; break;
case UNWIND_HINT_TYPE_REGS_PARTIAL: case UNWIND_HINT_TYPE_REGS_PARTIAL:
...@@ -604,7 +604,6 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -604,7 +604,6 @@ bool unwind_next_frame(struct unwind_state *state)
state->prev_regs = state->regs; state->prev_regs = state->regs;
state->regs = (void *)sp - IRET_FRAME_OFFSET; state->regs = (void *)sp - IRET_FRAME_OFFSET;
state->full_regs = false; state->full_regs = false;
state->signal = true;
break; break;
default: default:
......
...@@ -15,6 +15,7 @@ struct unwind_hint { ...@@ -15,6 +15,7 @@ struct unwind_hint {
s16 sp_offset; s16 sp_offset;
u8 sp_reg; u8 sp_reg;
u8 type; u8 type;
u8 signal;
u8 end; u8 end;
}; };
#endif #endif
...@@ -49,7 +50,7 @@ struct unwind_hint { ...@@ -49,7 +50,7 @@ struct unwind_hint {
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define UNWIND_HINT(sp_reg, sp_offset, type, end) \ #define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \
"987: \n\t" \ "987: \n\t" \
".pushsection .discard.unwind_hints\n\t" \ ".pushsection .discard.unwind_hints\n\t" \
/* struct unwind_hint */ \ /* struct unwind_hint */ \
...@@ -57,6 +58,7 @@ struct unwind_hint { ...@@ -57,6 +58,7 @@ struct unwind_hint {
".short " __stringify(sp_offset) "\n\t" \ ".short " __stringify(sp_offset) "\n\t" \
".byte " __stringify(sp_reg) "\n\t" \ ".byte " __stringify(sp_reg) "\n\t" \
".byte " __stringify(type) "\n\t" \ ".byte " __stringify(type) "\n\t" \
".byte " __stringify(signal) "\n\t" \
".byte " __stringify(end) "\n\t" \ ".byte " __stringify(end) "\n\t" \
".balign 4 \n\t" \ ".balign 4 \n\t" \
".popsection\n\t" ".popsection\n\t"
...@@ -129,7 +131,7 @@ struct unwind_hint { ...@@ -129,7 +131,7 @@ struct unwind_hint {
* the debuginfo as necessary. It will also warn if it sees any * the debuginfo as necessary. It will also warn if it sees any
* inconsistencies. * 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_\@: .Lunwind_hint_ip_\@:
.pushsection .discard.unwind_hints .pushsection .discard.unwind_hints
/* struct unwind_hint */ /* struct unwind_hint */
...@@ -137,6 +139,7 @@ struct unwind_hint { ...@@ -137,6 +139,7 @@ struct unwind_hint {
.short \sp_offset .short \sp_offset
.byte \sp_reg .byte \sp_reg
.byte \type .byte \type
.byte \signal
.byte \end .byte \end
.balign 4 .balign 4
.popsection .popsection
...@@ -174,7 +177,7 @@ struct unwind_hint { ...@@ -174,7 +177,7 @@ struct unwind_hint {
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define UNWIND_HINT(sp_reg, sp_offset, type, end) \ #define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \
"\n\t" "\n\t"
#define STACK_FRAME_NON_STANDARD(func) #define STACK_FRAME_NON_STANDARD(func)
#define STACK_FRAME_NON_STANDARD_FP(func) #define STACK_FRAME_NON_STANDARD_FP(func)
...@@ -182,7 +185,7 @@ struct unwind_hint { ...@@ -182,7 +185,7 @@ struct unwind_hint {
#define ASM_REACHABLE #define ASM_REACHABLE
#else #else
#define ANNOTATE_INTRA_FUNCTION_CALL #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 .endm
.macro STACK_FRAME_NON_STANDARD func:req .macro STACK_FRAME_NON_STANDARD func:req
.endm .endm
......
...@@ -57,12 +57,14 @@ struct orc_entry { ...@@ -57,12 +57,14 @@ struct orc_entry {
unsigned sp_reg:4; unsigned sp_reg:4;
unsigned bp_reg:4; unsigned bp_reg:4;
unsigned type:2; unsigned type:2;
unsigned signal:1;
unsigned end:1; unsigned end:1;
#elif defined(__BIG_ENDIAN_BITFIELD) #elif defined(__BIG_ENDIAN_BITFIELD)
unsigned bp_reg:4; unsigned bp_reg:4;
unsigned sp_reg:4; unsigned sp_reg:4;
unsigned unused:5; unsigned unused:4;
unsigned end:1; unsigned end:1;
unsigned signal:1;
unsigned type:2; unsigned type:2;
#endif #endif
} __packed; } __packed;
......
...@@ -15,6 +15,7 @@ struct unwind_hint { ...@@ -15,6 +15,7 @@ struct unwind_hint {
s16 sp_offset; s16 sp_offset;
u8 sp_reg; u8 sp_reg;
u8 type; u8 type;
u8 signal;
u8 end; u8 end;
}; };
#endif #endif
...@@ -49,7 +50,7 @@ struct unwind_hint { ...@@ -49,7 +50,7 @@ struct unwind_hint {
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define UNWIND_HINT(sp_reg, sp_offset, type, end) \ #define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \
"987: \n\t" \ "987: \n\t" \
".pushsection .discard.unwind_hints\n\t" \ ".pushsection .discard.unwind_hints\n\t" \
/* struct unwind_hint */ \ /* struct unwind_hint */ \
...@@ -57,6 +58,7 @@ struct unwind_hint { ...@@ -57,6 +58,7 @@ struct unwind_hint {
".short " __stringify(sp_offset) "\n\t" \ ".short " __stringify(sp_offset) "\n\t" \
".byte " __stringify(sp_reg) "\n\t" \ ".byte " __stringify(sp_reg) "\n\t" \
".byte " __stringify(type) "\n\t" \ ".byte " __stringify(type) "\n\t" \
".byte " __stringify(signal) "\n\t" \
".byte " __stringify(end) "\n\t" \ ".byte " __stringify(end) "\n\t" \
".balign 4 \n\t" \ ".balign 4 \n\t" \
".popsection\n\t" ".popsection\n\t"
...@@ -129,7 +131,7 @@ struct unwind_hint { ...@@ -129,7 +131,7 @@ struct unwind_hint {
* the debuginfo as necessary. It will also warn if it sees any * the debuginfo as necessary. It will also warn if it sees any
* inconsistencies. * 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_\@: .Lunwind_hint_ip_\@:
.pushsection .discard.unwind_hints .pushsection .discard.unwind_hints
/* struct unwind_hint */ /* struct unwind_hint */
...@@ -137,6 +139,7 @@ struct unwind_hint { ...@@ -137,6 +139,7 @@ struct unwind_hint {
.short \sp_offset .short \sp_offset
.byte \sp_reg .byte \sp_reg
.byte \type .byte \type
.byte \signal
.byte \end .byte \end
.balign 4 .balign 4
.popsection .popsection
...@@ -174,7 +177,7 @@ struct unwind_hint { ...@@ -174,7 +177,7 @@ struct unwind_hint {
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define UNWIND_HINT(sp_reg, sp_offset, type, end) \ #define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \
"\n\t" "\n\t"
#define STACK_FRAME_NON_STANDARD(func) #define STACK_FRAME_NON_STANDARD(func)
#define STACK_FRAME_NON_STANDARD_FP(func) #define STACK_FRAME_NON_STANDARD_FP(func)
...@@ -182,7 +185,7 @@ struct unwind_hint { ...@@ -182,7 +185,7 @@ struct unwind_hint {
#define ASM_REACHABLE #define ASM_REACHABLE
#else #else
#define ANNOTATE_INTRA_FUNCTION_CALL #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 .endm
.macro STACK_FRAME_NON_STANDARD func:req .macro STACK_FRAME_NON_STANDARD func:req
.endm .endm
......
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
arch/x86/lib/inat-tables.c arch/x86/lib/inat-tables.c
/objtool /objtool
fixdep fixdep
libsubcmd/
...@@ -16,8 +16,6 @@ objtool-y += libctype.o ...@@ -16,8 +16,6 @@ objtool-y += libctype.o
objtool-y += str_error_r.o objtool-y += str_error_r.o
objtool-y += librbtree.o objtool-y += librbtree.o
CFLAGS += -I$(srctree)/tools/lib
$(OUTPUT)libstring.o: ../lib/string.c FORCE $(OUTPUT)libstring.o: ../lib/string.c FORCE
$(call rule_mkdir) $(call rule_mkdir)
$(call if_changed_dep,cc_o_c) $(call if_changed_dep,cc_o_c)
......
...@@ -410,6 +410,14 @@ the objtool maintainers. ...@@ -410,6 +410,14 @@ the objtool maintainers.
can remove this warning by putting the ANNOTATE_INTRA_FUNCTION_CALL can remove this warning by putting the ANNOTATE_INTRA_FUNCTION_CALL
directive right before the 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. 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. Feel free to ask the objtool maintainer for help.
......
...@@ -2,19 +2,18 @@ ...@@ -2,19 +2,18 @@
include ../scripts/Makefile.include include ../scripts/Makefile.include
include ../scripts/Makefile.arch include ../scripts/Makefile.arch
# always use the host compiler
AR = $(HOSTAR)
CC = $(HOSTCC)
LD = $(HOSTLD)
ifeq ($(srctree),) ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(CURDIR))) srctree := $(patsubst %/,%,$(dir $(CURDIR)))
srctree := $(patsubst %/,%,$(dir $(srctree))) srctree := $(patsubst %/,%,$(dir $(srctree)))
endif endif
SUBCMD_SRCDIR = $(srctree)/tools/lib/subcmd/ LIBSUBCMD_DIR = $(srctree)/tools/lib/subcmd/
LIBSUBCMD_OUTPUT = $(or $(OUTPUT),$(CURDIR)/) ifneq ($(OUTPUT),)
LIBSUBCMD = $(LIBSUBCMD_OUTPUT)libsubcmd.a LIBSUBCMD_OUTPUT = $(abspath $(OUTPUT))/libsubcmd
else
LIBSUBCMD_OUTPUT = $(CURDIR)/libsubcmd
endif
LIBSUBCMD = $(LIBSUBCMD_OUTPUT)/libsubcmd.a
OBJTOOL := $(OUTPUT)objtool OBJTOOL := $(OUTPUT)objtool
OBJTOOL_IN := $(OBJTOOL)-in.o OBJTOOL_IN := $(OBJTOOL)-in.o
...@@ -28,16 +27,29 @@ INCLUDES := -I$(srctree)/tools/include \ ...@@ -28,16 +27,29 @@ INCLUDES := -I$(srctree)/tools/include \
-I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \ -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \
-I$(srctree)/tools/arch/$(SRCARCH)/include \ -I$(srctree)/tools/arch/$(SRCARCH)/include \
-I$(srctree)/tools/objtool/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 WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed -Wno-nested-externs
CFLAGS := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS) OBJTOOL_CFLAGS := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS)
LDFLAGS += $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) OBJTOOL_LDFLAGS := $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS)
# Allow old libelf to be used: # Allow old libelf to be used:
elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr) elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - | grep elf_getshdr)
CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) OBJTOOL_CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)
# Always want host compilation.
HOST_OVERRIDES := CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)"
AWK = awk AWK = awk
MKDIR = mkdir
ifeq ($(V),1)
Q =
else
Q = @
endif
BUILD_ORC := n BUILD_ORC := n
...@@ -49,21 +61,33 @@ export BUILD_ORC ...@@ -49,21 +61,33 @@ export BUILD_ORC
export srctree OUTPUT CFLAGS SRCARCH AWK export srctree OUTPUT CFLAGS SRCARCH AWK
include $(srctree)/tools/build/Makefile.include include $(srctree)/tools/build/Makefile.include
$(OBJTOOL_IN): fixdep FORCE $(OBJTOOL_IN): fixdep $(LIBSUBCMD) FORCE
@$(CONFIG_SHELL) ./sync-check.sh $(Q)$(CONFIG_SHELL) ./sync-check.sh
@$(MAKE) $(build)=objtool $(Q)$(MAKE) $(build)=objtool $(HOST_OVERRIDES) CFLAGS="$(OBJTOOL_CFLAGS)" \
LDFLAGS="$(OBJTOOL_LDFLAGS)"
$(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) $(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 $(LIBSUBCMD)-clean:
$(Q)$(MAKE) -C $(SUBCMD_SRCDIR) OUTPUT=$(LIBSUBCMD_OUTPUT) $(call QUIET_CLEAN, libsubcmd)
$(Q)$(RM) -r -- $(LIBSUBCMD_OUTPUT)
clean: clean: $(LIBSUBCMD)-clean
$(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL)
$(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete $(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: FORCE:
......
...@@ -41,38 +41,36 @@ const char *arch_ret_insn(int len) ...@@ -41,38 +41,36 @@ const char *arch_ret_insn(int len)
int arch_decode_instruction(struct objtool_file *file, const struct section *sec, int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
unsigned long offset, unsigned int maxlen, unsigned long offset, unsigned int maxlen,
unsigned int *len, enum insn_type *type, struct instruction *insn)
unsigned long *immediate,
struct list_head *ops_list)
{ {
unsigned int opcode; unsigned int opcode;
enum insn_type typ; enum insn_type typ;
unsigned long imm; unsigned long imm;
u32 insn; u32 ins;
insn = bswap_if_needed(file->elf, *(u32 *)(sec->data->d_buf + offset)); ins = bswap_if_needed(file->elf, *(u32 *)(sec->data->d_buf + offset));
opcode = insn >> 26; opcode = ins >> 26;
typ = INSN_OTHER; typ = INSN_OTHER;
imm = 0; imm = 0;
switch (opcode) { switch (opcode) {
case 18: /* b[l][a] */ case 18: /* b[l][a] */
if ((insn & 3) == 1) /* bl */ if ((ins & 3) == 1) /* bl */
typ = INSN_CALL; typ = INSN_CALL;
imm = insn & 0x3fffffc; imm = ins & 0x3fffffc;
if (imm & 0x2000000) if (imm & 0x2000000)
imm -= 0x4000000; imm -= 0x4000000;
break; break;
} }
if (opcode == 1) if (opcode == 1)
*len = 8; insn->len = 8;
else else
*len = 4; insn->len = 4;
*type = typ; insn->type = typ;
*immediate = imm; insn->immediate = imm;
return 0; return 0;
} }
......
...@@ -105,7 +105,7 @@ bool arch_pc_relative_reloc(struct reloc *reloc) ...@@ -105,7 +105,7 @@ bool arch_pc_relative_reloc(struct reloc *reloc)
#define ADD_OP(op) \ #define ADD_OP(op) \
if (!(op = calloc(1, sizeof(*op)))) \ if (!(op = calloc(1, sizeof(*op)))) \
return -1; \ 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: * Helpers to decode ModRM/SIB:
...@@ -146,12 +146,11 @@ static bool has_notrack_prefix(struct insn *insn) ...@@ -146,12 +146,11 @@ static bool has_notrack_prefix(struct insn *insn)
int arch_decode_instruction(struct objtool_file *file, const struct section *sec, int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
unsigned long offset, unsigned int maxlen, unsigned long offset, unsigned int maxlen,
unsigned int *len, enum insn_type *type, struct instruction *insn)
unsigned long *immediate,
struct list_head *ops_list)
{ {
struct stack_op **ops_list = &insn->stack_ops;
const struct elf *elf = file->elf; const struct elf *elf = file->elf;
struct insn insn; struct insn ins;
int x86_64, ret; int x86_64, ret;
unsigned char op1, op2, op3, prefix, unsigned char op1, op2, op3, prefix,
rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0, 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 ...@@ -165,42 +164,42 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
if (x86_64 == -1) if (x86_64 == -1)
return -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); x86_64 ? INSN_MODE_64 : INSN_MODE_32);
if (ret < 0) { if (ret < 0) {
WARN("can't decode instruction at %s:0x%lx", sec->name, offset); WARN("can't decode instruction at %s:0x%lx", sec->name, offset);
return -1; return -1;
} }
*len = insn.length; insn->len = ins.length;
*type = INSN_OTHER; insn->type = INSN_OTHER;
if (insn.vex_prefix.nbytes) if (ins.vex_prefix.nbytes)
return 0; return 0;
prefix = insn.prefixes.bytes[0]; prefix = ins.prefixes.bytes[0];
op1 = insn.opcode.bytes[0]; op1 = ins.opcode.bytes[0];
op2 = insn.opcode.bytes[1]; op2 = ins.opcode.bytes[1];
op3 = insn.opcode.bytes[2]; op3 = ins.opcode.bytes[2];
if (insn.rex_prefix.nbytes) { if (ins.rex_prefix.nbytes) {
rex = insn.rex_prefix.bytes[0]; rex = ins.rex_prefix.bytes[0];
rex_w = X86_REX_W(rex) >> 3; rex_w = X86_REX_W(rex) >> 3;
rex_r = X86_REX_R(rex) >> 2; rex_r = X86_REX_R(rex) >> 2;
rex_x = X86_REX_X(rex) >> 1; rex_x = X86_REX_X(rex) >> 1;
rex_b = X86_REX_B(rex); rex_b = X86_REX_B(rex);
} }
if (insn.modrm.nbytes) { if (ins.modrm.nbytes) {
modrm = insn.modrm.bytes[0]; modrm = ins.modrm.bytes[0];
modrm_mod = X86_MODRM_MOD(modrm); modrm_mod = X86_MODRM_MOD(modrm);
modrm_reg = X86_MODRM_REG(modrm) + 8*rex_r; modrm_reg = X86_MODRM_REG(modrm) + 8*rex_r;
modrm_rm = X86_MODRM_RM(modrm) + 8*rex_b; modrm_rm = X86_MODRM_RM(modrm) + 8*rex_b;
} }
if (insn.sib.nbytes) { if (ins.sib.nbytes) {
sib = insn.sib.bytes[0]; sib = ins.sib.bytes[0];
/* sib_scale = X86_SIB_SCALE(sib); */ /* sib_scale = X86_SIB_SCALE(sib); */
sib_index = X86_SIB_INDEX(sib) + 8*rex_x; sib_index = X86_SIB_INDEX(sib) + 8*rex_x;
sib_base = X86_SIB_BASE(sib) + 8*rex_b; 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 ...@@ -254,7 +253,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
break; break;
case 0x70 ... 0x7f: case 0x70 ... 0x7f:
*type = INSN_JUMP_CONDITIONAL; insn->type = INSN_JUMP_CONDITIONAL;
break; break;
case 0x80 ... 0x83: case 0x80 ... 0x83:
...@@ -278,7 +277,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -278,7 +277,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
if (!rm_is_reg(CFI_SP)) if (!rm_is_reg(CFI_SP))
break; break;
imm = insn.immediate.value; imm = ins.immediate.value;
if (op1 & 2) { /* sign extend */ if (op1 & 2) { /* sign extend */
if (op1 & 1) { /* imm32 */ if (op1 & 1) { /* imm32 */
imm <<= 32; imm <<= 32;
...@@ -309,7 +308,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -309,7 +308,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_AND; op->src.type = OP_SRC_AND;
op->src.reg = CFI_SP; 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.type = OP_DEST_REG;
op->dest.reg = CFI_SP; op->dest.reg = CFI_SP;
} }
...@@ -356,7 +355,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -356,7 +355,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
op->src.reg = CFI_SP; op->src.reg = CFI_SP;
op->dest.type = OP_DEST_REG_INDIRECT; op->dest.type = OP_DEST_REG_INDIRECT;
op->dest.reg = modrm_rm; op->dest.reg = modrm_rm;
op->dest.offset = insn.displacement.value; op->dest.offset = ins.displacement.value;
} }
break; break;
} }
...@@ -389,7 +388,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -389,7 +388,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
op->src.reg = modrm_reg; op->src.reg = modrm_reg;
op->dest.type = OP_DEST_REG_INDIRECT; op->dest.type = OP_DEST_REG_INDIRECT;
op->dest.reg = CFI_BP; op->dest.reg = CFI_BP;
op->dest.offset = insn.displacement.value; op->dest.offset = ins.displacement.value;
} }
break; break;
} }
...@@ -402,7 +401,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -402,7 +401,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
op->src.reg = modrm_reg; op->src.reg = modrm_reg;
op->dest.type = OP_DEST_REG_INDIRECT; op->dest.type = OP_DEST_REG_INDIRECT;
op->dest.reg = CFI_SP; op->dest.reg = CFI_SP;
op->dest.offset = insn.displacement.value; op->dest.offset = ins.displacement.value;
} }
break; break;
} }
...@@ -419,7 +418,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -419,7 +418,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_REG_INDIRECT; op->src.type = OP_SRC_REG_INDIRECT;
op->src.reg = CFI_BP; 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.type = OP_DEST_REG;
op->dest.reg = modrm_reg; op->dest.reg = modrm_reg;
} }
...@@ -432,7 +431,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -432,7 +431,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
ADD_OP(op) { ADD_OP(op) {
op->src.type = OP_SRC_REG_INDIRECT; op->src.type = OP_SRC_REG_INDIRECT;
op->src.reg = CFI_SP; 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.type = OP_DEST_REG;
op->dest.reg = modrm_reg; op->dest.reg = modrm_reg;
} }
...@@ -464,7 +463,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -464,7 +463,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
/* lea disp(%src), %dst */ /* lea disp(%src), %dst */
ADD_OP(op) { ADD_OP(op) {
op->src.offset = insn.displacement.value; op->src.offset = ins.displacement.value;
if (!op->src.offset) { if (!op->src.offset) {
/* lea (%src), %dst */ /* lea (%src), %dst */
op->src.type = OP_SRC_REG; op->src.type = OP_SRC_REG;
...@@ -487,7 +486,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -487,7 +486,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
break; break;
case 0x90: case 0x90:
*type = INSN_NOP; insn->type = INSN_NOP;
break; break;
case 0x9c: case 0x9c:
...@@ -511,39 +510,39 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -511,39 +510,39 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
if (op2 == 0x01) { if (op2 == 0x01) {
if (modrm == 0xca) if (modrm == 0xca)
*type = INSN_CLAC; insn->type = INSN_CLAC;
else if (modrm == 0xcb) else if (modrm == 0xcb)
*type = INSN_STAC; insn->type = INSN_STAC;
} else if (op2 >= 0x80 && op2 <= 0x8f) { } else if (op2 >= 0x80 && op2 <= 0x8f) {
*type = INSN_JUMP_CONDITIONAL; insn->type = INSN_JUMP_CONDITIONAL;
} else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 ||
op2 == 0x35) { op2 == 0x35) {
/* sysenter, sysret */ /* sysenter, sysret */
*type = INSN_CONTEXT_SWITCH; insn->type = INSN_CONTEXT_SWITCH;
} else if (op2 == 0x0b || op2 == 0xb9) { } else if (op2 == 0x0b || op2 == 0xb9) {
/* ud2 */ /* ud2 */
*type = INSN_BUG; insn->type = INSN_BUG;
} else if (op2 == 0x0d || op2 == 0x1f) { } else if (op2 == 0x0d || op2 == 0x1f) {
/* nopl/nopw */ /* nopl/nopw */
*type = INSN_NOP; insn->type = INSN_NOP;
} else if (op2 == 0x1e) { } else if (op2 == 0x1e) {
if (prefix == 0xf3 && (modrm == 0xfa || modrm == 0xfb)) if (prefix == 0xf3 && (modrm == 0xfa || modrm == 0xfb))
*type = INSN_ENDBR; insn->type = INSN_ENDBR;
} else if (op2 == 0x38 && op3 == 0xf8) { } else if (op2 == 0x38 && op3 == 0xf8) {
if (insn.prefixes.nbytes == 1 && if (ins.prefixes.nbytes == 1 &&
insn.prefixes.bytes[0] == 0xf2) { ins.prefixes.bytes[0] == 0xf2) {
/* ENQCMD cannot be used in the kernel. */ /* ENQCMD cannot be used in the kernel. */
WARN("ENQCMD instruction at %s:%lx", sec->name, WARN("ENQCMD instruction at %s:%lx", sec->name,
offset); offset);
...@@ -591,29 +590,29 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -591,29 +590,29 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
case 0xcc: case 0xcc:
/* int3 */ /* int3 */
*type = INSN_TRAP; insn->type = INSN_TRAP;
break; break;
case 0xe3: case 0xe3:
/* jecxz/jrcxz */ /* jecxz/jrcxz */
*type = INSN_JUMP_CONDITIONAL; insn->type = INSN_JUMP_CONDITIONAL;
break; break;
case 0xe9: case 0xe9:
case 0xeb: case 0xeb:
*type = INSN_JUMP_UNCONDITIONAL; insn->type = INSN_JUMP_UNCONDITIONAL;
break; break;
case 0xc2: case 0xc2:
case 0xc3: case 0xc3:
*type = INSN_RETURN; insn->type = INSN_RETURN;
break; break;
case 0xc7: /* mov imm, r/m */ case 0xc7: /* mov imm, r/m */
if (!opts.noinstr) if (!opts.noinstr)
break; 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 reloc *immr, *disp;
struct symbol *func; struct symbol *func;
int idx; int idx;
...@@ -661,17 +660,17 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -661,17 +660,17 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
case 0xca: /* retf */ case 0xca: /* retf */
case 0xcb: /* retf */ case 0xcb: /* retf */
*type = INSN_CONTEXT_SWITCH; insn->type = INSN_CONTEXT_SWITCH;
break; break;
case 0xe0: /* loopne */ case 0xe0: /* loopne */
case 0xe1: /* loope */ case 0xe1: /* loope */
case 0xe2: /* loop */ case 0xe2: /* loop */
*type = INSN_JUMP_CONDITIONAL; insn->type = INSN_JUMP_CONDITIONAL;
break; break;
case 0xe8: case 0xe8:
*type = INSN_CALL; insn->type = INSN_CALL;
/* /*
* For the impact on the stack, a CALL behaves like * For the impact on the stack, a CALL behaves like
* a PUSH of an immediate value (the return address). * 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 ...@@ -683,30 +682,30 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
break; break;
case 0xfc: case 0xfc:
*type = INSN_CLD; insn->type = INSN_CLD;
break; break;
case 0xfd: case 0xfd:
*type = INSN_STD; insn->type = INSN_STD;
break; break;
case 0xff: case 0xff:
if (modrm_reg == 2 || modrm_reg == 3) { if (modrm_reg == 2 || modrm_reg == 3) {
*type = INSN_CALL_DYNAMIC; insn->type = INSN_CALL_DYNAMIC;
if (has_notrack_prefix(&insn)) if (has_notrack_prefix(&ins))
WARN("notrack prefix found at %s:0x%lx", sec->name, offset); WARN("notrack prefix found at %s:0x%lx", sec->name, offset);
} else if (modrm_reg == 4) { } else if (modrm_reg == 4) {
*type = INSN_JUMP_DYNAMIC; insn->type = INSN_JUMP_DYNAMIC;
if (has_notrack_prefix(&insn)) if (has_notrack_prefix(&ins))
WARN("notrack prefix found at %s:0x%lx", sec->name, offset); WARN("notrack prefix found at %s:0x%lx", sec->name, offset);
} else if (modrm_reg == 5) { } else if (modrm_reg == 5) {
/* jmpf */ /* jmpf */
*type = INSN_CONTEXT_SWITCH; insn->type = INSN_CONTEXT_SWITCH;
} else if (modrm_reg == 6) { } else if (modrm_reg == 6) {
...@@ -723,7 +722,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -723,7 +722,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
break; break;
} }
*immediate = insn.immediate.nbytes ? insn.immediate.value : 0; insn->immediate = ins.immediate.nbytes ? ins.immediate.value : 0;
return 0; return 0;
} }
......
...@@ -65,7 +65,7 @@ static int parse_hacks(const struct option *opt, const char *str, int unset) ...@@ -65,7 +65,7 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)
return found ? 0 : -1; return found ? 0 : -1;
} }
const struct option check_options[] = { static const struct option check_options[] = {
OPT_GROUP("Actions:"), OPT_GROUP("Actions:"),
OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake", "patch toolchain bugs/limitations", parse_hacks), 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"), 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) ...@@ -284,13 +284,13 @@ static int read_sections(struct elf *elf)
!elf_alloc_hash(section_name, sections_nr)) !elf_alloc_hash(section_name, sections_nr))
return -1; return -1;
elf->section_data = calloc(sections_nr, sizeof(*sec));
if (!elf->section_data) {
perror("calloc");
return -1;
}
for (i = 0; i < sections_nr; i++) { for (i = 0; i < sections_nr; i++) {
sec = malloc(sizeof(*sec)); sec = &elf->section_data[i];
if (!sec) {
perror("malloc");
return -1;
}
memset(sec, 0, sizeof(*sec));
INIT_LIST_HEAD(&sec->symbol_list); INIT_LIST_HEAD(&sec->symbol_list);
INIT_LIST_HEAD(&sec->reloc_list); INIT_LIST_HEAD(&sec->reloc_list);
...@@ -422,13 +422,13 @@ static int read_symbols(struct elf *elf) ...@@ -422,13 +422,13 @@ static int read_symbols(struct elf *elf)
!elf_alloc_hash(symbol_name, symbols_nr)) !elf_alloc_hash(symbol_name, symbols_nr))
return -1; return -1;
elf->symbol_data = calloc(symbols_nr, sizeof(*sym));
if (!elf->symbol_data) {
perror("calloc");
return -1;
}
for (i = 0; i < symbols_nr; i++) { for (i = 0; i < symbols_nr; i++) {
sym = malloc(sizeof(*sym)); sym = &elf->symbol_data[i];
if (!sym) {
perror("malloc");
return -1;
}
memset(sym, 0, sizeof(*sym));
sym->idx = i; sym->idx = i;
...@@ -918,13 +918,13 @@ static int read_relocs(struct elf *elf) ...@@ -918,13 +918,13 @@ static int read_relocs(struct elf *elf)
sec->base->reloc = sec; sec->base->reloc = sec;
nr_reloc = 0; nr_reloc = 0;
sec->reloc_data = calloc(sec->sh.sh_size / sec->sh.sh_entsize, sizeof(*reloc));
if (!sec->reloc_data) {
perror("calloc");
return -1;
}
for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
reloc = malloc(sizeof(*reloc)); reloc = &sec->reloc_data[i];
if (!reloc) {
perror("malloc");
return -1;
}
memset(reloc, 0, sizeof(*reloc));
switch (sec->sh.sh_type) { switch (sec->sh.sh_type) {
case SHT_REL: case SHT_REL:
if (read_rel_reloc(sec, i, reloc, &symndx)) if (read_rel_reloc(sec, i, reloc, &symndx))
...@@ -1453,16 +1453,16 @@ void elf_close(struct elf *elf) ...@@ -1453,16 +1453,16 @@ void elf_close(struct elf *elf)
list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
list_del(&sym->list); list_del(&sym->list);
hash_del(&sym->hash); hash_del(&sym->hash);
free(sym);
} }
list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) { list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) {
list_del(&reloc->list); list_del(&reloc->list);
hash_del(&reloc->hash); hash_del(&reloc->hash);
free(reloc);
} }
list_del(&sec->list); list_del(&sec->list);
free(sec); free(sec->reloc_data);
} }
free(elf->symbol_data);
free(elf->section_data);
free(elf); free(elf);
} }
...@@ -62,9 +62,9 @@ struct op_src { ...@@ -62,9 +62,9 @@ struct op_src {
}; };
struct stack_op { struct stack_op {
struct stack_op *next;
struct op_dest dest; struct op_dest dest;
struct op_src src; struct op_src src;
struct list_head list;
}; };
struct instruction; struct instruction;
...@@ -75,9 +75,7 @@ void arch_initial_func_cfi_state(struct cfi_init_state *state); ...@@ -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, int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
unsigned long offset, unsigned int maxlen, unsigned long offset, unsigned int maxlen,
unsigned int *len, enum insn_type *type, struct instruction *insn);
unsigned long *immediate,
struct list_head *ops_list);
bool arch_callee_saved_reg(unsigned char reg); bool arch_callee_saved_reg(unsigned char reg);
......
...@@ -7,8 +7,6 @@ ...@@ -7,8 +7,6 @@
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>
extern const struct option check_options[];
struct opts { struct opts {
/* actions: */ /* actions: */
bool dump_orc; bool dump_orc;
......
...@@ -34,6 +34,7 @@ struct cfi_state { ...@@ -34,6 +34,7 @@ struct cfi_state {
unsigned char type; unsigned char type;
bool bp_scratch; bool bp_scratch;
bool drap; bool drap;
bool signal;
bool end; bool end;
}; };
......
...@@ -27,7 +27,7 @@ struct alt_group { ...@@ -27,7 +27,7 @@ struct alt_group {
struct alt_group *orig_group; struct alt_group *orig_group;
/* First and last instructions in the 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. * Byte-offset-addressed len-sized array of pointers to CFI structs.
...@@ -36,39 +36,46 @@ struct alt_group { ...@@ -36,39 +36,46 @@ struct alt_group {
struct cfi_state **cfi; 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 instruction {
struct list_head list;
struct hlist_node hash; struct hlist_node hash;
struct list_head call_node; struct list_head call_node;
struct section *sec; struct section *sec;
unsigned long offset; unsigned long offset;
unsigned int len;
enum insn_type type;
unsigned long immediate; unsigned long immediate;
u16 dead_end : 1, u8 len;
ignore : 1, u8 prev_len;
ignore_alts : 1, u8 type;
hint : 1,
save : 1,
restore : 1,
retpoline_safe : 1,
noendbr : 1,
entry : 1;
/* 7 bit hole */
s8 instr; s8 instr;
u8 visited;
u32 idx : INSN_CHUNK_BITS,
dead_end : 1,
ignore : 1,
ignore_alts : 1,
hint : 1,
save : 1,
restore : 1,
retpoline_safe : 1,
noendbr : 1,
entry : 1,
visited : 4,
no_reloc : 1;
/* 10 bit hole */
struct alt_group *alt_group; struct alt_group *alt_group;
struct symbol *call_dest;
struct instruction *jump_dest; struct instruction *jump_dest;
struct instruction *first_jump_src; struct instruction *first_jump_src;
struct reloc *jump_table; union {
struct reloc *reloc; struct symbol *_call_dest;
struct list_head alts; struct reloc *_jump_table;
};
struct alternative *alts;
struct symbol *sym; struct symbol *sym;
struct list_head stack_ops; struct stack_op *stack_ops;
struct cfi_state *cfi; struct cfi_state *cfi;
}; };
...@@ -107,13 +114,11 @@ static inline bool is_jump(struct instruction *insn) ...@@ -107,13 +114,11 @@ static inline bool is_jump(struct instruction *insn)
struct instruction *find_insn(struct objtool_file *file, struct instruction *find_insn(struct objtool_file *file,
struct section *sec, unsigned long offset); struct section *sec, unsigned long offset);
#define for_each_insn(file, insn) \ struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruction *insn);
list_for_each_entry(insn, &file->insn_list, list)
#define sec_for_each_insn(file, sec, insn) \ #define sec_for_each_insn(file, _sec, insn) \
for (insn = find_insn(file, sec, 0); \ for (insn = find_insn(file, _sec, 0); \
insn && &insn->list != &file->insn_list && \ insn && insn->sec == _sec; \
insn->sec == sec; \ insn = next_insn_same_sec(file, insn))
insn = list_next_entry(insn, list))
#endif /* _CHECK_H */ #endif /* _CHECK_H */
...@@ -39,6 +39,7 @@ struct section { ...@@ -39,6 +39,7 @@ struct section {
char *name; char *name;
int idx; int idx;
bool changed, text, rodata, noinstr, init, truncate; bool changed, text, rodata, noinstr, init, truncate;
struct reloc *reloc_data;
}; };
struct symbol { struct symbol {
...@@ -49,12 +50,11 @@ struct symbol { ...@@ -49,12 +50,11 @@ struct symbol {
GElf_Sym sym; GElf_Sym sym;
struct section *sec; struct section *sec;
char *name; char *name;
unsigned int idx; unsigned int idx, len;
unsigned char bind, type;
unsigned long offset; unsigned long offset;
unsigned int len;
unsigned long __subtree_last; unsigned long __subtree_last;
struct symbol *pfunc, *cfunc, *alias; struct symbol *pfunc, *cfunc, *alias;
unsigned char bind, type;
u8 uaccess_safe : 1; u8 uaccess_safe : 1;
u8 static_call_tramp : 1; u8 static_call_tramp : 1;
u8 retpoline_thunk : 1; u8 retpoline_thunk : 1;
...@@ -104,6 +104,9 @@ struct elf { ...@@ -104,6 +104,9 @@ struct elf {
struct hlist_head *section_hash; struct hlist_head *section_hash;
struct hlist_head *section_name_hash; struct hlist_head *section_name_hash;
struct hlist_head *reloc_hash; struct hlist_head *reloc_hash;
struct section *section_data;
struct symbol *symbol_data;
}; };
#define OFFSET_STRIDE_BITS 4 #define OFFSET_STRIDE_BITS 4
......
...@@ -21,7 +21,6 @@ struct pv_state { ...@@ -21,7 +21,6 @@ struct pv_state {
struct objtool_file { struct objtool_file {
struct elf *elf; struct elf *elf;
struct list_head insn_list;
DECLARE_HASHTABLE(insn_hash, 20); DECLARE_HASHTABLE(insn_hash, 20);
struct list_head retpoline_call_list; struct list_head retpoline_call_list;
struct list_head return_thunk_list; struct list_head return_thunk_list;
......
...@@ -19,6 +19,7 @@ struct special_alt { ...@@ -19,6 +19,7 @@ struct special_alt {
bool skip_orig; bool skip_orig;
bool skip_alt; bool skip_alt;
bool jump_or_nop; bool jump_or_nop;
u8 key_addend;
struct section *orig_sec; struct section *orig_sec;
unsigned long orig_off; unsigned long orig_off;
...@@ -27,7 +28,6 @@ struct special_alt { ...@@ -27,7 +28,6 @@ struct special_alt {
unsigned long new_off; unsigned long new_off;
unsigned int orig_len, new_len; /* group only */ unsigned int orig_len, new_len; /* group only */
u8 key_addend;
}; };
int special_get_alts(struct elf *elf, struct list_head *alts); int special_get_alts(struct elf *elf, struct list_head *alts);
......
...@@ -99,7 +99,6 @@ struct objtool_file *objtool_open_read(const char *_objname) ...@@ -99,7 +99,6 @@ struct objtool_file *objtool_open_read(const char *_objname)
return NULL; return NULL;
} }
INIT_LIST_HEAD(&file.insn_list);
hash_init(file.insn_hash); hash_init(file.insn_hash);
INIT_LIST_HEAD(&file.retpoline_call_list); INIT_LIST_HEAD(&file.retpoline_call_list);
INIT_LIST_HEAD(&file.return_thunk_list); INIT_LIST_HEAD(&file.return_thunk_list);
......
...@@ -211,8 +211,8 @@ int orc_dump(const char *_objname) ...@@ -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)); print_reg(orc[i].bp_reg, bswap_if_needed(&dummy_elf, orc[i].bp_offset));
printf(" type:%s end:%d\n", printf(" type:%s signal:%d end:%d\n",
orc_type_name(orc[i].type), orc[i].end); orc_type_name(orc[i].type), orc[i].signal, orc[i].end);
} }
elf_end(elf); elf_end(elf);
......
...@@ -27,6 +27,7 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, ...@@ -27,6 +27,7 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,
} }
orc->end = cfi->end; orc->end = cfi->end;
orc->signal = cfi->signal;
if (cfi->cfa.base == CFI_UNDEFINED) { if (cfi->cfa.base == CFI_UNDEFINED) {
orc->sp_reg = ORC_REG_UNDEFINED; orc->sp_reg = ORC_REG_UNDEFINED;
......
...@@ -26,7 +26,7 @@ struct special_entry { ...@@ -26,7 +26,7 @@ struct special_entry {
unsigned char key; /* jump_label key */ unsigned char key; /* jump_label key */
}; };
struct special_entry entries[] = { static const struct special_entry entries[] = {
{ {
.sec = ".altinstructions", .sec = ".altinstructions",
.group = true, .group = true,
...@@ -65,7 +65,7 @@ static void reloc_to_sec_off(struct reloc *reloc, struct section **sec, ...@@ -65,7 +65,7 @@ static void reloc_to_sec_off(struct reloc *reloc, struct section **sec,
*off = reloc->sym->offset + reloc->addend; *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 section *sec, int idx,
struct special_alt *alt) struct special_alt *alt)
{ {
...@@ -139,7 +139,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry, ...@@ -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) int special_get_alts(struct elf *elf, struct list_head *alts)
{ {
struct special_entry *entry; const struct special_entry *entry;
struct section *sec; struct section *sec;
unsigned int nr_entries; unsigned int nr_entries;
struct special_alt *alt; 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