ia64/xen-unstable

view xen/common/symbols.c @ 6538:84ee014ebd41

Merge xen-vtx-unstable.hg
author adsharma@los-vmm.sc.intel.com
date Wed Aug 17 12:34:38 2005 -0800 (2005-08-17)
parents 23979fb12c49 f294acb25858
children 99914b54f7bf
line source
1 /*
2 * symbols.c: in-kernel printing of symbolic oopses and stack traces.
3 *
4 * Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
5 *
6 * ChangeLog:
7 *
8 * (25/Aug/2004) Paulo Marques <pmarques@grupopie.com>
9 * Changed the compression method from stem compression to "table lookup"
10 * compression (see tools/symbols.c for a more complete description)
11 */
13 #include <xen/config.h>
14 #include <xen/symbols.h>
15 #include <xen/init.h>
16 #include <xen/lib.h>
17 #include <xen/string.h>
19 /* These will be re-linked against their real values during the second link stage */
20 extern unsigned long symbols_addresses[] __attribute__((weak));
21 extern unsigned long symbols_num_syms __attribute__((weak,section("data")));
22 extern u8 symbols_names[] __attribute__((weak));
24 extern u8 symbols_token_table[] __attribute__((weak));
25 extern u16 symbols_token_index[] __attribute__((weak));
27 extern unsigned long symbols_markers[] __attribute__((weak));
29 /* expand a compressed symbol data into the resulting uncompressed string,
30 given the offset to where the symbol is in the compressed stream */
31 static unsigned int symbols_expand_symbol(unsigned int off, char *result)
32 {
33 int len, skipped_first = 0;
34 u8 *tptr, *data;
36 /* get the compressed symbol length from the first symbol byte */
37 data = &symbols_names[off];
38 len = *data;
39 data++;
41 /* update the offset to return the offset for the next symbol on
42 * the compressed stream */
43 off += len + 1;
45 /* for every byte on the compressed symbol data, copy the table
46 entry for that byte */
47 while(len) {
48 tptr = &symbols_token_table[ symbols_token_index[*data] ];
49 data++;
50 len--;
52 while (*tptr) {
53 if(skipped_first) {
54 *result = *tptr;
55 result++;
56 } else
57 skipped_first = 1;
58 tptr++;
59 }
60 }
62 *result = '\0';
64 /* return to offset to the next symbol */
65 return off;
66 }
68 /* find the offset on the compressed stream given and index in the
69 * symbols array */
70 static unsigned int get_symbol_offset(unsigned long pos)
71 {
72 u8 *name;
73 int i;
75 /* use the closest marker we have. We have markers every 256 positions,
76 * so that should be close enough */
77 name = &symbols_names[ symbols_markers[pos>>8] ];
79 /* sequentially scan all the symbols up to the point we're searching for.
80 * Every symbol is stored in a [<len>][<len> bytes of data] format, so we
81 * just need to add the len to the current pointer for every symbol we
82 * wish to skip */
83 for(i = 0; i < (pos&0xFF); i++)
84 name = name + (*name) + 1;
86 return name - symbols_names;
87 }
89 const char *symbols_lookup(unsigned long addr,
90 unsigned long *symbolsize,
91 unsigned long *offset,
92 char *namebuf)
93 {
94 unsigned long i, low, high, mid;
95 unsigned long symbol_end = 0;
97 /* This kernel should never had been booted. */
98 BUG_ON(!symbols_addresses);
100 namebuf[KSYM_NAME_LEN] = 0;
101 namebuf[0] = 0;
103 if (!is_kernel_text(addr))
104 return NULL;
106 /* do a binary search on the sorted symbols_addresses array */
107 low = 0;
108 high = symbols_num_syms;
110 while (high-low > 1) {
111 mid = (low + high) / 2;
112 if (symbols_addresses[mid] <= addr) low = mid;
113 else high = mid;
114 }
116 /* search for the first aliased symbol. Aliased symbols are
117 symbols with the same address */
118 while (low && symbols_addresses[low - 1] == symbols_addresses[low])
119 --low;
121 /* Grab name */
122 symbols_expand_symbol(get_symbol_offset(low), namebuf);
124 /* Search for next non-aliased symbol */
125 for (i = low + 1; i < symbols_num_syms; i++) {
126 if (symbols_addresses[i] > symbols_addresses[low]) {
127 symbol_end = symbols_addresses[i];
128 break;
129 }
130 }
132 /* if we found no next symbol, we use the end of the section */
133 if (!symbol_end)
134 symbol_end = kernel_text_end();
136 *symbolsize = symbol_end - symbols_addresses[low];
137 *offset = addr - symbols_addresses[low];
138 return namebuf;
139 }
141 /* Replace "%s" in format with address, or returns -errno. */
142 void __print_symbol(const char *fmt, unsigned long address)
143 {
144 const char *name;
145 unsigned long offset, size;
146 char namebuf[KSYM_NAME_LEN+1];
147 char buffer[sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN +
148 2*(BITS_PER_LONG*3/10) + 1];
150 name = symbols_lookup(address, &size, &offset, namebuf);
152 if (!name)
153 sprintf(buffer, "???");
154 else
155 sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
157 printk(fmt, buffer);
158 }