Fix RHBZ#494858: fix bad address checks in core file support.
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index a2487ed..d2c823f 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2009-04-14  Roland McGrath  <roland@redhat.com>
+
+	* dwfl_segment_report_module.c: Handle DT_STRTAB value being either
+	absolute (already adjusted in place) or needing load bias adjustment.
+
+	* core-file.c (dwfl_elf_phdr_memory_callback): Fix return value for
+	gelf_getphdr failure.  Fix file size limit checks.
+
+	* dwfl_segment_report_module.c: Fix underflow in DYNSTRSZ check.
+
 2009-04-08  Roland McGrath  <roland@redhat.com>
 
 	* dwfl_module_getsym.c: Don't adjust for bias again after
diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c
index bc881eb..77f208c 100644
--- a/libdwfl/core-file.c
+++ b/libdwfl/core-file.c
@@ -1,5 +1,5 @@
 /* Core file handling.
-   Copyright (C) 2008 Red Hat, Inc.
+   Copyright (C) 2008, 2009 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -278,7 +278,7 @@
 
   do
     if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
-      return true;
+      return false;
   while (phdr.p_type != PT_LOAD
 	 || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr);
 
@@ -320,8 +320,14 @@
   if (elf->map_address != NULL)
     (void) more (elf->maximum_size - start);
 
-  if (unlikely (end - start > elf->maximum_size))
-    end = start + elf->maximum_size;
+  /* Make sure we don't look past the end of the actual file,
+     even if the headers tell us to.  */
+  if (unlikely (end > elf->maximum_size))
+    end = elf->maximum_size;
+
+  /* If the file is too small, there is nothing at all to get.  */
+  if (unlikely (start >= end))
+    return false;
 
   if (elf->map_address != NULL)
     {
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index a6639be..10787bd 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -519,13 +519,28 @@
   size_t soname_size = 0;
   if (dynstrsz != 0 && dynstr_vaddr != 0)
     {
-      /* We know the bounds of the .dynstr section.  */
-      dynstr_vaddr += bias;
+      /* We know the bounds of the .dynstr section.
+
+	 The DYNSTR_VADDR pointer comes from the .dynamic section
+	 (DT_STRTAB, detected above).  Ordinarily the dynamic linker
+	 will have adjusted this pointer in place so it's now an
+	 absolute address.  But sometimes .dynamic is read-only (in
+	 vDSOs and odd architectures), and sometimes the adjustment
+	 just hasn't happened yet in the memory image we looked at.
+	 So treat DYNSTR_VADDR as an absolute address if it falls
+	 within the module bounds, or try applying the phdr bias
+	 when that adjusts it to fall within the module bounds.  */
+
+      if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
+	  && dynstr_vaddr + bias >= module_start
+	  && dynstr_vaddr + bias < module_end)
+	dynstr_vaddr += bias;
+
       if (unlikely (dynstr_vaddr + dynstrsz > module_end))
 	dynstrsz = 0;
 
       /* Try to get the DT_SONAME string.  */
-      if (soname_stroff != 0 && soname_stroff < dynstrsz - 1
+      if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
 	  && ! read_portion (&soname, &soname_size,
 			     dynstr_vaddr + soname_stroff, 0))
 	name = soname;
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 30fb445..2d4d75f 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -585,7 +585,6 @@
 	  (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
 			      memory_callback_arg);
 
-
 	  if (*elfclass == ELFCLASSNONE)
 	    *elfclass = ehdr.e_ident[EI_CLASS];
 	  else if (*elfclass != ehdr.e_ident[EI_CLASS])