]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
propagate from branch 'com.redhat.elfutils.roland.pending' (head e0c7abd450c9e49093cf...
authorUlrich Drepper <drepper@redhat.com>
Tue, 13 Mar 2007 06:22:40 +0000 (06:22 +0000)
committerUlrich Drepper <drepper@redhat.com>
Tue, 13 Mar 2007 06:22:40 +0000 (06:22 +0000)
            to branch 'com.redhat.elfutils' (head 2c784d50eee72e33972c333138a3a28df304da63)

18 files changed:
NEWS
libdw/ChangeLog
libdw/libdw.map
libdwfl/ChangeLog
libdwfl/Makefile.am
libdwfl/dwfl_module.c
libdwfl/dwfl_module_addrname.c
libdwfl/dwfl_module_addrsym.c [new file with mode: 0644]
libdwfl/dwfl_module_getdwarf.c
libdwfl/elf-from-memory.c
libdwfl/libdwfl.h
libdwfl/libdwflP.h
libdwfl/linux-kernel-modules.c
libdwfl/offline.c
tests/ChangeLog
tests/Makefile.am
tests/dwfl-bug-fd-leak.c [new file with mode: 0644]
tests/dwflmodtest.c

diff --git a/NEWS b/NEWS
index b1e968567eda5d3053290492cc995d90c3b085dd..a7a5e32993c44dcea6daf0838770da7dc0811475 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Version 0.127-UNFINISHED:
+
+libdwfl: new function dwfl_module_addrsym
+
 Version 0.126:
 
 new program: ar
index 61170d59f407cbcf33a5c7cc51cb6fbefe71cce3..76f04bb9f259d6bb98a0f9f642efbb8e529af008 100644 (file)
@@ -1,3 +1,12 @@
+2007-03-12  Roland McGrath  <roland@redhat.com>
+
+       * libdw.map (ELFUTILS_0.127): Add dwfl_report_begin_add.
+
+2007-03-04  Roland McGrath  <roland@redhat.com>
+
+       * libdw.map (ELFUTILS_0.127): New version set, inherits from
+       ELFUTILS_0.126.  Add dwfl_module_addrsym.
+
 2007-02-10  Roland McGrath  <roland@redhat.com>
 
        * dwarf.h (DW_OP_fbreg): Comment fix.
index 71e9f50fe96cc583aa95bbd07257539990dd8ddc..e79b6e01abb191945e1e112131f3e69f8716e534 100644 (file)
@@ -145,6 +145,7 @@ ELFUTILS_0.122 {
   local:
     *;
 } ELFUTILS_0;
+
 ELFUTILS_0.126 {
   global:
     dwarf_getelf;
@@ -152,3 +153,12 @@ ELFUTILS_0.126 {
   local:
     *;
 } ELFUTILS_0.122;
+
+ELFUTILS_0.127 {
+  global:
+    dwfl_module_addrsym;
+    dwfl_report_begin_add;
+
+  local:
+    *;
+} ELFUTILS_0.126;
index 71b167f351e544c934800da180090a2b8d65f601..02829e30f2c4e09b3c0746c3bb941efb035eaa77 100644 (file)
@@ -1,3 +1,47 @@
+2007-03-12  Roland McGrath  <roland@redhat.com>
+
+       * dwfl_module.c (dwfl_report_begin_add): New function broken out of ...
+       (dwfl_report_begin): ... here.  Call it.
+       * libdwfl.h: Declare it.
+       * libdwflP.h: Add INTDECL.
+
+       * elf-from-memory.c (elf_from_remote_memory): Fix 32/64 typo.
+
+       * offline.c: Comment typo fix.
+
+2007-03-04  Roland McGrath  <roland@redhat.com>
+
+       * linux-kernel-modules.c (KERNEL_MODNAME): New macro for "kernel".
+       (find_kernel_elf): New function, broken out of ...
+       (report_kernel): ... here.  Call it.
+       (dwfl_linux_kernel_find_elf): Use it for module named KERNEL_MODNAME.
+       (intuit_kernel_bounds): New function, grovel /proc/kallsyms to guess
+       virtual address bounds of kernel from symbols rounded to page size.
+       (dwfl_linux_kernel_report_kernel): Use that if it works, before
+       resorting to report_kernel.
+
+       * dwfl_module_getdwarf.c (open_elf): Set MOD->e_type to ET_DYN for an
+       ET_EXEC file with nonzero bias.
+
+       * dwfl_module_addrname.c (dwfl_module_addrname): Just call
+       dwfl_module_addrsym.  Guts moved to ...
+       * dwfl_module_addrsym.c: ... here; new file.
+       * Makefile.am (libdwfl_a_SOURCES): Add it.
+       * libdwfl.h: Declare dwfl_module_addrsym.
+       * libdwflP.h: Add INTDECL.
+
+2007-03-03  Roland McGrath  <roland@redhat.com>
+
+       * dwfl_module.c (free_file): New function, broken out of ...
+       (__libdwfl_module_free): ... here.  In it, close fd after elf_end.
+
+       * dwfl_module_getdwarf.c (open_elf): Close fd and reset to -1
+       on libelf failure.
+
+2007-03-02  Roland McGrath  <roland@redhat.com>
+
+       * linux-kernel-modules.c: Fix bogus error test for asprintf call.
+
 2007-02-02  Roland McGrath  <roland@redhat.com>
 
        * dwfl_addrmodule.c (dwfl_addrmodule): Match a module's high boundary
index ee9efec93cdcc712a791e29da5114b3602e5e780..e5cbb979485788c109005adee9e1f25dfc411f6e 100644 (file)
@@ -2,7 +2,7 @@
 ##
 ## Process this file with automake to create Makefile.in
 ##
-## Copyright (C) 2005, 2006 Red Hat, Inc.
+## Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
 ## This file is part of Red Hat elfutils.
 ##
 ## Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -66,7 +66,8 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
                    dwfl_module_getsrc_file.c \
                    libdwfl_crc32.c libdwfl_crc32_file.c \
                    elf-from-memory.c \
-                   dwfl_module_getsym.c dwfl_module_addrname.c \
+                   dwfl_module_getsym.c \
+                   dwfl_module_addrname.c dwfl_module_addrsym.c \
                    dwfl_module_return_value_location.c \
                    dwfl_module_register_names.c
 
index 16c616d26fe318e9031d7ba2a8354574c65d1c60..08730ec64a1139f358161d5ad0b7656d41517baa 100644 (file)
@@ -1,5 +1,5 @@
 /* Maintenance of module list in libdwfl.
-   Copyright (C) 2005, 2006 Red Hat, Inc.
+   Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -49,6 +49,7 @@
 
 #include "libdwflP.h"
 #include <search.h>
+#include <unistd.h>
 
 static void
 free_cu (struct dwfl_cu *cu)
@@ -63,6 +64,17 @@ nofree (void *arg __attribute__ ((unused)))
 {
 }
 
+static void
+free_file (struct dwfl_file *file)
+{
+  if (file->elf != NULL)
+    {
+      elf_end (file->elf);
+      if (file->fd != -1)
+       close (file->fd);
+    }
+}
+
 void
 internal_function
 __libdwfl_module_free (Dwfl_Module *mod)
@@ -86,24 +98,30 @@ __libdwfl_module_free (Dwfl_Module *mod)
   if (mod->ebl != NULL)
     ebl_closebackend (mod->ebl);
 
-  if (mod->debug.elf != mod->main.elf && mod->debug.elf != NULL)
-    elf_end (mod->debug.elf);
-  if (mod->main.elf != NULL)
-    elf_end (mod->main.elf);
+  if (mod->debug.elf != mod->main.elf)
+    free_file (&mod->debug);
+  free_file (&mod->main);
 
   free (mod->name);
 }
 
 void
-dwfl_report_begin (Dwfl *dwfl)
+dwfl_report_begin_add (Dwfl *dwfl)
 {
-  for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
-    m->gc = true;
-
   if (dwfl->modules != NULL)
     free (dwfl->modules);
   dwfl->modules = NULL;
   dwfl->nmodules = 0;
+}
+INTDEF (dwfl_report_begin_add)
+
+void
+dwfl_report_begin (Dwfl *dwfl)
+{
+  INTUSE(dwfl_report_begin_add) (dwfl);
+
+  for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
+    m->gc = true;
 
   dwfl->offline_next_address = OFFLINE_REDZONE;
 }
index b107448bcae0bf124b4e14d2129d913361a33fbc..7d365fe2c2d7e17ec2055299b400b0a52e43ae78 100644 (file)
 const char *
 dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr addr)
 {
-  int syments = INTUSE(dwfl_module_getsymtab) (mod);
-  if (syments < 0)
-    return NULL;
-
-  /* Return true iff we consider ADDR to lie in the same section as SYM.  */
-  GElf_Word addr_shndx = SHN_UNDEF;
-  inline bool same_section (const GElf_Sym *sym, GElf_Word shndx)
-    {
-      /* For absolute symbols and the like, only match exactly.  */
-      if (shndx >= SHN_LORESERVE)
-       return sym->st_value == addr;
-
-      /* Ignore section and other special symbols.  */
-      switch (GELF_ST_TYPE (sym->st_info))
-       {
-       case STT_SECTION:
-       case STT_FILE:
-       case STT_TLS:
-         return false;
-       }
-
-      /* Figure out what section ADDR lies in.  */
-      if (addr_shndx == SHN_UNDEF)
-       {
-         GElf_Addr mod_addr = addr - mod->symfile->bias;
-         Elf_Scn *scn = NULL;
-         addr_shndx = SHN_ABS;
-         while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
-           {
-             GElf_Shdr shdr_mem;
-             GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-             if (likely (shdr != NULL)
-                 && mod_addr >= shdr->sh_addr
-                 && mod_addr < shdr->sh_addr + shdr->sh_size)
-               {
-                 addr_shndx = elf_ndxscn (scn);
-                 break;
-               }
-           }
-       }
-
-      return shndx == addr_shndx;
-    }
-
-  /* Look through the symbol table for a matching symbol.  */
-  const char *closest = NULL;
-  GElf_Addr closest_value = 0;
-  for (int i = 1; i < syments; ++i)
-    {
-      GElf_Sym sym;
-      GElf_Word shndx;
-      const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
-      if (name != NULL && sym.st_value <= addr)
-       {
-         if (addr < sym.st_value + sym.st_size)
-           return name;
-
-         /* Handwritten assembly symbols sometimes have no st_size.
-            If no symbol with proper size includes the address, we'll
-            use the closest one that is in the same section as ADDR.   */
-         if (sym.st_size == 0 && sym.st_value >= closest_value
-             && same_section (&sym, shndx))
-           {
-             closest_value = sym.st_value;
-             closest = name;
-           }
-       }
-    }
-
-  return closest;
+  GElf_Sym sym;
+  return INTUSE(dwfl_module_addrsym) (mod, addr, &sym, NULL);
 }
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
new file mode 100644 (file)
index 0000000..98ab15a
--- /dev/null
@@ -0,0 +1,137 @@
+/* Find debugging and symbol information for a module in libdwfl.
+   Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include "libdwflP.h"
+
+const char *
+dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
+                    GElf_Sym *closest_sym, GElf_Word *shndxp)
+{
+  int syments = INTUSE(dwfl_module_getsymtab) (mod);
+  if (syments < 0)
+    return NULL;
+
+  /* Return true iff we consider ADDR to lie in the same section as SYM.  */
+  GElf_Word addr_shndx = SHN_UNDEF;
+  inline bool same_section (const GElf_Sym *sym, GElf_Word shndx)
+    {
+      /* For absolute symbols and the like, only match exactly.  */
+      if (shndx >= SHN_LORESERVE)
+       return sym->st_value == addr;
+
+      /* Ignore section and other special symbols.  */
+      switch (GELF_ST_TYPE (sym->st_info))
+       {
+       case STT_SECTION:
+       case STT_FILE:
+       case STT_TLS:
+         return false;
+       }
+
+      /* Figure out what section ADDR lies in.  */
+      if (addr_shndx == SHN_UNDEF)
+       {
+         GElf_Addr mod_addr = addr - mod->symfile->bias;
+         Elf_Scn *scn = NULL;
+         addr_shndx = SHN_ABS;
+         while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
+           {
+             GElf_Shdr shdr_mem;
+             GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+             if (likely (shdr != NULL)
+                 && mod_addr >= shdr->sh_addr
+                 && mod_addr < shdr->sh_addr + shdr->sh_size)
+               {
+                 addr_shndx = elf_ndxscn (scn);
+                 break;
+               }
+           }
+       }
+
+      return shndx == addr_shndx;
+    }
+
+  /* Look through the symbol table for a matching symbol.  */
+  const char *closest_name = NULL;
+  closest_sym->st_value = 0;
+  GElf_Word closest_shndx = SHN_UNDEF;
+  for (int i = 1; i < syments; ++i)
+    {
+      GElf_Sym sym;
+      GElf_Word shndx;
+      const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
+      if (name != NULL && sym.st_value <= addr)
+       {
+         inline void closest (void)
+           {
+             *closest_sym = sym;
+             closest_shndx = shndx;
+             closest_name = name;
+           }
+
+         if (addr < sym.st_value + sym.st_size)
+           {
+             closest ();
+             break;
+           }
+
+         /* Handwritten assembly symbols sometimes have no st_size.
+            If no symbol with proper size includes the address, we'll
+            use the closest one that is in the same section as ADDR.   */
+         if (sym.st_size == 0 && sym.st_value >= closest_sym->st_value
+             && same_section (&sym, shndx))
+           closest ();
+       }
+    }
+
+  if (shndxp != NULL)
+    *shndxp = closest_shndx;
+  return closest_name;
+}
+INTDEF (dwfl_module_addrsym)
index 07248bf78e4d509405c5311e776ea6bfd62ba267..3a22c3bebf6cbafb0b3c5958db48eceaac8b36a1 100644 (file)
@@ -1,5 +1,5 @@
 /* Find debugging and symbol information for a module in libdwfl.
-   Copyright (C) 2005, 2006 Red Hat, Inc.
+   Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -69,9 +69,12 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
 
   GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
   if (ehdr == NULL)
-    return DWFL_E (LIBELF, elf_errno ());
-
-  mod->e_type = ehdr->e_type;
+    {
+    elf_error:
+      close (file->fd);
+      file->fd = -1;
+      return DWFL_E_LIBELF;
+    }
 
   file->bias = 0;
   for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
@@ -79,7 +82,7 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
       GElf_Phdr ph_mem;
       GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
       if (ph == NULL)
-       return DWFL_E_LIBELF;
+       goto elf_error;
       if (ph->p_type == PT_LOAD)
        {
          file->bias = ((mod->low_addr & -ph->p_align)
@@ -88,6 +91,12 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
        }
     }
 
+  mod->e_type = ehdr->e_type;
+
+  /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN.  */
+  if (mod->e_type == ET_EXEC && file->bias != 0)
+    mod->e_type = ET_DYN;
+
   return DWFL_E_NOERROR;
 }
 
