Blame view

scripts/kallsyms.c 18.1 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
  static bool is_ignored_symbol(const char *name, char type)
  {
516d980f8   Masahiro Yamada   scripts/kallsyms:...
79
  	/* Symbol names that exactly match to the following are ignored.*/
a41333e06   Masahiro Yamada   scripts/kallsyms:...
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	static const char * const ignored_symbols[] = {
  		/*
  		 * Symbols which vary between passes. Passes 1 and 2 must have
  		 * identical symbol lists. The kallsyms_* symbols below are
  		 * only added after pass 1, they would be included in pass 2
  		 * when --all-symbols is specified so exclude them to get a
  		 * stable symbol list.
  		 */
  		"kallsyms_addresses",
  		"kallsyms_offsets",
  		"kallsyms_relative_base",
  		"kallsyms_num_syms",
  		"kallsyms_names",
  		"kallsyms_markers",
  		"kallsyms_token_table",
  		"kallsyms_token_index",
  		/* Exclude linker generated symbols which vary between passes */
  		"_SDA_BASE_",		/* ppc */
  		"_SDA2_BASE_",		/* ppc */
  		NULL
  	};
516d980f8   Masahiro Yamada   scripts/kallsyms:...
101
  	/* Symbol names that begin with the following are ignored.*/
a41333e06   Masahiro Yamada   scripts/kallsyms:...
102
  	static const char * const ignored_prefixes[] = {
97261e1e2   Masahiro Yamada   scripts/kallsyms:...
103
104
  		"$",			/* local symbols for ARM, MIPS, etc. */
  		".LASANPC",		/* s390 kasan local symbols */
a41333e06   Masahiro Yamada   scripts/kallsyms:...
105
106
  		"__crc_",		/* modversions */
  		"__efistub_",		/* arm64 EFI stub namespace */
762171291   David Brazdil   KVM: arm64: Add b...
107
  		"__kvm_nvhe_",		/* arm64 non-VHE KVM namespace */
efe6e3068   Arnd Bergmann   kallsyms: fix non...
108
109
110
111
112
113
  		"__AArch64ADRPThunk_",	/* arm64 lld */
  		"__ARMV5PILongThunk_",	/* arm lld */
  		"__ARMV7PILongThunk_",
  		"__ThumbV7PILongThunk_",
  		"__LA25Thunk_",		/* mips lld */
  		"__microLA25Thunk_",
a41333e06   Masahiro Yamada   scripts/kallsyms:...
114
115
  		NULL
  	};
516d980f8   Masahiro Yamada   scripts/kallsyms:...
116
  	/* Symbol names that end with the following are ignored.*/
a41333e06   Masahiro Yamada   scripts/kallsyms:...
117
118
119
120
121
122
  	static const char * const ignored_suffixes[] = {
  		"_from_arm",		/* arm */
  		"_from_thumb",		/* arm */
  		"_veneer",		/* arm */
  		NULL
  	};
516d980f8   Masahiro Yamada   scripts/kallsyms:...
123
124
125
126
127
128
  	/* Symbol names that contain the following are ignored.*/
  	static const char * const ignored_matches[] = {
  		".long_branch.",	/* ppc stub */
  		".plt_branch.",		/* ppc stub */
  		NULL
  	};
a41333e06   Masahiro Yamada   scripts/kallsyms:...
129
  	const char * const *p;
a41333e06   Masahiro Yamada   scripts/kallsyms:...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  	for (p = ignored_symbols; *p; p++)
  		if (!strcmp(name, *p))
  			return true;
  
  	for (p = ignored_prefixes; *p; p++)
  		if (!strncmp(name, *p, strlen(*p)))
  			return true;
  
  	for (p = ignored_suffixes; *p; p++) {
  		int l = strlen(name) - strlen(*p);
  
  		if (l >= 0 && !strcmp(name + l, *p))
  			return true;
  	}
516d980f8   Masahiro Yamada   scripts/kallsyms:...
144
145
146
147
  	for (p = ignored_matches; *p; p++) {
  		if (strstr(name, *p))
  			return true;
  	}
887df76de   Masahiro Yamada   scripts/kallsyms:...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  	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:...
162
163
  	return false;
  }
b6233d0de   Masahiro Yamada   scripts/kallsyms:...
164
165
  static void check_symbol_range(const char *sym, unsigned long long addr,
  			       struct addr_range *ranges, int entries)
