objtool: Refactor jump table code
authorJosh Poimboeuf <jpoimboe@redhat.com>
Thu, 18 Jul 2019 01:36:53 +0000 (20:36 -0500)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 18 Jul 2019 19:01:09 +0000 (21:01 +0200)
Now that C jump tables are supported, call them "jump tables" instead of
"switch tables".  Also rename some other variables, add comments, and
simplify the code flow a bit.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Nick Desaulniers <ndesaulniers@google.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/cf951b0c0641628e0b9b81f7ceccd9bcabcb4bd8.1563413318.git.jpoimboe@redhat.com
tools/objtool/check.c
tools/objtool/elf.c
tools/objtool/elf.h

index 7fe31e0..4525cf6 100644 (file)
@@ -627,7 +627,7 @@ static int add_jump_destinations(struct objtool_file *file)
                         * However this code can't completely replace the
                         * read_symbols() code because this doesn't detect the
                         * case where the parent function's only reference to a
-                        * subfunction is through a switch table.
+                        * subfunction is through a jump table.
                         */
                        if (!strstr(insn->func->name, ".cold.") &&
                            strstr(insn->jump_dest->func->name, ".cold.")) {
@@ -899,20 +899,24 @@ out:
        return ret;
 }
 
-static int add_switch_table(struct objtool_file *file, struct instruction *insn,
+static int add_jump_table(struct objtool_file *file, struct instruction *insn,
                            struct rela *table, struct rela *next_table)
 {
        struct rela *rela = table;
-       struct instruction *alt_insn;
+       struct instruction *dest_insn;
        struct alternative *alt;
        struct symbol *pfunc = insn->func->pfunc;
        unsigned int prev_offset = 0;
 
-       list_for_each_entry_from(rela, &table->rela_sec->rela_list, list) {
+       /*
+        * Each @rela is a switch table relocation which points to the target
+        * instruction.
+        */
+       list_for_each_entry_from(rela, &table->sec->rela_list, list) {
                if (rela == next_table)
                        break;
 
-               /* Make sure the switch table entries are consecutive: */
+               /* Make sure the table entries are consecutive: */
                if (prev_offset && rela->offset != prev_offset + 8)
                        break;
 
@@ -921,12 +925,12 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
                    rela->addend == pfunc->offset)
                        break;
 
-               alt_insn = find_insn(file, rela->sym->sec, rela->addend);
-               if (!alt_insn)
+               dest_insn = find_insn(file, rela->sym->sec, rela->addend);
+               if (!dest_insn)
                        break;
 
-               /* Make sure the jmp dest is in the function or subfunction: */
-               if (alt_insn->func->pfunc != pfunc)
+               /* Make sure the destination is in the same function: */
+               if (dest_insn->func->pfunc != pfunc)
                        break;
 
                alt = malloc(sizeof(*alt));
@@ -935,7 +939,7 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
                        return -1;
                }
 
-               alt->insn = alt_insn;
+               alt->insn = dest_insn;
                list_add_tail(&alt->list, &insn->alts);
                prev_offset = rela->offset;
        }
@@ -950,7 +954,7 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
 }
 
 /*
- * find_switch_table() - Given a dynamic jump, find the switch jump table in
+ * find_jump_table() - Given a dynamic jump, find the switch jump table in
  * .rodata associated with it.
  *
  * There are 3 basic patterns:
@@ -992,13 +996,13 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
  *
  *    NOTE: RETPOLINE made it harder still to decode dynamic jumps.
  */
-static struct rela *find_switch_table(struct objtool_file *file,
+static struct rela *find_jump_table(struct objtool_file *file,
                                      struct symbol *func,
                                      struct instruction *insn)
 {
-       struct rela *text_rela, *rodata_rela;
+       struct rela *text_rela, *table_rela;
        struct instruction *orig_insn = insn;
-       struct section *rodata_sec;
+       struct section *table_sec;
        unsigned long table_offset;
 
        /*
@@ -1031,7 +1035,7 @@ static struct rela *find_switch_table(struct objtool_file *file,
                        continue;
 
                table_offset = text_rela->addend;
-               rodata_sec = text_rela->sym->sec;
+               table_sec = text_rela->sym->sec;
 
                if (text_rela->type == R_X86_64_PC32)
                        table_offset += 4;
@@ -1045,29 +1049,31 @@ static struct rela *find_switch_table(struct objtool_file *file,
                 * 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) &&
-                   strcmp(rodata_sec->name, C_JUMP_TABLE_SECTION))
+               if (find_symbol_containing(table_sec, table_offset) &&
+                   strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
                        continue;
 
-               rodata_rela = find_rela_by_dest(rodata_sec, table_offset);
-               if (rodata_rela) {
-                       /*
-                        * Use of RIP-relative switch jumps is quite rare, and
-                        * indicates a rare GCC quirk/bug which can leave dead
-                        * code behind.
-                        */
-                       if (text_rela->type == R_X86_64_PC32)
-                               file->ignore_unreachables = true;
+               /* Each table entry has a rela associated with it. */
+               table_rela = find_rela_by_dest(table_sec, table_offset);
+               if (!table_rela)
+                       continue;
 
-                       return rodata_rela;
-               }
+               /*
+                * Use of RIP-relative switch jumps is quite rare, and
+                * indicates a rare GCC quirk/bug which can leave dead code
+                * behind.
+                */
+               if (text_rela->type == R_X86_64_PC32)
+                       file->ignore_unreachables = true;
+
+               return table_rela;
        }
 
        return NULL;
 }
 
 
