Blame view

scripts/kallsyms.c 16.5 KB
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *      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%.
   *
   */
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <ctype.h>
17b1f0de7   Mike Frysinger   kallsyms: general...
25
26
27
  #ifndef ARRAY_SIZE
  #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
  #endif
9281acea6   Tejun Heo   kallsyms: make KS...
28
  #define KSYM_NAME_LEN		128
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
  struct sym_entry {
  	unsigned long long addr;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
32
  	unsigned int len;
f2df3f65d   Paulo Marques   kallsyms should p...
33
  	unsigned int start_pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
  	unsigned char *sym;
  };
78eb71594   Kees Cook   kallsyms: general...
36
37
  struct addr_range {
  	const char *start_sym, *end_sym;
17b1f0de7   Mike Frysinger   kallsyms: general...
38
39
40
41
  	unsigned long long start, end;
  };
  
  static unsigned long long _text;
78eb71594   Kees Cook   kallsyms: general...
42
  static struct addr_range text_ranges[] = {
17b1f0de7   Mike Frysinger   kallsyms: general...
43
44
45
46
47
48
49
  	{ "_stext",     "_etext"     },
  	{ "_sinittext", "_einittext" },
  	{ "_stext_l1",  "_etext_l1"  },	/* Blackfin on-chip L1 inst SRAM */
  	{ "_stext_l2",  "_etext_l2"  },	/* Blackfin on-chip L2 SRAM */
  };
  #define text_range_text     (&text_ranges[0])
  #define text_range_inittext (&text_ranges[1])