index 2a174759b93ef81a25ed1f5d4fe8fec9f4c25db0..a292210ae4c9a2d67d36a1b0aad3dc6b2bc5b0a9 100644 (file)
@@ -1,5 +1,5 @@
 /* Reconstruct an ELF file by reading the segments out of remote memory.
-   Copyright (C) 2005, 2006 Red Hat, Inc.
+   Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -154,7 +154,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
 
     case ELFCLASS64:
       xlatefrom.d_size = sizeof (Elf64_Ehdr);
-      if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
+      if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
        goto libelf_error;
       phoff = ehdr.e64.e_phoff;
       phnum = ehdr.e64.e_phnum;
index ec006562716cf83e9683450a3178387eaa27fe74..c36f9206bc3f104c168c1acb0d9663040781bda6 100644 (file)
@@ -156,6 +156,14 @@ extern int dwfl_report_end (Dwfl *dwfl,
                                            void *arg),
                            void *arg);
 
+/* Start reporting additional modules to the library.  No calls but
+   dwfl_report_* can be made on DWFL until dwfl_report_end is called.
+   This is like dwfl_report_begin, but all the old modules are kept on.
+   More dwfl_report_* calls can follow to add more modules.
+   When dwfl_report_end is called, no old modules will be removed.  */
+extern void dwfl_report_begin_add (Dwfl *dwfl);
+
+
 /* Return the name of the module, and for each non-null argument store
    interesting details: *USERDATA is a location for storing your own
    pointer, **USERDATA is initially null; *START and *END give the address
@@ -332,6 +340,12 @@ extern const char *dwfl_module_getsym (Dwfl_Module *mod, int ndx,
 /* Find the symbol that ADDRESS lies inside, and return its name.  */
 extern const char *dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr address);
 
