From 4790db149699b21113c566b8b9249953038fd3a7 Mon Sep 17 00:00:00 2001 From: Andrew Burgess Date: Fri, 5 Feb 2021 11:16:31 +0000 Subject: [PATCH] gdb: 'maint info sections' - handle the no executable case The 'maint info sections' command is split into two blocks or work, first if there's an executable then the sections from the executable, and optionally all other loaded object files are printed. Then all the sections from any core file are printed. I ran into a situation where (for various reasons) I wasn't using a main executable. Instead I connected to a remote target and used add-symbol-file. This allowed me to debug an image that was already loaded on the remote system. Unfortunately, when I tried to use 'maint info sections' I saw nothing. The reason is that the loop over all object files is hidden behind a check that we have a main executable. This commit removes this check and merges together some duplicate code. I also (I think) made the output of this command cleaner. Here is the original output of 'maint info sections': Exec file: `/tmp/hello.x', file type elf64-x86-64. [0] 0x004002a8->0x004002c4 at 0x000002a8: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS [1] 0x004002c4->0x004002e8 at 0x000002c4: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS ... And my modified output: Exec file: `/home/andrew/tmp/hello.x', file type elf64-x86-64. [0] 0x004002a8->0x004002c4 at 0x000002a8: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS [1] 0x004002c4->0x004002e8 at 0x000002c4: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS ... The forced newline after 'Exec file: ' has been removed. This is now a wrap point (in case the filename is very long). Here is the original output of 'maint info sections ALLOBJ': Exec file: `/tmp/hello.x', file type elf64-x86-64. Object file: /tmp/hello.x [0] 0x004002a8->0x004002c4 at 0x000002a8: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS [1] 0x004002c4->0x004002e8 at 0x000002c4: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS ... Object file: /lib64/ld-linux-x86-64.so.2 [0] 0x7ffff7fd12a8->0x7ffff7fd12c8 at 0x000002a8: .note.gnu.property ALLOC LOAD READONLY DATA HAS_CONTENTS [1] 0x7ffff7fd12c8->0x7ffff7fd12ec at 0x000002c8: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS ... And my modified output: Exec file: `/tmp/hello.x', file type elf64-x86-64. [0] 0x004002a8->0x004002c4 at 0x000002a8: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS [1] 0x004002c4->0x004002e8 at 0x000002c4: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS ... Object file: `/lib64/ld-linux-x86-64.so.2', file type elf64-x86-64. [0] 0x7ffff7fd12a8->0x7ffff7fd12c8 at 0x000002a8: .note.gnu.property ALLOC LOAD READONLY DATA HAS_CONTENTS [1] 0x7ffff7fd12c8->0x7ffff7fd12ec at 0x000002c8: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS ... The executable now only gets a single header line. The header line for the additional object files is no longer indented as it was before, and the line is laid out in a similar style to the main executable line (with quotes and file type information). And of course, the biggest change. If GDB is started with no executable, but then the user does 'add-symbol-file ....' followed by 'maint info sections ALLOBJ', previously they got nothing, now they get: Object file: `/tmp/hello.x', file type elf64-x86-64. [0] 0x004002a8->0x004002c4 at 0x000002a8: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS [1] 0x004002c4->0x004002e8 at 0x000002c4: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS ... gdb/ChangeLog: * maint.c (print_bfd_section_info_maybe_relocated): Delete, functionality merged into... (maint_print_all_sections): ...this new function. (maintenance_info_sections): Make use of maint_print_all_sections, allow all objects to be printed even where there's no executable. gdb/testsuite/ChangeLog: * gdb.base/maint-info-sections.exp: Update expected output, and add additional tests. --- gdb/ChangeLog | 8 ++ gdb/maint.c | 114 +++++++++--------- gdb/testsuite/ChangeLog | 5 + .../gdb.base/maint-info-sections.exp | 41 ++++++- 4 files changed, 105 insertions(+), 63 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 69e14b32730..14b11be1fe3 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2021-02-11 Andrew Burgess + + * maint.c (print_bfd_section_info_maybe_relocated): Delete, + functionality merged into... + (maint_print_all_sections): ...this new function. + (maintenance_info_sections): Make use of maint_print_all_sections, + allow all objects to be printed even where there's no executable. + 2021-02-11 Andrew Burgess * breakpoint.c (resolve_sal_pc): Make use of diff --git a/gdb/maint.c b/gdb/maint.c index f6e42f6a7e3..0dda11b7c2e 100644 --- a/gdb/maint.c +++ b/gdb/maint.c @@ -354,25 +354,50 @@ maint_obj_section_from_bfd_section (bfd *abfd, return osect; } -/* Print information about ASECT from ABFD. Where possible the information for - ASECT will print the relocated addresses of the section. +/* Print information about all sections from ABFD, which is the bfd + corresponding to OBJFILE. It is fine for OBJFILE to be nullptr, but + ABFD must never be nullptr. If OBJFILE is provided then the sections of + ABFD will (potentially) be displayed relocated (i.e. the object file was + loaded with add-symbol-file and custom offsets were provided). - ARG is the argument string passed by the user to the top level maintenance - info sections command. Used for filtering which sections are printed. */ + HEADER is a string that describes this file, e.g. 'Exec file: ', or + 'Core file: '. + + ARG is a string used for filtering which sections are printed, this can + be nullptr for no filtering. See the top level 'maint info sections' + for a fuller description of the possible filtering strings. */ static void -print_bfd_section_info_maybe_relocated (bfd *abfd, asection *asect, - objfile *objfile, const char *arg, - int index_digits) +maint_print_all_sections (const char *header, bfd *abfd, objfile *objfile, + const char *arg) { - gdb_assert (objfile->sections != NULL); - obj_section *osect - = maint_obj_section_from_bfd_section (abfd, asect, objfile); + puts_filtered (header); + wrap_here (" "); + printf_filtered ("`%s', ", bfd_get_filename (abfd)); + wrap_here (" "); + printf_filtered (_("file type %s.\n"), bfd_get_target (abfd)); - if (osect->the_bfd_section == NULL) - print_bfd_section_info (abfd, asect, arg, index_digits); - else - print_objfile_section_info (abfd, osect, arg, index_digits); + int section_count = gdb_bfd_count_sections (abfd); + int digits = index_digits (section_count); + + for (asection *sect : gdb_bfd_sections (abfd)) + { + obj_section *osect = nullptr; + + if (objfile != nullptr) + { + gdb_assert (objfile->sections != nullptr); + osect + = maint_obj_section_from_bfd_section (abfd, sect, objfile); + if (osect->the_bfd_section == nullptr) + osect = nullptr; + } + + if (osect == nullptr) + print_bfd_section_info (abfd, sect, arg, digits); + else + print_objfile_section_info (abfd, osect, arg, digits); + } } /* Implement the "maintenance info sections" command. */ @@ -380,56 +405,27 @@ print_bfd_section_info_maybe_relocated (bfd *abfd, asection *asect, static void maintenance_info_sections (const char *arg, int from_tty) { - if (current_program_space->exec_bfd ()) - { - bool allobj = false; - - printf_filtered (_("Exec file:\n")); - printf_filtered (" `%s', ", - bfd_get_filename (current_program_space->exec_bfd ())); - wrap_here (" "); - printf_filtered (_("file type %s.\n"), - bfd_get_target (current_program_space->exec_bfd ())); - - /* Only this function cares about the 'ALLOBJ' argument; - if 'ALLOBJ' is the only argument, discard it rather than - passing it down to print_objfile_section_info (which - wouldn't know how to handle it). */ - if (arg && strcmp (arg, "ALLOBJ") == 0) - { - arg = NULL; - allobj = true; - } + bool allobj = false; - for (objfile *ofile : current_program_space->objfiles ()) - { - if (allobj) - printf_filtered (_(" Object file: %s\n"), - bfd_get_filename (ofile->obfd)); - else if (ofile->obfd != current_program_space->exec_bfd ()) - continue; - - int section_count = gdb_bfd_count_sections (ofile->obfd); - - for (asection *sect : gdb_bfd_sections (ofile->obfd)) - print_bfd_section_info_maybe_relocated - (ofile->obfd, sect, ofile, arg, index_digits (section_count)); - } + /* Only this function cares about the 'ALLOBJ' argument; if 'ALLOBJ' is + the only argument, discard it rather than passing it down to + print_objfile_section_info (which wouldn't know how to handle it). */ + if (arg != nullptr && strcmp (arg, "ALLOBJ") == 0) + { + arg = nullptr; + allobj = true; } - if (core_bfd) + for (objfile *ofile : current_program_space->objfiles ()) { - printf_filtered (_("Core file:\n")); - printf_filtered (" `%s', ", bfd_get_filename (core_bfd)); - wrap_here (" "); - printf_filtered (_("file type %s.\n"), bfd_get_target (core_bfd)); - - int section_count = gdb_bfd_count_sections (core_bfd); - - for (asection *sect : gdb_bfd_sections (core_bfd)) - print_bfd_section_info (core_bfd, sect, arg, - index_digits (section_count)); + if (ofile->obfd == current_program_space->exec_bfd ()) + maint_print_all_sections (_("Exec file: "), ofile->obfd, ofile, arg); + else if (allobj) + maint_print_all_sections (_("Object file: "), ofile->obfd, ofile, arg); } + + if (core_bfd) + maint_print_all_sections (_("Core file: "), core_bfd, nullptr, arg); } static void diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index c2cc22254c1..0102a937fcf 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2021-02-11 Andrew Burgess + + * gdb.base/maint-info-sections.exp: Update expected output, and + add additional tests. + 2021-02-11 Andrew Burgess * gdb.base/maint-info-sections.exp: New file, content is moved diff --git a/gdb/testsuite/gdb.base/maint-info-sections.exp b/gdb/testsuite/gdb.base/maint-info-sections.exp index 6c41ff2bd90..19e5c122226 100644 --- a/gdb/testsuite/gdb.base/maint-info-sections.exp +++ b/gdb/testsuite/gdb.base/maint-info-sections.exp @@ -34,7 +34,7 @@ if ![runto_main] then { set seen_header false set seen_a_section false gdb_test_multiple "maint info sections" "general output check" { - -re "Exec file:\r\n\[\t ]+`\[^'\]+', file type \[^.\]+\.\r\n" { + -re "Exec file: `\[^'\]+', file type \[^.\]+\.\r\n" { set seen_header true exp_continue } @@ -63,18 +63,18 @@ set text_section ".text" set data_section ".data" gdb_test_multiple "maint info sections" "" { - -re -wrap "Exec file:\r\n.*${binfile}., file type.*ER_RO.*" { + -re -wrap "Exec file: .*${binfile}., file type.*ER_RO.*" { # Looks like RealView which uses different section names. set text_section ER_RO set data_section ER_RW pass "maint info sections" } - -re -wrap "Exec file:\r\n.*${binfile}., file type.*neardata.*" { + -re -wrap "Exec file: .*${binfile}., file type.*neardata.*" { # c6x doesn't have .data section. It has .neardata and .fardata section. set data_section ".neardata" pass "maint info sections" } - -re -wrap "Exec file:\r\n.*${binfile}., file type.*" { + -re -wrap "Exec file: .*${binfile}., file type.*" { pass "maint info sections" } } @@ -125,3 +125,36 @@ gdb_test_multiple "maint info sections DATA" "" { pass $gdb_test_name } } + +# Restart GDB, but don't load the executable. +clean_restart + +# Now load the executable in as a symbol file. +gdb_test "add-symbol-file ${binfile}" ".*" \ + "load the executable as a symbol file" \ + "add symbol table from file \"${binfile}\"\r\n\\(y or n\\) " \ + "y" + +# As we have no object file 'maint info sections' will print nothing. +gdb_test_no_output "maint info sections" \ + "no output when no executable is set" + +# Check that the executable shows up as an object file when ALLOBJ is +# used. +set seen_header false +set seen_a_section false +gdb_test_multiple "maint info sections ALLOBJ" "" { + -re "Object file: `${binfile}', file type \[^.\]+\.\r\n" { + set seen_header true + exp_continue + } + -re "^ \\\[\[0-9\]+\\\]\[\t \]+$hex->$hex at $hex: \[^*\r\]+\r\n" { + set seen_a_section true + exp_continue + } + -re "^$gdb_prompt $" { + gdb_assert { $seen_header && $seen_a_section } \ + "ensure header and section seen in ALLOBJ case" + pass $gdb_test_name + } +} -- 2.30.2