17b1f0de7   Mike Frysinger   kallsyms: general...
166
167
  {
  	size_t i;
78eb71594   Kees Cook   kallsyms: general...
168
  	struct addr_range *ar;
17b1f0de7   Mike Frysinger   kallsyms: general...
169

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

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

be9f6133f   Masahiro Yamada   scripts/kallsyms:...
206
  	if (strcmp(name, "_text") == 0)
8d6052699   Masahiro Yamada   scripts/kallsyms:...
207
  		_text = addr;
b6233d0de   Masahiro Yamada   scripts/kallsyms:...
208

7883a1433   Mikhail Petrov   scripts/kallsyms:...
209
210
211
  	/* Ignore most absolute/undefined (?) symbols. */
  	if (is_ignored_symbol(name, type))
  		return NULL;
8d6052699   Masahiro Yamada   scripts/kallsyms:...
212
213
  	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
214
215
216
  
  	/* include the type field in the symbol name, so that it gets
  	 * compressed together */
8d6052699   Masahiro Yamada   scripts/kallsyms:...
217
218
  
  	len = strlen(name) + 1;
9d1b38958   Masahiro Yamada   scripts/kallsyms:...
219
  	sym = malloc(sizeof(*sym) + len + 1);
8d6052699   Masahiro Yamada   scripts/kallsyms:...
220
  	if (!sym) {
f1a136e0d   Jesper Juhl   [PATCH] kallsyms:...
221
222
223
224
225
  		fprintf(stderr, "kallsyms failure: "
  			"unable to allocate required amount of memory
  ");
  		exit(EXIT_FAILURE);
  	}
8d6052699   Masahiro Yamada   scripts/kallsyms:...
226
227
228
  	sym->addr = addr;
  	sym->len = len;
  	sym->sym[0] = type;
9d1b38958   Masahiro Yamada   scripts/kallsyms:...
229
  	strcpy(sym_name(sym), name);
8d6052699   Masahiro Yamada   scripts/kallsyms:...
230
  	sym->percpu_absolute = 0;
8c996940b   Ard Biesheuvel   kallsyms: don't o...
231

8d6052699   Masahiro Yamada   scripts/kallsyms:...
232
  	return sym;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  }
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
234
235
  static int symbol_in_range(const struct sym_entry *s,
  			   const struct addr_range *ranges, int entries)
17b1f0de7   Mike Frysinger   kallsyms: general...
236
237
  {
  	size_t i;
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
238
  	const struct addr_range *ar;
17b1f0de7   Mike Frysinger   kallsyms: general...
239

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

78eb71594   Kees Cook   kallsyms: general...
243
  		if (s->addr >= ar->start && s->addr <= ar->end)
ac6ca5c86   Mike Frysinger   kallsyms: fix inv...
244
  			return 1;
17b1f0de7   Mike Frysinger   kallsyms: general...
245
  	}
ac6ca5c86   Mike Frysinger   kallsyms: fix inv...
246
  	return 0;
17b1f0de7   Mike Frysinger   kallsyms: general...
247
  }
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
248
  static int symbol_valid(const struct sym_entry *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  {
29e55ad3d   Masahiro Yamada   scripts/kallsyms:...
250
  	const char *name = sym_name(s);
bd8b22d28   Ard Biesheuvel   Kbuild: kallsyms:...
251

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

500193ec5   Masahiro Yamada   kallsyms: include...
374
375
  	printf("#include <asm/bitsperlong.h>
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
378
379
  	printf("#if BITS_PER_LONG == 64
  ");
  	printf("#define PTR .quad
  ");
72d3ebb92   Mathias Krause   kallsyms: lower a...
380
381
  	printf("#define ALGN .balign 8
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
384
385
  	printf("#else
  ");
  	printf("#define PTR .long
  ");
72d3ebb92   Mathias Krause   kallsyms: lower a...
386
387
  	printf("#define ALGN .balign 4
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
  	printf("#endif
  ");
aad094701   Jan Beulich   [PATCH] move kall...
390
391
  	printf("\t.section .rodata, \"a\"
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392

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

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

5e5c4fa78   Masahiro Yamada   scripts/kallsyms:...
528
  	for (i = 0; i < table_cnt; i++)
8d6052699   Masahiro Yamada   scripts/kallsyms:...
529
  		learn_symbol(table[i]->sym, table[i]->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  }
2558c138a   Masahiro Yamada   scripts/kallsyms:...
531
  static unsigned char *find_token(unsigned char *str, int len,
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
532
  				 const unsigned char *token)
7c5d249ad   Paulo Marques   kallsyms: remove ...
533
534
535
536
537
538
539
540
541
  {
  	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
542
543
  /* replace a given token in all the valid symbols. Use the sampled symbols
   * to update the counts */
4bfe2b781   Masahiro Yamada   scripts/kallsyms:...
544
  static void compress_symbols(const unsigned char *str, int idx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
546
547
  	unsigned int i, len, size;
  	unsigned char *p1, *p2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548

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

8d6052699   Masahiro Yamada   scripts/kallsyms:...
551
552
  		len = table[i]->len;
  		p1 = table[i]->sym;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
553
554
  
  		/* find the token on the symbol */
7c5d249ad   Paulo Marques   kallsyms: remove ...
555
  		p2 = find_token(p1, len, str);
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
556
557
558
  		if (!p2) continue;
  
  		/* decrease the counts for this symbol's tokens */
8d6052699   Masahiro Yamada   scripts/kallsyms:...
559
  		forget_symbol(table[i]->sym, len);
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
560
561
  
  		size = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
  
  		do {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
564
565
566
567
568
569
570
571
  			*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
572
  			/* find the token on the symbol */
7c5d249ad   Paulo Marques   kallsyms: remove ...
573
  			p2 = find_token(p1, size, str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574

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

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

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
579
  		/* increase the counts for this symbol's new tokens */
8d6052699   Masahiro Yamada   scripts/kallsyms:...
580
  		learn_symbol(table[i]->sym, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
582
583
584
  	}
  }
  
  /* search the token with the maximum profit */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
585
  static int find_best_token(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
587
  	int i, best, bestprofit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
  
  	bestprofit=-10000;
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
590
  	best = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591

b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
592
593
594
595
  	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
596
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
600
601
602
603
  	return best;
  }
  
  /* this is the core of the algorithm: calculate the "best" table */
  static void optimize_result(void)
  {
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
604
  	int i, best;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
607
608
609
610
611
612
  
  	/* 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: ...
613
  			/* find the token with the best profit value */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
  			best = find_best_token();
e0a04b11e   Xiaochen Wang   scripts/kallsyms....
615
616
  			if (token_profit[best] == 0)
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
  
  			/* place it in the "best" table */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
619
620
621
  			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
622
623
  
  			/* replace this token in all the valid symbols */
b3dbb4ecd   Paulo Marques   [PATCH] kallsyms:...
624
  			compress_symbols(best_table[i], i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
629
630
631
  		}
  	}
  }
  
  /* 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:...
632
  	unsigned int i, j, c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633

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

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