+/* Find the symbol that ADDRESS lies inside, and return detailed
+   information as for dwfl_module_getsym (above).  */
+extern const char *dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr address,
+                                       GElf_Sym *sym, GElf_Word *shndxp)
+  __nonnull_attribute__ (3);
+
 
 /*** Dwarf access functions ***/
 
index 31da938db982db956d9290480ace9aff7b304884..25e9a4e8642637302b3a49460d4fb6f13b59b1fd 100644 (file)
@@ -1,5 +1,5 @@
 /* Internal definitions for libdwfl.
-   Copyright (C) 2005, 2006 Red Hat, Inc.
+   Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -269,6 +269,7 @@ INTDECL (dwfl_addrmodule)
 INTDECL (dwfl_addrdwarf)
 INTDECL (dwfl_addrdie)
 INTDECL (dwfl_module_addrdie)
+INTDECL (dwfl_module_addrsym)
 INTDECL (dwfl_module_getdwarf)
 INTDECL (dwfl_module_getelf)
 INTDECL (dwfl_module_getsym)
@@ -276,6 +277,7 @@ INTDECL (dwfl_module_getsymtab)
 INTDECL (dwfl_module_getsrc)
 INTDECL (dwfl_report_elf)
 INTDECL (dwfl_report_begin)
+INTDECL (dwfl_report_begin_add)
 INTDECL (dwfl_report_module)
 INTDECL (dwfl_report_offline)
 INTDECL (dwfl_report_end)
index 4ea391c07b5fee8226fa616b2c8ff3dd9c5089a3..2aaa25acb942954f644c70762522dbcfda42a898 100644 (file)
 #include <fts.h>
 
 
+#define KERNEL_MODNAME "kernel"
+
 #define MODULEDIRFMT   "/lib/modules/%s"
 
+#define KSYMSFILE      "/proc/kallsyms"
 #define MODULELIST     "/proc/modules"
 #define        SECADDRDIRFMT   "/sys/module/%s/sections/"
 #define MODULE_SECT_NAME_LEN 32        /* Minimum any linux/module.h has had.  */
