| .. | .. |
|---|
| 18 | 18 | * |
|---|
| 19 | 19 | */ |
|---|
| 20 | 20 | |
|---|
| 21 | +#include <stdbool.h> |
|---|
| 21 | 22 | #include <stdio.h> |
|---|
| 22 | 23 | #include <stdlib.h> |
|---|
| 23 | 24 | #include <string.h> |
|---|
| 24 | 25 | #include <ctype.h> |
|---|
| 25 | 26 | #include <limits.h> |
|---|
| 26 | 27 | |
|---|
| 27 | | -#ifndef ARRAY_SIZE |
|---|
| 28 | 28 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) |
|---|
| 29 | | -#endif |
|---|
| 30 | 29 | |
|---|
| 31 | 30 | #define KSYM_NAME_LEN 128 |
|---|
| 32 | 31 | |
|---|
| .. | .. |
|---|
| 34 | 33 | unsigned long long addr; |
|---|
| 35 | 34 | unsigned int len; |
|---|
| 36 | 35 | unsigned int start_pos; |
|---|
| 37 | | - unsigned char *sym; |
|---|
| 38 | 36 | unsigned int percpu_absolute; |
|---|
| 37 | + unsigned char sym[]; |
|---|
| 39 | 38 | }; |
|---|
| 40 | 39 | |
|---|
| 41 | 40 | struct addr_range { |
|---|
| .. | .. |
|---|
| 48 | 47 | static struct addr_range text_ranges[] = { |
|---|
| 49 | 48 | { "_stext", "_etext" }, |
|---|
| 50 | 49 | { "_sinittext", "_einittext" }, |
|---|
| 51 | | - { "_stext_l1", "_etext_l1" }, /* Blackfin on-chip L1 inst SRAM */ |
|---|
| 52 | | - { "_stext_l2", "_etext_l2" }, /* Blackfin on-chip L2 SRAM */ |
|---|
| 53 | 50 | }; |
|---|
| 54 | 51 | #define text_range_text (&text_ranges[0]) |
|---|
| 55 | 52 | #define text_range_inittext (&text_ranges[1]) |
|---|
| .. | .. |
|---|
| 58 | 55 | "__per_cpu_start", "__per_cpu_end", -1ULL, 0 |
|---|
| 59 | 56 | }; |
|---|
| 60 | 57 | |
|---|
| 61 | | -static struct sym_entry *table; |
|---|
| 58 | +static struct sym_entry **table; |
|---|
| 62 | 59 | static unsigned int table_size, table_cnt; |
|---|
| 63 | | -static int all_symbols = 0; |
|---|
| 64 | | -static int absolute_percpu = 0; |
|---|
| 65 | | -static int base_relative = 0; |
|---|
| 60 | +static int all_symbols; |
|---|
| 61 | +static int absolute_percpu; |
|---|
| 62 | +static int base_relative; |
|---|
| 66 | 63 | |
|---|
| 67 | | -int token_profit[0x10000]; |
|---|
| 64 | +static int token_profit[0x10000]; |
|---|
| 68 | 65 | |
|---|
| 69 | 66 | /* the table that holds the result of the compression */ |
|---|
| 70 | | -unsigned char best_table[256][2]; |
|---|
| 71 | | -unsigned char best_table_len[256]; |
|---|
| 67 | +static unsigned char best_table[256][2]; |
|---|
| 68 | +static unsigned char best_table_len[256]; |
|---|
| 72 | 69 | |
|---|
| 73 | 70 | |
|---|
| 74 | 71 | static void usage(void) |
|---|
| .. | .. |
|---|
| 78 | 75 | exit(1); |
|---|
| 79 | 76 | } |
|---|
| 80 | 77 | |
|---|
| 81 | | -/* |
|---|
| 82 | | - * This ignores the intensely annoying "mapping symbols" found |
|---|
| 83 | | - * in ARM ELF files: $a, $t and $d. |
|---|
| 84 | | - */ |
|---|
| 85 | | -static inline int is_arm_mapping_symbol(const char *str) |
|---|
| 78 | +static char *sym_name(const struct sym_entry *s) |
|---|
| 86 | 79 | { |
|---|
| 87 | | - return str[0] == '$' && strchr("axtd", str[1]) |
|---|
| 88 | | - && (str[2] == '\0' || str[2] == '.'); |
|---|
| 80 | + return (char *)s->sym + 1; |
|---|
| 89 | 81 | } |
|---|
| 90 | 82 | |
|---|
| 91 | | -static int check_symbol_range(const char *sym, unsigned long long addr, |
|---|
| 92 | | - struct addr_range *ranges, int entries) |
|---|
| 83 | +static bool is_ignored_symbol(const char *name, char type) |
|---|
| 84 | +{ |
|---|
| 85 | + /* Symbol names that exactly match to the following are ignored.*/ |
|---|
| 86 | + static const char * const ignored_symbols[] = { |
|---|
| 87 | + /* |
|---|
| 88 | + * Symbols which vary between passes. Passes 1 and 2 must have |
|---|
| 89 | + * identical symbol lists. The kallsyms_* symbols below are |
|---|
| 90 | + * only added after pass 1, they would be included in pass 2 |
|---|
| 91 | + * when --all-symbols is specified so exclude them to get a |
|---|
| 92 | + * stable symbol list. |
|---|
| 93 | + */ |
|---|
| 94 | + "kallsyms_addresses", |
|---|
| 95 | + "kallsyms_offsets", |
|---|
| 96 | + "kallsyms_relative_base", |
|---|
| 97 | + "kallsyms_num_syms", |
|---|
| 98 | + "kallsyms_names", |
|---|
| 99 | + "kallsyms_markers", |
|---|
| 100 | + "kallsyms_token_table", |
|---|
| 101 | + "kallsyms_token_index", |
|---|
| 102 | + /* Exclude linker generated symbols which vary between passes */ |
|---|
| 103 | + "_SDA_BASE_", /* ppc */ |
|---|
| 104 | + "_SDA2_BASE_", /* ppc */ |
|---|
| 105 | + NULL |
|---|
| 106 | + }; |
|---|
| 107 | + |
|---|
| 108 | + /* Symbol names that begin with the following are ignored.*/ |
|---|
| 109 | + static const char * const ignored_prefixes[] = { |
|---|
| 110 | + "$", /* local symbols for ARM, MIPS, etc. */ |
|---|
| 111 | + ".LASANPC", /* s390 kasan local symbols */ |
|---|
| 112 | + "__crc_", /* modversions */ |
|---|
| 113 | + "__efistub_", /* arm64 EFI stub namespace */ |
|---|
| 114 | + "__kvm_nvhe_", /* arm64 non-VHE KVM namespace */ |
|---|
| 115 | + "__AArch64ADRPThunk_", /* arm64 lld */ |
|---|
| 116 | + "__ARMV5PILongThunk_", /* arm lld */ |
|---|
| 117 | + "__ARMV7PILongThunk_", |
|---|
| 118 | + "__ThumbV7PILongThunk_", |
|---|
| 119 | + "__LA25Thunk_", /* mips lld */ |
|---|
| 120 | + "__microLA25Thunk_", |
|---|
| 121 | + NULL |
|---|
| 122 | + }; |
|---|
| 123 | + |
|---|
| 124 | + /* Symbol names that end with the following are ignored.*/ |
|---|
| 125 | + static const char * const ignored_suffixes[] = { |
|---|
| 126 | + "_from_arm", /* arm */ |
|---|
| 127 | + "_from_thumb", /* arm */ |
|---|
| 128 | + "_veneer", /* arm */ |
|---|
| 129 | + NULL |
|---|
| 130 | + }; |
|---|
| 131 | + |
|---|
| 132 | + /* Symbol names that contain the following are ignored.*/ |
|---|
| 133 | + static const char * const ignored_matches[] = { |
|---|
| 134 | + ".long_branch.", /* ppc stub */ |
|---|
| 135 | + ".plt_branch.", /* ppc stub */ |
|---|
| 136 | + NULL |
|---|
| 137 | + }; |
|---|
| 138 | + |
|---|
| 139 | + const char * const *p; |
|---|
| 140 | + |
|---|
| 141 | + for (p = ignored_symbols; *p; p++) |
|---|
| 142 | + if (!strcmp(name, *p)) |
|---|
| 143 | + return true; |
|---|
| 144 | + |
|---|
| 145 | + for (p = ignored_prefixes; *p; p++) |
|---|
| 146 | + if (!strncmp(name, *p, strlen(*p))) |
|---|
| 147 | + return true; |
|---|
| 148 | + |
|---|
| 149 | + for (p = ignored_suffixes; *p; p++) { |
|---|
| 150 | + int l = strlen(name) - strlen(*p); |
|---|
| 151 | + |
|---|
| 152 | + if (l >= 0 && !strcmp(name + l, *p)) |
|---|
| 153 | + return true; |
|---|
| 154 | + } |
|---|
| 155 | + |
|---|
| 156 | + for (p = ignored_matches; *p; p++) { |
|---|
| 157 | + if (strstr(name, *p)) |
|---|
| 158 | + return true; |
|---|
| 159 | + } |
|---|
| 160 | + |
|---|
| 161 | + if (type == 'U' || type == 'u') |
|---|
| 162 | + return true; |
|---|
| 163 | + /* exclude debugging symbols */ |
|---|
| 164 | + if (type == 'N' || type == 'n') |
|---|
| 165 | + return true; |
|---|
| 166 | + |
|---|
| 167 | + if (toupper(type) == 'A') { |
|---|
| 168 | + /* Keep these useful absolute symbols */ |
|---|
| 169 | + if (strcmp(name, "__kernel_syscall_via_break") && |
|---|
| 170 | + strcmp(name, "__kernel_syscall_via_epc") && |
|---|
| 171 | + strcmp(name, "__kernel_sigtramp") && |
|---|
| 172 | + strcmp(name, "__gp")) |
|---|
| 173 | + return true; |
|---|
| 174 | + } |
|---|
| 175 | + |
|---|
| 176 | + return false; |
|---|
| 177 | +} |
|---|
| 178 | + |
|---|
| 179 | +static void check_symbol_range(const char *sym, unsigned long long addr, |
|---|
| 180 | + struct addr_range *ranges, int entries) |
|---|
| 93 | 181 | { |
|---|
| 94 | 182 | size_t i; |
|---|
| 95 | 183 | struct addr_range *ar; |
|---|
| .. | .. |
|---|
| 99 | 187 | |
|---|
| 100 | 188 | if (strcmp(sym, ar->start_sym) == 0) { |
|---|
| 101 | 189 | ar->start = addr; |
|---|
| 102 | | - return 0; |
|---|
| 190 | + return; |
|---|
| 103 | 191 | } else if (strcmp(sym, ar->end_sym) == 0) { |
|---|
| 104 | 192 | ar->end = addr; |
|---|
| 105 | | - return 0; |
|---|
| 193 | + return; |
|---|
| 106 | 194 | } |
|---|
| 107 | 195 | } |
|---|
| 108 | | - |
|---|
| 109 | | - return 1; |
|---|
| 110 | 196 | } |
|---|
| 111 | 197 | |
|---|
| 112 | | -static int read_symbol(FILE *in, struct sym_entry *s) |
|---|
| 198 | +static struct sym_entry *read_symbol(FILE *in) |
|---|
| 113 | 199 | { |
|---|
| 114 | | - char sym[500], stype; |
|---|
| 200 | + char name[500], type; |
|---|
| 201 | + unsigned long long addr; |
|---|
| 202 | + unsigned int len; |
|---|
| 203 | + struct sym_entry *sym; |
|---|
| 115 | 204 | int rc; |
|---|
| 116 | 205 | |
|---|
| 117 | | - rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, sym); |
|---|
| 206 | + rc = fscanf(in, "%llx %c %499s\n", &addr, &type, name); |
|---|
| 118 | 207 | if (rc != 3) { |
|---|
| 119 | | - if (rc != EOF && fgets(sym, 500, in) == NULL) |
|---|
| 208 | + if (rc != EOF && fgets(name, 500, in) == NULL) |
|---|
| 120 | 209 | fprintf(stderr, "Read error or end of file.\n"); |
|---|
| 121 | | - return -1; |
|---|
| 210 | + return NULL; |
|---|
| 122 | 211 | } |
|---|
| 123 | | - if (strlen(sym) >= KSYM_NAME_LEN) { |
|---|
| 212 | + if (strlen(name) >= KSYM_NAME_LEN) { |
|---|
| 124 | 213 | fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).\n" |
|---|
| 125 | 214 | "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n", |
|---|
| 126 | | - sym, strlen(sym), KSYM_NAME_LEN); |
|---|
| 127 | | - return -1; |
|---|
| 215 | + name, strlen(name), KSYM_NAME_LEN); |
|---|
| 216 | + return NULL; |
|---|
| 128 | 217 | } |
|---|
| 218 | + |
|---|
| 219 | + if (strcmp(name, "_text") == 0) |
|---|
| 220 | + _text = addr; |
|---|
| 129 | 221 | |
|---|
| 130 | 222 | /* Ignore most absolute/undefined (?) symbols. */ |
|---|
| 131 | | - if (strcmp(sym, "_text") == 0) |
|---|
| 132 | | - _text = s->addr; |
|---|
| 133 | | - else if (check_symbol_range(sym, s->addr, text_ranges, |
|---|
| 134 | | - ARRAY_SIZE(text_ranges)) == 0) |
|---|
| 135 | | - /* nothing to do */; |
|---|
| 136 | | - else if (toupper(stype) == 'A') |
|---|
| 137 | | - { |
|---|
| 138 | | - /* Keep these useful absolute symbols */ |
|---|
| 139 | | - if (strcmp(sym, "__kernel_syscall_via_break") && |
|---|
| 140 | | - strcmp(sym, "__kernel_syscall_via_epc") && |
|---|
| 141 | | - strcmp(sym, "__kernel_sigtramp") && |
|---|
| 142 | | - strcmp(sym, "__gp")) |
|---|
| 143 | | - return -1; |
|---|
| 223 | + if (is_ignored_symbol(name, type)) |
|---|
| 224 | + return NULL; |
|---|
| 144 | 225 | |
|---|
| 145 | | - } |
|---|
| 146 | | - else if (toupper(stype) == 'U' || |
|---|
| 147 | | - is_arm_mapping_symbol(sym)) |
|---|
| 148 | | - return -1; |
|---|
| 149 | | - /* exclude also MIPS ELF local symbols ($L123 instead of .L123) */ |
|---|
| 150 | | - else if (sym[0] == '$') |
|---|
| 151 | | - return -1; |
|---|
| 152 | | - /* exclude debugging symbols */ |
|---|
| 153 | | - else if (stype == 'N' || stype == 'n') |
|---|
| 154 | | - return -1; |
|---|
| 155 | | - /* exclude s390 kasan local symbols */ |
|---|
| 156 | | - else if (!strncmp(sym, ".LASANPC", 8)) |
|---|
| 157 | | - return -1; |
|---|
| 226 | + check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges)); |
|---|
| 227 | + check_symbol_range(name, addr, &percpu_range, 1); |
|---|
| 158 | 228 | |
|---|
| 159 | 229 | /* include the type field in the symbol name, so that it gets |
|---|
| 160 | 230 | * compressed together */ |
|---|
| 161 | | - s->len = strlen(sym) + 1; |
|---|
| 162 | | - s->sym = malloc(s->len + 1); |
|---|
| 163 | | - if (!s->sym) { |
|---|
| 231 | + |
|---|
| 232 | + len = strlen(name) + 1; |
|---|
| 233 | + |
|---|
| 234 | + sym = malloc(sizeof(*sym) + len + 1); |
|---|
| 235 | + if (!sym) { |
|---|
| 164 | 236 | fprintf(stderr, "kallsyms failure: " |
|---|
| 165 | 237 | "unable to allocate required amount of memory\n"); |
|---|
| 166 | 238 | exit(EXIT_FAILURE); |
|---|
| 167 | 239 | } |
|---|
| 168 | | - strcpy((char *)s->sym + 1, sym); |
|---|
| 169 | | - s->sym[0] = stype; |
|---|
| 240 | + sym->addr = addr; |
|---|
| 241 | + sym->len = len; |
|---|
| 242 | + sym->sym[0] = type; |
|---|
| 243 | + strcpy(sym_name(sym), name); |
|---|
| 244 | + sym->percpu_absolute = 0; |
|---|
| 170 | 245 | |
|---|
| 171 | | - s->percpu_absolute = 0; |
|---|
| 172 | | - |
|---|
| 173 | | - /* Record if we've found __per_cpu_start/end. */ |
|---|
| 174 | | - check_symbol_range(sym, s->addr, &percpu_range, 1); |
|---|
| 175 | | - |
|---|
| 176 | | - return 0; |
|---|
| 246 | + return sym; |
|---|
| 177 | 247 | } |
|---|
| 178 | 248 | |
|---|
| 179 | | -static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges, |
|---|
| 180 | | - int entries) |
|---|
| 249 | +static int symbol_in_range(const struct sym_entry *s, |
|---|
| 250 | + const struct addr_range *ranges, int entries) |
|---|
| 181 | 251 | { |
|---|
| 182 | 252 | size_t i; |
|---|
| 183 | | - struct addr_range *ar; |
|---|
| 253 | + const struct addr_range *ar; |
|---|
| 184 | 254 | |
|---|
| 185 | 255 | for (i = 0; i < entries; ++i) { |
|---|
| 186 | 256 | ar = &ranges[i]; |
|---|
| .. | .. |
|---|
| 192 | 262 | return 0; |
|---|
| 193 | 263 | } |
|---|
| 194 | 264 | |
|---|
| 195 | | -static int symbol_valid(struct sym_entry *s) |
|---|
| 265 | +static int symbol_valid(const struct sym_entry *s) |
|---|
| 196 | 266 | { |
|---|
| 197 | | - /* Symbols which vary between passes. Passes 1 and 2 must have |
|---|
| 198 | | - * identical symbol lists. The kallsyms_* symbols below are only added |
|---|
| 199 | | - * after pass 1, they would be included in pass 2 when --all-symbols is |
|---|
| 200 | | - * specified so exclude them to get a stable symbol list. |
|---|
| 201 | | - */ |
|---|
| 202 | | - static char *special_symbols[] = { |
|---|
| 203 | | - "kallsyms_addresses", |
|---|
| 204 | | - "kallsyms_offsets", |
|---|
| 205 | | - "kallsyms_relative_base", |
|---|
| 206 | | - "kallsyms_num_syms", |
|---|
| 207 | | - "kallsyms_names", |
|---|
| 208 | | - "kallsyms_markers", |
|---|
| 209 | | - "kallsyms_token_table", |
|---|
| 210 | | - "kallsyms_token_index", |
|---|
| 211 | | - |
|---|
| 212 | | - /* Exclude linker generated symbols which vary between passes */ |
|---|
| 213 | | - "_SDA_BASE_", /* ppc */ |
|---|
| 214 | | - "_SDA2_BASE_", /* ppc */ |
|---|
| 215 | | - NULL }; |
|---|
| 216 | | - |
|---|
| 217 | | - static char *special_prefixes[] = { |
|---|
| 218 | | - "__crc_", /* modversions */ |
|---|
| 219 | | - "__efistub_", /* arm64 EFI stub namespace */ |
|---|
| 220 | | - NULL }; |
|---|
| 221 | | - |
|---|
| 222 | | - static char *special_suffixes[] = { |
|---|
| 223 | | - "_veneer", /* arm */ |
|---|
| 224 | | - "_from_arm", /* arm */ |
|---|
| 225 | | - "_from_thumb", /* arm */ |
|---|
| 226 | | - NULL }; |
|---|
| 227 | | - |
|---|
| 228 | | - int i; |
|---|
| 229 | | - char *sym_name = (char *)s->sym + 1; |
|---|
| 267 | + const char *name = sym_name(s); |
|---|
| 230 | 268 | |
|---|
| 231 | 269 | /* if --all-symbols is not specified, then symbols outside the text |
|---|
| 232 | 270 | * and inittext sections are discarded */ |
|---|
| .. | .. |
|---|
| 241 | 279 | * rules. |
|---|
| 242 | 280 | */ |
|---|
| 243 | 281 | if ((s->addr == text_range_text->end && |
|---|
| 244 | | - strcmp(sym_name, |
|---|
| 245 | | - text_range_text->end_sym)) || |
|---|
| 282 | + strcmp(name, text_range_text->end_sym)) || |
|---|
| 246 | 283 | (s->addr == text_range_inittext->end && |
|---|
| 247 | | - strcmp(sym_name, |
|---|
| 248 | | - text_range_inittext->end_sym))) |
|---|
| 249 | | - return 0; |
|---|
| 250 | | - } |
|---|
| 251 | | - |
|---|
| 252 | | - /* Exclude symbols which vary between passes. */ |
|---|
| 253 | | - for (i = 0; special_symbols[i]; i++) |
|---|
| 254 | | - if (strcmp(sym_name, special_symbols[i]) == 0) |
|---|
| 255 | | - return 0; |
|---|
| 256 | | - |
|---|
| 257 | | - for (i = 0; special_prefixes[i]; i++) { |
|---|
| 258 | | - int l = strlen(special_prefixes[i]); |
|---|
| 259 | | - |
|---|
| 260 | | - if (l <= strlen(sym_name) && |
|---|
| 261 | | - strncmp(sym_name, special_prefixes[i], l) == 0) |
|---|
| 262 | | - return 0; |
|---|
| 263 | | - } |
|---|
| 264 | | - |
|---|
| 265 | | - for (i = 0; special_suffixes[i]; i++) { |
|---|
| 266 | | - int l = strlen(sym_name) - strlen(special_suffixes[i]); |
|---|
| 267 | | - |
|---|
| 268 | | - if (l >= 0 && strcmp(sym_name + l, special_suffixes[i]) == 0) |
|---|
| 284 | + strcmp(name, text_range_inittext->end_sym))) |
|---|
| 269 | 285 | return 0; |
|---|
| 270 | 286 | } |
|---|
| 271 | 287 | |
|---|
| 272 | 288 | return 1; |
|---|
| 273 | 289 | } |
|---|
| 274 | 290 | |
|---|
| 291 | +/* remove all the invalid symbols from the table */ |
|---|
| 292 | +static void shrink_table(void) |
|---|
| 293 | +{ |
|---|
| 294 | + unsigned int i, pos; |
|---|
| 295 | + |
|---|
| 296 | + pos = 0; |
|---|
| 297 | + for (i = 0; i < table_cnt; i++) { |
|---|
| 298 | + if (symbol_valid(table[i])) { |
|---|
| 299 | + if (pos != i) |
|---|
| 300 | + table[pos] = table[i]; |
|---|
| 301 | + pos++; |
|---|
| 302 | + } else { |
|---|
| 303 | + free(table[i]); |
|---|
| 304 | + } |
|---|
| 305 | + } |
|---|
| 306 | + table_cnt = pos; |
|---|
| 307 | + |
|---|
| 308 | + /* When valid symbol is not registered, exit to error */ |
|---|
| 309 | + if (!table_cnt) { |
|---|
| 310 | + fprintf(stderr, "No valid symbol.\n"); |
|---|
| 311 | + exit(1); |
|---|
| 312 | + } |
|---|
| 313 | +} |
|---|
| 314 | + |
|---|
| 275 | 315 | static void read_map(FILE *in) |
|---|
| 276 | 316 | { |
|---|
| 317 | + struct sym_entry *sym; |
|---|
| 318 | + |
|---|
| 277 | 319 | while (!feof(in)) { |
|---|
| 320 | + sym = read_symbol(in); |
|---|
| 321 | + if (!sym) |
|---|
| 322 | + continue; |
|---|
| 323 | + |
|---|
| 324 | + sym->start_pos = table_cnt; |
|---|
| 325 | + |
|---|
| 278 | 326 | if (table_cnt >= table_size) { |
|---|
| 279 | 327 | table_size += 10000; |
|---|
| 280 | 328 | table = realloc(table, sizeof(*table) * table_size); |
|---|
| .. | .. |
|---|
| 283 | 331 | exit (1); |
|---|
| 284 | 332 | } |
|---|
| 285 | 333 | } |
|---|
| 286 | | - if (read_symbol(in, &table[table_cnt]) == 0) { |
|---|
| 287 | | - table[table_cnt].start_pos = table_cnt; |
|---|
| 288 | | - table_cnt++; |
|---|
| 289 | | - } |
|---|
| 334 | + |
|---|
| 335 | + table[table_cnt++] = sym; |
|---|
| 290 | 336 | } |
|---|
| 291 | 337 | } |
|---|
| 292 | 338 | |
|---|
| 293 | | -static void output_label(char *label) |
|---|
| 339 | +static void output_label(const char *label) |
|---|
| 294 | 340 | { |
|---|
| 295 | 341 | printf(".globl %s\n", label); |
|---|
| 296 | 342 | printf("\tALGN\n"); |
|---|
| 297 | 343 | printf("%s:\n", label); |
|---|
| 298 | 344 | } |
|---|
| 299 | 345 | |
|---|
| 346 | +/* Provide proper symbols relocatability by their '_text' relativeness. */ |
|---|
| 347 | +static void output_address(unsigned long long addr) |
|---|
| 348 | +{ |
|---|
| 349 | + if (_text <= addr) |
|---|
| 350 | + printf("\tPTR\t_text + %#llx\n", addr - _text); |
|---|
| 351 | + else |
|---|
| 352 | + printf("\tPTR\t_text - %#llx\n", _text - addr); |
|---|
| 353 | +} |
|---|
| 354 | + |
|---|
| 300 | 355 | /* uncompress a compressed symbol. When this function is called, the best table |
|---|
| 301 | 356 | * might still be compressed itself, so the function needs to be recursive */ |
|---|
| 302 | | -static int expand_symbol(unsigned char *data, int len, char *result) |
|---|
| 357 | +static int expand_symbol(const unsigned char *data, int len, char *result) |
|---|
| 303 | 358 | { |
|---|
| 304 | 359 | int c, rlen, total=0; |
|---|
| 305 | 360 | |
|---|
| .. | .. |
|---|
| 324 | 379 | return total; |
|---|
| 325 | 380 | } |
|---|
| 326 | 381 | |
|---|
| 327 | | -static int symbol_absolute(struct sym_entry *s) |
|---|
| 382 | +static int symbol_absolute(const struct sym_entry *s) |
|---|
| 328 | 383 | { |
|---|
| 329 | 384 | return s->percpu_absolute; |
|---|
| 330 | 385 | } |
|---|
| .. | .. |
|---|
| 336 | 391 | unsigned int *markers; |
|---|
| 337 | 392 | char buf[KSYM_NAME_LEN]; |
|---|
| 338 | 393 | |
|---|
| 339 | | - printf("#include <asm/types.h>\n"); |
|---|
| 394 | + printf("#include <asm/bitsperlong.h>\n"); |
|---|
| 340 | 395 | printf("#if BITS_PER_LONG == 64\n"); |
|---|
| 341 | 396 | printf("#define PTR .quad\n"); |
|---|
| 342 | | - printf("#define ALGN .align 8\n"); |
|---|
| 397 | + printf("#define ALGN .balign 8\n"); |
|---|
| 343 | 398 | printf("#else\n"); |
|---|
| 344 | 399 | printf("#define PTR .long\n"); |
|---|
| 345 | | - printf("#define ALGN .align 4\n"); |
|---|
| 400 | + printf("#define ALGN .balign 4\n"); |
|---|
| 346 | 401 | printf("#endif\n"); |
|---|
| 347 | 402 | |
|---|
| 348 | 403 | printf("\t.section .rodata, \"a\"\n"); |
|---|
| 349 | 404 | |
|---|
| 350 | | - /* Provide proper symbols relocatability by their relativeness |
|---|
| 351 | | - * to a fixed anchor point in the runtime image, either '_text' |
|---|
| 352 | | - * for absolute address tables, in which case the linker will |
|---|
| 353 | | - * emit the final addresses at build time. Otherwise, use the |
|---|
| 354 | | - * offset relative to the lowest value encountered of all relative |
|---|
| 355 | | - * symbols, and emit non-relocatable fixed offsets that will be fixed |
|---|
| 356 | | - * up at runtime. |
|---|
| 357 | | - * |
|---|
| 358 | | - * The symbol names cannot be used to construct normal symbol |
|---|
| 359 | | - * references as the list of symbols contains symbols that are |
|---|
| 360 | | - * declared static and are private to their .o files. This prevents |
|---|
| 361 | | - * .tmp_kallsyms.o or any other object from referencing them. |
|---|
| 362 | | - */ |
|---|
| 363 | 405 | if (!base_relative) |
|---|
| 364 | 406 | output_label("kallsyms_addresses"); |
|---|
| 365 | 407 | else |
|---|
| .. | .. |
|---|
| 367 | 409 | |
|---|
| 368 | 410 | for (i = 0; i < table_cnt; i++) { |
|---|
| 369 | 411 | if (base_relative) { |
|---|
| 412 | + /* |
|---|
| 413 | + * Use the offset relative to the lowest value |
|---|
| 414 | + * encountered of all relative symbols, and emit |
|---|
| 415 | + * non-relocatable fixed offsets that will be fixed |
|---|
| 416 | + * up at runtime. |
|---|
| 417 | + */ |
|---|
| 418 | + |
|---|
| 370 | 419 | long long offset; |
|---|
| 371 | 420 | int overflow; |
|---|
| 372 | 421 | |
|---|
| 373 | 422 | if (!absolute_percpu) { |
|---|
| 374 | | - offset = table[i].addr - relative_base; |
|---|
| 423 | + offset = table[i]->addr - relative_base; |
|---|
| 375 | 424 | overflow = (offset < 0 || offset > UINT_MAX); |
|---|
| 376 | | - } else if (symbol_absolute(&table[i])) { |
|---|
| 377 | | - offset = table[i].addr; |
|---|
| 425 | + } else if (symbol_absolute(table[i])) { |
|---|
| 426 | + offset = table[i]->addr; |
|---|
| 378 | 427 | overflow = (offset < 0 || offset > INT_MAX); |
|---|
| 379 | 428 | } else { |
|---|
| 380 | | - offset = relative_base - table[i].addr - 1; |
|---|
| 429 | + offset = relative_base - table[i]->addr - 1; |
|---|
| 381 | 430 | overflow = (offset < INT_MIN || offset >= 0); |
|---|
| 382 | 431 | } |
|---|
| 383 | 432 | if (overflow) { |
|---|
| 384 | 433 | fprintf(stderr, "kallsyms failure: " |
|---|
| 385 | 434 | "%s symbol value %#llx out of range in relative mode\n", |
|---|
| 386 | | - symbol_absolute(&table[i]) ? "absolute" : "relative", |
|---|
| 387 | | - table[i].addr); |
|---|
| 435 | + symbol_absolute(table[i]) ? "absolute" : "relative", |
|---|
| 436 | + table[i]->addr); |
|---|
| 388 | 437 | exit(EXIT_FAILURE); |
|---|
| 389 | 438 | } |
|---|
| 390 | 439 | printf("\t.long\t%#x\n", (int)offset); |
|---|
| 391 | | - } else if (!symbol_absolute(&table[i])) { |
|---|
| 392 | | - if (_text <= table[i].addr) |
|---|
| 393 | | - printf("\tPTR\t_text + %#llx\n", |
|---|
| 394 | | - table[i].addr - _text); |
|---|
| 395 | | - else |
|---|
| 396 | | - printf("\tPTR\t_text - %#llx\n", |
|---|
| 397 | | - _text - table[i].addr); |
|---|
| 440 | + } else if (!symbol_absolute(table[i])) { |
|---|
| 441 | + output_address(table[i]->addr); |
|---|
| 398 | 442 | } else { |
|---|
| 399 | | - printf("\tPTR\t%#llx\n", table[i].addr); |
|---|
| 443 | + printf("\tPTR\t%#llx\n", table[i]->addr); |
|---|
| 400 | 444 | } |
|---|
| 401 | 445 | } |
|---|
| 402 | 446 | printf("\n"); |
|---|
| 403 | 447 | |
|---|
| 404 | 448 | if (base_relative) { |
|---|
| 405 | 449 | output_label("kallsyms_relative_base"); |
|---|
| 406 | | - printf("\tPTR\t_text - %#llx\n", _text - relative_base); |
|---|
| 450 | + output_address(relative_base); |
|---|
| 407 | 451 | printf("\n"); |
|---|
| 408 | 452 | } |
|---|
| 409 | 453 | |
|---|
| 410 | 454 | output_label("kallsyms_num_syms"); |
|---|
| 411 | | - printf("\tPTR\t%u\n", table_cnt); |
|---|
| 455 | + printf("\t.long\t%u\n", table_cnt); |
|---|
| 412 | 456 | printf("\n"); |
|---|
| 413 | 457 | |
|---|
| 414 | 458 | /* table of offset markers, that give the offset in the compressed stream |
|---|
| .. | .. |
|---|
| 426 | 470 | if ((i & 0xFF) == 0) |
|---|
| 427 | 471 | markers[i >> 8] = off; |
|---|
| 428 | 472 | |
|---|
| 429 | | - printf("\t.byte 0x%02x", table[i].len); |
|---|
| 430 | | - for (k = 0; k < table[i].len; k++) |
|---|
| 431 | | - printf(", 0x%02x", table[i].sym[k]); |
|---|
| 473 | + printf("\t.byte 0x%02x", table[i]->len); |
|---|
| 474 | + for (k = 0; k < table[i]->len; k++) |
|---|
| 475 | + printf(", 0x%02x", table[i]->sym[k]); |
|---|
| 432 | 476 | printf("\n"); |
|---|
| 433 | 477 | |
|---|
| 434 | | - off += table[i].len + 1; |
|---|
| 478 | + off += table[i]->len + 1; |
|---|
| 435 | 479 | } |
|---|
| 436 | 480 | printf("\n"); |
|---|
| 437 | 481 | |
|---|
| 438 | 482 | output_label("kallsyms_markers"); |
|---|
| 439 | 483 | for (i = 0; i < ((table_cnt + 255) >> 8); i++) |
|---|
| 440 | | - printf("\tPTR\t%d\n", markers[i]); |
|---|
| 484 | + printf("\t.long\t%u\n", markers[i]); |
|---|
| 441 | 485 | printf("\n"); |
|---|
| 442 | 486 | |
|---|
| 443 | 487 | free(markers); |
|---|
| .. | .. |
|---|
| 462 | 506 | /* table lookup compression functions */ |
|---|
| 463 | 507 | |
|---|
| 464 | 508 | /* count all the possible tokens in a symbol */ |
|---|
| 465 | | -static void learn_symbol(unsigned char *symbol, int len) |
|---|
| 509 | +static void learn_symbol(const unsigned char *symbol, int len) |
|---|
| 466 | 510 | { |
|---|
| 467 | 511 | int i; |
|---|
| 468 | 512 | |
|---|
| .. | .. |
|---|
| 471 | 515 | } |
|---|
| 472 | 516 | |
|---|
| 473 | 517 | /* decrease the count for all the possible tokens in a symbol */ |
|---|
| 474 | | -static void forget_symbol(unsigned char *symbol, int len) |
|---|
| 518 | +static void forget_symbol(const unsigned char *symbol, int len) |
|---|
| 475 | 519 | { |
|---|
| 476 | 520 | int i; |
|---|
| 477 | 521 | |
|---|
| .. | .. |
|---|
| 479 | 523 | token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--; |
|---|
| 480 | 524 | } |
|---|
| 481 | 525 | |
|---|
| 482 | | -/* remove all the invalid symbols from the table and do the initial token count */ |
|---|
| 526 | +/* do the initial token count */ |
|---|
| 483 | 527 | static void build_initial_tok_table(void) |
|---|
| 484 | 528 | { |
|---|
| 485 | | - unsigned int i, pos; |
|---|
| 529 | + unsigned int i; |
|---|
| 486 | 530 | |
|---|
| 487 | | - pos = 0; |
|---|
| 488 | | - for (i = 0; i < table_cnt; i++) { |
|---|
| 489 | | - if ( symbol_valid(&table[i]) ) { |
|---|
| 490 | | - if (pos != i) |
|---|
| 491 | | - table[pos] = table[i]; |
|---|
| 492 | | - learn_symbol(table[pos].sym, table[pos].len); |
|---|
| 493 | | - pos++; |
|---|
| 494 | | - } else { |
|---|
| 495 | | - free(table[i].sym); |
|---|
| 496 | | - } |
|---|
| 497 | | - } |
|---|
| 498 | | - table_cnt = pos; |
|---|
| 531 | + for (i = 0; i < table_cnt; i++) |
|---|
| 532 | + learn_symbol(table[i]->sym, table[i]->len); |
|---|
| 499 | 533 | } |
|---|
| 500 | 534 | |
|---|
| 501 | | -static void *find_token(unsigned char *str, int len, unsigned char *token) |
|---|
| 535 | +static unsigned char *find_token(unsigned char *str, int len, |
|---|
| 536 | + const unsigned char *token) |
|---|
| 502 | 537 | { |
|---|
| 503 | 538 | int i; |
|---|
| 504 | 539 | |
|---|
| .. | .. |
|---|
| 511 | 546 | |
|---|
| 512 | 547 | /* replace a given token in all the valid symbols. Use the sampled symbols |
|---|
| 513 | 548 | * to update the counts */ |
|---|
| 514 | | -static void compress_symbols(unsigned char *str, int idx) |
|---|
| 549 | +static void compress_symbols(const unsigned char *str, int idx) |
|---|
| 515 | 550 | { |
|---|
| 516 | 551 | unsigned int i, len, size; |
|---|
| 517 | 552 | unsigned char *p1, *p2; |
|---|
| 518 | 553 | |
|---|
| 519 | 554 | for (i = 0; i < table_cnt; i++) { |
|---|
| 520 | 555 | |
|---|
| 521 | | - len = table[i].len; |
|---|
| 522 | | - p1 = table[i].sym; |
|---|
| 556 | + len = table[i]->len; |
|---|
| 557 | + p1 = table[i]->sym; |
|---|
| 523 | 558 | |
|---|
| 524 | 559 | /* find the token on the symbol */ |
|---|
| 525 | 560 | p2 = find_token(p1, len, str); |
|---|
| 526 | 561 | if (!p2) continue; |
|---|
| 527 | 562 | |
|---|
| 528 | 563 | /* decrease the counts for this symbol's tokens */ |
|---|
| 529 | | - forget_symbol(table[i].sym, len); |
|---|
| 564 | + forget_symbol(table[i]->sym, len); |
|---|
| 530 | 565 | |
|---|
| 531 | 566 | size = len; |
|---|
| 532 | 567 | |
|---|
| .. | .. |
|---|
| 545 | 580 | |
|---|
| 546 | 581 | } while (p2); |
|---|
| 547 | 582 | |
|---|
| 548 | | - table[i].len = len; |
|---|
| 583 | + table[i]->len = len; |
|---|
| 549 | 584 | |
|---|
| 550 | 585 | /* increase the counts for this symbol's new tokens */ |
|---|
| 551 | | - learn_symbol(table[i].sym, len); |
|---|
| 586 | + learn_symbol(table[i]->sym, len); |
|---|
| 552 | 587 | } |
|---|
| 553 | 588 | } |
|---|
| 554 | 589 | |
|---|
| .. | .. |
|---|
| 603 | 638 | { |
|---|
| 604 | 639 | unsigned int i, j, c; |
|---|
| 605 | 640 | |
|---|
| 606 | | - memset(best_table, 0, sizeof(best_table)); |
|---|
| 607 | | - memset(best_table_len, 0, sizeof(best_table_len)); |
|---|
| 608 | | - |
|---|
| 609 | 641 | for (i = 0; i < table_cnt; i++) { |
|---|
| 610 | | - for (j = 0; j < table[i].len; j++) { |
|---|
| 611 | | - c = table[i].sym[j]; |
|---|
| 642 | + for (j = 0; j < table[i]->len; j++) { |
|---|
| 643 | + c = table[i]->sym[j]; |
|---|
| 612 | 644 | best_table[c][0]=c; |
|---|
| 613 | 645 | best_table_len[c]=1; |
|---|
| 614 | 646 | } |
|---|
| .. | .. |
|---|
| 621 | 653 | |
|---|
| 622 | 654 | insert_real_symbols_in_table(); |
|---|
| 623 | 655 | |
|---|
| 624 | | - /* When valid symbol is not registered, exit to error */ |
|---|
| 625 | | - if (!table_cnt) { |
|---|
| 626 | | - fprintf(stderr, "No valid symbol.\n"); |
|---|
| 627 | | - exit(1); |
|---|
| 628 | | - } |
|---|
| 629 | | - |
|---|
| 630 | 656 | optimize_result(); |
|---|
| 631 | 657 | } |
|---|
| 632 | 658 | |
|---|
| 633 | 659 | /* guess for "linker script provide" symbol */ |
|---|
| 634 | 660 | static int may_be_linker_script_provide_symbol(const struct sym_entry *se) |
|---|
| 635 | 661 | { |
|---|
| 636 | | - const char *symbol = (char *)se->sym + 1; |
|---|
| 662 | + const char *symbol = sym_name(se); |
|---|
| 637 | 663 | int len = se->len - 1; |
|---|
| 638 | 664 | |
|---|
| 639 | 665 | if (len < 8) |
|---|
| .. | .. |
|---|
| 665 | 691 | return 0; |
|---|
| 666 | 692 | } |
|---|
| 667 | 693 | |
|---|
| 668 | | -static int prefix_underscores_count(const char *str) |
|---|
| 669 | | -{ |
|---|
| 670 | | - const char *tail = str; |
|---|
| 671 | | - |
|---|
| 672 | | - while (*tail == '_') |
|---|
| 673 | | - tail++; |
|---|
| 674 | | - |
|---|
| 675 | | - return tail - str; |
|---|
| 676 | | -} |
|---|
| 677 | | - |
|---|
| 678 | 694 | static int compare_symbols(const void *a, const void *b) |
|---|
| 679 | 695 | { |
|---|
| 680 | | - const struct sym_entry *sa; |
|---|
| 681 | | - const struct sym_entry *sb; |
|---|
| 696 | + const struct sym_entry *sa = *(const struct sym_entry **)a; |
|---|
| 697 | + const struct sym_entry *sb = *(const struct sym_entry **)b; |
|---|
| 682 | 698 | int wa, wb; |
|---|
| 683 | | - |
|---|
| 684 | | - sa = a; |
|---|
| 685 | | - sb = b; |
|---|
| 686 | 699 | |
|---|
| 687 | 700 | /* sort by address first */ |
|---|
| 688 | 701 | if (sa->addr > sb->addr) |
|---|
| .. | .. |
|---|
| 703 | 716 | return wa - wb; |
|---|
| 704 | 717 | |
|---|
| 705 | 718 | /* sort by the number of prefix underscores */ |
|---|
| 706 | | - wa = prefix_underscores_count((const char *)sa->sym + 1); |
|---|
| 707 | | - wb = prefix_underscores_count((const char *)sb->sym + 1); |
|---|
| 719 | + wa = strspn(sym_name(sa), "_"); |
|---|
| 720 | + wb = strspn(sym_name(sb), "_"); |
|---|
| 708 | 721 | if (wa != wb) |
|---|
| 709 | 722 | return wa - wb; |
|---|
| 710 | 723 | |
|---|
| .. | .. |
|---|
| 714 | 727 | |
|---|
| 715 | 728 | static void sort_symbols(void) |
|---|
| 716 | 729 | { |
|---|
| 717 | | - qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols); |
|---|
| 730 | + qsort(table, table_cnt, sizeof(table[0]), compare_symbols); |
|---|
| 718 | 731 | } |
|---|
| 719 | 732 | |
|---|
| 720 | 733 | static void make_percpus_absolute(void) |
|---|
| .. | .. |
|---|
| 722 | 735 | unsigned int i; |
|---|
| 723 | 736 | |
|---|
| 724 | 737 | for (i = 0; i < table_cnt; i++) |
|---|
| 725 | | - if (symbol_in_range(&table[i], &percpu_range, 1)) { |
|---|
| 738 | + if (symbol_in_range(table[i], &percpu_range, 1)) { |
|---|
| 726 | 739 | /* |
|---|
| 727 | 740 | * Keep the 'A' override for percpu symbols to |
|---|
| 728 | 741 | * ensure consistent behavior compared to older |
|---|
| 729 | 742 | * versions of this tool. |
|---|
| 730 | 743 | */ |
|---|
| 731 | | - table[i].sym[0] = 'A'; |
|---|
| 732 | | - table[i].percpu_absolute = 1; |
|---|
| 744 | + table[i]->sym[0] = 'A'; |
|---|
| 745 | + table[i]->percpu_absolute = 1; |
|---|
| 733 | 746 | } |
|---|
| 734 | 747 | } |
|---|
| 735 | 748 | |
|---|
| .. | .. |
|---|
| 738 | 751 | { |
|---|
| 739 | 752 | unsigned int i; |
|---|
| 740 | 753 | |
|---|
| 741 | | - relative_base = -1ULL; |
|---|
| 742 | 754 | for (i = 0; i < table_cnt; i++) |
|---|
| 743 | | - if (!symbol_absolute(&table[i]) && |
|---|
| 744 | | - table[i].addr < relative_base) |
|---|
| 745 | | - relative_base = table[i].addr; |
|---|
| 755 | + if (!symbol_absolute(table[i])) { |
|---|
| 756 | + /* |
|---|
| 757 | + * The table is sorted by address. |
|---|
| 758 | + * Take the first non-absolute symbol value. |
|---|
| 759 | + */ |
|---|
| 760 | + relative_base = table[i]->addr; |
|---|
| 761 | + return; |
|---|
| 762 | + } |
|---|
| 746 | 763 | } |
|---|
| 747 | 764 | |
|---|
| 748 | 765 | int main(int argc, char **argv) |
|---|
| .. | .. |
|---|
| 763 | 780 | usage(); |
|---|
| 764 | 781 | |
|---|
| 765 | 782 | read_map(stdin); |
|---|
| 783 | + shrink_table(); |
|---|
| 766 | 784 | if (absolute_percpu) |
|---|
| 767 | 785 | make_percpus_absolute(); |
|---|
| 786 | + sort_symbols(); |
|---|
| 768 | 787 | if (base_relative) |
|---|
| 769 | 788 | record_relative_base(); |
|---|
| 770 | | - sort_symbols(); |
|---|
| 771 | 789 | optimize_token_table(); |
|---|
| 772 | 790 | write_src(); |
|---|
| 773 | 791 | |
|---|