From: Steven Rostedt <[email protected]>

In preparation for removing weak functions from available_filter_functions,
have the sorttable.c code that sorts the mcount regions during the build
modified to take a "nm -S vmlinux" as input, sort it, and any function
listed in the mcount_loc section that is not within a boundary of the
function list given by nm is considered a weak function and is zeroed out.
This will move them all to the beginning of the mcount_loc section. This
will allow for the ftrace code to be able to skip them in one go.

Signed-off-by: Steven Rostedt (Google) <[email protected]>
---
 scripts/link-vmlinux.sh |   4 +-
 scripts/sorttable.c     | 129 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 130 insertions(+), 3 deletions(-)

diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index d853ddb3b28c..976808c46665 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -177,12 +177,14 @@ mksysmap()
 
 sorttable()
 {
-       ${objtree}/scripts/sorttable ${1}
+       ${NM} -S ${1} > .tmp_vmlinux.nm-sort
+       ${objtree}/scripts/sorttable -s .tmp_vmlinux.nm-sort ${1}
 }
 
 cleanup()
 {
        rm -f .btf.*
+       rm -f .tmp_vmlinux.nm-sort
        rm -f System.map
        rm -f vmlinux
        rm -f vmlinux.map
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index c26e71e6ec6b..1a2b420a4929 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -446,6 +446,98 @@ static void *sort_orctable(void *arg)
 #endif
 
 #ifdef MCOUNT_SORT_ENABLED
+struct func_info {
+       uint64_t        addr;
+       uint64_t        size;
+};
+
+/* List of functions created by: nm -S vmlinux */
+static struct func_info *function_list;
+static int function_list_size;
+
+/* Allocate functions in 1k blocks */
+#define FUNC_BLK_SIZE  1024
+#define FUNC_BLK_MASK  (FUNC_BLK_SIZE - 1)
+
+static int add_field(uint64_t addr, uint64_t size)
+{
+       struct func_info *fi;
+       int fsize = function_list_size;
+
+       if (!(fsize & FUNC_BLK_MASK)) {
+               fsize += FUNC_BLK_SIZE;
+               fi = realloc(function_list, fsize * sizeof(struct func_info));
+               if (!fi)
+                       return -1;
+               function_list = fi;
+       }
+       fi = &function_list[function_list_size++];
+       fi->addr = addr;
+       fi->size = size;
+       return 0;
+}
+
+/* Only return match if the address lies inside the function size */
+static int cmp_func_addr(const void *K, const void *A)
+{
+       uint64_t key = *(const uint64_t *)K;
+       const struct func_info *a = A;
+
+       if (key < a->addr)
+               return -1;
+       return key >= a->addr + a->size;
+}
+
+/* Find the function in function list that is bounded by the function size */
+static int find_func(uint64_t key)
+{
+       return bsearch(&key, function_list, function_list_size,
+                      sizeof(struct func_info), cmp_func_addr) != NULL;
+}
+
+static int cmp_funcs(const void *A, const void *B)
+{
+       const struct func_info *a = A;
+       const struct func_info *b = B;
+
+       if (a->addr < b->addr)
+               return -1;
+       return a->addr > b->addr;
+}
+
+static int parse_symbols(const char *fname)
+{
+       FILE *fp;
+       char addr_str[20]; /* Only need 17, but round up to next int size */
+       char size_str[20];
+       char type;
+
+       fp = fopen(fname, "r");
+       if (!fp) {
+               perror(fname);
+               return -1;
+       }
+
+       while (fscanf(fp, "%16s %16s %c %*s\n", addr_str, size_str, &type) == 
3) {
+               uint64_t addr;
+               uint64_t size;
+
+               /* Only care about functions */
+               if (type != 't' && type != 'T')
+                       continue;
+
+               addr = strtoull(addr_str, NULL, 16);
+               size = strtoull(size_str, NULL, 16);
+               if (add_field(addr, size) < 0)
+                       return -1;
+       }
+       fclose(fp);
+
+       qsort(function_list, function_list_size, sizeof(struct func_info), 
cmp_funcs);
+
+       return 0;
+}
+
 static pthread_t mcount_sort_thread;
 
 struct elf_mcount_loc {
@@ -463,6 +555,22 @@ static void *sort_mcount_loc(void *arg)
                                        + shdr_offset(emloc->init_data_sec);
        uint64_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
        unsigned char *start_loc = (void *)emloc->ehdr + offset;
+       void *end_loc = start_loc + count;
+
+       /* zero out any locations not found by function list */
+       if (function_list_size) {
+               for (void *ptr = start_loc; ptr < end_loc; ptr += long_size) {
+                       uint64_t key;
+
+                       key = long_size == 4 ? r((uint32_t *)ptr) : 
r8((uint64_t *)ptr);
+                       if (!find_func(key)) {
+                               if (long_size == 4)
+                                       *(uint32_t *)ptr = 0;
+                               else
+                                       *(uint64_t *)ptr = 0;
+                       }
+               }
+       }
 
        qsort(start_loc, count/long_size, long_size, compare_extable);
        return NULL;
@@ -502,6 +610,8 @@ static void get_mcount_loc(struct elf_mcount_loc *emloc, 
Elf_Shdr *symtab_sec,
                return;
        }
 }
+#else /* MCOUNT_SORT_ENABLED */
+static inline int parse_symbols(const char *fname) { return 0; }
 #endif
 
 static int do_sort(Elf_Ehdr *ehdr,
@@ -930,14 +1040,29 @@ int main(int argc, char *argv[])
        int i, n_error = 0;  /* gcc-4.3.0 false positive complaint */
        size_t size = 0;
        void *addr = NULL;
+       int c;
+
+       while ((c = getopt(argc, argv, "s:")) >= 0) {
+               switch (c) {
+               case 's':
+                       if (parse_symbols(optarg) < 0) {
+                               fprintf(stderr, "Could not parse %s\n", optarg);
+                               return -1;
+                       }
+                       break;
+               default:
+                       fprintf(stderr, "usage: sorttable [-s nm-file] 
vmlinux...\n");
+                       return 0;
+               }
+       }
 
-       if (argc < 2) {
+       if ((argc - optind) < 1) {
                fprintf(stderr, "usage: sorttable vmlinux...\n");
                return 0;
        }
 
        /* Process each file in turn, allowing deep failure. */
-       for (i = 1; i < argc; i++) {
+       for (i = optind; i < argc; i++) {
                addr = mmap_file(argv[i], &size);
                if (!addr) {
                        ++n_error;
-- 
2.45.2



Reply via email to