diff options
Diffstat (limited to 'arch/arc/kernel/unwind.c')
-rw-r--r-- | arch/arc/kernel/unwind.c | 94 |
1 files changed, 38 insertions, 56 deletions
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c index 93c6ea52b671..5eb707640e9c 100644 --- a/arch/arc/kernel/unwind.c +++ b/arch/arc/kernel/unwind.c | |||
@@ -170,6 +170,23 @@ static struct unwind_table *find_table(unsigned long pc) | |||
170 | 170 | ||
171 | static unsigned long read_pointer(const u8 **pLoc, | 171 | static unsigned long read_pointer(const u8 **pLoc, |
172 | const void *end, signed ptrType); | 172 | const void *end, signed ptrType); |
173 | static void init_unwind_hdr(struct unwind_table *table, | ||
174 | void *(*alloc) (unsigned long)); | ||
175 | |||
176 | /* | ||
177 | * wrappers for header alloc (vs. calling one vs. other at call site) | ||
178 | * to elide section mismatches warnings | ||
179 | */ | ||
180 | static void *__init unw_hdr_alloc_early(unsigned long sz) | ||
181 | { | ||
182 | return __alloc_bootmem_nopanic(sz, sizeof(unsigned int), | ||
183 | MAX_DMA_ADDRESS); | ||
184 | } | ||
185 | |||
186 | static void *unw_hdr_alloc(unsigned long sz) | ||
187 | { | ||
188 | return kmalloc(sz, GFP_KERNEL); | ||
189 | } | ||
173 | 190 | ||
174 | static void init_unwind_table(struct unwind_table *table, const char *name, | 191 | static void init_unwind_table(struct unwind_table *table, const char *name, |
175 | const void *core_start, unsigned long core_size, | 192 | const void *core_start, unsigned long core_size, |
@@ -209,6 +226,8 @@ void __init arc_unwind_init(void) | |||
209 | __start_unwind, __end_unwind - __start_unwind, | 226 | __start_unwind, __end_unwind - __start_unwind, |
210 | NULL, 0); | 227 | NULL, 0); |
211 | /*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/ | 228 | /*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/ |
229 | |||
230 | init_unwind_hdr(&root_table, unw_hdr_alloc_early); | ||
212 | } | 231 | } |
213 | 232 | ||
214 | static const u32 bad_cie, not_fde; | 233 | static const u32 bad_cie, not_fde; |
@@ -241,8 +260,8 @@ static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size) | |||
241 | e2->fde = v; | 260 | e2->fde = v; |
242 | } | 261 | } |
243 | 262 | ||
244 | static void __init setup_unwind_table(struct unwind_table *table, | 263 | static void init_unwind_hdr(struct unwind_table *table, |
245 | void *(*alloc) (unsigned long)) | 264 | void *(*alloc) (unsigned long)) |
246 | { | 265 | { |
247 | const u8 *ptr; | 266 | const u8 *ptr; |
248 | unsigned long tableSize = table->size, hdrSize; | 267 | unsigned long tableSize = table->size, hdrSize; |
@@ -277,10 +296,10 @@ static void __init setup_unwind_table(struct unwind_table *table, | |||
277 | if (cie == ¬_fde) | 296 | if (cie == ¬_fde) |
278 | continue; | 297 | continue; |
279 | if (cie == NULL || cie == &bad_cie) | 298 | if (cie == NULL || cie == &bad_cie) |
280 | return; | 299 | goto ret_err; |
281 | ptrType = fde_pointer_type(cie); | 300 | ptrType = fde_pointer_type(cie); |
282 | if (ptrType < 0) | 301 | if (ptrType < 0) |
283 | return; | 302 | goto ret_err; |
284 | 303 | ||
285 | ptr = (const u8 *)(fde + 2); | 304 | ptr = (const u8 *)(fde + 2); |
286 | if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, | 305 | if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, |
@@ -296,13 +315,15 @@ static void __init setup_unwind_table(struct unwind_table *table, | |||
296 | } | 315 | } |
297 | 316 | ||
298 | if (tableSize || !n) | 317 | if (tableSize || !n) |
299 | return; | 318 | goto ret_err; |
300 | 319 | ||
301 | hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) | 320 | hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) |
302 | + 2 * n * sizeof(unsigned long); | 321 | + 2 * n * sizeof(unsigned long); |
322 | |||
303 | header = alloc(hdrSize); | 323 | header = alloc(hdrSize); |
304 | if (!header) | 324 | if (!header) |
305 | return; | 325 | goto ret_err; |
326 | |||
306 | header->version = 1; | 327 | header->version = 1; |
307 | header->eh_frame_ptr_enc = DW_EH_PE_abs | DW_EH_PE_native; | 328 | header->eh_frame_ptr_enc = DW_EH_PE_abs | DW_EH_PE_native; |
308 | header->fde_count_enc = DW_EH_PE_abs | DW_EH_PE_data4; | 329 | header->fde_count_enc = DW_EH_PE_abs | DW_EH_PE_data4; |
@@ -340,18 +361,10 @@ static void __init setup_unwind_table(struct unwind_table *table, | |||
340 | table->hdrsz = hdrSize; | 361 | table->hdrsz = hdrSize; |
341 | smp_wmb(); | 362 | smp_wmb(); |
342 | table->header = (const void *)header; | 363 | table->header = (const void *)header; |
343 | } | 364 | return; |
344 | |||
345 | static void *__init balloc(unsigned long sz) | ||
346 | { | ||
347 | return __alloc_bootmem_nopanic(sz, | ||
348 | sizeof(unsigned int), | ||
349 | __pa(MAX_DMA_ADDRESS)); | ||
350 | } | ||
351 | 365 | ||
352 | void __init arc_unwind_setup(void) | 366 | ret_err: |
353 | { | 367 | panic("Attention !!! Dwarf FDE parsing errors\n");; |
354 | setup_unwind_table(&root_table, balloc); | ||
355 | } | 368 | } |
356 | 369 | ||
357 | #ifdef CONFIG_MODULES | 370 | #ifdef CONFIG_MODULES |
@@ -377,6 +390,8 @@ void *unwind_add_table(struct module *module, const void *table_start, | |||
377 | table_start, table_size, | 390 | table_start, table_size, |
378 | NULL, 0); | 391 | NULL, 0); |
379 | 392 | ||
393 | init_unwind_hdr(table, unw_hdr_alloc); | ||
394 | |||
380 | #ifdef UNWIND_DEBUG | 395 | #ifdef UNWIND_DEBUG |
381 | unw_debug("Table added for [%s] %lx %lx\n", | 396 | unw_debug("Table added for [%s] %lx %lx\n", |
382 | module->name, table->core.pc, table->core.range); | 397 | module->name, table->core.pc, table->core.range); |
@@ -439,6 +454,7 @@ void unwind_remove_table(void *handle, int init_only) | |||
439 | info.init_only = init_only; | 454 | info.init_only = init_only; |
440 | 455 | ||
441 | unlink_table(&info); /* XXX: SMP */ | 456 | unlink_table(&info); /* XXX: SMP */ |
457 | kfree(table->header); | ||
442 | kfree(table); | 458 | kfree(table); |
443 | } | 459 | } |
444 | 460 | ||
@@ -588,9 +604,6 @@ static signed fde_pointer_type(const u32 *cie) | |||
588 | const u8 *ptr = (const u8 *)(cie + 2); | 604 | const u8 *ptr = (const u8 *)(cie + 2); |
589 | unsigned version = *ptr; | 605 | unsigned version = *ptr; |
590 | 606 | ||
591 | if (version != 1) | ||
592 | return -1; /* unsupported */ | ||
593 | |||
594 | if (*++ptr) { | 607 | if (*++ptr) { |
595 | const char *aug; | 608 | const char *aug; |
596 | const u8 *end = (const u8 *)(cie + 1) + *cie; | 609 | const u8 *end = (const u8 *)(cie + 1) + *cie; |
@@ -986,42 +999,13 @@ int arc_unwind(struct unwind_frame_info *frame) | |||
986 | (const u8 *)(fde + | 999 | (const u8 *)(fde + |
987 | 1) + | 1000 | 1) + |
988 | *fde, ptrType); | 1001 | *fde, ptrType); |
989 | if (pc >= endLoc) | 1002 | if (pc >= endLoc) { |
990 | fde = NULL; | 1003 | fde = NULL; |
991 | } else | ||
992 | fde = NULL; | ||
993 | } | ||
994 | if (fde == NULL) { | ||
995 | for (fde = table->address, tableSize = table->size; | ||
996 | cie = NULL, tableSize > sizeof(*fde) | ||
997 | && tableSize - sizeof(*fde) >= *fde; | ||
998 | tableSize -= sizeof(*fde) + *fde, | ||
999 | fde += 1 + *fde / sizeof(*fde)) { | ||
1000 | cie = cie_for_fde(fde, table); | ||
1001 | if (cie == &bad_cie) { | ||
1002 | cie = NULL; | 1004 | cie = NULL; |
1003 | break; | ||
1004 | } | 1005 | } |
1005 | if (cie == NULL | 1006 | } else { |
1006 | || cie == ¬_fde | 1007 | fde = NULL; |
1007 | || (ptrType = fde_pointer_type(cie)) < 0) | 1008 | cie = NULL; |
1008 | continue; | ||
1009 | ptr = (const u8 *)(fde + 2); | ||
1010 | startLoc = read_pointer(&ptr, | ||
1011 | (const u8 *)(fde + 1) + | ||
1012 | *fde, ptrType); | ||
1013 | if (!startLoc) | ||
1014 | continue; | ||
1015 | if (!(ptrType & DW_EH_PE_indirect)) | ||
1016 | ptrType &= | ||
1017 | DW_EH_PE_FORM | DW_EH_PE_signed; | ||
1018 | endLoc = | ||
1019 | startLoc + read_pointer(&ptr, | ||
1020 | (const u8 *)(fde + | ||
1021 | 1) + | ||
1022 | *fde, ptrType); | ||
1023 | if (pc >= startLoc && pc < endLoc) | ||
1024 | break; | ||
1025 | } | 1009 | } |
1026 | } | 1010 | } |
1027 | } | 1011 | } |
@@ -1031,9 +1015,7 @@ int arc_unwind(struct unwind_frame_info *frame) | |||
1031 | ptr = (const u8 *)(cie + 2); | 1015 | ptr = (const u8 *)(cie + 2); |
1032 | end = (const u8 *)(cie + 1) + *cie; | 1016 | end = (const u8 *)(cie + 1) + *cie; |
1033 | frame->call_frame = 1; | 1017 | frame->call_frame = 1; |
1034 | if ((state.version = *ptr) != 1) | 1018 | if (*++ptr) { |
1035 | cie = NULL; /* unsupported version */ | ||
1036 | else if (*++ptr) { | ||
1037 | /* check if augmentation size is first (thus present) */ | 1019 | /* check if augmentation size is first (thus present) */ |
1038 | if (*ptr == 'z') { | 1020 | if (*ptr == 'z') { |
1039 | while (++ptr < end && *ptr) { | 1021 | while (++ptr < end && *ptr) { |