Index: dwarf.c
===================================================================
--- dwarf.c	(revision 192266)
+++ dwarf.c	(working copy)
@@ -333,6 +333,10 @@ struct unit_addrs_vector
 
 struct dwarf_data
 {
+  /* The data for the next file we know about.  */
+  struct dwarf_data *next;
+  /* The base address for this file.  */
+  uintptr_t base_address;
   /* A sorted list of address ranges.  */
   struct unit_addrs *addrs;
   /* Number of address ranges in list.  */
@@ -831,12 +835,18 @@ function_addrs_search (const void *vkey,
    success, 0 on failure.  */
 
 static int
-add_unit_addr (struct backtrace_state *state, struct unit_addrs addrs,
+add_unit_addr (struct backtrace_state *state, uintptr_t base_address,
+	       struct unit_addrs addrs,
 	       backtrace_error_callback error_callback, void *data,
 	       struct unit_addrs_vector *vec)
 {
   struct unit_addrs *p;
 
+  /* Add in the base address of the module here, so that we can look
+     up the PC directly.  */
+  addrs.low += base_address;
+  addrs.high += base_address;
+
   /* Try to merge with the last entry.  */
   if (vec->count > 0)
     {
@@ -1156,9 +1166,10 @@ lookup_abbrev (struct abbrevs *abbrevs, 
    1 on success, 0 on failure.  */
 
 static int
-add_unit_ranges (struct backtrace_state *state, struct unit *u,
-		 uint64_t ranges, uint64_t base, int is_bigendian,
-		 const unsigned char *dwarf_ranges, size_t dwarf_ranges_size,
+add_unit_ranges (struct backtrace_state *state, uintptr_t base_address,
+		 struct unit *u, uint64_t ranges, uint64_t base,
+		 int is_bigendian, const unsigned char *dwarf_ranges,
+		 size_t dwarf_ranges_size,
 		 backtrace_error_callback error_callback, void *data,
 		 struct unit_addrs_vector *addrs)
 {
@@ -1202,7 +1213,8 @@ add_unit_ranges (struct backtrace_state 
 	  a.low = low + base;
 	  a.high = high + base;
 	  a.u = u;
-	  if (!add_unit_addr (state, a, error_callback, data, addrs))
+	  if (!add_unit_addr (state, base_address, a, error_callback, data,
+			      addrs))
 	    return 0;
 	}
     }
@@ -1218,7 +1230,7 @@ add_unit_ranges (struct backtrace_state 
    on success, 0 on failure.  */
 
 static int
-build_address_map (struct backtrace_state *state,
+build_address_map (struct backtrace_state *state, uintptr_t base_address,
 		   const unsigned char *dwarf_info, size_t dwarf_info_size,
 		   const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size,
 		   const unsigned char *dwarf_ranges, size_t dwarf_ranges_size,
@@ -1417,9 +1429,10 @@ build_address_map (struct backtrace_stat
 
 	  if (have_ranges)
 	    {
-	      if (!add_unit_ranges (state, u, ranges, lowpc, is_bigendian,
-				    dwarf_ranges, dwarf_ranges_size,
-				    error_callback, data, addrs))
+	      if (!add_unit_ranges (state, base_address, u, ranges, lowpc,
+				    is_bigendian, dwarf_ranges,
+				    dwarf_ranges_size, error_callback, data,
+				    addrs))
 		{
 		  free_abbrevs (state, &u->abbrevs, error_callback, data);
 		  backtrace_free (state, u, sizeof *u, error_callback, data);
@@ -1434,7 +1447,8 @@ build_address_map (struct backtrace_stat
 	      a.high = highpc;
 	      a.u = u;
 
-	      if (!add_unit_addr (state, a, error_callback, data, addrs))
+	      if (!add_unit_addr (state, base_address, a, error_callback, data,
+				  addrs))
 		{
 		  free_abbrevs (state, &u->abbrevs, error_callback, data);
 		  backtrace_free (state, u, sizeof *u, error_callback, data);
@@ -1463,8 +1477,9 @@ build_address_map (struct backtrace_stat
    building.  Returns 1 on success, 0 on failure.  */
 
 static int
-add_line (struct backtrace_state *state, uintptr_t pc, const char *filename,
-	  int lineno, backtrace_error_callback error_callback, void *data,
+add_line (struct backtrace_state *state, struct dwarf_data *ddata,
+	  uintptr_t pc, const char *filename, int lineno,
+	  backtrace_error_callback error_callback, void *data,
 	  struct line_vector *vec)
 {
   struct line *ln;
@@ -1484,7 +1499,10 @@ add_line (struct backtrace_state *state,
   if (ln == NULL)
     return 0;
 
-  ln->pc = pc;
+  /* Add in the base address here, so that we can look up the PC
+     directly.  */
+  ln->pc = pc + ddata->base_address;
+
   ln->filename = filename;
   ln->lineno = lineno;
 
@@ -1672,9 +1690,9 @@ read_line_header (struct backtrace_state
    success, 0 on failure.  */
 
 static int
-read_line_program (struct backtrace_state *state, struct unit *u,
-		   const struct line_header *hdr, struct dwarf_buf *line_buf,
-		   struct line_vector *vec)
+read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
+		   struct unit *u, const struct line_header *hdr,
+		   struct dwarf_buf *line_buf, struct line_vector *vec)
 {
   uint64_t address;
   unsigned int op_index;
@@ -1706,8 +1724,8 @@ read_line_program (struct backtrace_stat
 		      / hdr->max_ops_per_insn);
 	  op_index = (op_index + advance) % hdr->max_ops_per_insn;
 	  lineno += hdr->line_base + (int) (op % hdr->line_range);
-	  add_line (state, address, filename, lineno, line_buf->error_callback,
-		    line_buf->data, vec);
+	  add_line (state, ddata, address, filename, lineno,
+		    line_buf->error_callback, line_buf->data, vec);
 	}
       else if (op == DW_LNS_extended_op)
 	{
@@ -1795,7 +1813,7 @@ read_line_program (struct backtrace_stat
 	  switch (op)
 	    {
 	    case DW_LNS_copy:
-	      add_line (state, address, filename, lineno,
+	      add_line (state, ddata, address, filename, lineno,
 			line_buf->error_callback, line_buf->data, vec);
 	      break;
 	    case DW_LNS_advance_pc:
@@ -1923,7 +1941,7 @@ read_line_info (struct backtrace_state *
   if (!read_line_header (state, u, is_dwarf64, &line_buf, hdr))
     goto fail;
 
-  if (!read_line_program (state, u, hdr, &line_buf, &vec))
+  if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec))
     goto fail;
 
   if (line_buf.reported_underflow)
@@ -2076,13 +2094,18 @@ read_referenced_name (struct dwarf_data 
    success, 0 on error.  */
 
 static int
-add_function_range (struct backtrace_state *state, struct function *function,
-		    uint64_t lowpc, uint64_t highpc,
+add_function_range (struct backtrace_state *state, struct dwarf_data *ddata,
+		    struct function *function, uint64_t lowpc, uint64_t highpc,
 		    backtrace_error_callback error_callback,
 		    void *data, struct function_vector *vec)
 {
   struct function_addrs *p;
 
+  /* Add in the base address here, so that we can look up the PC
+     directly.  */
+  lowpc += ddata->base_address;
+  highpc += ddata->base_address;
+
   if (vec->count > 0)
     {
       p = (struct function_addrs *) vec->vec.base + vec->count - 1;
@@ -2153,8 +2176,8 @@ add_function_ranges (struct backtrace_st
 	base = high;
       else
 	{
-	  if (!add_function_range (state, function, low + base, high + base,
-				   error_callback, data, vec))
+	  if (!add_function_range (state, ddata, function, low + base,
+				   high + base, error_callback, data, vec))
 	    return 0;
 	}
     }
@@ -2364,7 +2387,7 @@ read_function_entry (struct backtrace_st
 	    {
 	      if (highpc_is_relative)
 		highpc += lowpc;
-	      if (!add_function_range (state, function, lowpc, highpc,
+	      if (!add_function_range (state, ddata, function, lowpc, highpc,
 				       error_callback, data, vec))
 		return 0;
 	    }
@@ -2522,15 +2545,17 @@ report_inlined_functions (uintptr_t pc, 
   return 0;
 }
 
-/* Return the file/line information for a PC using the DWARF mapping
-   we built earlier.  */
+/* Look for a PC in the DWARF mapping 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.  */
 
 static int
-dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
-		backtrace_full_callback callback,
-		backtrace_error_callback error_callback, void *data)
+dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
+		 uintptr_t pc, backtrace_full_callback callback,
+		 backtrace_error_callback error_callback, void *data,
+		 int *found)
 {
-  struct dwarf_data *ddata;
   struct unit_addrs *entry;
   struct unit *u;
   int new_data;
@@ -2542,14 +2567,17 @@ dwarf_fileline (struct backtrace_state *
   int lineno;
   int ret;
 
-  ddata = (struct dwarf_data *) state->fileline_data;
+  *found = 1;
 
   /* Find an address range that includes PC.  */
   entry = bsearch (&pc, ddata->addrs, ddata->addrs_count,
 		   sizeof (struct unit_addrs), unit_addrs_search);
 
   if (entry == NULL)
-    return callback (data, pc, NULL, 0, NULL);
+    {
+      *found = 0;
+      return 0;
+    }
 
   /* If there are multiple ranges that contain PC, use the last one,
      in order to produce predictable results.  If we assume that all
@@ -2656,7 +2684,8 @@ dwarf_fileline (struct backtrace_state *
 	 try again to see if there is a better compilation unit for
 	 this PC.  */
       if (new_data)
-	dwarf_fileline (state, pc, callback, error_callback, data);
+	return dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
+				data, found);
       return callback (data, pc, NULL, 0, NULL);
     }
 
@@ -2705,39 +2734,93 @@ dwarf_fileline (struct backtrace_state *
   return callback (data, pc, filename, lineno, function->name);
 }
 
-/* Build our data structures from the .debug_info and .debug_line
-   sections.  Set *FILELINE_FN and *FILELINE_DATA.  Return 1 on
-   success, 0 on failure.  */
 
-int
-backtrace_dwarf_initialize (struct backtrace_state *state,
-			    const unsigned char *dwarf_info,
-			    size_t dwarf_info_size,
-			    const unsigned char *dwarf_line,
-			    size_t dwarf_line_size,
-			    const unsigned char *dwarf_abbrev,
-			    size_t dwarf_abbrev_size,
-			    const unsigned char *dwarf_ranges,
-			    size_t dwarf_ranges_size,
-			    const unsigned char *dwarf_str,
-			    size_t dwarf_str_size,
-			    int is_bigendian,
-			    backtrace_error_callback error_callback,
-			    void *data, fileline *fileline_fn)
+/* Return the file/line information for a PC using the DWARF mapping
+   we built earlier.  */
+
+static int
+dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
+		backtrace_full_callback callback,
+		backtrace_error_callback error_callback, void *data)
+{
+  struct dwarf_data *ddata;
+  int found;
+  int ret;
+
+  if (!state->threaded)
+    {
+      for (ddata = (struct dwarf_data *) state->fileline_data;
+	   ddata != NULL;
+	   ddata = ddata->next)
+	{
+	  ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
+				 data, &found);
+	  if (ret != 0 || found)
+	    return ret;
+	}
+    }
+  else
+    {
+      struct dwarf_data **pp;
+
+      pp = (struct dwarf_data **) &state->fileline_data;
+      while (1)
+	{
+	  ddata = *pp;
+	  /* Atomic load.  */
+	  while (!__sync_bool_compare_and_swap (pp, ddata, ddata))
+	    ddata = *pp;
+
+	  if (ddata == NULL)
+	    break;
+
+	  ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
+				 data, &found);
+	  if (ret != 0 || found)
+	    return ret;
+
+	  pp = &ddata->next;
+	}
+    }
+
+  /* FIXME: See if any libraries have been dlopen'ed.  */
+
+  return callback (data, pc, NULL, 0, NULL);
+}
+
+/* Initialize our data structures from the DWARF debug info for a
+   file.  Return NULL on failure.  */
+
+static struct dwarf_data *
+build_dwarf_data (struct backtrace_state *state,
+		  uintptr_t base_address,
+		  const unsigned char *dwarf_info,
+		  size_t dwarf_info_size,
+		  const unsigned char *dwarf_line,
+		  size_t dwarf_line_size,
+		  const unsigned char *dwarf_abbrev,
+		  size_t dwarf_abbrev_size,
+		  const unsigned char *dwarf_ranges,
+		  size_t dwarf_ranges_size,
+		  const unsigned char *dwarf_str,
+		  size_t dwarf_str_size,
+		  int is_bigendian,
+		  backtrace_error_callback error_callback,
+		  void *data)
 {
   struct unit_addrs_vector addrs_vec;
   struct unit_addrs *addrs;
   size_t addrs_count;
   struct dwarf_data *fdata;
 
-  if (!build_address_map (state, dwarf_info, dwarf_info_size, dwarf_abbrev,
-			  dwarf_abbrev_size, dwarf_ranges, dwarf_ranges_size,
-			  dwarf_str, dwarf_str_size, is_bigendian,
-			  error_callback, data, &addrs_vec))
-    return 0;
+  if (!build_address_map (state, base_address, dwarf_info, dwarf_info_size,
+			  dwarf_abbrev, dwarf_abbrev_size, dwarf_ranges,
+			  dwarf_ranges_size, dwarf_str, dwarf_str_size,
+			  is_bigendian, error_callback, data, &addrs_vec))
+    return NULL;
 
   if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data))
-    return 0;
+    return NULL;
   addrs = (struct unit_addrs *) addrs_vec.vec.base;
   addrs_count = addrs_vec.count;
   qsort (addrs, addrs_count, sizeof (struct unit_addrs), unit_addrs_compare);
@@ -2746,8 +2829,10 @@ backtrace_dwarf_initialize (struct backt
 	   backtrace_alloc (state, sizeof (struct dwarf_data),
 			    error_callback, data));
   if (fdata == NULL)
-    return 0;
+    return NULL;
 
+  fdata->next = NULL;
+  fdata->base_address = base_address;
   fdata->addrs = addrs;
   fdata->addrs_count = addrs_count;
   fdata->dwarf_info = dwarf_info;
@@ -2761,7 +2846,77 @@ backtrace_dwarf_initialize (struct backt
   fdata->is_bigendian = is_bigendian;
   memset (&fdata->fvec, 0, sizeof fdata->fvec);
 
-  state->fileline_data = fdata;
+  return fdata;
+}
+
+/* Build our data structures from the DWARF sections for a module.
+   Set FILELINE_FN and STATE->FILELINE_DATA.  Return 1 on success, 0
+   on failure.  */
+
+int
+backtrace_dwarf_add (struct backtrace_state *state,
+		     uintptr_t base_address,
+		     const unsigned char *dwarf_info,
+		     size_t dwarf_info_size,
+		     const unsigned char *dwarf_line,
+		     size_t dwarf_line_size,
+		     const unsigned char *dwarf_abbrev,
+		     size_t dwarf_abbrev_size,
+		     const unsigned char *dwarf_ranges,
+		     size_t dwarf_ranges_size,
+		     const unsigned char *dwarf_str,
+		     size_t dwarf_str_size,
+		     int is_bigendian,
+		     backtrace_error_callback error_callback,
+		     void *data, fileline *fileline_fn)
+{
+  struct dwarf_data *fdata;
+
+  fdata = build_dwarf_data (state, base_address, dwarf_info, dwarf_info_size,
+			    dwarf_line, dwarf_line_size, dwarf_abbrev,
+			    dwarf_abbrev_size, dwarf_ranges, dwarf_ranges_size,
+			    dwarf_str, dwarf_str_size, is_bigendian,
+			    error_callback, data);
+  if (fdata == NULL)
+    return 0;
+
+  if (!state->threaded)
+    {
+      struct dwarf_data **pp;
+
+      for (pp = (struct dwarf_data **) &state->fileline_data;
+	   *pp != NULL;
+	   pp = &(*pp)->next)
+	;
+      *pp = fdata;
+    }
+  else
+    {
+      while (1)
+	{
+	  struct dwarf_data **pp;
+
+	  pp = (struct dwarf_data **) &state->fileline_data;
+
+	  while (1)
+	    {
+	      struct dwarf_data *p;
+
+	      /* Atomic load.  */
+	      p = *pp;
+	      while (!__sync_bool_compare_and_swap (pp, p, p))
+		p = *pp;
+
+	      if (p == NULL)
+		break;
+
+	      pp = &p->next;
+	    }
+
+	  if (__sync_bool_compare_and_swap (pp, NULL, fdata))
+	    break;
+	}
+    }
 
   *fileline_fn = dwarf_fileline;
 
Index: elf.c
===================================================================
--- elf.c	(revision 192266)
+++ elf.c	(working copy)
@@ -36,9 +36,36 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #include <string.h>
 #include <sys/types.h>
 
+#ifdef HAVE_DL_ITERATE_PHDR
+#include <link.h>
+#endif
+
 #include "backtrace.h"
 #include "internal.h"
 
+#ifndef HAVE_DL_ITERATE_PHDR
+
+/* Dummy version of dl_iterate_phdr for systems that don't have it.  */
+
+#define dl_phdr_info x_dl_phdr_info
+#define dl_iterate_phdr x_dl_iterate_phdr
+
+struct dl_phdr_info
+{
+  uintptr_t dlpi_addr;
+  const char *dlpi_name;
+};
+
+static int
+dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
+				  size_t, void *) ATTRIBUTE_UNUSED,
+		 void *data ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */
+
 /* The configure script must tell us whether we are 32-bit or 64-bit
    ELF.  We could make this code test and support either possibility,
    but there is no point.  This code only works for the currently
@@ -49,6 +76,33 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #error "Unknown BACKTRACE_ELF_SIZE"
 #endif
 
+/* <link.h> might #include <elf.h> which might define our constants
+   with slightly different values.  Undefine them to be safe.  */
+
+#undef EI_NIDENT
+#undef EI_MAG0
+#undef EI_MAG1
+#undef EI_MAG2
+#undef EI_MAG3
+#undef EI_CLASS
+#undef EI_DATA
+#undef EI_VERSION
+#undef ELF_MAG0
+#undef ELF_MAG1
+#undef ELF_MAG2
+#undef ELF_MAG3
+#undef ELFCLASS32
+#undef ELFCLASS64
+#undef ELFDATA2LSB
+#undef ELFDATA2MSB
+#undef EV_CURRENT
+#undef SHN_LORESERVE
+#undef SHN_XINDEX
+#undef SHT_SYMTAB
+#undef SHT_STRTAB
+#undef SHT_DYNSYM
+#undef STT_FUNC
+
 /* Basic types.  */
 
 typedef uint16_t Elf_Half;
@@ -214,6 +268,8 @@ struct elf_symbol
 
 struct elf_syminfo_data
 {
+  /* Symbols for the next module.  */
+  struct elf_syminfo_data *next;
   /* The ELF symbols, sorted by address.  */
   struct elf_symbol *symbols;
   /* The number of symbols.  */
@@ -337,12 +393,58 @@ elf_initialize_syminfo (struct backtrace
   qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol),
 	 elf_symbol_compare);
 
+  sdata->next = NULL;
   sdata->symbols = elf_symbols;
   sdata->count = elf_symbol_count;
 
   return 1;
 }
 
+/* Add EDATA to the list in STATE.  */
+
+static void
+elf_add_syminfo_data (struct backtrace_state *state,
+		      struct elf_syminfo_data *edata)
+{
+  if (!state->threaded)
+    {
+      struct elf_syminfo_data **pp;
+
+      for (pp = (struct elf_syminfo_data **) &state->syminfo_data;
+	   *pp != NULL;
+	   pp = &(*pp)->next)
+	;
+      *pp = edata;
+    }
+  else
+    {
+      while (1)
+	{
+	  struct elf_syminfo_data **pp;
+
+	  pp = (struct elf_syminfo_data **) &state->syminfo_data;
+
+	  while (1)
+	    {
+	      struct elf_syminfo_data *p;
+
+	      /* Atomic load.  */
+	      p = *pp;
+	      while (!__sync_bool_compare_and_swap (pp, p, p))
+		p = *pp;
+
+	      if (p == NULL)
+		break;
+
+	      pp = &p->next;
+	    }
+
+	  if (__sync_bool_compare_and_swap (pp, NULL, edata))
+	    break;
+	}
+    }
+}
+
 /* Return the symbol name and value for a PC.  */
 
 static void
@@ -364,14 +466,12 @@ elf_syminfo (struct backtrace_state *sta
     callback (data, pc, sym->name, sym->address);
 }
 
-/* Initialize the backtrace data we need from an ELF executable.  At
-   the ELF level, all we need to do is find the debug info
-   sections.  */
+/* Add the backtrace data for one ELF file.  */
 
-int
-backtrace_initialize (struct backtrace_state *state, int descriptor,
-		      backtrace_error_callback error_callback,
-		      void *data, fileline *fileline_fn)
+static int
+elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
+	 backtrace_error_callback error_callback, void *data,
+	 fileline *fileline_fn, int *found_sym, int *found_dwarf)
 {
   struct backtrace_view ehdr_view;
   Elf_Ehdr ehdr;
@@ -400,6 +500,9 @@ backtrace_initialize (struct backtrace_s
   struct backtrace_view debug_view;
   int debug_view_valid;
 
+  *found_sym = 0;
+  *found_dwarf = 0;
+
   shdrs_view_valid = 0;
   names_view_valid = 0;
   symtab_view_valid = 0;
@@ -516,6 +619,8 @@ backtrace_initialize (struct backtrace_s
   dynsym_shndx = 0;
 
   memset (sections, 0, sizeof sections);
+
+  /* Look for the symbol table.  */
   for (i = 1; i < shnum; ++i)
     {
       const Elf_Shdr *shdr;
@@ -552,12 +657,7 @@ backtrace_initialize (struct backtrace_s
 
   if (symtab_shndx == 0)
     symtab_shndx = dynsym_shndx;
-  if (symtab_shndx == 0)
-    {
-      state->syminfo_fn = elf_nosyms;
-      state->syminfo_data = NULL;
-    }
-  else
+  if (symtab_shndx != 0)
     {
       const Elf_Shdr *symtab_shdr;
       unsigned int strtab_shndx;
@@ -604,8 +704,9 @@ backtrace_initialize (struct backtrace_s
 	 string table permanently.  */
       backtrace_release_view (state, &symtab_view, error_callback, data);
 
-      state->syminfo_fn = elf_syminfo;
-      state->syminfo_data = sdata;
+      *found_sym = 1;
+
+      elf_add_syminfo_data (state, sdata);
     }
 
   /* FIXME: Need to handle compressed debug sections.  */
@@ -635,7 +736,6 @@ backtrace_initialize (struct backtrace_s
       if (!backtrace_close (descriptor, error_callback, data))
 	goto fail;
       *fileline_fn = elf_nodebug;
-      state->fileline_data = NULL;
       return 1;
     }
 
@@ -654,21 +754,23 @@ backtrace_initialize (struct backtrace_s
     sections[i].data = ((const unsigned char *) debug_view.data
 			+ (sections[i].offset - min_offset));
 
-  if (!backtrace_dwarf_initialize (state,
-				   sections[DEBUG_INFO].data,
-				   sections[DEBUG_INFO].size,
-				   sections[DEBUG_LINE].data,
-				   sections[DEBUG_LINE].size,
-				   sections[DEBUG_ABBREV].data,
-				   sections[DEBUG_ABBREV].size,
-				   sections[DEBUG_RANGES].data,
-				   sections[DEBUG_RANGES].size,
-				   sections[DEBUG_STR].data,
-				   sections[DEBUG_STR].size,
-				   ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
-				   error_callback, data, fileline_fn))
+  if (!backtrace_dwarf_add (state, base_address,
+			    sections[DEBUG_INFO].data,
+			    sections[DEBUG_INFO].size,
+			    sections[DEBUG_LINE].data,
+			    sections[DEBUG_LINE].size,
+			    sections[DEBUG_ABBREV].data,
+			    sections[DEBUG_ABBREV].size,
+			    sections[DEBUG_RANGES].data,
+			    sections[DEBUG_RANGES].size,
+			    sections[DEBUG_STR].data,
+			    sections[DEBUG_STR].size,
+			    ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
+			    error_callback, data, fileline_fn))
     goto fail;
 
+  *found_dwarf = 1;
+
   return 1;
 
  fail:
@@ -686,3 +788,115 @@ backtrace_initialize (struct backtrace_s
     backtrace_close (descriptor, error_callback, data);
   return 0;
 }
+
+/* Data passed to phdr_callback.  */
+
+struct phdr_data
+{
+  struct backtrace_state *state;
+  backtrace_error_callback error_callback;
+  void *data;
+  fileline *fileline_fn;
+  int *found_sym;
+  int *found_dwarf;
+};
+
+/* Callback passed to dl_iterate_phdr.  Load debug info from shared
+   libraries.  */
+
+static int
+phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
+	       void *pdata)
+{
+  struct phdr_data *pd = (struct phdr_data *) pdata;
+  int descriptor;
+  fileline elf_fileline_fn;
+  int found_dwarf;
+
+  /* There is not much we can do if we don't have the module name.  If
+     the base address is 0, this is probably the executable, which we
+     already loaded.  */
+  if (info->dlpi_name == NULL
+      || info->dlpi_name[0] == '\0'
+      || info->dlpi_addr == 0)
+    return 0;
+
+  descriptor = backtrace_open (info->dlpi_name, pd->error_callback, pd->data);
+  if (descriptor < 0)
+    return 0;
+
+  if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback,
+	       pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf))
+    {
+      if (found_dwarf)
+	{
+	  *pd->found_dwarf = 1;
+	  *pd->fileline_fn = elf_fileline_fn;
+	}
+    }
+
+  return 0;
+}
+
+/* Initialize the backtrace data we need from an ELF executable.  At
+   the ELF level, all we need to do is find the debug info
+   sections.  */
+
+int
+backtrace_initialize (struct backtrace_state *state, int descriptor,
+		      backtrace_error_callback error_callback,
+		      void *data, fileline *fileline_fn)
+{
+  int found_sym;
+  int found_dwarf;
+  syminfo elf_syminfo_fn;
+  fileline elf_fileline_fn;
+  struct phdr_data pd;
+
+  if (!elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
+		&found_sym, &found_dwarf))
+    return 0;
+
+  pd.state = state;
+  pd.error_callback = error_callback;
+  pd.data = data;
+  pd.fileline_fn = fileline_fn;
+  pd.found_sym = &found_sym;
+  pd.found_dwarf = &found_dwarf;
+
+  dl_iterate_phdr (phdr_callback, (void *) &pd);
+
+  elf_syminfo_fn = found_sym ? elf_syminfo : elf_nosyms;
+  if (!state->threaded)
+    {
+      if (state->syminfo_fn == NULL || found_sym)
+	state->syminfo_fn = elf_syminfo_fn;
+    }
+  else
+    {
+      __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, elf_syminfo_fn);
+      if (found_sym)
+	__sync_bool_compare_and_swap (&state->syminfo_fn, elf_nosyms,
+				      elf_syminfo_fn);
+    }
+
+  if (!state->threaded)
+    {
+      if (state->fileline_fn == NULL || state->fileline_fn == elf_nodebug)
+	*fileline_fn = elf_fileline_fn;
+    }
+  else
+    {
+      fileline current_fn;
+
+      /* Atomic load.  */
+      current_fn = state->fileline_fn;
+      while (!__sync_bool_compare_and_swap (&state->fileline_fn, current_fn,
+					    current_fn))
+	current_fn = state->fileline_fn;
+      if (current_fn == NULL || current_fn == elf_nodebug)
+	*fileline_fn = elf_fileline_fn;
+    }
+
+  return 1;
+}
Index: internal.h
===================================================================
--- internal.h	(revision 192266)
+++ internal.h	(working copy)
@@ -215,21 +215,22 @@ extern int backtrace_initialize (struct 
 				 void *data,
 				 fileline *fileline_fn);
 
-/* Prepare to read file/line information from DWARF debug data.  */
+/* Add file/line information for a DWARF module.  */
 
-extern int backtrace_dwarf_initialize (struct backtrace_state *state,
-				       const unsigned char* dwarf_info,
-				       size_t dwarf_info_size,
-				       const unsigned char *dwarf_line,
-				       size_t dwarf_line_size,
-				       const unsigned char *dwarf_abbrev,
-				       size_t dwarf_abbrev_size,
-				       const unsigned char *dwarf_ranges,
-				       size_t dwarf_range_size,
-				       const unsigned char *dwarf_str,
-				       size_t dwarf_str_size,
-				       int is_bigendian,
-				       backtrace_error_callback error_callback,
-				       void *data, fileline *fileline_fn);
+extern int backtrace_dwarf_add (struct backtrace_state *state,
+				uintptr_t base_address,
+				const unsigned char* dwarf_info,
+				size_t dwarf_info_size,
+				const unsigned char *dwarf_line,
+				size_t dwarf_line_size,
+				const unsigned char *dwarf_abbrev,
+				size_t dwarf_abbrev_size,
+				const unsigned char *dwarf_ranges,
+				size_t dwarf_range_size,
+				const unsigned char *dwarf_str,
+				size_t dwarf_str_size,
+				int is_bigendian,
+				backtrace_error_callback error_callback,
+				void *data, fileline *fileline_fn);
 
 #endif
Index: configure.ac
===================================================================
--- configure.ac	(revision 192266)
+++ configure.ac	(working copy)
@@ -226,6 +226,24 @@ if test "$ALLOC_FILE" = "alloc.lo"; then
 fi
 AC_SUBST(BACKTRACE_USES_MALLOC)
 
+# Check for dl_iterate_phdr.
+AC_CHECK_HEADERS(link.h)
+if test "$ac_cv_header_link_h" = "no"; then
+  have_dl_iterate_phdr=no
+else
+  if test -n "${with_target_subdir}"; then
+    # When built as a GCC target library, we can't do a link test.
+    AC_EGREP_HEADER([dl_iterate_phdr], [link.h], [have_dl_iterate_phdr=yes],
+		    [have_dl_iterate_phdr=no])
+  else
+    AC_CHECK_FUNC([dl_iterate_phdr], [have_dl_iterate_phdr=yes],
+		  [have_dl_iterate_phdr=no])
+  fi
+fi
+if test "$have_dl_iterate_phdr" = "yes"; then
+  AC_DEFINE(HAVE_DL_ITERATE_PHDR, 1, [Define if dl_iterate_phdr is available.])
+fi
+
 # Check for the fcntl function.
 if test -n "${with_target_subdir}"; then
    case "${host}" in
