libdrgn: bring back dwfl_core_file_report() bug workaround

This workaround was originally present in commit e5874ad18a ("libdrgn:
use libdwfl"). We dropped in in commit 6a13d74c0c ("libdrgn: build
with bundled elfutils") because the bundled version of elfutils had the
fix. We forgot to bring it back in commit 4c5c5f3842 ("Remove bundled
version of elfutils") even though we support versions without the fix.

Reported-by: Serapheim Dimitropoulos <serapheim@delphix.com>
Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
Omar Sandoval 2021-06-09 15:11:36 -07:00
parent 46e3617a1e
commit 6b2dda3f95

View File

@ -644,6 +644,30 @@ drgn_debug_info_module_finish_indexing(struct drgn_debug_info *dbinfo,
}
}
/*
* Wrapper around dwfl_report_end() that works around a libdwfl bug which causes
* it to close stdin when it frees some modules that were reported by
* dwfl_core_file_report(). This was fixed in elfutils 0.177 by commit
* d37f6ea7e3e5 ("libdwfl: Fix fd leak/closing wrong fd after
* dwfl_core_file_report()"), but we support older versions.
*/
static int my_dwfl_report_end(struct drgn_debug_info *dbinfo,
int (*removed)(Dwfl_Module *, void *,
const char *, Dwarf_Addr, void *),
void *arg)
{
int fd = -1;
if ((dbinfo->prog->flags
& (DRGN_PROGRAM_IS_LINUX_KERNEL | DRGN_PROGRAM_IS_LIVE)) == 0)
fd = dup(0);
int ret = dwfl_report_end(dbinfo->dwfl, removed, arg);
if (fd != -1) {
dup2(fd, 0);
close(fd);
}
return ret;
}
struct drgn_dwfl_module_removed_arg {
struct drgn_debug_info *dbinfo;
bool finish_indexing;
@ -727,7 +751,7 @@ static void drgn_debug_info_free_modules(struct drgn_debug_info *dbinfo,
.finish_indexing = finish_indexing,
.free_all = free_all,
};
dwfl_report_end(dbinfo->dwfl, drgn_dwfl_module_removed, &arg);
my_dwfl_report_end(dbinfo, drgn_dwfl_module_removed, &arg);
}
struct drgn_error *
@ -1412,7 +1436,7 @@ struct drgn_error *
drgn_debug_info_report_flush(struct drgn_debug_info_load_state *load)
{
struct drgn_debug_info *dbinfo = load->dbinfo;
dwfl_report_end(dbinfo->dwfl, NULL, NULL);
my_dwfl_report_end(dbinfo, NULL, NULL);
struct drgn_error *err = drgn_debug_info_update_index(load);
dwfl_report_begin_add(dbinfo->dwfl);
if (err)
@ -1464,7 +1488,7 @@ struct drgn_error *drgn_debug_info_load(struct drgn_debug_info *dbinfo,
err = linux_kernel_report_debug_info(&load);
else
err = userspace_report_debug_info(&load);
dwfl_report_end(dbinfo->dwfl, NULL, NULL);
my_dwfl_report_end(dbinfo, NULL, NULL);
if (err)
goto err;