-static int add_func_switch_tables(struct objtool_file *file,
+static int add_func_jump_tables(struct objtool_file *file,
                                  struct symbol *func)
 {
        struct instruction *insn, *last = NULL, *prev_jump = NULL;
@@ -1080,7 +1086,7 @@ static int add_func_switch_tables(struct objtool_file *file,
 
                /*
                 * Store back-pointers for unconditional forward jumps such
-                * that find_switch_table() can back-track using those and
+                * that find_jump_table() can back-track using those and
                 * avoid some potentially confusing code.
                 */
                if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
@@ -1095,17 +1101,17 @@ static int add_func_switch_tables(struct objtool_file *file,
                if (insn->type != INSN_JUMP_DYNAMIC)
                        continue;
 
-               rela = find_switch_table(file, func, insn);
+               rela = find_jump_table(file, func, insn);
                if (!rela)
                        continue;
 
                /*
-                * We found a switch table, but we don't know yet how big it
+                * We found a jump table, but we don't know yet how big it
                 * is.  Don't add it until we reach the end of the function or
-                * the beginning of another switch table in the same function.
+                * the beginning of another jump table in the same function.
                 */
                if (prev_jump) {
-                       ret = add_switch_table(file, prev_jump, prev_rela, rela);
+                       ret = add_jump_table(file, prev_jump, prev_rela, rela);
                        if (ret)
                                return ret;
                }
@@ -1115,7 +1121,7 @@ static int add_func_switch_tables(struct objtool_file *file,
        }
 
        if (prev_jump) {
-               ret = add_switch_table(file, prev_jump, prev_rela, NULL);
+               ret = add_jump_table(file, prev_jump, prev_rela, NULL);
                if (ret)
                        return ret;
        }
@@ -1128,7 +1134,7 @@ static int add_func_switch_tables(struct objtool_file *file,
  * section which contains a list of addresses within the function to jump to.
  * This finds these jump tables and adds them to the insn->alts lists.
  */
-static int add_switch_table_alts(struct objtool_file *file)
+static int add_jump_table_alts(struct objtool_file *file)
 {
        struct section *sec;
        struct symbol *func;
@@ -1142,7 +1148,7 @@ static int add_switch_table_alts(struct objtool_file *file)
                        if (func->type != STT_FUNC)
                                continue;
 
-                       ret = add_func_switch_tables(file, func);
+                       ret = add_func_jump_tables(file, func);
                        if (ret)
                                return ret;
                }
@@ -1339,7 +1345,7 @@ static int decode_sections(struct objtool_file *file)
        if (ret)
                return ret;
 
-       ret = add_switch_table_alts(file);
+       ret = add_jump_table_alts(file);
        if (ret)
                return ret;
 
index 9194732..edba474 100644 (file)
@@ -385,7 +385,7 @@ static int read_relas(struct elf *elf)
                        rela->offset = rela->rela.r_offset;
                        symndx = GELF_R_SYM(rela->rela.r_info);
                        rela->sym = find_symbol_by_index(elf, symndx);
-                       rela->rela_sec = sec;
+                       rela->sec = sec;
                        if (!rela->sym) {
                                WARN("can't find rela entry symbol %d for %s",
                                     symndx, sec->name);
index 2fe0b0a..d4d3e05 100644 (file)
@@ -57,7 +57,7 @@ struct rela {
        struct list_head list;
        struct hlist_node hash;
        GElf_Rela rela;
-       struct section *rela_sec;
+       struct section *sec;
        struct symbol *sym;
        unsigned int type;
        unsigned long offset;