Description:
 * This patch optimizes the time required for loading XCOFF data.

Tests:
 * AIX: Build: SUCCESS
   - build made by means of gmake on AIX.

ChangeLog:
  * xcoff.c: Optimize loading of XCOFF data.
 
 
Cordialement,
 
 Tony Reix
 
 tony.r...@atos.net
 
 ATOS / Bull SAS
 ATOS Expert
 IBM Coop Architect & Technical Leader
  
Office : +33 (0) 4 76 29 72 67 
1 rue de Provence - 38432 Échirolles - France 
www.atos.net         
Index: libbacktrace/xcoff.c
===================================================================
--- ./libbacktrace/xcoff.c	(revision 262803)
+++ ./libbacktrace/xcoff.c	(working copy)
@@ -338,27 +338,32 @@ struct xcoff_incl_vector
   size_t count;
 };
 
-/* Map a single PC value to a file/function/line.  */
+/* A growable vector of functions information.  */
 
-struct xcoff_line
+struct xcoff_func
 {
   /* PC.  */
   uintptr_t pc;
-  /* File name.  Many entries in the array are expected to point to
-     the same file name.  */
+  /* The size of the function.  */
+  size_t size;
+  /* Function name.  */
+  const char *name;
+  /* File name.  */
   const char *filename;
-  /* Function name.  */
-  const char *function;
-  /* Line number.  */
-  int lineno;
+  /* Pointer to first lnno entry.  */
+  uintptr_t lnnoptr;
+  /* Base address of containing section.  */
+  uintptr_t sect_base;
+  /* Starting source line number.  */
+  int lnno;
 };
 
-/* A growable vector of line number information.  This is used while
-   reading the line numbers.  */
+/* A growable vector of function information.  This is used while
+   reading the function symbols.  */
 
