From d50c08025d41b2efc70dbb384fc691f2d9632463 Mon Sep 17 00:00:00 2001 From: Nick Alcock Date: Tue, 9 Jun 2020 10:27:57 +0100 Subject: libctf, open: fix opening CTF in binaries with no symtab This is a perfectly possible case, and half of ctf_bfdopen_ctfsect handled it fine. The other half hit a divide by zero or two before we got that far, and had no code path to load the strtab from anywhere in the absence of a symtab to point at it in any case. So, as a fallback, if there is no symtab, try loading ".strtab" explicitly by name, like we used to before we started looking for the strtab the symtab used. Of course, such a strtab is not kept hold of by BFD, so this means we have to bring back the code to possibly explicitly free the strtab that we read in. libctf/ * ctf-impl.h (struct ctf_archive_internal) New. * ctf-open-bfd.c (ctf_bfdopen_ctfsect): Explicitly open a strtab if the input has no symtab, rather than dividing by zero. Arrange to free it later via ctfi_free_ctfsect. * ctf-archive.c (ctf_new_archive_internal): Do not ctfi_free_strsect by default. (ctf_arc_close): Possibly free it here. --- libctf/ChangeLog | 11 +++++++ libctf/ctf-archive.c | 3 ++ libctf/ctf-impl.h | 1 + libctf/ctf-open-bfd.c | 81 ++++++++++++++++++++++++++++++++++----------------- 4 files changed, 70 insertions(+), 26 deletions(-) diff --git a/libctf/ChangeLog b/libctf/ChangeLog index 841f146..3f82c64 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,5 +1,16 @@ 2020-07-22 Nick Alcock + * ctf-impl.h (struct ctf_archive_internal) + New. + * ctf-open-bfd.c (ctf_bfdopen_ctfsect): Explicitly open a strtab + if the input has no symtab, rather than dividing by + zero. Arrange to free it later via ctfi_free_ctfsect. + * ctf-archive.c (ctf_new_archive_internal): Do not + ctfi_free_strsect by default. + (ctf_arc_close): Possibly free it here. + +2020-07-22 Nick Alcock + * ctf-dump.c (ctf_is_slice): Delete, unnecessary. (ctf_dump_format_type): improve slice formatting. Always print the type size, even of slices. diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c index 54d3d0a..e33f1cc 100644 --- a/libctf/ctf-archive.c +++ b/libctf/ctf-archive.c @@ -368,6 +368,7 @@ ctf_new_archive_internal (int is_archive, int unmap_on_close, if (strsect) memcpy (&arci->ctfi_strsect, strsect, sizeof (struct ctf_sect)); arci->ctfi_free_symsect = 0; + arci->ctfi_free_strsect = 0; arci->ctfi_unmap_on_close = unmap_on_close; return arci; @@ -493,6 +494,8 @@ ctf_arc_close (ctf_archive_t *arc) ctf_file_close (arc->ctfi_file); if (arc->ctfi_free_symsect) free ((void *) arc->ctfi_symsect.cts_data); + if (arc->ctfi_free_strsect) + free ((void *) arc->ctfi_strsect.cts_data); free (arc->ctfi_data); if (arc->ctfi_bfd_close) arc->ctfi_bfd_close (arc); diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 47a3927..913a264 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -333,6 +333,7 @@ struct ctf_archive_internal ctf_sect_t ctfi_symsect; ctf_sect_t ctfi_strsect; int ctfi_free_symsect; + int ctfi_free_strsect; void *ctfi_data; bfd *ctfi_abfd; /* Optional source of section data. */ void (*ctfi_bfd_close) (struct ctf_archive_internal *); diff --git a/libctf/ctf-open-bfd.c b/libctf/ctf-open-bfd.c index 2d2d572..9fcce2f 100644 --- a/libctf/ctf-open-bfd.c +++ b/libctf/ctf-open-bfd.c @@ -94,46 +94,69 @@ ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_, ctf_sect_t *symsectp = NULL; ctf_sect_t *strsectp = NULL; const char *bfderrstr = NULL; + char *strtab_alloc = NULL; #ifdef HAVE_BFD_ELF ctf_sect_t symsect, strsect; - Elf_Internal_Shdr *strhdr; Elf_Internal_Shdr *symhdr = &elf_symtab_hdr (abfd); - size_t symcount = symhdr->sh_size / symhdr->sh_entsize; + size_t symcount; Elf_Internal_Sym *isymbuf; - bfd_byte *symtab; + bfd_byte *symtab = NULL; const char *strtab = NULL; + size_t strsize; /* TODO: handle SYMTAB_SHNDX. */ - if ((symtab = malloc (symhdr->sh_size)) == NULL) + /* Get the symtab, and the strtab associated with it. */ + if (elf_tdata (abfd) && symhdr && symhdr->sh_size && symhdr->sh_entsize) { - bfderrstr = "Cannot malloc symbol table"; - goto err; - } + symcount = symhdr->sh_size / symhdr->sh_entsize; + if ((symtab = malloc (symhdr->sh_size)) == NULL) + { + bfderrstr = "Cannot malloc symbol table"; + goto err; + } - isymbuf = bfd_elf_get_elf_syms (abfd, symhdr, symcount, 0, - NULL, symtab, NULL); - free (isymbuf); - if (isymbuf == NULL) - { - bfderrstr = "Cannot read symbol table"; - goto err_free_sym; - } + isymbuf = bfd_elf_get_elf_syms (abfd, symhdr, symcount, 0, + NULL, symtab, NULL); + free (isymbuf); + if (isymbuf == NULL) + { + bfderrstr = "Cannot read symbol table"; + goto err_free_sym; + } + + if (elf_elfsections (abfd) != NULL + && symhdr->sh_link < elf_numsections (abfd)) + { + Elf_Internal_Shdr *strhdr = elf_elfsections (abfd)[symhdr->sh_link]; - if (elf_elfsections (abfd) != NULL - && symhdr->sh_link < elf_numsections (abfd)) + strsize = strhdr->sh_size; + if (strhdr->contents == NULL) + { + if ((strtab = bfd_elf_get_str_section (abfd, symhdr->sh_link)) == NULL) + { + bfderrstr = "Cannot read string table"; + goto err_free_sym; + } + } + else + strtab = (const char *) strhdr->contents; + } + } + else /* No symtab: just try getting .strtab by name. */ { - strhdr = elf_elfsections (abfd)[symhdr->sh_link]; - if (strhdr->contents == NULL) + bfd_byte *str_bcontents; + asection *str_asect; + + if ((str_asect = bfd_get_section_by_name (abfd, ".strtab")) != NULL) { - if ((strtab = bfd_elf_get_str_section (abfd, symhdr->sh_link)) == NULL) + if (bfd_malloc_and_get_section (abfd, str_asect, &str_bcontents)) { - bfderrstr = "Cannot read string table"; - goto err_free_sym; + strtab = (const char *) str_bcontents; + strtab_alloc = (char *) str_bcontents; + strsize = str_asect->size; } } - else - strtab = (const char *) strhdr->contents; } if (strtab) @@ -144,9 +167,12 @@ ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_, strsect.cts_data = strtab; strsect.cts_name = ".strtab"; - strsect.cts_size = strhdr->sh_size; + strsect.cts_size = strsize; strsectp = &strsect; + } + if (symtab) + { assert (symhdr->sh_entsize == get_elf_backend_data (abfd)->s->sizeof_sym); symsect.cts_name = ".symtab"; symsect.cts_entsize = symhdr->sh_entsize; @@ -159,13 +185,16 @@ ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_, arci = ctf_arc_bufopen (ctfsect, symsectp, strsectp, errp); if (arci) { - /* Request freeing of the symsect. */ + /* Request freeing of the symsect and possibly the strsect. */ arci->ctfi_free_symsect = 1; + if (strtab_alloc) + arci->ctfi_free_strsect = 1; return arci; } #ifdef HAVE_BFD_ELF err_free_sym: free (symtab); + free (strtab_alloc); #endif err: _libctf_unused_; if (bfderrstr) -- cgit v1.1