aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/unwind.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/unwind.c')
-rw-r--r--kernel/unwind.c66
1 files changed, 47 insertions, 19 deletions
diff --git a/kernel/unwind.c b/kernel/unwind.c
index 209e248517db..08645aa7c2d6 100644
--- a/kernel/unwind.c
+++ b/kernel/unwind.c
@@ -164,7 +164,9 @@ static struct unwind_table *find_table(unsigned long pc)
164 164
165static unsigned long read_pointer(const u8 **pLoc, 165static unsigned long read_pointer(const u8 **pLoc,
166 const void *end, 166 const void *end,
167 signed ptrType); 167 signed ptrType,
168 unsigned long text_base,
169 unsigned long data_base);
168 170
169static void init_unwind_table(struct unwind_table *table, 171static void init_unwind_table(struct unwind_table *table,
170 const char *name, 172 const char *name,
@@ -189,10 +191,13 @@ static void init_unwind_table(struct unwind_table *table,
189 /* See if the linker provided table looks valid. */ 191 /* See if the linker provided table looks valid. */
190 if (header_size <= 4 192 if (header_size <= 4
191 || header_start[0] != 1 193 || header_start[0] != 1
192 || (void *)read_pointer(&ptr, end, header_start[1]) != table_start 194 || (void *)read_pointer(&ptr, end, header_start[1], 0, 0)
193 || header_start[2] == DW_EH_PE_omit 195 != table_start
194 || read_pointer(&ptr, end, header_start[2]) <= 0 196 || !read_pointer(&ptr, end, header_start[2], 0, 0)
195 || 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))
196 header_start = NULL; 201 header_start = NULL;
197 table->hdrsz = header_size; 202 table->hdrsz = header_size;
198 smp_wmb(); 203 smp_wmb();
@@ -282,7 +287,7 @@ static void __init setup_unwind_table(struct unwind_table *table,
282 ptr = (const u8 *)(fde + 2); 287 ptr = (const u8 *)(fde + 2);
283 if (!read_pointer(&ptr, 288 if (!read_pointer(&ptr,
284 (const u8 *)(fde + 1) + *fde, 289 (const u8 *)(fde + 1) + *fde,
285 ptrType)) 290 ptrType, 0, 0))
286 return; 291 return;
287 ++n; 292 ++n;
288 } 293 }
@@ -317,7 +322,7 @@ static void __init setup_unwind_table(struct unwind_table *table,
317 ptr = (const u8 *)(fde + 2); 322 ptr = (const u8 *)(fde + 2);
318 header->table[n].start = read_pointer(&ptr, 323 header->table[n].start = read_pointer(&ptr,
319 (const u8 *)(fde + 1) + *fde, 324 (const u8 *)(fde + 1) + *fde,
320 fde_pointer_type(cie)); 325 fde_pointer_type(cie), 0, 0);
321 header->table[n].fde = (unsigned long)fde; 326 header->table[n].fde = (unsigned long)fde;
322 ++n; 327 ++n;
323 } 328 }
@@ -500,7 +505,9 @@ static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table)
500 505
501static unsigned long read_pointer(const u8 **pLoc, 506static unsigned long read_pointer(const u8 **pLoc,
502 const void *end, 507 const void *end,
503 signed ptrType) 508 signed ptrType,
509 unsigned long text_base,
510 unsigned long data_base)
504{ 511{
505 unsigned long value = 0; 512 unsigned long value = 0;
506 union { 513 union {
@@ -572,6 +579,22 @@ static unsigned long read_pointer(const u8 **pLoc,
572 case DW_EH_PE_pcrel: 579 case DW_EH_PE_pcrel:
573 value += (unsigned long)*pLoc; 580 value += (unsigned long)*pLoc;
574 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;
575 default: 598 default:
576 dprintk(2, "Cannot adjust pointer type %02X (%p,%p).", 599 dprintk(2, "Cannot adjust pointer type %02X (%p,%p).",
577 ptrType, *pLoc, end); 600 ptrType, *pLoc, end);
@@ -625,7 +648,8 @@ static signed fde_pointer_type(const u32 *cie)
625 case 'P': { 648 case 'P': {
626 signed ptrType = *ptr++; 649 signed ptrType = *ptr++;
627 650
628 if (!read_pointer(&ptr, end, ptrType) || ptr > end) 651 if (!read_pointer(&ptr, end, ptrType, 0, 0)
652 || ptr > end)
629 return -1; 653 return -1;
630 } 654 }
631 break; 655 break;
@@ -685,7 +709,8 @@ static int processCFI(const u8 *start,
685 case DW_CFA_nop: 709 case DW_CFA_nop:
686 break; 710 break;
687 case DW_CFA_set_loc: 711 case DW_CFA_set_loc:
688 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)
689 result = 0; 714 result = 0;
690 break; 715 break;
691 case DW_CFA_advance_loc1: 716 case DW_CFA_advance_loc1:
@@ -854,9 +879,9 @@ int unwind(struct unwind_frame_info *frame)
854 ptr = hdr + 4; 879 ptr = hdr + 4;
855 end = hdr + table->hdrsz; 880 end = hdr + table->hdrsz;
856 if (tableSize 881 if (tableSize
857 && read_pointer(&ptr, end, hdr[1]) 882 && read_pointer(&ptr, end, hdr[1], 0, 0)
858 == (unsigned long)table->address 883 == (unsigned long)table->address
859 && (i = read_pointer(&ptr, end, hdr[2])) > 0 884 && (i = read_pointer(&ptr, end, hdr[2], 0, 0)) > 0
860 && i == (end - ptr) / (2 * tableSize) 885 && i == (end - ptr) / (2 * tableSize)
861 && !((end - ptr) % (2 * tableSize))) { 886 && !((end - ptr) % (2 * tableSize))) {
862 do { 887 do {
@@ -864,7 +889,8 @@ int unwind(struct unwind_frame_info *frame)
864 889
865 startLoc = read_pointer(&cur, 890 startLoc = read_pointer(&cur,
866 cur + tableSize, 891 cur + tableSize,
867 hdr[3]); 892 hdr[3], 0,
893 (unsigned long)hdr);
868 if (pc < startLoc) 894 if (pc < startLoc)
869 i /= 2; 895 i /= 2;
870 else { 896 else {
@@ -875,11 +901,13 @@ int unwind(struct unwind_frame_info *frame)
875 if (i == 1 901 if (i == 1
876 && (startLoc = read_pointer(&ptr, 902 && (startLoc = read_pointer(&ptr,
877 ptr + tableSize, 903 ptr + tableSize,
878 hdr[3])) != 0 904 hdr[3], 0,
905 (unsigned long)hdr)) != 0
879 && pc >= startLoc) 906 && pc >= startLoc)
880 fde = (void *)read_pointer(&ptr, 907 fde = (void *)read_pointer(&ptr,
881 ptr + tableSize, 908 ptr + tableSize,
882 hdr[3]); 909 hdr[3], 0,
910 (unsigned long)hdr);
883 } 911 }
884 } 912 }
885 if(hdr && !fde) 913 if(hdr && !fde)
@@ -894,13 +922,13 @@ int unwind(struct unwind_frame_info *frame)
894 && (ptrType = fde_pointer_type(cie)) >= 0 922 && (ptrType = fde_pointer_type(cie)) >= 0
895 && read_pointer(&ptr, 923 && read_pointer(&ptr,
896 (const u8 *)(fde + 1) + *fde, 924 (const u8 *)(fde + 1) + *fde,
897 ptrType) == startLoc) { 925 ptrType, 0, 0) == startLoc) {
898 if (!(ptrType & DW_EH_PE_indirect)) 926 if (!(ptrType & DW_EH_PE_indirect))
899 ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed; 927 ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed;
900 endLoc = startLoc 928 endLoc = startLoc
901 + read_pointer(&ptr, 929 + read_pointer(&ptr,
902 (const u8 *)(fde + 1) + *fde, 930 (const u8 *)(fde + 1) + *fde,
903 ptrType); 931 ptrType, 0, 0);
904 if(pc >= endLoc) 932 if(pc >= endLoc)
905 fde = NULL; 933 fde = NULL;
906 } else 934 } else
@@ -926,7 +954,7 @@ int unwind(struct unwind_frame_info *frame)
926 ptr = (const u8 *)(fde + 2); 954 ptr = (const u8 *)(fde + 2);
927 startLoc = read_pointer(&ptr, 955 startLoc = read_pointer(&ptr,
928 (const u8 *)(fde + 1) + *fde, 956 (const u8 *)(fde + 1) + *fde,
929 ptrType); 957 ptrType, 0, 0);
930 if (!startLoc) 958 if (!startLoc)
931 continue; 959 continue;
932 if (!(ptrType & DW_EH_PE_indirect)) 960 if (!(ptrType & DW_EH_PE_indirect))
@@ -934,7 +962,7 @@ int unwind(struct unwind_frame_info *frame)
934 endLoc = startLoc 962 endLoc = startLoc
935 + read_pointer(&ptr, 963 + read_pointer(&ptr,
936 (const u8 *)(fde + 1) + *fde, 964 (const u8 *)(fde + 1) + *fde,
937 ptrType); 965 ptrType, 0, 0);
938 if (pc >= startLoc && pc < endLoc) 966 if (pc >= startLoc && pc < endLoc)
939 break; 967 break;
940 } 968 }