From: George Guo <[email protected]>

With -mannotate-tablejump, LoongArch compilers emit a
.discard.tablejump_annotate section.  Each entry is a pair of 8-byte
words: the address of a jump instruction and the address of its jump
table.  objtool reads these pairs to find switch jump tables when
decoding.

klp-diff creates one fake symbol per 8-byte word and clones a word only
if should_keep_special_sym() accepts it.  The default rule keeps a word
only if it references a function that was cloned into the output
module.  The instruction-side word references the function and is
kept.  The table-side word references the jump table via its .rodata
section symbol, which is not a function symbol, so it is dropped.

The cloned annotate section then holds only instruction-side words,
compacted together.  The pairing is destroyed.  Parsing the malformed
section crashes objtool on the patch module and no .ko is produced:

  Building patch module: livepatch-shadow-newpid.ko
  livepatch-shadow-newpid.o: error: SIGSEGV: objtool crash!

Keep all .discard.tablejump_annotate words whose referenced symbol has
been cloned.

Reproduced with the shadow-newpid test, which patches
proc_pid_status().  That function contains two switch jump tables.

Before, klp-diff clones only the instruction-side words:

  DEBUG: vmlinux.o: _discard_tablejump_annotate_57441 [+DATA]
  DEBUG: vmlinux.o:         .discard.tablejump_annotate+0x0: 
proc_pid_status+0xc70 [FUNC GLOBAL]
  DEBUG: vmlinux.o: _discard_tablejump_annotate_57443 [+DATA]
  DEBUG: vmlinux.o:         .discard.tablejump_annotate+0x8: 
proc_pid_status+0xd2c [FUNC GLOBAL]

After, the full pairs are kept, including the .rodata table words:

  DEBUG: vmlinux.o: _discard_tablejump_annotate_57441 [+DATA]
  DEBUG: vmlinux.o:         .discard.tablejump_annotate+0x0: 
proc_pid_status+0xc70 [FUNC GLOBAL]
  DEBUG: vmlinux.o: _discard_tablejump_annotate_57442 [+DATA]
  DEBUG: vmlinux.o:         .discard.tablejump_annotate+0x8: 
.rodata.proc_pid_status+0x0 [SECTION]
  DEBUG: vmlinux.o: _discard_tablejump_annotate_57443 [+DATA]
  DEBUG: vmlinux.o:         .discard.tablejump_annotate+0x10: 
proc_pid_status+0xd2c [FUNC GLOBAL]
  DEBUG: vmlinux.o: _discard_tablejump_annotate_57444 [+DATA]
  DEBUG: vmlinux.o:         .discard.tablejump_annotate+0x18: 
.rodata.proc_pid_status+0x80 [SECTION]

and the patch module builds.

Co-developed-by: Kexin Liu <[email protected]>
Signed-off-by: Kexin Liu <[email protected]>
Signed-off-by: George Guo <[email protected]>
---
 tools/objtool/klp-diff.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 92cf0fc3ff2f..f151ffc71184 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1956,6 +1956,7 @@ static int create_fake_symbols(struct elf *elf)
 static bool should_keep_special_sym(struct elf *elf, struct symbol *sym)
 {
        bool annotate_insn = !strcmp(sym->sec->name, ".discard.annotate_insn");
+       bool tablejump_annotate = !strcmp(sym->sec->name, 
".discard.tablejump_annotate");
        struct reloc *reloc;
 
        if (is_sec_sym(sym) || !sym->sec->rsec)
@@ -1968,6 +1969,16 @@ static bool should_keep_special_sym(struct elf *elf, 
struct symbol *sym)
                if (!reloc->sym->clone || is_undef_sym(reloc->sym->clone))
                        continue;
 
+               /*
+                * .discard.tablejump_annotate (LoongArch -mannotate-tablejump)
+                * holds pairs of words: a jump instruction and its jump table.
+                * The table word references the table via its .rodata section
+                * symbol, which the is_func_sym() rule below would drop,
+                * breaking the pairing.  Keep both words of each entry.
+                */
+               if (tablejump_annotate)
+                       return true;
+
                /*
                 * Keep special section references to cloned functions.
                 * In some cases annotate_insn can also reference cloned alt
-- 
2.53.0


Reply via email to