aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2006-12-06 20:14:19 -0500
committerAndi Kleen <andi@basil.nowhere.org>2006-12-06 20:14:19 -0500
commitc65f38d911aa301cea109d38d40925750dd6c2da (patch)
treef4655ffc3cf80070fa5261490b906905d88fa1ee /kernel
parent6bedb2ccb02dcc70ffc8eb76df71c746378190ad (diff)
[PATCH] unwinder: fully support linker generated .eh_frame_hdr section
Now that binutils' ld is able to properly populate .eh_frame_hdr in the Linux kernel case, here's a patch to add some functionality to the Dwarf2 unwinder to actually be able to make use of this (applies on firstfloor tree with the previously sent patch to add debug output, but not on plain 2.6.19). Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'kernel')
-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 }