Commit 87b512de authored by Josh Poimboeuf's avatar Josh Poimboeuf Committed by Ingo Molnar

objtool: Add support for C jump tables

Objtool doesn't know how to read C jump tables, so it has to whitelist
functions which use them, causing missing ORC unwinder data for such
functions, e.g. ___bpf_prog_run().

C jump tables are very similar to GCC switch jump tables, which objtool
already knows how to read.  So adding support for C jump tables is easy.
It just needs to be able to find the tables and distinguish them from
other data.

To allow the jump tables to be found, create an __annotate_jump_table
macro which can be used to annotate them.

The annotation is done by placing the jump table in an
.rodata..c_jump_table section.  The '.rodata' prefix ensures that the data
will be placed in the rodata section by the vmlinux linker script.  The
double periods are part of an existing convention which distinguishes
kernel sections from GCC sections.
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Song Liu <songliubraving@fb.com>
Cc: Kairui Song <kasong@redhat.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lkml.kernel.org/r/0ba2ca30442b16b97165992381ce643dc27b3d1a.1561685471.git.jpoimboe@redhat.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 222a21d2
...@@ -116,9 +116,14 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, ...@@ -116,9 +116,14 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
".pushsection .discard.unreachable\n\t" \ ".pushsection .discard.unreachable\n\t" \
".long 999b - .\n\t" \ ".long 999b - .\n\t" \
".popsection\n\t" ".popsection\n\t"
/* Annotate a C jump table to allow objtool to follow the code flow */
#define __annotate_jump_table __section(".rodata..c_jump_table")
#else #else
#define annotate_reachable() #define annotate_reachable()
#define annotate_unreachable() #define annotate_unreachable()
#define __annotate_jump_table
#endif #endif
#ifndef ASM_UNREACHABLE #ifndef ASM_UNREACHABLE
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#define FAKE_JUMP_OFFSET -1 #define FAKE_JUMP_OFFSET -1
#define C_JUMP_TABLE_SECTION ".rodata..c_jump_table"
struct alternative { struct alternative {
struct list_head list; struct list_head list;
struct instruction *insn; struct instruction *insn;
...@@ -1035,9 +1037,15 @@ static struct rela *find_switch_table(struct objtool_file *file, ...@@ -1035,9 +1037,15 @@ static struct rela *find_switch_table(struct objtool_file *file,
/* /*
* Make sure the .rodata address isn't associated with a * Make sure the .rodata address isn't associated with a
* symbol. gcc jump tables are anonymous data. * symbol. GCC jump tables are anonymous data.
*
* Also support C jump tables which are in the same format as
* switch jump tables. For objtool to recognize them, they
* need to be placed in the C_JUMP_TABLE_SECTION section. They
* have symbols associated with them.
*/ */
if (find_symbol_containing(rodata_sec, table_offset)) if (find_symbol_containing(rodata_sec, table_offset) &&
strcmp(rodata_sec->name, C_JUMP_TABLE_SECTION))
continue; continue;
rodata_rela = find_rela_by_dest(rodata_sec, table_offset); rodata_rela = find_rela_by_dest(rodata_sec, table_offset);
...@@ -1277,13 +1285,18 @@ static void mark_rodata(struct objtool_file *file) ...@@ -1277,13 +1285,18 @@ static void mark_rodata(struct objtool_file *file)
bool found = false; bool found = false;
/* /*
* This searches for the .rodata section or multiple .rodata.func_name * Search for the following rodata sections, each of which can
* sections if -fdata-sections is being used. The .str.1.1 and .str.1.8 * potentially contain jump tables:
* rodata sections are ignored as they don't contain jump tables. *
* - .rodata: can contain GCC switch tables
* - .rodata.<func>: same, if -fdata-sections is being used
* - .rodata..c_jump_table: contains C annotated jump tables
*
* .rodata.str1.* sections are ignored; they don't contain jump tables.
*/ */
for_each_sec(file, sec) { for_each_sec(file, sec) {
if (!strncmp(sec->name, ".rodata", 7) && if ((!strncmp(sec->name, ".rodata", 7) && !strstr(sec->name, ".str1.")) ||
!strstr(sec->name, ".str1.")) { !strcmp(sec->name, C_JUMP_TABLE_SECTION)) {
sec->rodata = true; sec->rodata = true;
found = true; found = true;
} }
......
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