-struct xcoff_line_vector
+struct xcoff_func_vector
 {
-  /* Memory.  This is an array of struct xcoff_line.  */
+  /* Memory.  This is an array of struct xcoff_func.  */
   struct backtrace_vector vec;
   /* Number of valid mappings.  */
   size_t count;
@@ -370,8 +375,16 @@ struct xcoff_fileline_data
 {
   /* The data for the next file we know about.  */
   struct xcoff_fileline_data *next;
-  /* Line number information.  */
-  struct xcoff_line_vector vec;
+  /* Functions information.  */
+  struct xcoff_func_vector func_vec;
+  /* Include files information.  */
+  struct xcoff_incl_vector incl_vec;
+  /* Line numbers information.  */
+  const unsigned char *linenos;
+  size_t linenos_size;
+  uint64_t lnnoptr0;
+  /* Loader address.  */
+  uintptr_t base_address;
 };
 
 /* An index of DWARF sections we care about.  */
@@ -509,6 +522,7 @@ xcoff_syminfo (struct backtrace_state *state ATTRI
 {
   struct xcoff_syminfo_data *edata;
   struct xcoff_symbol *sym = NULL;
+  const char *name;
 
   if (!state->threaded)
     {
@@ -547,7 +561,13 @@ xcoff_syminfo (struct backtrace_state *state ATTRI
   if (sym == NULL)
     callback (data, addr, NULL, 0, 0);
   else
-    callback (data, addr, sym->name, sym->address, sym->size);
+    {
+      name = sym->name;
+      /* AIX prepends a '.' to function entry points, remove it.  */
+      if (name && *name == '.')
+	++name;
+      callback (data, addr, name, sym->address, sym->size);
+    }
 }
 
 /* Return the name of an XCOFF symbol.  */
@@ -640,43 +660,76 @@ xcoff_initialize_syminfo (struct backtrace_state *
   return 1;
 }
 
-/* Compare struct xcoff_line for qsort.  */
+/* Compare struct xcoff_func for qsort.  */
 
 static int
-xcoff_line_compare (const void *v1, const void *v2)
+xcoff_func_compare (const void *v1, const void *v2)
 {
-  const struct xcoff_line *ln1 = (const struct xcoff_line *) v1;
-  const struct xcoff_line *ln2 = (const struct xcoff_line *) v2;
+  const struct xcoff_func *fn1 = (const struct xcoff_func *) v1;
+  const struct xcoff_func *fn2 = (const struct xcoff_func *) v2;
 
-  if (ln1->pc < ln2->pc)
+  if (fn1->pc < fn2->pc)
     return -1;
-  else if (ln1->pc > ln2->pc)
+  else if (fn1->pc > fn2->pc)
     return 1;
   else
     return 0;
 }
 
-/* Find a PC in a line vector.  We always allocate an extra entry at
-   the end of the lines vector, so that this routine can safely look
-   at the next entry.  */
+/* Compare a PC against an xcoff_func for bsearch.  */
 
 static int
-xcoff_line_search (const void *vkey, const void *ventry)
+xcoff_func_search (const void *vkey, const void *ventry)
 {
   const uintptr_t *key = (const uintptr_t *) vkey;
-  const struct xcoff_line *entry = (const struct xcoff_line *) ventry;
+  const struct xcoff_func *entry = (const struct xcoff_func *) ventry;
   uintptr_t pc;
 
   pc = *key;
   if (pc < entry->pc)
     return -1;
-  else if ((entry + 1)->pc == (uintptr_t) -1 || pc >= (entry + 1)->pc)
+  else if ((entry->size == 0 && pc > entry->pc)
+	   || (entry->size > 0 && pc >= entry->pc + entry->size))
     return 1;
   else
     return 0;
 }
 
-/* Look for a PC in the line vector for one module.  On success,
+/* Compare struct xcoff_incl for qsort.  */
+
+static int
+xcoff_incl_compare (const void *v1, const void *v2)
+{
+  const struct xcoff_incl *in1 = (const struct xcoff_incl *) v1;
+  const struct xcoff_incl *in2 = (const struct xcoff_incl *) v2;
+
+  if (in1->begin < in2->begin)
+    return -1;
+  else if (in1->begin > in2->begin)
+    return 1;
+  else
+    return 0;
+}
+
+/* Find a lnnoptr in an include file.  */
+
+static int
+xcoff_incl_search (const void *vkey, const void *ventry)
+{
+  const uintptr_t *key = (const uintptr_t *) vkey;
+  const struct xcoff_incl *entry = (const struct xcoff_incl *) ventry;
+  uintptr_t lnno;
+
+  lnno = *key;
+  if (lnno < entry->begin)
+    return -1;
+  else if (lnno > entry->end)
+    return 1;
+  else
+    return 0;
+}
+
+/* Look for a PC in the function vector for one module.  On success,
    call CALLBACK and return whatever it returns.  On error, call
    ERROR_CALLBACK and return 0.  Sets *FOUND to 1 if the PC is found,
    0 if not.  */
@@ -688,26 +741,82 @@ xcoff_lookup_pc (struct backtrace_state *state ATT
 		 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
 		 void *data, int *found)
 {
-  const struct xcoff_line *ln;
+  const struct xcoff_incl *incl, *bincl;
+  const struct xcoff_func *fn;
+  const b_xcoff_lineno *lineno;
+  const unsigned char *lineptr;
   const char *function;
+  const char *filename;
+  uintptr_t lnnoptr, match;
+  uint32_t lnno = 0;
 
   *found = 1;
 
-  ln = (struct xcoff_line *) bsearch (&pc, fdata->vec.vec.base,
-				      fdata->vec.count,
-				      sizeof (struct xcoff_line),
-				      xcoff_line_search);
-  if (ln == NULL)
+  if (pc & 3)
+    ++pc;
+
+  /* Find the function first.  */
+  fn = ((struct xcoff_func *)
+	bsearch (&pc, fdata->func_vec.vec.base, fdata->func_vec.count,
+		 sizeof (struct xcoff_func), xcoff_func_search));
+  if (fn == NULL)
     {
       *found = 0;
       return 0;
     }
 
-  function = ln->function;
+  filename = fn->filename;
+
+  /* Find the line number next.  */
+
+  /* Skip first entry that points to symtab.  */
+  lnnoptr = fn->lnnoptr + LINESZ;
+  match = lnnoptr;
+
+  lineptr = fdata->linenos + (lnnoptr - fdata->lnnoptr0);
+  while (lineptr + LINESZ <= fdata->linenos + fdata->linenos_size)
+    {
+      lineno = (const b_xcoff_lineno *) lineptr;
+      if (lineno->l_lnno == 0)
+	break;
+      if (pc <= fdata->base_address + lineno->l_addr.l_paddr - fn->sect_base)
+	break;
+      match = lnnoptr;
+      lnno = lineno->l_lnno;
+
+      lnnoptr += LINESZ;
+      lineptr += LINESZ;
+    }
+
+  /* If part of a function other than the beginning comes from an
+     include file, the line numbers are absolute, rather than
+     relative to the beginning of the function.  */
+  incl = ((struct xcoff_incl *)
+	  bsearch (&match, fdata->incl_vec.vec.base,
+		   fdata->incl_vec.count, sizeof (struct xcoff_incl),
+		   xcoff_incl_search));
+  if (incl != NULL)
+    {
+      bincl = ((struct xcoff_incl *)
+	       bsearch (&fn->lnnoptr, fdata->incl_vec.vec.base,
+			fdata->incl_vec.count, sizeof (struct xcoff_incl),
+			xcoff_incl_search));
+      if (bincl != NULL && !strcmp (incl->filename, bincl->filename))
+	{
+	  lnno += fn->lnno - 1;
+	}
+      filename = incl->filename;
+    }
+  else
+    {
+      lnno += fn->lnno - 1;
+    }
+
+  function = fn->name;
   /* AIX prepends a '.' to function entry points, remove it.  */
-  if (*function == '.')
+  if (function && *function == '.')
     ++function;
-  return callback (data, pc, ln->filename, ln->lineno, function);
+  return callback (data, pc, filename, lnno, function);
 }
 
 /* Return the file/line information for a PC using the XCOFF lineno
@@ -760,148 +869,9 @@ xcoff_fileline (struct backtrace_state *state, uin
   return callback (data, pc, NULL, 0, NULL);
 }
 
-/* Compare struct xcoff_incl for qsort.  */
+/* Initialize the function vector info for xcoff_fileline.  */
 
 static int
-xcoff_incl_compare (const void *v1, const void *v2)
-{
-  const struct xcoff_incl *in1 = (const struct xcoff_incl *) v1;
-  const struct xcoff_incl *in2 = (const struct xcoff_incl *) v2;
-
-  if (in1->begin < in2->begin)
-    return -1;
-  else if (in1->begin > in2->begin)
-    return 1;
-  else
-    return 0;
-}
-
-/* Find a lnnoptr in an include file.  */
-
-static int
-xcoff_incl_search (const void *vkey, const void *ventry)
-{
-  const uintptr_t *key = (const uintptr_t *) vkey;
-  const struct xcoff_incl *entry = (const struct xcoff_incl *) ventry;
-  uintptr_t lnno;
-
-  lnno = *key;
-  if (lnno < entry->begin)
-    return -1;
-  else if (lnno > entry->end)
-    return 1;
-  else
-    return 0;
-}
-
-/* Add a new mapping to the vector of line mappings that we are
-   building.  Returns 1 on success, 0 on failure.  */
-
-static int
-xcoff_add_line (struct backtrace_state *state, uintptr_t pc,
-		const char *filename, const char *function, uint32_t lnno,
-		backtrace_error_callback error_callback, void *data,
-		struct xcoff_line_vector *vec)
-{
-  struct xcoff_line *ln;
-
-  ln = ((struct xcoff_line *)
-	backtrace_vector_grow (state, sizeof (struct xcoff_line),
-			       error_callback, data, &vec->vec));
-  if (ln == NULL)
-    return 0;
-
-  ln->pc = pc;
-  ln->filename = filename;
-  ln->function = function;
-  ln->lineno = lnno;
-
-  ++vec->count;
-
-  return 1;
-}
-
-/* Add the line number entries for a function to the line vector.  */
-
-static int
-xcoff_process_linenos (struct backtrace_state *state, uintptr_t base_address,
-		       const b_xcoff_syment *fsym, const char *filename,
-		       const b_xcoff_scnhdr *sects,
-		       const unsigned char *strtab, size_t strtab_size,
-		       uint32_t fcn_lnno, struct xcoff_incl_vector *vec,
-		       struct xcoff_line_vector *lvec,
-		       const unsigned char *linenos, size_t linenos_size,
-		       uintptr_t lnnoptr0,
-		       backtrace_error_callback error_callback, void *data)
-{
-  const b_xcoff_auxent *aux;
-  const b_xcoff_lineno *lineno;
-  const unsigned char *lineptr;
-  const char *function;
-  struct xcoff_incl *incl = NULL;
-  uintptr_t lnnoptr;
-  uintptr_t pc;
-  uint32_t lnno;
-  int begincl;
-
-  aux = (const b_xcoff_auxent *) (fsym + 1);
-  lnnoptr = aux->x_fcn.x_lnnoptr;
-
-  if (lnnoptr < lnnoptr0 || lnnoptr + LINESZ > lnnoptr0 + linenos_size)
-    return 0;
-
-  function = xcoff_symname (fsym, strtab, strtab_size);
-  if (function == NULL)
-    return 0;
-
-  /* Skip first entry that points to symtab.  */
-
-  lnnoptr += LINESZ;
-
-  lineptr = linenos + (lnnoptr - lnnoptr0);
-
-  begincl = -1;
-  while (lineptr + LINESZ <= linenos + linenos_size)
-    {
-      lineno = (const b_xcoff_lineno *) lineptr;
-
-      lnno = lineno->l_lnno;
-      if (lnno == 0)
-	  break;
-
-      /* If part of a function other than the beginning comes from an
-	 include file, the line numbers are absolute, rather than
-	 relative to the beginning of the function.  */
-      incl = (struct xcoff_incl *) bsearch (&lnnoptr, vec->vec.base,
-					    vec->count,
-					    sizeof (struct xcoff_incl),
-					    xcoff_incl_search);
-      if (begincl == -1)
-	begincl = incl != NULL;
-      if (incl != NULL)
-	{
-	  filename = incl->filename;
-	  if (begincl == 1)
-	    lnno += fcn_lnno - 1;
-	}
-      else
-	lnno += fcn_lnno - 1;
-
-      pc = base_address + lineno->l_addr.l_paddr
-	 - sects[fsym->n_scnum - 1].s_paddr;
-      xcoff_add_line (state, pc, filename, function, lnno, error_callback,
-		      data, lvec);
-
-      lnnoptr += LINESZ;
-      lineptr += LINESZ;
-    }
-
-  return 1;
-}
-
-/* Initialize the line vector info for xcoff_fileline.  */
-
-static int
 xcoff_initialize_fileline (struct backtrace_state *state,
 			   uintptr_t base_address,
 			   const b_xcoff_scnhdr *sects,
@@ -912,8 +882,7 @@ xcoff_initialize_fileline (struct backtrace_state
 			   backtrace_error_callback error_callback, void *data)
 {
   struct xcoff_fileline_data *fdata;
-  struct xcoff_incl_vector vec;
-  struct xcoff_line *ln;
+  struct xcoff_func *fn;
   const b_xcoff_syment *fsym;
   const b_xcoff_auxent *aux;
   const char *filename;
@@ -920,7 +889,8 @@ xcoff_initialize_fileline (struct backtrace_state
   const char *name;
   struct xcoff_incl *incl;
   uintptr_t begin, end;
-  uintptr_t lnno;
+  uintptr_t lnno, lnnoptr;
+  uint32_t fsize;
   size_t i;
 
   fdata = ((struct xcoff_fileline_data *)
@@ -928,13 +898,17 @@ xcoff_initialize_fileline (struct backtrace_state
 			    error_callback, data));
   if (fdata == NULL)
     return 0;
-
   memset (fdata, 0, sizeof *fdata);
-  memset (&vec, 0, sizeof vec);
+  fdata->base_address = base_address;
+  fdata->linenos = linenos;
+  fdata->linenos_size = linenos_size;
+  fdata->lnnoptr0 = lnnoptr0;
 
-  /* Process include files first.  */
-
   begin = 0;
+  filename = NULL;
+  fsym = NULL;
+  lnnoptr = 0;
+  fsize = 0;
   for (i = 0; i < nsyms; ++i)
     {
       const b_xcoff_syment *asym = &syms[i];
@@ -951,32 +925,18 @@ xcoff_initialize_fileline (struct backtrace_state
 	    end = asym->n_value;
 	    incl = ((struct xcoff_incl *)
 		    backtrace_vector_grow (state, sizeof (struct xcoff_incl),
-					   error_callback, data, &vec.vec));
+					   error_callback, data,
+					   &fdata->incl_vec.vec));
 	    if (incl != NULL)
 	      {
 		incl->filename = xcoff_symname (asym, strtab, strtab_size);
 		incl->begin = begin;
 		incl->end = end;
-		++vec.count;
+		++fdata->incl_vec.count;
 	      }
 	    begin = 0;
 	    break;
-	}
 
-      i += asym->n_numaux;
-    }
-
-  backtrace_qsort (vec.vec.base, vec.count,
-		   sizeof (struct xcoff_incl), xcoff_incl_compare);
-
-  filename = NULL;
-  fsym = NULL;
-  for (i = 0; i < nsyms; ++i)
-    {
-      const b_xcoff_syment *asym = &syms[i];
-
-      switch (asym->n_sclass)
-	{
 	  case C_FILE:
 	    filename = xcoff_symname (asym, strtab, strtab_size);
 	    if (filename == NULL)
@@ -1010,10 +970,20 @@ xcoff_initialize_fileline (struct backtrace_state
 	  case C_HIDEXT:
 	  case C_WEAKEXT:
 	    fsym = NULL;
-	    if (!ISFCN (asym->n_type) || asym->n_numaux == 0)
+	    lnnoptr = 0;
+	    fsize = 0;
+	    if (!ISFCN (asym->n_type) || asym->n_numaux == 0
+		|| asym->n_scnum <= 0)
 	      break;
 	    if (filename == NULL)
 	      break;
+	    aux = (const b_xcoff_auxent *) (asym + 1);
+	    lnnoptr = aux->x_fcn.x_lnnoptr;
+	    if (lnnoptr < lnnoptr0
+		|| lnnoptr + LINESZ > lnnoptr0 + linenos_size)
+	      break;
+	    /* x_fsize will be 0 if there is no debug information.  */
+	    fsize = aux->x_fcn.x_fsize;
 	    fsym = asym;
 	    break;
 
@@ -1023,8 +993,11 @@ xcoff_initialize_fileline (struct backtrace_state
 	    if (fsym == NULL)
 	      break;
 	    name = xcoff_symname (asym, strtab, strtab_size);
-	    if (name == NULL)
-	      break;
+	    if (name == NULL || strcmp (name, ".bf"))
+	      {
+		fsym = NULL;
+		break;
+	      }
 	    aux = (const b_xcoff_auxent *) (asym + 1);
 #if BACKTRACE_XCOFF_SIZE == 32
 	    lnno = (uint32_t) aux->x_block.x_lnnohi << 16
@@ -1032,17 +1005,20 @@ xcoff_initialize_fileline (struct backtrace_state
 #else
 	    lnno = aux->x_block.x_lnno;
 #endif
-	    if (!strcmp (name, ".bf"))
-	      {
-		xcoff_process_linenos (state, base_address, fsym, filename,
-				       sects, strtab, strtab_size, lnno, &vec,
-				       &fdata->vec, linenos, linenos_size,
-				       lnnoptr0, error_callback, data);
-	      }
-	    else if (!strcmp (name, ".ef"))
-	      {
-		fsym = NULL;
-	      }
+	    fn = ((struct xcoff_func *)
+		  backtrace_vector_grow (state, sizeof (struct xcoff_func),
+					 error_callback, data,
+					 &fdata->func_vec.vec));
+	    if (fn == NULL)
+	      break;
+	    fn->name = xcoff_symname (fsym, strtab, strtab_size);
+	    fn->filename = filename;
+	    fn->sect_base = sects[fsym->n_scnum - 1].s_paddr;
+	    fn->pc = base_address + fsym->n_value - fn->sect_base;
+	    fn->size = fsize;
+	    fn->lnno = lnno;
+	    fn->lnnoptr = lnnoptr;
+	    ++fdata->func_vec.count;
 	    break;
 	}
 
@@ -1049,23 +1025,18 @@ xcoff_initialize_fileline (struct backtrace_state
       i += asym->n_numaux;
     }
 
-  /* Allocate one extra entry at the end.  */
-  ln = ((struct xcoff_line *)
-	backtrace_vector_grow (state, sizeof (struct xcoff_line),
-			       error_callback, data, &fdata->vec.vec));
-  if (ln == NULL)
+  if (!backtrace_vector_release (state, &fdata->func_vec.vec, error_callback,
+				 data))
     goto fail;
-  ln->pc = (uintptr_t) -1;
-  ln->filename = NULL;
-  ln->function = NULL;
-  ln->lineno = 0;
+  backtrace_qsort (fdata->func_vec.vec.base, fdata->func_vec.count,
+		   sizeof (struct xcoff_func), xcoff_func_compare);
 
-  if (!backtrace_vector_release (state, &fdata->vec.vec, error_callback, data))
+  if (!backtrace_vector_release (state, &fdata->incl_vec.vec, error_callback,
+				 data))
     goto fail;
+  backtrace_qsort (fdata->incl_vec.vec.base, fdata->incl_vec.count,
+		   sizeof (struct xcoff_incl), xcoff_incl_compare);
 
-  backtrace_qsort (fdata->vec.vec.base, fdata->vec.count,
-		   sizeof (struct xcoff_line), xcoff_line_compare);
-
   if (!state->threaded)
     {
       struct xcoff_fileline_data **pp;
@@ -1354,6 +1325,7 @@ xcoff_add (struct backtrace_state *state, int desc
     {
       size_t linenos_size = (size_t) nlnno * LINESZ;
 
+      /* We never release this view.  */
       if (!backtrace_get_view (state, descriptor, offset + lnnoptr,
 			       linenos_size,
 			       error_callback, data, &linenos_view))
@@ -1366,9 +1338,6 @@ xcoff_add (struct backtrace_state *state, int desc
 				     linenos_view.data, linenos_size,
 				     lnnoptr, error_callback, data))
 	*fileline_fn = xcoff_fileline;
-
-      backtrace_release_view (state, &linenos_view, error_callback, data);
-      linenos_view_valid = 0;
     }
 
   backtrace_release_view (state, &sects_view, error_callback, data);

Reply via email to