+Version 0.127-UNFINISHED:
+
+libdwfl: new function dwfl_module_addrsym
+
Version 0.126:
new program: ar
+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.
local:
*;
} ELFUTILS_0;
+
ELFUTILS_0.126 {
global:
dwarf_getelf;
local:
*;
} ELFUTILS_0.122;
+
+ELFUTILS_0.127 {
+ global:
+ dwfl_module_addrsym;
+ dwfl_report_begin_add;
+
+ local:
+ *;
+} ELFUTILS_0.126;
+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
##
## 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
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
/* 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
#include "libdwflP.h"
#include <search.h>
+#include <unistd.h>
static void
free_cu (struct dwfl_cu *cu)
{
}
+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)
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;
}
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);
}
--- /dev/null
+/* 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)
/* 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
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)
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)
}
}
+ 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;
}
/* 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
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;
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
/* 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 ***/
/* 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
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)
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)
#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. */
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))
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
{
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;
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)
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)
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 };
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");
/* 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
+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.
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
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
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
--- /dev/null
+/* 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;
+}
/* 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
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)),
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;