mirror of
https://github.com/torvalds/linux.git
synced 2024-12-04 01:51:34 +00:00
4a60aa05a0
Add support for processing switch jump tables in objects with multiple .rodata sections, such as those created by '-ffunction-sections' and '-fdata-sections'. Currently, objtool always looks in .rodata for jump table information, which results in many "sibling call from callable instruction with modified stack frame" warnings with objects compiled using those flags. The fix is comprised of three parts: 1. Flagging all .rodata sections when importing ELF information for easier checking later. 2. Keeping a reference to the section each relocation is from in order to get the list_head for the other relocations in that section. 3. Finding jump tables by following relocations to .rodata sections, rather than always referencing a single global .rodata section. The patch has been tested without data sections enabled and no differences in the resulting orc unwind information were seen. Note that as objtool adds terminators to end of each .text section the unwind information generated between a function+data sections build and a normal build aren't directly comparable. Manual inspection suggests that objtool is now generating the correct information, or at least making more of an effort to do so than it did previously. Signed-off-by: Allan Xavier <allan.x.xavier@oracle.com> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lkml.kernel.org/r/099bdc375195c490dda04db777ee0b95d566ded1.1536325914.git.jpoimboe@redhat.com
83 lines
2.2 KiB
C
83 lines
2.2 KiB
C
/*
|
|
* 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 "orc.h"
|
|
#include <linux/hashtable.h>
|
|
|
|
struct insn_state {
|
|
struct cfi_reg cfa;
|
|
struct cfi_reg regs[CFI_NUM_REGS];
|
|
int stack_size;
|
|
unsigned char type;
|
|
bool bp_scratch;
|
|
bool drap, end;
|
|
int drap_reg, drap_offset;
|
|
struct cfi_reg vals[CFI_NUM_REGS];
|
|
};
|
|
|
|
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, hint, save, restore, ignore_alts;
|
|
bool retpoline_safe;
|
|
struct symbol *call_dest;
|
|
struct instruction *jump_dest;
|
|
struct instruction *first_jump_src;
|
|
struct list_head alts;
|
|
struct symbol *func;
|
|
struct stack_op stack_op;
|
|
struct insn_state state;
|
|
struct orc_entry orc;
|
|
};
|
|
|
|
struct objtool_file {
|
|
struct elf *elf;
|
|
struct list_head insn_list;
|
|
DECLARE_HASHTABLE(insn_hash, 16);
|
|
struct section *whitelist;
|
|
bool ignore_unreachables, c_file, hints, rodata;
|
|
};
|
|
|
|
int check(const char *objname, bool orc);
|
|
|
|
struct instruction *find_insn(struct objtool_file *file,
|
|
struct section *sec, unsigned long offset);
|
|
|
|
#define for_each_insn(file, insn) \
|
|
list_for_each_entry(insn, &file->insn_list, list)
|
|
|
|
#define sec_for_each_insn(file, sec, insn) \
|
|
for (insn = find_insn(file, sec, 0); \
|
|
insn && &insn->list != &file->insn_list && \
|
|
insn->sec == sec; \
|
|
insn = list_next_entry(insn, list))
|
|
|
|
|
|
#endif /* _CHECK_H */
|