OSDN Git Service

objtool: Add .call_sites section
authorPeter Zijlstra <peterz@infradead.org>
Thu, 15 Sep 2022 11:11:09 +0000 (13:11 +0200)
committerPeter Zijlstra <peterz@infradead.org>
Mon, 17 Oct 2022 14:41:07 +0000 (16:41 +0200)
In preparation for call depth tracking provide a section which collects all
direct calls.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20220915111146.016511961@infradead.org
arch/x86/kernel/vmlinux.lds.S
tools/objtool/check.c
tools/objtool/include/objtool/objtool.h
tools/objtool/objtool.c

index 0e9fc08..b69df9e 100644 (file)
@@ -291,6 +291,13 @@ SECTIONS
                *(.return_sites)
                __return_sites_end = .;
        }
+
+       . = ALIGN(8);
+       .call_sites : AT(ADDR(.call_sites) - LOAD_OFFSET) {
+               __call_sites = .;
+               *(.call_sites)
+               __call_sites_end = .;
+       }
 #endif
 
 #ifdef CONFIG_X86_KERNEL_IBT
index bb7c819..f578e03 100644 (file)
@@ -902,6 +902,49 @@ static int create_mcount_loc_sections(struct objtool_file *file)
        return 0;
 }
 
+static int create_direct_call_sections(struct objtool_file *file)
+{
+       struct instruction *insn;
+       struct section *sec;
+       unsigned int *loc;
+       int idx;
+
+       sec = find_section_by_name(file->elf, ".call_sites");
+       if (sec) {
+               INIT_LIST_HEAD(&file->call_list);
+               WARN("file already has .call_sites section, skipping");
+               return 0;
+       }
+
+       if (list_empty(&file->call_list))
+               return 0;
+
+       idx = 0;
+       list_for_each_entry(insn, &file->call_list, call_node)
+               idx++;
+
+       sec = elf_create_section(file->elf, ".call_sites", 0, sizeof(unsigned int), idx);
+       if (!sec)
+               return -1;
+
+       idx = 0;
+       list_for_each_entry(insn, &file->call_list, call_node) {
+
+               loc = (unsigned int *)sec->data->d_buf + idx;
+               memset(loc, 0, sizeof(unsigned int));
+
+               if (elf_add_reloc_to_insn(file->elf, sec,
+                                         idx * sizeof(unsigned int),
+                                         R_X86_64_PC32,
+                                         insn->sec, insn->offset))
+                       return -1;
+
+               idx++;
+       }
+
+       return 0;
+}
+
 /*
  * Warnings shouldn't be reported for ignored functions.
  */
@@ -1279,6 +1322,9 @@ static void annotate_call_site(struct objtool_file *file,
                return;
        }
 
+       if (insn->type == INSN_CALL && !insn->sec->init)
+               list_add_tail(&insn->call_node, &file->call_list);
+
        if (!sibling && dead_end_function(file, sym))
                insn->dead_end = true;
 }
@@ -4305,6 +4351,11 @@ int check(struct objtool_file *file)
                if (ret < 0)
                        goto out;
                warnings += ret;
+
+               ret = create_direct_call_sections(file);
+               if (ret < 0)
+                       goto out;
+               warnings += ret;
        }
 
        if (opts.mcount) {
index 7f2d1b0..6b40977 100644 (file)
@@ -28,6 +28,7 @@ struct objtool_file {
        struct list_head static_call_list;
        struct list_head mcount_loc_list;
        struct list_head endbr_list;
+       struct list_head call_list;
        bool ignore_unreachables, hints, rodata;
 
        unsigned int nr_endbr;
index a7ecc32..6affd80 100644 (file)
@@ -106,6 +106,7 @@ struct objtool_file *objtool_open_read(const char *_objname)
        INIT_LIST_HEAD(&file.static_call_list);
        INIT_LIST_HEAD(&file.mcount_loc_list);
        INIT_LIST_HEAD(&file.endbr_list);
+       INIT_LIST_HEAD(&file.call_list);
        file.ignore_unreachables = opts.no_unreachable;
        file.hints = false;