aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFranck Bui-Huu <vagabon.xyz@gmail.com>2006-10-03 04:13:48 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-03 11:03:41 -0400
commitffc5089196446c08d9a005cf0dd7cab18d119606 (patch)
treee15925251553152f6859c354e34afe3adfcd1c64
parent339b0c0813a257893fa84be999b9b85a50846dd8 (diff)
[PATCH] Create kallsyms_lookup_size_offset()
Some uses of kallsyms_lookup() do not need to find out the name of a symbol and its module's name it belongs. This is specially true in arch specific code, which needs to unwind the stack to show the back trace during oops (mips is an example). In this specific case, we just need to retreive the function's size and the offset of the active intruction inside it. Adds a new entry "kallsyms_lookup_size_offset()" This new entry does exactly the same as kallsyms_lookup() but does not require any buffers to store any names. It returns 0 if it fails otherwise 1. Signed-off-by: Franck Bui-Huu <vagabon.xyz@gmail.com> Cc: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/kallsyms.h11
-rw-r--r--kernel/kallsyms.c123
-rw-r--r--kernel/module.c3
3 files changed, 93 insertions, 44 deletions
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
index 849043ce4ed6..1cebcbc28b47 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -12,6 +12,10 @@
12/* Lookup the address for a symbol. Returns 0 if not found. */ 12/* Lookup the address for a symbol. Returns 0 if not found. */
13unsigned long kallsyms_lookup_name(const char *name); 13unsigned long kallsyms_lookup_name(const char *name);
14 14
15extern int kallsyms_lookup_size_offset(unsigned long addr,
16 unsigned long *symbolsize,
17 unsigned long *offset);
18
15/* Lookup an address. modname is set to NULL if it's in the kernel. */ 19/* Lookup an address. modname is set to NULL if it's in the kernel. */
16const char *kallsyms_lookup(unsigned long addr, 20const char *kallsyms_lookup(unsigned long addr,
17 unsigned long *symbolsize, 21 unsigned long *symbolsize,
@@ -28,6 +32,13 @@ static inline unsigned long kallsyms_lookup_name(const char *name)
28 return 0; 32 return 0;
29} 33}
30 34
35static inline int kallsyms_lookup_size_offset(unsigned long addr,
36 unsigned long *symbolsize,
37 unsigned long *offset)
38{
39 return 0;
40}
41
31static inline const char *kallsyms_lookup(unsigned long addr, 42static inline const char *kallsyms_lookup(unsigned long addr,
32 unsigned long *symbolsize, 43 unsigned long *symbolsize,
33 unsigned long *offset, 44 unsigned long *offset,
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 342bca62c496..eeac3e313b2b 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -69,6 +69,15 @@ static inline int is_kernel(unsigned long addr)
69 return in_gate_area_no_task(addr); 69 return in_gate_area_no_task(addr);
70} 70}
71 71
72static int is_ksym_addr(unsigned long addr)
73{
74 if (all_var)
75 return is_kernel(addr);
76
77 return is_kernel_text(addr) || is_kernel_inittext(addr) ||
78 is_kernel_extratext(addr);
79}
80
72/* expand a compressed symbol data into the resulting uncompressed string, 81/* expand a compressed symbol data into the resulting uncompressed string,
73 given the offset to where the symbol is in the compressed stream */ 82 given the offset to where the symbol is in the compressed stream */
74static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) 83static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
@@ -155,6 +164,73 @@ unsigned long kallsyms_lookup_name(const char *name)
155 return module_kallsyms_lookup_name(name); 164 return module_kallsyms_lookup_name(name);
156} 165}
157 166
167static unsigned long get_symbol_pos(unsigned long addr,
168 unsigned long *symbolsize,
169 unsigned long *offset)
170{
171 unsigned long symbol_start = 0, symbol_end = 0;
172 unsigned long i, low, high, mid;
173
174 /* This kernel should never had been booted. */
175 BUG_ON(!kallsyms_addresses);
176
177 /* do a binary search on the sorted kallsyms_addresses array */
178 low = 0;
179 high = kallsyms_num_syms;
180
181 while (high - low > 1) {
182 mid = (low + high) / 2;
183 if (kallsyms_addresses[mid] <= addr)
184 low = mid;
185 else
186 high = mid;
187 }
188
189 /*
190 * search for the first aliased symbol. Aliased
191 * symbols are symbols with the same address
192 */
193 while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low])
194 --low;
195
196 symbol_start = kallsyms_addresses[low];
197
198 /* Search for next non-aliased symbol */
199 for (i = low + 1; i < kallsyms_num_syms; i++) {
200 if (kallsyms_addresses[i] > symbol_start) {
201 symbol_end = kallsyms_addresses[i];
202 break;
203 }
204 }
205
206 /* if we found no next symbol, we use the end of the section */
207 if (!symbol_end) {
208 if (is_kernel_inittext(addr))
209 symbol_end = (unsigned long)_einittext;
210 else if (all_var)
211 symbol_end = (unsigned long)_end;
212 else
213 symbol_end = (unsigned long)_etext;
214 }
215
216 *symbolsize = symbol_end - symbol_start;
217 *offset = addr - symbol_start;
218
219 return low;
220}
221
222/*
223 * Lookup an address but don't bother to find any names.
224 */
225int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
226 unsigned long *offset)
227{
228 if (is_ksym_addr(addr))
229 return !!get_symbol_pos(addr, symbolsize, offset);
230
231 return !!module_address_lookup(addr, symbolsize, offset, NULL);
232}
233
158/* 234/*
159 * Lookup an address 235 * Lookup an address
160 * - modname is set to NULL if it's in the kernel 236 * - modname is set to NULL if it's in the kernel
@@ -167,57 +243,18 @@ const char *kallsyms_lookup(unsigned long addr,
167 unsigned long *offset, 243 unsigned long *offset,
168 char **modname, char *namebuf) 244 char **modname, char *namebuf)
169{ 245{
170 unsigned long i, low, high, mid;
171 const char *msym; 246 const char *msym;
172 247
173 /* This kernel should never had been booted. */
174 BUG_ON(!kallsyms_addresses);
175
176 namebuf[KSYM_NAME_LEN] = 0; 248 namebuf[KSYM_NAME_LEN] = 0;
177 namebuf[0] = 0; 249 namebuf[0] = 0;
178 250
179 if ((all_var && is_kernel(addr)) || 251 if (is_ksym_addr(addr)) {
180 (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr) || 252 unsigned long pos;
181 is_kernel_extratext(addr)))) {
182 unsigned long symbol_end = 0;
183
184 /* do a binary search on the sorted kallsyms_addresses array */
185 low = 0;
186 high = kallsyms_num_syms;
187
188 while (high-low > 1) {
189 mid = (low + high) / 2;
190 if (kallsyms_addresses[mid] <= addr) low = mid;
191 else high = mid;
192 }
193
194 /* search for the first aliased symbol. Aliased symbols are
195 symbols with the same address */
196 while (low && kallsyms_addresses[low - 1] == kallsyms_addresses[low])
197 --low;
198 253
254 pos = get_symbol_pos(addr, symbolsize, offset);
199 /* Grab name */ 255 /* Grab name */
200 kallsyms_expand_symbol(get_symbol_offset(low), namebuf); 256 kallsyms_expand_symbol(get_symbol_offset(pos), namebuf);
201
202 /* Search for next non-aliased symbol */
203 for (i = low + 1; i < kallsyms_num_syms; i++) {
204 if (kallsyms_addresses[i] > kallsyms_addresses[low]) {
205 symbol_end = kallsyms_addresses[i];
206 break;
207 }
208 }
209
210 /* if we found no next symbol, we use the end of the section */
211 if (!symbol_end) {
212 if (is_kernel_inittext(addr))
213 symbol_end = (unsigned long)_einittext;
214 else
215 symbol_end = all_var ? (unsigned long)_end : (unsigned long)_etext;
216 }
217
218 *symbolsize = symbol_end - kallsyms_addresses[low];
219 *modname = NULL; 257 *modname = NULL;
220 *offset = addr - kallsyms_addresses[low];
221 return namebuf; 258 return namebuf;
222 } 259 }
223 260
diff --git a/kernel/module.c b/kernel/module.c
index 7c77a0a9275c..7f60e782de1e 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2040,7 +2040,8 @@ const char *module_address_lookup(unsigned long addr,
2040 list_for_each_entry(mod, &modules, list) { 2040 list_for_each_entry(mod, &modules, list) {
2041 if (within(addr, mod->module_init, mod->init_size) 2041 if (within(addr, mod->module_init, mod->init_size)
2042 || within(addr, mod->module_core, mod->core_size)) { 2042 || within(addr, mod->module_core, mod->core_size)) {
2043 *modname = mod->name; 2043 if (modname)
2044 *modname = mod->name;
2044 return get_ksymbol(mod, addr, size, offset); 2045 return get_ksymbol(mod, addr, size, offset);
2045 } 2046 }
2046 } 2047 }