* coffcode.h (coff_sort_func_alent): New function.
authorNick Clifton <nickc@redhat.com>
Wed, 1 Aug 2007 16:55:54 +0000 (16:55 +0000)
committerNick Clifton <nickc@redhat.com>
Wed, 1 Aug 2007 16:55:54 +0000 (16:55 +0000)
  (coff_slurp_line_table): Sort line table if not already sorted.

bfd/ChangeLog
bfd/coffcode.h

index 36f0583..6e10aad 100644 (file)
@@ -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
index 5a858dd..043e929 100644 (file)
@@ -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;
 }