/root/src/xen/xen/common/symbols.c
Line | Count | Source (jump to first uncovered line) |
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 | | */ |
12 | | |
13 | | #include <xen/symbols.h> |
14 | | #include <xen/kernel.h> |
15 | | #include <xen/init.h> |
16 | | #include <xen/lib.h> |
17 | | #include <xen/string.h> |
18 | | #include <xen/spinlock.h> |
19 | | #include <xen/virtual_region.h> |
20 | | #include <public/platform.h> |
21 | | #include <xen/guest_access.h> |
22 | | |
23 | | #ifdef SYMBOLS_ORIGIN |
24 | | extern const unsigned int symbols_offsets[]; |
25 | 0 | #define symbols_address(n) (SYMBOLS_ORIGIN + symbols_offsets[n]) |
26 | | #else |
27 | | extern const unsigned long symbols_addresses[]; |
28 | | #define symbols_address(n) symbols_addresses[n] |
29 | | #endif |
30 | | extern const unsigned int symbols_num_syms; |
31 | | extern const u8 symbols_names[]; |
32 | | |
33 | | extern const struct symbol_offset symbols_sorted_offsets[]; |
34 | | |
35 | | extern const u8 symbols_token_table[]; |
36 | | extern const u16 symbols_token_index[]; |
37 | | |
38 | | extern const unsigned int symbols_markers[]; |
39 | | |
40 | | /* expand a compressed symbol data into the resulting uncompressed string, |
41 | | given the offset to where the symbol is in the compressed stream */ |
42 | | static unsigned int symbols_expand_symbol(unsigned int off, char *result) |
43 | 0 | { |
44 | 0 | int len, skipped_first = 0; |
45 | 0 | const u8 *tptr, *data; |
46 | 0 |
|
47 | 0 | /* get the compressed symbol length from the first symbol byte */ |
48 | 0 | data = &symbols_names[off]; |
49 | 0 | len = *data; |
50 | 0 | data++; |
51 | 0 |
|
52 | 0 | /* update the offset to return the offset for the next symbol on |
53 | 0 | * the compressed stream */ |
54 | 0 | off += len + 1; |
55 | 0 |
|
56 | 0 | /* for every byte on the compressed symbol data, copy the table |
57 | 0 | entry for that byte */ |
58 | 0 | while(len) { |
59 | 0 | tptr = &symbols_token_table[ symbols_token_index[*data] ]; |
60 | 0 | data++; |
61 | 0 | len--; |
62 | 0 |
|
63 | 0 | while (*tptr) { |
64 | 0 | if(skipped_first) { |
65 | 0 | *result = *tptr; |
66 | 0 | result++; |
67 | 0 | } else |
68 | 0 | skipped_first = 1; |
69 | 0 | tptr++; |
70 | 0 | } |
71 | 0 | } |
72 | 0 |
|
73 | 0 | *result = '\0'; |
74 | 0 |
|
75 | 0 | /* return to offset to the next symbol */ |
76 | 0 | return off; |
77 | 0 | } |
78 | | |
79 | | /* find the offset on the compressed stream given and index in the |
80 | | * symbols array */ |
81 | | static unsigned int get_symbol_offset(unsigned long pos) |
82 | 0 | { |
83 | 0 | const u8 *name; |
84 | 0 | int i; |
85 | 0 |
|
86 | 0 | /* use the closest marker we have. We have markers every 256 positions, |
87 | 0 | * so that should be close enough */ |
88 | 0 | name = &symbols_names[ symbols_markers[pos>>8] ]; |
89 | 0 |
|
90 | 0 | /* sequentially scan all the symbols up to the point we're searching for. |
91 | 0 | * Every symbol is stored in a [<len>][<len> bytes of data] format, so we |
92 | 0 | * just need to add the len to the current pointer for every symbol we |
93 | 0 | * wish to skip */ |
94 | 0 | for(i = 0; i < (pos&0xFF); i++) |
95 | 0 | name = name + (*name) + 1; |
96 | 0 |
|
97 | 0 | return name - symbols_names; |
98 | 0 | } |
99 | | |
100 | | bool_t is_active_kernel_text(unsigned long addr) |
101 | 2 | { |
102 | 2 | return !!find_text_region(addr); |
103 | 2 | } |
104 | | |
105 | | const char *symbols_lookup(unsigned long addr, |
106 | | unsigned long *symbolsize, |
107 | | unsigned long *offset, |
108 | | char *namebuf) |
109 | 3 | { |
110 | 3 | unsigned long i, low, high, mid; |
111 | 3 | unsigned long symbol_end = 0; |
112 | 3 | const struct virtual_region *region; |
113 | 3 | |
114 | 3 | namebuf[KSYM_NAME_LEN] = 0; |
115 | 3 | namebuf[0] = 0; |
116 | 3 | |
117 | 3 | region = find_text_region(addr); |
118 | 3 | if (!region) |
119 | 3 | return NULL; |
120 | 3 | |
121 | 0 | if (region->symbols_lookup) |
122 | 0 | return region->symbols_lookup(addr, symbolsize, offset, namebuf); |
123 | 0 |
|
124 | 0 | /* do a binary search on the sorted symbols_addresses array */ |
125 | 0 | low = 0; |
126 | 0 | high = symbols_num_syms; |
127 | 0 |
|
128 | 0 | while (high-low > 1) { |
129 | 0 | mid = (low + high) / 2; |
130 | 0 | if (symbols_address(mid) <= addr) low = mid; |
131 | 0 | else high = mid; |
132 | 0 | } |
133 | 0 |
|
134 | 0 | /* search for the first aliased symbol. Aliased symbols are |
135 | 0 | symbols with the same address */ |
136 | 0 | while (low && symbols_address(low - 1) == symbols_address(low)) |
137 | 0 | --low; |
138 | 0 |
|
139 | 0 | /* Grab name */ |
140 | 0 | symbols_expand_symbol(get_symbol_offset(low), namebuf); |
141 | 0 |
|
142 | 0 | /* Search for next non-aliased symbol */ |
143 | 0 | for (i = low + 1; i < symbols_num_syms; i++) { |
144 | 0 | if (symbols_address(i) > symbols_address(low)) { |
145 | 0 | symbol_end = symbols_address(i); |
146 | 0 | break; |
147 | 0 | } |
148 | 0 | } |
149 | 0 |
|
150 | 0 | /* if we found no next symbol, we use the end of the section */ |
151 | 0 | if (!symbol_end) |
152 | 0 | symbol_end = is_kernel_inittext(addr) ? |
153 | 0 | (unsigned long)_einittext : (unsigned long)_etext; |
154 | 0 |
|
155 | 0 | *symbolsize = symbol_end - symbols_address(low); |
156 | 0 | *offset = addr - symbols_address(low); |
157 | 0 | return namebuf; |
158 | 0 | } |
159 | | |
160 | | /* |
161 | | * Get symbol type information. This is encoded as a single char at the |
162 | | * beginning of the symbol name. |
163 | | */ |
164 | | static char symbols_get_symbol_type(unsigned int off) |
165 | 0 | { |
166 | 0 | /* |
167 | 0 | * Get just the first code, look it up in the token table, |
168 | 0 | * and return the first char from this token. |
169 | 0 | */ |
170 | 0 | return symbols_token_table[symbols_token_index[symbols_names[off + 1]]]; |
171 | 0 | } |
172 | | |
173 | | int xensyms_read(uint32_t *symnum, char *type, |
174 | | unsigned long *address, char *name) |
175 | 0 | { |
176 | 0 | /* |
177 | 0 | * Symbols are most likely accessed sequentially so we remember position |
178 | 0 | * from previous read. This can help us avoid the extra call to |
179 | 0 | * get_symbol_offset(). |
180 | 0 | */ |
181 | 0 | static uint64_t next_symbol, next_offset; |
182 | 0 | static DEFINE_SPINLOCK(symbols_mutex); |
183 | 0 |
|
184 | 0 | if ( *symnum > symbols_num_syms ) |
185 | 0 | return -ERANGE; |
186 | 0 | if ( *symnum == symbols_num_syms ) |
187 | 0 | { |
188 | 0 | /* No more symbols */ |
189 | 0 | name[0] = '\0'; |
190 | 0 | return 0; |
191 | 0 | } |
192 | 0 |
|
193 | 0 | spin_lock(&symbols_mutex); |
194 | 0 |
|
195 | 0 | if ( *symnum == 0 ) |
196 | 0 | next_offset = next_symbol = 0; |
197 | 0 | if ( next_symbol != *symnum ) |
198 | 0 | /* Non-sequential access */ |
199 | 0 | next_offset = get_symbol_offset(*symnum); |
200 | 0 |
|
201 | 0 | *type = symbols_get_symbol_type(next_offset); |
202 | 0 | next_offset = symbols_expand_symbol(next_offset, name); |
203 | 0 | *address = symbols_address(*symnum); |
204 | 0 |
|
205 | 0 | next_symbol = ++*symnum; |
206 | 0 |
|
207 | 0 | spin_unlock(&symbols_mutex); |
208 | 0 |
|
209 | 0 | return 0; |
210 | 0 | } |
211 | | |
212 | | unsigned long symbols_lookup_by_name(const char *symname) |
213 | 0 | { |
214 | 0 | char name[KSYM_NAME_LEN + 1]; |
215 | 0 | #ifdef CONFIG_FAST_SYMBOL_LOOKUP |
216 | | unsigned long low, high; |
217 | | #else |
218 | 0 | uint32_t symnum = 0; |
219 | 0 | char type; |
220 | 0 | unsigned long addr; |
221 | 0 | int rc; |
222 | 0 | #endif |
223 | 0 |
|
224 | 0 | if ( *symname == '\0' ) |
225 | 0 | return 0; |
226 | 0 |
|
227 | 0 | #ifdef CONFIG_FAST_SYMBOL_LOOKUP |
228 | | low = 0; |
229 | | high = symbols_num_syms; |
230 | | while ( low < high ) |
231 | | { |
232 | | unsigned long mid = low + ((high - low) / 2); |
233 | | const struct symbol_offset *s; |
234 | | int rc; |
235 | | |
236 | | s = &symbols_sorted_offsets[mid]; |
237 | | (void)symbols_expand_symbol(s->stream, name); |
238 | | /* Format is: [filename]#<symbol>. symbols_expand_symbol eats type.*/ |
239 | | rc = strcmp(symname, name); |
240 | | if ( rc < 0 ) |
241 | | high = mid; |
242 | | else if ( rc > 0 ) |
243 | | low = mid + 1; |
244 | | else |
245 | | return symbols_address(s->addr); |
246 | | } |
247 | | #else |
248 | 0 | do { |
249 | 0 | rc = xensyms_read(&symnum, &type, &addr, name); |
250 | 0 | if ( rc ) |
251 | 0 | break; |
252 | 0 |
|
253 | 0 | if ( !strcmp(name, symname) ) |
254 | 0 | return addr; |
255 | 0 |
|
256 | 0 | } while ( name[0] != '\0' ); |
257 | 0 |
|
258 | 0 | #endif |
259 | 0 | return 0; |
260 | 0 | } |
261 | | |
262 | | /* |
263 | | * Local variables: |
264 | | * mode: C |
265 | | * c-file-style: "BSD" |
266 | | * c-basic-offset: 4 |
267 | | * tab-width: 4 |
268 | | * indent-tabs-mode: nil |
269 | | * End: |
270 | | */ |