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"),
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/static_call_types.h> #include <linux/static_call_types.h>
struct alternative { struct alternative {
struct list_head list; struct alternative *next;
struct instruction *insn; struct instruction *insn;
bool skip_orig; bool skip_orig;
}; };
...@@ -47,27 +47,29 @@ struct instruction *find_insn(struct objtool_file *file, ...@@ -47,27 +47,29 @@ struct instruction *find_insn(struct objtool_file *file,
return NULL; return NULL;
} }
static struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruction *next_insn_same_sec(struct objtool_file *file,
struct instruction *insn) struct instruction *insn)
{ {
struct instruction *next = list_next_entry(insn, list); if (insn->idx == INSN_CHUNK_MAX)
return find_insn(file, insn->sec, insn->offset + insn->len);
if (!next || &next->list == &file->insn_list || next->sec != insn->sec) insn++;
if (!insn->len)
return NULL; return NULL;
return next; return insn;
} }
static struct instruction *next_insn_same_func(struct objtool_file *file, static struct instruction *next_insn_same_func(struct objtool_file *file,
struct instruction *insn) struct instruction *insn)
{ {
struct instruction *next = list_next_entry(insn, list); struct instruction *next = next_insn_same_sec(file, insn);
struct symbol *func = insn_func(insn); struct symbol *func = insn_func(insn);
if (!func) if (!func)
return NULL; return NULL;
if (&next->list != &file->insn_list && insn_func(next) == func) if (next && insn_func(next) == func)
return next; return next;
/* Check if we're already in the subfunction: */ /* Check if we're already in the subfunction: */
...@@ -78,17 +80,35 @@ static struct instruction *next_insn_same_func(struct objtool_file *file, ...@@ -78,17 +80,35 @@ static struct instruction *next_insn_same_func(struct objtool_file *file,
return find_insn(file, func->cfunc->sec, func->cfunc->offset); return find_insn(file, func->cfunc->sec, func->cfunc->offset);
} }
static struct instruction *prev_insn_same_sec(struct objtool_file *file,
struct instruction *insn)
{
if (insn->idx == 0) {
if (insn->prev_len)
return find_insn(file, insn->sec, insn->offset - insn->prev_len);
return NULL;
}
return insn - 1;
}
static struct instruction *prev_insn_same_sym(struct objtool_file *file, static struct instruction *prev_insn_same_sym(struct objtool_file *file,
struct instruction *insn) struct instruction *insn)
{ {
struct instruction *prev = list_prev_entry(insn, list); struct instruction *prev = prev_insn_same_sec(file, insn);
if (&prev->list != &file->insn_list && insn_func(prev) == insn_func(insn)) if (prev && insn_func(prev) == insn_func(insn))
return prev; return prev;
return NULL; return NULL;
} }
#define for_each_insn(file, insn) \
for (struct section *__sec, *__fake = (struct section *)1; \
__fake; __fake = NULL) \
for_each_sec(file, __sec) \
sec_for_each_insn(file, __sec, insn)
#define func_for_each_insn(file, func, insn) \ #define func_for_each_insn(file, func, insn) \
for (insn = find_insn(file, func->sec, func->offset); \ for (insn = find_insn(file, func->sec, func->offset); \
insn; \ insn; \
...@@ -96,16 +116,13 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file, ...@@ -96,16 +116,13 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file,
#define sym_for_each_insn(file, sym, insn) \ #define sym_for_each_insn(file, sym, insn) \
for (insn = find_insn(file, sym->sec, sym->offset); \ for (insn = find_insn(file, sym->sec, sym->offset); \
insn && &insn->list != &file->insn_list && \ insn && insn->offset < sym->offset + sym->len; \
insn->sec == sym->sec && \ insn = next_insn_same_sec(file, insn))
insn->offset < sym->offset + sym->len; \
insn = list_next_entry(insn, list))
#define sym_for_each_insn_continue_reverse(file, sym, insn) \ #define sym_for_each_insn_continue_reverse(file, sym, insn) \
for (insn = list_prev_entry(insn, list); \ for (insn = prev_insn_same_sec(file, insn); \
&insn->list != &file->insn_list && \ insn && insn->offset >= sym->offset; \
insn->sec == sym->sec && insn->offset >= sym->offset; \ insn = prev_insn_same_sec(file, insn))
insn = list_prev_entry(insn, list))
#define sec_for_each_insn_from(file, insn) \ #define sec_for_each_insn_from(file, insn) \
for (; insn; insn = next_insn_same_sec(file, insn)) for (; insn; insn = next_insn_same_sec(file, insn))
...@@ -114,16 +131,34 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file, ...@@ -114,16 +131,34 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file,
for (insn = next_insn_same_sec(file, insn); insn; \ for (insn = next_insn_same_sec(file, insn); insn; \
insn = next_insn_same_sec(file, insn)) insn = next_insn_same_sec(file, insn))
static inline struct symbol *insn_call_dest(struct instruction *insn)
{
if (insn->type == INSN_JUMP_DYNAMIC ||
insn->type == INSN_CALL_DYNAMIC)
return NULL;
return insn->_call_dest;
}
static inline struct reloc *insn_jump_table(struct instruction *insn)
{
if (insn->type == INSN_JUMP_DYNAMIC ||
insn->type == INSN_CALL_DYNAMIC)
return insn->_jump_table;
return NULL;
}
static bool is_jump_table_jump(struct instruction *insn) static bool is_jump_table_jump(struct instruction *insn)
{ {
struct alt_group *alt_group = insn->alt_group; struct alt_group *alt_group = insn->alt_group;
if (insn->jump_table) if (insn_jump_table(insn))
return true; return true;
/* Retpoline alternative for a jump table? */ /* Retpoline alternative for a jump table? */
return alt_group && alt_group->orig_group && return alt_group && alt_group->orig_group &&
alt_group->orig_group->first_insn->jump_table; insn_jump_table(alt_group->orig_group->first_insn);
} }
static bool is_sibling_call(struct instruction *insn) static bool is_sibling_call(struct instruction *insn)
...@@ -137,8 +172,8 @@ static bool is_sibling_call(struct instruction *insn) ...@@ -137,8 +172,8 @@ static bool is_sibling_call(struct instruction *insn)
return !is_jump_table_jump(insn); return !is_jump_table_jump(insn);
} }
/* add_jump_destinations() sets insn->call_dest for sibling calls. */ /* add_jump_destinations() sets insn_call_dest(insn) for sibling calls. */
return (is_static_jump(insn) && insn->call_dest); return (is_static_jump(insn) && insn_call_dest(insn));
} }
/* /*
...@@ -274,8 +309,8 @@ static void init_insn_state(struct objtool_file *file, struct insn_state *state, ...@@ -274,8 +309,8 @@ static void init_insn_state(struct objtool_file *file, struct insn_state *state,
/* /*
* We need the full vmlinux for noinstr validation, otherwise we can * We need the full vmlinux for noinstr validation, otherwise we can
* not correctly determine insn->call_dest->sec (external symbols do * not correctly determine insn_call_dest(insn)->sec (external symbols
* not have a section). * do not have a section).
*/ */
if (opts.link && opts.noinstr && sec) if (opts.link && opts.noinstr && sec)
state->noinstr = sec->noinstr; state->noinstr = sec->noinstr;
...@@ -366,6 +401,9 @@ static int decode_instructions(struct objtool_file *file) ...@@ -366,6 +401,9 @@ static int decode_instructions(struct objtool_file *file)
int ret; int ret;
for_each_sec(file, sec) { for_each_sec(file, sec) {
struct instruction *insns = NULL;
u8 prev_len = 0;
u8 idx = 0;
if (!(sec->sh.sh_flags & SHF_EXECINSTR)) if (!(sec->sh.sh_flags & SHF_EXECINSTR))
continue; continue;
...@@ -391,26 +429,31 @@ static int decode_instructions(struct objtool_file *file) ...@@ -391,26 +429,31 @@ static int decode_instructions(struct objtool_file *file)
sec->init = true; sec->init = true;
for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) { for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) {
insn = malloc(sizeof(*insn)); if (!insns || idx == INSN_CHUNK_MAX) {
if (!insn) { insns = calloc(sizeof(*insn), INSN_CHUNK_SIZE);
WARN("malloc failed"); if (!insns) {
return -1; WARN("malloc failed");
return -1;
}
idx = 0;
} else {
idx++;
} }
memset(insn, 0, sizeof(*insn)); insn = &insns[idx];
INIT_LIST_HEAD(&insn->alts); insn->idx = idx;
INIT_LIST_HEAD(&insn->stack_ops);
INIT_LIST_HEAD(&insn->call_node);
INIT_LIST_HEAD(&insn->call_node);
insn->sec = sec; insn->sec = sec;
insn->offset = offset; insn->offset = offset;
insn->prev_len = prev_len;
ret = arch_decode_instruction(file, sec, offset, ret = arch_decode_instruction(file, sec, offset,
sec->sh.sh_size - offset, sec->sh.sh_size - offset,
&insn->len, &insn->type, insn);
&insn->immediate,
&insn->stack_ops);
if (ret) if (ret)
goto err; return ret;
prev_len = insn->len;
/* /*
* By default, "ud2" is a dead end unless otherwise * By default, "ud2" is a dead end unless otherwise
...@@ -421,10 +464,11 @@ static int decode_instructions(struct objtool_file *file) ...@@ -421,10 +464,11 @@ static int decode_instructions(struct objtool_file *file)
insn->dead_end = true; insn->dead_end = true;
hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset)); hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset));
list_add_tail(&insn->list, &file->insn_list);
nr_insns++; nr_insns++;
} }
// printf("%s: last chunk used: %d\n", sec->name, (int)idx);
list_for_each_entry(func, &sec->symbol_list, list) { list_for_each_entry(func, &sec->symbol_list, list) {
if (func->type != STT_NOTYPE && func->type != STT_FUNC) if (func->type != STT_NOTYPE && func->type != STT_FUNC)
continue; continue;
...@@ -467,10 +511,6 @@ static int decode_instructions(struct objtool_file *file) ...@@ -467,10 +511,6 @@ static int decode_instructions(struct objtool_file *file)
printf("nr_insns: %lu\n", nr_insns); printf("nr_insns: %lu\n", nr_insns);
return 0; return 0;
err:
free(insn);
return ret;
} }
/* /*
...@@ -585,7 +625,7 @@ static int add_dead_ends(struct objtool_file *file) ...@@ -585,7 +625,7 @@ static int add_dead_ends(struct objtool_file *file)
} }
insn = find_insn(file, reloc->sym->sec, reloc->addend); insn = find_insn(file, reloc->sym->sec, reloc->addend);
if (insn) if (insn)
insn = list_prev_entry(insn, list); insn = prev_insn_same_sec(file, insn);
else if (reloc->addend == reloc->sym->sec->sh.sh_size) { else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
insn = find_last_insn(file, reloc->sym->sec); insn = find_last_insn(file, reloc->sym->sec);
if (!insn) { if (!insn) {
...@@ -620,7 +660,7 @@ static int add_dead_ends(struct objtool_file *file) ...@@ -620,7 +660,7 @@ static int add_dead_ends(struct objtool_file *file)
} }
insn = find_insn(file, reloc->sym->sec, reloc->addend); insn = find_insn(file, reloc->sym->sec, reloc->addend);
if (insn) if (insn)
insn = list_prev_entry(insn, list); insn = prev_insn_same_sec(file, insn);
else if (reloc->addend == reloc->sym->sec->sh.sh_size) { else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
insn = find_last_insn(file, reloc->sym->sec); insn = find_last_insn(file, reloc->sym->sec);
if (!insn) { if (!insn) {
...@@ -682,7 +722,7 @@ static int create_static_call_sections(struct objtool_file *file) ...@@ -682,7 +722,7 @@ static int create_static_call_sections(struct objtool_file *file)
return -1; return -1;
/* find key symbol */ /* find key symbol */
key_name = strdup(insn->call_dest->name); key_name = strdup(insn_call_dest(insn)->name);
if (!key_name) { if (!key_name) {
perror("strdup"); perror("strdup");
return -1; return -1;
...@@ -690,6 +730,7 @@ static int create_static_call_sections(struct objtool_file *file) ...@@ -690,6 +730,7 @@ static int create_static_call_sections(struct objtool_file *file)
if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR, if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR,
STATIC_CALL_TRAMP_PREFIX_LEN)) { STATIC_CALL_TRAMP_PREFIX_LEN)) {
WARN("static_call: trampoline name malformed: %s", key_name); WARN("static_call: trampoline name malformed: %s", key_name);
free(key_name);
return -1; return -1;
} }
tmp = key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX_LEN; tmp = key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX_LEN;
...@@ -699,6 +740,7 @@ static int create_static_call_sections(struct objtool_file *file) ...@@ -699,6 +740,7 @@ static int create_static_call_sections(struct objtool_file *file)
if (!key_sym) { if (!key_sym) {
if (!opts.module) { if (!opts.module) {
WARN("static_call: can't find static_call_key symbol: %s", tmp); WARN("static_call: can't find static_call_key symbol: %s", tmp);
free(key_name);
return -1; return -1;
} }
...@@ -711,7 +753,7 @@ static int create_static_call_sections(struct objtool_file *file) ...@@ -711,7 +753,7 @@ static int create_static_call_sections(struct objtool_file *file)
* trampoline address. This is fixed up in * trampoline address. This is fixed up in
* static_call_add_module(). * static_call_add_module().
*/ */
key_sym = insn->call_dest; key_sym = insn_call_dest(insn);
} }
free(key_name); free(key_name);
...@@ -856,8 +898,15 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file) ...@@ -856,8 +898,15 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file)
list_for_each_entry(insn, &file->endbr_list, call_node) { list_for_each_entry(insn, &file->endbr_list, call_node) {
int *site = (int *)sec->data->d_buf + idx; int *site = (int *)sec->data->d_buf + idx;
struct symbol *sym = insn->sym;
*site = 0; *site = 0;
if (opts.module && sym && sym->type == STT_FUNC &&
insn->offset == sym->offset &&
(!strcmp(sym->name, "init_module") ||
!strcmp(sym->name, "cleanup_module")))
WARN("%s(): not an indirect call target", sym->name);
if (elf_add_reloc_to_insn(file->elf, sec, if (elf_add_reloc_to_insn(file->elf, sec,
idx * sizeof(int), idx * sizeof(int),
R_X86_64_PC32, R_X86_64_PC32,
...@@ -1302,43 +1351,42 @@ __weak bool arch_is_rethunk(struct symbol *sym) ...@@ -1302,43 +1351,42 @@ __weak bool arch_is_rethunk(struct symbol *sym)
return false; return false;
} }
#define NEGATIVE_RELOC ((void *)-1L)
static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn) static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
{ {
if (insn->reloc == NEGATIVE_RELOC) struct reloc *reloc;
if (insn->no_reloc)
return NULL; return NULL;
if (!insn->reloc) { if (!file)
if (!file) return NULL;
return NULL;
insn->reloc = find_reloc_by_dest_range(file->elf, insn->sec, reloc = find_reloc_by_dest_range(file->elf, insn->sec,
insn->offset, insn->len); insn->offset, insn->len);
if (!insn->reloc) { if (!reloc) {
insn->reloc = NEGATIVE_RELOC; insn->no_reloc = 1;
return NULL; return NULL;
}
} }
return insn->reloc; return reloc;
} }
static void remove_insn_ops(struct instruction *insn) static void remove_insn_ops(struct instruction *insn)
{ {
struct stack_op *op, *tmp; struct stack_op *op, *next;
list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) { for (op = insn->stack_ops; op; op = next) {
list_del(&op->list); next = op->next;
free(op); free(op);
} }
insn->stack_ops = NULL;
} }
static void annotate_call_site(struct objtool_file *file, static void annotate_call_site(struct objtool_file *file,
struct instruction *insn, bool sibling) struct instruction *insn, bool sibling)
{ {
struct reloc *reloc = insn_reloc(file, insn); struct reloc *reloc = insn_reloc(file, insn);
struct symbol *sym = insn->call_dest; struct symbol *sym = insn_call_dest(insn);
if (!sym) if (!sym)
sym = reloc->sym; sym = reloc->sym;
...@@ -1423,7 +1471,7 @@ static void annotate_call_site(struct objtool_file *file, ...@@ -1423,7 +1471,7 @@ static void annotate_call_site(struct objtool_file *file,
static void add_call_dest(struct objtool_file *file, struct instruction *insn, static void add_call_dest(struct objtool_file *file, struct instruction *insn,
struct symbol *dest, bool sibling) struct symbol *dest, bool sibling)
{ {
insn->call_dest = dest; insn->_call_dest = dest;
if (!dest) if (!dest)
return; return;
...@@ -1681,12 +1729,12 @@ static int add_call_destinations(struct objtool_file *file) ...@@ -1681,12 +1729,12 @@ static int add_call_destinations(struct objtool_file *file)
if (insn->ignore) if (insn->ignore)
continue; continue;
if (!insn->call_dest) { if (!insn_call_dest(insn)) {
WARN_FUNC("unannotated intra-function call", insn->sec, insn->offset); WARN_FUNC("unannotated intra-function call", insn->sec, insn->offset);
return -1; return -1;
} }
if (insn_func(insn) && insn->call_dest->type != STT_FUNC) { if (insn_func(insn) && insn_call_dest(insn)->type != STT_FUNC) {
WARN_FUNC("unsupported call to non-function", WARN_FUNC("unsupported call to non-function",
insn->sec, insn->offset); insn->sec, insn->offset);
return -1; return -1;
...@@ -1724,36 +1772,50 @@ static int handle_group_alt(struct objtool_file *file, ...@@ -1724,36 +1772,50 @@ static int handle_group_alt(struct objtool_file *file,
struct instruction *orig_insn, struct instruction *orig_insn,
struct instruction **new_insn) struct instruction **new_insn)
{ {
struct instruction *last_orig_insn, *last_new_insn = NULL, *insn, *nop = NULL; struct instruction *last_new_insn = NULL, *insn, *nop = NULL;
struct alt_group *orig_alt_group, *new_alt_group; struct alt_group *orig_alt_group, *new_alt_group;
unsigned long dest_off; unsigned long dest_off;
orig_alt_group = orig_insn->alt_group;
orig_alt_group = malloc(sizeof(*orig_alt_group));
if (!orig_alt_group) { if (!orig_alt_group) {
WARN("malloc failed"); struct instruction *last_orig_insn = NULL;
return -1;
}
orig_alt_group->cfi = calloc(special_alt->orig_len,
sizeof(struct cfi_state *));
if (!orig_alt_group->cfi) {
WARN("calloc failed");
return -1;
}
last_orig_insn = NULL; orig_alt_group = malloc(sizeof(*orig_alt_group));
insn = orig_insn; if (!orig_alt_group) {
sec_for_each_insn_from(file, insn) { WARN("malloc failed");
if (insn->offset >= special_alt->orig_off + special_alt->orig_len) return -1;
break; }
orig_alt_group->cfi = calloc(special_alt->orig_len,
sizeof(struct cfi_state *));
if (!orig_alt_group->cfi) {
WARN("calloc failed");
return -1;
}
insn->alt_group = orig_alt_group; insn = orig_insn;
last_orig_insn = insn; sec_for_each_insn_from(file, insn) {
} if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
orig_alt_group->orig_group = NULL; break;
orig_alt_group->first_insn = orig_insn;
orig_alt_group->last_insn = last_orig_insn;
insn->alt_group = orig_alt_group;
last_orig_insn = insn;
}
orig_alt_group->orig_group = NULL;
orig_alt_group->first_insn = orig_insn;
orig_alt_group->last_insn = last_orig_insn;
orig_alt_group->nop = NULL;
} else {
if (orig_alt_group->last_insn->offset + orig_alt_group->last_insn->len -
orig_alt_group->first_insn->offset != special_alt->orig_len) {
WARN_FUNC("weirdly overlapping alternative! %ld != %d",
orig_insn->sec, orig_insn->offset,
orig_alt_group->last_insn->offset +
orig_alt_group->last_insn->len -
orig_alt_group->first_insn->offset,
special_alt->orig_len);
return -1;
}
}
new_alt_group = malloc(sizeof(*new_alt_group)); new_alt_group = malloc(sizeof(*new_alt_group));
if (!new_alt_group) { if (!new_alt_group) {
...@@ -1775,8 +1837,6 @@ static int handle_group_alt(struct objtool_file *file, ...@@ -1775,8 +1837,6 @@ static int handle_group_alt(struct objtool_file *file,
return -1; return -1;
} }
memset(nop, 0, sizeof(*nop)); memset(nop, 0, sizeof(*nop));
INIT_LIST_HEAD(&nop->alts);
INIT_LIST_HEAD(&nop->stack_ops);
nop->sec = special_alt->new_sec; nop->sec = special_alt->new_sec;
nop->offset = special_alt->new_off + special_alt->new_len; nop->offset = special_alt->new_off + special_alt->new_len;
...@@ -1830,7 +1890,7 @@ static int handle_group_alt(struct objtool_file *file, ...@@ -1830,7 +1890,7 @@ static int handle_group_alt(struct objtool_file *file,
dest_off = arch_jump_destination(insn); dest_off = arch_jump_destination(insn);
if (dest_off == special_alt->new_off + special_alt->new_len) { if (dest_off == special_alt->new_off + special_alt->new_len) {
insn->jump_dest = next_insn_same_sec(file, last_orig_insn); insn->jump_dest = next_insn_same_sec(file, orig_alt_group->last_insn);
if (!insn->jump_dest) { if (!insn->jump_dest) {
WARN_FUNC("can't find alternative jump destination", WARN_FUNC("can't find alternative jump destination",
insn->sec, insn->offset); insn->sec, insn->offset);
...@@ -1845,12 +1905,11 @@ static int handle_group_alt(struct objtool_file *file, ...@@ -1845,12 +1905,11 @@ static int handle_group_alt(struct objtool_file *file,
return -1; return -1;
} }
if (nop)
list_add(&nop->list, &last_new_insn->list);
end: end:
new_alt_group->orig_group = orig_alt_group; new_alt_group->orig_group = orig_alt_group;
new_alt_group->first_insn = *new_insn; new_alt_group->first_insn = *new_insn;
new_alt_group->last_insn = nop ? : last_new_insn; new_alt_group->last_insn = last_new_insn;
new_alt_group->nop = nop;
new_alt_group->cfi = orig_alt_group->cfi; new_alt_group->cfi = orig_alt_group->cfi;
return 0; return 0;
} }
...@@ -1900,7 +1959,7 @@ static int handle_jump_alt(struct objtool_file *file, ...@@ -1900,7 +1959,7 @@ static int handle_jump_alt(struct objtool_file *file,
else else
file->jl_long++; file->jl_long++;
*new_insn = list_next_entry(orig_insn, list); *new_insn = next_insn_same_sec(file, orig_insn);
return 0; return 0;
} }
...@@ -1974,7 +2033,8 @@ static int add_special_section_alts(struct objtool_file *file) ...@@ -1974,7 +2033,8 @@ static int add_special_section_alts(struct objtool_file *file)
alt->insn = new_insn; alt->insn = new_insn;
alt->skip_orig = special_alt->skip_orig; alt->skip_orig = special_alt->skip_orig;
orig_insn->ignore_alts |= special_alt->skip_alt; orig_insn->ignore_alts |= special_alt->skip_alt;
list_add_tail(&alt->list, &orig_insn->alts); alt->next = orig_insn->alts;
orig_insn->alts = alt;
list_del(&special_alt->list); list_del(&special_alt->list);
free(special_alt); free(special_alt);
...@@ -2033,7 +2093,8 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn, ...@@ -2033,7 +2093,8 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
} }
alt->insn = dest_insn; alt->insn = dest_insn;
list_add_tail(&alt->list, &insn->alts); alt->next = insn->alts;
insn->alts = alt;
prev_offset = reloc->offset; prev_offset = reloc->offset;
} }
...@@ -2123,7 +2184,7 @@ static void mark_func_jump_tables(struct objtool_file *file, ...@@ -2123,7 +2184,7 @@ static void mark_func_jump_tables(struct objtool_file *file,
reloc = find_jump_table(file, func, insn); reloc = find_jump_table(file, func, insn);
if (reloc) { if (reloc) {
reloc->jump_table_start = true; reloc->jump_table_start = true;
insn->jump_table = reloc; insn->_jump_table = reloc;
} }
} }
} }
...@@ -2135,10 +2196,10 @@ static int add_func_jump_tables(struct objtool_file *file, ...@@ -2135,10 +2196,10 @@ static int add_func_jump_tables(struct objtool_file *file,
int ret; int ret;
func_for_each_insn(file, func, insn) { func_for_each_insn(file, func, insn) {
if (!insn->jump_table) if (!insn_jump_table(insn))
continue; continue;
ret = add_jump_table(file, insn, insn->jump_table); ret = add_jump_table(file, insn, insn_jump_table(insn));
if (ret) if (ret)
return ret; return ret;
} }
...@@ -2271,6 +2332,7 @@ static int read_unwind_hints(struct objtool_file *file) ...@@ -2271,6 +2332,7 @@ static int read_unwind_hints(struct objtool_file *file)
cfi.cfa.offset = bswap_if_needed(file->elf, hint->sp_offset); cfi.cfa.offset = bswap_if_needed(file->elf, hint->sp_offset);
cfi.type = hint->type; cfi.type = hint->type;
cfi.signal = hint->signal;
cfi.end = hint->end; cfi.end = hint->end;
insn->cfi = cfi_hash_find_or_add(&cfi); insn->cfi = cfi_hash_find_or_add(&cfi);
...@@ -2610,8 +2672,8 @@ static int decode_sections(struct objtool_file *file) ...@@ -2610,8 +2672,8 @@ static int decode_sections(struct objtool_file *file)
static bool is_fentry_call(struct instruction *insn) static bool is_fentry_call(struct instruction *insn)
{ {
if (insn->type == INSN_CALL && if (insn->type == INSN_CALL &&
insn->call_dest && insn_call_dest(insn) &&
insn->call_dest->fentry) insn_call_dest(insn)->fentry)
return true; return true;
return false; return false;
...@@ -3206,8 +3268,12 @@ static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn ...@@ -3206,8 +3268,12 @@ static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn
alt_cfi[group_off] = insn->cfi; alt_cfi[group_off] = insn->cfi;
} else { } else {
if (cficmp(alt_cfi[group_off], insn->cfi)) { if (cficmp(alt_cfi[group_off], insn->cfi)) {
WARN_FUNC("stack layout conflict in alternatives", struct alt_group *orig_group = insn->alt_group->orig_group ?: insn->alt_group;
insn->sec, insn->offset); struct instruction *orig = orig_group->first_insn;
char *where = offstr(insn->sec, insn->offset);
WARN_FUNC("stack layout conflict in alternatives: %s",
orig->sec, orig->offset, where);
free(where);
return -1; return -1;
} }
} }
...@@ -3221,7 +3287,7 @@ static int handle_insn_ops(struct instruction *insn, ...@@ -3221,7 +3287,7 @@ static int handle_insn_ops(struct instruction *insn,
{ {
struct stack_op *op; struct stack_op *op;
list_for_each_entry(op, &insn->stack_ops, list) { for (op = insn->stack_ops; op; op = op->next) {
if (update_cfi_state(insn, next_insn, &state->cfi, op)) if (update_cfi_state(insn, next_insn, &state->cfi, op))
return 1; return 1;
...@@ -3318,8 +3384,8 @@ static inline const char *call_dest_name(struct instruction *insn) ...@@ -3318,8 +3384,8 @@ static inline const char *call_dest_name(struct instruction *insn)
struct reloc *rel; struct reloc *rel;
int idx; int idx;
if (insn->call_dest) if (insn_call_dest(insn))
return insn->call_dest->name; return insn_call_dest(insn)->name;
rel = insn_reloc(NULL, insn); rel = insn_reloc(NULL, insn);
if (rel && !strcmp(rel->sym->name, "pv_ops")) { if (rel && !strcmp(rel->sym->name, "pv_ops")) {
...@@ -3401,13 +3467,13 @@ static int validate_call(struct objtool_file *file, ...@@ -3401,13 +3467,13 @@ static int validate_call(struct objtool_file *file,
struct insn_state *state) struct insn_state *state)
{ {
if (state->noinstr && state->instr <= 0 && if (state->noinstr && state->instr <= 0 &&
!noinstr_call_dest(file, insn, insn->call_dest)) { !noinstr_call_dest(file, insn, insn_call_dest(insn))) {
WARN_FUNC("call to %s() leaves .noinstr.text section", WARN_FUNC("call to %s() leaves .noinstr.text section",
insn->sec, insn->offset, call_dest_name(insn)); insn->sec, insn->offset, call_dest_name(insn));
return 1; return 1;
} }
if (state->uaccess && !func_uaccess_safe(insn->call_dest)) { if (state->uaccess && !func_uaccess_safe(insn_call_dest(insn))) {
WARN_FUNC("call to %s() with UACCESS enabled", WARN_FUNC("call to %s() with UACCESS enabled",
insn->sec, insn->offset, call_dest_name(insn)); insn->sec, insn->offset, call_dest_name(insn));
return 1; return 1;
...@@ -3485,11 +3551,28 @@ static struct instruction *next_insn_to_validate(struct objtool_file *file, ...@@ -3485,11 +3551,28 @@ static struct instruction *next_insn_to_validate(struct objtool_file *file,
* Simulate the fact that alternatives are patched in-place. When the * Simulate the fact that alternatives are patched in-place. When the
* end of a replacement alt_group is reached, redirect objtool flow to * end of a replacement alt_group is reached, redirect objtool flow to
* the end of the original alt_group. * the end of the original alt_group.
*
* insn->alts->insn -> alt_group->first_insn
* ...
* alt_group->last_insn
* [alt_group->nop] -> next(orig_group->last_insn)
*/ */
if (alt_group && insn == alt_group->last_insn && alt_group->orig_group) if (alt_group) {
return next_insn_same_sec(file, alt_group->orig_group->last_insn); if (alt_group->nop) {
/* ->nop implies ->orig_group */
if (insn == alt_group->last_insn)
return alt_group->nop;
if (insn == alt_group->nop)
goto next_orig;
}
if (insn == alt_group->last_insn && alt_group->orig_group)
goto next_orig;
}
return next_insn_same_sec(file, insn); return next_insn_same_sec(file, insn);
next_orig:
return next_insn_same_sec(file, alt_group->orig_group->last_insn);
} }
/* /*
...@@ -3590,10 +3673,10 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, ...@@ -3590,10 +3673,10 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
if (propagate_alt_cfi(file, insn)) if (propagate_alt_cfi(file, insn))
return 1; return 1;
if (!insn->ignore_alts && !list_empty(&insn->alts)) { if (!insn->ignore_alts && insn->alts) {
bool skip_orig = false; bool skip_orig = false;
list_for_each_entry(alt, &insn->alts, list) { for (alt = insn->alts; alt; alt = alt->next) {
if (alt->skip_orig) if (alt->skip_orig)
skip_orig = true; skip_orig = true;
...@@ -3740,11 +3823,25 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, ...@@ -3740,11 +3823,25 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
return 0; return 0;
} }
static int validate_unwind_hint(struct objtool_file *file,
struct instruction *insn,
struct insn_state *state)
{
if (insn->hint && !insn->visited && !insn->ignore) {
int ret = validate_branch(file, insn_func(insn), insn, *state);
if (ret && opts.backtrace)
BT_FUNC("<=== (hint)", insn);
return ret;
}
return 0;
}
static int validate_unwind_hints(struct objtool_file *file, struct section *sec) static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
{ {
struct instruction *insn; struct instruction *insn;
struct insn_state state; struct insn_state state;
int ret, warnings = 0; int warnings = 0;
if (!file->hints) if (!file->hints)
return 0; return 0;
...@@ -3752,22 +3849,11 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec) ...@@ -3752,22 +3849,11 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
init_insn_state(file, &state, sec); init_insn_state(file, &state, sec);
if (sec) { if (sec) {
insn = find_insn(file, sec, 0); sec_for_each_insn(file, sec, insn)
if (!insn) warnings += validate_unwind_hint(file, insn, &state);
return 0;
} else { } else {
insn = list_first_entry(&file->insn_list, typeof(*insn), list); for_each_insn(file, insn)
} warnings += validate_unwind_hint(file, insn, &state);
while (&insn->list != &file->insn_list && (!sec || insn->sec == sec)) {
if (insn->hint && !insn->visited && !insn->ignore) {
ret = validate_branch(file, insn_func(insn), insn, state);
if (ret && opts.backtrace)
BT_FUNC("<=== (hint)", insn);
warnings += ret;
}
insn = list_next_entry(insn, list);
} }
return warnings; return warnings;
...@@ -3792,11 +3878,11 @@ static int validate_entry(struct objtool_file *file, struct instruction *insn) ...@@ -3792,11 +3878,11 @@ static int validate_entry(struct objtool_file *file, struct instruction *insn)
insn->visited |= VISITED_ENTRY; insn->visited |= VISITED_ENTRY;
if (!insn->ignore_alts && !list_empty(&insn->alts)) { if (!insn->ignore_alts && insn->alts) {
struct alternative *alt; struct alternative *alt;
bool skip_orig = false; bool skip_orig = false;
list_for_each_entry(alt, &insn->alts, list) { for (alt = insn->alts; alt; alt = alt->next) {
if (alt->skip_orig) if (alt->skip_orig)
skip_orig = true; skip_orig = true;
...@@ -3845,11 +3931,11 @@ static int validate_entry(struct objtool_file *file, struct instruction *insn) ...@@ -3845,11 +3931,11 @@ static int validate_entry(struct objtool_file *file, struct instruction *insn)
/* fallthrough */ /* fallthrough */
case INSN_CALL: case INSN_CALL:
dest = find_insn(file, insn->call_dest->sec, dest = find_insn(file, insn_call_dest(insn)->sec,
insn->call_dest->offset); insn_call_dest(insn)->offset);
if (!dest) { if (!dest) {
WARN("Unresolved function after linking!?: %s", WARN("Unresolved function after linking!?: %s",
insn->call_dest->name); insn_call_dest(insn)->name);
return -1; return -1;
} }
...@@ -3950,13 +4036,13 @@ static int validate_retpoline(struct objtool_file *file) ...@@ -3950,13 +4036,13 @@ static int validate_retpoline(struct objtool_file *file)
static bool is_kasan_insn(struct instruction *insn) static bool is_kasan_insn(struct instruction *insn)
{ {
return (insn->type == INSN_CALL && return (insn->type == INSN_CALL &&
!strcmp(insn->call_dest->name, "__asan_handle_no_return")); !strcmp(insn_call_dest(insn)->name, "__asan_handle_no_return"));
} }
static bool is_ubsan_insn(struct instruction *insn) static bool is_ubsan_insn(struct instruction *insn)
{ {
return (insn->type == INSN_CALL && return (insn->type == INSN_CALL &&
!strcmp(insn->call_dest->name, !strcmp(insn_call_dest(insn)->name,
"__ubsan_handle_builtin_unreachable")); "__ubsan_handle_builtin_unreachable"));
} }
...@@ -4033,8 +4119,9 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio ...@@ -4033,8 +4119,9 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
* *
* It may also insert a UD2 after calling a __noreturn function. * It may also insert a UD2 after calling a __noreturn function.
*/ */
prev_insn = list_prev_entry(insn, list); prev_insn = prev_insn_same_sec(file, insn);
if ((prev_insn->dead_end || dead_end_function(file, prev_insn->call_dest)) && if ((prev_insn->dead_end ||
dead_end_function(file, insn_call_dest(prev_insn))) &&
(insn->type == INSN_BUG || (insn->type == INSN_BUG ||
(insn->type == INSN_JUMP_UNCONDITIONAL && (insn->type == INSN_JUMP_UNCONDITIONAL &&
insn->jump_dest && insn->jump_dest->type == INSN_BUG))) insn->jump_dest && insn->jump_dest->type == INSN_BUG)))
...@@ -4064,7 +4151,7 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio ...@@ -4064,7 +4151,7 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
if (insn->offset + insn->len >= insn_func(insn)->offset + insn_func(insn)->len) if (insn->offset + insn->len >= insn_func(insn)->offset + insn_func(insn)->len)
break; break;
insn = list_next_entry(insn, list); insn = next_insn_same_sec(file, insn);
} }
return false; return false;
...@@ -4077,10 +4164,10 @@ static int add_prefix_symbol(struct objtool_file *file, struct symbol *func, ...@@ -4077,10 +4164,10 @@ static int add_prefix_symbol(struct objtool_file *file, struct symbol *func,
return 0; return 0;
for (;;) { for (;;) {
struct instruction *prev = list_prev_entry(insn, list); struct instruction *prev = prev_insn_same_sec(file, insn);
u64 offset; u64 offset;
if (&prev->list == &file->insn_list) if (!prev)
break; break;
if (prev->type != INSN_NOP) if (prev->type != INSN_NOP)
...@@ -4479,7 +4566,7 @@ int check(struct objtool_file *file) ...@@ -4479,7 +4566,7 @@ int check(struct objtool_file *file)
warnings += ret; warnings += ret;
if (list_empty(&file->insn_list)) if (!nr_insns)
goto out; goto out;
if (opts.retpoline) { if (opts.retpoline) {
...@@ -4588,7 +4675,7 @@ int check(struct objtool_file *file) ...@@ -4588,7 +4675,7 @@ int check(struct objtool_file *file)
warnings += ret; warnings += ret;
} }
if (opts.orc && !list_empty(&file->insn_list)) { if (opts.orc && nr_insns) {
ret = orc_create(file); ret = orc_create(file);
if (ret < 0) if (ret < 0)
goto out; goto out;
......
...@@ -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