aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kallsyms.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kallsyms.c')
-rw-r--r--kernel/kallsyms.c123
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
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