From 1656bc00ae97fa16a941a8cefacc4e01488d0e8a Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Fri, 23 Dec 2005 01:49:50 +0000 Subject: [PATCH] 2005-12-22 Roland McGrath * argp-std.c (parse_opt): Call dwfl_end in failure cases. * linux-proc-maps.c (proc_maps_report): New function, broken out of ... (dwfl_linux_proc_report): ... here. Call it. (dwfl_linux_proc_maps_report): New function. * libdwfl.h: Declare it. * libdwflP.h: Add INTDECL. * argp-std.c (options, parse_opt): Grok -M/--linux-process-map. --- libdwfl/ChangeLog | 9 ++++++ libdwfl/argp-std.c | 47 +++++++++++++++++++++------ libdwfl/libdwfl.h | 5 +++ libdwfl/libdwflP.h | 1 + libdwfl/linux-proc-maps.c | 67 ++++++++++++++++++++++++--------------- 5 files changed, 93 insertions(+), 36 deletions(-) diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index ed52f44d0..8615f0cda 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,5 +1,14 @@ 2005-12-22 Roland McGrath + * argp-std.c (parse_opt): Call dwfl_end in failure cases. + + * linux-proc-maps.c (proc_maps_report): New function, broken out of ... + (dwfl_linux_proc_report): ... here. Call it. + (dwfl_linux_proc_maps_report): New function. + * libdwfl.h: Declare it. + * libdwflP.h: Add INTDECL. + * argp-std.c (options, parse_opt): Grok -M/--linux-process-map. + * dwfl_nextcu.c (dwfl_nextcu): Don't fail when dwfl_module_getdwarf failed with DWFL_E_NO_DWARF. diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c index 4a6e1607f..4ee5ce16f 100644 --- a/libdwfl/argp-std.c +++ b/libdwfl/argp-std.c @@ -29,6 +29,9 @@ static const struct argp_option options[] = { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 }, { "pid", 'p', "PID", 0, N_("Find addresses in files mapped into process PID"), 0 }, + { "linux-process-map", 'M', "FILE", 0, + N_("Find addresses in files mapped as read from FILE" + " in Linux /proc/PID/maps format"), 0 }, { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 }, { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL, N_("Kernel with all modules"), 0 }, @@ -67,17 +70,19 @@ static const Dwfl_Callbacks kernel_callbacks = static error_t parse_opt (int key, char *arg, struct argp_state *state) { - inline void failure (int errnum, const char *msg) + inline void failure (Dwfl *dwfl, int errnum, const char *msg) { if (errnum == -1) argp_failure (state, EXIT_FAILURE, 0, "%s: %s", msg, INTUSE(dwfl_errmsg) (-1)); else argp_failure (state, EXIT_FAILURE, errnum, "%s", msg); + if (dwfl != NULL) + dwfl_end (dwfl); } - inline error_t fail (int errnum, const char *msg) + inline error_t fail (Dwfl *dwfl, int errnum, const char *msg) { - failure (errnum, msg); + failure (dwfl, errnum, msg); return errnum == -1 ? EIO : errnum; } @@ -94,13 +99,13 @@ parse_opt (int key, char *arg, struct argp_state *state) { dwfl = INTUSE(dwfl_begin) (&offline_callbacks); if (dwfl == NULL) - return fail (-1, arg); + return fail (dwfl, -1, arg); state->hook = dwfl; } if (dwfl->callbacks == &offline_callbacks) { if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL) - return fail (-1, arg); + return fail (dwfl, -1, arg); state->hook = dwfl; } else @@ -119,7 +124,29 @@ parse_opt (int key, char *arg, struct argp_state *state) Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks); int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg)); if (result != 0) - return fail (result, arg); + return fail (dwfl, result, arg); + state->hook = dwfl; + } + else + goto toomany; + break; + + case 'M': + if (state->hook == NULL) + { + FILE *f = fopen (arg, "r"); + if (f == NULL) + { + int code = errno; + argp_failure (state, EXIT_FAILURE, code, + "cannot open '%s'", arg); + return code; + } + Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks); + int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f); + fclose (f); + if (result != 0) + return fail (dwfl, result, arg); state->hook = dwfl; } else @@ -132,11 +159,11 @@ parse_opt (int key, char *arg, struct argp_state *state) Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks); int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl); if (result != 0) - return fail (result, _("cannot load kernel symbols")); + return fail (dwfl, result, _("cannot load kernel symbols")); result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl); if (result != 0) /* Non-fatal to have no modules since we do have the kernel. */ - failure (result, _("cannot find kernel modules")); + failure (dwfl, result, _("cannot find kernel modules")); state->hook = dwfl; } else @@ -150,7 +177,7 @@ parse_opt (int key, char *arg, struct argp_state *state) int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg, NULL); if (result != 0) - return fail (result, _("cannot find kernel or modules")); + return fail (dwfl, result, _("cannot find kernel or modules")); state->hook = dwfl; } else @@ -167,7 +194,7 @@ parse_opt (int key, char *arg, struct argp_state *state) arg = "a.out"; dwfl = INTUSE(dwfl_begin) (&offline_callbacks); if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL) - return fail (-1, arg); + return fail (dwfl, -1, arg); state->hook = dwfl; } diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h index f46528097..4135fc3de 100644 --- a/libdwfl/libdwfl.h +++ b/libdwfl/libdwfl.h @@ -15,6 +15,7 @@ #define _LIBDWFL_H 1 #include "libdw.h" +#include /* Handle for a session using the library. */ typedef struct Dwfl Dwfl; @@ -213,6 +214,10 @@ extern int dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release, or an errno code if opening the kernel binary failed. */ extern int dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid); +/* Similar, but reads an input stream in the format of Linux /proc/PID/maps + files giving module layout, not the file for a live process. */ +extern int dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *); + /* Trivial find_elf callback for use with dwfl_linux_proc_report. This uses the module name as a file name directly and tries to open it if it begin with a slash, or handles the magic string "[vdso]". */ diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index a0d88d115..904cd55e2 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -244,6 +244,7 @@ INTDECL (dwfl_standard_find_debuginfo) INTDECL (dwfl_linux_kernel_find_elf) INTDECL (dwfl_linux_kernel_module_section_address) INTDECL (dwfl_linux_proc_report) +INTDECL (dwfl_linux_proc_maps_report) INTDECL (dwfl_linux_proc_find_elf) INTDECL (dwfl_linux_kernel_report_kernel) INTDECL (dwfl_linux_kernel_report_modules) diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c index 2611c73a4..fc1619ce4 100644 --- a/libdwfl/linux-proc-maps.c +++ b/libdwfl/linux-proc-maps.c @@ -91,30 +91,9 @@ find_sysinfo_ehdr (pid_t pid, GElf_Addr *sysinfo_ehdr) return nread < 0 ? errno : 0; } -int -dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid) +static int +proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid) { - if (dwfl == NULL) - return -1; - - /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it. */ - GElf_Addr sysinfo_ehdr = 0; - int result = find_sysinfo_ehdr (pid, &sysinfo_ehdr); - if (result != 0) - return result; - - char *fname = NULL; - asprintf (&fname, PROCMAPSFMT, pid); - if (fname == NULL) - return ENOMEM; - - FILE *f = fopen (fname, "r"); - free (fname); - if (f == NULL) - return errno; - - (void) __fsetlocking (f, FSETLOCKING_BYCALLER); - unsigned int last_dmajor = -1, last_dminor = -1; uint64_t last_ino = -1; char *last_file = NULL; @@ -201,16 +180,52 @@ dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid) } free (line); - result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC; - fclose (f); + int result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC; /* Report the final one. */ bool lose = report (); return result != 0 ? result : lose ? -1 : 0; } -INTDEF (dwfl_linux_proc_report) +int +dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *f) +{ + return proc_maps_report (dwfl, f, 0, 0); +} +INTDEF (dwfl_linux_proc_maps_report) + +int +dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid) +{ + if (dwfl == NULL) + return -1; + + /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it. */ + GElf_Addr sysinfo_ehdr = 0; + int result = find_sysinfo_ehdr (pid, &sysinfo_ehdr); + if (result != 0) + return result; + + char *fname = NULL; + asprintf (&fname, PROCMAPSFMT, pid); + if (fname == NULL) + return ENOMEM; + + FILE *f = fopen (fname, "r"); + free (fname); + if (f == NULL) + return errno; + + (void) __fsetlocking (f, FSETLOCKING_BYCALLER); + + result = proc_maps_report (dwfl, f, sysinfo_ehdr, pid); + + fclose (f); + + return result; +} +INTDEF (dwfl_linux_proc_report) static ssize_t read_proc_memory (void *arg, void *data, GElf_Addr address, -- 2.47.2