c6bda7c98   Rusty Russell   kallsyms: fix per...
50
51
52
  static struct addr_range percpu_range = {
  	"__per_cpu_start", "__per_cpu_end", -1ULL, 0
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  static struct sym_entry *table;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
54
  static unsigned int table_size, table_cnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  static int all_symbols = 0;
c6bda7c98   Rusty Russell   kallsyms: fix per...
56
  static int absolute_percpu = 0;
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
57
  static char symbol_prefix_char = '\0';
f6537f2f0   Ming Lei   scripts/kallsyms:...
58
  static unsigned long long kernel_start_addr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
60
  int token_profit[0x10000];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  
  /* the table that holds the result of the compression */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
63
  unsigned char best_table[256][2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  unsigned char best_table_len[256];
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
65
  static void usage(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  {
f6537f2f0   Ming Lei   scripts/kallsyms:...
67
68
69
70
71
  	fprintf(stderr, "Usage: kallsyms [--all-symbols] "
  			"[--symbol-prefix=<prefix char>] "
  			"[--page-offset=<CONFIG_PAGE_OFFSET>] "
  			"< in.map > out.S
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
78
  	exit(1);
  }
  
  /*
   * This ignores the intensely annoying "mapping symbols" found
   * in ARM ELF files: $a, $t and $d.
   */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
79
  static inline int is_arm_mapping_symbol(const char *str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
  {
  	return str[0] == '$' && strchr("atd", str[1])
  	       && (str[2] == '\0' || str[2] == '.');
  }
78eb71594   Kees Cook   kallsyms: general...
84
85
  static int check_symbol_range(const char *sym, unsigned long long addr,
  			      struct addr_range *ranges, int entries)
17b1f0de7   Mike Frysinger   kallsyms: general...
86
87
  {
  	size_t i;
78eb71594   Kees Cook   kallsyms: general...
88
  	struct addr_range *ar;
17b1f0de7   Mike Frysinger   kallsyms: general...
89

78eb71594   Kees Cook   kallsyms: general...
90
91
  	for (i = 0; i < entries; ++i) {
  		ar = &ranges[i];
17b1f0de7   Mike Frysinger   kallsyms: general...
92

78eb71594   Kees Cook   kallsyms: general...
93
94
  		if (strcmp(sym, ar->start_sym) == 0) {
  			ar->start = addr;
17b1f0de7   Mike Frysinger   kallsyms: general...
95
  			return 0;
78eb71594   Kees Cook   kallsyms: general...
96
97
  		} else if (strcmp(sym, ar->end_sym) == 0) {
  			ar->end = addr;
17b1f0de7   Mike Frysinger   kallsyms: general...
98
99
100
101
102
103
  			return 0;
  		}
  	}
  
  	return 1;
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
104
  static int read_symbol(FILE *in, struct sym_entry *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
  {
  	char str[500];
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
107
  	char *sym, stype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  	int rc;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
109
110
  	rc = fscanf(in, "%llx %c %499s
  ", &s->addr, &stype, str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
  	if (rc != 3) {
ef894870c   Jean Sacren   scripts/kallsyms:...
112
113
114
  		if (rc != EOF && fgets(str, 500, in) == NULL)
  			fprintf(stderr, "Read error or end of file.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
  		return -1;
  	}
f3462aa95   Andi Kleen   Kbuild: Handle lo...
117
  	if (strlen(str) > KSYM_NAME_LEN) {
6f62259b1   Fabio Estevam   scripts: kallsyms...
118
119
  		fprintf(stderr, "Symbol %s too long for kallsyms (%zu vs %d).
  "
f3462aa95   Andi Kleen   Kbuild: Handle lo...
120
121
122
123
124
                                  "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c
  ",
  			str, strlen(str), KSYM_NAME_LEN);
  		return -1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125

41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
126
127
128
129
  	sym = str;
  	/* skip prefix char */
  	if (symbol_prefix_char && str[0] == symbol_prefix_char)
  		sym++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  	/* Ignore most absolute/undefined (?) symbols. */
fd593d127   Eric W. Biederman   [PATCH] relocatab...
131
132
  	if (strcmp(sym, "_text") == 0)
  		_text = s->addr;
78eb71594   Kees Cook   kallsyms: general...
133
134
  	else if (check_symbol_range(sym, s->addr, text_ranges,
  				    ARRAY_SIZE(text_ranges)) == 0)
17b1f0de7   Mike Frysinger   kallsyms: general...
135
  		/* nothing to do */;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
136
  	else if (toupper(stype) == 'A')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
  	{
  		/* Keep these useful absolute symbols */
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
139
140
141
142
  		if (strcmp(sym, "__kernel_syscall_via_break") &&
  		    strcmp(sym, "__kernel_syscall_via_epc") &&
  		    strcmp(sym, "__kernel_sigtramp") &&
  		    strcmp(sym, "__gp"))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
  			return -1;
  
  	}
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
146
  	else if (toupper(stype) == 'U' ||
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
147
  		 is_arm_mapping_symbol(sym))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  		return -1;
6f00df24e   Ralf Baechle   [PATCH] Strip loc...
149
150
151
  	/* exclude also MIPS ELF local symbols ($L123 instead of .L123) */
  	else if (str[0] == '$')
  		return -1;
aab34ac85   Sam Ravnborg   kbuild: filter aw...
152
153
154
  	/* exclude debugging symbols */
  	else if (stype == 'N')
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
  
  	/* include the type field in the symbol name, so that it gets
  	 * compressed together */
  	s->len = strlen(str) + 1;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
159
  	s->sym = malloc(s->len + 1);
f1a136e0d   Jesper Juhl   [PATCH] kallsyms:...
160
161
162
163
164
165
  	if (!s->sym) {
  		fprintf(stderr, "kallsyms failure: "
  			"unable to allocate required amount of memory
  ");
  		exit(EXIT_FAILURE);
  	}
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
166
167
  	strcpy((char *)s->sym + 1, str);
  	s->sym[0] = stype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168

c6bda7c98   Rusty Russell   kallsyms: fix per...
169
170
  	/* Record if we've found __per_cpu_start/end. */
  	check_symbol_range(sym, s->addr, &percpu_range, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
  	return 0;
  }
78eb71594   Kees Cook   kallsyms: general...
173
174
  static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges,
  			   int entries)
17b1f0de7   Mike Frysinger   kallsyms: general...
175
176
  {
  	size_t i;
78eb71594   Kees Cook   kallsyms: general...
177
  	struct addr_range *ar;
17b1f0de7   Mike Frysinger   kallsyms: general...
178

78eb71594   Kees Cook   kallsyms: general...
179
180
  	for (i = 0; i < entries; ++i) {
  		ar = &ranges[i];
17b1f0de7   Mike Frysinger   kallsyms: general...
181

78eb71594   Kees Cook   kallsyms: general...
182
  		if (s->addr >= ar->start && s->addr <= ar->end)
ac6ca5c86   Mike Frysinger   kallsyms: fix inv...
183
  			return 1;
17b1f0de7   Mike Frysinger   kallsyms: general...
184
  	}
ac6ca5c86   Mike Frysinger   kallsyms: fix inv...
185
  	return 0;
17b1f0de7   Mike Frysinger   kallsyms: general...
186
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
187
  static int symbol_valid(struct sym_entry *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
  {
  	/* Symbols which vary between passes.  Passes 1 and 2 must have
2ea038917   Sam Ravnborg   Revert "kbuild: s...
190
191
192
  	 * 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.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  	 */
  	static char *special_symbols[] = {
2ea038917   Sam Ravnborg   Revert "kbuild: s...
195
196
197
198
199
200
  		"kallsyms_addresses",
  		"kallsyms_num_syms",
  		"kallsyms_names",
  		"kallsyms_markers",
  		"kallsyms_token_table",
  		"kallsyms_token_index",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
204
205
  	/* Exclude linker generated symbols which vary between passes */
  		"_SDA_BASE_",		/* ppc */
  		"_SDA2_BASE_",		/* ppc */
  		NULL };
  	int i;
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
206
  	int offset = 1;
f6537f2f0   Ming Lei   scripts/kallsyms:...
207
208
  	if (s->addr < kernel_start_addr)
  		return 0;
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
209
210
211
  	/* skip prefix char */
  	if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char)
  		offset++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
  
  	/* if --all-symbols is not specified, then symbols outside the text
  	 * and inittext sections are discarded */
  	if (!all_symbols) {
78eb71594   Kees Cook   kallsyms: general...
216
217
  		if (symbol_in_range(s, text_ranges,
  				    ARRAY_SIZE(text_ranges)) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
  			return 0;
  		/* Corner case.  Discard any symbols with the same value as
a3b81113f   Robin Getz   remove support fo...
220
221
222
223
  		 * _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   Linus Torvalds   Linux-2.6.12-rc2
224
  		 */
17b1f0de7   Mike Frysinger   kallsyms: general...
225
  		if ((s->addr == text_range_text->end &&
78eb71594   Kees Cook   kallsyms: general...
226
227
  				strcmp((char *)s->sym + offset,
  				       text_range_text->end_sym)) ||
17b1f0de7   Mike Frysinger   kallsyms: general...
228
  		    (s->addr == text_range_inittext->end &&
78eb71594   Kees Cook   kallsyms: general...
229
230
  				strcmp((char *)s->sym + offset,
  				       text_range_inittext->end_sym)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
234
  			return 0;
  	}
  
  	/* Exclude symbols which vary between passes. */
2ea038917   Sam Ravnborg   Revert "kbuild: s...
235
  	if (strstr((char *)s->sym + offset, "_compiled."))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
  		return 0;
  
  	for (i = 0; special_symbols[i]; i++)
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
239
  		if( strcmp((char *)s->sym + offset, special_symbols[i]) == 0 )
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
243
  			return 0;
  
  	return 1;
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
244
  static void read_map(FILE *in)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
  {
  	while (!feof(in)) {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
247
248
249
  		if (table_cnt >= table_size) {
  			table_size += 10000;
  			table = realloc(table, sizeof(*table) * table_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
  			if (!table) {
  				fprintf(stderr, "out of memory
  ");
  				exit (1);
  			}
  		}
f2df3f65d   Paulo Marques   kallsyms should p...
256
257
  		if (read_symbol(in, &table[table_cnt]) == 0) {
  			table[table_cnt].start_pos = table_cnt;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
258
  			table_cnt++;
f2df3f65d   Paulo Marques   kallsyms should p...
259
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
263
264
  	}
  }
  
  static void output_label(char *label)
  {
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
265
266
267
268
269
270
  	if (symbol_prefix_char)
  		printf(".globl %c%s
  ", symbol_prefix_char, label);
  	else
  		printf(".globl %s
  ", label);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
  	printf("\tALGN
  ");
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
273
274
275
276
277
278
  	if (symbol_prefix_char)
  		printf("%c%s:
  ", symbol_prefix_char, label);
  	else
  		printf("%s:
  ", label);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
  }
  
  /* uncompress a compressed symbol. When this function is called, the best table
   * might still be compressed itself, so the function needs to be recursive */
  static int expand_symbol(unsigned char *data, int len, char *result)
  {
  	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;
  }
78eb71594   Kees Cook   kallsyms: general...
307
308
309
310
  static int symbol_absolute(struct sym_entry *s)
  {
  	return toupper(s->sym[0]) == 'A';
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
311
  static void write_src(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
313
  	unsigned int i, k, off;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
  	unsigned int best_idx[256];
  	unsigned int *markers;
9281acea6   Tejun Heo   kallsyms: make KS...
316
  	char buf[KSYM_NAME_LEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
  
  	printf("#include <asm/types.h>
  ");
  	printf("#if BITS_PER_LONG == 64
  ");
  	printf("#define PTR .quad
  ");
  	printf("#define ALGN .align 8
  ");
  	printf("#else
  ");
  	printf("#define PTR .long
  ");
  	printf("#define ALGN .align 4
  ");
  	printf("#endif
  ");
aad094701   Jan Beulich   [PATCH] move kall...
334
335
  	printf("\t.section .rodata, \"a\"
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336

fd593d127   Eric W. Biederman   [PATCH] relocatab...
337
338
339
340
341
342
343
  	/* 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.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  	output_label("kallsyms_addresses");
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
345
  	for (i = 0; i < table_cnt; i++) {
78eb71594   Kees Cook   kallsyms: general...
346
  		if (!symbol_absolute(&table[i])) {
2c22d8baa   Vivek Goyal   [PATCH] relocatab...
347
348
349
350
351
  			if (_text <= table[i].addr)
  				printf("\tPTR\t_text + %#llx
  ",
  					table[i].addr - _text);
  			else
2930ffc75   Andrew Morton   revert "kallsyms:...
352
353
354
  				printf("\tPTR\t_text - %#llx
  ",
  					_text - table[i].addr);
fd593d127   Eric W. Biederman   [PATCH] relocatab...
355
356
357
358
  		} else {
  			printf("\tPTR\t%#llx
  ", table[i].addr);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
363
  	}
  	printf("
  ");
  
  	output_label("kallsyms_num_syms");
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
364
365
  	printf("\tPTR\t%d
  ", table_cnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
370
  	printf("
  ");
  
  	/* table of offset markers, that give the offset in the compressed stream
  	 * every 256 symbols */
f1a136e0d   Jesper Juhl   [PATCH] kallsyms:...
371
372
373
374
375
376
377
  	markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
  	if (!markers) {
  		fprintf(stderr, "kallsyms failure: "
  			"unable to allocate required memory
  ");
  		exit(EXIT_FAILURE);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
  
  	output_label("kallsyms_names");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  	off = 0;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
381
382
383
  	for (i = 0; i < table_cnt; i++) {
  		if ((i & 0xFF) == 0)
  			markers[i >> 8] = off;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
388
389
390
391
  
  		printf("\t.byte 0x%02x", table[i].len);
  		for (k = 0; k < table[i].len; k++)
  			printf(", 0x%02x", table[i].sym[k]);
  		printf("
  ");
  
  		off += table[i].len + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
  	}
  	printf("
  ");
  
  	output_label("kallsyms_markers");
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
397
  	for (i = 0; i < ((table_cnt + 255) >> 8); i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
401
402
403
404
405
406
407
408
  		printf("\tPTR\t%d
  ", markers[i]);
  	printf("
  ");
  
  	free(markers);
  
  	output_label("kallsyms_token_table");
  	off = 0;
  	for (i = 0; i < 256; i++) {
  		best_idx[i] = off;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
409
  		expand_symbol(best_table[i], best_table_len[i], buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  		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   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
430
431
432
  /* count all the possible tokens in a symbol */
  static void learn_symbol(unsigned char *symbol, int len)
  {
  	int i;
  
  	for (i = 0; i < len - 1; i++)
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
433
  		token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
437
438
439
440
441
  }
  
  /* decrease the count for all the possible tokens in a symbol */
  static void forget_symbol(unsigned char *symbol, int len)
  {
  	int i;
  
  	for (i = 0; i < len - 1; i++)
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
442
  		token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
444
  /* remove all the invalid symbols from the table and do the initial token count */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
  static void build_initial_tok_table(void)
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
447
  	unsigned int i, pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
449
450
  	pos = 0;
  	for (i = 0; i < table_cnt; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
  		if ( symbol_valid(&table[i]) ) {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
452
453
454
455
  			if (pos != i)
  				table[pos] = table[i];
  			learn_symbol(table[pos].sym, table[pos].len);
  			pos++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  	}
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
458
  	table_cnt = pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  }
7c5d249ad   Paulo Marques   kallsyms: remove ...
460
461
462
463
464
465
466
467
468
469
  static void *find_token(unsigned char *str, int len, unsigned char *token)
  {
  	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   Linus Torvalds   Linux-2.6.12-rc2
470
471
  /* replace a given token in all the valid symbols. Use the sampled symbols
   * to update the counts */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
472
  static void compress_symbols(unsigned char *str, int idx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
474
475
  	unsigned int i, len, size;
  	unsigned char *p1, *p2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
477
  	for (i = 0; i < table_cnt; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
  
  		len = table[i].len;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
480
481
482
  		p1 = table[i].sym;
  
  		/* find the token on the symbol */
7c5d249ad   Paulo Marques   kallsyms: remove ...
483
  		p2 = find_token(p1, len, str);
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
484
485
486
487
488
489
  		if (!p2) continue;
  
  		/* decrease the counts for this symbol's tokens */
  		forget_symbol(table[i].sym, len);
  
  		size = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
  
  		do {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
492
493
494
495
496
497
498
499
  			*p2 = idx;
  			p2++;
  			size -= (p2 - p1);
  			memmove(p2, p2 + 1, size);
  			p1 = p2;
  			len--;
  
  			if (size < 2) break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  			/* find the token on the symbol */
7c5d249ad   Paulo Marques   kallsyms: remove ...
501
  			p2 = find_token(p1, size, str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
503
  		} while (p2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
505
  		table[i].len = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
507
508
  		/* increase the counts for this symbol's new tokens */
  		learn_symbol(table[i].sym, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
512
  	}
  }
  
  /* search the token with the maximum profit */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
513
  static int find_best_token(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
515
  	int i, best, bestprofit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
  
  	bestprofit=-10000;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
518
  	best = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
520
521
522
523
  	for (i = 0; i < 0x10000; i++) {
  		if (token_profit[i] > bestprofit) {
  			best = i;
  			bestprofit = token_profit[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
530
531
  	return best;
  }
  
  /* this is the core of the algorithm: calculate the "best" table */
  static void optimize_result(void)
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
532
  	int i, best;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
537
538
539
540
541
542
543
  
  	/* 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]) {
  
  			/* find the token with the breates profit value */
  			best = find_best_token();
e0a04b11e   Xiaochen Wang   scripts/kallsyms....
544
545
  			if (token_profit[best] == 0)
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
  
  			/* place it in the "best" table */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
548
549
550
  			best_table_len[i] = 2;
  			best_table[i][0] = best & 0xFF;
  			best_table[i][1] = (best >> 8) & 0xFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
  
  			/* replace this token in all the valid symbols */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
553
  			compress_symbols(best_table[i], i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
555
556
557
558
559
560
  		}
  	}
  }
  
  /* start by placing the symbols that are actually used on the table */
  static void insert_real_symbols_in_table(void)
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
561
  	unsigned int i, j, c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
  
  	memset(best_table, 0, sizeof(best_table));
  	memset(best_table_len, 0, sizeof(best_table_len));
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
565
566
567
568
569
  	for (i = 0; i < table_cnt; i++) {
  		for (j = 0; j < table[i].len; j++) {
  			c = table[i].sym[j];
  			best_table[c][0]=c;
  			best_table_len[c]=1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
574
575
  		}
  	}
  }
  
  static void optimize_token_table(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
578
  	build_initial_tok_table();
  
  	insert_real_symbols_in_table();
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
579
  	/* When valid symbol is not registered, exit to error */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
580
  	if (!table_cnt) {
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
581
582
583
584
  		fprintf(stderr, "No valid symbol.
  ");
  		exit(1);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
  	optimize_result();
  }
b478b782e   Lai Jiangshan   kallsyms, tracing...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
  /* guess for "linker script provide" symbol */
  static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
  {
  	const char *symbol = (char *)se->sym + 1;
  	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;
  }
  
  static int prefix_underscores_count(const char *str)
  {
  	const char *tail = str;
a9ece53c4   Paul Mundt   kallsyms: fix seg...
625
  	while (*tail == '_')
b478b782e   Lai Jiangshan   kallsyms, tracing...
626
627
628
629
  		tail++;
  
  	return tail - str;
  }
f2df3f65d   Paulo Marques   kallsyms should p...
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
  static int compare_symbols(const void *a, const void *b)
  {
  	const struct sym_entry *sa;
  	const struct sym_entry *sb;
  	int wa, wb;
  
  	sa = a;
  	sb = b;
  
  	/* 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   Lai Jiangshan   kallsyms, tracing...
650
651
652
653
654
655
656
657
658
659
660
  	/* 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 */
  	wa = prefix_underscores_count((const char *)sa->sym + 1);
  	wb = prefix_underscores_count((const char *)sb->sym + 1);
  	if (wa != wb)
  		return wa - wb;
f2df3f65d   Paulo Marques   kallsyms should p...
661
662
663
664
665
666
667
668
  	/* sort by initial order, so that other symbols are left undisturbed */
  	return sa->start_pos - sb->start_pos;
  }
  
  static void sort_symbols(void)
  {
  	qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669

c6bda7c98   Rusty Russell   kallsyms: fix per...
670
671
672
673
674
675
676
677
  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))
  			table[i].sym[0] = 'A';
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
678
  int main(int argc, char **argv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  {
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
680
681
682
683
684
  	if (argc >= 2) {
  		int i;
  		for (i = 1; i < argc; i++) {
  			if(strcmp(argv[i], "--all-symbols") == 0)
  				all_symbols = 1;
c6bda7c98   Rusty Russell   kallsyms: fix per...
685
686
  			else if (strcmp(argv[i], "--absolute-percpu") == 0)
  				absolute_percpu = 1;
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
687
688
689
690
691
692
  			else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) {
  				char *p = &argv[i][16];
  				/* skip quote */
  				if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
  					p++;
  				symbol_prefix_char = *p;
f6537f2f0   Ming Lei   scripts/kallsyms:...
693
694
695
  			} else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
  				const char *p = &argv[i][14];
  				kernel_start_addr = strtoull(p, NULL, 16);
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
696
697
698
699
  			} else
  				usage();
  		}
  	} else if (argc != 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
  		usage();
  
  	read_map(stdin);
c6bda7c98   Rusty Russell   kallsyms: fix per...
703
704
  	if (absolute_percpu)
  		make_percpus_absolute();
2ea038917   Sam Ravnborg   Revert "kbuild: s...
705
706
  	sort_symbols();
  	optimize_token_table();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
710
  	write_src();
  
  	return 0;
  }