diff options
-rw-r--r-- | bfd/ChangeLog | 5 | ||||
-rw-r--r-- | bfd/coffcode.h | 165 |
2 files changed, 125 insertions, 45 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 36f0583..6e10aad 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,8 @@ +2007-08-01 Tristan Gingold <gingold@adacore.com> + + * coffcode.h (coff_sort_func_alent): New function. + (coff_slurp_line_table): Sort line table if not already sorted. + 2007-08-01 Jakub Jelinek <jakub@redhat.com> * elf.c (_bfd_elf_map_sections_to_segments): Work around buggy diff --git a/bfd/coffcode.h b/bfd/coffcode.h index 5a858dd..043e929 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -4253,12 +4253,34 @@ SUBSUBSECTION How does this work ? */ +static int +coff_sort_func_alent (const void * arg1, const void * arg2) +{ + const alent *al1 = *(const alent **) arg1; + const alent *al2 = *(const alent **) arg2; + const coff_symbol_type *s1 = (const coff_symbol_type *) (al1->u.sym); + const coff_symbol_type *s2 = (const coff_symbol_type *) (al2->u.sym); + + if (s1->symbol.value < s2->symbol.value) + return -1; + else if (s1->symbol.value > s2->symbol.value) + return 1; + + return 0; +} + static bfd_boolean coff_slurp_line_table (bfd *abfd, asection *asect) { LINENO *native_lineno; alent *lineno_cache; bfd_size_type amt; + unsigned int counter; + alent *cache_ptr; + bfd_vma prev_offset = 0; + int ordered = 1; + unsigned int nbr_func; + LINENO *src; BFD_ASSERT (asect->lineno == NULL); @@ -4270,67 +4292,120 @@ coff_slurp_line_table (bfd *abfd, asection *asect) (_("%B: warning: line number table read failed"), abfd); return FALSE; } + amt = ((bfd_size_type) asect->lineno_count + 1) * sizeof (alent); lineno_cache = bfd_alloc (abfd, amt); if (lineno_cache == NULL) return FALSE; - else + + cache_ptr = lineno_cache; + src = native_lineno; + nbr_func = 0; + + for (counter = 0; counter < asect->lineno_count; counter++) + { + struct internal_lineno dst; + + bfd_coff_swap_lineno_in (abfd, src, &dst); + cache_ptr->line_number = dst.l_lnno; + + if (cache_ptr->line_number == 0) + { + bfd_boolean warned; + bfd_signed_vma symndx; + coff_symbol_type *sym; + + nbr_func++; + warned = FALSE; + symndx = dst.l_addr.l_symndx; + if (symndx < 0 + || (bfd_vma) symndx >= obj_raw_syment_count (abfd)) + { + (*_bfd_error_handler) + (_("%B: warning: illegal symbol index %ld in line numbers"), + abfd, dst.l_addr.l_symndx); + symndx = 0; + warned = TRUE; + } + + /* FIXME: We should not be casting between ints and + pointers like this. */ + sym = ((coff_symbol_type *) + ((symndx + obj_raw_syments (abfd)) + ->u.syment._n._n_n._n_zeroes)); + cache_ptr->u.sym = (asymbol *) sym; + if (sym->lineno != NULL && ! warned) + (*_bfd_error_handler) + (_("%B: warning: duplicate line number information for `%s'"), + abfd, bfd_asymbol_name (&sym->symbol)); + + sym->lineno = cache_ptr; + if (sym->symbol.value < prev_offset) + ordered = 0; + prev_offset = sym->symbol.value; + } + else + cache_ptr->u.offset = dst.l_addr.l_paddr + - bfd_section_vma (abfd, asect); + + cache_ptr++; + src++; + } + cache_ptr->line_number = 0; + + /* On some systems (eg AIX5.3) the lineno table may not be sorted. */ + if (!ordered) { - unsigned int counter = 0; - alent *cache_ptr = lineno_cache; - LINENO *src = native_lineno; + /* Sort the table. */ + alent **func_table; + alent *n_lineno_cache; - while (counter < asect->lineno_count) + /* Create a table of functions. */ + func_table = bfd_malloc (nbr_func * sizeof (alent *)); + if (func_table != NULL) { - struct internal_lineno dst; + alent **p = func_table; + unsigned int i; - bfd_coff_swap_lineno_in (abfd, src, &dst); - cache_ptr->line_number = dst.l_lnno; + for (i = 0; i < counter; i++) + if (lineno_cache[i].line_number == 0) + *p++ = &lineno_cache[i]; - if (cache_ptr->line_number == 0) + /* Sort by functions. */ + qsort (func_table, nbr_func, sizeof (alent *), coff_sort_func_alent); + + /* Create the new sorted table. */ + n_lineno_cache = bfd_alloc (abfd, amt); + if (n_lineno_cache != NULL) { - bfd_boolean warned; - bfd_signed_vma symndx; - coff_symbol_type *sym; - - warned = FALSE; - symndx = dst.l_addr.l_symndx; - if (symndx < 0 - || (bfd_vma) symndx >= obj_raw_syment_count (abfd)) - { - (*_bfd_error_handler) - (_("%B: warning: illegal symbol index %ld in line numbers"), - abfd, dst.l_addr.l_symndx); - symndx = 0; - warned = TRUE; - } - /* FIXME: We should not be casting between ints and - pointers like this. */ - sym = ((coff_symbol_type *) - ((symndx + obj_raw_syments (abfd)) - ->u.syment._n._n_n._n_zeroes)); - cache_ptr->u.sym = (asymbol *) sym; - if (sym->lineno != NULL && ! warned) + alent *n_cache_ptr = n_lineno_cache; + + for (i = 0; i < nbr_func; i++) { - (*_bfd_error_handler) - (_("%B: warning: duplicate line number information for `%s'"), - abfd, bfd_asymbol_name (&sym->symbol)); + coff_symbol_type *sym; + alent *old_ptr = func_table[i]; + + /* Copy the function entry and update it. */ + *n_cache_ptr = *old_ptr; + sym = (coff_symbol_type *)n_cache_ptr->u.sym; + sym->lineno = n_cache_ptr; + n_cache_ptr++; + old_ptr++; + + /* Copy the line number entries. */ + while (old_ptr->line_number != 0) + *n_cache_ptr++ = *old_ptr++; } - sym->lineno = cache_ptr; + n_cache_ptr->line_number = 0; + bfd_release (abfd, lineno_cache); + lineno_cache = n_lineno_cache; } - else - cache_ptr->u.offset = dst.l_addr.l_paddr - - bfd_section_vma (abfd, asect); - - cache_ptr++; - src++; - counter++; + free (func_table); } - cache_ptr->line_number = 0; - } + asect->lineno = lineno_cache; - /* FIXME, free native_lineno here, or use alloca or something. */ + bfd_release (abfd, native_lineno); return TRUE; } |