summaryrefslogtreecommitdiffstats
path: root/tools/objtool
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2019-06-27 21:50:46 -0400
committerIngo Molnar <mingo@kernel.org>2019-07-09 07:55:46 -0400
commit87b512def792579641499d9bef1d640994ea9c18 (patch)
treebac6ea7c9a3a0822b358931ff7260eecfb9a1f59 /tools/objtool
parent222a21d29521d144f3dd7a0bc4d4020e448f0126 (diff)
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: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Thomas 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.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/objtool')
-rw-r--r--tools/objtool/check.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 172f99195726..27818a93f0b1 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -18,6 +18,8 @@
18 18
19#define FAKE_JUMP_OFFSET -1 19#define FAKE_JUMP_OFFSET -1
20 20
21#define C_JUMP_TABLE_SECTION ".rodata..c_jump_table"
22
21struct alternative { 23struct alternative {
22 struct list_head list; 24 struct list_head list;
23 struct instruction *insn; 25 struct instruction *insn;
@@ -1035,9 +1037,15 @@ static struct rela *find_switch_table(struct objtool_file *file,
1035 1037
1036 /* 1038 /*
1037 * Make sure the .rodata address isn't associated with a 1039 * Make sure the .rodata address isn't associated with a
1038 * symbol. gcc jump tables are anonymous data. 1040 * symbol. GCC jump tables are anonymous data.
1041 *
1042 * Also support C jump tables which are in the same format as
1043 * switch jump tables. For objtool to recognize them, they
1044 * need to be placed in the C_JUMP_TABLE_SECTION section. They
1045 * have symbols associated with them.
1039 */ 1046 */
1040 if (find_symbol_containing(rodata_sec, table_offset)) 1047 if (find_symbol_containing(rodata_sec, table_offset) &&
1048 strcmp(rodata_sec->name, C_JUMP_TABLE_SECTION))
1041 continue; 1049 continue;
1042 1050
1043 rodata_rela = find_rela_by_dest(rodata_sec, table_offset); 1051 rodata_rela = find_rela_by_dest(rodata_sec, table_offset);
@@ -1277,13 +1285,18 @@ static void mark_rodata(struct objtool_file *file)
1277 bool found = false; 1285 bool found = false;
1278 1286
1279 /* 1287 /*
1280 * This searches for the .rodata section or multiple .rodata.func_name 1288 * Search for the following rodata sections, each of which can
1281 * sections if -fdata-sections is being used. The .str.1.1 and .str.1.8 1289 * potentially contain jump tables:
1282 * rodata sections are ignored as they don't contain jump tables. 1290 *
1291 * - .rodata: can contain GCC switch tables
1292 * - .rodata.<func>: same, if -fdata-sections is being used
1293 * - .rodata..c_jump_table: contains C annotated jump tables
1294 *
1295 * .rodata.str1.* sections are ignored; they don't contain jump tables.
1283 */ 1296 */
1284 for_each_sec(file, sec) { 1297 for_each_sec(file, sec) {
1285 if (!strncmp(sec->name, ".rodata", 7) && 1298 if ((!strncmp(sec->name, ".rodata", 7) && !strstr(sec->name, ".str1.")) ||
1286 !strstr(sec->name, ".str1.")) { 1299 !strcmp(sec->name, C_JUMP_TABLE_SECTION)) {
1287 sec->rodata = true; 1300 sec->rodata = true;
1288 found = true; 1301 found = true;
1289 } 1302 }