patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / kernel / kallsyms.c
1 /*
2  * kallsyms.c: in-kernel printing of symbolic oopses and stack traces.
3  *
4  * Rewritten and vastly simplified by Rusty Russell for in-kernel
5  * module loader:
6  *   Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
7  * Stem compression by Andi Kleen.
8  */
9 #include <linux/kallsyms.h>
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/seq_file.h>
13 #include <linux/fs.h>
14 #include <linux/err.h>
15 #include <linux/proc_fs.h>
16
17 /* These will be re-linked against their real values during the second link stage */
18 extern unsigned long kallsyms_addresses[] __attribute__((weak));
19 extern unsigned long kallsyms_num_syms __attribute__((weak));
20 extern char kallsyms_names[] __attribute__((weak));
21
22 /* Defined by the linker script. */
23 extern char _stext[], _etext[], _sinittext[], _einittext[];
24
25 static inline int is_kernel_inittext(unsigned long addr)
26 {
27         if (addr >= (unsigned long)_sinittext
28             && addr <= (unsigned long)_einittext)
29                 return 1;
30         return 0;
31 }
32
33 static inline int is_kernel_text(unsigned long addr)
34 {
35         if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext)
36                 return 1;
37         return 0;
38 }
39
40 /* Lookup the address for this symbol. Returns 0 if not found. */
41 unsigned long kallsyms_lookup_name(const char *name)
42 {
43         char namebuf[128];
44         unsigned long i;
45         char *knames;
46
47         for (i = 0, knames = kallsyms_names; i < kallsyms_num_syms; i++) {
48                 unsigned prefix = *knames++;
49
50                 strlcpy(namebuf + prefix, knames, 127 - prefix);
51                 if (strcmp(namebuf, name) == 0)
52                         return kallsyms_addresses[i];
53
54                 knames += strlen(knames) + 1;
55         }
56         return module_kallsyms_lookup_name(name);
57 }
58
59 /* Lookup an address.  modname is set to NULL if it's in the kernel. */
60 const char *kallsyms_lookup(unsigned long addr,
61                             unsigned long *symbolsize,
62                             unsigned long *offset,
63                             char **modname, char *namebuf)
64 {
65         unsigned long i, best = 0;
66
67         /* This kernel should never had been booted. */
68         BUG_ON(!kallsyms_addresses);
69
70         namebuf[127] = 0;
71         namebuf[0] = 0;
72
73         if (is_kernel_text(addr) || is_kernel_inittext(addr)) {
74                 unsigned long symbol_end;
75                 char *name = kallsyms_names;
76
77                 /* They're sorted, we could be clever here, but who cares? */
78                 for (i = 0; i < kallsyms_num_syms; i++) {
79                         if (kallsyms_addresses[i] > kallsyms_addresses[best] &&
80                             kallsyms_addresses[i] <= addr)
81                                 best = i;
82                 }
83
84                 /* Grab name */
85                 for (i = 0; i <= best; i++) { 
86                         unsigned prefix = *name++;
87                         strncpy(namebuf + prefix, name, 127 - prefix);
88                         name += strlen(name) + 1;
89                 }
90
91                 /* At worst, symbol ends at end of section. */
92                 if (is_kernel_inittext(addr))
93                         symbol_end = (unsigned long)_einittext;
94                 else
95                         symbol_end = (unsigned long)_etext;
96
97                 /* Search for next non-aliased symbol */
98                 for (i = best+1; i < kallsyms_num_syms; i++) {
99                         if (kallsyms_addresses[i] > kallsyms_addresses[best]) {
100                                 symbol_end = kallsyms_addresses[i];
101                                 break;
102                         }
103                 }
104
105                 *symbolsize = symbol_end - kallsyms_addresses[best];
106                 *modname = NULL;
107                 *offset = addr - kallsyms_addresses[best];
108                 return namebuf;
109         }
110
111         return module_address_lookup(addr, symbolsize, offset, modname);
112 }
113
114 /* Replace "%s" in format with address, or returns -errno. */
115 void __print_symbol(const char *fmt, unsigned long address)
116 {
117         char *modname;
118         const char *name;
119         unsigned long offset, size;
120         char namebuf[128];
121
122         name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
123
124         if (!name) {
125                 char addrstr[sizeof("0x%lx") + (BITS_PER_LONG*3/10)];
126
127                 sprintf(addrstr, "0x%lx", address);
128                 printk(fmt, addrstr);
129                 return;
130         }
131
132         if (modname) {
133                 /* This is pretty small. */
134                 char buffer[sizeof("%s+%#lx/%#lx [%s]")
135                            + strlen(name) + 2*(BITS_PER_LONG*3/10)
136                            + strlen(modname)];
137
138                 sprintf(buffer, "%s+%#lx/%#lx [%s]",
139                         name, offset, size, modname);
140                 printk(fmt, buffer);
141         } else {
142                 char buffer[sizeof("%s+%#lx/%#lx")
143                            + strlen(name) + 2*(BITS_PER_LONG*3/10)];
144
145                 sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
146                 printk(fmt, buffer);
147         }
148 }
149
150 /* To avoid O(n^2) iteration, we carry prefix along. */
151 struct kallsym_iter
152 {
153         loff_t pos;
154         struct module *owner;
155         unsigned long value;
156         unsigned int nameoff; /* If iterating in core kernel symbols */
157         char type;
158         char name[128];
159 };
160
161 /* Only label it "global" if it is exported. */
162 static void upcase_if_global(struct kallsym_iter *iter)
163 {
164         if (is_exported(iter->name, iter->owner))
165                 iter->type += 'A' - 'a';
166 }
167
168 static int get_ksymbol_mod(struct kallsym_iter *iter)
169 {
170         iter->owner = module_get_kallsym(iter->pos - kallsyms_num_syms,
171                                          &iter->value,
172                                          &iter->type, iter->name);
173         if (iter->owner == NULL)
174                 return 0;
175
176         upcase_if_global(iter);
177         return 1;
178 }
179
180 /* Returns space to next name. */
181 static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
182 {
183         unsigned stemlen, off = iter->nameoff;
184
185         /* First char of each symbol name indicates prefix length
186            shared with previous name (stem compression). */
187         stemlen = kallsyms_names[off++];
188
189         strlcpy(iter->name+stemlen, kallsyms_names + off, 128-stemlen);
190         off += strlen(kallsyms_names + off) + 1;
191         iter->owner = NULL;
192         iter->value = kallsyms_addresses[iter->pos];
193         if (is_kernel_text(iter->value) || is_kernel_inittext(iter->value))
194                 iter->type = 't';
195         else
196                 iter->type = 'd';
197
198         upcase_if_global(iter);
199         return off - iter->nameoff;
200 }
201
202 static void reset_iter(struct kallsym_iter *iter)
203 {
204         iter->name[0] = '\0';
205         iter->nameoff = 0;
206         iter->pos = 0;
207 }
208
209 /* Returns false if pos at or past end of file. */
210 static int update_iter(struct kallsym_iter *iter, loff_t pos)
211 {
212         /* Module symbols can be accessed randomly. */
213         if (pos >= kallsyms_num_syms) {
214                 iter->pos = pos;
215                 return get_ksymbol_mod(iter);
216         }
217         
218         /* If we're past the desired position, reset to start. */
219         if (pos < iter->pos)
220                 reset_iter(iter);
221
222         /* We need to iterate through the previous symbols: can be slow */
223         for (; iter->pos != pos; iter->pos++) {
224                 iter->nameoff += get_ksymbol_core(iter);
225                 cond_resched();
226         }
227         get_ksymbol_core(iter);
228         return 1;
229 }
230
231 static void *s_next(struct seq_file *m, void *p, loff_t *pos)
232 {
233         (*pos)++;
234
235         if (!update_iter(m->private, *pos))
236                 return NULL;
237         return p;
238 }
239
240 static void *s_start(struct seq_file *m, loff_t *pos)
241 {
242         if (!update_iter(m->private, *pos))
243                 return NULL;
244         return m->private;
245 }
246
247 static void s_stop(struct seq_file *m, void *p)
248 {
249 }
250
251 static int s_show(struct seq_file *m, void *p)
252 {
253         struct kallsym_iter *iter = m->private;
254
255         /* Some debugging symbols have no name.  Ignore them. */ 
256         if (!iter->name[0])
257                 return 0;
258
259         if (iter->owner)
260                 seq_printf(m, "%0*lx %c %s\t[%s]\n",
261                            (int)(2*sizeof(void*)),
262                            iter->value, iter->type, iter->name,
263                            module_name(iter->owner));
264         else
265                 seq_printf(m, "%0*lx %c %s\n",
266                            (int)(2*sizeof(void*)),
267                            iter->value, iter->type, iter->name);
268         return 0;
269 }
270
271 struct seq_operations kallsyms_op = {
272         .start = s_start,
273         .next = s_next,
274         .stop = s_stop,
275         .show = s_show
276 };
277
278 static int kallsyms_open(struct inode *inode, struct file *file)
279 {
280         /* We keep iterator in m->private, since normal case is to
281          * s_start from where we left off, so we avoid O(N^2). */
282         struct kallsym_iter *iter;
283         int ret;
284
285         iter = kmalloc(sizeof(*iter), GFP_KERNEL);
286         if (!iter)
287                 return -ENOMEM;
288         reset_iter(iter);
289
290         ret = seq_open(file, &kallsyms_op);
291         if (ret == 0)
292                 ((struct seq_file *)file->private_data)->private = iter;
293         else
294                 kfree(iter);
295         return ret;
296 }
297
298 static int kallsyms_release(struct inode *inode, struct file *file)
299 {
300         struct seq_file *m = (struct seq_file *)file->private_data;
301         kfree(m->private);
302         return seq_release(inode, file);
303 }
304
305 static struct file_operations kallsyms_operations = {
306         .open = kallsyms_open,
307         .read = seq_read,
308         .llseek = seq_lseek,
309         .release = kallsyms_release,
310 };
311
312 int __init kallsyms_init(void)
313 {
314         struct proc_dir_entry *entry;
315
316         entry = create_proc_entry("kallsyms", 0444, NULL);
317         if (entry)
318                 entry->proc_fops = &kallsyms_operations;
319         return 0;
320 }
321 __initcall(kallsyms_init);
322
323 EXPORT_SYMBOL(kallsyms_lookup);
324 EXPORT_SYMBOL(__print_symbol);