]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - scripts/kallsyms.c
Add linux-next specific files for 20160211
[karo-tx-linux.git] / scripts / kallsyms.c
index 8fa81e84e29510c053e5e52cefc5eb9e1da16887..638b143ee60f4246cc16d67936bc62095a66c646 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <limits.h>
 
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
@@ -34,6 +35,7 @@ struct sym_entry {
        unsigned int len;
        unsigned int start_pos;
        unsigned char *sym;
+       unsigned int percpu_absolute;
 };
 
 struct addr_range {
@@ -42,6 +44,7 @@ struct addr_range {
 };
 
 static unsigned long long _text;
+static unsigned long long relative_base;
 static struct addr_range text_ranges[] = {
        { "_stext",     "_etext"     },
        { "_sinittext", "_einittext" },
@@ -61,6 +64,7 @@ static int all_symbols = 0;
 static int absolute_percpu = 0;
 static char symbol_prefix_char = '\0';
 static unsigned long long kernel_start_addr = 0;
+static int base_relative = 0;
 
 int token_profit[0x10000];
 
@@ -74,7 +78,7 @@ static void usage(void)
        fprintf(stderr, "Usage: kallsyms [--all-symbols] "
                        "[--symbol-prefix=<prefix char>] "
                        "[--page-offset=<CONFIG_PAGE_OFFSET>] "
-                       "< in.map > out.S\n");
+                       "[--base-relative] < in.map > out.S\n");
        exit(1);
 }
 
@@ -171,6 +175,8 @@ static int read_symbol(FILE *in, struct sym_entry *s)
        strcpy((char *)s->sym + 1, str);
        s->sym[0] = stype;
 
+       s->percpu_absolute = 0;
+
        /* Record if we've found __per_cpu_start/end. */
        check_symbol_range(sym, s->addr, &percpu_range, 1);
 
@@ -202,6 +208,8 @@ static int symbol_valid(struct sym_entry *s)
         */
        static char *special_symbols[] = {
                "kallsyms_addresses",
+               "kallsyms_offsets",
+               "kallsyms_relative_base",
                "kallsyms_num_syms",
                "kallsyms_names",
                "kallsyms_markers",
@@ -325,7 +333,7 @@ static int expand_symbol(unsigned char *data, int len, char *result)
 
 static int symbol_absolute(struct sym_entry *s)
 {
-       return toupper(s->sym[0]) == 'A';
+       return s->percpu_absolute;
 }
 
 static void write_src(void)
@@ -346,16 +354,48 @@ static void write_src(void)
 
        printf("\t.section .rodata, \"a\"\n");
 
-       /* Provide proper symbols relocatability by their '_text'
-        * relativeness.  The symbol names cannot be used to construct
-        * normal symbol references as the list of symbols contains
-        * symbols that are declared static and are private to their
-        * .o files.  This prevents .tmp_kallsyms.o or any other
-        * object from referencing them.
+       /* Provide proper symbols relocatability by their relativeness
+        * to a fixed anchor point in the runtime image, either '_text'
+        * for absolute address tables, in which case the linker will
+        * emit the final addresses at build time. Otherwise, use the
+        * offset relative to the lowest value encountered of all relative
+        * symbols, and emit non-relocatable fixed offsets that will be fixed
+        * up at runtime.
+        *
+        * The symbol names cannot be used to construct normal symbol
+        * references as the list of symbols contains symbols that are
+        * declared static and are private to their .o files.  This prevents
+        * .tmp_kallsyms.o or any other object from referencing them.
         */
-       output_label("kallsyms_addresses");
+       if (!base_relative)
+               output_label("kallsyms_addresses");
+       else
+               output_label("kallsyms_offsets");
+
        for (i = 0; i < table_cnt; i++) {
-               if (!symbol_absolute(&table[i])) {
+               if (base_relative) {
+                       long long offset;
+                       int overflow;
+
+                       if (!absolute_percpu) {
+                               offset = table[i].addr - relative_base;
+                               overflow = (offset < 0 || offset > UINT_MAX);
+                       } else if (symbol_absolute(&table[i])) {
+                               offset = table[i].addr;
+                               overflow = (offset < 0 || offset > INT_MAX);
+                       } else {
+                               offset = relative_base - table[i].addr - 1;
+                               overflow = (offset < INT_MIN || offset >= 0);
+                       }
+                       if (overflow) {
+                               fprintf(stderr, "kallsyms failure: "
+                                       "%s symbol value %#llx out of range in relative mode\n",
+                                       symbol_absolute(&table[i]) ? "absolute" : "relative",
+                                       table[i].addr);
+                               exit(EXIT_FAILURE);
+                       }
+                       printf("\t.long\t%#x\n", (int)offset);
+               } else if (!symbol_absolute(&table[i])) {
                        if (_text <= table[i].addr)
                                printf("\tPTR\t_text + %#llx\n",
                                        table[i].addr - _text);
@@ -368,6 +408,12 @@ static void write_src(void)
        }
        printf("\n");
 
+       if (base_relative) {
+               output_label("kallsyms_relative_base");
+               printf("\tPTR\t_text - %#llx\n", _text - relative_base);
+               printf("\n");
+       }
+
        output_label("kallsyms_num_syms");
        printf("\tPTR\t%d\n", table_cnt);
        printf("\n");
@@ -681,8 +727,27 @@ static void make_percpus_absolute(void)
        unsigned int i;
 
        for (i = 0; i < table_cnt; i++)
-               if (symbol_in_range(&table[i], &percpu_range, 1))
+               if (symbol_in_range(&table[i], &percpu_range, 1)) {
+                       /*
+                        * Keep the 'A' override for percpu symbols to
+                        * ensure consistent behavior compared to older
+                        * versions of this tool.
+                        */
                        table[i].sym[0] = 'A';
+                       table[i].percpu_absolute = 1;
+               }
+}
+
+/* find the minimum non-absolute symbol address */
+static void record_relative_base(void)
+{
+       unsigned int i;
+
+       relative_base = -1ULL;
+       for (i = 0; i < table_cnt; i++)
+               if (!symbol_absolute(&table[i]) &&
+                   table[i].addr < relative_base)
+                       relative_base = table[i].addr;
 }
 
 int main(int argc, char **argv)
@@ -703,7 +768,9 @@ int main(int argc, char **argv)
                        } else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
                                const char *p = &argv[i][14];
                                kernel_start_addr = strtoull(p, NULL, 16);
-                       } else
+                       } else if (strcmp(argv[i], "--base-relative") == 0)
+                               base_relative = 1;
+                       else
                                usage();
                }
        } else if (argc != 1)
@@ -712,6 +779,8 @@ int main(int argc, char **argv)
        read_map(stdin);
        if (absolute_percpu)
                make_percpus_absolute();
+       if (base_relative)
+               record_relative_base();
        sort_symbols();
        optimize_token_table();
        write_src();