diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 3 | ||||
-rw-r--r-- | kernel/unwind.c | 113 |
2 files changed, 99 insertions, 17 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 4e90aa427aea..d34fd6a28faa 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -1735,6 +1735,9 @@ and is between 256 and 4096 characters. It is defined in the file | |||
1735 | norandmaps Don't use address space randomization | 1735 | norandmaps Don't use address space randomization |
1736 | Equivalent to echo 0 > /proc/sys/kernel/randomize_va_space | 1736 | Equivalent to echo 0 > /proc/sys/kernel/randomize_va_space |
1737 | 1737 | ||
1738 | unwind_debug=N N > 0 will enable dwarf2 unwinder debugging | ||
1739 | This is useful to get more information why | ||
1740 | you got a "dwarf2 unwinder stuck" | ||
1738 | 1741 | ||
1739 | ______________________________________________________________________ | 1742 | ______________________________________________________________________ |
1740 | 1743 | ||
diff --git a/kernel/unwind.c b/kernel/unwind.c index 7e721f104105..209e248517db 100644 --- a/kernel/unwind.c +++ b/kernel/unwind.c | |||
@@ -137,6 +137,17 @@ struct unwind_state { | |||
137 | 137 | ||
138 | static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 }; | 138 | static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 }; |
139 | 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 | |||
140 | static struct unwind_table *find_table(unsigned long pc) | 151 | static struct unwind_table *find_table(unsigned long pc) |
141 | { | 152 | { |
142 | struct unwind_table *table; | 153 | struct unwind_table *table; |
@@ -281,6 +292,7 @@ static void __init setup_unwind_table(struct unwind_table *table, | |||
281 | 292 | ||
282 | hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) | 293 | hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) |
283 | + 2 * n * sizeof(unsigned long); | 294 | + 2 * n * sizeof(unsigned long); |
295 | dprintk(2, "Binary lookup table size for %s: %lu bytes", table->name, hdrSize); | ||
284 | header = alloc(hdrSize); | 296 | header = alloc(hdrSize); |
285 | if (!header) | 297 | if (!header) |
286 | return; | 298 | return; |
@@ -500,13 +512,17 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
500 | const unsigned long *pul; | 512 | const unsigned long *pul; |
501 | } ptr; | 513 | } ptr; |
502 | 514 | ||
503 | if (ptrType < 0 || ptrType == DW_EH_PE_omit) | 515 | if (ptrType < 0 || ptrType == DW_EH_PE_omit) { |
516 | dprintk(1, "Invalid pointer encoding %02X (%p,%p).", ptrType, *pLoc, end); | ||
504 | return 0; | 517 | return 0; |
518 | } | ||
505 | ptr.p8 = *pLoc; | 519 | ptr.p8 = *pLoc; |
506 | switch(ptrType & DW_EH_PE_FORM) { | 520 | switch(ptrType & DW_EH_PE_FORM) { |
507 | case DW_EH_PE_data2: | 521 | case DW_EH_PE_data2: |
508 | if (end < (const void *)(ptr.p16u + 1)) | 522 | if (end < (const void *)(ptr.p16u + 1)) { |
523 | dprintk(1, "Data16 overrun (%p,%p).", ptr.p8, end); | ||
509 | return 0; | 524 | return 0; |
525 | } | ||
510 | if(ptrType & DW_EH_PE_signed) | 526 | if(ptrType & DW_EH_PE_signed) |
511 | value = get_unaligned(ptr.p16s++); | 527 | value = get_unaligned(ptr.p16s++); |
512 | else | 528 | else |
@@ -514,8 +530,10 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
514 | break; | 530 | break; |
515 | case DW_EH_PE_data4: | 531 | case DW_EH_PE_data4: |
516 | #ifdef CONFIG_64BIT | 532 | #ifdef CONFIG_64BIT |
517 | if (end < (const void *)(ptr.p32u + 1)) | 533 | if (end < (const void *)(ptr.p32u + 1)) { |
534 | dprintk(1, "Data32 overrun (%p,%p).", ptr.p8, end); | ||
518 | return 0; | 535 | return 0; |
536 | } | ||
519 | if(ptrType & DW_EH_PE_signed) | 537 | if(ptrType & DW_EH_PE_signed) |
520 | value = get_unaligned(ptr.p32s++); | 538 | value = get_unaligned(ptr.p32s++); |
521 | else | 539 | else |
@@ -527,8 +545,10 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
527 | BUILD_BUG_ON(sizeof(u32) != sizeof(value)); | 545 | BUILD_BUG_ON(sizeof(u32) != sizeof(value)); |
528 | #endif | 546 | #endif |
529 | case DW_EH_PE_native: | 547 | case DW_EH_PE_native: |
530 | if (end < (const void *)(ptr.pul + 1)) | 548 | if (end < (const void *)(ptr.pul + 1)) { |
549 | dprintk(1, "DataUL overrun (%p,%p).", ptr.p8, end); | ||
531 | return 0; | 550 | return 0; |
551 | } | ||
532 | value = get_unaligned(ptr.pul++); | 552 | value = get_unaligned(ptr.pul++); |
533 | break; | 553 | break; |
534 | case DW_EH_PE_leb128: | 554 | case DW_EH_PE_leb128: |
@@ -536,10 +556,14 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
536 | value = ptrType & DW_EH_PE_signed | 556 | value = ptrType & DW_EH_PE_signed |
537 | ? get_sleb128(&ptr.p8, end) | 557 | ? get_sleb128(&ptr.p8, end) |
538 | : get_uleb128(&ptr.p8, end); | 558 | : get_uleb128(&ptr.p8, end); |
539 | if ((const void *)ptr.p8 > end) | 559 | if ((const void *)ptr.p8 > end) { |
560 | dprintk(1, "DataLEB overrun (%p,%p).", ptr.p8, end); | ||
540 | return 0; | 561 | return 0; |
562 | } | ||
541 | break; | 563 | break; |
542 | default: | 564 | default: |
565 | dprintk(2, "Cannot decode pointer type %02X (%p,%p).", | ||
566 | ptrType, ptr.p8, end); | ||
543 | return 0; | 567 | return 0; |
544 | } | 568 | } |
545 | switch(ptrType & DW_EH_PE_ADJUST) { | 569 | switch(ptrType & DW_EH_PE_ADJUST) { |
@@ -549,11 +573,16 @@ static unsigned long read_pointer(const u8 **pLoc, | |||
549 | value += (unsigned long)*pLoc; | 573 | value += (unsigned long)*pLoc; |
550 | break; | 574 | break; |
551 | default: | 575 | default: |
576 | dprintk(2, "Cannot adjust pointer type %02X (%p,%p).", | ||
577 | ptrType, *pLoc, end); | ||
552 | return 0; | 578 | return 0; |
553 | } | 579 | } |
554 | if ((ptrType & DW_EH_PE_indirect) | 580 | if ((ptrType & DW_EH_PE_indirect) |
555 | && probe_kernel_address((unsigned long *)value, value)) | 581 | && probe_kernel_address((unsigned long *)value, value)) { |
582 | dprintk(1, "Cannot read indirect value %lx (%p,%p).", | ||
583 | value, *pLoc, end); | ||
556 | return 0; | 584 | return 0; |
585 | } | ||
557 | *pLoc = ptr.p8; | 586 | *pLoc = ptr.p8; |
558 | 587 | ||
559 | return value; | 588 | return value; |
@@ -702,8 +731,10 @@ static int processCFI(const u8 *start, | |||
702 | state->label = NULL; | 731 | state->label = NULL; |
703 | return 1; | 732 | return 1; |
704 | } | 733 | } |
705 | if (state->stackDepth >= MAX_STACK_DEPTH) | 734 | if (state->stackDepth >= MAX_STACK_DEPTH) { |
735 | dprintk(1, "State stack overflow (%p,%p).", ptr.p8, end); | ||
706 | return 0; | 736 | return 0; |
737 | } | ||
707 | state->stack[state->stackDepth++] = ptr.p8; | 738 | state->stack[state->stackDepth++] = ptr.p8; |
708 | break; | 739 | break; |
709 | case DW_CFA_restore_state: | 740 | case DW_CFA_restore_state: |
@@ -718,8 +749,10 @@ static int processCFI(const u8 *start, | |||
718 | result = processCFI(start, end, 0, ptrType, state); | 749 | result = processCFI(start, end, 0, ptrType, state); |
719 | state->loc = loc; | 750 | state->loc = loc; |
720 | state->label = label; | 751 | state->label = label; |
721 | } else | 752 | } else { |
753 | dprintk(1, "State stack underflow (%p,%p).", ptr.p8, end); | ||
722 | return 0; | 754 | return 0; |
755 | } | ||
723 | break; | 756 | break; |
724 | case DW_CFA_def_cfa: | 757 | case DW_CFA_def_cfa: |
725 | state->cfa.reg = get_uleb128(&ptr.p8, end); | 758 | state->cfa.reg = get_uleb128(&ptr.p8, end); |
@@ -751,6 +784,7 @@ static int processCFI(const u8 *start, | |||
751 | break; | 784 | break; |
752 | case DW_CFA_GNU_window_save: | 785 | case DW_CFA_GNU_window_save: |
753 | default: | 786 | default: |
787 | dprintk(1, "Unrecognized CFI op %02X (%p,%p).", ptr.p8[-1], ptr.p8 - 1, end); | ||
754 | result = 0; | 788 | result = 0; |
755 | break; | 789 | break; |
756 | } | 790 | } |
@@ -766,12 +800,17 @@ static int processCFI(const u8 *start, | |||
766 | set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state); | 800 | set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state); |
767 | break; | 801 | break; |
768 | } | 802 | } |
769 | if (ptr.p8 > end) | 803 | if (ptr.p8 > end) { |
804 | dprintk(1, "Data overrun (%p,%p).", ptr.p8, end); | ||
770 | result = 0; | 805 | result = 0; |
806 | } | ||
771 | if (result && targetLoc != 0 && targetLoc < state->loc) | 807 | if (result && targetLoc != 0 && targetLoc < state->loc) |
772 | return 1; | 808 | return 1; |
773 | } | 809 | } |
774 | 810 | ||
811 | if (result && ptr.p8 < end) | ||
812 | dprintk(1, "Data underrun (%p,%p).", ptr.p8, end); | ||
813 | |||
775 | return result | 814 | return result |
776 | && ptr.p8 == end | 815 | && ptr.p8 == end |
777 | && (targetLoc == 0 | 816 | && (targetLoc == 0 |
@@ -843,6 +882,8 @@ int unwind(struct unwind_frame_info *frame) | |||
843 | hdr[3]); | 882 | hdr[3]); |
844 | } | 883 | } |
845 | } | 884 | } |
885 | if(hdr && !fde) | ||
886 | dprintk(3, "Binary lookup for %lx failed.", pc); | ||
846 | 887 | ||
847 | if (fde != NULL) { | 888 | if (fde != NULL) { |
848 | cie = cie_for_fde(fde, table); | 889 | cie = cie_for_fde(fde, table); |
@@ -864,6 +905,8 @@ int unwind(struct unwind_frame_info *frame) | |||
864 | fde = NULL; | 905 | fde = NULL; |
865 | } else | 906 | } else |
866 | fde = NULL; | 907 | fde = NULL; |
908 | if(!fde) | ||
909 | dprintk(1, "Binary lookup result for %lx discarded.", pc); | ||
867 | } | 910 | } |
868 | if (fde == NULL) { | 911 | if (fde == NULL) { |
869 | for (fde = table->address, tableSize = table->size; | 912 | for (fde = table->address, tableSize = table->size; |
@@ -895,6 +938,8 @@ int unwind(struct unwind_frame_info *frame) | |||
895 | if (pc >= startLoc && pc < endLoc) | 938 | if (pc >= startLoc && pc < endLoc) |
896 | break; | 939 | break; |
897 | } | 940 | } |
941 | if(!fde) | ||
942 | dprintk(3, "Linear lookup for %lx failed.", pc); | ||
898 | } | 943 | } |
899 | } | 944 | } |
900 | if (cie != NULL) { | 945 | if (cie != NULL) { |
@@ -928,6 +973,8 @@ int unwind(struct unwind_frame_info *frame) | |||
928 | if (ptr >= end || *ptr) | 973 | if (ptr >= end || *ptr) |
929 | cie = NULL; | 974 | cie = NULL; |
930 | } | 975 | } |
976 | if(!cie) | ||
977 | dprintk(1, "CIE unusable (%p,%p).", ptr, end); | ||
931 | ++ptr; | 978 | ++ptr; |
932 | } | 979 | } |
933 | if (cie != NULL) { | 980 | if (cie != NULL) { |
@@ -938,9 +985,11 @@ int unwind(struct unwind_frame_info *frame) | |||
938 | if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end) | 985 | if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end) |
939 | cie = NULL; | 986 | cie = NULL; |
940 | else if (UNW_PC(frame) % state.codeAlign | 987 | else if (UNW_PC(frame) % state.codeAlign |
941 | || UNW_SP(frame) % sleb128abs(state.dataAlign)) | 988 | || UNW_SP(frame) % sleb128abs(state.dataAlign)) { |
989 | dprintk(1, "Input pointer(s) misaligned (%lx,%lx).", | ||
990 | UNW_PC(frame), UNW_SP(frame)); | ||
942 | return -EPERM; | 991 | return -EPERM; |
943 | else { | 992 | } else { |
944 | retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end); | 993 | retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end); |
945 | /* skip augmentation */ | 994 | /* skip augmentation */ |
946 | if (((const char *)(cie + 2))[1] == 'z') { | 995 | if (((const char *)(cie + 2))[1] == 'z') { |
@@ -954,6 +1003,8 @@ int unwind(struct unwind_frame_info *frame) | |||
954 | || reg_info[retAddrReg].width != sizeof(unsigned long)) | 1003 | || reg_info[retAddrReg].width != sizeof(unsigned long)) |
955 | cie = NULL; | 1004 | cie = NULL; |
956 | } | 1005 | } |
1006 | if(!cie) | ||
1007 | dprintk(1, "CIE validation failed (%p,%p).", ptr, end); | ||
957 | } | 1008 | } |
958 | if (cie != NULL) { | 1009 | if (cie != NULL) { |
959 | state.cieStart = ptr; | 1010 | state.cieStart = ptr; |
@@ -967,6 +1018,8 @@ int unwind(struct unwind_frame_info *frame) | |||
967 | if ((ptr += augSize) > end) | 1018 | if ((ptr += augSize) > end) |
968 | fde = NULL; | 1019 | fde = NULL; |
969 | } | 1020 | } |
1021 | if(!fde) | ||
1022 | dprintk(1, "FDE validation failed (%p,%p).", ptr, end); | ||
970 | } | 1023 | } |
971 | if (cie == NULL || fde == NULL) { | 1024 | if (cie == NULL || fde == NULL) { |
972 | #ifdef CONFIG_FRAME_POINTER | 1025 | #ifdef CONFIG_FRAME_POINTER |
@@ -1025,8 +1078,10 @@ int unwind(struct unwind_frame_info *frame) | |||
1025 | || state.cfa.reg >= ARRAY_SIZE(reg_info) | 1078 | || state.cfa.reg >= ARRAY_SIZE(reg_info) |
1026 | || reg_info[state.cfa.reg].width != sizeof(unsigned long) | 1079 | || reg_info[state.cfa.reg].width != sizeof(unsigned long) |
1027 | || FRAME_REG(state.cfa.reg, unsigned long) % sizeof(unsigned long) | 1080 | || FRAME_REG(state.cfa.reg, unsigned long) % sizeof(unsigned long) |
1028 | || state.cfa.offs % sizeof(unsigned long)) | 1081 | || state.cfa.offs % sizeof(unsigned long)) { |
1082 | dprintk(1, "Unusable unwind info (%p,%p).", ptr, end); | ||
1029 | return -EIO; | 1083 | return -EIO; |
1084 | } | ||
1030 | /* update frame */ | 1085 | /* update frame */ |
1031 | #ifndef CONFIG_AS_CFI_SIGNAL_FRAME | 1086 | #ifndef CONFIG_AS_CFI_SIGNAL_FRAME |
1032 | if(frame->call_frame | 1087 | if(frame->call_frame |
@@ -1051,6 +1106,8 @@ int unwind(struct unwind_frame_info *frame) | |||
1051 | if (REG_INVALID(i)) { | 1106 | if (REG_INVALID(i)) { |
1052 | if (state.regs[i].where == Nowhere) | 1107 | if (state.regs[i].where == Nowhere) |
1053 | continue; | 1108 | continue; |
1109 | dprintk(1, "Cannot restore register %u (%d).", | ||
1110 | i, state.regs[i].where); | ||
1054 | return -EIO; | 1111 | return -EIO; |
1055 | } | 1112 | } |
1056 | switch(state.regs[i].where) { | 1113 | switch(state.regs[i].where) { |
@@ -1059,8 +1116,11 @@ int unwind(struct unwind_frame_info *frame) | |||
1059 | case Register: | 1116 | case Register: |
1060 | if (state.regs[i].value >= ARRAY_SIZE(reg_info) | 1117 | if (state.regs[i].value >= ARRAY_SIZE(reg_info) |
1061 | || REG_INVALID(state.regs[i].value) | 1118 | || REG_INVALID(state.regs[i].value) |
1062 | || reg_info[i].width > reg_info[state.regs[i].value].width) | 1119 | || reg_info[i].width > reg_info[state.regs[i].value].width) { |
1120 | dprintk(1, "Cannot restore register %u from register %lu.", | ||
1121 | i, state.regs[i].value); | ||
1063 | return -EIO; | 1122 | return -EIO; |
1123 | } | ||
1064 | switch(reg_info[state.regs[i].value].width) { | 1124 | switch(reg_info[state.regs[i].value].width) { |
1065 | #define CASE(n) \ | 1125 | #define CASE(n) \ |
1066 | case sizeof(u##n): \ | 1126 | case sizeof(u##n): \ |
@@ -1070,6 +1130,9 @@ int unwind(struct unwind_frame_info *frame) | |||
1070 | CASES; | 1130 | CASES; |
1071 | #undef CASE | 1131 | #undef CASE |
1072 | default: | 1132 | default: |
1133 | dprintk(1, "Unsupported register size %u (%lu).", | ||
1134 | reg_info[state.regs[i].value].width, | ||
1135 | state.regs[i].value); | ||
1073 | return -EIO; | 1136 | return -EIO; |
1074 | } | 1137 | } |
1075 | break; | 1138 | break; |
@@ -1094,12 +1157,17 @@ int unwind(struct unwind_frame_info *frame) | |||
1094 | CASES; | 1157 | CASES; |
1095 | #undef CASE | 1158 | #undef CASE |
1096 | default: | 1159 | default: |
1160 | dprintk(1, "Unsupported register size %u (%u).", | ||
1161 | reg_info[i].width, i); | ||
1097 | return -EIO; | 1162 | return -EIO; |
1098 | } | 1163 | } |
1099 | break; | 1164 | break; |
1100 | case Value: | 1165 | case Value: |
1101 | if (reg_info[i].width != sizeof(unsigned long)) | 1166 | if (reg_info[i].width != sizeof(unsigned long)) { |
1167 | dprintk(1, "Unsupported value size %u (%u).", | ||
1168 | reg_info[i].width, i); | ||
1102 | return -EIO; | 1169 | return -EIO; |
1170 | } | ||
1103 | FRAME_REG(i, unsigned long) = cfa + state.regs[i].value | 1171 | FRAME_REG(i, unsigned long) = cfa + state.regs[i].value |
1104 | * state.dataAlign; | 1172 | * state.dataAlign; |
1105 | break; | 1173 | break; |
@@ -1111,8 +1179,11 @@ int unwind(struct unwind_frame_info *frame) | |||
1111 | % sizeof(unsigned long) | 1179 | % sizeof(unsigned long) |
1112 | || addr < startLoc | 1180 | || addr < startLoc |
1113 | || addr + sizeof(unsigned long) < addr | 1181 | || addr + sizeof(unsigned long) < addr |
1114 | || addr + sizeof(unsigned long) > endLoc) | 1182 | || addr + sizeof(unsigned long) > endLoc) { |
1183 | dprintk(1, "Bad memory location %lx (%lx).", | ||
1184 | addr, state.regs[i].value); | ||
1115 | return -EIO; | 1185 | return -EIO; |
1186 | } | ||
1116 | switch(reg_info[i].width) { | 1187 | switch(reg_info[i].width) { |
1117 | #define CASE(n) case sizeof(u##n): \ | 1188 | #define CASE(n) case sizeof(u##n): \ |
1118 | probe_kernel_address((u##n *)addr, FRAME_REG(i, u##n)); \ | 1189 | probe_kernel_address((u##n *)addr, FRAME_REG(i, u##n)); \ |
@@ -1120,6 +1191,8 @@ int unwind(struct unwind_frame_info *frame) | |||
1120 | CASES; | 1191 | CASES; |
1121 | #undef CASE | 1192 | #undef CASE |
1122 | default: | 1193 | default: |
1194 | dprintk(1, "Unsupported memory size %u (%u).", | ||
1195 | reg_info[i].width, i); | ||
1123 | return -EIO; | 1196 | return -EIO; |
1124 | } | 1197 | } |
1125 | } | 1198 | } |
@@ -1128,9 +1201,15 @@ int unwind(struct unwind_frame_info *frame) | |||
1128 | } | 1201 | } |
1129 | 1202 | ||
1130 | if (UNW_PC(frame) % state.codeAlign | 1203 | if (UNW_PC(frame) % state.codeAlign |
1131 | || UNW_SP(frame) % sleb128abs(state.dataAlign) | 1204 | || UNW_SP(frame) % sleb128abs(state.dataAlign)) { |
1132 | || (pc == UNW_PC(frame) && sp == UNW_SP(frame))) | 1205 | dprintk(1, "Output pointer(s) misaligned (%lx,%lx).", |
1206 | UNW_PC(frame), UNW_SP(frame)); | ||
1133 | return -EIO; | 1207 | return -EIO; |
1208 | } | ||
1209 | if (pc == UNW_PC(frame) && sp == UNW_SP(frame)) { | ||
1210 | dprintk(1, "No progress (%lx,%lx).", pc, sp); | ||
1211 | return -EIO; | ||
1212 | } | ||
1134 | 1213 | ||
1135 | return 0; | 1214 | return 0; |
1136 | #undef CASES | 1215 | #undef CASES |