Blame view

scripts/kallsyms.c 17.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
   *      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   Masahiro Yamada   scripts/kallsyms:...
20
  #include <stdbool.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <ctype.h>
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
25
  #include <limits.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26

17b1f0de7   Mike Frysinger   kallsyms: general...
27
  #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
17b1f0de7   Mike Frysinger   kallsyms: general...
28

9281acea6   Tejun Heo   kallsyms: make KS...
29
  #define KSYM_NAME_LEN		128
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  struct sym_entry {
  	unsigned long long addr;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
33
  	unsigned int len;
f2df3f65d   Paulo Marques   kallsyms should p...
34
  	unsigned int start_pos;
8c996940b   Ard Biesheuvel   kallsyms: don't o...
35
  	unsigned int percpu_absolute;
9d82973e0   Linus Torvalds   gcc-10 warnings: ...
36
  	unsigned char sym[];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  };
78eb71594   Kees Cook   kallsyms: general...
38
39
  struct addr_range {
  	const char *start_sym, *end_sym;
17b1f0de7   Mike Frysinger   kallsyms: general...
40
41
42
43
  	unsigned long long start, end;
  };
  
  static unsigned long long _text;
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
44
  static unsigned long long relative_base;
78eb71594   Kees Cook   kallsyms: general...
45
  static struct addr_range text_ranges[] = {
17b1f0de7   Mike Frysinger   kallsyms: general...
46
47
  	{ "_stext",     "_etext"     },
  	{ "_sinittext", "_einittext" },
17b1f0de7   Mike Frysinger   kallsyms: general...
48
49
50
  };
  #define text_range_text     (&text_ranges[0])
  #define text_range_inittext (&text_ranges[1])
c6bda7c98   Rusty Russell   kallsyms: fix per...
51
52
53
  static struct addr_range percpu_range = {
  	"__per_cpu_start", "__per_cpu_end", -1ULL, 0
  };
8d6052699   Masahiro Yamada   scripts/kallsyms:...
54
  static struct sym_entry **table;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
55
  static unsigned int table_size, table_cnt;
831362fc3   Masahiro Yamada   scripts/kallsyms:...
56
57
58
  static int all_symbols;
  static int absolute_percpu;
  static int base_relative;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59

f43e9daac   Masahiro Yamada   kallsyms: add sta...
60
  static int token_profit[0x10000];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  
  /* the table that holds the result of the compression */
f43e9daac   Masahiro Yamada   kallsyms: add sta...
63
64
  static unsigned char best_table[256][2];
  static unsigned char best_table_len[256];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
66
  static void usage(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  {
f6537f2f0   Ming Lei   scripts/kallsyms:...
68
  	fprintf(stderr, "Usage: kallsyms [--all-symbols] "
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
69
70
  			"[--base-relative] < in.map > out.S
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
  	exit(1);
  }
29e55ad3d   Masahiro Yamada   scripts/kallsyms:...
73
74
75
76
  static char *sym_name(const struct sym_entry *s)
  {
  	return (char *)s->sym + 1;
  }
a41333e06   Masahiro Yamada   scripts/kallsyms:...
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  static bool is_ignored_symbol(const char *name, char type)
  {
  	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
  	};
  
  	static const char * const ignored_prefixes[] = {
97261e1e2   Masahiro Yamada   scripts/kallsyms:...
102
103
  		"$",			/* local symbols for ARM, MIPS, etc. */
  		".LASANPC",		/* s390 kasan local symbols */
a41333e06   Masahiro Yamada   scripts/kallsyms:...
104
105
  		"__crc_",		/* modversions */
  		"__efistub_",		/* arm64 EFI stub namespace */
762171291   David Brazdil   KVM: arm64: Add b...
106
  		"__kvm_nvhe_",		/* arm64 non-VHE KVM namespace */
a41333e06   Masahiro Yamada   scripts/kallsyms:...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  		NULL
  	};
  
  	static const char * const ignored_suffixes[] = {
  		"_from_arm",		/* arm */
  		"_from_thumb",		/* arm */
  		"_veneer",		/* arm */
  		NULL
  	};
  
  	const char * const *p;
  
  	/* Exclude symbols which vary between passes. */
  	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;
  	}
887df76de   Masahiro Yamada   scripts/kallsyms:...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  	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   Masahiro Yamada   scripts/kallsyms:...
148
149
  	return false;
  }
