diff options
Diffstat (limited to 'kernel/kallsyms.c')
-rw-r--r-- | kernel/kallsyms.c | 123 |
1 files changed, 80 insertions, 43 deletions
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 | ||
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 | /* 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 */ |
74 | static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) | 83 | static 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 | ||
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 | |||
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 | |||
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 | ||