diff options
| author | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 11:59:11 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 11:59:11 -0500 |
| commit | 4522d58275f124105819723e24e912c8e5bf3cdd (patch) | |
| tree | b92c29014fadffe049c1925676037f0092b8d112 /kernel | |
| parent | 6cf24f031bc97cb5a7c9df3b6e73c45b628b2b28 (diff) | |
| parent | 64a26a731235b59c9d73bbe82c1f896d57400d37 (diff) | |
Merge branch 'for-linus' of git://one.firstfloor.org/home/andi/git/linux-2.6
* 'for-linus' of git://one.firstfloor.org/home/andi/git/linux-2.6: (156 commits)
[PATCH] x86-64: Export smp_call_function_single
[PATCH] i386: Clean up smp_tune_scheduling()
[PATCH] unwinder: move .eh_frame to RODATA
[PATCH] unwinder: fully support linker generated .eh_frame_hdr section
[PATCH] x86-64: don't use set_irq_regs()
[PATCH] x86-64: check vector in setup_ioapic_dest to verify if need setup_IO_APIC_irq
[PATCH] x86-64: Make ix86 default to HIGHMEM4G instead of NOHIGHMEM
[PATCH] i386: replace kmalloc+memset with kzalloc
[PATCH] x86-64: remove remaining pc98 code
[PATCH] x86-64: remove unused variable
[PATCH] x86-64: Fix constraints in atomic_add_return()
[PATCH] x86-64: fix asm constraints in i386 atomic_add_return
[PATCH] x86-64: Correct documentation for bzImage protocol v2.05
[PATCH] x86-64: replace kmalloc+memset with kzalloc in MTRR code
[PATCH] x86-64: Fix numaq build error
[PATCH] x86-64: include/asm-x86_64/cpufeature.h isn't a userspace header
[PATCH] unwinder: Add debugging output to the Dwarf2 unwinder
[PATCH] x86-64: Clarify error message in GART code
[PATCH] x86-64: Fix interrupt race in idle callback (3rd try)
[PATCH] x86-64: Remove unwind stack pointer alignment forcing again
...
Fixed conflict in include/linux/uaccess.h manually
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/fork.c | 2 | ||||
| -rw-r--r-- | kernel/lockdep.c | 4 | ||||
| -rw-r--r-- | kernel/sysctl.c | 9 | ||||
| -rw-r--r-- | kernel/unwind.c | 203 |
4 files changed, 173 insertions, 45 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 658838148647..7f2e31ba33af 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -1319,7 +1319,7 @@ fork_out: | |||
| 1319 | return ERR_PTR(retval); | 1319 | return ERR_PTR(retval); |
| 1320 | } | 1320 | } |
| 1321 | 1321 | ||
| 1322 | struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_regs *regs) | 1322 | noinline struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_regs *regs) |
| 1323 | { | 1323 | { |
| 1324 | memset(regs, 0, sizeof(struct pt_regs)); | 1324 | memset(regs, 0, sizeof(struct pt_regs)); |
| 1325 | return regs; | 1325 | return regs; |
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 62e73ce68197..b02032476dc2 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
| @@ -221,11 +221,7 @@ static int save_trace(struct stack_trace *trace) | |||
| 221 | trace->skip = 3; | 221 | trace->skip = 3; |
| 222 | trace->all_contexts = 0; | 222 | trace->all_contexts = 0; |
| 223 | 223 | ||
| 224 | /* Make sure to not recurse in case the the unwinder needs to tak | ||
| 225 | e locks. */ | ||
| 226 | lockdep_off(); | ||
| 227 | save_stack_trace(trace, NULL); | 224 | save_stack_trace(trace, NULL); |
| 228 | lockdep_on(); | ||
| 229 | 225 | ||
| 230 | trace->max_entries = trace->nr_entries; | 226 | trace->max_entries = trace->nr_entries; |
| 231 | 227 | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 758dbbf972a5..8e9f00fd6d18 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -54,6 +54,7 @@ extern int proc_nr_files(ctl_table *table, int write, struct file *filp, | |||
| 54 | 54 | ||
| 55 | #ifdef CONFIG_X86 | 55 | #ifdef CONFIG_X86 |
| 56 | #include <asm/nmi.h> | 56 | #include <asm/nmi.h> |
| 57 | #include <asm/stacktrace.h> | ||
| 57 | #endif | 58 | #endif |
| 58 | 59 | ||
| 59 | #if defined(CONFIG_SYSCTL) | 60 | #if defined(CONFIG_SYSCTL) |
| @@ -707,6 +708,14 @@ static ctl_table kern_table[] = { | |||
| 707 | .mode = 0444, | 708 | .mode = 0444, |
| 708 | .proc_handler = &proc_dointvec, | 709 | .proc_handler = &proc_dointvec, |
| 709 | }, | 710 | }, |
| 711 | { | ||
| 712 | .ctl_name = CTL_UNNUMBERED, | ||
| 713 | .procname = "kstack_depth_to_print", | ||
| 714 | .data = &kstack_depth_to_print, | ||
| 715 | .maxlen = sizeof(int), | ||
| 716 | .mode = 0644, | ||
| 717 | .proc_handler = &proc_dointvec, | ||
| 718 | }, | ||
| 710 | #endif | 719 | #endif |
| 711 | #if defined(CONFIG_MMU) | 720 | #if defined(CONFIG_MMU) |
| 712 | { | 721 | { |
diff --git a/kernel/unwind.c b/kernel/unwind.c index ed0a21d4a902..09c261329249 100644 --- a/kernel/unwind.c +++ b/kernel/unwind.c | |||
| @@ -14,11 +14,12 @@ | |||
| 14 | #include <linux/bootmem.h> | 14 | #include <linux/bootmem.h> |
| 15 | #include <linux/sort.h> | 15 | #include <linux/sort.h> |
| 16 | #include <linux/stop_machine.h> | 16 | #include <linux/stop_machine.h> |
| 17 | #include <linux/uaccess.h> | ||
| 17 | #include <asm/sections.h> | 18 | #include <asm/sections.h> |
| 18 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
| 19 | #include <asm/unaligned.h> | 20 | #include <asm/unaligned.h> |
| 20 | 21 | ||
| 21 | extern char __start_unwind[], __end_unwind[]; | 22 | extern const char __start_unwind[], __end_unwind[]; |
| 22 | extern const u8 __start_unwind_hdr[], __end_unwind_hdr[]; | 23 | extern const u8 __start_unwind_hdr[], __end_unwind_hdr[]; |
| 23 | 24 | ||
| 24 | #define MAX_STACK_DEPTH 8 | 25 | #define MAX_STACK_DEPTH 8 |
| @@ -94,6 +95,7 @@ static const struct { | |||
| 94 | 95 | ||
| 95 | typedef unsigned long uleb128_t; | 96 | typedef unsigned long uleb128_t; |
| 96 | typedef signed long sleb128_t; | 97 | typedef signed long sleb128_t; |
| 98 | #define sleb128abs __builtin_labs | ||
| 97 | 99 | ||
| 98 | static struct unwind_table { | 100 | static struct unwind_table { |
| 99 | struct { | 101 | struct { |
| @@ -135,6 +137,17 @@ struct unwind_state { | |||
| 135 | 137 | ||
| 136 | static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 }; | 138 | static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 }; |
| 137 | 139 | ||
| 140 | static unsigned unwind_debug; | ||
| 141 | static int __init unwind_debug_setup(char *s) | ||
| 142 | { | ||
| 143 | unwind_debug = simple_strtoul(s, NULL, 0); | ||
| 144 | return 1; | ||
| 145 | } | ||
| 146 | __setup("unwind_debug=", unwind_debug_setup); | ||
| 147 | #define dprintk(lvl, fmt, args...) \ | ||
| 148 | ((void)(lvl > unwind_debug \ | ||
| 149 | || printk(KERN_DEBUG "unwind: " fmt "\n", ##args))) | ||
| 150 | |||
| 138 | static struct unwind_table *find_table(unsigned long pc) | 151 | static struct unwind_table *find_table(unsigned long pc) |
| 139 | { | 152 | { |
| 140 | struct unwind_table *table; | 153 | struct unwind_table *table; |
| @@ -151,7 +164,9 @@ static struct unwind_table *find_table(unsigned long pc) | |||
| 151 | 164 | ||
| 152 | static unsigned long read_pointer(const u8 **pLoc, | 165 | static unsigned long read_pointer(const u8 **pLoc, |
| 153 | const void *end, | 166 | const void *end, |
| 154 | signed ptrType); | 167 | signed ptrType, |
| 168 | unsigned long text_base, | ||
| 169 | unsigned long data_base); | ||
| 155 | 170 | ||
| 156 | static void init_unwind_table(struct unwind_table *table, | 171 | static void init_unwind_table(struct unwind_table *table, |
| 157 | const char *name, | 172 | const char *name, |
| @@ -176,10 +191,13 @@ static void init_unwind_table(struct unwind_table *table, | |||
| 176 | /* See if the linker provided table looks valid. */ | 191 | /* See if the linker provided table looks valid. */ |
| 177 | if (header_size <= 4 | 192 | if (header_size <= 4 |
| 178 | || header_start[0] != 1 | 193 | || header_start[0] != 1 |
| 179 | || (void *)read_pointer(&ptr, end, header_start[1]) != table_start | 194 | || (void *)read_pointer(&ptr, end, header_start[1], 0, 0) |
| 180 | || header_start[2] == DW_EH_PE_omit | 195 | != table_start |
| 181 | || read_pointer(&ptr, end, header_start[2]) <= 0 | 196 | || !read_pointer(&ptr, end, header_start[2], 0, 0) |
| 182 | || header_start[3] == DW_EH_PE_omit) | 197 | || !read_pointer(&ptr, end, header_start[3], 0, |
| 198 | (unsigned long)header_start) | ||
| 199 | || !read_pointer(&ptr, end, header_start[3], 0, | ||
| 200 | (unsigned long)header_start)) | ||
| 183 | header_start = NULL; | 201 | header_start = NULL; |
| 184 | table->hdrsz = header_size; | 202 | table->hdrsz = header_size; |
| 185 | smp_wmb(); | 203 | smp_wmb(); |
| @@ -269,7 +287,7 @@ static void __init setup_unwind_table(struct unwind_table *table, | |||
| 269 | ptr = (const u8 *)(fde + 2); | 287 | ptr = (const u8 *)(fde + 2); |
| 270 | if (!read_pointer(&ptr, | 288 | if (!read_pointer(&ptr, |
| 271 | (const u8 *)(fde + 1) + *fde, | 289 | (const u8 *)(fde + 1) + *fde, |
| 272 | ptrType)) | 290 | ptrType, 0, 0)) |
| 273 | return; | 291 | return; |
| 274 | ++n; | 292 | ++n; |
| 275 | } | 293 | } |
| @@ -279,6 +297,7 @@ static void __init setup_unwind_table(struct unwind_table *table, | |||
| 279 | 297 | ||
| 280 | hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) | 298 | hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) |
| 281 | + 2 * n * sizeof(unsigned long); | 299 | + 2 * n * sizeof(unsigned long); |
| 300 | dprintk(2, "Binary lookup table size for %s: %lu bytes", table->name, hdrSize); | ||
| 282 | header = alloc(hdrSize); | 301 | header = alloc(hdrSize); |
| 283 | if (!header) | 302 | if (!header) |
| 284 | return; | 303 | return; |
| @@ -303,7 +322,7 @@ static void __init setup_unwind_table(struct unwind_table *table, | |||
| 303 | ptr = (const u8 *)(fde + 2); | 322 | ptr = (const u8 *)(fde + 2); |
| 304 | header->table[n].start = read_pointer(&ptr, | 323 | header->table[n].start = read_pointer(&ptr, |
| 305 | (const u8 *)(fde + 1) + *fde, | 324 | (const u8 *)(fde + 1) + *fde, |
| 306 | fde_pointer_type(cie)); | 325 | fde_pointer_type(cie), 0, 0); |
| 307 | header->table[n].fde = (unsigned long)fde; | 326 | header->table[n].fde = (unsigned long)fde; |
| 308 | ++n; | 327 | ++n; |
| 309 | } | 328 | } |
| @@ -486,7 +505,9 @@ static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table) | |||
| 486 | 505 | ||
| 487 | static unsigned long read_pointer(const u8 **pLoc, | 506 | static unsigned long read_pointer(const u8 **pLoc, |
| 488 | const void *end, | 507 | const void *end, |
| 489 | signed ptrType) | 508 | signed ptrType, |
| 509 | unsigned long text_base, | ||
| 510 | unsigned long data_base) | ||
| 490 | { | 511 | { |
| 491 | unsigned long value = 0; | 512 | unsigned long value = 0; |
| 492 | union { | 513 | union { |
| @@ -498,13 +519,17 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
| 498 | const unsigned long *pul; | 519 | const unsigned long *pul; |
| 499 | } ptr; | 520 | } ptr; |
| 500 | 521 | ||
| 501 | if (ptrType < 0 || ptrType == DW_EH_PE_omit) | 522 | if (ptrType < 0 || ptrType == DW_EH_PE_omit) { |
| 523 | dprintk(1, "Invalid pointer encoding %02X (%p,%p).", ptrType, *pLoc, end); | ||
| 502 | return 0; | 524 | return 0; |
| 525 | } | ||
| 503 | ptr.p8 = *pLoc; | 526 | ptr.p8 = *pLoc; |
| 504 | switch(ptrType & DW_EH_PE_FORM) { | 527 | switch(ptrType & DW_EH_PE_FORM) { |
| 505 | case DW_EH_PE_data2: | 528 | case DW_EH_PE_data2: |
| 506 | if (end < (const void *)(ptr.p16u + 1)) | 529 | if (end < (const void *)(ptr.p16u + 1)) { |
| 530 | dprintk(1, "Data16 overrun (%p,%p).", ptr.p8, end); | ||
| 507 | return 0; | 531 | return 0; |
| 532 | } | ||
| 508 | if(ptrType & DW_EH_PE_signed) | 533 | if(ptrType & DW_EH_PE_signed) |
| 509 | value = get_unaligned(ptr.p16s++); | 534 | value = get_unaligned(ptr.p16s++); |
| 510 | else | 535 | else |
| @@ -512,8 +537,10 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
| 512 | break; | 537 | break; |
| 513 | case DW_EH_PE_data4: | 538 | case DW_EH_PE_data4: |
| 514 | #ifdef CONFIG_64BIT | 539 | #ifdef CONFIG_64BIT |
| 515 | if (end < (const void *)(ptr.p32u + 1)) | 540 | if (end < (const void *)(ptr.p32u + 1)) { |
| 541 | dprintk(1, "Data32 overrun (%p,%p).", ptr.p8, end); | ||
| 516 | return 0; | 542 | return 0; |
| 543 | } | ||
| 517 | if(ptrType & DW_EH_PE_signed) | 544 | if(ptrType & DW_EH_PE_signed) |
| 518 | value = get_unaligned(ptr.p32s++); | 545 | value = get_unaligned(ptr.p32s++); |
| 519 | else | 546 | else |
| @@ -525,8 +552,10 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
| 525 | BUILD_BUG_ON(sizeof(u32) != sizeof(value)); | 552 | BUILD_BUG_ON(sizeof(u32) != sizeof(value)); |
| 526 | #endif | 553 | #endif |
| 527 | case DW_EH_PE_native: | 554 | case DW_EH_PE_native: |
| 528 | if (end < (const void *)(ptr.pul + 1)) | 555 | if (end < (const void *)(ptr.pul + 1)) { |
| 556 | dprintk(1, "DataUL overrun (%p,%p).", ptr.p8, end); | ||
| 529 | return 0; | 557 | return 0; |
| 558 | } | ||
| 530 | value = get_unaligned(ptr.pul++); | 559 | value = get_unaligned(ptr.pul++); |
| 531 | break; | 560 | break; |
| 532 | case DW_EH_PE_leb128: | 561 | case DW_EH_PE_leb128: |
| @@ -534,10 +563,14 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
| 534 | value = ptrType & DW_EH_PE_signed | 563 | value = ptrType & DW_EH_PE_signed |
| 535 | ? get_sleb128(&ptr.p8, end) | 564 | ? get_sleb128(&ptr.p8, end) |
| 536 | : get_uleb128(&ptr.p8, end); | 565 | : get_uleb128(&ptr.p8, end); |
| 537 | if ((const void *)ptr.p8 > end) | 566 | if ((const void *)ptr.p8 > end) { |
| 567 | dprintk(1, "DataLEB overrun (%p,%p).", ptr.p8, end); | ||
| 538 | return 0; | 568 | return 0; |
| 569 | } | ||
| 539 | break; | 570 | break; |
| 540 | default: | 571 | default: |
| 572 | dprintk(2, "Cannot decode pointer type %02X (%p,%p).", | ||
| 573 | ptrType, ptr.p8, end); | ||
| 541 | return 0; | 574 | return 0; |
| 542 | } | 575 | } |
| 543 | switch(ptrType & DW_EH_PE_ADJUST) { | 576 | switch(ptrType & DW_EH_PE_ADJUST) { |
| @@ -546,12 +579,33 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
| 546 | case DW_EH_PE_pcrel: | 579 | case DW_EH_PE_pcrel: |
| 547 | value += (unsigned long)*pLoc; | 580 | value += (unsigned long)*pLoc; |
| 548 | break; | 581 | break; |
| 582 | case DW_EH_PE_textrel: | ||
| 583 | if (likely(text_base)) { | ||
| 584 | value += text_base; | ||
| 585 | break; | ||
| 586 | } | ||
| 587 | dprintk(2, "Text-relative encoding %02X (%p,%p), but zero text base.", | ||
| 588 | ptrType, *pLoc, end); | ||
| 589 | return 0; | ||
| 590 | case DW_EH_PE_datarel: | ||
| 591 | if (likely(data_base)) { | ||
| 592 | value += data_base; | ||
| 593 | break; | ||
| 594 | } | ||
| 595 | dprintk(2, "Data-relative encoding %02X (%p,%p), but zero data base.", | ||
| 596 | ptrType, *pLoc, end); | ||
| 597 | return 0; | ||
| 549 | default: | 598 | default: |
| 599 | dprintk(2, "Cannot adjust pointer type %02X (%p,%p).", | ||
| 600 | ptrType, *pLoc, end); | ||
| 550 | return 0; | 601 | return 0; |
| 551 | } | 602 | } |
| 552 | if ((ptrType & DW_EH_PE_indirect) | 603 | if ((ptrType & DW_EH_PE_indirect) |
| 553 | && __get_user(value, (unsigned long *)value)) | 604 | && probe_kernel_address((unsigned long *)value, value)) { |
| 605 | dprintk(1, "Cannot read indirect value %lx (%p,%p).", | ||
| 606 | value, *pLoc, end); | ||
| 554 | return 0; | 607 | return 0; |
| 608 | } | ||
| 555 | *pLoc = ptr.p8; | 609 | *pLoc = ptr.p8; |
| 556 | 610 | ||
| 557 | return value; | 611 | return value; |
| @@ -594,7 +648,8 @@ static signed fde_pointer_type(const u32 *cie) | |||
| 594 | case 'P': { | 648 | case 'P': { |
| 595 | signed ptrType = *ptr++; | 649 | signed ptrType = *ptr++; |
| 596 | 650 | ||
| 597 | if (!read_pointer(&ptr, end, ptrType) || ptr > end) | 651 | if (!read_pointer(&ptr, end, ptrType, 0, 0) |
| 652 | || ptr > end) | ||
| 598 | return -1; | 653 | return -1; |
| 599 | } | 654 | } |
| 600 | break; | 655 | break; |
| @@ -654,7 +709,8 @@ static int processCFI(const u8 *start, | |||
| 654 | case DW_CFA_nop: | 709 | case DW_CFA_nop: |
| 655 | break; | 710 | break; |
| 656 | case DW_CFA_set_loc: | 711 | case DW_CFA_set_loc: |
| 657 | if ((state->loc = read_pointer(&ptr.p8, end, ptrType)) == 0) | 712 | state->loc = read_pointer(&ptr.p8, end, ptrType, 0, 0); |
| 713 | if (state->loc == 0) | ||
| 658 | result = 0; | 714 | result = 0; |
| 659 | break; | 715 | break; |
| 660 | case DW_CFA_advance_loc1: | 716 | case DW_CFA_advance_loc1: |
| @@ -700,8 +756,10 @@ static int processCFI(const u8 *start, | |||
| 700 | state->label = NULL; | 756 | state->label = NULL; |
| 701 | return 1; | 757 | return 1; |
| 702 | } | 758 | } |
| 703 | if (state->stackDepth >= MAX_STACK_DEPTH) | 759 | if (state->stackDepth >= MAX_STACK_DEPTH) { |
| 760 | dprintk(1, "State stack overflow (%p,%p).", ptr.p8, end); | ||
| 704 | return 0; | 761 | return 0; |
| 762 | } | ||
| 705 | state->stack[state->stackDepth++] = ptr.p8; | 763 | state->stack[state->stackDepth++] = ptr.p8; |
| 706 | break; | 764 | break; |
| 707 | case DW_CFA_restore_state: | 765 | case DW_CFA_restore_state: |
| @@ -716,8 +774,10 @@ static int processCFI(const u8 *start, | |||
| 716 | result = processCFI(start, end, 0, ptrType, state); | 774 | result = processCFI(start, end, 0, ptrType, state); |
| 717 | state->loc = loc; | 775 | state->loc = loc; |
| 718 | state->label = label; | 776 | state->label = label; |
| 719 | } else | 777 | } else { |
| 778 | dprintk(1, "State stack underflow (%p,%p).", ptr.p8, end); | ||
| 720 | return 0; | 779 | return 0; |
| 780 | } | ||
| 721 | break; | 781 | break; |
| 722 | case DW_CFA_def_cfa: | 782 | case DW_CFA_def_cfa: |
| 723 | state->cfa.reg = get_uleb128(&ptr.p8, end); | 783 | state->cfa.reg = get_uleb128(&ptr.p8, end); |
| @@ -749,6 +809,7 @@ static int processCFI(const u8 *start, | |||
| 749 | break; | 809 | break; |
| 750 | case DW_CFA_GNU_window_save: | 810 | case DW_CFA_GNU_window_save: |
| 751 | default: | 811 | default: |
| 812 | dprintk(1, "Unrecognized CFI op %02X (%p,%p).", ptr.p8[-1], ptr.p8 - 1, end); | ||
| 752 | result = 0; | 813 | result = 0; |
| 753 | break; | 814 | break; |
| 754 | } | 815 | } |
| @@ -764,12 +825,17 @@ static int processCFI(const u8 *start, | |||
| 764 | set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state); | 825 | set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state); |
| 765 | break; | 826 | break; |
| 766 | } | 827 | } |
| 767 | if (ptr.p8 > end) | 828 | if (ptr.p8 > end) { |
| 829 | dprintk(1, "Data overrun (%p,%p).", ptr.p8, end); | ||
| 768 | result = 0; | 830 | result = 0; |
| 831 | } | ||
| 769 | if (result && targetLoc != 0 && targetLoc < state->loc) | 832 | if (result && targetLoc != 0 && targetLoc < state->loc) |
| 770 | return 1; | 833 | return 1; |
| 771 | } | 834 | } |
| 772 | 835 | ||
| 836 | if (result && ptr.p8 < end) | ||
| 837 | dprintk(1, "Data underrun (%p,%p).", ptr.p8, end); | ||
| 838 | |||
| 773 | return result | 839 | return result |
| 774 | && ptr.p8 == end | 840 | && ptr.p8 == end |
| 775 | && (targetLoc == 0 | 841 | && (targetLoc == 0 |
| @@ -786,7 +852,7 @@ int unwind(struct unwind_frame_info *frame) | |||
| 786 | #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) | 852 | #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) |
| 787 | const u32 *fde = NULL, *cie = NULL; | 853 | const u32 *fde = NULL, *cie = NULL; |
| 788 | const u8 *ptr = NULL, *end = NULL; | 854 | const u8 *ptr = NULL, *end = NULL; |
| 789 | unsigned long pc = UNW_PC(frame) - frame->call_frame; | 855 | unsigned long pc = UNW_PC(frame) - frame->call_frame, sp; |
| 790 | unsigned long startLoc = 0, endLoc = 0, cfa; | 856 | unsigned long startLoc = 0, endLoc = 0, cfa; |
| 791 | unsigned i; | 857 | unsigned i; |
| 792 | signed ptrType = -1; | 858 | signed ptrType = -1; |
| @@ -813,9 +879,9 @@ int unwind(struct unwind_frame_info *frame) | |||
| 813 | ptr = hdr + 4; | 879 | ptr = hdr + 4; |
| 814 | end = hdr + table->hdrsz; | 880 | end = hdr + table->hdrsz; |
| 815 | if (tableSize | 881 | if (tableSize |
| 816 | && read_pointer(&ptr, end, hdr[1]) | 882 | && read_pointer(&ptr, end, hdr[1], 0, 0) |
| 817 | == (unsigned long)table->address | 883 | == (unsigned long)table->address |
| 818 | && (i = read_pointer(&ptr, end, hdr[2])) > 0 | 884 | && (i = read_pointer(&ptr, end, hdr[2], 0, 0)) > 0 |
| 819 | && i == (end - ptr) / (2 * tableSize) | 885 | && i == (end - ptr) / (2 * tableSize) |
| 820 | && !((end - ptr) % (2 * tableSize))) { | 886 | && !((end - ptr) % (2 * tableSize))) { |
| 821 | do { | 887 | do { |
| @@ -823,7 +889,8 @@ int unwind(struct unwind_frame_info *frame) | |||
| 823 | 889 | ||
| 824 | startLoc = read_pointer(&cur, | 890 | startLoc = read_pointer(&cur, |
| 825 | cur + tableSize, | 891 | cur + tableSize, |
| 826 | hdr[3]); | 892 | hdr[3], 0, |
| 893 | (unsigned long)hdr); | ||
| 827 | if (pc < startLoc) | 894 | if (pc < startLoc) |
| 828 | i /= 2; | 895 | i /= 2; |
| 829 | else { | 896 | else { |
| @@ -834,13 +901,17 @@ int unwind(struct unwind_frame_info *frame) | |||
| 834 | if (i == 1 | 901 | if (i == 1 |
| 835 | && (startLoc = read_pointer(&ptr, | 902 | && (startLoc = read_pointer(&ptr, |
| 836 | ptr + tableSize, | 903 | ptr + tableSize, |
| 837 | hdr[3])) != 0 | 904 | hdr[3], 0, |
| 905 | (unsigned long)hdr)) != 0 | ||
| 838 | && pc >= startLoc) | 906 | && pc >= startLoc) |
| 839 | fde = (void *)read_pointer(&ptr, | 907 | fde = (void *)read_pointer(&ptr, |
| 840 | ptr + tableSize, | 908 | ptr + tableSize, |
| 841 | hdr[3]); | 909 | hdr[3], 0, |
| 910 | (unsigned long)hdr); | ||
| 842 | } | 911 | } |
| 843 | } | 912 | } |
| 913 | if(hdr && !fde) | ||
| 914 | dprintk(3, "Binary lookup for %lx failed.", pc); | ||
| 844 | 915 | ||
| 845 | if (fde != NULL) { | 916 | if (fde != NULL) { |
| 846 | cie = cie_for_fde(fde, table); | 917 | cie = cie_for_fde(fde, table); |
| @@ -851,17 +922,19 @@ int unwind(struct unwind_frame_info *frame) | |||
| 851 | && (ptrType = fde_pointer_type(cie)) >= 0 | 922 | && (ptrType = fde_pointer_type(cie)) >= 0 |
| 852 | && read_pointer(&ptr, | 923 | && read_pointer(&ptr, |
| 853 | (const u8 *)(fde + 1) + *fde, | 924 | (const u8 *)(fde + 1) + *fde, |
| 854 | ptrType) == startLoc) { | 925 | ptrType, 0, 0) == startLoc) { |
| 855 | if (!(ptrType & DW_EH_PE_indirect)) | 926 | if (!(ptrType & DW_EH_PE_indirect)) |
| 856 | ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed; | 927 | ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed; |
| 857 | endLoc = startLoc | 928 | endLoc = startLoc |
| 858 | + read_pointer(&ptr, | 929 | + read_pointer(&ptr, |
| 859 | (const u8 *)(fde + 1) + *fde, | 930 | (const u8 *)(fde + 1) + *fde, |
| 860 | ptrType); | 931 | ptrType, 0, 0); |
| 861 | if(pc >= endLoc) | 932 | if(pc >= endLoc) |
| 862 | fde = NULL; | 933 | fde = NULL; |
| 863 | } else | 934 | } else |
| 864 | fde = NULL; | 935 | fde = NULL; |
| 936 | if(!fde) | ||
| 937 | dprintk(1, "Binary lookup result for %lx discarded.", pc); | ||
| 865 | } | 938 | } |
| 866 | if (fde == NULL) { | 939 | if (fde == NULL) { |
| 867 | for (fde = table->address, tableSize = table->size; | 940 | for (fde = table->address, tableSize = table->size; |
| @@ -881,7 +954,7 @@ int unwind(struct unwind_frame_info *frame) | |||
| 881 | ptr = (const u8 *)(fde + 2); | 954 | ptr = (const u8 *)(fde + 2); |
| 882 | startLoc = read_pointer(&ptr, | 955 | startLoc = read_pointer(&ptr, |
| 883 | (const u8 *)(fde + 1) + *fde, | 956 | (const u8 *)(fde + 1) + *fde, |
| 884 | ptrType); | 957 | ptrType, 0, 0); |
| 885 | if (!startLoc) | 958 | if (!startLoc) |
| 886 | continue; | 959 | continue; |
| 887 | if (!(ptrType & DW_EH_PE_indirect)) | 960 | if (!(ptrType & DW_EH_PE_indirect)) |
| @@ -889,10 +962,12 @@ int unwind(struct unwind_frame_info *frame) | |||
| 889 | endLoc = startLoc | 962 | endLoc = startLoc |
| 890 | + read_pointer(&ptr, | 963 | + read_pointer(&ptr, |
| 891 | (const u8 *)(fde + 1) + *fde, | 964 | (const u8 *)(fde + 1) + *fde, |
| 892 | ptrType); | 965 | ptrType, 0, 0); |
| 893 | if (pc >= startLoc && pc < endLoc) | 966 | if (pc >= startLoc && pc < endLoc) |
| 894 | break; | 967 | break; |
| 895 | } | 968 | } |
| 969 | if(!fde) | ||
| 970 | dprintk(3, "Linear lookup for %lx failed.", pc); | ||
| 896 | } | 971 | } |
| 897 | } | 972 | } |
| 898 | if (cie != NULL) { | 973 | if (cie != NULL) { |
| @@ -926,6 +1001,8 @@ int unwind(struct unwind_frame_info *frame) | |||
| 926 | if (ptr >= end || *ptr) | 1001 | if (ptr >= end || *ptr) |
| 927 | cie = NULL; | 1002 | cie = NULL; |
| 928 | } | 1003 | } |
| 1004 | if(!cie) | ||
| 1005 | dprintk(1, "CIE unusable (%p,%p).", ptr, end); | ||
| 929 | ++ptr; | 1006 | ++ptr; |
| 930 | } | 1007 | } |
| 931 | if (cie != NULL) { | 1008 | if (cie != NULL) { |
| @@ -935,7 +1012,12 @@ int unwind(struct unwind_frame_info *frame) | |||
| 935 | state.dataAlign = get_sleb128(&ptr, end); | 1012 | state.dataAlign = get_sleb128(&ptr, end); |
| 936 | if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end) | 1013 | if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end) |
| 937 | cie = NULL; | 1014 | cie = NULL; |
| 938 | else { | 1015 | else if (UNW_PC(frame) % state.codeAlign |
| 1016 | || UNW_SP(frame) % sleb128abs(state.dataAlign)) { | ||
| 1017 | dprintk(1, "Input pointer(s) misaligned (%lx,%lx).", | ||
| 1018 | UNW_PC(frame), UNW_SP(frame)); | ||
| 1019 | return -EPERM; | ||
| 1020 | } else { | ||
| 939 | retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end); | 1021 | retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end); |
| 940 | /* skip augmentation */ | 1022 | /* skip augmentation */ |
| 941 | if (((const char *)(cie + 2))[1] == 'z') { | 1023 | if (((const char *)(cie + 2))[1] == 'z') { |
| @@ -949,6 +1031,8 @@ int unwind(struct unwind_frame_info *frame) | |||
| 949 | || reg_info[retAddrReg].width != sizeof(unsigned long)) | 1031 | || reg_info[retAddrReg].width != sizeof(unsigned long)) |
| 950 | cie = NULL; | 1032 | cie = NULL; |
| 951 | } | 1033 | } |
| 1034 | if(!cie) | ||
| 1035 | dprintk(1, "CIE validation failed (%p,%p).", ptr, end); | ||
| 952 | } | 1036 | } |
| 953 | if (cie != NULL) { | 1037 | if (cie != NULL) { |
| 954 | state.cieStart = ptr; | 1038 | state.cieStart = ptr; |
| @@ -962,11 +1046,15 @@ int unwind(struct unwind_frame_info *frame) | |||
| 962 | if ((ptr += augSize) > end) | 1046 | if ((ptr += augSize) > end) |
| 963 | fde = NULL; | 1047 | fde = NULL; |
| 964 | } | 1048 | } |
| 1049 | if(!fde) | ||
| 1050 | dprintk(1, "FDE validation failed (%p,%p).", ptr, end); | ||
| 965 | } | 1051 | } |
| 966 | if (cie == NULL || fde == NULL) { | 1052 | if (cie == NULL || fde == NULL) { |
| 967 | #ifdef CONFIG_FRAME_POINTER | 1053 | #ifdef CONFIG_FRAME_POINTER |
| 968 | unsigned long top, bottom; | 1054 | unsigned long top, bottom; |
| 969 | 1055 | ||
| 1056 | if ((UNW_SP(frame) | UNW_FP(frame)) % sizeof(unsigned long)) | ||
| 1057 | return -EPERM; | ||
| 970 | top = STACK_TOP(frame->task); | 1058 | top = STACK_TOP(frame->task); |
| 971 | bottom = STACK_BOTTOM(frame->task); | 1059 | bottom = STACK_BOTTOM(frame->task); |
| 972 | # if FRAME_RETADDR_OFFSET < 0 | 1060 | # if FRAME_RETADDR_OFFSET < 0 |
| @@ -982,18 +1070,19 @@ int unwind(struct unwind_frame_info *frame) | |||
| 982 | & (sizeof(unsigned long) - 1))) { | 1070 | & (sizeof(unsigned long) - 1))) { |
| 983 | unsigned long link; | 1071 | unsigned long link; |
| 984 | 1072 | ||
| 985 | if (!__get_user(link, | 1073 | if (!probe_kernel_address( |
| 986 | (unsigned long *)(UNW_FP(frame) | 1074 | (unsigned long *)(UNW_FP(frame) |
| 987 | + FRAME_LINK_OFFSET)) | 1075 | + FRAME_LINK_OFFSET), |
| 1076 | link) | ||
| 988 | # if FRAME_RETADDR_OFFSET < 0 | 1077 | # if FRAME_RETADDR_OFFSET < 0 |
| 989 | && link > bottom && link < UNW_FP(frame) | 1078 | && link > bottom && link < UNW_FP(frame) |
| 990 | # else | 1079 | # else |
| 991 | && link > UNW_FP(frame) && link < bottom | 1080 | && link > UNW_FP(frame) && link < bottom |
| 992 | # endif | 1081 | # endif |
| 993 | && !(link & (sizeof(link) - 1)) | 1082 | && !(link & (sizeof(link) - 1)) |
| 994 | && !__get_user(UNW_PC(frame), | 1083 | && !probe_kernel_address( |
| 995 | (unsigned long *)(UNW_FP(frame) | 1084 | (unsigned long *)(UNW_FP(frame) |
| 996 | + FRAME_RETADDR_OFFSET))) { | 1085 | + FRAME_RETADDR_OFFSET), UNW_PC(frame))) { |
| 997 | UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET | 1086 | UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET |
| 998 | # if FRAME_RETADDR_OFFSET < 0 | 1087 | # if FRAME_RETADDR_OFFSET < 0 |
| 999 | - | 1088 | - |
| @@ -1016,8 +1105,11 @@ int unwind(struct unwind_frame_info *frame) | |||
| 1016 | || state.regs[retAddrReg].where == Nowhere | 1105 | || state.regs[retAddrReg].where == Nowhere |
| 1017 | || state.cfa.reg >= ARRAY_SIZE(reg_info) | 1106 | || state.cfa.reg >= ARRAY_SIZE(reg_info) |
| 1018 | || reg_info[state.cfa.reg].width != sizeof(unsigned long) | 1107 | || reg_info[state.cfa.reg].width != sizeof(unsigned long) |
| 1019 | || state.cfa.offs % sizeof(unsigned long)) | 1108 | || FRAME_REG(state.cfa.reg, unsigned long) % sizeof(unsigned long) |
| 1109 | || state.cfa.offs % sizeof(unsigned long)) { | ||
| 1110 | dprintk(1, "Unusable unwind info (%p,%p).", ptr, end); | ||
| 1020 | return -EIO; | 1111 | return -EIO; |
| 1112 | } | ||
| 1021 | /* update frame */ | 1113 | /* update frame */ |
| 1022 | #ifndef CONFIG_AS_CFI_SIGNAL_FRAME | 1114 | #ifndef CONFIG_AS_CFI_SIGNAL_FRAME |
| 1023 | if(frame->call_frame | 1115 | if(frame->call_frame |
| @@ -1036,10 +1128,14 @@ int unwind(struct unwind_frame_info *frame) | |||
| 1036 | #else | 1128 | #else |
| 1037 | # define CASES CASE(8); CASE(16); CASE(32); CASE(64) | 1129 | # define CASES CASE(8); CASE(16); CASE(32); CASE(64) |
| 1038 | #endif | 1130 | #endif |
| 1131 | pc = UNW_PC(frame); | ||
| 1132 | sp = UNW_SP(frame); | ||
| 1039 | for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { | 1133 | for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { |
| 1040 | if (REG_INVALID(i)) { | 1134 | if (REG_INVALID(i)) { |
| 1041 | if (state.regs[i].where == Nowhere) | 1135 | if (state.regs[i].where == Nowhere) |
| 1042 | continue; | 1136 | continue; |
| 1137 | dprintk(1, "Cannot restore register %u (%d).", | ||
| 1138 | i, state.regs[i].where); | ||
| 1043 | return -EIO; | 1139 | return -EIO; |
| 1044 | } | 1140 | } |
| 1045 | switch(state.regs[i].where) { | 1141 | switch(state.regs[i].where) { |
| @@ -1048,8 +1144,11 @@ int unwind(struct unwind_frame_info *frame) | |||
| 1048 | case Register: | 1144 | case Register: |
| 1049 | if (state.regs[i].value >= ARRAY_SIZE(reg_info) | 1145 | if (state.regs[i].value >= ARRAY_SIZE(reg_info) |
| 1050 | || REG_INVALID(state.regs[i].value) | 1146 | || REG_INVALID(state.regs[i].value) |
| 1051 | || reg_info[i].width > reg_info[state.regs[i].value].width) | 1147 | || reg_info[i].width > reg_info[state.regs[i].value].width) { |
| 1148 | dprintk(1, "Cannot restore register %u from register %lu.", | ||
| 1149 | i, state.regs[i].value); | ||
| 1052 | return -EIO; | 1150 | return -EIO; |
| 1151 | } | ||
| 1053 | switch(reg_info[state.regs[i].value].width) { | 1152 | switch(reg_info[state.regs[i].value].width) { |
| 1054 | #define CASE(n) \ | 1153 | #define CASE(n) \ |
| 1055 | case sizeof(u##n): \ | 1154 | case sizeof(u##n): \ |
| @@ -1059,6 +1158,9 @@ int unwind(struct unwind_frame_info *frame) | |||
| 1059 | CASES; | 1158 | CASES; |
| 1060 | #undef CASE | 1159 | #undef CASE |
| 1061 | default: | 1160 | default: |
| 1161 | dprintk(1, "Unsupported register size %u (%lu).", | ||
| 1162 | reg_info[state.regs[i].value].width, | ||
| 1163 | state.regs[i].value); | ||
| 1062 | return -EIO; | 1164 | return -EIO; |
| 1063 | } | 1165 | } |
| 1064 | break; | 1166 | break; |
| @@ -1083,12 +1185,17 @@ int unwind(struct unwind_frame_info *frame) | |||
| 1083 | CASES; | 1185 | CASES; |
| 1084 | #undef CASE | 1186 | #undef CASE |
| 1085 | default: | 1187 | default: |
| 1188 | dprintk(1, "Unsupported register size %u (%u).", | ||
| 1189 | reg_info[i].width, i); | ||
| 1086 | return -EIO; | 1190 | return -EIO; |
| 1087 | } | 1191 | } |
| 1088 | break; | 1192 | break; |
| 1089 | case Value: | 1193 | case Value: |
| 1090 | if (reg_info[i].width != sizeof(unsigned long)) | 1194 | if (reg_info[i].width != sizeof(unsigned long)) { |
| 1195 | dprintk(1, "Unsupported value size %u (%u).", | ||
| 1196 | reg_info[i].width, i); | ||
| 1091 | return -EIO; | 1197 | return -EIO; |
| 1198 | } | ||
| 1092 | FRAME_REG(i, unsigned long) = cfa + state.regs[i].value | 1199 | FRAME_REG(i, unsigned long) = cfa + state.regs[i].value |
| 1093 | * state.dataAlign; | 1200 | * state.dataAlign; |
| 1094 | break; | 1201 | break; |
| @@ -1100,15 +1207,20 @@ int unwind(struct unwind_frame_info *frame) | |||
| 1100 | % sizeof(unsigned long) | 1207 | % sizeof(unsigned long) |
| 1101 | || addr < startLoc | 1208 | || addr < startLoc |
| 1102 | || addr + sizeof(unsigned long) < addr | 1209 | || addr + sizeof(unsigned long) < addr |
| 1103 | || addr + sizeof(unsigned long) > endLoc) | 1210 | || addr + sizeof(unsigned long) > endLoc) { |
| 1211 | dprintk(1, "Bad memory location %lx (%lx).", | ||
| 1212 | addr, state.regs[i].value); | ||
| 1104 | return -EIO; | 1213 | return -EIO; |
| 1214 | } | ||
| 1105 | switch(reg_info[i].width) { | 1215 | switch(reg_info[i].width) { |
| 1106 | #define CASE(n) case sizeof(u##n): \ | 1216 | #define CASE(n) case sizeof(u##n): \ |
| 1107 | __get_user(FRAME_REG(i, u##n), (u##n *)addr); \ | 1217 | probe_kernel_address((u##n *)addr, FRAME_REG(i, u##n)); \ |
| 1108 | break | 1218 | break |
| 1109 | CASES; | 1219 | CASES; |
| 1110 | #undef CASE | 1220 | #undef CASE |
| 1111 | default: | 1221 | default: |
| 1222 | dprintk(1, "Unsupported memory size %u (%u).", | ||
| 1223 | reg_info[i].width, i); | ||
| 1112 | return -EIO; | 1224 | return -EIO; |
| 1113 | } | 1225 | } |
| 1114 | } | 1226 | } |
| @@ -1116,6 +1228,17 @@ int unwind(struct unwind_frame_info *frame) | |||
| 1116 | } | 1228 | } |
| 1117 | } | 1229 | } |
| 1118 | 1230 | ||
| 1231 | if (UNW_PC(frame) % state.codeAlign | ||
| 1232 | || UNW_SP(frame) % sleb128abs(state.dataAlign)) { | ||
| 1233 | dprintk(1, "Output pointer(s) misaligned (%lx,%lx).", | ||
| 1234 | UNW_PC(frame), UNW_SP(frame)); | ||
| 1235 | return -EIO; | ||
| 1236 | } | ||
| 1237 | if (pc == UNW_PC(frame) && sp == UNW_SP(frame)) { | ||
| 1238 | dprintk(1, "No progress (%lx,%lx).", pc, sp); | ||
| 1239 | return -EIO; | ||
| 1240 | } | ||
| 1241 | |||
| 1119 | return 0; | 1242 | return 0; |
| 1120 | #undef CASES | 1243 | #undef CASES |
| 1121 | #undef FRAME_REG | 1244 | #undef FRAME_REG |