b6233d0de   Masahiro Yamada   scripts/kallsyms:...
150
151
  static void check_symbol_range(const char *sym, unsigned long long addr,
  			       struct addr_range *ranges, int entries)
17b1f0de7   Mike Frysinger   kallsyms: general...
152
153
  {
  	size_t i;
78eb71594   Kees Cook   kallsyms: general...
154
  	struct addr_range *ar;
17b1f0de7   Mike Frysinger   kallsyms: general...
155

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

78eb71594   Kees Cook   kallsyms: general...
159
160
  		if (strcmp(sym, ar->start_sym) == 0) {
  			ar->start = addr;
b6233d0de   Masahiro Yamada   scripts/kallsyms:...
161
  			return;
78eb71594   Kees Cook   kallsyms: general...
162
163
  		} else if (strcmp(sym, ar->end_sym) == 0) {
  			ar->end = addr;
b6233d0de   Masahiro Yamada   scripts/kallsyms:...
164
  			return;
17b1f0de7   Mike Frysinger   kallsyms: general...
165
166
  		}
  	}
17b1f0de7   Mike Frysinger   kallsyms: general...
167
  }
8d6052699   Masahiro Yamada   scripts/kallsyms:...
168
  static struct sym_entry *read_symbol(FILE *in)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  {
be9f6133f   Masahiro Yamada   scripts/kallsyms:...
170
  	char name[500], type;
8d6052699   Masahiro Yamada   scripts/kallsyms:...
171
172
173
  	unsigned long long addr;
  	unsigned int len;
  	struct sym_entry *sym;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  	int rc;
8d6052699   Masahiro Yamada   scripts/kallsyms:...
175
176
  	rc = fscanf(in, "%llx %c %499s
  ", &addr, &type, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  	if (rc != 3) {
be9f6133f   Masahiro Yamada   scripts/kallsyms:...
178
  		if (rc != EOF && fgets(name, 500, in) == NULL)
ef894870c   Jean Sacren   scripts/kallsyms:...
179
180
  			fprintf(stderr, "Read error or end of file.
  ");
8d6052699   Masahiro Yamada   scripts/kallsyms:...
181
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  	}
be9f6133f   Masahiro Yamada   scripts/kallsyms:...
183
  	if (strlen(name) >= KSYM_NAME_LEN) {
6db2983cd   Eugene Loh   kallsyms: Handle ...
184
185
  		fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).
  "
bb66fc671   Masahiro Yamada   kbuild: trivial -...
186
187
  				"Please increase KSYM_NAME_LEN both in kernel and kallsyms.c
  ",
be9f6133f   Masahiro Yamada   scripts/kallsyms:...
188
  			name, strlen(name), KSYM_NAME_LEN);
8d6052699   Masahiro Yamada   scripts/kallsyms:...
189
  		return NULL;
f3462aa95   Andi Kleen   Kbuild: Handle lo...
190
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191

be9f6133f   Masahiro Yamada   scripts/kallsyms:...
192
  	if (strcmp(name, "_text") == 0)
8d6052699   Masahiro Yamada   scripts/kallsyms:...
193
  		_text = addr;
b6233d0de   Masahiro Yamada   scripts/kallsyms:...
194

7883a1433   Mikhail Petrov   scripts/kallsyms:...
195
196
197
  	/* Ignore most absolute/undefined (?) symbols. */
  	if (is_ignored_symbol(name, type))
  		return NULL;
8d6052699   Masahiro Yamada   scripts/kallsyms:...
198
199
  	check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges));
  	check_symbol_range(name, addr, &percpu_range, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
  
  	/* include the type field in the symbol name, so that it gets
  	 * compressed together */
8d6052699   Masahiro Yamada   scripts/kallsyms:...
203
204
  
  	len = strlen(name) + 1;
9d1b38958   Masahiro Yamada   scripts/kallsyms:...
205
  	sym = malloc(sizeof(*sym) + len + 1);
8d6052699   Masahiro Yamada   scripts/kallsyms:...
206
  	if (!sym) {
f1a136e0d   Jesper Juhl   [PATCH] kallsyms:...
207
208
209
210
211
  		fprintf(stderr, "kallsyms failure: "
  			"unable to allocate required amount of memory
  ");
  		exit(EXIT_FAILURE);
  	}
8d6052699   Masahiro Yamada   scripts/kallsyms:...
212
213
214
  	sym->addr = addr;
  	sym->len = len;
  	sym->sym[0] = type;
9d1b38958   Masahiro Yamada   scripts/kallsyms:...
215
  	strcpy(sym_name(sym), name);
8d6052699   Masahiro Yamada   scripts/kallsyms:...
216
  	sym->percpu_absolute = 0;
8c996940b   Ard Biesheuvel   kallsyms: don't o...
217

8d6052699   Masahiro Yamada   scripts/kallsyms:...
218
  	return sym;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  }
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
220
221
  static int symbol_in_range(const struct sym_entry *s,
  			   const struct addr_range *ranges, int entries)
17b1f0de7   Mike Frysinger   kallsyms: general...
222
223
  {
  	size_t i;
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
224
  	const struct addr_range *ar;
17b1f0de7   Mike Frysinger   kallsyms: general...
225

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

78eb71594   Kees Cook   kallsyms: general...
229
  		if (s->addr >= ar->start && s->addr <= ar->end)
ac6ca5c86   Mike Frysinger   kallsyms: fix inv...
230
  			return 1;
17b1f0de7   Mike Frysinger   kallsyms: general...
231
  	}
ac6ca5c86   Mike Frysinger   kallsyms: fix inv...
232
  	return 0;
17b1f0de7   Mike Frysinger   kallsyms: general...
233
  }
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
234
  static int symbol_valid(const struct sym_entry *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  {
29e55ad3d   Masahiro Yamada   scripts/kallsyms:...
236
  	const char *name = sym_name(s);
bd8b22d28   Ard Biesheuvel   Kbuild: kallsyms:...
237

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
  	/* if --all-symbols is not specified, then symbols outside the text
  	 * and inittext sections are discarded */
  	if (!all_symbols) {
78eb71594   Kees Cook   kallsyms: general...
241
242
  		if (symbol_in_range(s, text_ranges,
  				    ARRAY_SIZE(text_ranges)) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
  			return 0;
  		/* Corner case.  Discard any symbols with the same value as
a3b81113f   Robin Getz   remove support fo...
245
246
247
248
  		 * _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
249
  		 */
17b1f0de7   Mike Frysinger   kallsyms: general...
250
  		if ((s->addr == text_range_text->end &&
29e55ad3d   Masahiro Yamada   scripts/kallsyms:...
251
  		     strcmp(name, text_range_text->end_sym)) ||
17b1f0de7   Mike Frysinger   kallsyms: general...
252
  		    (s->addr == text_range_inittext->end &&
29e55ad3d   Masahiro Yamada   scripts/kallsyms:...
253
  		     strcmp(name, text_range_inittext->end_sym)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
  			return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
  	return 1;
  }
5e5c4fa78   Masahiro Yamada   scripts/kallsyms:...
258
259
260
261
262
263
264
  /* 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   Masahiro Yamada   scripts/kallsyms:...
265
  		if (symbol_valid(table[i])) {
5e5c4fa78   Masahiro Yamada   scripts/kallsyms:...
266
267
268
269
  			if (pos != i)
  				table[pos] = table[i];
  			pos++;
  		} else {
8d6052699   Masahiro Yamada   scripts/kallsyms:...
270
  			free(table[i]);
5e5c4fa78   Masahiro Yamada   scripts/kallsyms:...
271
272
273
274
275
276
277
278
279
280
281
  		}
  	}
  	table_cnt = pos;
  
  	/* When valid symbol is not registered, exit to error */
  	if (!table_cnt) {
  		fprintf(stderr, "No valid symbol.
  ");
  		exit(1);
  	}
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
282
  static void read_map(FILE *in)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  {
8d6052699   Masahiro Yamada   scripts/kallsyms:...
284
  	struct sym_entry *sym;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	while (!feof(in)) {
8d6052699   Masahiro Yamada   scripts/kallsyms:...
286
287
288
289
290
  		sym = read_symbol(in);
  		if (!sym)
  			continue;
  
  		sym->start_pos = table_cnt;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
291
292
293
  		if (table_cnt >= table_size) {
  			table_size += 10000;
  			table = realloc(table, sizeof(*table) * table_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
298
299
  			if (!table) {
  				fprintf(stderr, "out of memory
  ");
  				exit (1);
  			}
  		}
8d6052699   Masahiro Yamada   scripts/kallsyms:...
300
301
  
  		table[table_cnt++] = sym;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
  	}
  }
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
304
  static void output_label(const char *label)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  {
534c9f2ec   Masahiro Yamada   kallsyms: remove ...
306
307
  	printf(".globl %s
  ", label);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
  	printf("\tALGN
  ");
534c9f2ec   Masahiro Yamada   kallsyms: remove ...
310
311
  	printf("%s:
  ", label);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  }
fd2ab2f66   Masahiro Yamada   scripts/kallsyms:...
313
314
315
316
317
318
319
320
321
322
  /* 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   Linus Torvalds   Linux-2.6.12-rc2
323
324
  /* 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   Masahiro Yamada   scripts/kallsyms:...
325
  static int expand_symbol(const unsigned char *data, int len, char *result)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  {
  	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   Masahiro Yamada   scripts/kallsyms:...
349
  static int symbol_absolute(const struct sym_entry *s)
78eb71594   Kees Cook   kallsyms: general...
350
  {
8c996940b   Ard Biesheuvel   kallsyms: don't o...
351
  	return s->percpu_absolute;
78eb71594   Kees Cook   kallsyms: general...
352
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
353
  static void write_src(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
355
  	unsigned int i, k, off;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
  	unsigned int best_idx[256];
  	unsigned int *markers;
9281acea6   Tejun Heo   kallsyms: make KS...
358
  	char buf[KSYM_NAME_LEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359

500193ec5   Masahiro Yamada   kallsyms: include...
360
361
  	printf("#include <asm/bitsperlong.h>
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
  	printf("#if BITS_PER_LONG == 64
  ");
  	printf("#define PTR .quad
  ");
72d3ebb92   Mathias Krause   kallsyms: lower a...
366
367
  	printf("#define ALGN .balign 8
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
371
  	printf("#else
  ");
  	printf("#define PTR .long
  ");
72d3ebb92   Mathias Krause   kallsyms: lower a...
372
373
  	printf("#define ALGN .balign 4
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
  	printf("#endif
  ");
aad094701   Jan Beulich   [PATCH] move kall...
376
377
  	printf("\t.section .rodata, \"a\"
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378

2213e9a66   Ard Biesheuvel   kallsyms: add sup...
379
380
381
382
  	if (!base_relative)
  		output_label("kallsyms_addresses");
  	else
  		output_label("kallsyms_offsets");
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
383
  	for (i = 0; i < table_cnt; i++) {
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
384
  		if (base_relative) {
fd2ab2f66   Masahiro Yamada   scripts/kallsyms:...
385
386
387
388
389
390
  			/*
  			 * 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   Ard Biesheuvel   kallsyms: add sup...
391
392
393
394
  			long long offset;
  			int overflow;
  
  			if (!absolute_percpu) {
8d6052699   Masahiro Yamada   scripts/kallsyms:...
395
  				offset = table[i]->addr - relative_base;
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
396
  				overflow = (offset < 0 || offset > UINT_MAX);
8d6052699   Masahiro Yamada   scripts/kallsyms:...
397
398
  			} else if (symbol_absolute(table[i])) {
  				offset = table[i]->addr;
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
399
400
  				overflow = (offset < 0 || offset > INT_MAX);
  			} else {
8d6052699   Masahiro Yamada   scripts/kallsyms:...
401
  				offset = relative_base - table[i]->addr - 1;
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
402
403
404
405
406
407
  				overflow = (offset < INT_MIN || offset >= 0);
  			}
  			if (overflow) {
  				fprintf(stderr, "kallsyms failure: "
  					"%s symbol value %#llx out of range in relative mode
  ",
8d6052699   Masahiro Yamada   scripts/kallsyms:...
408
409
  					symbol_absolute(table[i]) ? "absolute" : "relative",
  					table[i]->addr);
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
410
411
412
413
  				exit(EXIT_FAILURE);
  			}
  			printf("\t.long\t%#x
  ", (int)offset);
8d6052699   Masahiro Yamada   scripts/kallsyms:...
414
415
  		} else if (!symbol_absolute(table[i])) {
  			output_address(table[i]->addr);
fd593d127   Eric W. Biederman   [PATCH] relocatab...
416
  		} else {
8d6052699   Masahiro Yamada   scripts/kallsyms:...
417
418
  			printf("\tPTR\t%#llx
  ", table[i]->addr);
fd593d127   Eric W. Biederman   [PATCH] relocatab...
419
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
  	}
  	printf("
  ");
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
423
424
  	if (base_relative) {
  		output_label("kallsyms_relative_base");
fd2ab2f66   Masahiro Yamada   scripts/kallsyms:...
425
  		output_address(relative_base);
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
426
427
428
  		printf("
  ");
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  	output_label("kallsyms_num_syms");
80ffbaa5b   Jan Beulich   kallsyms: reduce ...
430
431
  	printf("\t.long\t%u
  ", table_cnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
435
436
  	printf("
  ");
  
  	/* table of offset markers, that give the offset in the compressed stream
  	 * every 256 symbols */
f1a136e0d   Jesper Juhl   [PATCH] kallsyms:...
437
438
439
440
441
442
443
  	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
444
445
  
  	output_label("kallsyms_names");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  	off = 0;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
447
448
449
  	for (i = 0; i < table_cnt; i++) {
  		if ((i & 0xFF) == 0)
  			markers[i >> 8] = off;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450

8d6052699   Masahiro Yamada   scripts/kallsyms:...
451
452
453
  		printf("\t.byte 0x%02x", table[i]->len);
  		for (k = 0; k < table[i]->len; k++)
  			printf(", 0x%02x", table[i]->sym[k]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
  		printf("
  ");
8d6052699   Masahiro Yamada   scripts/kallsyms:...
456
  		off += table[i]->len + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
460
461
  	}
  	printf("
  ");
  
  	output_label("kallsyms_markers");
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
462
  	for (i = 0; i < ((table_cnt + 255) >> 8); i++)
80ffbaa5b   Jan Beulich   kallsyms: reduce ...
463
464
  		printf("\t.long\t%u
  ", markers[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
468
469
470
471
472
473
  	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:...
474
  		expand_symbol(best_table[i], best_table_len[i], buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  		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
492
  /* count all the possible tokens in a symbol */
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
493
  static void learn_symbol(const unsigned char *symbol, int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
  {
  	int i;
  
  	for (i = 0; i < len - 1; i++)
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
498
  		token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
501
  }
  
  /* decrease the count for all the possible tokens in a symbol */
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
502
  static void forget_symbol(const unsigned char *symbol, int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
  {
  	int i;
  
  	for (i = 0; i < len - 1; i++)
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
507
  		token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  }
5e5c4fa78   Masahiro Yamada   scripts/kallsyms:...
509
  /* do the initial token count */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
  static void build_initial_tok_table(void)
  {
5e5c4fa78   Masahiro Yamada   scripts/kallsyms:...
512
  	unsigned int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513

5e5c4fa78   Masahiro Yamada   scripts/kallsyms:...
514
  	for (i = 0; i < table_cnt; i++)
8d6052699   Masahiro Yamada   scripts/kallsyms:...
515
  		learn_symbol(table[i]->sym, table[i]->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
  }
2558c138a   Masahiro Yamada   scripts/kallsyms:...
517
  static unsigned char *find_token(unsigned char *str, int len,
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
518
  				 const unsigned char *token)
7c5d249ad   Paulo Marques   kallsyms: remove ...
519
520
521
522
523
524
525
526
527
  {
  	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
528
529
  /* replace a given token in all the valid symbols. Use the sampled symbols
   * to update the counts */
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
530
  static void compress_symbols(const unsigned char *str, int idx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
532
533
  	unsigned int i, len, size;
  	unsigned char *p1, *p2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
535
  	for (i = 0; i < table_cnt; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536

8d6052699   Masahiro Yamada   scripts/kallsyms:...
537
538
  		len = table[i]->len;
  		p1 = table[i]->sym;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
539
540
  
  		/* find the token on the symbol */
7c5d249ad   Paulo Marques   kallsyms: remove ...
541
  		p2 = find_token(p1, len, str);
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
542
543
544
  		if (!p2) continue;
  
  		/* decrease the counts for this symbol's tokens */
8d6052699   Masahiro Yamada   scripts/kallsyms:...
545
  		forget_symbol(table[i]->sym, len);
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
546
547
  
  		size = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
  
  		do {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
550
551
552
553
554
555
556
557
  			*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
558
  			/* find the token on the symbol */
7c5d249ad   Paulo Marques   kallsyms: remove ...
559
  			p2 = find_token(p1, size, str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560

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

8d6052699   Masahiro Yamada   scripts/kallsyms:...
563
  		table[i]->len = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
565
  		/* increase the counts for this symbol's new tokens */
8d6052699   Masahiro Yamada   scripts/kallsyms:...
566
  		learn_symbol(table[i]->sym, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
569
570
  	}
  }
  
  /* search the token with the maximum profit */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
571
  static int find_best_token(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
573
  	int i, best, bestprofit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
  
  	bestprofit=-10000;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
576
  	best = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
578
579
580
581
  	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
582
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
586
587
588
589
  	return best;
  }
  
  /* this is the core of the algorithm: calculate the "best" table */
  static void optimize_result(void)
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
590
  	int i, best;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
594
595
596
597
598
  
  	/* 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   Cao jin   kbuild/kallsyms: ...
599
  			/* find the token with the best profit value */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  			best = find_best_token();
e0a04b11e   Xiaochen Wang   scripts/kallsyms....
601
602
  			if (token_profit[best] == 0)
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
  
  			/* place it in the "best" table */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
605
606
607
  			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
608
609
  
  			/* replace this token in all the valid symbols */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
610
  			compress_symbols(best_table[i], i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
614
615
616
617
  		}
  	}
  }
  
  /* 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:...
618
  	unsigned int i, j, c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
620
  	for (i = 0; i < table_cnt; i++) {
8d6052699   Masahiro Yamada   scripts/kallsyms:...
621
622
  		for (j = 0; j < table[i]->len; j++) {
  			c = table[i]->sym[j];
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
623
624
  			best_table[c][0]=c;
  			best_table_len[c]=1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
629
630
  		}
  	}
  }
  
  static void optimize_token_table(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
635
636
  	build_initial_tok_table();
  
  	insert_real_symbols_in_table();
  
  	optimize_result();
  }
b478b782e   Lai Jiangshan   kallsyms, tracing...
637
638
639
  /* guess for "linker script provide" symbol */
  static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
  {
29e55ad3d   Masahiro Yamada   scripts/kallsyms:...
640
  	const char *symbol = sym_name(se);
b478b782e   Lai Jiangshan   kallsyms, tracing...
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
  	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   Paulo Marques   kallsyms should p...
671
672
  static int compare_symbols(const void *a, const void *b)
  {
8d6052699   Masahiro Yamada   scripts/kallsyms:...
673
674
  	const struct sym_entry *sa = *(const struct sym_entry **)a;
  	const struct sym_entry *sb = *(const struct sym_entry **)b;
f2df3f65d   Paulo Marques   kallsyms should p...
675
  	int wa, wb;
f2df3f65d   Paulo Marques   kallsyms should p...
676
677
678
679
680
681
682
683
684
685
686
  	/* 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...
687
688
689
690
691
692
693
  	/* 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   Masahiro Yamada   scripts/kallsyms:...
694
695
  	wa = strspn(sym_name(sa), "_");
  	wb = strspn(sym_name(sb), "_");
b478b782e   Lai Jiangshan   kallsyms, tracing...
696
697
  	if (wa != wb)
  		return wa - wb;
f2df3f65d   Paulo Marques   kallsyms should p...
698
699
700
701
702
703
  	/* sort by initial order, so that other symbols are left undisturbed */
  	return sa->start_pos - sb->start_pos;
  }
  
  static void sort_symbols(void)
  {
8d6052699   Masahiro Yamada   scripts/kallsyms:...
704
  	qsort(table, table_cnt, sizeof(table[0]), compare_symbols);
f2df3f65d   Paulo Marques   kallsyms should p...
705
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706

c6bda7c98   Rusty Russell   kallsyms: fix per...
707
708
709
710
711
  static void make_percpus_absolute(void)
  {
  	unsigned int i;
  
  	for (i = 0; i < table_cnt; i++)
8d6052699   Masahiro Yamada   scripts/kallsyms:...
712
  		if (symbol_in_range(table[i], &percpu_range, 1)) {
8c996940b   Ard Biesheuvel   kallsyms: don't o...
713
714
715
716
717
  			/*
  			 * Keep the 'A' override for percpu symbols to
  			 * ensure consistent behavior compared to older
  			 * versions of this tool.
  			 */
8d6052699   Masahiro Yamada   scripts/kallsyms:...
718
719
  			table[i]->sym[0] = 'A';
  			table[i]->percpu_absolute = 1;
8c996940b   Ard Biesheuvel   kallsyms: don't o...
720
  		}
c6bda7c98   Rusty Russell   kallsyms: fix per...
721
  }
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
722
723
724
725
  /* find the minimum non-absolute symbol address */
  static void record_relative_base(void)
  {
  	unsigned int i;
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
726
  	for (i = 0; i < table_cnt; i++)
8d6052699   Masahiro Yamada   scripts/kallsyms:...
727
  		if (!symbol_absolute(table[i])) {
f34ea0291   Masahiro Yamada   scripts/kallsyms:...
728
729
730
731
  			/*
  			 * The table is sorted by address.
  			 * Take the first non-absolute symbol value.
  			 */
8d6052699   Masahiro Yamada   scripts/kallsyms:...
732
  			relative_base = table[i]->addr;
f34ea0291   Masahiro Yamada   scripts/kallsyms:...
733
734
  			return;
  		}
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
735
  }
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
736
  int main(int argc, char **argv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
  {
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
738
739
740
741
742
  	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...
743
744
  			else if (strcmp(argv[i], "--absolute-percpu") == 0)
  				absolute_percpu = 1;
534c9f2ec   Masahiro Yamada   kallsyms: remove ...
745
  			else if (strcmp(argv[i], "--base-relative") == 0)
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
746
747
  				base_relative = 1;
  			else
41f11a4fa   Yoshinori Sato   [PATCH] kallsyms ...
748
749
750
  				usage();
  		}
  	} else if (argc != 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
  		usage();
  
  	read_map(stdin);
5e5c4fa78   Masahiro Yamada   scripts/kallsyms:...
754
  	shrink_table();
c6bda7c98   Rusty Russell   kallsyms: fix per...
755
756
  	if (absolute_percpu)
  		make_percpus_absolute();
f34ea0291   Masahiro Yamada   scripts/kallsyms:...
757
  	sort_symbols();
2213e9a66   Ard Biesheuvel   kallsyms: add sup...
758
759
  	if (base_relative)
  		record_relative_base();
2ea038917   Sam Ravnborg   Revert "kbuild: s...
760
  	optimize_token_table();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
762
763
764
  	write_src();
  
  	return 0;
  }