Blame view
scripts/kallsyms.c
17.9 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 |
/* Generate assembler source containing symbol information * * Copyright 2002 by Kai Germaschewski * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S * |
1da177e4c Linux-2.6.12-rc2 |
10 11 12 13 14 15 16 17 18 19 |
* Table compression uses all the unused char codes on the symbols and * maps these to the most used substrings (tokens). For instance, it might * map char code 0xF7 to represent "write_" and then in every symbol where * "write_" appears it can be replaced by 0xF7, saving 5 bytes. * The used codes themselves are also placed in the table so that the * decompresion can work without "special cases". * Applied to kernel symbols, this usually produces a compression ratio * of about 50%. * */ |
a41333e06 scripts/kallsyms:... |
20 |
#include <stdbool.h> |
1da177e4c Linux-2.6.12-rc2 |
21 22 23 24 |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> |
2213e9a66 kallsyms: add sup... |
25 |
#include <limits.h> |
1da177e4c Linux-2.6.12-rc2 |
26 |
|
17b1f0de7 kallsyms: general... |
27 |
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) |
17b1f0de7 kallsyms: general... |
28 |
|
9281acea6 kallsyms: make KS... |
29 |
#define KSYM_NAME_LEN 128 |
1da177e4c Linux-2.6.12-rc2 |
30 |
|
1da177e4c Linux-2.6.12-rc2 |
31 32 |
struct sym_entry { unsigned long long addr; |
b3dbb4ecd [PATCH] kallsyms:... |
33 |
unsigned int len; |
f2df3f65d kallsyms should p... |
34 |
unsigned int start_pos; |
8c996940b kallsyms: don't o... |
35 |
unsigned int percpu_absolute; |
9d82973e0 gcc-10 warnings: ... |
36 |
unsigned char sym[]; |
1da177e4c Linux-2.6.12-rc2 |
37 |
}; |
78eb71594 kallsyms: general... |
38 39 |
struct addr_range { const char *start_sym, *end_sym; |
17b1f0de7 kallsyms: general... |
40 41 42 43 |
unsigned long long start, end; }; static unsigned long long _text; |
2213e9a66 kallsyms: add sup... |
44 |
static unsigned long long relative_base; |
78eb71594 kallsyms: general... |
45 |
static struct addr_range text_ranges[] = { |
17b1f0de7 kallsyms: general... |
46 47 |
{ "_stext", "_etext" }, { "_sinittext", "_einittext" }, |
17b1f0de7 kallsyms: general... |
48 49 50 |
}; #define text_range_text (&text_ranges[0]) #define text_range_inittext (&text_ranges[1]) |
c6bda7c98 kallsyms: fix per... |
51 52 53 |
static struct addr_range percpu_range = { "__per_cpu_start", "__per_cpu_end", -1ULL, 0 }; |
8d6052699 scripts/kallsyms:... |
54 |
static struct sym_entry **table; |
b3dbb4ecd [PATCH] kallsyms:... |
55 |
static unsigned int table_size, table_cnt; |
831362fc3 scripts/kallsyms:... |
56 57 58 |
static int all_symbols; static int absolute_percpu; static int base_relative; |
1da177e4c Linux-2.6.12-rc2 |
59 |
|
f43e9daac kallsyms: add sta... |
60 |
static int token_profit[0x10000]; |
1da177e4c Linux-2.6.12-rc2 |
61 62 |
/* the table that holds the result of the compression */ |
f43e9daac kallsyms: add sta... |
63 64 |
static unsigned char best_table[256][2]; static unsigned char best_table_len[256]; |
1da177e4c Linux-2.6.12-rc2 |
65 |
|
b3dbb4ecd [PATCH] kallsyms:... |
66 |
static void usage(void) |
1da177e4c Linux-2.6.12-rc2 |
67 |
{ |
f6537f2f0 scripts/kallsyms:... |
68 |
fprintf(stderr, "Usage: kallsyms [--all-symbols] " |
2213e9a66 kallsyms: add sup... |
69 70 |
"[--base-relative] < in.map > out.S "); |
1da177e4c Linux-2.6.12-rc2 |
71 72 |
exit(1); } |
29e55ad3d scripts/kallsyms:... |
73 74 75 76 |
static char *sym_name(const struct sym_entry *s) { return (char *)s->sym + 1; } |
a41333e06 scripts/kallsyms:... |
77 78 |
static bool is_ignored_symbol(const char *name, char type) { |
516d980f8 scripts/kallsyms:... |
79 |
/* Symbol names that exactly match to the following are ignored.*/ |
a41333e06 scripts/kallsyms:... |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
static const char * const ignored_symbols[] = { /* * Symbols which vary between passes. Passes 1 and 2 must have * identical symbol lists. The kallsyms_* symbols below are * only added after pass 1, they would be included in pass 2 * when --all-symbols is specified so exclude them to get a * stable symbol list. */ "kallsyms_addresses", "kallsyms_offsets", "kallsyms_relative_base", "kallsyms_num_syms", "kallsyms_names", "kallsyms_markers", "kallsyms_token_table", "kallsyms_token_index", /* Exclude linker generated symbols which vary between passes */ "_SDA_BASE_", /* ppc */ "_SDA2_BASE_", /* ppc */ NULL }; |
516d980f8 scripts/kallsyms:... |
101 |
/* Symbol names that begin with the following are ignored.*/ |
a41333e06 scripts/kallsyms:... |
102 |
static const char * const ignored_prefixes[] = { |
97261e1e2 scripts/kallsyms:... |
103 104 |
"$", /* local symbols for ARM, MIPS, etc. */ ".LASANPC", /* s390 kasan local symbols */ |
a41333e06 scripts/kallsyms:... |
105 106 |
"__crc_", /* modversions */ "__efistub_", /* arm64 EFI stub namespace */ |
762171291 KVM: arm64: Add b... |
107 |
"__kvm_nvhe_", /* arm64 non-VHE KVM namespace */ |
a41333e06 scripts/kallsyms:... |
108 109 |
NULL }; |
516d980f8 scripts/kallsyms:... |
110 |
/* Symbol names that end with the following are ignored.*/ |
a41333e06 scripts/kallsyms:... |
111 112 113 114 115 116 |
static const char * const ignored_suffixes[] = { "_from_arm", /* arm */ "_from_thumb", /* arm */ "_veneer", /* arm */ NULL }; |
516d980f8 scripts/kallsyms:... |
117 118 119 120 121 122 |
/* Symbol names that contain the following are ignored.*/ static const char * const ignored_matches[] = { ".long_branch.", /* ppc stub */ ".plt_branch.", /* ppc stub */ NULL }; |
a41333e06 scripts/kallsyms:... |
123 |
const char * const *p; |
a41333e06 scripts/kallsyms:... |
124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
for (p = ignored_symbols; *p; p++) if (!strcmp(name, *p)) return true; for (p = ignored_prefixes; *p; p++) if (!strncmp(name, *p, strlen(*p))) return true; for (p = ignored_suffixes; *p; p++) { int l = strlen(name) - strlen(*p); if (l >= 0 && !strcmp(name + l, *p)) return true; } |
516d980f8 scripts/kallsyms:... |
138 139 140 141 |
for (p = ignored_matches; *p; p++) { if (strstr(name, *p)) return true; } |
887df76de scripts/kallsyms:... |
142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
if (type == 'U' || type == 'u') return true; /* exclude debugging symbols */ if (type == 'N' || type == 'n') return true; if (toupper(type) == 'A') { /* Keep these useful absolute symbols */ if (strcmp(name, "__kernel_syscall_via_break") && strcmp(name, "__kernel_syscall_via_epc") && strcmp(name, "__kernel_sigtramp") && strcmp(name, "__gp")) return true; } |
a41333e06 scripts/kallsyms:... |
156 157 |
return false; } |
b6233d0de scripts/kallsyms:... |
158 159 |
static void check_symbol_range(const char *sym, unsigned long long addr, struct addr_range *ranges, int entries) |
17b1f0de7 kallsyms: general... |
160 161 |
{ size_t i; |
78eb71594 kallsyms: general... |
162 |
struct addr_range *ar; |
17b1f0de7 kallsyms: general... |
163 |
|
78eb71594 kallsyms: general... |
164 165 |
for (i = 0; i < entries; ++i) { ar = &ranges[i]; |
17b1f0de7 kallsyms: general... |
166 |
|
78eb71594 kallsyms: general... |
167 168 |
if (strcmp(sym, ar->start_sym) == 0) { ar->start = addr; |
b6233d0de scripts/kallsyms:... |
169 |
return; |
78eb71594 kallsyms: general... |
170 171 |
} else if (strcmp(sym, ar->end_sym) == 0) { ar->end = addr; |
b6233d0de scripts/kallsyms:... |
172 |
return; |
17b1f0de7 kallsyms: general... |
173 174 |
} } |
17b1f0de7 kallsyms: general... |
175 |
} |
8d6052699 scripts/kallsyms:... |
176 |
static struct sym_entry *read_symbol(FILE *in) |
1da177e4c Linux-2.6.12-rc2 |
177 |
{ |
be9f6133f scripts/kallsyms:... |
178 |
char name[500], type; |
8d6052699 scripts/kallsyms:... |
179 180 181 |
unsigned long long addr; unsigned int len; struct sym_entry *sym; |
1da177e4c Linux-2.6.12-rc2 |
182 |
int rc; |
8d6052699 scripts/kallsyms:... |
183 184 |
rc = fscanf(in, "%llx %c %499s ", &addr, &type, name); |
1da177e4c Linux-2.6.12-rc2 |
185 |
if (rc != 3) { |
be9f6133f scripts/kallsyms:... |
186 |
if (rc != EOF && fgets(name, 500, in) == NULL) |
ef894870c scripts/kallsyms:... |
187 188 |
fprintf(stderr, "Read error or end of file. "); |
8d6052699 scripts/kallsyms:... |
189 |
return NULL; |
1da177e4c Linux-2.6.12-rc2 |
190 |
} |
be9f6133f scripts/kallsyms:... |
191 |
if (strlen(name) >= KSYM_NAME_LEN) { |
6db2983cd kallsyms: Handle ... |
192 193 |
fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d). " |
bb66fc671 kbuild: trivial -... |
194 195 |
"Please increase KSYM_NAME_LEN both in kernel and kallsyms.c ", |
be9f6133f scripts/kallsyms:... |
196 |
name, strlen(name), KSYM_NAME_LEN); |
8d6052699 scripts/kallsyms:... |
197 |
return NULL; |
f3462aa95 Kbuild: Handle lo... |
198 |
} |
1da177e4c Linux-2.6.12-rc2 |
199 |
|
be9f6133f scripts/kallsyms:... |
200 |
if (strcmp(name, "_text") == 0) |
8d6052699 scripts/kallsyms:... |
201 |
_text = addr; |
b6233d0de scripts/kallsyms:... |
202 |
|
7883a1433 scripts/kallsyms:... |
203 204 205 |
/* Ignore most absolute/undefined (?) symbols. */ if (is_ignored_symbol(name, type)) return NULL; |
8d6052699 scripts/kallsyms:... |
206 207 |
check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges)); check_symbol_range(name, addr, &percpu_range, 1); |
1da177e4c Linux-2.6.12-rc2 |
208 209 210 |
/* include the type field in the symbol name, so that it gets * compressed together */ |
8d6052699 scripts/kallsyms:... |
211 212 |
len = strlen(name) + 1; |
9d1b38958 scripts/kallsyms:... |
213 |
sym = malloc(sizeof(*sym) + len + 1); |
8d6052699 scripts/kallsyms:... |
214 |
if (!sym) { |
f1a136e0d [PATCH] kallsyms:... |
215 216 217 218 219 |
fprintf(stderr, "kallsyms failure: " "unable to allocate required amount of memory "); exit(EXIT_FAILURE); } |
8d6052699 scripts/kallsyms:... |
220 221 222 |
sym->addr = addr; sym->len = len; sym->sym[0] = type; |
9d1b38958 scripts/kallsyms:... |
223 |
strcpy(sym_name(sym), name); |
8d6052699 scripts/kallsyms:... |
224 |
sym->percpu_absolute = 0; |
8c996940b kallsyms: don't o... |
225 |
|
8d6052699 scripts/kallsyms:... |
226 |
return sym; |
1da177e4c Linux-2.6.12-rc2 |
227 |
} |
4bfe2b781 scripts/kallsyms:... |
228 229 |
static int symbol_in_range(const struct sym_entry *s, const struct addr_range *ranges, int entries) |
17b1f0de7 kallsyms: general... |
230 231 |
{ size_t i; |
4bfe2b781 scripts/kallsyms:... |
232 |
const struct addr_range *ar; |
17b1f0de7 kallsyms: general... |
233 |
|
78eb71594 kallsyms: general... |
234 235 |
for (i = 0; i < entries; ++i) { ar = &ranges[i]; |
17b1f0de7 kallsyms: general... |
236 |
|
78eb71594 kallsyms: general... |
237 |
if (s->addr >= ar->start && s->addr <= ar->end) |
ac6ca5c86 kallsyms: fix inv... |
238 |
return 1; |
17b1f0de7 kallsyms: general... |
239 |
} |
ac6ca5c86 kallsyms: fix inv... |
240 |
return 0; |
17b1f0de7 kallsyms: general... |
241 |
} |
4bfe2b781 scripts/kallsyms:... |
242 |
static int symbol_valid(const struct sym_entry *s) |
1da177e4c Linux-2.6.12-rc2 |
243 |
{ |
29e55ad3d scripts/kallsyms:... |
244 |
const char *name = sym_name(s); |
bd8b22d28 Kbuild: kallsyms:... |
245 |
|
1da177e4c Linux-2.6.12-rc2 |
246 247 248 |
/* if --all-symbols is not specified, then symbols outside the text * and inittext sections are discarded */ if (!all_symbols) { |
78eb71594 kallsyms: general... |
249 250 |
if (symbol_in_range(s, text_ranges, ARRAY_SIZE(text_ranges)) == 0) |
1da177e4c Linux-2.6.12-rc2 |
251 252 |
return 0; /* Corner case. Discard any symbols with the same value as |
a3b81113f remove support fo... |
253 254 255 256 |
* _etext _einittext; they can move between pass 1 and 2 when * the kallsyms data are added. If these symbols move then * they may get dropped in pass 2, which breaks the kallsyms * rules. |
1da177e4c Linux-2.6.12-rc2 |
257 |
*/ |
17b1f0de7 kallsyms: general... |
258 |
if ((s->addr == text_range_text->end && |
29e55ad3d scripts/kallsyms:... |
259 |
strcmp(name, text_range_text->end_sym)) || |
17b1f0de7 kallsyms: general... |
260 |
(s->addr == text_range_inittext->end && |
29e55ad3d scripts/kallsyms:... |
261 |
strcmp(name, text_range_inittext->end_sym))) |
1da177e4c Linux-2.6.12-rc2 |
262 263 |
return 0; } |
1da177e4c Linux-2.6.12-rc2 |
264 265 |
return 1; } |
5e5c4fa78 scripts/kallsyms:... |
266 267 268 269 270 271 272 |
/* remove all the invalid symbols from the table */ static void shrink_table(void) { unsigned int i, pos; pos = 0; for (i = 0; i < table_cnt; i++) { |
8d6052699 scripts/kallsyms:... |
273 |
if (symbol_valid(table[i])) { |
5e5c4fa78 scripts/kallsyms:... |
274 275 276 277 |
if (pos != i) table[pos] = table[i]; pos++; } else { |
8d6052699 scripts/kallsyms:... |
278 |
free(table[i]); |
5e5c4fa78 scripts/kallsyms:... |
279 280 281 282 283 284 285 286 287 288 289 |
} } table_cnt = pos; /* When valid symbol is not registered, exit to error */ if (!table_cnt) { fprintf(stderr, "No valid symbol. "); exit(1); } } |
b3dbb4ecd [PATCH] kallsyms:... |
290 |
static void read_map(FILE *in) |
1da177e4c Linux-2.6.12-rc2 |
291 |
{ |
8d6052699 scripts/kallsyms:... |
292 |
struct sym_entry *sym; |
1da177e4c Linux-2.6.12-rc2 |
293 |
while (!feof(in)) { |
8d6052699 scripts/kallsyms:... |
294 295 296 297 298 |
sym = read_symbol(in); if (!sym) continue; sym->start_pos = table_cnt; |
b3dbb4ecd [PATCH] kallsyms:... |
299 300 301 |
if (table_cnt >= table_size) { table_size += 10000; table = realloc(table, sizeof(*table) * table_size); |
1da177e4c Linux-2.6.12-rc2 |
302 303 304 305 306 307 |
if (!table) { fprintf(stderr, "out of memory "); exit (1); } } |
8d6052699 scripts/kallsyms:... |
308 309 |
table[table_cnt++] = sym; |
1da177e4c Linux-2.6.12-rc2 |
310 311 |
} } |
4bfe2b781 scripts/kallsyms:... |
312 |
static void output_label(const char *label) |
1da177e4c Linux-2.6.12-rc2 |
313 |
{ |
534c9f2ec kallsyms: remove ... |
314 315 |
printf(".globl %s ", label); |
1da177e4c Linux-2.6.12-rc2 |
316 317 |
printf("\tALGN "); |
534c9f2ec kallsyms: remove ... |
318 319 |
printf("%s: ", label); |
1da177e4c Linux-2.6.12-rc2 |
320 |
} |
fd2ab2f66 scripts/kallsyms:... |
321 322 323 324 325 326 327 328 329 330 |
/* Provide proper symbols relocatability by their '_text' relativeness. */ static void output_address(unsigned long long addr) { if (_text <= addr) printf("\tPTR\t_text + %#llx ", addr - _text); else printf("\tPTR\t_text - %#llx ", _text - addr); } |
1da177e4c Linux-2.6.12-rc2 |
331 332 |
/* uncompress a compressed symbol. When this function is called, the best table * might still be compressed itself, so the function needs to be recursive */ |
4bfe2b781 scripts/kallsyms:... |
333 |
static int expand_symbol(const unsigned char *data, int len, char *result) |
1da177e4c Linux-2.6.12-rc2 |
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
{ int c, rlen, total=0; while (len) { c = *data; /* if the table holds a single char that is the same as the one * we are looking for, then end the search */ if (best_table[c][0]==c && best_table_len[c]==1) { *result++ = c; total++; } else { /* if not, recurse and expand */ rlen = expand_symbol(best_table[c], best_table_len[c], result); total += rlen; result += rlen; } data++; len--; } *result=0; return total; } |
4bfe2b781 scripts/kallsyms:... |
357 |
static int symbol_absolute(const struct sym_entry *s) |
78eb71594 kallsyms: general... |
358 |
{ |
8c996940b kallsyms: don't o... |
359 |
return s->percpu_absolute; |
78eb71594 kallsyms: general... |
360 |
} |
b3dbb4ecd [PATCH] kallsyms:... |
361 |
static void write_src(void) |
1da177e4c Linux-2.6.12-rc2 |
362 |
{ |
b3dbb4ecd [PATCH] kallsyms:... |
363 |
unsigned int i, k, off; |
1da177e4c Linux-2.6.12-rc2 |
364 365 |
unsigned int best_idx[256]; unsigned int *markers; |
9281acea6 kallsyms: make KS... |
366 |
char buf[KSYM_NAME_LEN]; |
1da177e4c Linux-2.6.12-rc2 |
367 |
|
500193ec5 kallsyms: include... |
368 369 |
printf("#include <asm/bitsperlong.h> "); |
1da177e4c Linux-2.6.12-rc2 |
370 371 372 373 |
printf("#if BITS_PER_LONG == 64 "); printf("#define PTR .quad "); |
72d3ebb92 kallsyms: lower a... |
374 375 |
printf("#define ALGN .balign 8 "); |
1da177e4c Linux-2.6.12-rc2 |
376 377 378 379 |
printf("#else "); printf("#define PTR .long "); |
72d3ebb92 kallsyms: lower a... |
380 381 |
printf("#define ALGN .balign 4 "); |
1da177e4c Linux-2.6.12-rc2 |
382 383 |
printf("#endif "); |
aad094701 [PATCH] move kall... |
384 385 |
printf("\t.section .rodata, \"a\" "); |
1da177e4c Linux-2.6.12-rc2 |
386 |
|
2213e9a66 kallsyms: add sup... |
387 388 389 390 |
if (!base_relative) output_label("kallsyms_addresses"); else output_label("kallsyms_offsets"); |
b3dbb4ecd [PATCH] kallsyms:... |
391 |
for (i = 0; i < table_cnt; i++) { |
2213e9a66 kallsyms: add sup... |
392 |
if (base_relative) { |
fd2ab2f66 scripts/kallsyms:... |
393 394 395 396 397 398 |
/* * 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. */ |
2213e9a66 kallsyms: add sup... |
399 400 401 402 |
long long offset; int overflow; if (!absolute_percpu) { |
8d6052699 scripts/kallsyms:... |
403 |
offset = table[i]->addr - relative_base; |
2213e9a66 kallsyms: add sup... |
404 |
overflow = (offset < 0 || offset > UINT_MAX); |
8d6052699 scripts/kallsyms:... |
405 406 |
} else if (symbol_absolute(table[i])) { offset = table[i]->addr; |
2213e9a66 kallsyms: add sup... |
407 408 |
overflow = (offset < 0 || offset > INT_MAX); } else { |
8d6052699 scripts/kallsyms:... |
409 |
offset = relative_base - table[i]->addr - 1; |
2213e9a66 kallsyms: add sup... |
410 411 412 413 414 415 |
overflow = (offset < INT_MIN || offset >= 0); } if (overflow) { fprintf(stderr, "kallsyms failure: " "%s symbol value %#llx out of range in relative mode ", |
8d6052699 scripts/kallsyms:... |
416 417 |
symbol_absolute(table[i]) ? "absolute" : "relative", table[i]->addr); |
2213e9a66 kallsyms: add sup... |
418 419 420 421 |
exit(EXIT_FAILURE); } printf("\t.long\t%#x ", (int)offset); |
8d6052699 scripts/kallsyms:... |
422 423 |
} else if (!symbol_absolute(table[i])) { output_address(table[i]->addr); |
fd593d127 [PATCH] relocatab... |
424 |
} else { |
8d6052699 scripts/kallsyms:... |
425 426 |
printf("\tPTR\t%#llx ", table[i]->addr); |
fd593d127 [PATCH] relocatab... |
427 |
} |
1da177e4c Linux-2.6.12-rc2 |
428 429 430 |
} printf(" "); |
2213e9a66 kallsyms: add sup... |
431 432 |
if (base_relative) { output_label("kallsyms_relative_base"); |
fd2ab2f66 scripts/kallsyms:... |
433 |
output_address(relative_base); |
2213e9a66 kallsyms: add sup... |
434 435 436 |
printf(" "); } |
1da177e4c Linux-2.6.12-rc2 |
437 |
output_label("kallsyms_num_syms"); |
80ffbaa5b kallsyms: reduce ... |
438 439 |
printf("\t.long\t%u ", table_cnt); |
1da177e4c Linux-2.6.12-rc2 |
440 441 442 443 444 |
printf(" "); /* table of offset markers, that give the offset in the compressed stream * every 256 symbols */ |
f1a136e0d [PATCH] kallsyms:... |
445 446 447 448 449 450 451 |
markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256)); if (!markers) { fprintf(stderr, "kallsyms failure: " "unable to allocate required memory "); exit(EXIT_FAILURE); } |
1da177e4c Linux-2.6.12-rc2 |
452 453 |
output_label("kallsyms_names"); |
1da177e4c Linux-2.6.12-rc2 |
454 |
off = 0; |
b3dbb4ecd [PATCH] kallsyms:... |
455 456 457 |
for (i = 0; i < table_cnt; i++) { if ((i & 0xFF) == 0) markers[i >> 8] = off; |
1da177e4c Linux-2.6.12-rc2 |
458 |
|
8d6052699 scripts/kallsyms:... |
459 460 461 |
printf("\t.byte 0x%02x", table[i]->len); for (k = 0; k < table[i]->len; k++) printf(", 0x%02x", table[i]->sym[k]); |
1da177e4c Linux-2.6.12-rc2 |
462 463 |
printf(" "); |
8d6052699 scripts/kallsyms:... |
464 |
off += table[i]->len + 1; |
1da177e4c Linux-2.6.12-rc2 |
465 466 467 468 469 |
} printf(" "); output_label("kallsyms_markers"); |
b3dbb4ecd [PATCH] kallsyms:... |
470 |
for (i = 0; i < ((table_cnt + 255) >> 8); i++) |
80ffbaa5b kallsyms: reduce ... |
471 472 |
printf("\t.long\t%u ", markers[i]); |
1da177e4c Linux-2.6.12-rc2 |
473 474 475 476 477 478 479 480 481 |
printf(" "); free(markers); output_label("kallsyms_token_table"); off = 0; for (i = 0; i < 256; i++) { best_idx[i] = off; |
b3dbb4ecd [PATCH] kallsyms:... |
482 |
expand_symbol(best_table[i], best_table_len[i], buf); |
1da177e4c Linux-2.6.12-rc2 |
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
printf("\t.asciz\t\"%s\" ", buf); off += strlen(buf) + 1; } printf(" "); output_label("kallsyms_token_index"); for (i = 0; i < 256; i++) printf("\t.short\t%d ", best_idx[i]); printf(" "); } /* table lookup compression functions */ |
1da177e4c Linux-2.6.12-rc2 |
500 |
/* count all the possible tokens in a symbol */ |
4bfe2b781 scripts/kallsyms:... |
501 |
static void learn_symbol(const unsigned char *symbol, int len) |
1da177e4c Linux-2.6.12-rc2 |
502 503 504 505 |
{ int i; for (i = 0; i < len - 1; i++) |
b3dbb4ecd [PATCH] kallsyms:... |
506 |
token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++; |
1da177e4c Linux-2.6.12-rc2 |
507 508 509 |
} /* decrease the count for all the possible tokens in a symbol */ |
4bfe2b781 scripts/kallsyms:... |
510 |
static void forget_symbol(const unsigned char *symbol, int len) |
1da177e4c Linux-2.6.12-rc2 |
511 512 513 514 |
{ int i; for (i = 0; i < len - 1; i++) |
b3dbb4ecd [PATCH] kallsyms:... |
515 |
token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--; |
1da177e4c Linux-2.6.12-rc2 |
516 |
} |
5e5c4fa78 scripts/kallsyms:... |
517 |
/* do the initial token count */ |
1da177e4c Linux-2.6.12-rc2 |
518 519 |
static void build_initial_tok_table(void) { |
5e5c4fa78 scripts/kallsyms:... |
520 |
unsigned int i; |
1da177e4c Linux-2.6.12-rc2 |
521 |
|
5e5c4fa78 scripts/kallsyms:... |
522 |
for (i = 0; i < table_cnt; i++) |
8d6052699 scripts/kallsyms:... |
523 |
learn_symbol(table[i]->sym, table[i]->len); |
1da177e4c Linux-2.6.12-rc2 |
524 |
} |
2558c138a scripts/kallsyms:... |
525 |
static unsigned char *find_token(unsigned char *str, int len, |
4bfe2b781 scripts/kallsyms:... |
526 |
const unsigned char *token) |
7c5d249ad kallsyms: remove ... |
527 528 529 530 531 532 533 534 535 |
{ int i; for (i = 0; i < len - 1; i++) { if (str[i] == token[0] && str[i+1] == token[1]) return &str[i]; } return NULL; } |
1da177e4c Linux-2.6.12-rc2 |
536 537 |
/* replace a given token in all the valid symbols. Use the sampled symbols * to update the counts */ |
4bfe2b781 scripts/kallsyms:... |
538 |
static void compress_symbols(const unsigned char *str, int idx) |
1da177e4c Linux-2.6.12-rc2 |
539 |
{ |
b3dbb4ecd [PATCH] kallsyms:... |
540 541 |
unsigned int i, len, size; unsigned char *p1, *p2; |
1da177e4c Linux-2.6.12-rc2 |
542 |
|
b3dbb4ecd [PATCH] kallsyms:... |
543 |
for (i = 0; i < table_cnt; i++) { |
1da177e4c Linux-2.6.12-rc2 |
544 |
|
8d6052699 scripts/kallsyms:... |
545 546 |
len = table[i]->len; p1 = table[i]->sym; |
b3dbb4ecd [PATCH] kallsyms:... |
547 548 |
/* find the token on the symbol */ |
7c5d249ad kallsyms: remove ... |
549 |
p2 = find_token(p1, len, str); |
b3dbb4ecd [PATCH] kallsyms:... |
550 551 552 |
if (!p2) continue; /* decrease the counts for this symbol's tokens */ |
8d6052699 scripts/kallsyms:... |
553 |
forget_symbol(table[i]->sym, len); |
b3dbb4ecd [PATCH] kallsyms:... |
554 555 |
size = len; |
1da177e4c Linux-2.6.12-rc2 |
556 557 |
do { |
b3dbb4ecd [PATCH] kallsyms:... |
558 559 560 561 562 563 564 565 |
*p2 = idx; p2++; size -= (p2 - p1); memmove(p2, p2 + 1, size); p1 = p2; len--; if (size < 2) break; |
1da177e4c Linux-2.6.12-rc2 |
566 |
/* find the token on the symbol */ |
7c5d249ad kallsyms: remove ... |
567 |
p2 = find_token(p1, size, str); |
1da177e4c Linux-2.6.12-rc2 |
568 |
|
b3dbb4ecd [PATCH] kallsyms:... |
569 |
} while (p2); |
1da177e4c Linux-2.6.12-rc2 |
570 |
|
8d6052699 scripts/kallsyms:... |
571 |
table[i]->len = len; |
1da177e4c Linux-2.6.12-rc2 |
572 |
|
b3dbb4ecd [PATCH] kallsyms:... |
573 |
/* increase the counts for this symbol's new tokens */ |
8d6052699 scripts/kallsyms:... |
574 |
learn_symbol(table[i]->sym, len); |
1da177e4c Linux-2.6.12-rc2 |
575 576 577 578 |
} } /* search the token with the maximum profit */ |
b3dbb4ecd [PATCH] kallsyms:... |
579 |
static int find_best_token(void) |
1da177e4c Linux-2.6.12-rc2 |
580 |
{ |
b3dbb4ecd [PATCH] kallsyms:... |
581 |
int i, best, bestprofit; |
1da177e4c Linux-2.6.12-rc2 |
582 583 |
bestprofit=-10000; |
b3dbb4ecd [PATCH] kallsyms:... |
584 |
best = 0; |
1da177e4c Linux-2.6.12-rc2 |
585 |
|
b3dbb4ecd [PATCH] kallsyms:... |
586 587 588 589 |
for (i = 0; i < 0x10000; i++) { if (token_profit[i] > bestprofit) { best = i; bestprofit = token_profit[i]; |
1da177e4c Linux-2.6.12-rc2 |
590 |
} |
1da177e4c Linux-2.6.12-rc2 |
591 |
} |
1da177e4c Linux-2.6.12-rc2 |
592 593 594 595 596 597 |
return best; } /* this is the core of the algorithm: calculate the "best" table */ static void optimize_result(void) { |
b3dbb4ecd [PATCH] kallsyms:... |
598 |
int i, best; |
1da177e4c Linux-2.6.12-rc2 |
599 600 601 602 603 604 605 606 |
/* using the '\0' symbol last allows compress_symbols to use standard * fast string functions */ for (i = 255; i >= 0; i--) { /* if this table slot is empty (it is not used by an actual * original char code */ if (!best_table_len[i]) { |
cbf7a90e3 kbuild/kallsyms: ... |
607 |
/* find the token with the best profit value */ |
1da177e4c Linux-2.6.12-rc2 |
608 |
best = find_best_token(); |
e0a04b11e scripts/kallsyms.... |
609 610 |
if (token_profit[best] == 0) break; |
1da177e4c Linux-2.6.12-rc2 |
611 612 |
/* place it in the "best" table */ |
b3dbb4ecd [PATCH] kallsyms:... |
613 614 615 |
best_table_len[i] = 2; best_table[i][0] = best & 0xFF; best_table[i][1] = (best >> 8) & 0xFF; |
1da177e4c Linux-2.6.12-rc2 |
616 617 |
/* replace this token in all the valid symbols */ |
b3dbb4ecd [PATCH] kallsyms:... |
618 |
compress_symbols(best_table[i], i); |
1da177e4c Linux-2.6.12-rc2 |
619 620 621 622 623 624 625 |
} } } /* start by placing the symbols that are actually used on the table */ static void insert_real_symbols_in_table(void) { |
b3dbb4ecd [PATCH] kallsyms:... |
626 |
unsigned int i, j, c; |
1da177e4c Linux-2.6.12-rc2 |
627 |
|
b3dbb4ecd [PATCH] kallsyms:... |
628 |
for (i = 0; i < table_cnt; i++) { |
8d6052699 scripts/kallsyms:... |
629 630 |
for (j = 0; j < table[i]->len; j++) { c = table[i]->sym[j]; |
b3dbb4ecd [PATCH] kallsyms:... |
631 632 |
best_table[c][0]=c; best_table_len[c]=1; |
1da177e4c Linux-2.6.12-rc2 |
633 634 635 636 637 638 |
} } } static void optimize_token_table(void) { |
1da177e4c Linux-2.6.12-rc2 |
639 640 641 642 643 644 |
build_initial_tok_table(); insert_real_symbols_in_table(); optimize_result(); } |
b478b782e kallsyms, tracing... |
645 646 647 |
/* guess for "linker script provide" symbol */ static int may_be_linker_script_provide_symbol(const struct sym_entry *se) { |
29e55ad3d scripts/kallsyms:... |
648 |
const char *symbol = sym_name(se); |
b478b782e kallsyms, tracing... |
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 |
int len = se->len - 1; if (len < 8) return 0; if (symbol[0] != '_' || symbol[1] != '_') return 0; /* __start_XXXXX */ if (!memcmp(symbol + 2, "start_", 6)) return 1; /* __stop_XXXXX */ if (!memcmp(symbol + 2, "stop_", 5)) return 1; /* __end_XXXXX */ if (!memcmp(symbol + 2, "end_", 4)) return 1; /* __XXXXX_start */ if (!memcmp(symbol + len - 6, "_start", 6)) return 1; /* __XXXXX_end */ if (!memcmp(symbol + len - 4, "_end", 4)) return 1; return 0; } |
f2df3f65d kallsyms should p... |
679 680 |
static int compare_symbols(const void *a, const void *b) { |
8d6052699 scripts/kallsyms:... |
681 682 |
const struct sym_entry *sa = *(const struct sym_entry **)a; const struct sym_entry *sb = *(const struct sym_entry **)b; |
f2df3f65d kallsyms should p... |
683 |
int wa, wb; |
f2df3f65d kallsyms should p... |
684 685 686 687 688 689 690 691 692 693 694 |
/* sort by address first */ if (sa->addr > sb->addr) return 1; if (sa->addr < sb->addr) return -1; /* sort by "weakness" type */ wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W'); wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); if (wa != wb) return wa - wb; |
b478b782e kallsyms, tracing... |
695 696 697 698 699 700 701 |
/* sort by "linker script provide" type */ wa = may_be_linker_script_provide_symbol(sa); wb = may_be_linker_script_provide_symbol(sb); if (wa != wb) return wa - wb; /* sort by the number of prefix underscores */ |
aa9152450 scripts/kallsyms:... |
702 703 |
wa = strspn(sym_name(sa), "_"); wb = strspn(sym_name(sb), "_"); |
b478b782e kallsyms, tracing... |
704 705 |
if (wa != wb) return wa - wb; |
f2df3f65d kallsyms should p... |
706 707 708 709 710 711 |
/* sort by initial order, so that other symbols are left undisturbed */ return sa->start_pos - sb->start_pos; } static void sort_symbols(void) { |
8d6052699 scripts/kallsyms:... |
712 |
qsort(table, table_cnt, sizeof(table[0]), compare_symbols); |
f2df3f65d kallsyms should p... |
713 |
} |
1da177e4c Linux-2.6.12-rc2 |
714 |
|
c6bda7c98 kallsyms: fix per... |
715 716 717 718 719 |
static void make_percpus_absolute(void) { unsigned int i; for (i = 0; i < table_cnt; i++) |
8d6052699 scripts/kallsyms:... |
720 |
if (symbol_in_range(table[i], &percpu_range, 1)) { |
8c996940b kallsyms: don't o... |
721 722 723 724 725 |
/* * Keep the 'A' override for percpu symbols to * ensure consistent behavior compared to older * versions of this tool. */ |
8d6052699 scripts/kallsyms:... |
726 727 |
table[i]->sym[0] = 'A'; table[i]->percpu_absolute = 1; |
8c996940b kallsyms: don't o... |
728 |
} |
c6bda7c98 kallsyms: fix per... |
729 |
} |
2213e9a66 kallsyms: add sup... |
730 731 732 733 |
/* find the minimum non-absolute symbol address */ static void record_relative_base(void) { unsigned int i; |
2213e9a66 kallsyms: add sup... |
734 |
for (i = 0; i < table_cnt; i++) |
8d6052699 scripts/kallsyms:... |
735 |
if (!symbol_absolute(table[i])) { |
f34ea0291 scripts/kallsyms:... |
736 737 738 739 |
/* * The table is sorted by address. * Take the first non-absolute symbol value. */ |
8d6052699 scripts/kallsyms:... |
740 |
relative_base = table[i]->addr; |
f34ea0291 scripts/kallsyms:... |
741 742 |
return; } |
2213e9a66 kallsyms: add sup... |
743 |
} |
b3dbb4ecd [PATCH] kallsyms:... |
744 |
int main(int argc, char **argv) |
1da177e4c Linux-2.6.12-rc2 |
745 |
{ |
41f11a4fa [PATCH] kallsyms ... |
746 747 748 749 750 |
if (argc >= 2) { int i; for (i = 1; i < argc; i++) { if(strcmp(argv[i], "--all-symbols") == 0) all_symbols = 1; |
c6bda7c98 kallsyms: fix per... |
751 752 |
else if (strcmp(argv[i], "--absolute-percpu") == 0) absolute_percpu = 1; |
534c9f2ec kallsyms: remove ... |
753 |
else if (strcmp(argv[i], "--base-relative") == 0) |
2213e9a66 kallsyms: add sup... |
754 755 |
base_relative = 1; else |
41f11a4fa [PATCH] kallsyms ... |
756 757 758 |
usage(); } } else if (argc != 1) |
1da177e4c Linux-2.6.12-rc2 |
759 760 761 |
usage(); read_map(stdin); |
5e5c4fa78 scripts/kallsyms:... |
762 |
shrink_table(); |
c6bda7c98 kallsyms: fix per... |
763 764 |
if (absolute_percpu) make_percpus_absolute(); |
f34ea0291 scripts/kallsyms:... |
765 |
sort_symbols(); |
2213e9a66 kallsyms: add sup... |
766 767 |
if (base_relative) record_relative_base(); |
2ea038917 Revert "kbuild: s... |
768 |
optimize_token_table(); |
1da177e4c Linux-2.6.12-rc2 |
769 770 771 772 |
write_src(); return 0; } |