gdb/bfd: avoid crash when architecture is forced to csky or riscv

I built GDB with `--enable-targets=all`, then started GDB passing it
an x86-64 executable, finally I ran 'maint selftest', and observed GDB
crash like this:

  BFD: BFD (GNU Binutils) 2.36.50.20210519 assertion fail ../../src/bfd/hash.c:438
  Aborted (core dumped)

The problem originates from two locations, for example in csky-dis.c
(csky_get_disassembler) where we do this:

  const char *sec_name = NULL;
  ...
  sec_name = get_elf_backend_data (abfd)->obj_attrs_section;
  if (bfd_get_section_by_name (abfd, sec_name) != NULL)
    ...

We end up in here because during the selftests GDB forces the
architecture to be csky, but the BFD being accessed is still of type
x86-64.  As a result obj_attrs_section returns NULL, which means we
end up passing NULL to bfd_get_section_by_name.  If we follow the
function calls from bfd_get_section_by_name we eventually end up in
bfd_hash_hash, which asserts that the string (i.e. the name) is not
NULL.

The same crash can be reproduced in GDB without using the selftests,
for example:

  (gdb) file x86_64.elf
  (gdb) start
  (gdb) set architecture csky
  (gdb) disassemble main
  Dump of assembler code for function main:
  BFD: BFD (GNU Binutils) 2.36.50.20210519 assertion fail ../../src/bfd/hash.c:438
  Aborted (core dumped)

The fix I propose here is to have bfd_get_section_by_name return NULL
if name is ever NULL.  For consistency I updated
bfd_get_section_by_name_if in the same way, even though I'm not
hitting any problems along that code path right now.

I looked through the source tree and removed two NULL checks in
bfd/dwarf2.c which are no longer needed, its possible that there are
additional NULL checks that could be removed, I just didn't find them.

bfd/ChangeLog:

	* section.c (bfd_get_section_by_name): Return NULL if name is
	NULL.
	(bfd_get_section_by_name_if): Likewise.
	* dwarf2.c (read_section): Remove unneeded NULL check.
	(find_debug_info): Likewise.
This commit is contained in:
Andrew Burgess 2021-05-20 09:16:41 +01:00
parent 8baee38bfe
commit 427e4066af
3 changed files with 18 additions and 8 deletions

View file

@ -1,3 +1,11 @@
2021-05-20 Andrew Burgess <andrew.burgess@embecosm.com>
* section.c (bfd_get_section_by_name): Return NULL if name is
NULL.
(bfd_get_section_by_name_if): Likewise.
* dwarf2.c (read_section): Remove unneeded NULL check.
(find_debug_info): Likewise.
2021-05-19 Nick Clifton <nickc@redhat.com> 2021-05-19 Nick Clifton <nickc@redhat.com>
* plugin.c (bfd_plugin_open_input): Inform the user if the limit * plugin.c (bfd_plugin_open_input): Inform the user if the limit

View file

@ -545,8 +545,7 @@ read_section (bfd * abfd,
if (msec == NULL) if (msec == NULL)
{ {
section_name = sec->compressed_name; section_name = sec->compressed_name;
if (section_name != NULL) msec = bfd_get_section_by_name (abfd, section_name);
msec = bfd_get_section_by_name (abfd, section_name);
} }
if (msec == NULL) if (msec == NULL)
{ {
@ -4226,12 +4225,9 @@ find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections,
return msec; return msec;
look = debug_sections[debug_info].compressed_name; look = debug_sections[debug_info].compressed_name;
if (look != NULL) msec = bfd_get_section_by_name (abfd, look);
{ if (msec != NULL)
msec = bfd_get_section_by_name (abfd, look); return msec;
if (msec != NULL)
return msec;
}
for (msec = abfd->sections; msec != NULL; msec = msec->next) for (msec = abfd->sections; msec != NULL; msec = msec->next)
if (startswith (msec->name, GNU_LINKONCE_INFO)) if (startswith (msec->name, GNU_LINKONCE_INFO))

View file

@ -898,6 +898,9 @@ bfd_get_section_by_name (bfd *abfd, const char *name)
{ {
struct section_hash_entry *sh; struct section_hash_entry *sh;
if (name == NULL)
return NULL;
sh = section_hash_lookup (&abfd->section_htab, name, false, false); sh = section_hash_lookup (&abfd->section_htab, name, false, false);
if (sh != NULL) if (sh != NULL)
return &sh->section; return &sh->section;
@ -1006,6 +1009,9 @@ bfd_get_section_by_name_if (bfd *abfd, const char *name,
struct section_hash_entry *sh; struct section_hash_entry *sh;
unsigned long hash; unsigned long hash;
if (name == NULL)
return NULL;
sh = section_hash_lookup (&abfd->section_htab, name, false, false); sh = section_hash_lookup (&abfd->section_htab, name, false, false);
if (sh == NULL) if (sh == NULL)
return NULL; return NULL;