Blame view

scripts/kallsyms.c 17.9 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 */
a41333e06   Masahiro Yamada   scripts/kallsyms:...
108
109
  		NULL
  	};
516d980f8   Masahiro Yamada   scripts/kallsyms:...
110
  	/* Symbol names that end with the following are ignored.*/
a41333e06   Masahiro Yamada   scripts/kallsyms:...
111
112
113
114
115
116
  	static const char * const ignored_suffixes[] = {
  		"_from_arm",		/* arm */
  		"_from_thumb",		/* arm */
  		"_veneer",		/* arm */
  		NULL
  	};
516d980f8   Masahiro Yamada   scripts/kallsyms:...
117
118
119
120
121
122
  	/* 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:...
123
  	const char * const *p;
a41333e06   Masahiro Yamada   scripts/kallsyms:...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  	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:...
138
139
140
141
  	for (p = ignored_matches; *p; p++) {
  		if (strstr(name, *p))
  			return true;
  	}
887df76de   Masahiro Yamada   scripts/kallsyms:...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  	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:...
156
157
  	return false;
  }
b6233d0de   Masahiro Yamada   scripts/kallsyms:...
158
159
  static void check_symbol_range(const char *sym, unsigned long long addr,
  			       struct addr_range *ranges, int entries)
17b1f0de7   Mike Frysinger   kallsyms: general...
160
161
  {
  	size_t i;
78eb71594   Kees Cook   kallsyms: general...
162
  	struct addr_range *ar;
17b1f0de7   Mike Frysinger   kallsyms: general...
163

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

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

be9f6133f   Masahiro Yamada   scripts/kallsyms:...
200
  	if (strcmp(name, "_text") == 0)
8d6052699   Masahiro Yamada   scripts/kallsyms:...
201
  		_text = addr;
b6233d0de   Masahiro Yamada   scripts/kallsyms:...
202

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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