0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include <stdbool.h>
0022 #include <stdio.h>
0023 #include <stdlib.h>
0024 #include <string.h>
0025 #include <ctype.h>
0026 #include <limits.h>
0027
0028 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
0029
0030 #define KSYM_NAME_LEN 128
0031
0032 struct sym_entry {
0033 unsigned long long addr;
0034 unsigned int len;
0035 unsigned int start_pos;
0036 unsigned int percpu_absolute;
0037 unsigned char sym[];
0038 };
0039
0040 struct addr_range {
0041 const char *start_sym, *end_sym;
0042 unsigned long long start, end;
0043 };
0044
0045 static unsigned long long _text;
0046 static unsigned long long relative_base;
0047 static struct addr_range text_ranges[] = {
0048 { "_stext", "_etext" },
0049 { "_sinittext", "_einittext" },
0050 };
0051 #define text_range_text (&text_ranges[0])
0052 #define text_range_inittext (&text_ranges[1])
0053
0054 static struct addr_range percpu_range = {
0055 "__per_cpu_start", "__per_cpu_end", -1ULL, 0
0056 };
0057
0058 static struct sym_entry **table;
0059 static unsigned int table_size, table_cnt;
0060 static int all_symbols;
0061 static int absolute_percpu;
0062 static int base_relative;
0063
0064 static int token_profit[0x10000];
0065
0066
0067 static unsigned char best_table[256][2];
0068 static unsigned char best_table_len[256];
0069
0070
0071 static void usage(void)
0072 {
0073 fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] "
0074 "[--base-relative] < in.map > out.S\n");
0075 exit(1);
0076 }
0077
0078 static char *sym_name(const struct sym_entry *s)
0079 {
0080 return (char *)s->sym + 1;
0081 }
0082
0083 static bool is_ignored_symbol(const char *name, char type)
0084 {
0085
0086 static const char * const ignored_symbols[] = {
0087
0088
0089
0090
0091
0092
0093
0094 "kallsyms_addresses",
0095 "kallsyms_offsets",
0096 "kallsyms_relative_base",
0097 "kallsyms_num_syms",
0098 "kallsyms_names",
0099 "kallsyms_markers",
0100 "kallsyms_token_table",
0101 "kallsyms_token_index",
0102
0103 "_SDA_BASE_",
0104 "_SDA2_BASE_",
0105 NULL
0106 };
0107
0108
0109 static const char * const ignored_prefixes[] = {
0110 "$",
0111 ".L",
0112 "__crc_",
0113 "__efistub_",
0114 "__kvm_nvhe_$",
0115 "__kvm_nvhe_.L",
0116 "__AArch64ADRPThunk_",
0117 "__ARMV5PILongThunk_",
0118 "__ARMV7PILongThunk_",
0119 "__ThumbV7PILongThunk_",
0120 "__LA25Thunk_",
0121 "__microLA25Thunk_",
0122 NULL
0123 };
0124
0125
0126 static const char * const ignored_suffixes[] = {
0127 "_from_arm",
0128 "_from_thumb",
0129 "_veneer",
0130 NULL
0131 };
0132
0133
0134 static const char * const ignored_matches[] = {
0135 ".long_branch.",
0136 ".plt_branch.",
0137 NULL
0138 };
0139
0140 const char * const *p;
0141
0142 for (p = ignored_symbols; *p; p++)
0143 if (!strcmp(name, *p))
0144 return true;
0145
0146 for (p = ignored_prefixes; *p; p++)
0147 if (!strncmp(name, *p, strlen(*p)))
0148 return true;
0149
0150 for (p = ignored_suffixes; *p; p++) {
0151 int l = strlen(name) - strlen(*p);
0152
0153 if (l >= 0 && !strcmp(name + l, *p))
0154 return true;
0155 }
0156
0157 for (p = ignored_matches; *p; p++) {
0158 if (strstr(name, *p))
0159 return true;
0160 }
0161
0162 if (type == 'U' || type == 'u')
0163 return true;
0164
0165 if (type == 'N' || type == 'n')
0166 return true;
0167
0168 if (toupper(type) == 'A') {
0169
0170 if (strcmp(name, "__kernel_syscall_via_break") &&
0171 strcmp(name, "__kernel_syscall_via_epc") &&
0172 strcmp(name, "__kernel_sigtramp") &&
0173 strcmp(name, "__gp"))
0174 return true;
0175 }
0176
0177 return false;
0178 }
0179
0180 static void check_symbol_range(const char *sym, unsigned long long addr,
0181 struct addr_range *ranges, int entries)
0182 {
0183 size_t i;
0184 struct addr_range *ar;
0185
0186 for (i = 0; i < entries; ++i) {
0187 ar = &ranges[i];
0188
0189 if (strcmp(sym, ar->start_sym) == 0) {
0190 ar->start = addr;
0191 return;
0192 } else if (strcmp(sym, ar->end_sym) == 0) {
0193 ar->end = addr;
0194 return;
0195 }
0196 }
0197 }
0198
0199 static struct sym_entry *read_symbol(FILE *in)
0200 {
0201 char name[500], type;
0202 unsigned long long addr;
0203 unsigned int len;
0204 struct sym_entry *sym;
0205 int rc;
0206
0207 rc = fscanf(in, "%llx %c %499s\n", &addr, &type, name);
0208 if (rc != 3) {
0209 if (rc != EOF && fgets(name, 500, in) == NULL)
0210 fprintf(stderr, "Read error or end of file.\n");
0211 return NULL;
0212 }
0213 if (strlen(name) >= KSYM_NAME_LEN) {
0214 fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).\n"
0215 "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n",
0216 name, strlen(name), KSYM_NAME_LEN);
0217 return NULL;
0218 }
0219
0220 if (strcmp(name, "_text") == 0)
0221 _text = addr;
0222
0223
0224 if (is_ignored_symbol(name, type))
0225 return NULL;
0226
0227 check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges));
0228 check_symbol_range(name, addr, &percpu_range, 1);
0229
0230
0231
0232
0233 len = strlen(name) + 1;
0234
0235 sym = malloc(sizeof(*sym) + len + 1);
0236 if (!sym) {
0237 fprintf(stderr, "kallsyms failure: "
0238 "unable to allocate required amount of memory\n");
0239 exit(EXIT_FAILURE);
0240 }
0241 sym->addr = addr;
0242 sym->len = len;
0243 sym->sym[0] = type;
0244 strcpy(sym_name(sym), name);
0245 sym->percpu_absolute = 0;
0246
0247 return sym;
0248 }
0249
0250 static int symbol_in_range(const struct sym_entry *s,
0251 const struct addr_range *ranges, int entries)
0252 {
0253 size_t i;
0254 const struct addr_range *ar;
0255
0256 for (i = 0; i < entries; ++i) {
0257 ar = &ranges[i];
0258
0259 if (s->addr >= ar->start && s->addr <= ar->end)
0260 return 1;
0261 }
0262
0263 return 0;
0264 }
0265
0266 static int symbol_valid(const struct sym_entry *s)
0267 {
0268 const char *name = sym_name(s);
0269
0270
0271
0272 if (!all_symbols) {
0273 if (symbol_in_range(s, text_ranges,
0274 ARRAY_SIZE(text_ranges)) == 0)
0275 return 0;
0276
0277
0278
0279
0280
0281
0282 if ((s->addr == text_range_text->end &&
0283 strcmp(name, text_range_text->end_sym)) ||
0284 (s->addr == text_range_inittext->end &&
0285 strcmp(name, text_range_inittext->end_sym)))
0286 return 0;
0287 }
0288
0289 return 1;
0290 }
0291
0292
0293 static void shrink_table(void)
0294 {
0295 unsigned int i, pos;
0296
0297 pos = 0;
0298 for (i = 0; i < table_cnt; i++) {
0299 if (symbol_valid(table[i])) {
0300 if (pos != i)
0301 table[pos] = table[i];
0302 pos++;
0303 } else {
0304 free(table[i]);
0305 }
0306 }
0307 table_cnt = pos;
0308
0309
0310 if (!table_cnt) {
0311 fprintf(stderr, "No valid symbol.\n");
0312 exit(1);
0313 }
0314 }
0315
0316 static void read_map(FILE *in)
0317 {
0318 struct sym_entry *sym;
0319
0320 while (!feof(in)) {
0321 sym = read_symbol(in);
0322 if (!sym)
0323 continue;
0324
0325 sym->start_pos = table_cnt;
0326
0327 if (table_cnt >= table_size) {
0328 table_size += 10000;
0329 table = realloc(table, sizeof(*table) * table_size);
0330 if (!table) {
0331 fprintf(stderr, "out of memory\n");
0332 exit (1);
0333 }
0334 }
0335
0336 table[table_cnt++] = sym;
0337 }
0338 }
0339
0340 static void output_label(const char *label)
0341 {
0342 printf(".globl %s\n", label);
0343 printf("\tALGN\n");
0344 printf("%s:\n", label);
0345 }
0346
0347
0348 static void output_address(unsigned long long addr)
0349 {
0350 if (_text <= addr)
0351 printf("\tPTR\t_text + %#llx\n", addr - _text);
0352 else
0353 printf("\tPTR\t_text - %#llx\n", _text - addr);
0354 }
0355
0356
0357
0358 static int expand_symbol(const unsigned char *data, int len, char *result)
0359 {
0360 int c, rlen, total=0;
0361
0362 while (len) {
0363 c = *data;
0364
0365
0366 if (best_table[c][0]==c && best_table_len[c]==1) {
0367 *result++ = c;
0368 total++;
0369 } else {
0370
0371 rlen = expand_symbol(best_table[c], best_table_len[c], result);
0372 total += rlen;
0373 result += rlen;
0374 }
0375 data++;
0376 len--;
0377 }
0378 *result=0;
0379
0380 return total;
0381 }
0382
0383 static int symbol_absolute(const struct sym_entry *s)
0384 {
0385 return s->percpu_absolute;
0386 }
0387
0388 static void write_src(void)
0389 {
0390 unsigned int i, k, off;
0391 unsigned int best_idx[256];
0392 unsigned int *markers;
0393 char buf[KSYM_NAME_LEN];
0394
0395 printf("#include <asm/bitsperlong.h>\n");
0396 printf("#if BITS_PER_LONG == 64\n");
0397 printf("#define PTR .quad\n");
0398 printf("#define ALGN .balign 8\n");
0399 printf("#else\n");
0400 printf("#define PTR .long\n");
0401 printf("#define ALGN .balign 4\n");
0402 printf("#endif\n");
0403
0404 printf("\t.section .rodata, \"a\"\n");
0405
0406 if (!base_relative)
0407 output_label("kallsyms_addresses");
0408 else
0409 output_label("kallsyms_offsets");
0410
0411 for (i = 0; i < table_cnt; i++) {
0412 if (base_relative) {
0413
0414
0415
0416
0417
0418
0419
0420 long long offset;
0421 int overflow;
0422
0423 if (!absolute_percpu) {
0424 offset = table[i]->addr - relative_base;
0425 overflow = (offset < 0 || offset > UINT_MAX);
0426 } else if (symbol_absolute(table[i])) {
0427 offset = table[i]->addr;
0428 overflow = (offset < 0 || offset > INT_MAX);
0429 } else {
0430 offset = relative_base - table[i]->addr - 1;
0431 overflow = (offset < INT_MIN || offset >= 0);
0432 }
0433 if (overflow) {
0434 fprintf(stderr, "kallsyms failure: "
0435 "%s symbol value %#llx out of range in relative mode\n",
0436 symbol_absolute(table[i]) ? "absolute" : "relative",
0437 table[i]->addr);
0438 exit(EXIT_FAILURE);
0439 }
0440 printf("\t.long\t%#x\n", (int)offset);
0441 } else if (!symbol_absolute(table[i])) {
0442 output_address(table[i]->addr);
0443 } else {
0444 printf("\tPTR\t%#llx\n", table[i]->addr);
0445 }
0446 }
0447 printf("\n");
0448
0449 if (base_relative) {
0450 output_label("kallsyms_relative_base");
0451 output_address(relative_base);
0452 printf("\n");
0453 }
0454
0455 output_label("kallsyms_num_syms");
0456 printf("\t.long\t%u\n", table_cnt);
0457 printf("\n");
0458
0459
0460
0461 markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
0462 if (!markers) {
0463 fprintf(stderr, "kallsyms failure: "
0464 "unable to allocate required memory\n");
0465 exit(EXIT_FAILURE);
0466 }
0467
0468 output_label("kallsyms_names");
0469 off = 0;
0470 for (i = 0; i < table_cnt; i++) {
0471 if ((i & 0xFF) == 0)
0472 markers[i >> 8] = off;
0473
0474 printf("\t.byte 0x%02x", table[i]->len);
0475 for (k = 0; k < table[i]->len; k++)
0476 printf(", 0x%02x", table[i]->sym[k]);
0477 printf("\n");
0478
0479 off += table[i]->len + 1;
0480 }
0481 printf("\n");
0482
0483 output_label("kallsyms_markers");
0484 for (i = 0; i < ((table_cnt + 255) >> 8); i++)
0485 printf("\t.long\t%u\n", markers[i]);
0486 printf("\n");
0487
0488 free(markers);
0489
0490 output_label("kallsyms_token_table");
0491 off = 0;
0492 for (i = 0; i < 256; i++) {
0493 best_idx[i] = off;
0494 expand_symbol(best_table[i], best_table_len[i], buf);
0495 printf("\t.asciz\t\"%s\"\n", buf);
0496 off += strlen(buf) + 1;
0497 }
0498 printf("\n");
0499
0500 output_label("kallsyms_token_index");
0501 for (i = 0; i < 256; i++)
0502 printf("\t.short\t%d\n", best_idx[i]);
0503 printf("\n");
0504 }
0505
0506
0507
0508
0509
0510 static void learn_symbol(const unsigned char *symbol, int len)
0511 {
0512 int i;
0513
0514 for (i = 0; i < len - 1; i++)
0515 token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
0516 }
0517
0518
0519 static void forget_symbol(const unsigned char *symbol, int len)
0520 {
0521 int i;
0522
0523 for (i = 0; i < len - 1; i++)
0524 token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
0525 }
0526
0527
0528 static void build_initial_tok_table(void)
0529 {
0530 unsigned int i;
0531
0532 for (i = 0; i < table_cnt; i++)
0533 learn_symbol(table[i]->sym, table[i]->len);
0534 }
0535
0536 static unsigned char *find_token(unsigned char *str, int len,
0537 const unsigned char *token)
0538 {
0539 int i;
0540
0541 for (i = 0; i < len - 1; i++) {
0542 if (str[i] == token[0] && str[i+1] == token[1])
0543 return &str[i];
0544 }
0545 return NULL;
0546 }
0547
0548
0549
0550 static void compress_symbols(const unsigned char *str, int idx)
0551 {
0552 unsigned int i, len, size;
0553 unsigned char *p1, *p2;
0554
0555 for (i = 0; i < table_cnt; i++) {
0556
0557 len = table[i]->len;
0558 p1 = table[i]->sym;
0559
0560
0561 p2 = find_token(p1, len, str);
0562 if (!p2) continue;
0563
0564
0565 forget_symbol(table[i]->sym, len);
0566
0567 size = len;
0568
0569 do {
0570 *p2 = idx;
0571 p2++;
0572 size -= (p2 - p1);
0573 memmove(p2, p2 + 1, size);
0574 p1 = p2;
0575 len--;
0576
0577 if (size < 2) break;
0578
0579
0580 p2 = find_token(p1, size, str);
0581
0582 } while (p2);
0583
0584 table[i]->len = len;
0585
0586
0587 learn_symbol(table[i]->sym, len);
0588 }
0589 }
0590
0591
0592 static int find_best_token(void)
0593 {
0594 int i, best, bestprofit;
0595
0596 bestprofit=-10000;
0597 best = 0;
0598
0599 for (i = 0; i < 0x10000; i++) {
0600 if (token_profit[i] > bestprofit) {
0601 best = i;
0602 bestprofit = token_profit[i];
0603 }
0604 }
0605 return best;
0606 }
0607
0608
0609 static void optimize_result(void)
0610 {
0611 int i, best;
0612
0613
0614
0615 for (i = 255; i >= 0; i--) {
0616
0617
0618
0619 if (!best_table_len[i]) {
0620
0621
0622 best = find_best_token();
0623 if (token_profit[best] == 0)
0624 break;
0625
0626
0627 best_table_len[i] = 2;
0628 best_table[i][0] = best & 0xFF;
0629 best_table[i][1] = (best >> 8) & 0xFF;
0630
0631
0632 compress_symbols(best_table[i], i);
0633 }
0634 }
0635 }
0636
0637
0638 static void insert_real_symbols_in_table(void)
0639 {
0640 unsigned int i, j, c;
0641
0642 for (i = 0; i < table_cnt; i++) {
0643 for (j = 0; j < table[i]->len; j++) {
0644 c = table[i]->sym[j];
0645 best_table[c][0]=c;
0646 best_table_len[c]=1;
0647 }
0648 }
0649 }
0650
0651 static void optimize_token_table(void)
0652 {
0653 build_initial_tok_table();
0654
0655 insert_real_symbols_in_table();
0656
0657 optimize_result();
0658 }
0659
0660
0661 static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
0662 {
0663 const char *symbol = sym_name(se);
0664 int len = se->len - 1;
0665
0666 if (len < 8)
0667 return 0;
0668
0669 if (symbol[0] != '_' || symbol[1] != '_')
0670 return 0;
0671
0672
0673 if (!memcmp(symbol + 2, "start_", 6))
0674 return 1;
0675
0676
0677 if (!memcmp(symbol + 2, "stop_", 5))
0678 return 1;
0679
0680
0681 if (!memcmp(symbol + 2, "end_", 4))
0682 return 1;
0683
0684
0685 if (!memcmp(symbol + len - 6, "_start", 6))
0686 return 1;
0687
0688
0689 if (!memcmp(symbol + len - 4, "_end", 4))
0690 return 1;
0691
0692 return 0;
0693 }
0694
0695 static int compare_symbols(const void *a, const void *b)
0696 {
0697 const struct sym_entry *sa = *(const struct sym_entry **)a;
0698 const struct sym_entry *sb = *(const struct sym_entry **)b;
0699 int wa, wb;
0700
0701
0702 if (sa->addr > sb->addr)
0703 return 1;
0704 if (sa->addr < sb->addr)
0705 return -1;
0706
0707
0708 wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W');
0709 wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W');
0710 if (wa != wb)
0711 return wa - wb;
0712
0713
0714 wa = may_be_linker_script_provide_symbol(sa);
0715 wb = may_be_linker_script_provide_symbol(sb);
0716 if (wa != wb)
0717 return wa - wb;
0718
0719
0720 wa = strspn(sym_name(sa), "_");
0721 wb = strspn(sym_name(sb), "_");
0722 if (wa != wb)
0723 return wa - wb;
0724
0725
0726 return sa->start_pos - sb->start_pos;
0727 }
0728
0729 static void sort_symbols(void)
0730 {
0731 qsort(table, table_cnt, sizeof(table[0]), compare_symbols);
0732 }
0733
0734 static void make_percpus_absolute(void)
0735 {
0736 unsigned int i;
0737
0738 for (i = 0; i < table_cnt; i++)
0739 if (symbol_in_range(table[i], &percpu_range, 1)) {
0740
0741
0742
0743
0744
0745 table[i]->sym[0] = 'A';
0746 table[i]->percpu_absolute = 1;
0747 }
0748 }
0749
0750
0751 static void record_relative_base(void)
0752 {
0753 unsigned int i;
0754
0755 for (i = 0; i < table_cnt; i++)
0756 if (!symbol_absolute(table[i])) {
0757
0758
0759
0760
0761 relative_base = table[i]->addr;
0762 return;
0763 }
0764 }
0765
0766 int main(int argc, char **argv)
0767 {
0768 if (argc >= 2) {
0769 int i;
0770 for (i = 1; i < argc; i++) {
0771 if(strcmp(argv[i], "--all-symbols") == 0)
0772 all_symbols = 1;
0773 else if (strcmp(argv[i], "--absolute-percpu") == 0)
0774 absolute_percpu = 1;
0775 else if (strcmp(argv[i], "--base-relative") == 0)
0776 base_relative = 1;
0777 else
0778 usage();
0779 }
0780 } else if (argc != 1)
0781 usage();
0782
0783 read_map(stdin);
0784 shrink_table();
0785 if (absolute_percpu)
0786 make_percpus_absolute();
0787 sort_symbols();
0788 if (base_relative)
0789 record_relative_base();
0790 optimize_token_table();
0791 write_src();
0792
0793 return 0;
0794 }