Blame view
scripts/kallsyms.c
12 KB
1da177e4c 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 [PATCH] kallsyms:... |
26 |
#define _GNU_SOURCE |
1da177e4c Linux-2.6.12-rc2 |
27 28 29 30 |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> |
1da177e4c Linux-2.6.12-rc2 |
31 |
#define KSYM_NAME_LEN 127 |
1da177e4c Linux-2.6.12-rc2 |
32 33 34 |
struct sym_entry { unsigned long long addr; |
b3dbb4ecd [PATCH] kallsyms:... |
35 |
unsigned int len; |
1da177e4c Linux-2.6.12-rc2 |
36 37 38 39 40 |
unsigned char *sym; }; static struct sym_entry *table; |
b3dbb4ecd [PATCH] kallsyms:... |
41 |
static unsigned int table_size, table_cnt; |
075d6eb16 [PATCH] ppc32: pl... |
42 |
static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext; |
1da177e4c Linux-2.6.12-rc2 |
43 |
static int all_symbols = 0; |
41f11a4fa [PATCH] kallsyms ... |
44 |
static char symbol_prefix_char = '\0'; |
1da177e4c Linux-2.6.12-rc2 |
45 |
|
b3dbb4ecd [PATCH] kallsyms:... |
46 |
int token_profit[0x10000]; |
1da177e4c Linux-2.6.12-rc2 |
47 48 |
/* the table that holds the result of the compression */ |
b3dbb4ecd [PATCH] kallsyms:... |
49 |
unsigned char best_table[256][2]; |
1da177e4c Linux-2.6.12-rc2 |
50 |
unsigned char best_table_len[256]; |
b3dbb4ecd [PATCH] kallsyms:... |
51 |
static void usage(void) |
1da177e4c Linux-2.6.12-rc2 |
52 |
{ |
41f11a4fa [PATCH] kallsyms ... |
53 54 |
fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S "); |
1da177e4c 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 [PATCH] kallsyms:... |
62 |
static inline int is_arm_mapping_symbol(const char *str) |
1da177e4c Linux-2.6.12-rc2 |
63 64 65 66 |
{ return str[0] == '$' && strchr("atd", str[1]) && (str[2] == '\0' || str[2] == '.'); } |
b3dbb4ecd [PATCH] kallsyms:... |
67 |
static int read_symbol(FILE *in, struct sym_entry *s) |
1da177e4c Linux-2.6.12-rc2 |
68 69 |
{ char str[500]; |
b3dbb4ecd [PATCH] kallsyms:... |
70 |
char *sym, stype; |
1da177e4c Linux-2.6.12-rc2 |
71 |
int rc; |
b3dbb4ecd [PATCH] kallsyms:... |
72 73 |
rc = fscanf(in, "%llx %c %499s ", &s->addr, &stype, str); |
1da177e4c 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 [PATCH] kallsyms ... |
81 82 83 84 |
sym = str; /* skip prefix char */ if (symbol_prefix_char && str[0] == symbol_prefix_char) sym++; |
1da177e4c Linux-2.6.12-rc2 |
85 |
/* Ignore most absolute/undefined (?) symbols. */ |
41f11a4fa [PATCH] kallsyms ... |
86 |
if (strcmp(sym, "_stext") == 0) |
1da177e4c Linux-2.6.12-rc2 |
87 |
_stext = s->addr; |
41f11a4fa [PATCH] kallsyms ... |
88 |
else if (strcmp(sym, "_etext") == 0) |
1da177e4c Linux-2.6.12-rc2 |
89 |
_etext = s->addr; |
41f11a4fa [PATCH] kallsyms ... |
90 |
else if (strcmp(sym, "_sinittext") == 0) |
1da177e4c Linux-2.6.12-rc2 |
91 |
_sinittext = s->addr; |
41f11a4fa [PATCH] kallsyms ... |
92 |
else if (strcmp(sym, "_einittext") == 0) |
1da177e4c Linux-2.6.12-rc2 |
93 |
_einittext = s->addr; |
075d6eb16 [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 [PATCH] kallsyms:... |
98 |
else if (toupper(stype) == 'A') |
1da177e4c Linux-2.6.12-rc2 |
99 100 |
{ /* Keep these useful absolute symbols */ |
41f11a4fa [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 Linux-2.6.12-rc2 |
105 106 107 |
return -1; } |
b3dbb4ecd [PATCH] kallsyms:... |
108 |
else if (toupper(stype) == 'U' || |
41f11a4fa [PATCH] kallsyms ... |
109 |
is_arm_mapping_symbol(sym)) |
1da177e4c Linux-2.6.12-rc2 |
110 |
return -1; |
6f00df24e [PATCH] Strip loc... |
111 112 113 |
/* exclude also MIPS ELF local symbols ($L123 instead of .L123) */ else if (str[0] == '$') return -1; |
1da177e4c 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 [PATCH] kallsyms:... |
118 |
s->sym = malloc(s->len + 1); |
f1a136e0d [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 [PATCH] kallsyms:... |
125 126 |
strcpy((char *)s->sym + 1, str); s->sym[0] = stype; |
1da177e4c Linux-2.6.12-rc2 |
127 128 129 |
return 0; } |
b3dbb4ecd [PATCH] kallsyms:... |
130 |
static int symbol_valid(struct sym_entry *s) |
1da177e4c 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 [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 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 [PATCH] ppc32: pl... |
160 161 |
&& (s->addr < _sinittext || s->addr > _einittext) && (s->addr < _sextratext || s->addr > _eextratext)) |
1da177e4c Linux-2.6.12-rc2 |
162 163 |
return 0; /* Corner case. Discard any symbols with the same value as |
075d6eb16 [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 Linux-2.6.12-rc2 |
168 |
*/ |
61d9cdf2a [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 Linux-2.6.12-rc2 |
172 173 174 175 |
return 0; } /* Exclude symbols which vary between passes. */ |
b3dbb4ecd [PATCH] kallsyms:... |
176 |
if (strstr((char *)s->sym + offset, "_compiled.")) |
1da177e4c Linux-2.6.12-rc2 |
177 178 179 |
return 0; for (i = 0; special_symbols[i]; i++) |
b3dbb4ecd [PATCH] kallsyms:... |
180 |
if( strcmp((char *)s->sym + offset, special_symbols[i]) == 0 ) |
1da177e4c Linux-2.6.12-rc2 |
181 182 183 184 |
return 0; return 1; } |
b3dbb4ecd [PATCH] kallsyms:... |
185 |
static void read_map(FILE *in) |
1da177e4c Linux-2.6.12-rc2 |
186 187 |
{ while (!feof(in)) { |
b3dbb4ecd [PATCH] kallsyms:... |
188 189 190 |
if (table_cnt >= table_size) { table_size += 10000; table = realloc(table, sizeof(*table) * table_size); |
1da177e4c Linux-2.6.12-rc2 |
191 192 193 194 195 196 |
if (!table) { fprintf(stderr, "out of memory "); exit (1); } } |
b3dbb4ecd [PATCH] kallsyms:... |
197 198 |
if (read_symbol(in, &table[table_cnt]) == 0) table_cnt++; |
1da177e4c Linux-2.6.12-rc2 |
199 200 201 202 203 |
} } static void output_label(char *label) { |
41f11a4fa [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 Linux-2.6.12-rc2 |
210 211 |
printf("\tALGN "); |
41f11a4fa [PATCH] kallsyms ... |
212 213 214 215 216 217 |
if (symbol_prefix_char) printf("%c%s: ", symbol_prefix_char, label); else printf("%s: ", label); |
1da177e4c 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 [PATCH] kallsyms:... |
246 |
static void write_src(void) |
1da177e4c Linux-2.6.12-rc2 |
247 |
{ |
b3dbb4ecd [PATCH] kallsyms:... |
248 |
unsigned int i, k, off; |
1da177e4c 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 [PATCH] kallsyms:... |
274 275 276 |
for (i = 0; i < table_cnt; i++) { printf("\tPTR\t%#llx ", table[i].addr); |
1da177e4c Linux-2.6.12-rc2 |
277 278 279 280 281 |
} printf(" "); output_label("kallsyms_num_syms"); |
b3dbb4ecd [PATCH] kallsyms:... |
282 283 |
printf("\tPTR\t%d ", table_cnt); |
1da177e4c 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 [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 Linux-2.6.12-rc2 |
296 297 |
output_label("kallsyms_names"); |
1da177e4c Linux-2.6.12-rc2 |
298 |
off = 0; |
b3dbb4ecd [PATCH] kallsyms:... |
299 300 301 |
for (i = 0; i < table_cnt; i++) { if ((i & 0xFF) == 0) markers[i >> 8] = off; |
1da177e4c 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 Linux-2.6.12-rc2 |
310 311 312 313 314 |
} printf(" "); output_label("kallsyms_markers"); |
b3dbb4ecd [PATCH] kallsyms:... |
315 |
for (i = 0; i < ((table_cnt + 255) >> 8); i++) |
1da177e4c 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 [PATCH] kallsyms:... |
327 |
expand_symbol(best_table[i], best_table_len[i], buf); |
1da177e4c 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 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 [PATCH] kallsyms:... |
351 |
token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++; |
1da177e4c 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 [PATCH] kallsyms:... |
360 |
token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--; |
1da177e4c Linux-2.6.12-rc2 |
361 |
} |
b3dbb4ecd [PATCH] kallsyms:... |
362 |
/* remove all the invalid symbols from the table and do the initial token count */ |
1da177e4c Linux-2.6.12-rc2 |
363 364 |
static void build_initial_tok_table(void) { |
b3dbb4ecd [PATCH] kallsyms:... |
365 |
unsigned int i, pos; |
1da177e4c Linux-2.6.12-rc2 |
366 |
|
b3dbb4ecd [PATCH] kallsyms:... |
367 368 |
pos = 0; for (i = 0; i < table_cnt; i++) { |
1da177e4c Linux-2.6.12-rc2 |
369 |
if ( symbol_valid(&table[i]) ) { |
b3dbb4ecd [PATCH] kallsyms:... |
370 371 372 373 |
if (pos != i) table[pos] = table[i]; learn_symbol(table[pos].sym, table[pos].len); pos++; |
1da177e4c Linux-2.6.12-rc2 |
374 |
} |
1da177e4c Linux-2.6.12-rc2 |
375 |
} |
b3dbb4ecd [PATCH] kallsyms:... |
376 |
table_cnt = pos; |
1da177e4c 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 [PATCH] kallsyms:... |
381 |
static void compress_symbols(unsigned char *str, int idx) |
1da177e4c Linux-2.6.12-rc2 |
382 |
{ |
b3dbb4ecd [PATCH] kallsyms:... |
383 384 |
unsigned int i, len, size; unsigned char *p1, *p2; |
1da177e4c Linux-2.6.12-rc2 |
385 |
|
b3dbb4ecd [PATCH] kallsyms:... |
386 |
for (i = 0; i < table_cnt; i++) { |
1da177e4c Linux-2.6.12-rc2 |
387 388 |
len = table[i].len; |
b3dbb4ecd [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 Linux-2.6.12-rc2 |
399 400 |
do { |
b3dbb4ecd [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 Linux-2.6.12-rc2 |
409 |
/* find the token on the symbol */ |
b3dbb4ecd [PATCH] kallsyms:... |
410 |
p2 = memmem(p1, size, str, 2); |
1da177e4c Linux-2.6.12-rc2 |
411 |
|
b3dbb4ecd [PATCH] kallsyms:... |
412 |
} while (p2); |
1da177e4c Linux-2.6.12-rc2 |
413 |
|
b3dbb4ecd [PATCH] kallsyms:... |
414 |
table[i].len = len; |
1da177e4c Linux-2.6.12-rc2 |
415 |
|
b3dbb4ecd [PATCH] kallsyms:... |
416 417 |
/* increase the counts for this symbol's new tokens */ learn_symbol(table[i].sym, len); |
1da177e4c Linux-2.6.12-rc2 |
418 419 420 421 |
} } /* search the token with the maximum profit */ |
b3dbb4ecd [PATCH] kallsyms:... |
422 |
static int find_best_token(void) |
1da177e4c Linux-2.6.12-rc2 |
423 |
{ |
b3dbb4ecd [PATCH] kallsyms:... |
424 |
int i, best, bestprofit; |
1da177e4c Linux-2.6.12-rc2 |
425 426 |
bestprofit=-10000; |
b3dbb4ecd [PATCH] kallsyms:... |
427 |
best = 0; |
1da177e4c Linux-2.6.12-rc2 |
428 |
|
b3dbb4ecd [PATCH] kallsyms:... |
429 430 431 432 |
for (i = 0; i < 0x10000; i++) { if (token_profit[i] > bestprofit) { best = i; bestprofit = token_profit[i]; |
1da177e4c Linux-2.6.12-rc2 |
433 |
} |
1da177e4c Linux-2.6.12-rc2 |
434 |
} |
1da177e4c 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 [PATCH] kallsyms:... |
441 |
int i, best; |
1da177e4c 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 [PATCH] kallsyms:... |
455 456 457 |
best_table_len[i] = 2; best_table[i][0] = best & 0xFF; best_table[i][1] = (best >> 8) & 0xFF; |
1da177e4c Linux-2.6.12-rc2 |
458 459 |
/* replace this token in all the valid symbols */ |
b3dbb4ecd [PATCH] kallsyms:... |
460 |
compress_symbols(best_table[i], i); |
1da177e4c 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 [PATCH] kallsyms:... |
468 |
unsigned int i, j, c; |
1da177e4c 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 [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 Linux-2.6.12-rc2 |
477 478 479 480 481 482 |
} } } static void optimize_token_table(void) { |
1da177e4c Linux-2.6.12-rc2 |
483 484 485 |
build_initial_tok_table(); insert_real_symbols_in_table(); |
41f11a4fa [PATCH] kallsyms ... |
486 |
/* When valid symbol is not registered, exit to error */ |
b3dbb4ecd [PATCH] kallsyms:... |
487 |
if (!table_cnt) { |
41f11a4fa [PATCH] kallsyms ... |
488 489 490 491 |
fprintf(stderr, "No valid symbol. "); exit(1); } |
1da177e4c Linux-2.6.12-rc2 |
492 493 |
optimize_result(); } |
b3dbb4ecd [PATCH] kallsyms:... |
494 |
int main(int argc, char **argv) |
1da177e4c Linux-2.6.12-rc2 |
495 |
{ |
41f11a4fa [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 Linux-2.6.12-rc2 |
511 512 513 514 515 516 517 518 |
usage(); read_map(stdin); optimize_token_table(); write_src(); return 0; } |