Commit ffc5089196446c08d9a005cf0dd7cab18d119606

Authored by Franck Bui-Huu
Committed by Linus Torvalds
1 parent 339b0c0813

[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>

Showing 3 changed files with 93 additions and 44 deletions Side-by-side Diff

include/linux/kallsyms.h
... ... @@ -12,6 +12,10 @@
12 12 /* Lookup the address for a symbol. Returns 0 if not found. */
13 13 unsigned long kallsyms_lookup_name(const char *name);
14 14  
  15 +extern int kallsyms_lookup_size_offset(unsigned long addr,
  16 + unsigned long *symbolsize,
  17 + unsigned long *offset);
  18 +
15 19 /* Lookup an address. modname is set to NULL if it's in the kernel. */
16 20 const char *kallsyms_lookup(unsigned long addr,
17 21 unsigned long *symbolsize,
... ... @@ -24,6 +28,13 @@
24 28 #else /* !CONFIG_KALLSYMS */
25 29  
26 30 static inline unsigned long kallsyms_lookup_name(const char *name)
  31 +{
  32 + return 0;
  33 +}
  34 +
  35 +static inline int kallsyms_lookup_size_offset(unsigned long addr,
  36 + unsigned long *symbolsize,
  37 + unsigned long *offset)
27 38 {
28 39 return 0;
29 40 }
... ... @@ -69,6 +69,15 @@
69 69 return in_gate_area_no_task(addr);
70 70 }
71 71  
  72 +static 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 81 /* expand a compressed symbol data into the resulting uncompressed string,
73 82 given the offset to where the symbol is in the compressed stream */
74 83 static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
75 84  
... ... @@ -155,7 +164,74 @@
155 164 return module_kallsyms_lookup_name(name);
156 165 }
157 166  
  167 +static 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 +
158 222 /*
  223 + * Lookup an address but don't bother to find any names.
  224 + */
  225 +int 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 +
  234 +/*
159 235 * Lookup an address
160 236 * - modname is set to NULL if it's in the kernel
161 237 * - we guarantee that the returned name is valid until we reschedule even if
162 238  
163 239  
164 240  
165 241  
166 242  
... ... @@ -167,57 +243,18 @@
167 243 unsigned long *offset,
168 244 char **modname, char *namebuf)
169 245 {
170   - unsigned long i, low, high, mid;
171 246 const char *msym;
172 247  
173   - /* This kernel should never had been booted. */
174   - BUG_ON(!kallsyms_addresses);
175   -
176 248 namebuf[KSYM_NAME_LEN] = 0;
177 249 namebuf[0] = 0;
178 250  
179   - if ((all_var && is_kernel(addr)) ||
180   - (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr) ||
181   - is_kernel_extratext(addr)))) {
182   - unsigned long symbol_end = 0;
  251 + if (is_ksym_addr(addr)) {
  252 + unsigned long pos;
183 253  
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   -
  254 + pos = get_symbol_pos(addr, symbolsize, offset);
199 255 /* Grab name */
200   - kallsyms_expand_symbol(get_symbol_offset(low), 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];
  256 + kallsyms_expand_symbol(get_symbol_offset(pos), namebuf);
219 257 *modname = NULL;
220   - *offset = addr - kallsyms_addresses[low];
221 258 return namebuf;
222 259 }
223 260  
... ... @@ -2040,7 +2040,8 @@
2040 2040 list_for_each_entry(mod, &modules, list) {
2041 2041 if (within(addr, mod->module_init, mod->init_size)
2042 2042 || within(addr, mod->module_core, mod->core_size)) {
2043   - *modname = mod->name;
  2043 + if (modname)
  2044 + *modname = mod->name;
2044 2045 return get_ksymbol(mod, addr, size, offset);
2045 2046 }
2046 2047 }