@@ -1,3 +1,7 @@
+2022-09-13 Aleksei Vetrov <vvvvvv@google.com>
+
+ * NEWS (libdwfl): Add dwfl_report_offline_memory.
+
2022-04-28 Di Chen <dichen@redhat.com>
* NEWS: Add readefl -D, --use-dynamic.
@@ -137,6 +137,7 @@ ELFUTILS_0.122 {
dwfl_report_end;
dwfl_report_module;
dwfl_report_offline;
+ dwfl_report_offline_memory;
dwfl_standard_argp;
dwfl_standard_find_debuginfo;
dwfl_version;
@@ -159,6 +159,10 @@ extern Dwfl_Module *dwfl_report_elf (Dwfl *dwfl, const char *name,
extern Dwfl_Module *dwfl_report_offline (Dwfl *dwfl, const char *name,
const char *file_name, int fd);
+/* Similar, but report ELF from memory region. */
+extern Dwfl_Module *dwfl_report_offline_memory (Dwfl *dwfl, const char *name,
+ const char *file_name,
+ char *data, size_t size);
/* Finish reporting the current set of modules to the library.
If REMOVED is not null, it's called for each module that
@@ -631,6 +631,11 @@ extern Dwfl_Error __libdw_open_file (int *fdp, Elf **elfp,
bool close_on_fail, bool archive_ok)
internal_function;
+/* Same as __libdw_open_file, but opens Elf handle from memory region. */
+extern Dwfl_Error __libdw_open_elf_memory (char *data, size_t size, Elf **elfp,
+ bool archive_ok)
+ internal_function;
+
/* Same as __libdw_open_file, but never closes the given file
descriptor and ELF_K_AR is always an acceptable type. */
extern Dwfl_Error __libdw_open_elf (int fd, Elf **elfp) internal_function;
@@ -760,6 +765,7 @@ INTDECL (dwfl_report_begin_add)
INTDECL (dwfl_report_module)
INTDECL (dwfl_report_segment)
INTDECL (dwfl_report_offline)
+INTDECL (dwfl_report_offline_memory)
INTDECL (dwfl_report_end)
INTDECL (dwfl_build_id_find_elf)
INTDECL (dwfl_build_id_find_debuginfo)
@@ -1,6 +1,7 @@
/* Recover relocatibility for addresses computed from debug information.
Copyright (C) 2005-2009, 2012 Red Hat, Inc.
Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
+ Copyright (C) 2022 Google LLC
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -252,6 +253,7 @@ process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
{
Dwfl_Module *mod = NULL;
+ /* elf_begin supports opening archives even with fd == -1 passed. */
Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
if (unlikely (member == NULL)) /* Empty archive. */
{
@@ -320,3 +322,27 @@ dwfl_report_offline (Dwfl *dwfl, const char *name,
return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
}
INTDEF (dwfl_report_offline)
+
+Dwfl_Module *
+dwfl_report_offline_memory (Dwfl *dwfl, const char *name,
+ const char *file_name, char *data, size_t size)
+{
+ if (dwfl == NULL)
+ return NULL;
+
+ Elf *elf;
+ Dwfl_Error error = __libdw_open_elf_memory (data, size, &elf, true);
+ if (error != DWFL_E_NOERROR)
+ {
+ __libdwfl_seterrno (error);
+ return NULL;
+ }
+ /* It is ok to pass fd == -1 here, because libelf uses it as a value for
+ "no file opened" and supports working with files without fd, thanks to
+ the existence of the elf_memory function. */
+ Dwfl_Module *mod = process_file (dwfl, name, file_name, -1, elf, NULL);
+ if (mod == NULL)
+ elf_end (elf);
+ return mod;
+}
+INTDEF (dwfl_report_offline_memory)
@@ -1,5 +1,6 @@
/* Decompression support for libdwfl: zlib (gzip), bzlib (bzip2) or lzma (xz).
Copyright (C) 2009, 2016 Red Hat, Inc.
+ Copyright (C) 2022 Google LLC
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -53,6 +54,9 @@ static Dwfl_Error
decompress (int fd __attribute__ ((unused)), Elf **elf)
{
Dwfl_Error error = DWFL_E_BADELF;
+ /* ELF cannot be decompressed, if there is no file descriptor. */
+ if (fd == -1)
+ return error;
void *buffer = NULL;
size_t size = 0;
@@ -124,11 +128,12 @@ what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
static Dwfl_Error
libdw_open_elf (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok,
- bool never_close_fd, bool bad_elf_ok)
+ bool never_close_fd, bool bad_elf_ok, bool use_elfp)
{
bool may_close_fd = false;
- Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
+ Elf *elf =
+ use_elfp ? *elfp : elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
Elf_Kind kind;
Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
@@ -194,11 +199,28 @@ libdw_open_elf (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok,
Dwfl_Error internal_function
__libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
{
- return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false);
+ return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false,
+ false);
+}
+
+Dwfl_Error internal_function
+__libdw_open_elf_memory (char *data, size_t size, Elf **elfp, bool archive_ok)
+{
+ /* It is ok to use `fd == -1` here, because libelf uses it as a value for
+ "no file opened" and code supports working with this value, and also
+ `never_close_fd == false` is passed to prevent closing non-existant file.
+ The only caveat is in `decompress` method, which doesn't support
+ decompressing from memory, so reading compressed zImage using this method
+ won't work. */
+ int fd = -1;
+ *elfp = elf_memory (data, size);
+ /* Allow using this ELF as reference for subsequent elf_begin calls. */
+ (*elfp)->cmd = ELF_C_READ_MMAP_PRIVATE;
+ return libdw_open_elf (&fd, elfp, false, archive_ok, true, false, true);
}
Dwfl_Error internal_function
__libdw_open_elf (int fd, Elf **elfp)
{
- return libdw_open_elf (&fd, elfp, false, true, true, true);
+ return libdw_open_elf (&fd, elfp, false, true, true, true, false);
}
@@ -47,6 +47,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
alldts typeiter typeiter2 low_high_pc \
test-elf_cntl_gelf_getshdr dwflsyms dwfllines \
dwfl-report-elf-align dwfl-report-segment-contiguous \
+ dwfl-report-offline-memory \
varlocs backtrace backtrace-child \
backtrace-data backtrace-dwarf debuglink debugaltlink \
buildid deleted deleted-lib.so aggregate_size peel_type \
@@ -148,6 +149,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
run-readelf-mixed-corenote.sh run-dwfllines.sh \
run-readelf-variant.sh run-readelf-fat-lto.sh \
run-dwfl-report-elf-align.sh run-addr2line-test.sh \
+ run-dwfl-report-offline-memory.sh \
run-addr2line-i-test.sh run-addr2line-i-lex-test.sh \
run-addr2line-i-demangle-test.sh run-addr2line-alt-debugpath.sh \
run-varlocs.sh run-exprlocs.sh run-varlocs-vars.sh run-funcretval.sh \
@@ -411,6 +413,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
testfile69.core.bz2 testfile69.so.bz2 \
testfile70.core.bz2 testfile70.exec.bz2 testfile71.bz2 \
run-dwfllines.sh run-dwfl-report-elf-align.sh \
+ run-dwfl-report-offline-memory.sh \
testfile-dwfl-report-elf-align-shlib.so.bz2 \
testfilenolines.bz2 test-core-lib.so.bz2 test-core.core.bz2 \
test-core.exec.bz2 run-addr2line-test.sh \
@@ -709,6 +712,7 @@ test_elf_cntl_gelf_getshdr_LDADD = $(libelf)
dwflsyms_LDADD = $(libdw) $(libelf) $(argp_LDADD)
dwfllines_LDADD = $(libdw) $(libelf) $(argp_LDADD)
dwfl_report_elf_align_LDADD = $(libdw)
+dwfl_report_offline_memory_LDADD = $(libdw)
dwfl_report_segment_contiguous_LDADD = $(libdw) $(libebl) $(libelf)
varlocs_LDADD = $(libdw) $(libelf) $(argp_LDADD)
backtrace_LDADD = $(libdw) $(libelf) $(argp_LDADD)
new file mode 100644
@@ -0,0 +1,97 @@
+/* Test program for dwfl_report_offline_memory.
+ Copyright (C) 2022 Google LLC
+ This file is part of elfutils.
+
+ This file 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; either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <config.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include ELFUTILS_HEADER(dwfl)
+#include "system.h"
+
+
+static const Dwfl_Callbacks offline_callbacks =
+ {
+ .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
+ .section_address = INTUSE(dwfl_offline_section_address),
+ };
+
+static int
+count_modules (Dwfl_Module *mod __attribute__ ((unused)),
+ void **userdata __attribute__ ((unused)),
+ const char *name __attribute__ ((unused)),
+ Dwarf_Addr base __attribute__ ((unused)), void *arg)
+{
+ unsigned long long *counter = arg;
+ ++(*counter);
+ return DWARF_CB_OK;
+}
+
+int
+main (int argc, char **argv)
+{
+ /* We use no threads here which can interfere with handling a stream. */
+ (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
+
+ /* Set locale. */
+ (void) setlocale (LC_ALL, "");
+
+ if (argc != 3)
+ error (-1, 0,
+ "usage: dwfl_report_offline_memory [filename] "
+ "[expected number of modules]");
+
+ const char *fname = argv[1];
+ int fd = open (fname, O_RDONLY);
+ if (fd < 0)
+ error (-1, 0, "can't open file %s: %s", fname, strerror (errno));
+ size_t size = lseek (fd, 0, SEEK_END);
+ lseek (fd, 0, SEEK_SET);
+ char *data = malloc (size);
+ size_t bytes_read = read (fd, data, size);
+ assert (bytes_read == size);
+ close (fd);
+
+ Dwfl *dwfl = dwfl_begin (&offline_callbacks);
+ assert (dwfl != NULL);
+
+ Dwfl_Module *mod =
+ dwfl_report_offline_memory (dwfl, argv[1], argv[1], data, size);
+ assert (mod != NULL);
+ dwfl_report_end (dwfl, NULL, NULL);
+
+ unsigned long long number_of_modules = 0;
+ ptrdiff_t offset =
+ dwfl_getmodules (dwfl, &count_modules, &number_of_modules, 0);
+ if (offset < 0)
+ error (1, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
+ assert (offset == 0);
+
+ char *endptr;
+ unsigned long long expected_number_of_modules =
+ strtoull (argv[2], &endptr, 0);
+ assert (endptr && !*endptr);
+ assert (number_of_modules == expected_number_of_modules);
+
+ dwfl_end (dwfl);
+ free (data);
+
+ return 0;
+}
new file mode 100755
@@ -0,0 +1,26 @@
+#! /bin/sh
+# Copyright (C) 2022 Google LLC
+# This file is part of elfutils.
+#
+# This file 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; either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+testfiles testfile-dwfl-report-elf-align-shlib.so
+testfiles testarchive64.a
+
+testrun ${abs_builddir}/dwfl-report-offline-memory ./testfile-dwfl-report-elf-align-shlib.so 1
+testrun ${abs_builddir}/dwfl-report-offline-memory ./testarchive64.a 3
+
+exit 0