summaryrefslogtreecommitdiff
path: root/libdwfl
diff options
context:
space:
mode:
Diffstat (limited to 'libdwfl')
-rw-r--r--libdwfl/dwfl_module.c11
-rw-r--r--libdwfl/dwfl_module_getdwarf.c15
-rw-r--r--libdwfl/libdwfl.h6
-rw-r--r--libdwfl/libdwflP.h2
-rw-r--r--libdwfl/linux-proc-maps.c21
5 files changed, 49 insertions, 6 deletions
diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c
index bb167ab2..6787edf0 100644
--- a/libdwfl/dwfl_module.c
+++ b/libdwfl/dwfl_module.c
@@ -175,6 +175,17 @@ dwfl_report_module (Dwfl *dwfl, const char *name,
}
INTDEF (dwfl_report_module)
+Dwfl_Module *
+dwfl_report_module_pid (Dwfl *dwfl, const char *name, Dwarf_Addr start,
+ Dwarf_Addr end, pid_t pid)
+{
+ assert (pid > 0);
+ Dwfl_Module *mod = dwfl_report_module (dwfl, name, start, end);
+ if (mod != NULL)
+ mod->pid = pid;
+ return mod;
+}
+INTDEF (dwfl_report_module_pid)
/* Finish reporting the current set of modules to the library.
If REMOVED is not null, it's called for each module that
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index c4bd7395..d667513f 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -45,6 +45,16 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
set it with an open failure below. */
errno = 0;
+ off_t start_offset = 0;
+ size_t maximum_size = ~((size_t) 0);
+ if (mod->pid != 0 && file == &mod->main)
+ {
+ if (asprintf (&file->name, "/proc/%d/mem", mod->pid) < 0)
+ return CBFAIL;
+ start_offset = mod->low_addr;
+ maximum_size = mod->high_addr - mod->low_addr;
+ }
+
/* If there was a pre-primed file name left that the callback left
behind, try to open that file name. */
if (file->fd < 0 && file->name != NULL)
@@ -53,7 +63,10 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
if (file->fd < 0)
return CBFAIL;
- Dwfl_Error error = __libdw_open_file (&file->fd, &file->elf, true, false);
+ Dwfl_Error error = __libdw_open_file_at_offset (&file->fd, &file->elf,
+ start_offset,
+ maximum_size,
+ true, false);
if (error != DWFL_E_NOERROR)
return error;
}
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index 2bb4f455..cedadaef 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -145,6 +145,12 @@ extern int dwfl_report_segment (Dwfl *dwfl, int ndx,
extern Dwfl_Module *dwfl_report_module (Dwfl *dwfl, const char *name,
Dwarf_Addr start, Dwarf_Addr end);
+/* Call dwfl_report_module with support of possibly deleted files of running
+ live process with pid PID. */
+extern Dwfl_Module *dwfl_report_module_pid (Dwfl *dwfl, const char *name,
+ Dwarf_Addr start, Dwarf_Addr end,
+ pid_t pid);
+
/* Report a module to address BASE with start and end addresses computed
from the ELF program headers in the given file - see the table below.
FD may be -1 to open FILE_NAME. On success, FD is consumed by the
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 9d7157d6..f9915547 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -158,6 +158,7 @@ struct Dwfl_Module
char *name; /* Iterator name for this module. */
GElf_Addr low_addr, high_addr;
+ pid_t pid; /* Used for /proc/PID/mem reading. */
struct dwfl_file main, debug, aux_sym;
GElf_Addr main_bias;
@@ -709,6 +710,7 @@ INTDECL (dwfl_getthread_frames)
INTDECL (dwfl_getthreads)
INTDECL (dwfl_thread_getframes)
INTDECL (dwfl_frame_pc)
+INTDECL (dwfl_report_module_pid)
/* Leading arguments standard to callbacks passed a Dwfl_Module. */
#define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr
diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c
index cdb6959d..803cbdc0 100644
--- a/libdwfl/linux-proc-maps.c
+++ b/libdwfl/linux-proc-maps.c
@@ -177,14 +177,25 @@ proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
unsigned int last_dmajor = -1, last_dminor = -1;
uint64_t last_ino = -1;
char *last_file = NULL;
- Dwarf_Addr low = 0, high = 0;
+ Dwarf_Addr low = 0, high = 0, first_high = 0;
inline bool report (void)
{
if (last_file != NULL)
{
- Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, last_file,
- low, high);
+ size_t last_file_len = strlen (last_file);
+ const char deleted[] = " (deleted)";
+ const size_t deleted_len = strlen (deleted);
+ Dwfl_Module *mod;
+ if (last_file_len > deleted_len
+ && strcmp (last_file + last_file_len - deleted_len, deleted) == 0)
+ {
+ last_file[last_file_len - deleted_len] = 0;
+ mod = INTUSE(dwfl_report_module_pid) (dwfl, last_file,
+ low, first_high, pid);
+ }
+ else
+ mod = INTUSE(dwfl_report_module) (dwfl, last_file, low, high);
free (last_file);
last_file = NULL;
if (unlikely (mod == NULL))
@@ -226,7 +237,7 @@ proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
}
low = start;
- high = end;
+ high = first_high = end;
if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0
|| report ())
goto bad_report;
@@ -250,7 +261,7 @@ proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
if (report ())
goto bad_report;
low = start;
- high = end;
+ high = first_high = end;
last_file = strdup (file);
last_ino = ino;
last_dmajor = dmajor;