summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS8
-rw-r--r--configure.ac5
-rw-r--r--debuginfod/debuginfod.cxx2
-rw-r--r--doc/srcfiles.133
-rw-r--r--src/Makefile.am9
-rw-r--r--src/srcfiles.cxx300
-rwxr-xr-xtests/debuginfod-subr.sh14
-rwxr-xr-xtests/run-srcfiles-self.sh80
8 files changed, 401 insertions, 50 deletions
diff --git a/NEWS b/NEWS
index 0420d3b8..3391d6a1 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+Version 0.191 (after 0.189)
+
+srcfiles: Can now fetch the source files of a DWARF/ELF file and
+ place them into a zip.
+
Version 0.190 "Woke!"
CONTRIBUTING: Switch from real name policy to known identity policy.
@@ -9,6 +14,9 @@ libelf: Add RELR support.
libdw: Recognize .debug_[ct]u_index sections
+srcfiles: added srcfiles tool that lists all the source files of a given
+ DWARF/ELF file.
+
readelf: Support readelf -Ds, --use-dynamic --symbol.
Support .gdb_index version 9
diff --git a/configure.ac b/configure.ac
index af5b6bf7..ddb79b83 100644
--- a/configure.ac
+++ b/configure.ac
@@ -841,7 +841,7 @@ AM_CONDITIONAL([LIBDEBUGINFOD],[test "x$enable_libdebuginfod" = "xyes" || test "
AM_CONDITIONAL([DUMMY_LIBDEBUGINFOD],[test "x$enable_libdebuginfod" = "xdummy"])
AC_CHECK_HEADERS([execinfo.h])
-# Look for libmicrohttpd, libarchive, sqlite for debuginfo server
+# Look for libmicrohttpd, libarchive, sqlite for debuginfo server and srcfiles tool
# minimum versions as per rhel7.
AC_ARG_ENABLE([debuginfod],AS_HELP_STRING([--enable-debuginfod], [Build debuginfod server]))
AS_IF([test "x$enable_debuginfod" != "xno"], [
@@ -853,11 +853,12 @@ AS_IF([test "x$enable_debuginfod" != "xno"], [
AC_MSG_ERROR([need libdebuginfod (or dummy), use --disable-debuginfod to disable.])
fi
enable_debuginfod=yes # presume success
+ AC_DEFINE([HAVE_LIBARCHIVE], [1], [Define to 1 if libarchive is available]) # presume success
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES([libmicrohttpd],[libmicrohttpd >= 0.9.33],[],[enable_debuginfod=no])
PKG_CHECK_MODULES([oldlibmicrohttpd],[libmicrohttpd < 0.9.51],[old_libmicrohttpd=yes],[old_libmicrohttpd=no])
PKG_CHECK_MODULES([sqlite3],[sqlite3 >= 3.7.17],[],[enable_debuginfod=no])
- PKG_CHECK_MODULES([libarchive],[libarchive >= 3.1.2],[],[enable_debuginfod=no])
+ PKG_CHECK_MODULES([libarchive],[libarchive >= 3.1.2],[],[enable_debuginfod=no], AC_DEFINE([HAVE_LIBARCHIVE], [0], [Define to 0 if libarchive is not available]))
if test "x$enable_debuginfod" = "xno"; then
AC_MSG_ERROR([dependencies not found, use --disable-debuginfod to disable.])
fi
diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
index 524be948..6b21f46f 100644
--- a/debuginfod/debuginfod.cxx
+++ b/debuginfod/debuginfod.cxx
@@ -2996,8 +2996,6 @@ dwarf_extract_source_paths (Elf *elf, set<string>& debug_sourcefiles)
if (comp_dir[0] == '\0' && cuname[0] != '/')
{
- // This is a common symptom for dwz-compressed debug files,
- // where the altdebug file cannot be resolved.
if (verbose > 3)
obatched(clog) << "skipping cu=" << cuname << " due to empty comp_dir" << endl;
continue;
diff --git a/doc/srcfiles.1 b/doc/srcfiles.1
index 6149c21b..c6338315 100644
--- a/doc/srcfiles.1
+++ b/doc/srcfiles.1
@@ -21,15 +21,18 @@
eu-srcfiles \- Lists the source files of a DWARF/ELF file.
.SH "SYNOPSIS"
-eu-srcfiles [\fB\-0\fR|\fB\-\-null\fR] [\fB\-c\fR|\fB\-\-cu\-only\fR] [\fB\-v\fR|\fB\-\-verbose\fR] INPUT
+eu-srcfiles [\fB\-0\fR|\fB\-\-null\fR] [\fB\-c\fR|\fB\-\-cu\-only\fR] [\fB\-v\fR|\fB\-\-verbose\fR] [\fB\-z\fR|\fB\-\-zip\fR] INPUT
.SH "DESCRIPTION"
-\fBeu-srcfiles\fR lists the source files of a given \s-DWARF/ELF\s0
+\fBeu-srcfiles\fR lists all the source files of a given DWARF/ELF
file. This list is based on a search of the DWARF debuginfo, which
may be automatically fetched by debuginfod if applicable. The target
file may be an executable, a coredump, a process, or even the running
-kernel. The default is the file 'a.out'. The source file names are
-made unique and printed to standard output.
+kernel. The default input is the file 'a.out'. The source file names are
+made unique by prepending the full path name and then printed to standard output. The source files can be
+placed in a zip file that is sent to stdout.
+
+Note that all occurrences of '/./' and '/../' in the path name are canonicalized.
.SH "INPUT OPTIONS"
The long and short forms of options, shown here as alternatives, are
@@ -81,13 +84,28 @@ Print program version.
Separate items by a null instead of a newline.
.TP
+\fB\-b, \-\-no-backup\fR
+Disables local source file search when
+debuginfod fails to fetch files. This
+option is only applicable when fetching and
+zipping files.
+
+.TP
\fB\-c, \-\-cu\-only\fR
-Only list the CU names.
+Only list the CU (compilation unit) names.
.TP
\fB\-v, \-\-verbose\fR
Increase verbosity of logging messages.
+.TP
+\fB\-z, \-\-zip\fR
+Zip all the source files and send to stdout.
+By default, files will be automatically fetched by
+debuginfod (if applicable) or locally as a
+backup. Any source files that were not found
+will not be archived.
+
.SH EXAMPLES
@@ -119,6 +137,11 @@ List the source files of a kernel image.
eu-srcfiles -e /boot/vmlinuz-`uname -r`
.ESAMPLE
+Zip all the source files for a binary.
+.SAMPLE
+eu-srcfiles -z -e /bin/ls > ls.zip
+.ESAMPLE
+
.SH "AUTHOR"
Written by Housam Alamour.
diff --git a/src/Makefile.am b/src/Makefile.am
index d3d9d408..5fa8df3d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,7 +21,7 @@ DEFS += $(YYDEBUG) -DDEBUGPRED=@DEBUGPRED@ \
-DSRCDIR=\"$(shell cd $(srcdir);pwd)\" -DOBJDIR=\"$(shell pwd)\"
AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
-I$(srcdir)/../libdw -I$(srcdir)/../libdwelf \
- -I$(srcdir)/../libdwfl -I$(srcdir)/../libasm
+ -I$(srcdir)/../libdwfl -I$(srcdir)/../libasm -I../debuginfod
AM_LDFLAGS = -Wl,-rpath-link,../libelf:../libdw $(STACK_USAGE_NO_ERROR)
@@ -50,6 +50,11 @@ libelf = ../libelf/libelf.so
endif
libebl = ../libebl/libebl.a ../backends/libebl_backends.a ../libcpu/libcpu.a
libeu = ../lib/libeu.a
+if LIBDEBUGINFOD
+libdebuginfod = ../debuginfod/libdebuginfod.so
+else
+libdebuginfod =
+endif
if DEMANGLE
demanglelib = -lstdc++
@@ -85,7 +90,7 @@ stack_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) $(demanglelib)
elfcompress_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD)
elfclassify_LDADD = $(libelf) $(libdw) $(libeu) $(argp_LDADD)
srcfiles_SOURCES = srcfiles.cxx
-srcfiles_LDADD = $(libdw) $(libelf) $(libeu) $(argp_LDADD)
+srcfiles_LDADD = $(libdw) $(libelf) $(libeu) $(argp_LDADD) $(libarchive_LIBS) $(libdebuginfod)
installcheck-binPROGRAMS: $(bin_PROGRAMS)
bad=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \
diff --git a/src/srcfiles.cxx b/src/srcfiles.cxx
index 3c7afdc4..67f61b8d 100644
--- a/src/srcfiles.cxx
+++ b/src/srcfiles.cxx
@@ -15,6 +15,21 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+
+/* In case we have a bad fts we include this before config.h because it
+ can't handle _FILE_OFFSET_BITS.
+ Everything we need here is fine if its declarations just come first.
+ Also, include sys/types.h before fts. On some systems fts.h is not self
+ contained. */
+#ifdef BAD_FTS
+#include <sys/types.h>
+#include <fts.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
#include "printversion.h"
#include <dwarf.h>
@@ -23,12 +38,37 @@
#include <set>
#include <string>
#include <cassert>
-#include <config.h>
+#include <gelf.h>
+#include <memory>
+
+#ifdef ENABLE_LIBDEBUGINFOD
+#include "debuginfod.h"
+#endif
#include <libdwfl.h>
#include <fcntl.h>
#include <iostream>
#include <libdw.h>
+#include <sstream>
+#include <vector>
+
+/* Libraries for use by the --zip option */
+#ifdef HAVE_LIBARCHIVE
+#include <archive.h>
+#include <archive_entry.h>
+#endif
+
+/* If fts.h is included before config.h, its indirect inclusions may not
+ give us the right LFS aliases of these functions, so map them manually. */
+#ifdef BAD_FTS
+#ifdef _FILE_OFFSET_BITS
+#define open open64
+#define fopen fopen64
+#endif
+#else
+ #include <sys/types.h>
+ #include <fts.h>
+#endif
using namespace std;
@@ -38,8 +78,10 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
/* Bug report address. */
ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
+constexpr size_t BUFFER_SIZE = 8192;
+
/* Definitions of arguments for argp functions. */
-static const struct argp_option options[] =
+static const struct argp_option options[] =
{
{ NULL, 0, NULL, OPTION_DOC, N_("Output options:"), 1 },
{ "null", '0', NULL, 0,
@@ -47,11 +89,17 @@ static const struct argp_option options[] =
{ "verbose", 'v', NULL, 0,
N_ ("Increase verbosity of logging messages."), 0 },
{ "cu-only", 'c', NULL, 0, N_ ("Only list the CU names."), 0 },
- { NULL, 0, NULL, 0, NULL, 0 }
+ { "zip", 'z', NULL, 0, N_ ("Zip all the source files and send to stdout. "
+ "By default, priority is given to fetching source files from "
+ "debuginfod over local source files"), 0 },
+ { "no-backup", 'b', NULL, 0, N_ ("Disables local source file search when "
+ "debuginfod fails to fetch files. This option is only applicable "
+ "when fetching and zipping files."), 0 },
+ { NULL, 0, NULL, 0, NULL, 0 }
};
/* Short description of program. */
-static const char doc[] = N_("Lists the source files of a DWARF/ELF file. The default input is the file 'a.out'.");
+static const char doc[] = N_("Lists the source files of a DWARF/ELF file. The default input is the file 'a.out'.");
/* Strings for arguments in help texts. */
static const char args_doc[] = N_("INPUT");
@@ -67,18 +115,24 @@ static const struct argp argp =
options, parse_opt, args_doc, doc, argp_children, NULL, NULL
};
-/* Verbose message printing. */
+/* Verbose message printing. */
static bool verbose;
-/* Delimit the output with nulls. */
+/* Delimit the output with nulls. */
static bool null_arg;
-/* Only print compilation unit names. */
+/* Only print compilation unit names. */
static bool CU_only;
-
-/* Handle program arguments. */
+/* Zip all the source files and send to stdout. */
+static bool zip;
+/* Disables local source file search when debuginfod fails to fetch them.
+ This option is only applicable when fetching and zipping files.*/
+static bool no_backup;
+
+/* Handle program arguments. Note null arg and zip
+ cannot be combined due to warnings raised when unzipping. */
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
- /* Suppress "unused parameter" warning. */
+ /* Suppress "unused parameter" warning. */
(void)arg;
switch (key)
{
@@ -98,17 +152,54 @@ parse_opt (int key, char *arg, struct argp_state *state)
CU_only = true;
break;
+ case 'z':
+ zip = true;
+ break;
+
+ case 'b':
+ no_backup = true;
+ break;
+
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
+/* Remove the "/./" , "../" and the preceding directory
+ that some paths include which raise errors during unzip. */
+string canonicalize_path(string path)
+{
+ stringstream ss(path);
+ string token;
+ vector<string> tokens;
+ /* Extract each directory of the path and place into a vector. */
+ while (getline(ss, token, '/')) {
+ /* Ignore any empty //, or /./ dirs. */
+ if (token == "" || token == ".")
+ continue;
+ /* When /.. is encountered, remove the most recent directory from the vector. */
+ else if (token == "..") {
+ if (!tokens.empty())
+ tokens.pop_back();
+ } else
+ tokens.push_back(token);
+ }
+ stringstream result;
+ if (tokens.empty())
+ return "/";
+ /* Reconstruct the path from the extracted directories. */
+ for (const string &t : tokens) {
+ result << '/' << t;
+ }
+ return result.str();
+}
-/* Global list of collected source files. Normally, it'll contain
- the sources of just one named binary, but the '-K' option can cause
- multiple dwfl modules to be loaded, thus listed. */
- set<string> debug_sourcefiles;
+/* Global list of collected source files and their respective module.
+ Normally, it'll contain the sources of just one named binary, but
+ the '-K' option can cause multiple dwfl modules to be loaded, thus
+ listed. */
+set<pair<string, Dwfl_Module*>> debug_sourcefiles;
static int
collect_sourcefiles (Dwfl_Module *dwflmod,
@@ -118,14 +209,13 @@ collect_sourcefiles (Dwfl_Module *dwflmod,
void *arg __attribute__ ((unused)))
{
Dwarf *dbg;
- Dwarf_Addr bias; /* ignored - for addressing purposes only */
-
+ Dwarf_Addr bias; /* ignored - for addressing purposes only. */
+
dbg = dwfl_module_getdwarf (dwflmod, &bias);
Dwarf_Off offset = 0;
Dwarf_Off old_offset;
size_t hsize;
-
/* Traverse all CUs of this module. */
while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL, NULL) == 0)
{
@@ -141,7 +231,7 @@ collect_sourcefiles (Dwfl_Module *dwflmod,
if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0)
continue;
- /* extract DW_AT_comp_dir to resolve relative file names */
+ /* extract DW_AT_comp_dir to resolve relative file names. */
const char *comp_dir = "";
const char *const *dirs;
size_t ndirs;
@@ -152,11 +242,19 @@ collect_sourcefiles (Dwfl_Module *dwflmod,
comp_dir = "";
if (verbose)
- std::clog << "searching for sources for cu=" << cuname
+ clog << "searching for sources for cu=" << cuname
<< " comp_dir=" << comp_dir << " #files=" << nfiles
<< " #dirs=" << ndirs << endl;
-
- for (size_t f = 1; f < nfiles; f++)
+
+ if (comp_dir[0] == '\0' && cuname[0] != '/')
+ {
+ /* This is a common symptom for dwz-compressed debug files,
+ where the altdebug file cannot be resolved. */
+ if (verbose)
+ clog << "skipping cu=" << cuname << " due to empty comp_dir" << endl;
+ continue;
+ }
+ for (size_t f = 1; f < nfiles; ++f)
{
const char *hat;
if (CU_only)
@@ -172,7 +270,7 @@ collect_sourcefiles (Dwfl_Module *dwflmod,
continue;
if (string(hat).find("<built-in>")
- != std::string::npos) /* gcc intrinsics, don't bother record */
+ != string::npos) /* gcc intrinsics, don't bother recording */
continue;
string waldo;
@@ -180,38 +278,174 @@ collect_sourcefiles (Dwfl_Module *dwflmod,
waldo = (string (hat));
else if (comp_dir[0] != '\0') /* comp_dir relative */
waldo = (string (comp_dir) + string ("/") + string (hat));
- debug_sourcefiles.insert (waldo);
+ else
+ {
+ if (verbose)
+ clog << "skipping file=" << hat << " due to empty comp_dir" << endl;
+ continue;
+ }
+ waldo = canonicalize_path (waldo);
+ debug_sourcefiles.insert (make_pair(waldo, dwflmod));
}
}
-
return DWARF_CB_OK;
}
+#ifdef HAVE_LIBARCHIVE
+void zip_files()
+{
+ struct archive *a = archive_write_new();
+ struct stat st;
+ char buff[BUFFER_SIZE];
+ int len;
+ int fd;
+ #ifdef ENABLE_LIBDEBUGINFOD
+ /* Initialize a debuginfod client. */
+ static unique_ptr <debuginfod_client, void (*)(debuginfod_client*)>
+ client (debuginfod_begin(), &debuginfod_end);
+ #endif
+
+ archive_write_set_format_zip(a);
+ archive_write_open_fd(a, STDOUT_FILENO);
+
+ int missing_files = 0;
+ for (const auto &pair : debug_sourcefiles)
+ {
+ fd = -1;
+ const std::string &file_path = pair.first;
+
+ /* Attempt to query debuginfod client to fetch source files. */
+ #ifdef ENABLE_LIBDEBUGINFOD
+ Dwfl_Module* dwflmod = pair.second;
+ /* Obtain source file's build ID. */
+ const unsigned char *bits;
+ GElf_Addr vaddr;
+ int bits_length = dwfl_module_build_id(dwflmod, &bits, &vaddr);
+ /* Ensure successful client and build ID acquisition. */
+ if (client.get() != NULL && bits_length > 0)
+ {
+ fd = debuginfod_find_source(client.get(),
+ bits, bits_length,
+ file_path.c_str(), NULL);
+ }
+ else
+ {
+ if (client.get() == NULL)
+ cerr << "Error: Failed to initialize debuginfod client." << endl;
+ else
+ cerr << "Error: Invalid build ID length (" << bits_length << ")." << endl;
+ }
+ #endif
+
+ if (!no_backup)
+ /* Files could not be located using debuginfod, search locally */
+ if (fd < 0)
+ fd = open(file_path.c_str(), O_RDONLY);
+ if (fd < 0)
+ {
+ if (verbose)
+ cerr << file_path << endl;
+ missing_files++;
+ continue;
+ }
+
+ /* Create an entry for each file including file information to be placed in the zip. */
+ if (fstat(fd, &st) == -1)
+ {
+ if (verbose)
+ cerr << file_path << endl;
+ missing_files++;
+ if (verbose)
+ cerr << "Error: Failed to get file status for " << file_path << ": " << strerror(errno) << endl;
+ continue;
+ }
+ struct archive_entry *entry = archive_entry_new();
+ /* Removing first "/"" to make the path "relative" before zipping, otherwise warnings are raised when unzipping. */
+ string entry_name = file_path.substr(file_path.find_first_of('/') + 1);
+ archive_entry_set_pathname(entry, entry_name.c_str());
+ archive_entry_copy_stat(entry, &st);
+ if (archive_write_header(a, entry) != ARCHIVE_OK)
+ {
+ if (verbose)
+ cerr << file_path << endl;
+ missing_files++;
+ if (verbose)
+ cerr << "Error: failed to write header for " << file_path << ": " << archive_error_string(a) << endl;
+ continue;
+ }
+
+ /* Write the file to the zip. */
+ len = read(fd, buff, sizeof(buff));
+ if (len == -1)
+ {
+ if (verbose)
+ cerr << file_path << endl;
+ missing_files++;
+ if (verbose)
+ cerr << "Error: Failed to open file: " << file_path << ": " << strerror(errno) <<endl;
+ continue;
+ }
+ while (len > 0)
+ {
+ if (archive_write_data(a, buff, len) < ARCHIVE_OK)
+ {
+ if (verbose)
+ cerr << "Error: Failed to read from the file: " << file_path << ": " << strerror(errno) << endl;
+ break;
+ }
+ len = read(fd, buff, sizeof(buff));
+ }
+ close(fd);
+ archive_entry_free(entry);
+ }
+ if (verbose && missing_files > 0 )
+ cerr << missing_files << " file(s) listed above could not be found. " << endl;
+
+ archive_write_close(a);
+ archive_write_free(a);
+}
+#endif
int
main (int argc, char *argv[])
{
int remaining;
-
+
/* Parse and process arguments. This includes opening the modules. */
argp_children[0].argp = dwfl_standard_argp ();
argp_children[0].group = 1;
-
+
Dwfl *dwfl = NULL;
(void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
assert (dwfl != NULL);
- /* Process all loaded modules - probably just one, except if -K or -p is used. */
+ /* Process all loaded modules - probably just one, except if -K or -p is used. */
(void) dwfl_getmodules (dwfl, &collect_sourcefiles, NULL, 0);
if (!debug_sourcefiles.empty ())
- for (const string &element : debug_sourcefiles)
+ {
+ #ifndef HAVE_LIBARCHIVE
+ if (zip)
{
- std::cout << element;
- if (null_arg)
- std::cout << '\0';
- else
- std::cout << '\n';
+ clog << "LIBARCHIVE was not detected on the system. Zip option will be ignored.\n";
+ zip = false;
+ }
+ #endif
+ #ifdef HAVE_LIBARCHIVE
+ if (zip)
+ zip_files();
+ else
+ #endif
+ {
+ for (const auto &pair : debug_sourcefiles)
+ {
+ cout << pair.first;
+ if (null_arg)
+ cout << '\0';
+ else
+ cout << '\n';
+ }
}
+ }
dwfl_end (dwfl);
return 0;
diff --git a/tests/debuginfod-subr.sh b/tests/debuginfod-subr.sh
index 108dff74..c3b0603d 100755
--- a/tests/debuginfod-subr.sh
+++ b/tests/debuginfod-subr.sh
@@ -79,12 +79,12 @@ errfiles() {
# So we gather the LD_LIBRARY_PATH with this cunning trick:
ldpath=`testrun sh -c 'echo $LD_LIBRARY_PATH'`
-wait_ready()
+wait_ready4()
{
port=$1;
what=$2;
value=$3;
- timeout=20;
+ timeout=$4;
echo "Wait $timeout seconds on $port for metric $what to change to $value"
while [ $timeout -gt 0 ]; do
@@ -105,6 +105,16 @@ wait_ready()
fi
}
+wait_ready()
+{
+ port=$1;
+ what=$2;
+ value=$3;
+ timeout=20;
+ wait_ready4 "$port" "$what" "$value" "$timeout"
+}
+
+
archive_test() {
__BUILDID=$1
__SOURCEPATH=$2
diff --git a/tests/run-srcfiles-self.sh b/tests/run-srcfiles-self.sh
index 0e64dd2b..00b87cf3 100755
--- a/tests/run-srcfiles-self.sh
+++ b/tests/run-srcfiles-self.sh
@@ -1,4 +1,4 @@
-#! /bin/sh
+#! /usr/bin/env bash
# Copyright (C) 2023 Red Hat, Inc.
# This file is part of elfutils.
#
@@ -15,7 +15,13 @@
# 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
+. $srcdir/debuginfod-subr.sh
+
+# for test case debugging, uncomment:
+# set -x
+set -e
+base=14000
+get_ports
# Test different command line combinations on the srcfiles binary itself.
ET_EXEC="${abs_top_builddir}/src/srcfiles"
@@ -26,11 +32,22 @@ SRC_NAME="srcfiles.cxx"
# Ensure the output contains the expected source file srcfiles.cxx
testrun $ET_EXEC -e $ET_EXEC | grep $SRC_NAME > /dev/null
+# Check if --zip option is available (only available if libarchive,
+# zip, and unzip are available. Debuginfod optional to fetch
+# source files from debuginfod federation.)
+libarchive_available=$(ldconfig -p | grep -q libarchive)
+zip_available=$(type zip 2>/dev/null)
+unzip_available=$(type unzip 2>/dev/null)
+if [ "$libarchive_available" = true ] && [ "$zip_available" = true ] && [ "$unzip_available" = true ]; then
+ zip = true
+fi
+
for null_arg in --null ""; do
for verbose_arg in --verbose ""; do
+ echo "Test with options $null_arg $verbose_arg"
testrun $ET_EXEC $null_arg $verbose_arg -p $ET_PID > /dev/null
- # Ensure that the output contains srclines.cxx
+ # Ensure that the output contains srcfiles.cxx
cu_only=$(testrun $ET_EXEC $null_arg $verbose_arg -c -e $ET_EXEC)
default=$(testrun $ET_EXEC $null_arg $verbose_arg -e $ET_EXEC)
result1=$(echo "$cu_only" | grep "$SRC_NAME")
@@ -40,9 +57,64 @@ for null_arg in --null ""; do
exit 1
fi
- # Ensure that the output with the cu-only option contains less source files
+ # Ensure that the output with the cu-only option contains fewer source files
if [ $(echo "$cu_only" | wc -m) -gt $(echo "$default" | wc -m) ]; then
exit 1
fi
+
+ if $zip; then
+ # Zip option tests
+ testrun $ET_EXEC $verbose_arg -z -e $ET_EXEC > test.zip
+ tempfiles test.zip
+
+ unzip -v test.zip
+ unzip -t test.zip
+
+ # Ensure unzipped srcfiles.cxx and its contents are the same as the original source file
+ unzip -j test.zip "*/$SRC_NAME"
+ diff "$SRC_NAME" $abs_srcdir/../src/$SRC_NAME
+ rm -f test.zip $SRC_NAME
+ fi
done
done
+
+# Debuginfod source file downloading test.
+# Start debuginfod server on the elfutils build directory.
+if [ -x ${abs_builddir}/../debuginfod/debuginfod ] && $zip; then
+ LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../debuginfod/debuginfod -vvvv -d debuginfod.sqlite3 -F -p $PORT1 ${abs_top_builddir}/src > debuginfod.log 2>&1 &
+ PID1=$!
+ tempfiles debuginfod.sqlite3 debuginfod.log
+ wait_ready $PORT1 'ready' 1
+ wait_ready $PORT1 'thread_work_total{role="traverse"}' 1
+ wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
+ wait_ready4 $PORT1 'thread_busy{role="scan"}' 0 300 # lots of source files may be slow to index with $db on NFS
+
+ export DEBUGINFOD_URLS="http://localhost:${PORT1}/"
+ export DEBUGINFOD_VERBOSE=1
+ testrun $ET_EXEC -z -b -e $ET_EXEC > test.zip
+ tempfiles test.zip
+
+ unzip -v test.zip
+ unzip -t test.zip
+
+ # Extract the zip.
+ mkdir extracted
+ unzip test.zip -d extracted
+
+ # Ensure that source files for this tool have been archived.
+ source_files="srcfiles.cxx libdwfl.h gelf.h"
+ extracted_files=$(find extracted -type f)
+ for file in $source_files; do
+ echo "$extracted_files" | grep -q "$file" > /dev/null
+ done
+
+ # Compare between the extracted file and the actual source file srcfiles.cxx.
+ extracted_file=$(find extracted -name $SRC_NAME)
+ diff "$extracted_file" $abs_srcdir/../src/$SRC_NAME
+
+ rm -rf extracted
+
+ kill $PID1
+ wait
+ PID1=0
+fi