Commit e94693f7 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool updates from Ingo Molnar:
 "This is an extensive rewrite of the objdump tool to track all stack
  pointer modifications through the machine instructions of disassembled
  functions found in kernel .o files.

  This re-design removes the prior dependency on CONFIG_FRAME_POINTERS,
  with the goal to prepare the tool to generate kernel debuginfo data in
  the future. There's also an increase in checking/tracking robustness
  as a side effect as well.

  No (intended) changes to existing functionality"

* 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  objtool: Silence warnings for functions which use IRET
  objtool: Implement stack validation 2.0
  objtool, x86: Add several functions and files to the objtool whitelist
  objtool: Move checking code to check.c
parents 26d3a77d 2513cbf9
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
# Arch-specific CryptoAPI modules. # Arch-specific CryptoAPI modules.
# #
OBJECT_FILES_NON_STANDARD := y
avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no) avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no)
avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
$(comma)4)$(comma)%ymm2,yes,no) $(comma)4)$(comma)%ymm2,yes,no)
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
# Arch-specific CryptoAPI modules. # Arch-specific CryptoAPI modules.
# #
OBJECT_FILES_NON_STANDARD := y
avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
$(comma)4)$(comma)%ymm2,yes,no) $(comma)4)$(comma)%ymm2,yes,no)
ifeq ($(avx2_supported),yes) ifeq ($(avx2_supported),yes)
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
# Arch-specific CryptoAPI modules. # Arch-specific CryptoAPI modules.
# #
OBJECT_FILES_NON_STANDARD := y
avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
$(comma)4)$(comma)%ymm2,yes,no) $(comma)4)$(comma)%ymm2,yes,no)
ifeq ($(avx2_supported),yes) ifeq ($(avx2_supported),yes)
......
...@@ -29,6 +29,7 @@ OBJECT_FILES_NON_STANDARD_head_$(BITS).o := y ...@@ -29,6 +29,7 @@ OBJECT_FILES_NON_STANDARD_head_$(BITS).o := y
OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o := y OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o := y
OBJECT_FILES_NON_STANDARD_ftrace_$(BITS).o := y OBJECT_FILES_NON_STANDARD_ftrace_$(BITS).o := y
OBJECT_FILES_NON_STANDARD_test_nx.o := y OBJECT_FILES_NON_STANDARD_test_nx.o := y
OBJECT_FILES_NON_STANDARD_paravirt_patch_$(BITS).o := y
# If instrumentation of this dir is enabled, boot hangs during first second. # If instrumentation of this dir is enabled, boot hangs during first second.
# Probably could be more selective here, but note that files related to irqs, # Probably could be more selective here, but note that files related to irqs,
......
OBJECT_FILES_NON_STANDARD_wakeup_$(BITS).o := y
obj-$(CONFIG_ACPI) += boot.o obj-$(CONFIG_ACPI) += boot.o
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o
obj-$(CONFIG_ACPI_APEI) += apei.o obj-$(CONFIG_ACPI_APEI) += apei.o
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/frame.h>
#include <asm/text-patching.h> #include <asm/text-patching.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
...@@ -94,6 +95,7 @@ static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val) ...@@ -94,6 +95,7 @@ static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val)
} }
asm ( asm (
"optprobe_template_func:\n"
".global optprobe_template_entry\n" ".global optprobe_template_entry\n"
"optprobe_template_entry:\n" "optprobe_template_entry:\n"
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
...@@ -131,7 +133,12 @@ asm ( ...@@ -131,7 +133,12 @@ asm (
" popf\n" " popf\n"
#endif #endif
".global optprobe_template_end\n" ".global optprobe_template_end\n"
"optprobe_template_end:\n"); "optprobe_template_end:\n"
".type optprobe_template_func, @function\n"
".size optprobe_template_func, .-optprobe_template_func\n");
void optprobe_template_func(void);
STACK_FRAME_NON_STANDARD(optprobe_template_func);
#define TMPL_MOVE_IDX \ #define TMPL_MOVE_IDX \
((long)&optprobe_template_val - (long)&optprobe_template_entry) ((long)&optprobe_template_val - (long)&optprobe_template_entry)
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/tboot.h> #include <linux/tboot.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/frame.h>
#include <acpi/reboot.h> #include <acpi/reboot.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/apic.h> #include <asm/apic.h>
...@@ -123,6 +124,7 @@ void __noreturn machine_real_restart(unsigned int type) ...@@ -123,6 +124,7 @@ void __noreturn machine_real_restart(unsigned int type)
#ifdef CONFIG_APM_MODULE #ifdef CONFIG_APM_MODULE
EXPORT_SYMBOL(machine_real_restart); EXPORT_SYMBOL(machine_real_restart);
#endif #endif
STACK_FRAME_NON_STANDARD(machine_real_restart);
/* /*
* Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/amd-iommu.h> #include <linux/amd-iommu.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/frame.h>
#include <asm/apic.h> #include <asm/apic.h>
#include <asm/perf_event.h> #include <asm/perf_event.h>
...@@ -4906,6 +4907,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) ...@@ -4906,6 +4907,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
mark_all_clean(svm->vmcb); mark_all_clean(svm->vmcb);
} }
STACK_FRAME_NON_STANDARD(svm_vcpu_run);
static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
{ {
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/tboot.h> #include <linux/tboot.h>
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/frame.h>
#include "kvm_cache_regs.h" #include "kvm_cache_regs.h"
#include "x86.h" #include "x86.h"
...@@ -8652,6 +8653,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu) ...@@ -8652,6 +8653,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
); );
} }
} }
STACK_FRAME_NON_STANDARD(vmx_handle_external_intr);
static bool vmx_has_high_real_mode_segbase(void) static bool vmx_has_high_real_mode_segbase(void)
{ {
...@@ -9028,6 +9030,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) ...@@ -9028,6 +9030,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
vmx_recover_nmi_blocking(vmx); vmx_recover_nmi_blocking(vmx);
vmx_complete_interrupts(vmx); vmx_complete_interrupts(vmx);
} }
STACK_FRAME_NON_STANDARD(vmx_vcpu_run);
static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs) static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs)
{ {
......
...@@ -13,14 +13,14 @@ ...@@ -13,14 +13,14 @@
.macro op_safe_regs op .macro op_safe_regs op
ENTRY(\op\()_safe_regs) ENTRY(\op\()_safe_regs)
pushq %rbx pushq %rbx
pushq %rbp pushq %r12
movq %rdi, %r10 /* Save pointer */ movq %rdi, %r10 /* Save pointer */
xorl %r11d, %r11d /* Return value */ xorl %r11d, %r11d /* Return value */
movl (%rdi), %eax movl (%rdi), %eax
movl 4(%rdi), %ecx movl 4(%rdi), %ecx
movl 8(%rdi), %edx movl 8(%rdi), %edx
movl 12(%rdi), %ebx movl 12(%rdi), %ebx
movl 20(%rdi), %ebp movl 20(%rdi), %r12d
movl 24(%rdi), %esi movl 24(%rdi), %esi
movl 28(%rdi), %edi movl 28(%rdi), %edi
1: \op 1: \op
...@@ -29,10 +29,10 @@ ENTRY(\op\()_safe_regs) ...@@ -29,10 +29,10 @@ ENTRY(\op\()_safe_regs)
movl %ecx, 4(%r10) movl %ecx, 4(%r10)
movl %edx, 8(%r10) movl %edx, 8(%r10)
movl %ebx, 12(%r10) movl %ebx, 12(%r10)
movl %ebp, 20(%r10) movl %r12d, 20(%r10)
movl %esi, 24(%r10) movl %esi, 24(%r10)
movl %edi, 28(%r10) movl %edi, 28(%r10)
popq %rbp popq %r12
popq %rbx popq %rbx
ret ret
3: 3:
......
# #
# Arch-specific network modules # Arch-specific network modules
# #
OBJECT_FILES_NON_STANDARD_bpf_jit.o += y
obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o
OBJECT_FILES_NON_STANDARD_efi_thunk_$(BITS).o := y OBJECT_FILES_NON_STANDARD_efi_thunk_$(BITS).o := y
OBJECT_FILES_NON_STANDARD_efi_stub_$(BITS).o := y
obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o
obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
......
OBJECT_FILES_NON_STANDARD_hibernate_asm_$(BITS).o := y
# __restore_processor_state() restores %gs after S3 resume and so should not # __restore_processor_state() restores %gs after S3 resume and so should not
# itself be stack-protected # itself be stack-protected
nostackp := $(call cc-option, -fno-stack-protector) nostackp := $(call cc-option, -fno-stack-protector)
......
OBJECT_FILES_NON_STANDARD_xen-asm_$(BITS).o := y
OBJECT_FILES_NON_STANDARD_xen-pvh.o := y
ifdef CONFIG_FUNCTION_TRACER ifdef CONFIG_FUNCTION_TRACER
# Do not profile debug and lowlevel utilities # Do not profile debug and lowlevel utilities
CFLAGS_REMOVE_spinlock.o = -pg CFLAGS_REMOVE_spinlock.o = -pg
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/frame.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/sections.h> #include <asm/sections.h>
...@@ -874,7 +875,7 @@ int kexec_load_disabled; ...@@ -874,7 +875,7 @@ int kexec_load_disabled;
* only when panic_cpu holds the current CPU number; this is the only CPU * only when panic_cpu holds the current CPU number; this is the only CPU
* which processes crash_kexec routines. * which processes crash_kexec routines.
*/ */
void __crash_kexec(struct pt_regs *regs) void __noclone __crash_kexec(struct pt_regs *regs)
{ {
/* Take the kexec_mutex here to prevent sys_kexec_load /* Take the kexec_mutex here to prevent sys_kexec_load
* running on one cpu from replacing the crash kernel * running on one cpu from replacing the crash kernel
...@@ -896,6 +897,7 @@ void __crash_kexec(struct pt_regs *regs) ...@@ -896,6 +897,7 @@ void __crash_kexec(struct pt_regs *regs)
mutex_unlock(&kexec_mutex); mutex_unlock(&kexec_mutex);
} }
} }
STACK_FRAME_NON_STANDARD(__crash_kexec);
void crash_kexec(struct pt_regs *regs) void crash_kexec(struct pt_regs *regs)
{ {
......
objtool-y += arch/$(SRCARCH)/ objtool-y += arch/$(SRCARCH)/
objtool-y += builtin-check.o objtool-y += builtin-check.o
objtool-y += check.o
objtool-y += elf.o objtool-y += elf.o
objtool-y += special.o objtool-y += special.o
objtool-y += objtool.o objtool-y += objtool.o
......
...@@ -25,7 +25,7 @@ OBJTOOL_IN := $(OBJTOOL)-in.o ...@@ -25,7 +25,7 @@ OBJTOOL_IN := $(OBJTOOL)-in.o
all: $(OBJTOOL) all: $(OBJTOOL)
INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi
CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -fomit-frame-pointer -O2 -g $(INCLUDES)
LDFLAGS += -lelf $(LIBSUBCMD) LDFLAGS += -lelf $(LIBSUBCMD)
# Allow old libelf to be used: # Allow old libelf to be used:
......
...@@ -19,25 +19,63 @@ ...@@ -19,25 +19,63 @@
#define _ARCH_H #define _ARCH_H
#include <stdbool.h> #include <stdbool.h>
#include <linux/list.h>
#include "elf.h" #include "elf.h"
#include "cfi.h"
#define INSN_FP_SAVE 1 #define INSN_JUMP_CONDITIONAL 1
#define INSN_FP_SETUP 2 #define INSN_JUMP_UNCONDITIONAL 2
#define INSN_FP_RESTORE 3 #define INSN_JUMP_DYNAMIC 3
#define INSN_JUMP_CONDITIONAL 4 #define INSN_CALL 4
#define INSN_JUMP_UNCONDITIONAL 5 #define INSN_CALL_DYNAMIC 5
#define INSN_JUMP_DYNAMIC 6 #define INSN_RETURN 6
#define INSN_CALL 7 #define INSN_CONTEXT_SWITCH 7
#define INSN_CALL_DYNAMIC 8 #define INSN_STACK 8
#define INSN_RETURN 9 #define INSN_NOP 9
#define INSN_CONTEXT_SWITCH 10 #define INSN_OTHER 10
#define INSN_NOP 11
#define INSN_OTHER 12
#define INSN_LAST INSN_OTHER #define INSN_LAST INSN_OTHER
enum op_dest_type {
OP_DEST_REG,
OP_DEST_REG_INDIRECT,
OP_DEST_MEM,
OP_DEST_PUSH,
OP_DEST_LEAVE,
};
struct op_dest {
enum op_dest_type type;
unsigned char reg;
int offset;
};
enum op_src_type {
OP_SRC_REG,
OP_SRC_REG_INDIRECT,
OP_SRC_CONST,
OP_SRC_POP,
OP_SRC_ADD,
OP_SRC_AND,
};
struct op_src {
enum op_src_type type;
unsigned char reg;
int offset;
};
struct stack_op {
struct op_dest dest;
struct op_src src;
};
void arch_initial_func_cfi_state(struct cfi_state *state);
int arch_decode_instruction(struct elf *elf, struct section *sec, int arch_decode_instruction(struct elf *elf, struct section *sec,
unsigned long offset, unsigned int maxlen, unsigned long offset, unsigned int maxlen,
unsigned int *len, unsigned char *type, unsigned int *len, unsigned char *type,
unsigned long *displacement); unsigned long *immediate, struct stack_op *op);
bool arch_callee_saved_reg(unsigned char reg);
#endif /* _ARCH_H */ #endif /* _ARCH_H */
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _OBJTOOL_CFI_H
#define _OBJTOOL_CFI_H
#define CFI_UNDEFINED -1
#define CFI_CFA -2
#define CFI_SP_INDIRECT -3
#define CFI_BP_INDIRECT -4
#define CFI_AX 0
#define CFI_DX 1
#define CFI_CX 2
#define CFI_BX 3
#define CFI_SI 4
#define CFI_DI 5
#define CFI_BP 6
#define CFI_SP 7
#define CFI_R8 8
#define CFI_R9 9
#define CFI_R10 10
#define CFI_R11 11
#define CFI_R12 12
#define CFI_R13 13
#define CFI_R14 14
#define CFI_R15 15
#define CFI_RA 16
#define CFI_NUM_REGS 17
struct cfi_reg {
int base;
int offset;
};
struct cfi_state {
struct cfi_reg cfa;
struct cfi_reg regs[CFI_NUM_REGS];
};
#endif /* _OBJTOOL_CFI_H */
This diff is collapsed.
/*
* Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CHECK_H
#define _CHECK_H
#include <stdbool.h>
#include "elf.h"
#include "cfi.h"
#include "arch.h"
#include <linux/hashtable.h>
struct insn_state {
struct cfi_reg cfa;
struct cfi_reg regs[CFI_NUM_REGS];
int stack_size;
bool bp_scratch;
bool drap;
int drap_reg;
};
struct instruction {
struct list_head list;
struct hlist_node hash;
struct section *sec;
unsigned long offset;
unsigned int len;
unsigned char type;
unsigned long immediate;
bool alt_group, visited, dead_end, ignore;
struct symbol *call_dest;
struct instruction *jump_dest;
struct list_head alts;
struct symbol *func;
struct stack_op stack_op;
struct insn_state state;
};
struct objtool_file {
struct elf *elf;
struct list_head insn_list;
DECLARE_HASHTABLE(insn_hash, 16);
struct section *rodata, *whitelist;
bool ignore_unreachables, c_file;
};
int check(const char *objname, bool nofp);
#define for_each_insn(file, insn) \
list_for_each_entry(insn, &file->insn_list, list)
#endif /* _CHECK_H */
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
#define ELF_C_READ_MMAP ELF_C_READ #define ELF_C_READ_MMAP ELF_C_READ
#endif #endif
#define WARN_ELF(format, ...) \
WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1))
struct section *find_section_by_name(struct elf *elf, const char *name) struct section *find_section_by_name(struct elf *elf, const char *name)
{ {
struct section *sec; struct section *sec;
...@@ -139,12 +142,12 @@ static int read_sections(struct elf *elf) ...@@ -139,12 +142,12 @@ static int read_sections(struct elf *elf)
int i; int i;
if (elf_getshdrnum(elf->elf, &sections_nr)) { if (elf_getshdrnum(elf->elf, &sections_nr)) {
perror("elf_getshdrnum"); WARN_ELF("elf_getshdrnum");
return -1; return -1;
} }
if (elf_getshdrstrndx(elf->elf, &shstrndx)) { if (elf_getshdrstrndx(elf->elf, &shstrndx)) {
perror("elf_getshdrstrndx"); WARN_ELF("elf_getshdrstrndx");
return -1; return -1;
} }
...@@ -165,37 +168,36 @@ static int read_sections(struct elf *elf) ...@@ -165,37 +168,36 @@ static int read_sections(struct elf *elf)
s = elf_getscn(elf->elf, i); s = elf_getscn(elf->elf, i);
if (!s) { if (!s) {
perror("elf_getscn"); WARN_ELF("elf_getscn");
return -1; return -1;
} }
sec->idx = elf_ndxscn(s); sec->idx = elf_ndxscn(s);
if (!gelf_getshdr(s, &sec->sh)) { if (!gelf_getshdr(s, &sec->sh)) {
perror("gelf_getshdr"); WARN_ELF("gelf_getshdr");
return -1; return -1;
} }
sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name);
if (!sec->name) { if (!sec->name) {
perror("elf_strptr"); WARN_ELF("elf_strptr");
return -1; return -1;
} }
sec->elf_data = elf_getdata(s, NULL); sec->data = elf_getdata(s, NULL);
if (!sec->elf_data) { if (!sec->data) {
perror("elf_getdata"); WARN_ELF("elf_getdata");
return -1; return -1;
} }
if (sec->elf_data->d_off != 0 || if (sec->data->d_off != 0 ||
sec->elf_data->d_size != sec->sh.sh_size) { sec->data->d_size != sec->sh.sh_size) {
WARN("unexpected data attributes for %s", sec->name); WARN("unexpected data attributes for %s", sec->name);
return -1; return -1;
} }
sec->data = (unsigned long)sec->elf_data->d_buf; sec->len = sec->data->d_size;
sec->len = sec->elf_data->d_size;
} }
/* sanity check, one more call to elf_nextscn() should return NULL */ /* sanity check, one more call to elf_nextscn() should return NULL */
...@@ -232,15 +234,15 @@ static int read_symbols(struct elf *elf) ...@@ -232,15 +234,15 @@ static int read_symbols(struct elf *elf)
sym->idx = i; sym->idx = i;
if (!gelf_getsym(symtab->elf_data, i, &sym->sym)) { if (!gelf_getsym(symtab->data, i, &sym->sym)) {
perror("gelf_getsym"); WARN_ELF("gelf_getsym");
goto err; goto err;
} }
sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, sym->name = elf_strptr(elf->elf, symtab->sh.sh_link,
sym->sym.st_name); sym->sym.st_name);
if (!sym->name) { if (!sym->name) {
perror("elf_strptr"); WARN_ELF("elf_strptr");
goto err; goto err;
} }
...@@ -322,8 +324,8 @@ static int read_relas(struct elf *elf) ...@@ -322,8 +324,8 @@ static int read_relas(struct elf *elf)
} }
memset(rela, 0, sizeof(*rela)); memset(rela, 0, sizeof(*rela));
if (!gelf_getrela(sec->elf_data, i, &rela->rela)) { if (!gelf_getrela(sec->data, i, &rela->rela)) {
perror("gelf_getrela"); WARN_ELF("gelf_getrela");
return -1; return -1;
} }
...@@ -362,12 +364,6 @@ struct elf *elf_open(const char *name) ...@@ -362,12 +364,6 @@ struct elf *elf_open(const char *name)
INIT_LIST_HEAD(&elf->sections); INIT_LIST_HEAD(&elf->sections);
elf->name = strdup(name);
if (!elf->name) {
perror("strdup");
goto err;
}
elf->fd = open(name, O_RDONLY); elf->fd = open(name, O_RDONLY);
if (elf->fd == -1) { if (elf->fd == -1) {
perror("open"); perror("open");
...@@ -376,12 +372,12 @@ struct elf *elf_open(const char *name) ...@@ -376,12 +372,12 @@ struct elf *elf_open(const char *name)
elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL);
if (!elf->elf) { if (!elf->elf) {
perror("elf_begin"); WARN_ELF("elf_begin");
goto err; goto err;
} }
if (!gelf_getehdr(elf->elf, &elf->ehdr)) { if (!gelf_getehdr(elf->elf, &elf->ehdr)) {
perror("gelf_getehdr"); WARN_ELF("gelf_getehdr");
goto err; goto err;
} }
...@@ -407,6 +403,12 @@ void elf_close(struct elf *elf) ...@@ -407,6 +403,12 @@ void elf_close(struct elf *elf)
struct symbol *sym, *tmpsym; struct symbol *sym, *tmpsym;
struct rela *rela, *tmprela; struct rela *rela, *tmprela;
if (elf->elf)
elf_end(elf->elf);
if (elf->fd > 0)
close(elf->fd);
list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) {
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);
...@@ -421,11 +423,6 @@ void elf_close(struct elf *elf) ...@@ -421,11 +423,6 @@ void elf_close(struct elf *elf)
list_del(&sec->list); list_del(&sec->list);
free(sec); free(sec);
} }
if (elf->name)
free(elf->name);
if (elf->fd > 0)
close(elf->fd);
if (elf->elf)
elf_end(elf->elf);
free(elf); free(elf);
} }
...@@ -37,10 +37,9 @@ struct section { ...@@ -37,10 +37,9 @@ struct section {
DECLARE_HASHTABLE(rela_hash, 16); DECLARE_HASHTABLE(rela_hash, 16);
struct section *base, *rela; struct section *base, *rela;
struct symbol *sym; struct symbol *sym;
Elf_Data *elf_data; Elf_Data *data;
char *name; char *name;
int idx; int idx;
unsigned long data;
unsigned int len; unsigned int len;
}; };
...@@ -86,6 +85,7 @@ struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, ...@@ -86,6 +85,7 @@ struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
struct symbol *find_containing_func(struct section *sec, unsigned long offset); struct symbol *find_containing_func(struct section *sec, unsigned long offset);
void elf_close(struct elf *elf); void elf_close(struct elf *elf);
#define for_each_sec(file, sec) \
list_for_each_entry(sec, &file->elf->sections, list)
#endif /* _OBJTOOL_ELF_H */ #endif /* _OBJTOOL_ELF_H */
...@@ -91,16 +91,16 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry, ...@@ -91,16 +91,16 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry,
alt->jump_or_nop = entry->jump_or_nop; alt->jump_or_nop = entry->jump_or_nop;
if (alt->group) { if (alt->group) {
alt->orig_len = *(unsigned char *)(sec->data + offset + alt->orig_len = *(unsigned char *)(sec->data->d_buf + offset +
entry->orig_len); entry->orig_len);
alt->new_len = *(unsigned char *)(sec->data + offset + alt->new_len = *(unsigned char *)(sec->data->d_buf + offset +
entry->new_len); entry->new_len);
} }
if (entry->feature) { if (entry->feature) {
unsigned short feature; unsigned short feature;
feature = *(unsigned short *)(sec->data + offset + feature = *(unsigned short *)(sec->data->d_buf + offset +
entry->feature); entry->feature);
/* /*
......
...@@ -18,6 +18,13 @@ ...@@ -18,6 +18,13 @@
#ifndef _WARN_H #ifndef _WARN_H
#define _WARN_H #define _WARN_H
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "elf.h"
extern const char *objname; extern const char *objname;
static inline char *offstr(struct section *sec, unsigned long offset) static inline char *offstr(struct section *sec, unsigned long offset)
...@@ -57,4 +64,7 @@ static inline char *offstr(struct section *sec, unsigned long offset) ...@@ -57,4 +64,7 @@ static inline char *offstr(struct section *sec, unsigned long offset)
free(_str); \ free(_str); \
}) })
#define WARN_ELF(format, ...) \
WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1))
#endif /* _WARN_H */ #endif /* _WARN_H */
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