@@ -115,6 +118,26 @@ kernel_release (void)
   return utsname.release;
 }
 
+static int
+find_kernel_elf (Dwfl *dwfl, const char *release, char **fname)
+{
+  if ((release[0] == '/'
+       ? asprintf (fname, "%s/vmlinux", release)
+       : asprintf (fname, "/boot/vmlinux-%s", release)) < 0)
+    return -1;
+
+  int fd = try_kernel_name (dwfl, fname);
+  if (fd < 0 && release[0] != '/')
+    {
+      free (*fname);
+      if (asprintf (fname, MODULEDIRFMT "/vmlinux", release) < 0)
+       return -1;
+      fd = try_kernel_name (dwfl, fname);
+    }
+
+  return fd;
+}
+
 static int
 report_kernel (Dwfl *dwfl, const char *release,
               int (*predicate) (const char *module, const char *file))
@@ -122,23 +145,19 @@ report_kernel (Dwfl *dwfl, const char *release,
   if (dwfl == NULL)
     return -1;
 
-  char *fname;
-  if ((release[0] == '/'
-       ? asprintf (&fname, "%s/vmlinux", release)
-       : asprintf (&fname, "/boot/vmlinux-%s", release)) < 0)
-    return -1;
-  int fd = try_kernel_name (dwfl, &fname);
-  if (fd < 0 && release[0] != '/')
+  if (release == NULL)
     {
-      free (fname);
-      if (asprintf (&fname, MODULEDIRFMT "/vmlinux", release) < 0)
-       return -1;
-      fd = try_kernel_name (dwfl, &fname);
+      release = kernel_release ();
+      if (release == NULL)
+       return errno;
     }
 
+  char *fname;
+  int fd = find_kernel_elf (dwfl, release, &fname);
+
   int result = 0;
   if (fd < 0)
-    result = ((predicate != NULL && !(*predicate) ("kernel", NULL))
+    result = ((predicate != NULL && !(*predicate) (KERNEL_MODNAME, NULL))
              ? 0 : errno ?: ENOENT);
   else
     {
@@ -147,14 +166,15 @@ report_kernel (Dwfl *dwfl, const char *release,
       if (predicate != NULL)
        {
          /* Let the predicate decide whether to use this one.  */
-         int want = (*predicate) ("kernel", fname);
+         int want = (*predicate) (KERNEL_MODNAME, fname);
          if (want < 0)
            result = errno;
          report = want > 0;
        }
 
       if (report
-         && INTUSE(dwfl_report_elf) (dwfl, "kernel", fname, fd, 0) == NULL)
+         && INTUSE(dwfl_report_elf) (dwfl, KERNEL_MODNAME,
+                                     fname, fd, 0) == NULL)
        {
          close (fd);
          result = -1;
@@ -177,13 +197,6 @@ dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
                                  int (*predicate) (const char *module,
                                                    const char *file))
 {
-  if (release == NULL)
-    {
-      release = kernel_release ();
-      if (release == NULL)
-       return errno;
-    }
-
   /* First report the kernel.  */
   int result = report_kernel (dwfl, release, predicate);
   if (result == 0)
@@ -279,15 +292,87 @@ dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
 INTDEF (dwfl_linux_kernel_report_offline)
 
 
-/* Find the ELF file for the running kernel and dwfl_report_elf it.  */
+/* Grovel around to guess the bounds of the runtime kernel image.  */
+static int
+intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end)
+{
+  FILE *f = fopen (KSYMSFILE, "r");
+  if (f == NULL)
+    return errno;
+
+  (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
+
+  char *line = NULL;
+  size_t linesz = 0;
+  size_t n = getline (&line, &linesz, f);
+  Dwarf_Addr first;
+  char *p = NULL;
+  int result = 0;
+  if (n > 0 && (first = strtoull (line, &p, 16)) > 0 && p > line)
+    {
+      Dwarf_Addr last = 0;
+      while ((n = getline (&line, &linesz, f)) > 1 && line[n - 2] != ']')
+       {
+         p = NULL;
+         last = strtoull (line, &p, 16);
+         if (p == NULL || p == line || last == 0)
+           {
+             result = -1;
+             break;
+           }
+       }
+      if ((n == 0 && feof_unlocked (f)) || (n > 1 && line[n - 2] == ']'))
+       {
+         Dwarf_Addr round_kernel = sysconf (_SC_PAGE_SIZE);
+         first &= -(Dwarf_Addr) round_kernel;
+         last += round_kernel - 1;
+         last &= -(Dwarf_Addr) round_kernel;
+         *start = first;
+         *end = last;
+         result = 0;
+       }
+    }
+  free (line);
+
+  if (result == -1)
+    result = ferror_unlocked (f) ? errno : ENOEXEC;
+
+  fclose (f);
+
+  return result;
+}
+
 int
 dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
 {
-  const char *release = kernel_release ();
-  if (release == NULL)
-    return errno;
+  Dwarf_Addr start;
+  Dwarf_Addr end;
+  inline int report (void)
+    {
+      return INTUSE(dwfl_report_module) (dwfl, KERNEL_MODNAME,
+                                        start, end) == NULL ? -1 : 0;
+    }
+
+  /* This is a bit of a kludge.  If we already reported the kernel,
+     don't bother figuring it out again--it never changes.  */
+  for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
+    if (!strcmp (m->name, KERNEL_MODNAME))
+      {
+       start = m->low_addr;
+       end = m->high_addr;
+       return report ();
+      }
+
+  /* Try to figure out the bounds of the kernel image without
+     looking for any vmlinux file.  */
+  int result = intuit_kernel_bounds (&start, &end);
+  if (result == 0)
+    return report ();
+  if (result != ENOENT)
+    return result;
 
-  return report_kernel (dwfl, release, NULL);
+  /* Find the ELF file for the running kernel and dwfl_report_elf it.  */
+  return report_kernel (dwfl, NULL, NULL);
 }
 INTDEF (dwfl_linux_kernel_report_kernel)
 
@@ -306,6 +391,9 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
   if (release == NULL)
     return errno;
 
+  if (!strcmp (module_name, KERNEL_MODNAME))
+    return find_kernel_elf (mod->dwfl, release, file_name);
+
   /* Do "find /lib/modules/`uname -r`/kernel -name MODULE_NAME.ko".  */
 
   char *modulesdir[] = { NULL, NULL };
@@ -416,7 +504,7 @@ dwfl_linux_kernel_module_section_address
  Dwarf_Addr *addr)
 {
   char *sysfile;
-  if (asprintf (&sysfile, SECADDRDIRFMT "%s", modname, secname))
+  if (asprintf (&sysfile, SECADDRDIRFMT "%s", modname, secname) < 0)
     return ENOMEM;
 
   FILE *f = fopen (sysfile, "r");
index bde2aeb91dbdf2792f774666e98496525c83957b..beeb0abf2fc8431acdfdc9f065d2e1201e5dd3ba 100644 (file)
@@ -52,7 +52,7 @@
 
 /* Since dwfl_report_elf lays out the sections already, this will only be
    called when the section headers of the debuginfo file are being
-   consulted instead, or for a section located at zeron.  With binutils
+   consulted instead, or for a section located at zero.  With binutils
    strip-to-debug, the symbol table is in the debuginfo file and relocation
    looks there.  */
 int
index 5b188f845896eabe7bb3cad37c787feb2a4ad79f..770f33751b38015e915465079f331d3121c4e0a4 100644 (file)
@@ -1,3 +1,12 @@
+2007-03-04  Roland McGrath  <roland@redhat.com>
+
+       * dwfl-bug-fd-leak.c: New file.
+       * Makefile.am (noinst_PROGRAMS, TESTS): Add it.
+       (dwfl_bug_fd_leak_LDADD): New variable.
+
+       * dwflmodtest.c: Test dwfl_getmodules before and after getdwarf,
+       show what files have been located.
+
 2007-02-02  Roland McGrath  <roland@redhat.com>
 
        * run-addrname-test.sh: New file.
index bff5568b54eedf201c834a5be9d0ca7106937bbd..c72ea3ce6cba380936bba7636773ea9e0c8f40ef 100644 (file)
@@ -58,7 +58,7 @@ noinst_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
                  get-aranges allfcts line2addr addrscopes funcscopes \
                  show-abbrev hash newscn ecp dwflmodtest \
                  find-prologues funcretval allregs rdwrmmap \
-                 dwfl-bug-addr-overflow arls
+                 dwfl-bug-addr-overflow arls dwfl-bug-fd-leak
 # get-ciefde
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
            asm-tst6 asm-tst7 asm-tst8 asm-tst9
@@ -76,7 +76,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
        run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
        run-find-prologues.sh run-allregs.sh run-readelf-test1.sh \
        run-native-test.sh run-bug1-test.sh \
-       dwfl-bug-addr-overflow run-addrname-test.sh
+       dwfl-bug-addr-overflow run-addrname-test.sh dwfl-bug-fd-leak
 # run-show-ciefde.sh
 
 if !STANDALONE
@@ -203,6 +203,7 @@ dwflmodtest_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 rdwrmmap_LDADD = $(libelf)
 dwfl_bug_addr_overflow_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 arls_LDADD = $(libelf) $(libmudflap)
+dwfl_bug_fd_leak_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 
 CLEANFILES = xxx *.gcno *.gcda *gconv
 
diff --git a/tests/dwfl-bug-fd-leak.c b/tests/dwfl-bug-fd-leak.c
new file mode 100644 (file)
index 0000000..c75a79b
--- /dev/null
@@ -0,0 +1,110 @@
+/* Test program for libdwfl file decriptors leakage.
+   Copyright (C) 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include <config.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <locale.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <error.h>
+#include <unistd.h>
+#include <dwarf.h>
+#include <sys/resource.h>
+#include ELFUTILS_HEADER(dwfl)
+
+
+static Dwfl *
+elfutils_open (pid_t pid, Dwarf_Addr address)
+{
+  static char *debuginfo_path;
+  static const Dwfl_Callbacks proc_callbacks =
+    {
+      .find_debuginfo = dwfl_standard_find_debuginfo,
+      .debuginfo_path = &debuginfo_path,
+
+      .find_elf = dwfl_linux_proc_find_elf,
+    };
+  Dwfl *dwfl = dwfl_begin (&proc_callbacks);
+  if (dwfl == NULL)
+    error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
+
+  int result = dwfl_linux_proc_report (dwfl, pid);
+  if (result < 0)
+    error (2, 0, "dwfl_linux_proc_report: %s", dwfl_errmsg (-1));
+  else if (result > 0)
+    error (2, result, "dwfl_linux_proc_report");
+
+  if (dwfl_report_end (dwfl, NULL, NULL) != 0)
+    error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
+
+  Dwarf_Addr bias;
+  Dwarf *dbg = dwfl_addrdwarf (dwfl, address, &bias);
+  if (dbg != NULL)
+    {
+      Elf *elf = dwarf_getelf (dbg);
+      if (elf == NULL)
+       error (2, 0, "dwarf_getelf: %s", dwarf_errmsg (-1));
+    }
+  else
+    {
+      Elf *elf = dwfl_module_getelf (dwfl_addrmodule (dwfl, address), &bias);
+      if (elf == NULL)
+       error (2, 0, "dwfl_module_getelf: %s", dwfl_errmsg (-1));
+    }
+
+  return dwfl;
+}
+
+static void
+elfutils_close (Dwfl *dwfl)
+{
+  dwfl_end (dwfl);
+}
+
+int
+main (void)
+{
+  /* We use no threads here which can interfere with handling a stream.  */
+  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
+
+  /* Set locale.  */
+  (void) setlocale (LC_ALL, "");
+
+  struct rlimit fd_limit = { .rlim_cur = 32, .rlim_max = 32 };
+  if (setrlimit (RLIMIT_NOFILE, &fd_limit) < 0)
+    error (2, errno, "setrlimit");
+
+  for (int i = 0; i < 5000; ++i)
+    {
+      Dwfl *dwfl = elfutils_open (getpid (), (Dwarf_Addr) main);
+      elfutils_close (dwfl);
+    }
+
+  return 0;
+}
index 7e454e472860f428d6f5bf6e8bd517dae032d27e..c34cac42902b0753bce7896e963aee909ef1e2e9 100644 (file)
@@ -1,5 +1,5 @@
 /* Test program for libdwfl basic module tracking, relocation.
-   Copyright (C) 2005 Red Hat, Inc.
+   Copyright (C) 2005, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -162,6 +162,25 @@ print_func (Dwarf_Die *func, void *arg)
   return DWARF_CB_OK;
 }
 
+static int
+list_module (Dwfl_Module *mod __attribute__ ((unused)),
+            void **userdata __attribute__ ((unused)),
+            const char *name, Dwarf_Addr base,
+            void *arg __attribute__ ((unused)))
+{
+  Dwarf_Addr start;
+  Dwarf_Addr end;
+  const char *file;
+  const char *debug;
+  if (dwfl_module_info (mod, NULL, &start, &end,
+                       NULL, NULL, &file, &debug) != name
+      || start != base)
+    abort ();
+  printf ("module: %30s %08" PRIx64 "..%08" PRIx64 " %s %s\n",
+         name, start, end, file, debug);
+  return DWARF_CB_OK;
+}
+
 static int
 print_module (Dwfl_Module *mod __attribute__ ((unused)),
              void **userdata __attribute__ ((unused)),
@@ -251,12 +270,25 @@ main (int argc, char **argv)
   assert (dwfl != NULL);
 
   ptrdiff_t p = 0;
+  do
+    p = dwfl_getmodules (dwfl, &list_module, NULL, p);
+  while (p > 0);
+  if (p < 0)
+    error (2, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
+
   do
     p = dwfl_getdwarf (dwfl, &print_module, &show_functions, p);
   while (p > 0);
   if (p < 0)
     error (2, 0, "dwfl_getdwarf: %s", dwfl_errmsg (-1));
 
+  p = 0;
+  do
+    p = dwfl_getmodules (dwfl, &list_module, NULL, p);
+  while (p > 0);
+  if (p < 0)
+    error (2, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
+
   dwfl_end (dwfl);
 
   return 0;