diff options
author | Jan Beulich <jbeulich@novell.com> | 2006-12-06 20:14:19 -0500 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-12-06 20:14:19 -0500 |
commit | c65f38d911aa301cea109d38d40925750dd6c2da (patch) | |
tree | f4655ffc3cf80070fa5261490b906905d88fa1ee /kernel | |
parent | 6bedb2ccb02dcc70ffc8eb76df71c746378190ad (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.c | 66 |
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 | ||
165 | static unsigned long read_pointer(const u8 **pLoc, | 165 | static 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 | ||
169 | static void init_unwind_table(struct unwind_table *table, | 171 | static 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 | ||
501 | static unsigned long read_pointer(const u8 **pLoc, | 506 | static 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 | } |