VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / scripts / kallsyms.c
1 /* Generate assembler source containing symbol information
2  *
3  * Copyright 2002       by Kai Germaschewski
4  *
5  * This software may be used and distributed according to the terms
6  * of the GNU General Public License, incorporated herein by reference.
7  *
8  * Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S
9  */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15
16 struct sym_entry {
17         unsigned long long addr;
18         char type;
19         char *sym;
20 };
21
22
23 static struct sym_entry *table;
24 static int size, cnt;
25 static unsigned long long _stext, _etext, _sinittext, _einittext;
26 static int all_symbols = 0;
27
28 static void
29 usage(void)
30 {
31         fprintf(stderr, "Usage: kallsyms [--all-symbols] < in.map > out.S\n");
32         exit(1);
33 }
34
35 static int
36 read_symbol(FILE *in, struct sym_entry *s)
37 {
38         char str[500];
39         int rc;
40
41         rc = fscanf(in, "%llx %c %499s\n", &s->addr, &s->type, str);
42         if (rc != 3) {
43                 if (rc != EOF) {
44                         /* skip line */
45                         fgets(str, 500, in);
46                 }
47                 return -1;
48         }
49
50         /* Ignore most absolute/undefined (?) symbols. */
51         if (strcmp(str, "_stext") == 0)
52                 _stext = s->addr;
53         else if (strcmp(str, "_etext") == 0)
54                 _etext = s->addr;
55         else if (strcmp(str, "_sinittext") == 0)
56                 _sinittext = s->addr;
57         else if (strcmp(str, "_einittext") == 0)
58                 _einittext = s->addr;
59         else if (toupper(s->type) == 'A' || toupper(s->type) == 'U')
60                 return -1;
61
62         s->sym = strdup(str);
63         return 0;
64 }
65
66 static int
67 symbol_valid(struct sym_entry *s)
68 {
69         if (!all_symbols) {
70                 if ((s->addr < _stext || s->addr > _etext)
71                     && (s->addr < _sinittext || s->addr > _einittext))
72                         return 0;
73         }
74
75         /* Exclude symbols which vary between passes.  Passes 1 and 2 must have
76          * identical symbol lists.  The kallsyms_* symbols below are only added
77          * after pass 1, they would be included in pass 2 when --all-symbols is
78          * specified so exclude them to get a stable symbol list.
79          */
80         if (strstr(s->sym, "_compiled.") ||
81             strcmp(s->sym, "kallsyms_addresses") == 0 ||
82             strcmp(s->sym, "kallsyms_num_syms") == 0 ||
83             strcmp(s->sym, "kallsyms_names") == 0)
84                 return 0;
85
86         /* Exclude linker generated symbols which vary between passes */
87         if (strcmp(s->sym, "_SDA_BASE_") == 0 ||        /* ppc */
88             strcmp(s->sym, "_SDA2_BASE_") == 0)         /* ppc */
89                 return 0;
90
91         return 1;
92 }
93
94 static void
95 read_map(FILE *in)
96 {
97         while (!feof(in)) {
98                 if (cnt >= size) {
99                         size += 10000;
100                         table = realloc(table, sizeof(*table) * size);
101                         if (!table) {
102                                 fprintf(stderr, "out of memory\n");
103                                 exit (1);
104                         }
105                 }
106                 if (read_symbol(in, &table[cnt]) == 0)
107                         cnt++;
108         }
109 }
110
111 static void
112 write_src(void)
113 {
114         int i, valid = 0;
115         char *prev;
116
117         printf("#include <asm/types.h>\n");
118         printf("#if BITS_PER_LONG == 64\n");
119         printf("#define PTR .quad\n");
120         printf("#define ALGN .align 8\n");
121         printf("#else\n");
122         printf("#define PTR .long\n");
123         printf("#define ALGN .align 4\n");
124         printf("#endif\n");
125
126         printf(".data\n");
127
128         printf(".globl kallsyms_addresses\n");
129         printf("\tALGN\n");
130         printf("kallsyms_addresses:\n");
131         for (i = 0; i < cnt; i++) {
132                 if (!symbol_valid(&table[i]))
133                         continue;
134
135                 printf("\tPTR\t%#llx\n", table[i].addr);
136                 valid++;
137         }
138         printf("\n");
139
140         printf(".globl kallsyms_num_syms\n");
141         printf("\tALGN\n");
142         printf("kallsyms_num_syms:\n");
143         printf("\tPTR\t%d\n", valid);
144         printf("\n");
145
146         printf(".globl kallsyms_names\n");
147         printf("\tALGN\n");
148         printf("kallsyms_names:\n");
149         prev = ""; 
150         for (i = 0; i < cnt; i++) {
151                 int k;
152
153                 if (!symbol_valid(&table[i]))
154                         continue;
155
156                 for (k = 0; table[i].sym[k] && table[i].sym[k] == prev[k]; ++k)
157                         ; 
158
159                 printf("\t.byte 0x%02x\n\t.asciz\t\"%s\"\n", k, table[i].sym + k);
160                 prev = table[i].sym;
161         }
162         printf("\n");
163 }
164
165 int
166 main(int argc, char **argv)
167 {
168         if (argc == 2 && strcmp(argv[1], "--all-symbols") == 0)
169                 all_symbols = 1;
170         else if (argc != 1)
171                 usage();
172
173         read_map(stdin);
174         write_src();
175
176         return 0;
177 }
178