Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/kernel/kallsyms.c
10818 views
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 <[email protected]> IBM Corporation
7
*
8
* ChangeLog:
9
*
10
* (25/Aug/2004) Paulo Marques <[email protected]>
11
* Changed the compression method from stem compression to "table lookup"
12
* compression (see scripts/kallsyms.c for a more complete description)
13
*/
14
#include <linux/kallsyms.h>
15
#include <linux/module.h>
16
#include <linux/init.h>
17
#include <linux/seq_file.h>
18
#include <linux/fs.h>
19
#include <linux/kdb.h>
20
#include <linux/err.h>
21
#include <linux/proc_fs.h>
22
#include <linux/sched.h> /* for cond_resched */
23
#include <linux/mm.h>
24
#include <linux/ctype.h>
25
#include <linux/slab.h>
26
27
#include <asm/sections.h>
28
29
#ifdef CONFIG_KALLSYMS_ALL
30
#define all_var 1
31
#else
32
#define all_var 0
33
#endif
34
35
/*
36
* These will be re-linked against their real values
37
* during the second link stage.
38
*/
39
extern const unsigned long kallsyms_addresses[] __attribute__((weak));
40
extern const u8 kallsyms_names[] __attribute__((weak));
41
42
/*
43
* Tell the compiler that the count isn't in the small data section if the arch
44
* has one (eg: FRV).
45
*/
46
extern const unsigned long kallsyms_num_syms
47
__attribute__((weak, section(".rodata")));
48
49
extern const u8 kallsyms_token_table[] __attribute__((weak));
50
extern const u16 kallsyms_token_index[] __attribute__((weak));
51
52
extern const unsigned long kallsyms_markers[] __attribute__((weak));
53
54
static inline int is_kernel_inittext(unsigned long addr)
55
{
56
if (addr >= (unsigned long)_sinittext
57
&& addr <= (unsigned long)_einittext)
58
return 1;
59
return 0;
60
}
61
62
static inline int is_kernel_text(unsigned long addr)
63
{
64
if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) ||
65
arch_is_kernel_text(addr))
66
return 1;
67
return in_gate_area_no_mm(addr);
68
}
69
70
static inline int is_kernel(unsigned long addr)
71
{
72
if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end)
73
return 1;
74
return in_gate_area_no_mm(addr);
75
}
76
77
static int is_ksym_addr(unsigned long addr)
78
{
79
if (all_var)
80
return is_kernel(addr);
81
82
return is_kernel_text(addr) || is_kernel_inittext(addr);
83
}
84
85
/*
86
* Expand a compressed symbol data into the resulting uncompressed string,
87
* given the offset to where the symbol is in the compressed stream.
88
*/
89
static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
90
{
91
int len, skipped_first = 0;
92
const u8 *tptr, *data;
93
94
/* Get the compressed symbol length from the first symbol byte. */
95
data = &kallsyms_names[off];
96
len = *data;
97
data++;
98
99
/*
100
* Update the offset to return the offset for the next symbol on
101
* the compressed stream.
102
*/
103
off += len + 1;
104
105
/*
106
* For every byte on the compressed symbol data, copy the table
107
* entry for that byte.
108
*/
109
while (len) {
110
tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
111
data++;
112
len--;
113
114
while (*tptr) {
115
if (skipped_first) {
116
*result = *tptr;
117
result++;
118
} else
119
skipped_first = 1;
120
tptr++;
121
}
122
}
123
124
*result = '\0';
125
126
/* Return to offset to the next symbol. */
127
return off;
128
}
129
130
/*
131
* Get symbol type information. This is encoded as a single char at the
132
* beginning of the symbol name.
133
*/
134
static char kallsyms_get_symbol_type(unsigned int off)
135
{
136
/*
137
* Get just the first code, look it up in the token table,
138
* and return the first char from this token.
139
*/
140
return kallsyms_token_table[kallsyms_token_index[kallsyms_names[off + 1]]];
141
}
142
143
144
/*
145
* Find the offset on the compressed stream given and index in the
146
* kallsyms array.
147
*/
148
static unsigned int get_symbol_offset(unsigned long pos)
149
{
150
const u8 *name;
151
int i;
152
153
/*
154
* Use the closest marker we have. We have markers every 256 positions,
155
* so that should be close enough.
156
*/
157
name = &kallsyms_names[kallsyms_markers[pos >> 8]];
158
159
/*
160
* Sequentially scan all the symbols up to the point we're searching
161
* for. Every symbol is stored in a [<len>][<len> bytes of data] format,
162
* so we just need to add the len to the current pointer for every
163
* symbol we wish to skip.
164
*/
165
for (i = 0; i < (pos & 0xFF); i++)
166
name = name + (*name) + 1;
167
168
return name - kallsyms_names;
169
}
170
171
/* Lookup the address for this symbol. Returns 0 if not found. */
172
unsigned long kallsyms_lookup_name(const char *name)
173
{
174
char namebuf[KSYM_NAME_LEN];
175
unsigned long i;
176
unsigned int off;
177
178
for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
179
off = kallsyms_expand_symbol(off, namebuf);
180
181
if (strcmp(namebuf, name) == 0)
182
return kallsyms_addresses[i];
183
}
184
return module_kallsyms_lookup_name(name);
185
}
186
EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
187
188
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
189
unsigned long),
190
void *data)
191
{
192
char namebuf[KSYM_NAME_LEN];
193
unsigned long i;
194
unsigned int off;
195
int ret;
196
197
for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
198
off = kallsyms_expand_symbol(off, namebuf);
199
ret = fn(data, namebuf, NULL, kallsyms_addresses[i]);
200
if (ret != 0)
201
return ret;
202
}
203
return module_kallsyms_on_each_symbol(fn, data);
204
}
205
EXPORT_SYMBOL_GPL(kallsyms_on_each_symbol);
206
207
static unsigned long get_symbol_pos(unsigned long addr,
208
unsigned long *symbolsize,
209
unsigned long *offset)
210
{
211
unsigned long symbol_start = 0, symbol_end = 0;
212
unsigned long i, low, high, mid;
213
214
/* This kernel should never had been booted. */
215
BUG_ON(!kallsyms_addresses);
216
217
/* Do a binary search on the sorted kallsyms_addresses array. */
218
low = 0;
219
high = kallsyms_num_syms;
220
221
while (high - low > 1) {
222
mid = low + (high - low) / 2;
223
if (kallsyms_addresses[mid] <= addr)
224
low = mid;
225
else
226
high = mid;
227
}
228
229
/*
230
* Search for the first aliased symbol. Aliased
231
* symbols are symbols with the same address.
232
*/
233
while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low])
234
--low;
235
236
symbol_start = kallsyms_addresses[low];
237
238
/* Search for next non-aliased symbol. */
239
for (i = low + 1; i < kallsyms_num_syms; i++) {
240
if (kallsyms_addresses[i] > symbol_start) {
241
symbol_end = kallsyms_addresses[i];
242
break;
243
}
244
}
245
246
/* If we found no next symbol, we use the end of the section. */
247
if (!symbol_end) {
248
if (is_kernel_inittext(addr))
249
symbol_end = (unsigned long)_einittext;
250
else if (all_var)
251
symbol_end = (unsigned long)_end;
252
else
253
symbol_end = (unsigned long)_etext;
254
}
255
256
if (symbolsize)
257
*symbolsize = symbol_end - symbol_start;
258
if (offset)
259
*offset = addr - symbol_start;
260
261
return low;
262
}
263
264
/*
265
* Lookup an address but don't bother to find any names.
266
*/
267
int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
268
unsigned long *offset)
269
{
270
char namebuf[KSYM_NAME_LEN];
271
if (is_ksym_addr(addr))
272
return !!get_symbol_pos(addr, symbolsize, offset);
273
274
return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf);
275
}
276
277
/*
278
* Lookup an address
279
* - modname is set to NULL if it's in the kernel.
280
* - We guarantee that the returned name is valid until we reschedule even if.
281
* It resides in a module.
282
* - We also guarantee that modname will be valid until rescheduled.
283
*/
284
const char *kallsyms_lookup(unsigned long addr,
285
unsigned long *symbolsize,
286
unsigned long *offset,
287
char **modname, char *namebuf)
288
{
289
namebuf[KSYM_NAME_LEN - 1] = 0;
290
namebuf[0] = 0;
291
292
if (is_ksym_addr(addr)) {
293
unsigned long pos;
294
295
pos = get_symbol_pos(addr, symbolsize, offset);
296
/* Grab name */
297
kallsyms_expand_symbol(get_symbol_offset(pos), namebuf);
298
if (modname)
299
*modname = NULL;
300
return namebuf;
301
}
302
303
/* See if it's in a module. */
304
return module_address_lookup(addr, symbolsize, offset, modname,
305
namebuf);
306
}
307
308
int lookup_symbol_name(unsigned long addr, char *symname)
309
{
310
symname[0] = '\0';
311
symname[KSYM_NAME_LEN - 1] = '\0';
312
313
if (is_ksym_addr(addr)) {
314
unsigned long pos;
315
316
pos = get_symbol_pos(addr, NULL, NULL);
317
/* Grab name */
318
kallsyms_expand_symbol(get_symbol_offset(pos), symname);
319
return 0;
320
}
321
/* See if it's in a module. */
322
return lookup_module_symbol_name(addr, symname);
323
}
324
325
int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
326
unsigned long *offset, char *modname, char *name)
327
{
328
name[0] = '\0';
329
name[KSYM_NAME_LEN - 1] = '\0';
330
331
if (is_ksym_addr(addr)) {
332
unsigned long pos;
333
334
pos = get_symbol_pos(addr, size, offset);
335
/* Grab name */
336
kallsyms_expand_symbol(get_symbol_offset(pos), name);
337
modname[0] = '\0';
338
return 0;
339
}
340
/* See if it's in a module. */
341
return lookup_module_symbol_attrs(addr, size, offset, modname, name);
342
}
343
344
/* Look up a kernel symbol and return it in a text buffer. */
345
static int __sprint_symbol(char *buffer, unsigned long address,
346
int symbol_offset)
347
{
348
char *modname;
349
const char *name;
350
unsigned long offset, size;
351
int len;
352
353
address += symbol_offset;
354
name = kallsyms_lookup(address, &size, &offset, &modname, buffer);
355
if (!name)
356
return sprintf(buffer, "0x%lx", address);
357
358
if (name != buffer)
359
strcpy(buffer, name);
360
len = strlen(buffer);
361
buffer += len;
362
offset -= symbol_offset;
363
364
if (modname)
365
len += sprintf(buffer, "+%#lx/%#lx [%s]", offset, size, modname);
366
else
367
len += sprintf(buffer, "+%#lx/%#lx", offset, size);
368
369
return len;
370
}
371
372
/**
373
* sprint_symbol - Look up a kernel symbol and return it in a text buffer
374
* @buffer: buffer to be stored
375
* @address: address to lookup
376
*
377
* This function looks up a kernel symbol with @address and stores its name,
378
* offset, size and module name to @buffer if possible. If no symbol was found,
379
* just saves its @address as is.
380
*
381
* This function returns the number of bytes stored in @buffer.
382
*/
383
int sprint_symbol(char *buffer, unsigned long address)
384
{
385
return __sprint_symbol(buffer, address, 0);
386
}
387
388
EXPORT_SYMBOL_GPL(sprint_symbol);
389
390
/**
391
* sprint_backtrace - Look up a backtrace symbol and return it in a text buffer
392
* @buffer: buffer to be stored
393
* @address: address to lookup
394
*
395
* This function is for stack backtrace and does the same thing as
396
* sprint_symbol() but with modified/decreased @address. If there is a
397
* tail-call to the function marked "noreturn", gcc optimized out code after
398
* the call so that the stack-saved return address could point outside of the
399
* caller. This function ensures that kallsyms will find the original caller
400
* by decreasing @address.
401
*
402
* This function returns the number of bytes stored in @buffer.
403
*/
404
int sprint_backtrace(char *buffer, unsigned long address)
405
{
406
return __sprint_symbol(buffer, address, -1);
407
}
408
409
/* Look up a kernel symbol and print it to the kernel messages. */
410
void __print_symbol(const char *fmt, unsigned long address)
411
{
412
char buffer[KSYM_SYMBOL_LEN];
413
414
sprint_symbol(buffer, address);
415
416
printk(fmt, buffer);
417
}
418
EXPORT_SYMBOL(__print_symbol);
419
420
/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
421
struct kallsym_iter {
422
loff_t pos;
423
unsigned long value;
424
unsigned int nameoff; /* If iterating in core kernel symbols. */
425
char type;
426
char name[KSYM_NAME_LEN];
427
char module_name[MODULE_NAME_LEN];
428
int exported;
429
};
430
431
static int get_ksymbol_mod(struct kallsym_iter *iter)
432
{
433
if (module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value,
434
&iter->type, iter->name, iter->module_name,
435
&iter->exported) < 0)
436
return 0;
437
return 1;
438
}
439
440
/* Returns space to next name. */
441
static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
442
{
443
unsigned off = iter->nameoff;
444
445
iter->module_name[0] = '\0';
446
iter->value = kallsyms_addresses[iter->pos];
447
448
iter->type = kallsyms_get_symbol_type(off);
449
450
off = kallsyms_expand_symbol(off, iter->name);
451
452
return off - iter->nameoff;
453
}
454
455
static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
456
{
457
iter->name[0] = '\0';
458
iter->nameoff = get_symbol_offset(new_pos);
459
iter->pos = new_pos;
460
}
461
462
/* Returns false if pos at or past end of file. */
463
static int update_iter(struct kallsym_iter *iter, loff_t pos)
464
{
465
/* Module symbols can be accessed randomly. */
466
if (pos >= kallsyms_num_syms) {
467
iter->pos = pos;
468
return get_ksymbol_mod(iter);
469
}
470
471
/* If we're not on the desired position, reset to new position. */
472
if (pos != iter->pos)
473
reset_iter(iter, pos);
474
475
iter->nameoff += get_ksymbol_core(iter);
476
iter->pos++;
477
478
return 1;
479
}
480
481
static void *s_next(struct seq_file *m, void *p, loff_t *pos)
482
{
483
(*pos)++;
484
485
if (!update_iter(m->private, *pos))
486
return NULL;
487
return p;
488
}
489
490
static void *s_start(struct seq_file *m, loff_t *pos)
491
{
492
if (!update_iter(m->private, *pos))
493
return NULL;
494
return m->private;
495
}
496
497
static void s_stop(struct seq_file *m, void *p)
498
{
499
}
500
501
static int s_show(struct seq_file *m, void *p)
502
{
503
struct kallsym_iter *iter = m->private;
504
505
/* Some debugging symbols have no name. Ignore them. */
506
if (!iter->name[0])
507
return 0;
508
509
if (iter->module_name[0]) {
510
char type;
511
512
/*
513
* Label it "global" if it is exported,
514
* "local" if not exported.
515
*/
516
type = iter->exported ? toupper(iter->type) :
517
tolower(iter->type);
518
seq_printf(m, "%pK %c %s\t[%s]\n", (void *)iter->value,
519
type, iter->name, iter->module_name);
520
} else
521
seq_printf(m, "%pK %c %s\n", (void *)iter->value,
522
iter->type, iter->name);
523
return 0;
524
}
525
526
static const struct seq_operations kallsyms_op = {
527
.start = s_start,
528
.next = s_next,
529
.stop = s_stop,
530
.show = s_show
531
};
532
533
static int kallsyms_open(struct inode *inode, struct file *file)
534
{
535
/*
536
* We keep iterator in m->private, since normal case is to
537
* s_start from where we left off, so we avoid doing
538
* using get_symbol_offset for every symbol.
539
*/
540
struct kallsym_iter *iter;
541
int ret;
542
543
iter = kmalloc(sizeof(*iter), GFP_KERNEL);
544
if (!iter)
545
return -ENOMEM;
546
reset_iter(iter, 0);
547
548
ret = seq_open(file, &kallsyms_op);
549
if (ret == 0)
550
((struct seq_file *)file->private_data)->private = iter;
551
else
552
kfree(iter);
553
return ret;
554
}
555
556
#ifdef CONFIG_KGDB_KDB
557
const char *kdb_walk_kallsyms(loff_t *pos)
558
{
559
static struct kallsym_iter kdb_walk_kallsyms_iter;
560
if (*pos == 0) {
561
memset(&kdb_walk_kallsyms_iter, 0,
562
sizeof(kdb_walk_kallsyms_iter));
563
reset_iter(&kdb_walk_kallsyms_iter, 0);
564
}
565
while (1) {
566
if (!update_iter(&kdb_walk_kallsyms_iter, *pos))
567
return NULL;
568
++*pos;
569
/* Some debugging symbols have no name. Ignore them. */
570
if (kdb_walk_kallsyms_iter.name[0])
571
return kdb_walk_kallsyms_iter.name;
572
}
573
}
574
#endif /* CONFIG_KGDB_KDB */
575
576
static const struct file_operations kallsyms_operations = {
577
.open = kallsyms_open,
578
.read = seq_read,
579
.llseek = seq_lseek,
580
.release = seq_release_private,
581
};
582
583
static int __init kallsyms_init(void)
584
{
585
proc_create("kallsyms", 0444, NULL, &kallsyms_operations);
586
return 0;
587
}
588
device_initcall(kallsyms_init);
589
590