--- ./gdb/Makefile.in 2009-03-07 01:45:51.000000000 +0100 +++ ./gdb/Makefile.in 2009-03-07 01:52:00.000000000 +0100 @@ -396,7 +396,7 @@ CONFIG_UNINSTALL = @CONFIG_UNINSTALL@ # your system doesn't have fcntl.h in /usr/include (which is where it # should be according to Posix). DEFS = @DEFS@ -GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/config -DLOCALEDIR="\"$(localedir)\"" $(DEFS) +GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/config -I$(includedir)/rpm -DLOCALEDIR="\"$(localedir)\"" $(DEFS) # MH_CFLAGS, if defined, has host-dependent CFLAGS from the config directory. GLOBAL_CFLAGS = $(MH_CFLAGS) @@ -449,7 +449,7 @@ INSTALLED_LIBS=-lbfd -lreadline -lopcode CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \ $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ \ $(LIBICONV) $(LIBEXPAT) \ - $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) + $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) -lrpm CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) --- ./gdb/event-top.c 2009-03-07 02:29:51.000000000 +0100 +++ ./gdb/event-top.c 2009-03-07 01:52:00.000000000 +0100 @@ -33,6 +33,7 @@ #include "cli/cli-script.h" /* for reset_command_nest_depth */ #include "main.h" #include "gdbthread.h" +#include "symfile.h" /* For dont_repeat() */ #include "gdbcmd.h" @@ -193,6 +194,8 @@ cli_command_loop (void) char *a_prompt; char *gdb_prompt = get_prompt (); + debug_flush_missing (); + /* Tell readline what the prompt to display is and what function it will need to call after a whole line is read. This also displays the first prompt. */ @@ -264,6 +267,8 @@ display_gdb_prompt (char *new_prompt) /* Reset the nesting depth used when trace-commands is set. */ reset_command_nest_depth (); + debug_flush_missing (); + /* Each interpreter has its own rules on displaying the command prompt. */ if (!current_interp_display_prompt_p ()) --- ./gdb/symfile.c 2009-03-07 02:30:20.000000000 +0100 +++ ./gdb/symfile.c 2009-03-07 01:52:00.000000000 +0100 @@ -55,6 +55,7 @@ #include "solib.h" #include "remote.h" #include "libbfd.h" +#include "elf/external.h" #include #include @@ -63,6 +64,7 @@ #include #include #include +#include int (*deprecated_ui_load_progress_hook) (const char *section, unsigned long num); @@ -1684,6 +1686,269 @@ build_id_to_filename (struct build_id *b return retval; } +#include +#include +#include +#include + +/* This MISSING_RPM_HASH tracker is used to collect all the missing rpm files + and avoid their duplicities during a single inferior run. */ + +static struct htab *missing_rpm_hash; + +/* This MISSING_RPM_LIST tracker is used to collect and print as a single line + all the rpms right before the nearest GDB prompt. It gets cleared after + each such print (it is questionable if we should clear it after the print). + */ + +struct missing_rpm + { + struct missing_rpm *next; + char rpm[1]; + }; +static struct missing_rpm *missing_rpm_list; +static int missing_rpm_list_entries; + +/* Returns the count of newly added rpms. */ + +static int +missing_rpm_enlist (const char *filename) +{ + static int rpm_init_done = 0; + rpmts ts; + rpmdbMatchIterator mi; + int count = 0; + + if (filename == NULL) + return 0; + + if (!rpm_init_done) + { + if (rpmReadConfigFiles(NULL, NULL) != 0) + { + warning (_("Error reading the rpm configuration files")); + return 0; + } + rpm_init_done = 1; + } + + ts = rpmtsCreate (); + + mi = rpmtsInitIterator (ts, RPMTAG_BASENAMES, filename, 0); + if (mi != NULL) + { + for (;;) + { + Header h; + char *debuginfo, **slot, *s, *s2; + errmsg_t err; + size_t srcrpmlen = sizeof (".src.rpm") - 1; + size_t debuginfolen = sizeof ("-debuginfo") - 1; + rpmdbMatchIterator mi_debuginfo; + + h = rpmdbNextIterator (mi); + if (h == NULL) + break; + + /* Verify the debuginfo file is not already installed. */ + + debuginfo = headerFormat (h, "%{sourcerpm}-debuginfo.%{arch}", &err); + if (!debuginfo) + { + warning (_("Error querying the rpm file `%s': %s"), filename, + err); + continue; + } + /* s = `.src.rpm-debuginfo.%{arch}' */ + s = strrchr (debuginfo, '-') - srcrpmlen; + s2 = NULL; + if (s > debuginfo && memcmp (s, ".src.rpm", srcrpmlen) == 0) + { + /* s2 = `-%{release}.src.rpm-debuginfo.%{arch}' */ + s2 = memrchr (debuginfo, '-', s - debuginfo); + } + if (s2) + { + /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */ + s2 = memrchr (debuginfo, '-', s2 - debuginfo); + } + if (!s2) + { + warning (_("Error querying the rpm file `%s': %s"), filename, + debuginfo); + xfree (debuginfo); + continue; + } + /* s = `.src.rpm-debuginfo.%{arch}' */ + /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */ + memmove (s2 + debuginfolen, s2, s - s2); + memcpy (s2, "-debuginfo", debuginfolen); + /* s = `XXXX.%{arch}' */ + /* strlen ("XXXX") == srcrpmlen + debuginfolen */ + /* s2 = `-debuginfo-%{version}-%{release}XX.%{arch}' */ + /* strlen ("XX") == srcrpmlen */ + memmove (s + debuginfolen, s + srcrpmlen + debuginfolen, + strlen (s + srcrpmlen + debuginfolen) + 1); + /* s = `-debuginfo-%{version}-%{release}.%{arch}' */ + + /* RPMDBI_PACKAGES requires keylen == sizeof (int). */ + /* RPMDBI_LABEL is an interface for NVR-based dbiFindByLabel(). */ + mi_debuginfo = rpmtsInitIterator (ts, RPMDBI_LABEL, debuginfo, 0); + xfree (debuginfo); + if (mi_debuginfo) + { + rpmdbFreeIterator (mi_debuginfo); + count = 0; + break; + } + + /* The allocated memory gets utilized below for MISSING_RPM_HASH. */ + debuginfo = headerFormat (h, + "%{name}-%{version}-%{release}.%{arch}", + &err); + if (!debuginfo) + { + warning (_("Error querying the rpm file `%s': %s"), filename, + err); + continue; + } + + /* Base package name for `debuginfo-install'. We do not use the + `yum' command directly as the line + yum --enablerepo='*-debuginfo' install NAME-debuginfo.ARCH + would be more complicated than just: + debuginfo-install NAME-VERSION-RELEASE.ARCH + Do not supply the rpm base name (derived from .src.rpm name) as + debuginfo-install is unable to install the debuginfo package if + the base name PKG binary rpm is not installed while for example + PKG-libs would be installed (RH Bug 467901). + FUTURE: After multiple debuginfo versions simultaneously installed + get supported the support for the VERSION-RELEASE tags handling + may need an update. */ + + if (missing_rpm_hash == NULL) + { + /* DEL_F is passed NULL as MISSING_RPM_LIST's HTAB_DELETE + should not deallocate the entries. */ + + missing_rpm_hash = htab_create_alloc (64, htab_hash_string, + (int (*) (const void *, const void *)) streq, + NULL, xcalloc, xfree); + } + slot = (char **) htab_find_slot (missing_rpm_hash, debuginfo, INSERT); + /* XCALLOC never returns NULL. */ + gdb_assert (slot != NULL); + if (*slot == NULL) + { + struct missing_rpm *missing_rpm; + + *slot = debuginfo; + + missing_rpm = xmalloc (sizeof (*missing_rpm) + strlen (debuginfo)); + strcpy (missing_rpm->rpm, debuginfo); + missing_rpm->next = missing_rpm_list; + missing_rpm_list = missing_rpm; + missing_rpm_list_entries++; + } + else + xfree (debuginfo); + count++; + } + + rpmdbFreeIterator (mi); + } + + rpmtsFree (ts); + + return count; +} + +static int +missing_rpm_list_compar (const char *const *ap, const char *const *bp) +{ + return strcoll (*ap, *bp); +} + +/* It returns a NULL-terminated array of strings needing to be FREEd. It may + also return only NULL. */ + +static void +missing_rpm_list_print (void) +{ + char **array, **array_iter; + struct missing_rpm *list_iter; + struct cleanup *cleanups; + + if (missing_rpm_list_entries == 0) + return; + + array = xmalloc (sizeof (*array) * missing_rpm_list_entries); + cleanups = make_cleanup (xfree, array); + + array_iter = array; + for (list_iter = missing_rpm_list; list_iter != NULL; + list_iter = list_iter->next) + { + *array_iter++ = list_iter->rpm; + } + gdb_assert (array_iter == array + missing_rpm_list_entries); + + qsort (array, missing_rpm_list_entries, sizeof (*array), + (int (*) (const void *, const void *)) missing_rpm_list_compar); + + printf_unfiltered (_("Missing separate debuginfos, use: %s"), + "debuginfo-install"); + for (array_iter = array; array_iter < array + missing_rpm_list_entries; + array_iter++) + { + putchar_unfiltered (' '); + puts_unfiltered (*array_iter); + } + putchar_unfiltered ('\n'); + + while (missing_rpm_list != NULL) + { + list_iter = missing_rpm_list; + missing_rpm_list = list_iter->next; + xfree (list_iter); + } + missing_rpm_list_entries = 0; + + do_cleanups (cleanups); +} + +static void +missing_rpm_change (void) +{ + debug_flush_missing (); + + gdb_assert (missing_rpm_list == NULL); + if (missing_rpm_hash != NULL) + { + htab_delete (missing_rpm_hash); + missing_rpm_hash = NULL; + } +} + +enum missing_exec + { + /* Init state. EXEC_BFD also still could be NULL. */ + MISSING_EXEC_NOT_TRIED, + /* We saw a non-NULL EXEC_BFD but RPM has no info about it. */ + MISSING_EXEC_NOT_FOUND, + /* We found EXEC_BFD by RPM and we either have its symbols (either embedded + or separate) or the main executable's RPM is now contained in + MISSING_RPM_HASH. */ + MISSING_EXEC_ENLISTED + }; +static enum missing_exec missing_exec = MISSING_EXEC_NOT_TRIED; + +void +debug_flush_missing (void) +{ + missing_rpm_list_print (); +} + /* This MISSING_FILEPAIR_HASH tracker is used only for the duplicite messages yum --enablerepo='*-debuginfo' install ... avoidance. */ @@ -1739,11 +2004,13 @@ missing_filepair_change (void) /* All their memory came just from missing_filepair_OBSTACK. */ missing_filepair_hash = NULL; } + missing_exec = MISSING_EXEC_NOT_TRIED; } static void debug_print_executable_changed (void) { + missing_rpm_change (); missing_filepair_change (); } @@ -1802,14 +2069,31 @@ debug_print_missing (const char *binary, } *slot = missing_filepair; - /* We do not collect and flush these messages as each such message - already requires its own separate lines. */ + if (missing_exec == MISSING_EXEC_NOT_TRIED) + { + char *exec_filename; - fprintf_unfiltered (gdb_stdlog, - _("Missing separate debuginfo for %s\n"), binary); - if (debug != NULL) - fprintf_unfiltered (gdb_stdlog, _("Try: %s %s\n"), - "yum --enablerepo='*-debuginfo' install", debug); + exec_filename = get_exec_file (0); + if (exec_filename != NULL) + { + if (missing_rpm_enlist (exec_filename) == 0) + missing_exec = MISSING_EXEC_NOT_FOUND; + else + missing_exec = MISSING_EXEC_ENLISTED; + } + } + if (missing_exec != MISSING_EXEC_ENLISTED) + if (missing_rpm_enlist (binary) == 0 && missing_rpm_enlist (debug) == 0) + { + /* We do not collect and flush these messages as each such message + already requires its own separate lines. */ + + fprintf_unfiltered (gdb_stdlog, + _("Missing separate debuginfo for %s\n"), binary); + if (debug != NULL) + fprintf_unfiltered (gdb_stdlog, _("Try: %s %s\n"), + "yum --enablerepo='*-debuginfo' install", debug); + } } static char * --- ./gdb/symfile.h 2009-03-07 02:16:18.000000000 +0100 +++ ./gdb/symfile.h 2009-03-07 01:52:00.000000000 +0100 @@ -378,6 +378,7 @@ extern struct build_id *build_id_addr_ge extern char *build_id_to_filename (struct build_id *build_id, char **link_return, int add_debug_suffix); extern void debug_print_missing (const char *binary, const char *debug); +extern void debug_flush_missing (void); /* From dwarf2read.c */ --- ./gdb/testsuite/lib/gdb.exp 2009-03-07 02:10:11.000000000 +0100 +++ ./gdb/testsuite/lib/gdb.exp 2009-03-07 01:52:00.000000000 +0100 @@ -1230,7 +1230,7 @@ proc default_gdb_start { } { warning "Couldn't set the width to 0." } } - # Turn off the missing warnings as the testsuite does not expect it. + # Turn off the missing RPMs warnings as the testsuite does not expect it. send_gdb "set build-id-verbose 0\n" gdb_expect 10 { -re "$gdb_prompt $" { --- ./gdb/tui/tui-interp.c 2009-03-07 02:28:47.000000000 +0100 +++ ./gdb/tui/tui-interp.c 2009-03-07 01:52:00.000000000 +0100 @@ -30,6 +30,7 @@ #include "tui/tui.h" #include "tui/tui-io.h" #include "exceptions.h" +#include "symfile.h" /* Set to 1 when the TUI mode must be activated when we first start gdb. */ @@ -128,6 +129,8 @@ tui_command_loop (void *data) char *a_prompt; char *gdb_prompt = get_prompt (); + debug_flush_missing (); + /* Tell readline what the prompt to display is and what function it will need to call after a whole line is read. This also displays the first prompt. */