Blame view

scripts/kallsyms.c 12 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  /* 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
   *
   * ChangeLog:
   *
   * (25/Aug/2004) Paulo Marques <pmarques@grupopie.com>
   *      Changed the compression method from stem compression to "table lookup"
   *      compression
   *
   *      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%.
   *
   */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
26
  #define _GNU_SOURCE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <ctype.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  #define KSYM_NAME_LEN		127
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
  
  struct sym_entry {
  	unsigned long long addr;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
35
  	unsigned int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
  	unsigned char *sym;
  };
  
  
  static struct sym_entry *table;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
41
  static unsigned int table_size, table_cnt;
075d6eb16   David Woodhouse   [PATCH] ppc32: pl...
42
  static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  static int all_symbols = 0;
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
44
  static char symbol_prefix_char = '\0';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
46
  int token_profit[0x10000];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
  
  /* the table that holds the result of the compression */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
49
  unsigned char best_table[256][2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  unsigned char best_table_len[256];
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
51
  static void usage(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  {
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
53
54
  	fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
  	exit(1);
  }
  
  /*
   * This ignores the intensely annoying "mapping symbols" found
   * in ARM ELF files: $a, $t and $d.
   */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
62
  static inline int is_arm_mapping_symbol(const char *str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
  {
  	return str[0] == '$' && strchr("atd", str[1])
  	       && (str[2] == '\0' || str[2] == '.');
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
67
  static int read_symbol(FILE *in, struct sym_entry *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
  {
  	char str[500];
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
70
  	char *sym, stype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  	int rc;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
72
73
  	rc = fscanf(in, "%llx %c %499s
  ", &s->addr, &stype, str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
78
79
80
  	if (rc != 3) {
  		if (rc != EOF) {
  			/* skip line */
  			fgets(str, 500, in);
  		}
  		return -1;
  	}
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
81
82
83
84
  	sym = str;
  	/* skip prefix char */
  	if (symbol_prefix_char && str[0] == symbol_prefix_char)
  		sym++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  	/* Ignore most absolute/undefined (?) symbols. */
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
86
  	if (strcmp(sym, "_stext") == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
  		_stext = s->addr;
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
88
  	else if (strcmp(sym, "_etext") == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  		_etext = s->addr;
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
90
  	else if (strcmp(sym, "_sinittext") == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  		_sinittext = s->addr;
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
92
  	else if (strcmp(sym, "_einittext") == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  		_einittext = s->addr;
075d6eb16   David Woodhouse   [PATCH] ppc32: pl...
94
95
96
97
  	else if (strcmp(sym, "_sextratext") == 0)
  		_sextratext = s->addr;
  	else if (strcmp(sym, "_eextratext") == 0)
  		_eextratext = s->addr;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
98
  	else if (toupper(stype) == 'A')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
  	{
  		/* Keep these useful absolute symbols */
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
101
102
103
104
  		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
105
106
107
  			return -1;
  
  	}
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
108
  	else if (toupper(stype) == 'U' ||
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
109
  		 is_arm_mapping_symbol(sym))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  		return -1;
6f00df24e   Ralf Baechle   [PATCH] Strip loc...
111
112
113
  	/* exclude also MIPS ELF local symbols ($L123 instead of .L123) */
  	else if (str[0] == '$')
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
  
  	/* include the type field in the symbol name, so that it gets
  	 * compressed together */
  	s->len = strlen(str) + 1;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
118
  	s->sym = malloc(s->len + 1);
f1a136e0d   Jesper Juhl   [PATCH] kallsyms:...
119
120
121
122
123
124
  	if (!s->sym) {
  		fprintf(stderr, "kallsyms failure: "
  			"unable to allocate required amount of memory
  ");
  		exit(EXIT_FAILURE);
  	}
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
125
126
  	strcpy((char *)s->sym + 1, str);
  	s->sym[0] = stype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
  
  	return 0;
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
130
  static int symbol_valid(struct sym_entry *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  {
  	/* 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.
  	 */
  	static char *special_symbols[] = {
  		"kallsyms_addresses",
  		"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 };
  	int i;
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
150
151
152
153
154
  	int offset = 1;
  
  	/* skip prefix char */
  	if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char)
  		offset++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
  
  	/* if --all-symbols is not specified, then symbols outside the text
  	 * and inittext sections are discarded */
  	if (!all_symbols) {
  		if ((s->addr < _stext || s->addr > _etext)
075d6eb16   David Woodhouse   [PATCH] ppc32: pl...
160
161
  		    && (s->addr < _sinittext || s->addr > _einittext)
  		    && (s->addr < _sextratext || s->addr > _eextratext))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
  			return 0;
  		/* Corner case.  Discard any symbols with the same value as
075d6eb16   David Woodhouse   [PATCH] ppc32: pl...
164
165
166
167
  		 * _etext _einittext or _eextratext; 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
168
  		 */
61d9cdf2a   J.A. Magallon   [PATCH] kbuild: s...
169
170
171
  		if ((s->addr == _etext && strcmp((char*)s->sym + offset, "_etext")) ||
  		    (s->addr == _einittext && strcmp((char*)s->sym + offset, "_einittext")) ||
  		    (s->addr == _eextratext && strcmp((char*)s->sym + offset, "_eextratext")))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
175
  			return 0;
  	}
  
  	/* Exclude symbols which vary between passes. */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
176
  	if (strstr((char *)s->sym + offset, "_compiled."))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
  		return 0;
  
  	for (i = 0; special_symbols[i]; i++)
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
180
  		if( strcmp((char *)s->sym + offset, special_symbols[i]) == 0 )
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
  			return 0;
  
  	return 1;
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
185
  static void read_map(FILE *in)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
  {
  	while (!feof(in)) {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
188
189
190
  		if (table_cnt >= table_size) {
  			table_size += 10000;
  			table = realloc(table, sizeof(*table) * table_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
194
195
196
  			if (!table) {
  				fprintf(stderr, "out of memory
  ");
  				exit (1);
  			}
  		}
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
197
198
  		if (read_symbol(in, &table[table_cnt]) == 0)
  			table_cnt++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
202
203
  	}
  }
  
  static void output_label(char *label)
  {
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
204
205
206
207
208
209
  	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
210
211
  	printf("\tALGN
  ");
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
212
213
214
215
216
217
  	if (symbol_prefix_char)
  		printf("%c%s:
  ", symbol_prefix_char, label);
  	else
  		printf("%s:
  ", label);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  }
  
  /* 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;
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
246
  static void write_src(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
248
  	unsigned int i, k, off;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  	unsigned int best_idx[256];
  	unsigned int *markers;
  	char buf[KSYM_NAME_LEN+1];
  
  	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
  ");
  
  	printf(".data
  ");
  
  	output_label("kallsyms_addresses");
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
274
275
276
  	for (i = 0; i < table_cnt; i++) {
  		printf("\tPTR\t%#llx
  ", table[i].addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
281
  	}
  	printf("
  ");
  
  	output_label("kallsyms_num_syms");
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
282
283
  	printf("\tPTR\t%d
  ", table_cnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
286
287
288
  	printf("
  ");
  
  	/* table of offset markers, that give the offset in the compressed stream
  	 * every 256 symbols */
f1a136e0d   Jesper Juhl   [PATCH] kallsyms:...
289
290
291
292
293
294
295
  	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
296
297
  
  	output_label("kallsyms_names");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  	off = 0;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
299
300
301
  	for (i = 0; i < table_cnt; i++) {
  		if ((i & 0xFF) == 0)
  			markers[i >> 8] = off;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
307
308
309
  
  		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
310
311
312
313
314
  	}
  	printf("
  ");
  
  	output_label("kallsyms_markers");
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
315
  	for (i = 0; i < ((table_cnt + 255) >> 8); i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
321
322
323
324
325
326
  		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:...
327
  		expand_symbol(best_table[i], best_table_len[i], buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  		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
345
346
347
348
349
350
  /* 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:...
351
  		token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
357
358
359
  }
  
  /* 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:...
360
  		token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
362
  /* remove all the invalid symbols from the table and do the initial token count */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
  static void build_initial_tok_table(void)
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
365
  	unsigned int i, pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
367
368
  	pos = 0;
  	for (i = 0; i < table_cnt; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  		if ( symbol_valid(&table[i]) ) {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
370
371
372
373
  			if (pos != i)
  				table[pos] = table[i];
  			learn_symbol(table[pos].sym, table[pos].len);
  			pos++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  	}
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
376
  	table_cnt = pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
  }
  
  /* replace a given token in all the valid symbols. Use the sampled symbols
   * to update the counts */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
381
  static void compress_symbols(unsigned char *str, int idx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
383
384
  	unsigned int i, len, size;
  	unsigned char *p1, *p2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
386
  	for (i = 0; i < table_cnt; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
  
  		len = table[i].len;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
389
390
391
392
393
394
395
396
397
398
  		p1 = table[i].sym;
  
  		/* find the token on the symbol */
  		p2 = memmem(p1, len, str, 2);
  		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
399
400
  
  		do {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
401
402
403
404
405
406
407
408
  			*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
409
  			/* find the token on the symbol */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
410
  			p2 = memmem(p1, size, str, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411

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

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

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
416
417
  		/* increase the counts for this symbol's new tokens */
  		learn_symbol(table[i].sym, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
  	}
  }
  
  /* search the token with the maximum profit */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
422
  static int find_best_token(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
424
  	int i, best, bestprofit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
  
  	bestprofit=-10000;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
427
  	best = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
429
430
431
432
  	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
433
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
438
439
440
  	return best;
  }
  
  /* this is the core of the algorithm: calculate the "best" table */
  static void optimize_result(void)
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
441
  	int i, best;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
447
448
449
450
451
452
453
454
  
  	/* 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();
  
  			/* place it in the "best" table */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
455
456
457
  			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
458
459
  
  			/* replace this token in all the valid symbols */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
460
  			compress_symbols(best_table[i], i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
467
  		}
  	}
  }
  
  /* 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:...
468
  	unsigned int i, j, c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
  
  	memset(best_table, 0, sizeof(best_table));
  	memset(best_table_len, 0, sizeof(best_table_len));
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
472
473
474
475
476
  	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
477
478
479
480
481
482
  		}
  	}
  }
  
  static void optimize_token_table(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
  	build_initial_tok_table();
  
  	insert_real_symbols_in_table();
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
486
  	/* When valid symbol is not registered, exit to error */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
487
  	if (!table_cnt) {
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
488
489
490
491
  		fprintf(stderr, "No valid symbol.
  ");
  		exit(1);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
  	optimize_result();
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
494
  int main(int argc, char **argv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  {
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  	if (argc >= 2) {
  		int i;
  		for (i = 1; i < argc; i++) {
  			if(strcmp(argv[i], "--all-symbols") == 0)
  				all_symbols = 1;
  			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;
  			} else
  				usage();
  		}
  	} else if (argc != 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
514
515
516
517
518
  		usage();
  
  	read_map(stdin);
  	optimize_token_table();
  	write_src();
  
  	return 0;
  }