diff options
author | jbj <devnull@localhost> | 2003-03-06 00:57:54 +0000 |
---|---|---|
committer | jbj <devnull@localhost> | 2003-03-06 00:57:54 +0000 |
commit | 29cffe52fca8d5480c333c557996d2bc0196a801 (patch) | |
tree | 6f222be8cb18848730bd6a36fd07e37a39785deb /elfutils | |
parent | e8cf6cbb056a5b4517191b2a216d48a712993460 (diff) | |
download | rpm-29cffe52fca8d5480c333c557996d2bc0196a801.tar.gz rpm-29cffe52fca8d5480c333c557996d2bc0196a801.tar.bz2 rpm-29cffe52fca8d5480c333c557996d2bc0196a801.zip |
Revert c99 syntax in elfutils.
Fiddles to build on Red Hat 7.3.
CVS patchset: 6654
CVS date: 2003/03/06 00:57:54
Diffstat (limited to 'elfutils')
-rw-r--r-- | elfutils/libasm/asm_addint8.c | 29 | ||||
-rw-r--r-- | elfutils/libasm/asm_addsleb128.c | 22 | ||||
-rw-r--r-- | elfutils/libasm/asm_adduleb128.c | 22 | ||||
-rw-r--r-- | elfutils/libasm/asm_align.c | 44 | ||||
-rw-r--r-- | elfutils/libasm/asm_end.c | 142 | ||||
-rw-r--r-- | elfutils/libdw/dwarf_begin_elf.c | 18 | ||||
-rw-r--r-- | elfutils/libdw/dwarf_get_pubnames.c | 28 | ||||
-rw-r--r-- | elfutils/libebl/eblcorenote.c | 24 | ||||
-rw-r--r-- | elfutils/libebl/eblobjnote.c | 21 | ||||
-rw-r--r-- | elfutils/libebl/eblopenbackend.c | 246 | ||||
-rw-r--r-- | elfutils/libebl/i386_corenote.c | 44 | ||||
-rw-r--r-- | elfutils/po/elfutils.pot | 198 | ||||
-rw-r--r-- | elfutils/src/elflint.c | 515 | ||||
-rw-r--r-- | elfutils/src/nm.c | 484 | ||||
-rw-r--r-- | elfutils/src/readelf.c | 1103 | ||||
-rw-r--r-- | elfutils/src/strip.c | 937 | ||||
-rw-r--r-- | elfutils/tests/ecp.c | 19 | ||||
-rw-r--r-- | elfutils/tests/get-pubnames2.c | 5 | ||||
-rw-r--r-- | elfutils/tests/newscn.c | 4 |
19 files changed, 3042 insertions, 863 deletions
diff --git a/elfutils/libasm/asm_addint8.c b/elfutils/libasm/asm_addint8.c index b089d1cc0..677d484ce 100644 --- a/elfutils/libasm/asm_addint8.c +++ b/elfutils/libasm/asm_addint8.c @@ -2,18 +2,15 @@ Copyright (C) 2002 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2002. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -37,11 +34,13 @@ #define BSWAP(size) _BSWAP(size) #define _BSWAP(size) bswap_##size + int FCT(SIZE) (asmscn, num) AsmScn_t *asmscn; TYPE(SIZE) num; { + TYPE(SIZE) var; if (asmscn == NULL) return -1; @@ -79,10 +78,11 @@ FCT(SIZE) (asmscn, num) bool is_leb = (elf_getident (asmscn->ctx->out.elf, NULL)[EI_DATA] == ELFDATA2LSB); #endif - TYPE(SIZE) var = num; + var = num; /* Make sure we have enough room. */ - __libasm_ensure_section_space (asmscn, SIZE / 8); + if (__libasm_ensure_section_space (asmscn, SIZE / 8) != 0) + return -1; #if SIZE > 8 if ((BYTE_ORDER == LITTLE_ENDIAN && !is_leb) @@ -91,7 +91,8 @@ FCT(SIZE) (asmscn, num) #endif /* Copy the variable value. */ - memcpy (&asmscn->content->data[asmscn->content->len], &var, SIZE / 8); + if (likely (asmscn->type == SHT_NOBITS)) + memcpy (&asmscn->content->data[asmscn->content->len], &var, SIZE / 8); /* Adjust the pointer in the data buffer. */ asmscn->content->len += SIZE / 8; diff --git a/elfutils/libasm/asm_addsleb128.c b/elfutils/libasm/asm_addsleb128.c index e517202c7..f02a2a7ec 100644 --- a/elfutils/libasm/asm_addsleb128.c +++ b/elfutils/libasm/asm_addsleb128.c @@ -2,18 +2,15 @@ Copyright (C) 2002 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2002. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -47,6 +44,7 @@ asm_addsleb128 (asmscn, num) char *dest = tmpbuf; uint32_t byte; int32_t endval = num >> 31; + size_t nbytes; if (num == 0) byte = 0; @@ -66,7 +64,7 @@ asm_addsleb128 (asmscn, num) *dest++ = byte; /* Number of bytes produced. */ - size_t nbytes = dest - tmpbuf; + nbytes = dest - tmpbuf; /* Make sure we have enough room. */ if (__libasm_ensure_section_space (asmscn, nbytes) != 0) diff --git a/elfutils/libasm/asm_adduleb128.c b/elfutils/libasm/asm_adduleb128.c index d7923b44c..8fb1ac595 100644 --- a/elfutils/libasm/asm_adduleb128.c +++ b/elfutils/libasm/asm_adduleb128.c @@ -2,18 +2,15 @@ Copyright (C) 2002 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2002. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -46,6 +43,7 @@ asm_adduleb128 (asmscn, num) char tmpbuf[(sizeof (num) * 8 + 6) / 7]; char *dest = tmpbuf; uint32_t byte; + size_t nbytes; while (1) { @@ -62,7 +60,7 @@ asm_adduleb128 (asmscn, num) *dest++ = byte; /* Number of bytes produced. */ - size_t nbytes = dest - tmpbuf; + nbytes = dest - tmpbuf; /* Make sure we have enough room. */ if (__libasm_ensure_section_space (asmscn, nbytes) != 0) diff --git a/elfutils/libasm/asm_align.c b/elfutils/libasm/asm_align.c index eb6db67ef..c19996621 100644 --- a/elfutils/libasm/asm_align.c +++ b/elfutils/libasm/asm_align.c @@ -2,23 +2,21 @@ Copyright (C) 2002 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2002. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif +#include <stdlib.h> #include <sys/param.h> #include <libasmP.h> @@ -30,6 +28,7 @@ asm_align (asmscn, value) AsmScn_t *asmscn; GElf_Word value; { + int result = 0; if (asmscn == NULL) /* An earlier error. */ return -1; @@ -53,7 +52,9 @@ asm_align (asmscn, value) cnt = value - (asmscn->offset & (value - 1)); /* Ensure there is enough room to add the fill bytes. */ - __libasm_ensure_section_space (asmscn, cnt); + result = __libasm_ensure_section_space (asmscn, cnt); + if (result != 0) + goto out; /* Fill in the bytes. We align the pattern according to the current offset. */ @@ -90,15 +91,16 @@ asm_align (asmscn, value) } } + out: rwlock_unlock (asmscn->ctx->lock); - return 0; + return result; } /* Ensure there are at least LEN bytes available in the output buffer for ASMSCN. */ -void +int __libasm_ensure_section_space (asmscn, len) AsmScn_t *asmscn; size_t len; @@ -112,8 +114,10 @@ __libasm_ensure_section_space (asmscn, len) /* This is the first block. */ size = MAX (2 * len, 960); - asmscn->content = (struct AsmData *) xmalloc (sizeof (struct AsmData) - + size); + asmscn->content = (struct AsmData *) malloc (sizeof (struct AsmData) + + size); + if (asmscn->content == NULL) + return -1; asmscn->content->next = asmscn->content; } @@ -123,11 +127,13 @@ __libasm_ensure_section_space (asmscn, len) if (asmscn->content->maxlen - asmscn->content->len >= len) /* Nothing to do, there is enough space. */ - return; + return 0; size = MAX (2 *len, MIN (32768, 2 * asmscn->offset)); - newp = (struct AsmData *) xmalloc (sizeof (struct AsmData) + size); + newp = (struct AsmData *) malloc (sizeof (struct AsmData) + size); + if (newp == NULL) + return -1; newp->next = asmscn->content->next; asmscn->content = asmscn->content->next = newp; @@ -135,4 +141,6 @@ __libasm_ensure_section_space (asmscn, len) asmscn->content->len = 0; asmscn->content->maxlen = size; + + return 0; } diff --git a/elfutils/libasm/asm_end.c b/elfutils/libasm/asm_end.c index 3f1085620..39bc6b2bb 100644 --- a/elfutils/libasm/asm_end.c +++ b/elfutils/libasm/asm_end.c @@ -1,19 +1,16 @@ /* Finalize operations on the assembler context, free all resources. - Copyright (C) 2002 Red Hat, Inc. + Copyright (C) 2002, 2003 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2002. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -55,11 +52,16 @@ binary_end (AsmCtx_t *ctx) size_t strscnndx = 0; size_t xndxscnndx = 0; Elf_Data *data; + Elf_Data *shstrtabdata; + Elf_Data *strtabdata = NULL; + Elf_Data *xndxdata = NULL; GElf_Shdr shdr_mem; GElf_Shdr *shdr; GElf_Ehdr ehdr_mem; GElf_Ehdr *ehdr; AsmScn_t *asmscn; + int result = 0; + AsmScnGrp_t *scngrp; /* Iterate over the created sections and compute the offsets of the various subsections and fill in the content. */ @@ -128,14 +130,14 @@ binary_end (AsmCtx_t *ctx) /* Create the symbol string table section. */ strscn = elf_newscn (ctx->out.elf); - data = elf_newdata (strscn); + strtabdata = elf_newdata (strscn); shdr = gelf_getshdr (strscn, &shdr_mem); - if (data == NULL || shdr == NULL) + if (strtabdata == NULL || shdr == NULL) error (EXIT_FAILURE, 0, _("cannot create section for output file: %s"), elf_errmsg (-1)); strscnndx = elf_ndxscn (strscn); - ebl_strtabfinalize (ctx->symbol_strtab, data); + ebl_strtabfinalize (ctx->symbol_strtab, strtabdata); shdr->sh_type = SHT_STRTAB; assert (shdr->sh_entsize == 0); @@ -154,7 +156,9 @@ binary_end (AsmCtx_t *ctx) /* We know how many symbols there will be in the symbol table. */ data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM, ctx->nsymbol_tab + 1, EV_CURRENT); - symtab = xmalloc (data->d_size); + symtab = malloc (data->d_size); + if (symtab == NULL) + return -1; data->d_buf = symtab; data->d_type = ELF_T_SYM; data->d_off = 0; @@ -182,7 +186,8 @@ binary_end (AsmCtx_t *ctx) syment.st_value = sym->scn->offset + sym->offset; syment.st_size = sym->size; - /* Add local symbols at the beginning, the other from the end. */ + /* Add local symbols at the beginning, the other from + the end. */ ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--; /* Determine the section index. We have to handle the @@ -203,7 +208,6 @@ binary_end (AsmCtx_t *ctx) exist. */ Elf_Scn *xndxscn; size_t symscnndx = elf_ndxscn (symscn); - Elf_Data *xndxdata; xndxscn = elf_newscn (ctx->out.elf); xndxdata = elf_newdata (xndxscn); @@ -216,6 +220,7 @@ cannot create extended section index table: %s"), shdr->sh_type = SHT_SYMTAB_SHNDX; shdr->sh_entsize = sizeof (Elf32_Word); + shdr->sh_addralign = sizeof (Elf32_Word); shdr->sh_link = symscnndx; (void) gelf_update_shdr (xndxscn, shdr); @@ -228,7 +233,9 @@ cannot create extended section index table: %s"), xndxdata->d_size = elf32_fsize (ELF_T_WORD, ctx->nsymbol_tab + 1, EV_CURRENT); - xshndx = xndxdata->d_buf = xcalloc (1, xndxdata->d_size); + xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size); + if (xshndx == NULL) + return -1; /* Using ELF_T_WORD here relies on the fact that the 32- and 64-bit types are the same size. */ xndxdata->d_type = ELF_T_WORD; @@ -257,6 +264,8 @@ cannot create extended section index table: %s"), shdr->sh_link = strscnndx; shdr->sh_info = ptr_local; shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT); + shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1, + EV_CURRENT); (void) gelf_update_shdr (symscn, shdr); } @@ -265,9 +274,9 @@ cannot create extended section index table: %s"), /* Create the section header string table section and fill in the references in the section headers. */ shstrscn = elf_newscn (ctx->out.elf); - data = elf_newdata (shstrscn); + shstrtabdata = elf_newdata (shstrscn); shdr = gelf_getshdr (shstrscn, &shdr_mem); - if (shstrscn == NULL || data == NULL || shdr == NULL) + if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL) error (EXIT_FAILURE, 0, _("cannot create section for output file: %s"), elf_errmsg (-1)); @@ -275,7 +284,7 @@ cannot create extended section index table: %s"), /* Add the name of the section header string table. */ shstrscn_strent = ebl_strtabadd (ctx->section_strtab, ".shstrtab", 10); - ebl_strtabfinalize (ctx->section_strtab, data); + ebl_strtabfinalize (ctx->section_strtab, shstrtabdata); shdr->sh_type = SHT_STRTAB; assert (shdr->sh_entsize == 0); @@ -312,7 +321,9 @@ cannot create extended section index table: %s"), here. */ data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1, EV_CURRENT); - grpdata = data->d_buf = xmalloc (data->d_size); + grpdata = data->d_buf = malloc (data->d_size); + if (grpdata == NULL) + return -1; data->d_type = ELF_T_WORD; data->d_off = 0; data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT); @@ -438,19 +449,36 @@ cannot create extended section index table: %s"), /* Write out the ELF file. */ if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP)) < 0) { - err_libelf: __libasm_seterrno (ASM_E_LIBELF); - return -1; + result = -1; } + /* We do not need the section header and symbol string tables anymore. */ + free (shstrtabdata->d_buf); + if (strtabdata != NULL) + free (strtabdata->d_buf); + /* We might have allocated the extended symbol table index. */ + if (xndxdata != NULL) + free (xndxdata->d_buf); + + /* Free section groups memory. */ + scngrp = ctx->groups; + if (scngrp != NULL) + do + free (elf_getdata (scngrp->scn, NULL)->d_buf); + while ((scngrp = scngrp->next) != ctx->groups); + /* Finalize the ELF handling. */ if (unlikely (elf_end (ctx->out.elf)) != 0) - goto err_libelf; + { + __libasm_seterrno (ASM_E_LIBELF); + result = -1; + } /* Free the temporary resources. */ free (symtab); - return 0; + return result; } @@ -489,10 +517,65 @@ asm_end (ctx) } +static void +free_section (AsmScn_t *scnp) +{ + void *oldp; + struct AsmData *data; + + if (scnp->subnext != NULL) + free_section (scnp->subnext); + + data = scnp->content; + if (data != NULL) + do + { + oldp = data; + data = data->next; + free (oldp); + } + while (oldp != scnp->content); + + free (scnp); +} + + void __libasm_finictx (ctx) AsmCtx_t *ctx; { + void *runp = NULL; + AsmSym_t *sym; + AsmScnGrp_t *scngrp; + + /* Iterate through section table and free individual entries. */ + AsmScn_t *scn = ctx->section_list; + while (scn != NULL) + { + AsmScn_t *oldp = scn; + scn = scn->allnext; + free_section (oldp); + } + + /* Free the resources of the symbol table. */ + while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL) + free (sym); + asm_symbol_tab_free (&ctx->symbol_tab); + + + /* Free section groups. */ + scngrp = ctx->groups; + if (scngrp != NULL) + do + { + AsmScnGrp_t *oldp = scngrp; + + scngrp = scngrp->next; + free (oldp); + } + while (scngrp != ctx->groups); + + if (unlikely (ctx->textp)) { /* Close the stream. */ @@ -505,11 +588,6 @@ __libasm_finictx (ctx) find any. */ (void) close (ctx->fd); - - /* XXX Iterate through section table and free individual entries. */ - - /* Free the resources of the hash table. */ - asm_symbol_tab_free (&ctx->symbol_tab); /* And the string tables. */ ebl_strtabfree (ctx->section_strtab); ebl_strtabfree (ctx->symbol_strtab); diff --git a/elfutils/libdw/dwarf_begin_elf.c b/elfutils/libdw/dwarf_begin_elf.c index 7523aa23a..aaa0c1dac 100644 --- a/elfutils/libdw/dwarf_begin_elf.c +++ b/elfutils/libdw/dwarf_begin_elf.c @@ -54,6 +54,8 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) { GElf_Shdr shdr_mem; GElf_Shdr *shdr; + const char *scnname; + int cnt; /* Get the section header data. */ shdr = gelf_getshdr (scn, &shdr_mem); @@ -75,7 +77,7 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) /* We recognize the DWARF section by their names. This is not very safe and stable but the best we can do. */ - const char *scnname = elf_strptr (result->elf, ehdr->e_shstrndx, + scnname = elf_strptr (result->elf, ehdr->e_shstrndx, shdr->sh_name); if (scnname == NULL) { @@ -88,17 +90,17 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) /* Recognize the various sections. Most names start with .debug_. */ - int cnt; for (cnt = 0; cnt < ndwarf_scnnames; ++cnt) if (strcmp (scnname, dwarf_scnnames[cnt]) == 0) { + Elf_Data *data; /* Found it. Remember where the data is. */ if (unlikely (result->sectiondata[cnt] != NULL)) /* A section appears twice. That's bad. We ignore the section. */ break; /* Get the section data. */ - Elf_Data *data = elf_getdata (scn, NULL); + data = elf_getdata (scn, NULL); if (data != NULL && data->d_size != 0) /* Yep, there is actually data available. */ result->sectiondata[cnt] = data; @@ -144,6 +146,8 @@ static Dwarf * scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr, Dwarf_Cmd cmd, Elf_Scn *scngrp) { + Elf32_Word *scnidx; + size_t cnt; /* SCNGRP is the section descriptor for a section group which might contain debug sections. */ Elf_Data *data = elf_getdata (scngrp, NULL); @@ -156,8 +160,7 @@ scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr, Dwarf_Cmd cmd, /* The content of the section is a number of 32-bit words which represent section indices. The first word is a flag word. */ - Elf32_Word *scnidx = (Elf32_Word *) data->d_buf; - size_t cnt; + scnidx = (Elf32_Word *) data->d_buf; for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size; ++cnt) { Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]); @@ -185,6 +188,7 @@ dwarf_begin_elf (elf, cmd, scngrp) { GElf_Ehdr *ehdr; GElf_Ehdr ehdr_mem; + Dwarf *result; /* Get the ELF header of the file. We need various pieces of information from it. */ @@ -201,7 +205,7 @@ dwarf_begin_elf (elf, cmd, scngrp) /* Allocate the data structure. */ - Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf)); + result = (Dwarf *) calloc (1, sizeof (Dwarf)); if (result == NULL) { __libdwarf_seterrno (DWARF_E_NOMEM); @@ -235,7 +239,7 @@ dwarf_begin_elf (elf, cmd, scngrp) return NULL; } - __libdwarf_seterrno (DWARF_E_INVALIDCMD); + __libdwarf_seterrno (DWARF_E_INVALID_CMD); free (result); return NULL; } diff --git a/elfutils/libdw/dwarf_get_pubnames.c b/elfutils/libdw/dwarf_get_pubnames.c index 022e06de3..1bbcdadea 100644 --- a/elfutils/libdw/dwarf_get_pubnames.c +++ b/elfutils/libdw/dwarf_get_pubnames.c @@ -40,12 +40,17 @@ get_offsets (Dwarf *dbg) while (readp + 14 < endp) { + int len_bytes; + Dwarf_Off len; + uint16_t version; + unsigned char *infop; + /* If necessary, allocate more entries. */ if (cnt >= allocated) { + struct pubnames_s *newmem; allocated = MAX (10, 2 * allocated); - struct pubnames_s *newmem - = (struct pubnames_s *) realloc (mem, allocated * entsize); + newmem = (struct pubnames_s *) realloc (mem, allocated * entsize); if (newmem == NULL) { __libdwarf_seterrno (DWARF_E_NOMEM); @@ -58,8 +63,8 @@ get_offsets (Dwarf *dbg) } /* Read the set header. */ - int len_bytes = 4; - Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp); + len_bytes = 4; + len = read_4ubyte_unaligned_inc (dbg, readp); if (len == 0xffffffff) { len = read_8ubyte_unaligned_inc (dbg, readp); @@ -75,7 +80,7 @@ get_offsets (Dwarf *dbg) break; /* Read the version. It better be two for now. */ - uint16_t version = read_2ubyte_unaligned (dbg, readp); + version = read_2ubyte_unaligned (dbg, readp); if (version != 2) { __libdwarf_seterrno (DWARF_E_INVALID_VERSION); @@ -93,8 +98,7 @@ get_offsets (Dwarf *dbg) assert (dbg->sectiondata[IDX_debug_info]->d_buf != NULL); assert (mem[cnt].cu_offset + 3 < dbg->sectiondata[IDX_debug_info]->d_size); - unsigned char *infop - = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf + infop = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf + mem[cnt].cu_offset); if (read_4ubyte_unaligned_noncvt (infop) == 0xffffffff) mem[cnt].cu_header_size = 23; @@ -127,6 +131,10 @@ dwarf_get_pubnames (dbg, callback, arg, offset) void *arg; size_t offset; { + size_t cnt; + unsigned char *startp; + unsigned char *readp; + /* Make sure it is a valid offset. */ if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL || offset >= dbg->sectiondata[IDX_debug_pubnames]->d_size)) @@ -138,7 +146,6 @@ dwarf_get_pubnames (dbg, callback, arg, offset) return (size_t) -1; /* Find the place where to start. */ - size_t cnt; if (offset == 0) { cnt = 0; @@ -155,9 +162,8 @@ dwarf_get_pubnames (dbg, callback, arg, offset) assert (cnt + 1 < dbg->pubnames_nsets); } - unsigned char *startp - = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; - unsigned char *readp = startp + offset; + startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; + readp = startp + offset; while (1) { Dwarf_Global gl; diff --git a/elfutils/libebl/eblcorenote.c b/elfutils/libebl/eblcorenote.c index 54b68f727..5a246d27e 100644 --- a/elfutils/libebl/eblcorenote.c +++ b/elfutils/libebl/eblcorenote.c @@ -2,18 +2,15 @@ Copyright (C) 2002 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2002. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -44,10 +41,11 @@ ebl_core_note (ebl, name, type, descsz, desc) break; case NT_AUXV: - ; + { size_t cnt; size_t elsize = (class == ELFCLASS32 ? sizeof (Elf32_auxv_t) : sizeof (Elf64_auxv_t)); + const char *at; for (cnt = 0; (cnt + 1) * elsize <= descsz; ++cnt) { @@ -71,7 +69,6 @@ ebl_core_note (ebl, name, type, descsz, desc) /* XXX Do we need the auxiliary vector info anywhere else? If yes, move code into a separate function. */ - const char *at; switch (type) { @@ -145,6 +142,7 @@ ebl_core_note (ebl, name, type, descsz, desc) /* Reached the end. */ break; } + } break; default: diff --git a/elfutils/libebl/eblobjnote.c b/elfutils/libebl/eblobjnote.c index 816dd7443..87aadb753 100644 --- a/elfutils/libebl/eblobjnote.c +++ b/elfutils/libebl/eblobjnote.c @@ -2,18 +2,15 @@ Copyright (C) 2002 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2002. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -45,6 +42,7 @@ ebl_object_note (ebl, name, type, descsz, desc) uint32_t os; uint32_t version[descsz / 4 - 1]; } *tag = (__typeof (tag)) desc; + size_t cnt; const char *os; switch (tag->os) @@ -71,7 +69,6 @@ ebl_object_note (ebl, name, type, descsz, desc) } printf (gettext (" OS: %s, ABI: "), os); - size_t cnt; for (cnt = 0; cnt < descsz / 4 - 1; ++cnt) { if (cnt != 0) diff --git a/elfutils/libebl/eblopenbackend.c b/elfutils/libebl/eblopenbackend.c index be899db6c..ef195057f 100644 --- a/elfutils/libebl/eblopenbackend.c +++ b/elfutils/libebl/eblopenbackend.c @@ -1,27 +1,24 @@ /* Generate ELF backend handle. - Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2003 Red Hat, Inc. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <assert.h> +#include <dlfcn.h> #include <error.h> #include <gelf.h> -#include <ltdl.h> #include <stdlib.h> #include <string.h> @@ -41,46 +38,85 @@ static const struct int em; } machines[] = { - { "libebl_m32", "elf_m32", "m32", 3, EM_M32 }, - { "libebl_SPARC", "elf_sparc", "sparc", 5, EM_SPARC }, - { "libebl_i386", "elf_i386", "i386", 4, EM_386 }, - { "libebl_m68k", "elf_m68k", "m68k", 4, EM_68K }, - { "libebl_m88k", "elf_m88k", "m88k", 4, EM_88K }, - { "libebl_i860", "elf_i860", "i860", 4, EM_860 }, - { "libebl_mips", "elf_mips", "mips", 4, EM_MIPS }, - { "libebl_s370", "ebl_s370", "s370", 4, EM_S370 }, - { "libebl_mips", "elf_mipsel", "mips", 4, EM_MIPS_RS3_LE }, - { "libebl_parisc", "elf_parisc", "parisc", 6, EM_PARISC }, - { "libebl_vpp500", "elf_vpp500", "vpp500", 5, EM_VPP500 }, - { "libebl_v8plus", "elf_v8plus", "v8plus", 6, EM_SPARC32PLUS }, - { "libebl_i960", "elf_i960", "i960", 4, EM_960 }, - { "libebl_ppc", "elf_ppc", "ppc", 3, EM_PPC }, - { "libebl_ppc64", "elf_ppc64", "ppc64", 5, EM_PPC64 }, - { "libebl_s390", "ebl_s390", "s390", 4, EM_S390 }, - { "libebl_v800", "ebl_v800", "v800", 4, EM_V800 }, - { "libebl_fr20", "ebl_fr20", "fr20", 4, EM_FR20 }, - { "libebl_rh32", "ebl_rh32", "rh32", 4, EM_RH32 }, - { "libebl_rce", "ebl_rce", "rce", 3, EM_RCE }, - { "libebl_arm", "ebl_arm", "arm", 3, EM_ARM }, - { "libebl_sh", "elf_sh", "sh", 2, EM_SH }, - /* XXX Many more missing ... */ + { "i386", "elf_i386", "i386", 4, EM_386 }, + { "ia64", "elf_ia64", "ia64", 4, EM_IA_64 }, + { "alpha", "elf_alpha", "alpha", 5, EM_ALPHA }, + { "x86_64", "elf_x86_64", "x86_64", 6, EM_X86_64 }, + { "sh", "elf_sh", "sh", 2, EM_SH }, + { "arm", "ebl_arm", "arm", 3, EM_ARM }, + { "sparc", "elf_sparcv9", "sparc", 5, EM_SPARCV9 }, + { "sparc", "elf_sparc", "sparc", 5, EM_SPARC }, + { "sparc", "elf_sparcv8plus", "sparc", 5, EM_SPARC32PLUS }, + + { "m32", "elf_m32", "m32", 3, EM_M32 }, + { "m68k", "elf_m68k", "m68k", 4, EM_68K }, + { "m88k", "elf_m88k", "m88k", 4, EM_88K }, + { "i860", "elf_i860", "i860", 4, EM_860 }, + { "mips", "elf_mips", "mips", 4, EM_MIPS }, + { "s370", "ebl_s370", "s370", 4, EM_S370 }, + { "mips", "elf_mipsel", "mips", 4, EM_MIPS_RS3_LE }, + { "parisc", "elf_parisc", "parisc", 6, EM_PARISC }, + { "vpp500", "elf_vpp500", "vpp500", 5, EM_VPP500 }, + { "sparc", "elf_v8plus", "v8plus", 6, EM_SPARC32PLUS }, + { "i960", "elf_i960", "i960", 4, EM_960 }, + { "ppc", "elf_ppc", "ppc", 3, EM_PPC }, + { "ppc64", "elf_ppc64", "ppc64", 5, EM_PPC64 }, + { "s390", "ebl_s390", "s390", 4, EM_S390 }, + { "v800", "ebl_v800", "v800", 4, EM_V800 }, + { "fr20", "ebl_fr20", "fr20", 4, EM_FR20 }, + { "rh32", "ebl_rh32", "rh32", 4, EM_RH32 }, + { "rce", "ebl_rce", "rce", 3, EM_RCE }, + { "tricore", "elf_tricore", "tricore", 7, EM_TRICORE }, + { "arc", "elf_arc", "arc", 3, EM_ARC }, + { "h8", "elf_h8_300", "h8_300", 6, EM_H8_300 }, + { "h8", "elf_h8_300h", "h8_300h", 6, EM_H8_300H }, + { "h8", "elf_h8s", "h8s", 6, EM_H8S }, + { "h8", "elf_h8_500", "h8_500", 6, EM_H8_500 }, + { "mips_x", "elf_mips_x", "mips_x", 6, EM_MIPS_X }, + { "coldfire", "elf_coldfire", "coldfire", 8, EM_COLDFIRE }, + { "m68k", "elf_68hc12", "68hc12", 6, EM_68HC12 }, + { "mma", "elf_mma", "mma", 3, EM_MMA }, + { "pcp", "elf_pcp", "pcp", 3, EM_PCP }, + { "ncpu", "elf_ncpu", "ncpu", 4, EM_NCPU }, + { "ndr1", "elf_ndr1", "ndr1", 4, EM_NDR1 }, + { "starcore", "elf_starcore", "starcore", 8, EM_STARCORE }, + { "me16", "elf_me16", "em16", 4, EM_ME16 }, + { "st100", "elf_st100", "st100", 5, EM_ST100 }, + { "tinyj", "elf_tinyj", "tinyj", 5, EM_TINYJ }, + { "pdsp", "elf_pdsp", "pdsp", 4, EM_PDSP }, + { "fx66", "elf_fx66", "fx66", 4, EM_FX66 }, + { "st9plus", "elf_st9plus", "st9plus", 7, EM_ST9PLUS }, + { "st7", "elf_st7", "st7", 3, EM_ST7 }, + { "m68k", "elf_68hc16", "68hc16", 6, EM_68HC16 }, + { "m68k", "elf_68hc11", "68hc11", 6, EM_68HC11 }, + { "m68k", "elf_68hc08", "68hc08", 6, EM_68HC08 }, + { "m68k", "elf_68hc05", "68hc05", 6, EM_68HC05 }, + { "svx", "elf_svx", "svx", 3, EM_SVX }, + { "st19", "elf_st19", "st19", 4, EM_ST19 }, + { "vax", "elf_vax", "vax", 3, EM_VAX }, + { "cris", "elf_cris", "cris", 4, EM_CRIS }, + { "javelin", "elf_javelin", "javelin", 7, EM_JAVELIN }, + { "firepath", "elf_firepath", "firepath", 8, EM_FIREPATH }, + { "zsp", "elf_zsp", "zsp", 3, EM_ZSP}, + { "mmix", "elf_mmix", "mmix", 4, EM_MMIX }, + { "hunay", "elf_huany", "huany", 5, EM_HUANY }, + { "prism", "elf_prism", "prism", 5, EM_PRISM }, + { "avr", "elf_avr", "avr", 3, EM_AVR }, + { "fr30", "elf_fr30", "fr30", 4, EM_FR30 }, + { "dv10", "elf_dv10", "dv10", 4, EM_D10V }, + { "dv30", "elf_dv30", "dv30", 4, EM_D30V }, + { "v850", "elf_v850", "v850", 4, EM_V850 }, + { "m32r", "elf_m32r", "m32r", 4, EM_M32R }, + { "mn10300", "elf_mn10300", "mn10300", 7, EM_MN10300 }, + { "mn10200", "elf_mn10200", "mn10200", 7, EM_MN10200 }, + { "pj", "elf_pj", "pj", 2, EM_PJ }, + { "openrisc", "elf_openrisc", "openrisc", 8, EM_OPENRISC }, + { "arc", "elf_arc_a5", "arc_a5", 6, EM_ARC_A5 }, + { "xtensa", "elf_xtensa", "xtensa", 6, EM_XTENSA }, }; #define nmachines (sizeof (machines) / sizeof (machines[0])) -/* Initialize the ltdl library. */ -static void -dlinit (void) -{ - if (lt_dlinit () != 0) - error (EXIT_FAILURE, 0, _("initialization of libltdl failed")); - - /* Make sure we can find our modules. */ - /* XXX Use the correct path when done. */ - lt_dladdsearchdir (OBJDIR "/.libs"); -} - - /* Default callbacks. Mostly they just return the error value. */ static const char *default_object_type_name (int ignore, char *buf, size_t len); @@ -104,6 +140,15 @@ static bool default_dynamic_tag_check (int64_t ignore); static GElf_Word default_sh_flags_combine (GElf_Word flags1, GElf_Word flags2); static const char *default_osabi_name (int ignore, char *buf, size_t len); static void default_destr (struct ebl *ignore); +static const char *default_core_note_type_name (uint32_t, char *buf, + size_t len); +static const char *default_object_note_type_name (uint32_t, char *buf, + size_t len); +static bool default_core_note (const char *name, uint32_t type, + uint32_t descsz, const char *desc); +static bool default_object_note (const char *name, uint32_t type, + uint32_t descsz, const char *desc); +static bool default_debugscn_p (const char *name); /* Find an appropriate backend for the file associated with ELF. */ @@ -113,7 +158,6 @@ openbackend (elf, emulation, machine) const char *emulation; GElf_Half machine; { - once_define (static, once); Ebl *result; int cnt; @@ -128,9 +172,6 @@ openbackend (elf, emulation, machine) return NULL; } - /* We have to initialized the dynamic loading library. */ - once_execute (once, dlinit); - /* Fill in the default callbacks. The initializer for the machine specific module can overwrite the values. */ result->object_type_name = default_object_type_name; @@ -147,6 +188,11 @@ openbackend (elf, emulation, machine) result->dynamic_tag_check = default_dynamic_tag_check; result->sh_flags_combine = default_sh_flags_combine; result->osabi_name = default_osabi_name; + result->core_note_type_name = default_core_note_type_name; + result->object_note_type_name = default_object_note_type_name; + result->core_note = default_core_note; + result->object_note = default_object_note; + result->debugscn_p = default_debugscn_p; result->destr = default_destr; /* XXX Currently all we do is to look at 'e_machine' value in the @@ -162,11 +208,19 @@ openbackend (elf, emulation, machine) if ((emulation != NULL && strcmp (emulation, machines[cnt].emulation) == 0) || (emulation == NULL && machines[cnt].em == machine)) { + char dsoname[100]; + void *h; + + /* Well, we know the emulation name now. */ + result->emulation = machines[cnt].emulation; + /* Give it a try. At least the machine type matches. First try to load the module. */ - lt_dlhandle h; + strcpy (stpcpy (stpcpy (dsoname, "$ORIGIN/elfutils/libebl_"), + machines[cnt].dsoname), + ".so"); - h = lt_dlopenext (machines[cnt].dsoname); + h = dlopen (dsoname, RTLD_LAZY); if (h != NULL) { /* We managed to load the object. Now see whether the @@ -177,14 +231,13 @@ openbackend (elf, emulation, machine) strcpy (mempcpy (symname, machines[cnt].prefix, machines[cnt].prefix_len), "_init"); - initp = (ebl_bhinit_t) lt_dlsym (h, symname); + initp = (ebl_bhinit_t) dlsym (h, symname); if (initp != NULL && initp (elf, machine, result, sizeof (Ebl)) == 0) { /* We found a module to handle our file. */ result->dlhandle = h; result->elf = elf; - result->emulation = machines[cnt].emulation; /* A few entries are mandatory. */ assert (result->name != NULL); @@ -194,8 +247,16 @@ openbackend (elf, emulation, machine) } /* Not the module we need. */ - (void) lt_dlclose (h); + (void) dlclose (h); } + + /* We cannot find a DSO but the emulation/machine ID matches. + Return that information. */ + result->dlhandle = NULL; + result->elf = elf; + result->name = machines[cnt].prefix; + + return result; } /* Nothing matched. We use only the default callbacks. */ @@ -335,3 +396,72 @@ default_osabi_name (int ignore, char *buf, size_t len) { return NULL; } + +static const char * +default_core_note_type_name (uint32_t ignore, char *buf, size_t len) +{ + return NULL; +} + +static const char * +default_object_note_type_name (uint32_t ignore, char *buf, size_t len) +{ + return NULL; +} + +static bool +default_core_note (const char *name, uint32_t type, uint32_t descsz, + const char *desc) +{ + return false; +} + +static bool +default_object_note (const char *name, uint32_t type, uint32_t descsz, + const char *desc) +{ + return false; +} + +static bool +default_debugscn_p (const char *name) +{ + /* We know by default only about the DWARF debug sections which have + fixed names. */ + static const char *dwarf_scn_names[] = + { + /* DWARF 1 */ + ".debug", + ".line", + /* GNU DWARF 1 extensions */ + ".debug_srcinfo", + ".debug_sfnames", + /* DWARF 1.1 and DWARF 2 */ + ".debug_aranges", + ".debug_pubnames", + /* DWARF 2 */ + ".debug_info", + ".debug_abbrev", + ".debug_line", + ".debug_frame", + ".debug_str", + ".debug_loc", + ".debug_macinfo", + /* DWARF 3 */ + ".debug_ranges", + /* SGI/MIPS DWARF 2 extensions */ + ".debug_weaknames", + ".debug_funcnames", + ".debug_typenames", + ".debug_varnames" + }; + const size_t ndwarf_scn_names = (sizeof (dwarf_scn_names) + / sizeof (dwarf_scn_names[0])); + size_t cnt; + + for (cnt = 0; cnt < ndwarf_scn_names; ++cnt) + if (strcmp (name, dwarf_scn_names[cnt]) == 0) + return true; + + return false; +} diff --git a/elfutils/libebl/i386_corenote.c b/elfutils/libebl/i386_corenote.c index 55464057b..08de2821a 100644 --- a/elfutils/libebl/i386_corenote.c +++ b/elfutils/libebl/i386_corenote.c @@ -2,18 +2,15 @@ Copyright (C) 2002 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2002. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -62,7 +59,10 @@ struct elf_prpsinfo unsigned long int pr_flag; /* Flags. */ unsigned short int pr_uid; unsigned short int pr_gid; - int pr_pid, pr_ppid, pr_pgrp, pr_sid; + int pr_pid; + int pr_ppid; + int pr_pgrp; + int pr_sid; /* Lots missing */ char pr_fname[16]; /* Filename of executable. */ char pr_psargs[80]; /* Initial part of arg list. */ @@ -81,12 +81,12 @@ i386_core_note (name, type, descsz, desc) switch (type) { case NT_PRSTATUS: + { struct elf_prstatus *stat = (struct elf_prstatus *) desc; + if (descsz < sizeof (struct elf_prstatus)) /* Not enough data. */ break; - struct elf_prstatus *stat = (struct elf_prstatus *) desc; - printf (" SIGINFO: signo: %d, code = %d, errno = %d\n" " signal: %hd, pending: %#08lx, holding: %#08lx\n" " pid: %d, ppid = %d, pgrp = %d, sid = %d\n" @@ -104,10 +104,10 @@ i386_core_note (name, type, descsz, desc) stat->pr_cursig, stat->pr_sigpend, stat->pr_sighold, stat->pr_pid, stat->pr_ppid, stat->pr_pgrp, stat->pr_sid, - stat->pr_utime.tv_sec, stat->pr_utime.tv_usec, - stat->pr_stime.tv_sec, stat->pr_stime.tv_usec, - stat->pr_cutime.tv_sec, stat->pr_cutime.tv_usec, - stat->pr_cstime.tv_sec, stat->pr_cstime.tv_usec, + stat->pr_utime.tv_sec, (long int) stat->pr_utime.tv_usec, + stat->pr_stime.tv_sec, (long int) stat->pr_stime.tv_usec, + stat->pr_cutime.tv_sec, (long int) stat->pr_cutime.tv_usec, + stat->pr_cstime.tv_sec, (long int) stat->pr_cstime.tv_usec, stat->pr_reg[6], stat->pr_reg[0], stat->pr_reg[1], stat->pr_reg[2], stat->pr_reg[3], stat->pr_reg[4], stat->pr_reg[5], stat->pr_reg[15], stat->pr_reg[12], @@ -118,15 +118,15 @@ i386_core_note (name, type, descsz, desc) /* We handled this entry. */ result = true; - break; + } break; case NT_PRPSINFO: + { struct elf_prpsinfo *info = (struct elf_prpsinfo *) desc; + if (descsz < sizeof (struct elf_prpsinfo)) /* Not enough data. */ break; - struct elf_prpsinfo *info = (struct elf_prpsinfo *) desc; - printf (" state: %c (%hhd), zombie: %hhd, nice: %hhd\n" " flags: %08lx, uid: %hd, gid: %hd\n" " pid: %d, ppid: %d, pgrp: %d, sid: %d\n" @@ -139,7 +139,7 @@ i386_core_note (name, type, descsz, desc) /* We handled this entry. */ result = true; - break; + } break; default: break; diff --git a/elfutils/po/elfutils.pot b/elfutils/po/elfutils.pot index eb2c1da91..f330eaa7b 100644 --- a/elfutils/po/elfutils.pot +++ b/elfutils/po/elfutils.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2003-02-19 13:48-0800\n" +"POT-Creation-Date: 2003-03-05 15:25-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -170,15 +170,15 @@ msgstr "" msgid "%s%s%s: file format not recognized" msgstr "" -#: src/nm.c:792 src/nm.c:1174 src/readelf.c:661 src/readelf.c:791 +#: src/nm.c:791 src/nm.c:1173 src/readelf.c:661 src/readelf.c:791 #: src/readelf.c:875 src/readelf.c:1059 src/readelf.c:1279 src/readelf.c:1431 #: src/readelf.c:1605 src/readelf.c:1864 src/readelf.c:1941 src/readelf.c:2029 -#: src/readelf.c:2309 src/readelf.c:3726 src/size.c:424 src/size.c:498 -#: src/strip.c:428 +#: src/readelf.c:2309 src/readelf.c:3730 src/size.c:424 src/size.c:498 +#: src/strip.c:433 msgid "cannot get section header string table index" msgstr "" -#: src/nm.c:810 +#: src/nm.c:809 #, c-format msgid "" "\n" @@ -187,7 +187,7 @@ msgid "" "\n" msgstr "" -#: src/nm.c:812 +#: src/nm.c:811 #, c-format msgid "" "\n" @@ -196,29 +196,29 @@ msgid "" "\n" msgstr "" -#: src/nm.c:815 +#: src/nm.c:814 #, c-format msgid "" "%*s%-*s %-*s Class Type %-*s Line Section\n" "\n" msgstr "" -#: src/nm.c:1184 +#: src/nm.c:1183 #, c-format msgid "%s: entry size in section `%s' is not what we expect" msgstr "" -#: src/nm.c:1188 +#: src/nm.c:1187 #, c-format msgid "%s: size of section `%s' is not multiple of entry size" msgstr "" -#: src/nm.c:1288 +#: src/nm.c:1287 #, c-format msgid "%s%s%s%s: Invalid operation" msgstr "" -#: src/nm.c:1345 +#: src/nm.c:1344 #, c-format msgid "%s%s%s: no symbols" msgstr "" @@ -312,7 +312,7 @@ msgstr "" msgid "Not an ELF file - it has the wrong magic bytes at the start" msgstr "" -#: src/readelf.c:448 src/elflint.c:2021 +#: src/readelf.c:448 src/elflint.c:2028 #, c-format msgid "cannot read ELF header: %s" msgstr "" @@ -321,7 +321,7 @@ msgstr "" msgid "cannot create EBL handle" msgstr "" -#: src/readelf.c:462 src/strip.c:485 src/ldgeneric.c:575 src/ldgeneric.c:966 +#: src/readelf.c:462 src/strip.c:490 src/ldgeneric.c:575 src/ldgeneric.c:966 #, c-format msgid "cannot determine number of sections: %s" msgstr "" @@ -869,7 +869,7 @@ msgstr "" msgid "unknown form %<PRIx64>" msgstr "" -#: src/readelf.c:3113 +#: src/readelf.c:3114 #, c-format msgid "" "\n" @@ -877,50 +877,50 @@ msgid "" " [ Code]\n" msgstr "" -#: src/readelf.c:3136 +#: src/readelf.c:3137 #, c-format msgid " *** error while reading abbreviation: %s\n" msgstr "" -#: src/readelf.c:3147 +#: src/readelf.c:3148 #, c-format msgid " *** error while reading abbreviation code: %s\n" msgstr "" -#: src/readelf.c:3154 +#: src/readelf.c:3155 #, c-format msgid " *** error while reading abbreviation tag: %s\n" msgstr "" -#: src/readelf.c:3162 +#: src/readelf.c:3163 #, c-format msgid " *** error while reading abbreviation children flag: %s\n" msgstr "" -#: src/readelf.c:3168 +#: src/readelf.c:3169 #, c-format msgid " [%5<PRId64>] offset: %<PRId64>, children: %s, tag: %s\n" msgstr "" -#: src/readelf.c:3171 +#: src/readelf.c:3172 msgid "yes" msgstr "" -#: src/readelf.c:3171 +#: src/readelf.c:3172 msgid "no" msgstr "" -#: src/readelf.c:3186 +#: src/readelf.c:3187 #, c-format msgid " *** error while reading abbreviation entries: %s\n" msgstr "" -#: src/readelf.c:3210 +#: src/readelf.c:3211 #, c-format msgid "cannot get .debug_aranges content: %s" msgstr "" -#: src/readelf.c:3215 src/readelf.c:3648 +#: src/readelf.c:3216 src/readelf.c:3652 #, c-format msgid "" "\n" @@ -931,19 +931,19 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: src/readelf.c:3230 src/readelf.c:3663 +#: src/readelf.c:3231 src/readelf.c:3667 #, c-format msgid " [%5<PRId64>] ???\n" msgstr "" -#: src/readelf.c:3232 +#: src/readelf.c:3233 #, c-format msgid "" " [%5<PRId64>] start: %0#*<PRIx64>, length: %5<PRIu64>, CU DIE offset: %" "6<PRId64>\n" msgstr "" -#: src/readelf.c:3256 +#: src/readelf.c:3270 #, c-format msgid "" "\n" @@ -951,12 +951,12 @@ msgid "" " [Offset]\n" msgstr "" -#: src/readelf.c:3284 +#: src/readelf.c:3288 #, c-format msgid "cannot get CU header in section '%s': %s" msgstr "" -#: src/readelf.c:3289 +#: src/readelf.c:3293 #, c-format msgid "" " Compilation unit at offset %<PRIu64>:\n" @@ -964,70 +964,70 @@ msgid "" "<PRIu16>\n" msgstr "" -#: src/readelf.c:3301 +#: src/readelf.c:3305 #, c-format msgid "cannot get DIE at offset %<PRIu64> in section '%s': %s" msgstr "" -#: src/readelf.c:3311 +#: src/readelf.c:3372 #, c-format msgid "cannot get DIE offset: %s" msgstr "" -#: src/readelf.c:3319 +#: src/readelf.c:3379 #, c-format msgid "cannot get tag of DIE at offset %<PRIu64> in section '%s': %s" msgstr "" -#: src/readelf.c:3418 +#: src/readelf.c:3424 #, c-format msgid "cannot get attributes of DIE: %s" msgstr "" -#: src/readelf.c:3430 +#: src/readelf.c:3436 #, c-format msgid "cannot get attribute code: %s" msgstr "" -#: src/readelf.c:3438 +#: src/readelf.c:3443 #, c-format msgid "cannot get attribute form: %s" msgstr "" -#: src/readelf.c:3451 +#: src/readelf.c:3456 #, c-format msgid "cannot get attribute value: %s" msgstr "" -#: src/readelf.c:3579 +#: src/readelf.c:3583 #, c-format msgid "cannot get next DIE: %s\n" msgstr "" -#: src/readelf.c:3586 +#: src/readelf.c:3590 #, c-format msgid "cannot get next DIE: %s" msgstr "" -#: src/readelf.c:3614 src/readelf.c:3624 +#: src/readelf.c:3618 src/readelf.c:3628 #, c-format msgid "" "\n" "DWARF section '%s' at offset %#<PRIx64>:\n" msgstr "" -#: src/readelf.c:3643 +#: src/readelf.c:3647 #, c-format msgid "cannot get .debug_pubnames content: %s" msgstr "" -#: src/readelf.c:3665 +#: src/readelf.c:3669 #, c-format msgid "" " [%5<PRId64>] DIE offset: %6<PRId64>, CU DIE offset: %6<PRId64>, name: %s\n" msgstr "" -#: src/readelf.c:3687 +#: src/readelf.c:3691 #, c-format msgid "" "\n" @@ -1035,33 +1035,33 @@ msgid "" " [Offset] String\n" msgstr "" -#: src/readelf.c:3699 +#: src/readelf.c:3703 #, c-format msgid " *** error while reading strings: %s\n" msgstr "" -#: src/readelf.c:3718 +#: src/readelf.c:3722 #, c-format msgid "cannot get debug context descriptor: %s" msgstr "" -#: src/readelf.c:3792 +#: src/readelf.c:3799 #, c-format msgid "" "\n" "Note segment of %<PRId64> bytes at offset %#0*<PRIx64>:\n" msgstr "" -#: src/readelf.c:3799 +#: src/readelf.c:3806 #, c-format msgid "cannot get content of note section: %s" msgstr "" -#: src/readelf.c:3802 +#: src/readelf.c:3809 msgid " Owner Data size Type\n" msgstr "" -#: src/readelf.c:3841 +#: src/readelf.c:3848 #, c-format msgid " %-13.*s %9<PRId32> %s\n" msgstr "" @@ -1184,61 +1184,61 @@ msgstr "" msgid "cannot set access and modification date of \"%s\"" msgstr "" -#: src/strip.c:388 src/strip.c:414 +#: src/strip.c:394 src/strip.c:419 #, c-format msgid "cannot open `%s'" msgstr "" -#: src/strip.c:401 +#: src/strip.c:407 msgid "cannot open EBL backend" msgstr "" -#: src/strip.c:437 src/strip.c:463 +#: src/strip.c:442 src/strip.c:468 #, c-format msgid "cannot create new file `%s': %s" msgstr "" -#: src/strip.c:524 +#: src/strip.c:529 #, c-format msgid "illformed file `%s'" msgstr "" -#: src/strip.c:788 src/strip.c:873 +#: src/strip.c:793 src/strip.c:878 #, c-format msgid "while generating output file: %s" msgstr "" -#: src/strip.c:837 src/strip.c:1218 +#: src/strip.c:842 src/strip.c:1224 #, c-format msgid "%s: error while creating ELF header: %s" msgstr "" -#: src/strip.c:845 src/strip.c:1240 +#: src/strip.c:850 src/strip.c:1246 #, c-format msgid "while writing `%s': %s" msgstr "" -#: src/strip.c:860 +#: src/strip.c:865 #, c-format msgid "while preparing output for `%s'" msgstr "" -#: src/strip.c:914 src/strip.c:971 +#: src/strip.c:919 src/strip.c:976 #, c-format msgid "while create section header section: %s" msgstr "" -#: src/strip.c:920 +#: src/strip.c:925 #, c-format msgid "cannot allocate section data: %s" msgstr "" -#: src/strip.c:1226 +#: src/strip.c:1232 #, c-format msgid "%s: error while reading the file: %s" msgstr "" -#: src/strip.c:1254 src/strip.c:1261 +#: src/strip.c:1260 src/strip.c:1267 #, c-format msgid "error while finishing `%s': %s" msgstr "" @@ -2297,190 +2297,190 @@ msgstr "" msgid "section [%2d] '%s' is contained in more than one section group" msgstr "" -#: src/elflint.c:1563 +#: src/elflint.c:1565 msgid "cannot get section header of zeroth section" msgstr "" -#: src/elflint.c:1567 +#: src/elflint.c:1569 msgid "zeroth section has nonzero name" msgstr "" -#: src/elflint.c:1569 +#: src/elflint.c:1571 msgid "zeroth section has nonzero type" msgstr "" -#: src/elflint.c:1571 +#: src/elflint.c:1573 msgid "zeroth section has nonzero flags" msgstr "" -#: src/elflint.c:1573 +#: src/elflint.c:1575 msgid "zeroth section has nonzero address" msgstr "" -#: src/elflint.c:1575 +#: src/elflint.c:1577 msgid "zeroth section has nonzero offset" msgstr "" -#: src/elflint.c:1577 +#: src/elflint.c:1579 msgid "zeroth section has nonzero info field" msgstr "" -#: src/elflint.c:1579 +#: src/elflint.c:1581 msgid "zeroth section has nonzero align value" msgstr "" -#: src/elflint.c:1581 +#: src/elflint.c:1583 msgid "zeroth section has nonzero entry size value" msgstr "" -#: src/elflint.c:1584 +#: src/elflint.c:1586 msgid "" "zeroth section has nonzero size value while ELF header has nonzero shnum " "value" msgstr "" -#: src/elflint.c:1587 +#: src/elflint.c:1589 msgid "" "zeroth section has nonzero link value while ELF header does not signal " "overflow in shstrndx" msgstr "" -#: src/elflint.c:1598 +#: src/elflint.c:1601 #, c-format msgid "cannot get section header for section [%2d] '%s': %s" msgstr "" -#: src/elflint.c:1607 +#: src/elflint.c:1610 #, c-format msgid "section [%2d]: invalid name" msgstr "" -#: src/elflint.c:1622 +#: src/elflint.c:1625 #, c-format msgid "section [%2zd] '%s' has wrong type: expected %s, is %s" msgstr "" -#: src/elflint.c:1637 +#: src/elflint.c:1640 #, c-format msgid "section [%2d] '%s' has wrong flags: expected %s, is %s" msgstr "" -#: src/elflint.c:1655 +#: src/elflint.c:1658 #, c-format msgid "section [%2d] '%s' has wrong flags: expected %s and possibly %s, is %s" msgstr "" -#: src/elflint.c:1685 +#: src/elflint.c:1688 #, c-format msgid "" "section [%2d] '%s' has SHF_ALLOC flag set but there is no loadable segment" msgstr "" -#: src/elflint.c:1690 +#: src/elflint.c:1693 #, c-format msgid "" "section [%2d] '%s' has SHF_ALLOC flag not set but there are loadable segments" msgstr "" -#: src/elflint.c:1700 +#: src/elflint.c:1703 #, c-format msgid "section [%2d] '%s': size not multiple of entry size" msgstr "" -#: src/elflint.c:1705 +#: src/elflint.c:1708 msgid "cannot get section header" msgstr "" -#: src/elflint.c:1713 +#: src/elflint.c:1716 #, c-format msgid "unsupported section type %d" msgstr "" -#: src/elflint.c:1719 +#: src/elflint.c:1722 #, c-format msgid "section [%2d] '%s' contain unknown flag" msgstr "" -#: src/elflint.c:1722 +#: src/elflint.c:1725 #, c-format msgid "section [%2d] '%s': thread-local data sections not yet supported" msgstr "" -#: src/elflint.c:1727 +#: src/elflint.c:1730 #, c-format msgid "section [%2d] '%s': invalid section reference in link value" msgstr "" -#: src/elflint.c:1732 +#: src/elflint.c:1735 #, c-format msgid "section [%2d] '%s': invalid section reference in info value" msgstr "" -#: src/elflint.c:1739 +#: src/elflint.c:1742 #, c-format msgid "section [%2d] '%s': strings flag set without merge flag" msgstr "" -#: src/elflint.c:1744 +#: src/elflint.c:1747 #, c-format msgid "section [%2d] '%s': merge flag set but entry size is zero" msgstr "" -#: src/elflint.c:1752 +#: src/elflint.c:1755 #, c-format msgid "" "section [%2d] '%s': ELF header says this is the section header string table " "but type is not SHT_TYPE" msgstr "" -#: src/elflint.c:1798 +#: src/elflint.c:1801 msgid "INTERP program header entry but no .interp section" msgstr "" -#: src/elflint.c:1808 +#: src/elflint.c:1815 #, c-format msgid "phdr[%d]: no note entries defined for the type of file" msgstr "" -#: src/elflint.c:1890 +#: src/elflint.c:1897 #, c-format msgid "phdr[%d]: note entries probably in form of a 32-bit ELF file" msgstr "" -#: src/elflint.c:1893 +#: src/elflint.c:1900 #, c-format msgid "phdr[%d]: extra %zu bytes after last note" msgstr "" -#: src/elflint.c:1922 +#: src/elflint.c:1929 #, c-format msgid "phdr[%d]: unknown core file note type %<PRIu64> at offset %<PRIu64>" msgstr "" -#: src/elflint.c:1930 +#: src/elflint.c:1937 #, c-format msgid "phdr[%d]: unknown object file note type %<PRIu64> at offset %<PRIu64>" msgstr "" -#: src/elflint.c:1956 +#: src/elflint.c:1963 msgid "" "only executables, shared objects, and core files can have program headers" msgstr "" -#: src/elflint.c:1967 +#: src/elflint.c:1974 #, c-format msgid "cannot get program header entry %d: %s" msgstr "" -#: src/elflint.c:1973 +#: src/elflint.c:1980 #, c-format msgid "program header entry %d: unknown program header entry type" msgstr "" -#: src/elflint.c:1984 +#: src/elflint.c:1991 msgid "more than one INTERP entry in program header" msgstr "" -#: src/elflint.c:1993 +#: src/elflint.c:2000 msgid "more than one TLS entry in program header" msgstr "" diff --git a/elfutils/src/elflint.c b/elfutils/src/elflint.c index 09b0007a5..1f0e222d6 100644 --- a/elfutils/src/elflint.c +++ b/elfutils/src/elflint.c @@ -1,19 +1,16 @@ /* Pedantic checking of ELF files compliance with gABI/psABI spec. - Copyright (C) 2001, 2002 Red Hat, Inc. + Copyright (C) 2001, 2002, 2003 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2001. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -21,6 +18,8 @@ #include <argp.h> #include <assert.h> +#include <byteswap.h> +#include <endian.h> #include <error.h> #include <fcntl.h> #include <gelf.h> @@ -32,6 +31,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <sys/param.h> #include <elf-knowledge.h> #include <system.h> @@ -76,9 +76,9 @@ static struct argp argp = /* Declarations of local functions. */ static void process_file (int fd, Elf *elf, const char *prefix, - const char *fname, bool only_one); + const char *fname, size_t size, bool only_one); static void process_elf_file (Elf *elf, const char *prefix, const char *fname, - bool only_one); + size_t size, bool only_one); /* True if we should perform very strict testing. */ static bool be_strict; @@ -142,8 +142,16 @@ main (int argc, char *argv[]) else { int prev_error_message_count = error_message_count; + struct stat64 st; + + if (fstat64 (fd, &st) != 0) + { + printf ("cannot stat '%s': %m\n", argv[remaining]); + close (fd); + continue; + } - process_file (fd, elf, NULL, argv[remaining], only_one); + process_file (fd, elf, NULL, argv[remaining], st.st_size, only_one); /* Now we can close the descriptor. */ if (elf_end (elf) != 0) @@ -222,7 +230,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ /* Process one file. */ static void process_file (int fd, Elf *elf, const char *prefix, const char *fname, - bool only_one) + size_t size, bool only_one) { /* We can handle two types of files: ELF files and archives. */ Elf_Kind kind = elf_kind (elf); @@ -231,7 +239,7 @@ process_file (int fd, Elf *elf, const char *prefix, const char *fname, { case ELF_K_ELF: /* Yes! It's an ELF file. */ - process_elf_file (elf, prefix, fname, only_one); + process_elf_file (elf, prefix, fname, size, only_one); break; case ELF_K_AR: @@ -262,7 +270,8 @@ process_file (int fd, Elf *elf, const char *prefix, const char *fname, Elf_Arhdr *arhdr = elf_getarhdr (subelf); assert (arhdr != NULL); - process_file (fd, subelf, new_prefix, arhdr->ar_name, false); + process_file (fd, subelf, new_prefix, arhdr->ar_name, + arhdr->ar_size, false); } /* Get next archive element. */ @@ -305,7 +314,7 @@ static const int valid_e_machine[] = EM_H8_300H, EM_H8S, EM_H8_500, EM_IA_64, EM_MIPS_X, EM_COLDFIRE, EM_68HC12, EM_MMA, EM_PCP, EM_NCPU, EM_NDR1, EM_STARCORE, EM_ME16, EM_ST100, EM_TINYJ, EM_X86_64, EM_PDSP, EM_FX66, EM_ST9PLUS, EM_ST7, - EM_68HC16, EM_68HC11, EM_68HC08, EM_68HC05, EM_SVX, EM_AT19, EM_VAX, + EM_68HC16, EM_68HC11, EM_68HC08, EM_68HC05, EM_SVX, EM_ST19, EM_VAX, EM_CRIS, EM_JAVELIN, EM_FIREPATH, EM_ZSP, EM_MMIX, EM_HUANY, EM_PRISM, EM_AVR, EM_FR30, EM_D10V, EM_D30V, EM_V850, EM_M32R, EM_MN10300, EM_MN10200, EM_PJ, EM_OPENRISC, EM_ARC_A5, EM_XTENSA @@ -319,7 +328,7 @@ static int shnum; static void -check_elf_header (Ebl *ebl, GElf_Ehdr *ehdr) +check_elf_header (Ebl *ebl, GElf_Ehdr *ehdr, size_t size) { char buf[512]; int cnt; @@ -459,10 +468,14 @@ invalid number of section header table entries")); if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf32_Phdr)) error (0, 0, gettext ("invalid program header size: %hd"), ehdr->e_phentsize); + else if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > size) + error (0, 0, gettext ("invalid program header position or size")); if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf32_Shdr)) error (0, 0, gettext ("invalid section header size: %hd"), ehdr->e_shentsize); + else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) + error (0, 0, gettext ("invalid section header position or size")); } else if (gelf_getclass (ebl->elf) == ELFCLASS64) { @@ -472,10 +485,14 @@ invalid number of section header table entries")); if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf64_Phdr)) error (0, 0, gettext ("invalid program header size: %hd"), ehdr->e_phentsize); + else if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > size) + error (0, 0, gettext ("invalid program header position or size")); if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf64_Shdr)) error (0, 0, gettext ("invalid section header size: %hd"), ehdr->e_shentsize); + else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) + error (0, 0, gettext ("invalid section header position or size")); } } @@ -669,12 +686,12 @@ section [%2d] '%s': symbol %d: XINDEX used for index which would fit in st_shndx xndx); } else if ((sym->st_shndx >= SHN_LORESERVE - && sym->st_shndx <= SHN_HIRESERVE + // && sym->st_shndx <= SHN_HIRESERVE always true && sym->st_shndx != SHN_ABS && sym->st_shndx != SHN_COMMON) || (sym->st_shndx >= shnum && (sym->st_shndx < SHN_LORESERVE - || sym->st_shndx > SHN_HIRESERVE))) + /* || sym->st_shndx > SHN_HIRESERVE always false */))) error (0, 0, gettext ("\ section [%2d] '%s': symbol %d: invalid section index"), idx, section_name (ebl, ehdr, idx), cnt); @@ -705,11 +722,7 @@ section [%2d] '%s': symbol %d: st_value out of bounds"), if (GELF_ST_BIND (sym->st_info) == STB_LOCAL) { - if (shdr->sh_type == SHT_DYNSYM) - error (0, 0, gettext ("\ -section [%2d] '%s': symbol %d: dynamic symbol table contain local symbol"), - idx, section_name (ebl, ehdr, idx), cnt); - else if (cnt >= shdr->sh_info) + if (cnt >= shdr->sh_info) error (0, 0, gettext ("\ section [%2d] '%s': symbol %d: local symbol outside range described in sh_info"), idx, section_name (ebl, ehdr, idx), cnt); @@ -731,6 +744,9 @@ section [%2d] '%s': symbol %d: non-local section symbol"), } +#define REL_DYN_P(name) (strcmp (name, ".rel.dyn") == 0) + + static void check_rela (Ebl *ebl, GElf_Ehdr *ehdr, int idx) { @@ -767,7 +783,8 @@ check_rela (Ebl *ebl, GElf_Ehdr *ehdr, int idx) &destshdr_mem); if (destshdr != NULL && destshdr->sh_type != SHT_PROGBITS - && destshdr->sh_type != SHT_NOBITS) + && destshdr->sh_type != SHT_NOBITS + && ! REL_DYN_P (section_name (ebl, ehdr, idx))) error (0, 0, gettext ("\ section [%2d] '%s': invalid destination section type"), idx, section_name (ebl, ehdr, idx)); @@ -852,7 +869,8 @@ check_rel (Ebl *ebl, GElf_Ehdr *ehdr, int idx) &destshdr_mem); if (destshdr != NULL && destshdr->sh_type != SHT_PROGBITS - && destshdr->sh_type != SHT_NOBITS) + && destshdr->sh_type != SHT_NOBITS + && ! REL_DYN_P (section_name (ebl, ehdr, idx))) error (0, 0, gettext ("\ section [%2d] '%s': invalid destination section type"), idx, section_name (ebl, ehdr, idx)); @@ -945,6 +963,15 @@ check_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, int idx) [DT_RPATH] = true, [DT_SYMBOLIC] = true, [DT_TEXTREL] = true, [DT_BIND_NOW] = true }; + static const bool mandatory[DT_NUM] = + { + [DT_NULL] = true, + [DT_HASH] = true, + [DT_STRTAB] = true, + [DT_SYMTAB] = true, + [DT_STRSZ] = true, + [DT_SYMENT] = true + }; GElf_Addr reladdr = 0; GElf_Word relsz = 0; GElf_Addr pltreladdr = 0; @@ -1064,6 +1091,33 @@ section [%2d] '%s': contains %s entry but not %s"), ebl_dynamic_tag_name (ebl, inner, buf2, sizeof (buf2))); } } + else + { + if (mandatory[cnt]) + { + char buf[50]; + error (0, 0, gettext ("\ +section [%2d] '%s': mandatory tag %s not present"), + idx, section_name (ebl, ehdr, idx), + ebl_dynamic_tag_name (ebl, cnt, buf, sizeof (buf))); + } + } + + /* Check the rel/rela tags. At least one group must be available. */ + if ((has_dt[DT_RELA] || has_dt[DT_RELASZ] || has_dt[DT_RELAENT]) + && (!has_dt[DT_RELA] || !has_dt[DT_RELASZ] || !has_dt[DT_RELAENT])) + error (0, 0, gettext ("\ +section [%2d] '%s': not all of %s, %s, and %s are present"), + idx, section_name (ebl, ehdr, idx), + "DT_RELA", "DT_RELASZ", "DT_RELAENT"); + + if ((has_dt[DT_REL] || has_dt[DT_RELSZ] || has_dt[DT_RELENT]) + && (!has_dt[DT_REL] || !has_dt[DT_RELSZ] || !has_dt[DT_RELENT])) + error (0, 0, gettext ("\ +section [%2d] '%s': not all of %s, %s, and %s are present"), + idx, section_name (ebl, ehdr, idx), + "DT_REL", "DT_RELSZ", "DT_RELENT"); + } @@ -1384,7 +1438,108 @@ section [%2d] '%s' is contained in more than one section group"), } -static bool dot_interp_section; +static bool has_loadable_segment; +static bool has_interp_segment; + +static const struct +{ + const char *name; + size_t namelen; + int type; + enum { unused, exact, atleast } attrflag; + int attr; + int attr2; +} special_sections[] = + { + /* See figure 4-14 in the gABI. */ + { ".bss", 5, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".comment", 8, SHT_PROGBITS, exact, 0, 0 }, + { ".data", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".data1", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".debug", 7, SHT_PROGBITS, exact, 0, 0 }, + { ".dynamic", 9, SHT_DYNAMIC, atleast, SHF_ALLOC, SHF_WRITE }, + { ".dynstr", 8, SHT_STRTAB, exact, SHF_ALLOC, 0 }, + { ".dynsym", 8, SHT_DYNSYM, exact, SHF_ALLOC, 0 }, + { ".fini", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 }, + { ".fini_array", 12, SHT_FINI_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".got", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more info? + { ".hash", 6, SHT_HASH, exact, SHF_ALLOC, 0 }, + { ".init", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 }, + { ".init_array", 12, SHT_INIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".interp", 8, SHT_PROGBITS, atleast, 0, SHF_ALLOC }, // XXX more tests? + { ".line", 6, SHT_PROGBITS, exact, 0, 0 }, + { ".note", 6, SHT_NOTE, exact, 0, 0 }, + { ".plt", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more tests + { ".preinit_array", 15, SHT_PREINIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, + { ".rel", 4, SHT_REL, atleast, 0, SHF_ALLOC }, // XXX more tests + { ".rela", 5, SHT_RELA, atleast, 0, SHF_ALLOC }, // XXX more tests + { ".rodata", 8, SHT_PROGBITS, exact, SHF_ALLOC, 0 }, + { ".rodata1", 9, SHT_PROGBITS, exact, SHF_ALLOC, 0 }, + { ".shstrtab", 10, SHT_STRTAB, exact, 0, 0 }, + { ".strtab", 8, SHT_STRTAB, atleast, 0, SHF_ALLOC }, // XXX more tests + { ".symtab", 8, SHT_SYMTAB, atleast, 0, SHF_ALLOC }, // XXX more tests + { ".symtab_shndx", 14, SHT_SYMTAB_SHNDX, atleast, 0, SHF_ALLOC }, // XXX more tests + { ".tbss", 6, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, + { ".tdata", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, + { ".tdata1", 8, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, + { ".text", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 } + }; +#define nspecial_sections \ + (sizeof (special_sections) / sizeof (special_sections[0])) + + +static const char * +section_flags_string (GElf_Word flags, char *buf, size_t len) +{ + static const struct + { + GElf_Word flag; + const char *name; + } known_flags[] = + { +#define NEWFLAG(name) { SHF_##name, #name } + NEWFLAG (WRITE), + NEWFLAG (ALLOC), + NEWFLAG (EXECINSTR), + NEWFLAG (MERGE), + NEWFLAG (STRINGS), + NEWFLAG (INFO_LINK), + NEWFLAG (LINK_ORDER), + NEWFLAG (OS_NONCONFORMING), + NEWFLAG (GROUP), + NEWFLAG (TLS) + }; +#undef NEWFLAG + const size_t nknown_flags = sizeof (known_flags) / sizeof (known_flags[0]); + + char *cp = buf; + size_t cnt; + + for (cnt = 0; cnt < nknown_flags; ++cnt) + if (flags & known_flags[cnt].flag) + { + size_t ncopy; + + if (cp != buf && len > 1) + { + *cp++ = '|'; + --len; + } + + ncopy = MIN (len - 1, strlen (known_flags[cnt].name)); + cp = mempcpy (cp, known_flags[cnt].name, ncopy); + len -= ncopy; + + flags ^= known_flags[cnt].flag; + } + + if (flags != 0 || cp == buf) + snprintf (cp, len - 1, "%" PRIx64, (uint64_t) flags); + + *cp = '\0'; + + return buf; +} static void @@ -1393,6 +1548,7 @@ check_sections (Ebl *ebl, GElf_Ehdr *ehdr) GElf_Shdr shdr_mem; GElf_Shdr *shdr; int cnt; + bool dot_interp_section = false; /* Allocate array to count references in section groups. */ scnref = (int *) xcalloc (shnum, sizeof (int)); @@ -1436,6 +1592,7 @@ check_sections (Ebl *ebl, GElf_Ehdr *ehdr) for (cnt = 1; cnt < shnum; ++cnt) { Elf_Scn *scn; + const char *scnname; scn = elf_getscn (ebl->elf, cnt); shdr = gelf_getshdr (scn, &shdr_mem); @@ -1447,9 +1604,100 @@ cannot get section header for section [%2d] '%s': %s"), continue; } - if (strcmp (elf_strptr (ebl->elf, shstrndx, shdr->sh_name), ".interp") - == 0) - dot_interp_section = true; + scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name); + + if (scnname == NULL) + error (0, 0, gettext ("section [%2d]: invalid name"), cnt); + else + { + /* Check whether it is one of the special sections defined in + the gABI. */ + size_t s; + for (s = 0; s < nspecial_sections; ++s) + if (strncmp (scnname, special_sections[s].name, + special_sections[s].namelen) == 0) + { + char stbuf1[100]; + char stbuf2[100]; + char stbuf3[100]; + + if (shdr->sh_type != special_sections[s].type) + error (0, 0, gettext ("section [%2zd] '%s' has wrong type:" + " expected %s, is %s"), + s, scnname, + ebl_section_type_name (ebl, special_sections[s].type, + stbuf1, sizeof (stbuf1)), + ebl_section_type_name (ebl, shdr->sh_type, + stbuf2, sizeof (stbuf2))); + + if (special_sections[s].attrflag == exact) + { + /* Except for the link order and group bit all the + other bits should match exactly. */ + if ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP)) + != special_sections[s].attr) + error (0, 0, + gettext ("section [%2d] '%s' has wrong flags:" + " expected %s, is %s"), + cnt, scnname, + section_flags_string (special_sections[s].attr, + stbuf1, sizeof (stbuf1)), + section_flags_string (shdr->sh_flags + & ~SHF_LINK_ORDER, + stbuf2, sizeof (stbuf2))); + } + else if (special_sections[s].attrflag == atleast) + { + if ((shdr->sh_flags & special_sections[s].attr) + != special_sections[s].attr + || ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP + | special_sections[s].attr + | special_sections[s].attr2)) + != 0)) + error (0, 0, + gettext ("section [%2d] '%s' has wrong flags:" + " expected %s and possibly %s, is %s"), + cnt, scnname, + section_flags_string (special_sections[s].attr, + stbuf1, sizeof (stbuf1)), + section_flags_string (special_sections[s].attr2, + stbuf2, sizeof (stbuf2)), + section_flags_string (shdr->sh_flags + & ~(SHF_LINK_ORDER + | SHF_GROUP), + stbuf3, sizeof (stbuf3))); + } + + if (strcmp (scnname, ".interp") == 0) + dot_interp_section = true; + + if (strcmp (scnname, ".interp") == 0 + || strncmp (scnname, ".rel", 4) == 0 + || strcmp (scnname, ".strtab") == 0 + || strcmp (scnname, ".symtab") == 0 + || strcmp (scnname, ".symtab_shndx") == 0) + { + /* These sections must have the SHF_ALLOC flag set iff + a loadable segment is available. + + XXX These tests are no 100% correct since strtab, + symtab, etc only have to have the alloc bit set if + any loadable section is affected. */ + if ((shdr->sh_flags & SHF_ALLOC) != 0 + && !has_loadable_segment) + error (0, 0, gettext ("\ +section [%2d] '%s' has SHF_ALLOC flag set but there is no loadable segment"), + cnt, scnname); + else if ((shdr->sh_flags & SHF_ALLOC) == 0 + && has_loadable_segment) + error (0, 0, gettext ("\ +section [%2d] '%s' has SHF_ALLOC flag not set but there are loadable segments"), + cnt, scnname); + } + + break; + } + } if (shdr->sh_entsize != 0 && shdr->sh_size % shdr->sh_entsize) error (0, 0, gettext ("\ @@ -1547,27 +1795,173 @@ section [%2d] '%s': merge flag set but entry size is zero"), break; } } + + if (has_interp_segment && !dot_interp_section) + error (0, 0, + gettext ("INTERP program header entry but no .interp section")); } static void -check_program_header (Ebl *ebl, GElf_Ehdr *ehdr) +check_note (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Phdr *phdr, int cnt) { - int cnt; + char *notemem; + GElf_Xword align; + GElf_Xword idx; - if (ehdr->e_phoff == 0) + if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL + && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) + error (0, 0, + gettext ("phdr[%d]: no note entries defined for the type of file"), + cnt); + + notemem = gelf_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz); + + /* ELF64 files often use note section entries in the 32-bit format. + The p_align field is set to 8 in case the 64-bit format is used. + In case the p_align value is 0 or 4 the 32-bit format is + used. */ + align = phdr->p_align == 0 || phdr->p_align == 4 ? 4 : 8; +#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1)) + + idx = 0; + while (idx < phdr->p_filesz) { - /* No program header. */ - if (dot_interp_section) - error (0, 0, - gettext (".interp section present but no program header")); + uint64_t namesz; + uint64_t descsz; + uint64_t type; + uint32_t namesz32; + uint32_t descsz32; + + if (align == 4) + { + uint32_t *ptr = (uint32_t *) (notemem + idx); + + if ((__BYTE_ORDER == __LITTLE_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + || (__BYTE_ORDER == __BIG_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) + { + namesz32 = namesz = bswap_32 (*ptr); + ++ptr; + descsz32 = descsz = bswap_32 (*ptr); + ++ptr; + type = bswap_32 (*ptr); + } + else + { + namesz32 = namesz = *ptr++; + descsz32 = descsz = *ptr++; + type = *ptr; + } + } + else + { + uint64_t *ptr = (uint64_t *) (notemem + idx); + uint32_t *ptr32 = (uint32_t *) (notemem + idx); + + if ((__BYTE_ORDER == __LITTLE_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + || (__BYTE_ORDER == __BIG_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) + { + namesz = bswap_64 (*ptr); + ++ptr; + descsz = bswap_64 (*ptr); + ++ptr; + type = bswap_64 (*ptr); + + namesz32 = bswap_32 (*ptr32); + ++ptr32; + descsz32 = bswap_32 (*ptr32); + } + else + { + namesz = *ptr++; + descsz = *ptr++; + type = *ptr; + + namesz32 = *ptr32++; + descsz32 = *ptr32; + } + } + + if (idx + 3 * align > phdr->p_filesz + || (idx + 3 * align + ALIGNED_LEN (namesz) + ALIGNED_LEN (descsz) + > phdr->p_filesz)) + { + if (ehdr->e_ident[EI_CLASS] == ELFCLASS64 + && idx + 3 * 4 <= phdr->p_filesz + && (idx + 3 * 4 + ALIGNED_LEN (namesz32) + ALIGNED_LEN (descsz32) + <= phdr->p_filesz)) + error (0, 0, gettext ("\ +phdr[%d]: note entries probably in form of a 32-bit ELF file"), cnt); + else + error (0, 0, gettext ("phdr[%d]: extra %zu bytes after last note"), + cnt, (size_t) (phdr->p_filesz - idx)); + break; + } + + /* Make sure it is one of the note types we know about. */ + if (ehdr->e_type == ET_CORE) + { + switch (type) + { + case NT_PRSTATUS: + case NT_FPREGSET: + case NT_PRPSINFO: + case NT_TASKSTRUCT: /* NT_PRXREG on Solaris. */ + case NT_PLATFORM: + case NT_AUXV: + case NT_GWINDOWS: + case NT_ASRS: + case NT_PSTATUS: + case NT_PSINFO: + case NT_PRCRED: + case NT_UTSNAME: + case NT_LWPSTATUS: + case NT_LWPSINFO: + case NT_PRFPXREG: + /* Known type. */ + break; + + default: + error (0, 0, gettext ("\ +phdr[%d]: unknown core file note type %" PRIu64 " at offset %" PRIu64), + cnt, type, idx); + } + } + else + { + if (type != NT_VERSION) + error (0, 0, gettext ("\ +phdr[%d]: unknown object file note type %" PRIu64 " at offset %" PRIu64), + cnt, type, idx); + } + + /* Move to the next entry. */ + idx += 3 * align + ALIGNED_LEN (namesz) + ALIGNED_LEN (descsz); - return; } - if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) + gelf_freechunk (ebl->elf, notemem); +} + + +static void +check_program_header (Ebl *ebl, GElf_Ehdr *ehdr) +{ + int cnt; + int num_pt_interp = 0; + int num_pt_tls = 0; + + if (ehdr->e_phoff == 0) + return; + + if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN + && ehdr->e_type != ET_CORE) error (0, 0, gettext ("\ -only executables and shared objects can have program headers")); +only executables, shared objects, and core files can have program headers")); for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) { @@ -1582,14 +1976,31 @@ only executables and shared objects can have program headers")); continue; } - if (phdr->p_type >= PT_NUM) + if (phdr->p_type >= PT_NUM && phdr->p_type != PT_GNU_EH_FRAME) error (0, 0, gettext ("\ program header entry %d: unknown program header entry type"), cnt); - if (phdr->p_type == PT_INTERP && !dot_interp_section) - error (0, 0, - gettext ("INTERP program header entry but no .interp section")); + if (phdr->p_type == PT_LOAD) + has_loadable_segment = true; + else if (phdr->p_type == PT_INTERP) + { + if (++num_pt_interp != 1) + { + if (num_pt_interp == 2) + error (0, 0, gettext ("\ +more than one INTERP entry in program header")); + } + has_interp_segment = true; + } + else if (phdr->p_type == PT_TLS) + { + if (++num_pt_tls == 2) + error (0, 0, + gettext ("more than one TLS entry in program header")); + } + else if (phdr->p_type == PT_NOTE) + check_note (ebl, ehdr, phdr, cnt); } } @@ -1597,7 +2008,7 @@ program header entry %d: unknown program header entry type"), /* Process one file. */ static void process_elf_file (Elf *elf, const char *prefix, const char *fname, - bool only_one) + size_t size, bool only_one) { GElf_Ehdr ehdr_mem; GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); @@ -1624,12 +2035,12 @@ process_elf_file (Elf *elf, const char *prefix, const char *fname, is an error. */ /* Go straight by the gABI, check all the parts in turn. */ - check_elf_header (ebl, ehdr); + check_elf_header (ebl, ehdr, size); + + /* Check the program header. */ + check_program_header (ebl, ehdr); /* Next the section headers. It is OK if there are no section headers at all. */ check_sections (ebl, ehdr); - - /* Finally check the program header. */ - check_program_header (ebl, ehdr); } diff --git a/elfutils/src/nm.c b/elfutils/src/nm.c index 6e35028f7..069f408b4 100644 --- a/elfutils/src/nm.c +++ b/elfutils/src/nm.c @@ -1,27 +1,26 @@ /* Print information from ELF file in human-readable form. - Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2003 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2000. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif +#include <ar.h> #include <argp.h> #include <assert.h> #include <ctype.h> +#include <dwarf.h> #include <errno.h> #include <error.h> #include <fcntl.h> @@ -33,6 +32,7 @@ #include <locale.h> #include <mcheck.h> #include <search.h> +#include <stdbool.h> #include <stdio.h> #include <stdio_ext.h> #include <stdlib.h> @@ -61,17 +61,23 @@ static const struct argp_option options[] = { "dynamic", 'D', NULL, 0, N_("Display dynamic symbols instead of normal symbols") }, { "extern-only", 'g', NULL, 0, N_("Display only external symbols") }, { "undefined-only", 'u', NULL, 0, N_("Display only undefined symbols") }, + { "print-armap", 's', NULL, 0, + N_("Include index for symbols from archive members") }, + { NULL, 0, NULL, 0, N_("Output format:") }, { "print-file-name", 'A', NULL, 0, N_("Print name of the input file before every symbol") }, - { NULL, 'o', NULL, 0, N_("Same as -A") }, + { NULL, 'o', NULL, OPTION_HIDDEN, "Same as -A" }, { "format", 'f', "FORMAT", 0, N_("Use the output format FORMAT. FORMAT can be `bsd', `sysv' or `posix'. The default is `sysv'") }, { NULL, 'B', NULL, 0, N_("Same as --format=bsd") }, { "portability", 'P', NULL, 0, N_("Same as --format=posix") }, { "radix", 't', "RADIX", 0, N_("Use RADIX for printing symbol values") }, - { "mark-weak", OPT_MARK_WEAK, NULL, 0, N_("mark weak symbols") }, + { "mark-weak", OPT_MARK_WEAK, NULL, 0, N_("Mark weak symbols") }, + { "print-size", 'S', NULL, 0, N_("Print size of defined symbols") }, + { NULL, 0, NULL, 0, N_("Output options:") }, { "numeric-sort", 'n', NULL, 0, N_("Sort symbols numerically by address") }, { "no-sort", 'p', NULL, 0, N_("Do not sort the symbols") }, + { "reverse-sort", 'r', NULL, 0, N_("Reverse the sense of the sort") }, { NULL, 0, NULL, 0, N_("Miscellaneous:") }, { NULL, 0, NULL, 0, NULL } }; @@ -96,7 +102,7 @@ static struct argp argp = /* Print symbols in file named FNAME. */ -static int process_file (const char *fname); +static int process_file (const char *fname, bool more_than_one); /* Handle content of archive. */ static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, @@ -131,14 +137,23 @@ static enum } format; /* Print defined, undefined, or both? */ -static int hide_undefined; -static int hide_defined; +static bool hide_undefined; +static bool hide_defined; /* Print local symbols also? */ -static int hide_local; +static bool hide_local; /* Nonzero if full filename should precede every symbol. */ -static int print_file_name; +static bool print_file_name; + +/* If true print size of defined symbols in BSD format. */ +static bool print_size; + +/* If true print archive index. */ +static bool print_armap; + +/* If true reverse sorting. */ +static bool reverse_sort; /* Type of the section we are printing. */ static int symsec_type = SHT_SYMTAB; @@ -161,7 +176,7 @@ static enum /* If nonzero weak symbols are distinguished from global symbols by adding a `*' after the identifying letter for the symbol class and type. */ -static int mark_weak; +static bool mark_weak; int @@ -195,12 +210,16 @@ main (int argc, char *argv[]) if (remaining == argc) /* The user didn't specify a name so we use a.out. */ - result = process_file ("a.out"); + result = process_file ("a.out", false); else - /* Process all the remaining files. */ - do - result |= process_file (argv[remaining]); - while (++remaining < argc); + { + /* Process all the remaining files. */ + bool more_than_one = remaining + 1 < argc; + + do + result |= process_file (argv[remaining], more_than_one); + while (++remaining < argc); + } return result; } @@ -215,7 +234,7 @@ print_version (FILE *stream, struct argp_state *state) Copyright (C) %s Red Hat, Inc.\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ -"), "2002"); +"), "2003"); fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); } @@ -242,7 +261,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case 'g': - hide_local = 1; + hide_local = true; break; case 'n': @@ -263,13 +282,13 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case 'u': - hide_undefined = 0; - hide_defined = 1; + hide_undefined = false; + hide_defined = true; break; case 'A': case 'o': - print_file_name = 1; + print_file_name = true; break; case 'B': @@ -285,12 +304,24 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case OPT_DEFINED: - hide_undefined = 1; - hide_defined = 0; + hide_undefined = true; + hide_defined = false; break; case OPT_MARK_WEAK: - mark_weak = 1; + mark_weak = true; + break; + + case 'S': + print_size = true; + break; + + case 's': + print_armap = true; + break; + + case 'r': + reverse_sort = true; break; default: @@ -317,7 +348,7 @@ Report bugs to <drepper@redhat.com>.\n")); static int -process_file (const char *fname) +process_file (const char *fname, bool more_than_one) { /* Open the file and determine the type. */ int fd; @@ -337,7 +368,8 @@ process_file (const char *fname) { if (elf_kind (elf) == ELF_K_ELF) { - int result = handle_elf (elf, NULL, fname, NULL); + int result = handle_elf (elf, more_than_one ? "" : NULL, + fname, NULL); if (elf_end (elf) != 0) INTERNAL_ERROR (fname); @@ -389,12 +421,50 @@ handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, if (prefix != NULL) cp = stpcpy (cp, prefix); cp = stpcpy (cp, fname); - stpcpy (cp, "("); + stpcpy (cp, "["); cp = new_suffix; if (suffix != NULL) cp = stpcpy (cp, suffix); - stpcpy (cp, ")"); + stpcpy (cp, "]"); + + /* First print the archive index if this is wanted. */ + if (print_armap) + { + Elf_Arsym *arsym = elf_getarsym (elf, NULL); + + if (arsym != NULL) + { + Elf_Arhdr *arhdr = NULL; + size_t arhdr_off = 0; /* Note: 0 is no valid offset. */ + + puts (gettext("\nArchive index:")); + + while (arsym->as_off != 0) + { + if (arhdr_off != arsym->as_off + && (elf_rand (elf, arsym->as_off) != arsym->as_off + || (subelf = elf_begin (fd, cmd, elf)) == NULL + || (arhdr = elf_getarhdr (subelf)) == NULL)) + { + error (0, 0, gettext ("invalid offset %zu for symbol %s"), + arsym->as_off, arsym->as_name); + continue; + } + + printf (gettext ("%s in %s\n"), arsym->as_name, arhdr->ar_name); + + ++arsym; + } + + if (elf_rand (elf, SARMAG) != SARMAG) + { + error (0, 0, + gettext ("cannot reset archive offset to beginning")); + return 1; + } + } + } /* Process all the files contained in the archive. */ while ((subelf = elf_begin (fd, cmd, elf)) != NULL) @@ -402,16 +472,22 @@ handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, /* The the header for this element. */ Elf_Arhdr *arhdr = elf_getarhdr (subelf); - if (elf_kind (subelf) == ELF_K_ELF) - result |= handle_elf (subelf, new_prefix, arhdr->ar_name, new_suffix); - else if (elf_kind (subelf) == ELF_K_AR) - result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, - new_suffix); - else + /* Skip over the index entries. */ + if (strcmp (arhdr->ar_name, "/") != 0 + && strcmp (arhdr->ar_name, "//") != 0) { - error (0, 0, gettext ("%s%s%s: file format not recognized"), - new_prefix, arhdr->ar_name, new_suffix); - result = 1; + if (elf_kind (subelf) == ELF_K_ELF) + result |= handle_elf (subelf, new_prefix, arhdr->ar_name, + new_suffix); + else if (elf_kind (subelf) == ELF_K_AR) + result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, + new_suffix); + else + { + error (0, 0, gettext ("%s%s%s: file format not recognized"), + new_prefix, arhdr->ar_name, new_suffix); + result = 1; + } } /* Get next archive element. */ @@ -424,6 +500,172 @@ handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, } +struct local_name +{ + const char *name; + size_t lineno; + Dwarf_Addr lowpc; + Dwarf_Addr highpc; + char file[0]; +}; + + +static int +local_compare (const void *p1, const void *p2) +{ + struct local_name *g1 = (struct local_name *) p1; + struct local_name *g2 = (struct local_name *) p2; + int result; + + result = strcmp (g1->name, g2->name); + if (result == 0) + { + if (g1->lowpc <= g2->lowpc && g1->highpc >= g2->highpc) + { + /* g2 is contained in g1. Update the data. */ + g2->lowpc = g1->lowpc; + g2->highpc = g1->highpc; + result = 0; + } + else if (g2->lowpc <= g1->lowpc && g2->highpc >= g1->highpc) + { + /* g1 is contained in g2. Update the data. */ + g1->lowpc = g2->lowpc; + g1->highpc = g2->highpc; + result = 0; + } + else + result = g1->lowpc < g2->lowpc ? -1 : 1; + } + + return result; +} + + +static int +get_var_range (Dwarf_Die die, Dwarf_Unsigned *lowpc, Dwarf_Unsigned *highpc) +{ + Dwarf_Attribute loc; + Dwarf_Error err; + Dwarf_Locdesc *locdesc; + Dwarf_Signed len; + + if (dwarf_attr (die, DW_AT_location, &loc, &err) != DW_DLV_OK) + return 1; + + if (dwarf_loclist (loc, &locdesc, &len, &err) != DW_DLV_OK) + return 1; + + /* XXX incomplete. */ + return 1; +} + + +static void * +get_local_names (Ebl *ebl, Dwarf_Debug dbg) +{ + /* We iterate over the content of the .debug_info section. We only + look at the level immediately below the compile unit DIE. */ + int ret; + Dwarf_Error err; + Dwarf_Unsigned culen; + Dwarf_Unsigned nextcu; + Dwarf_Off offset = 0; + void *root = NULL; + + while ((ret = dwarf_next_cu_header (dbg, &culen, NULL, NULL, NULL, &nextcu, + &err)) == DW_DLV_OK) + { + Dwarf_Half tag; + Dwarf_Die die; + Dwarf_Die old = NULL; + char **files = NULL; + Dwarf_Signed nfiles; + + offset += culen; + + if (dwarf_offdie (dbg, offset, &die, &err) == DW_DLV_OK + /* This better be a compile unit DIE. */ + && dwarf_tag (die, &tag, &err) == DW_DLV_OK + && tag == DW_TAG_compile_unit + /* Get the source files for this compilation unit. */ + && dwarf_srcfiles (die, &files, &nfiles, &err) != DW_DLV_ERROR + /* Search all immediate children for subprogram and variable + DIEs. */ + && (old = die, dwarf_child (die, &die, &err) == DW_DLV_OK)) + do + { + dwarf_dealloc (dbg, old, DW_DLA_DIE); + + if (dwarf_tag (die, &tag, &err) == DW_DLV_OK + && (tag == DW_TAG_subprogram || tag == DW_TAG_variable)) + { + /* We are interested in five attributes: name, + decl_file, decl_line, low_pc, and high_pc. */ + Dwarf_Attribute name = NULL; + Dwarf_Attribute file = NULL; + Dwarf_Attribute line = NULL; + char *namestr; + Dwarf_Unsigned fileidx; + Dwarf_Unsigned lineno; + Dwarf_Addr lowpc; + Dwarf_Addr highpc; + + if (dwarf_attr (die, DW_AT_name, &name, &err) == DW_DLV_OK + && dwarf_formstring (name, &namestr, &err) == DW_DLV_OK + && (dwarf_attr (die, DW_AT_decl_file, &file, &err) + == DW_DLV_OK) + && dwarf_formudata (file, &fileidx, &err) == DW_DLV_OK + && fileidx > 0 && fileidx <= nfiles + && (dwarf_attr (die, DW_AT_decl_line, &line, &err) + == DW_DLV_OK) + && dwarf_formudata (line, &lineno, &err) == DW_DLV_OK + && lineno != 0 + && ((tag = DW_TAG_subprogram + && dwarf_lowpc (die, &lowpc, &err) == DW_DLV_OK + && dwarf_highpc (die, &highpc, &err) == DW_DLV_OK) + || (tag == DW_TAG_variable + && get_var_range (die, &lowpc, &highpc) == 0))) + { + struct local_name *newp; + size_t namelen = strlen (namestr) + 1; + const char *bfile = basename (files[fileidx - 1]); + size_t filelen = strlen (bfile) + 1; + + newp = xmalloc (sizeof (*newp) + namelen + filelen); + newp->name = memcpy (mempcpy (newp->file, bfile, filelen), + namestr, namelen); + newp->lineno = lineno; + newp->lowpc = lowpc; + newp->highpc = highpc; + + /* XXX Return value shouldn't be ignored. If the + new entry is not added to the tree the data + structure should be freed. */ + tsearch (newp, &root, local_compare); + } + + dwarf_dealloc (dbg, name, DW_DLA_ATTR); + dwarf_dealloc (dbg, file, DW_DLA_ATTR); + dwarf_dealloc (dbg, line, DW_DLA_ATTR); + } + + old = die; + } + while (dwarf_siblingof (dbg, die, &die, &err) == DW_DLV_OK); + + dwarf_dealloc (dbg, old, DW_DLA_DIE); + while (nfiles-- > 0) + dwarf_dealloc (dbg, files[nfiles], DW_DLA_STRING); + dwarf_dealloc (dbg, files, DW_DLA_LIST); + + offset = nextcu; + } + + return root; +} + + /* Mapping of radix and binary class to length. */ static const int length_map[2][3] = { @@ -459,6 +701,17 @@ global_compare (const void *p1, const void *p2) } +static void +free_global (void *p) +{ + struct global_name *g = (struct global_name *) p; + + free ((char *) g->name); + + free (p); +} + + /* Show symbols in SysV format. */ static void show_symbols_sysv (Ebl *ebl, GElf_Word strndx, @@ -472,14 +725,15 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, const char **scnnames; bool scnnames_malloced; const char *fmtstr; - uint32_t shstrndx; + size_t shstrndx; Dwarf_Debug dbg; Dwarf_Global *globals; Dwarf_Signed globcnt; Dwarf_Error err; const char *linenum; char linenumbuf[PATH_MAX + 10]; - void *root = NULL; + void *global_root = NULL; + void *local_root = NULL; if (elf_getshnum (ebl->elf, &shnum) < 0) INTERNAL_ERROR (fullname); @@ -513,12 +767,20 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, { newp->global = globals[cnt]; newp->name = name; - tsearch (newp, &root, global_compare); + /* XXX Return value shouldn't be ignored. If the + new entry is not added to the tree the data + structure should be freed. */ + tsearch (newp, &global_root, global_compare); } } } else globals = NULL; + + /* Try to get the local symbols which are not in the + .debug_pubnames section. */ + if (! hide_local) + local_root = get_local_names (ebl, dbg); } else dbg = NULL; @@ -535,7 +797,7 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, { GElf_Shdr shdr_mem; - assert (elf_ndxscn (scn) != cnt++); + assert (elf_ndxscn (scn) == cnt++); scnnames[elf_ndxscn (scn)] = elf_strptr (ebl->elf, shstrndx, @@ -543,8 +805,8 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, } /* We always print this prolog. */ - if (prefix == NULL) - printf (gettext ("\n\nSymbols from %s:\n\n"), fname); + if (prefix == NULL || 1) + printf (gettext ("\n\nSymbols from %s:\n\n"), fullname); else printf (gettext ("\n\nSymbols from %s[%s]:\n\n"), prefix, fname); @@ -582,17 +844,19 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, continue; linenum = ""; - if (root != NULL) + if (syms[cnt].sym.st_shndx != SHN_UNDEF + && GELF_ST_BIND (syms[cnt].sym.st_info) != STB_LOCAL + && global_root != NULL) { struct global_name fake; struct global_name **found; Dwarf_Off dieoff; Dwarf_Off cudieoff; - Dwarf_Die die; - Dwarf_Die cudie; + Dwarf_Die die = NULL; + Dwarf_Die cudie = NULL; fake.name = symstr; - found = tfind (&fake, &root, global_compare); + found = tfind (&fake, &global_root, global_compare); if (found != NULL && dwarf_global_name_offsets ((*found)->global, NULL, &dieoff, &cudieoff, &err) == DW_DLV_OK @@ -600,8 +864,9 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, && dwarf_offdie (dbg, cudieoff, &cudie, &err) == DW_DLV_OK) { Dwarf_Addr lowpc; - Dwarf_Line *lines; + Dwarf_Line *lines = NULL; Dwarf_Signed nlines; + int inner; if (dwarf_srclines (cudie, &lines, &nlines, &err) == DW_DLV_OK && dwarf_lowpc (die, &lowpc, &err) == DW_DLV_OK) @@ -609,7 +874,6 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, Dwarf_Addr addr; Dwarf_Unsigned lineno; char *linesrc; - int inner; for (inner = 1; inner < nlines; ++inner) if (dwarf_lineaddr (lines[inner], &addr, &err) != DW_DLV_OK @@ -628,13 +892,36 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, dwarf_dealloc (dbg, linesrc, DW_DLA_STRING); } + } + if (lines != NULL) + { for (inner = 0; inner < nlines; ++inner) dwarf_dealloc (dbg, lines[inner], DW_DLA_LINE); dwarf_dealloc (dbg, lines, DW_DLA_LIST); } + } + + dwarf_dealloc (dbg, die, DW_DLA_DIE); + dwarf_dealloc (dbg, cudie, DW_DLA_DIE); + } + + if (*linenum == '\0' + && *symstr != '\0' + && syms[cnt].sym.st_shndx != SHN_UNDEF + && local_root != NULL) + { + struct local_name fake; + struct local_name **found; - dwarf_dealloc (dbg, die, DW_DLA_DIE); + fake.name = symstr; + fake.lowpc = fake.highpc = syms[cnt].sym.st_value; + found = tfind (&fake, &local_root, local_compare); + if (found != NULL) + { + snprintf (linenumbuf, sizeof (linenumbuf), "%s:%" PRIu64, + (*found)->file, (uint64_t) (*found)->lineno); + linenum = linenumbuf; } } @@ -662,7 +949,8 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, if (dbg != NULL) { - tdestroy (root, free); + tdestroy (global_root, free_global); + tdestroy (local_root, free); if (globals != NULL) { @@ -708,17 +996,31 @@ show_symbols_bsd (Elf *elf, GElf_Ehdr *ehdr, GElf_Word strndx, { int digits = length_map[gelf_getclass (elf) - 1][radix]; const char *fmtstr; + const char *sfmtstr; + const char *ufmtstr; size_t cnt; if (prefix != NULL && ! print_file_name) printf ("\n%s:\n", fname); if (radix == radix_hex) - fmtstr = "%0*" PRIx64 " %c%s %s\n"; + { + fmtstr = "%0*" PRIx64 " %c%s %s\n"; + sfmtstr = "%2$0*1$" PRIx64 " %7$0*6$" PRIx64 " %3$c%4$s %5$s\n"; + ufmtstr = "%*s U%s %s\n"; + } else if (radix == radix_decimal) - fmtstr = "%*" PRId64 " %c%s %s\n"; + { + fmtstr = "%*" PRId64 " %c%s %s\n"; + sfmtstr = "%2$*1$" PRId64 " %7$*6$" PRId64 " %3$c%4$s %5$s\n"; + ufmtstr = "%*s U%s %s\n"; + } else - fmtstr = "%0*" PRIo64 " %c%s %s\n"; + { + fmtstr = "%0*" PRIo64 " %c%s %s\n"; + sfmtstr = "%2$0*1$" PRIo64 " %7$0*6$" PRIo64 " %3$c%4$s %5$s\n"; + ufmtstr = "%* U%s %s\n"; + } /* Iterate over all symbols. */ for (cnt = 0; cnt < nsyms; ++cnt) @@ -745,13 +1047,24 @@ show_symbols_bsd (Elf *elf, GElf_Ehdr *ehdr, GElf_Word strndx, putchar_unlocked (':'); } - printf (fmtstr, - digits, syms[cnt].sym.st_value, - class_type_char (&syms[cnt].sym), - mark_weak - ? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK ? "*" : " ") - : "", - elf_strptr (elf, strndx, syms[cnt].sym.st_name)); + if (syms[cnt].sym.st_shndx == SHN_UNDEF) + printf (ufmtstr, + digits, "", + mark_weak + ? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK + ? "*" : " ") + : "", + elf_strptr (elf, strndx, syms[cnt].sym.st_name)); + else + printf (print_size ? sfmtstr : fmtstr, + digits, syms[cnt].sym.st_value, + class_type_char (&syms[cnt].sym), + mark_weak + ? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK + ? "*" : " ") + : "", + elf_strptr (elf, strndx, syms[cnt].sym.st_name), + digits, (uint64_t) syms[cnt].sym.st_size); } } @@ -766,7 +1079,7 @@ show_symbols_posix (Elf *elf, GElf_Ehdr *ehdr, GElf_Word strndx, size_t cnt; if (prefix != NULL && ! print_file_name) - printf ("%s[%s]:\n", prefix, fname); + printf ("%s:\n", fullname); if (radix == radix_hex) fmtstr = "%s %c%s %0*" PRIx64 "\n"; @@ -798,6 +1111,7 @@ show_symbols_posix (Elf *elf, GElf_Ehdr *ehdr, GElf_Word strndx, { fputs_unlocked (fullname, stdout); putchar_unlocked (':'); + putchar_unlocked (' '); } printf (fmtstr, @@ -819,7 +1133,7 @@ show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, GElf_Shdr *shdr, const char *prefix, const char *fname, const char *fullname) { - uint32_t shstrndx; + size_t shstrndx; Elf_Data *data; Elf_Data *xndxdata; size_t size; @@ -833,18 +1147,24 @@ show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, { GElf_SymX *s1 = (GElf_SymX *) p1; GElf_SymX *s2 = (GElf_SymX *) p2; + int result; + + result = strcmp (elf_strptr (ebl->elf, shdr->sh_link, s1->sym.st_name), + elf_strptr (ebl->elf, shdr->sh_link, s2->sym.st_name)); - return strcmp (elf_strptr (ebl->elf, shdr->sh_link, s1->sym.st_name), - elf_strptr (ebl->elf, shdr->sh_link, s2->sym.st_name)); + return reverse_sort ? -result : result; } int sort_by_address (const void *p1, const void *p2) { GElf_SymX *s1 = (GElf_SymX *) p1; GElf_SymX *s2 = (GElf_SymX *) p2; + int result; + + result = (s1->sym.st_value < s2->sym.st_value + ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1)); - return (s1->sym.st_value < s2->sym.st_value - ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1)); + return reverse_sort ? -result : result; } /* Get the section header string table index. */ @@ -939,8 +1259,9 @@ handle_elf (Elf *elf, const char *prefix, const char *fname, const char *suffix) { size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); + size_t suffix_len = suffix == NULL ? 0 : strlen (suffix); size_t fname_len = strlen (fname) + 1; - char fullname[prefix_len + 1 + fname_len]; + char fullname[prefix_len + 1 + fname_len + suffix_len]; char *cp = fullname; Elf_Scn *scn = NULL; int any = 0; @@ -971,11 +1292,10 @@ handle_elf (Elf *elf, const char *prefix, const char *fname, /* Create the full name of the file. */ if (prefix != NULL) - { - cp = mempcpy (cp, prefix, prefix_len); - *cp++ = ':'; - } - memcpy (cp, fname, fname_len); + cp = mempcpy (cp, prefix, prefix_len); + cp = mempcpy (cp, fname, fname_len); + if (suffix != NULL) + memcpy (cp - 1, suffix, suffix_len + 1); /* Find the symbol table. diff --git a/elfutils/src/readelf.c b/elfutils/src/readelf.c index 5e2a5d66a..a7fe87e83 100644 --- a/elfutils/src/readelf.c +++ b/elfutils/src/readelf.c @@ -1,19 +1,16 @@ /* Print information from ELF file in human-readable form. - Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 1999. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -27,6 +24,7 @@ #include <fcntl.h> #include <gelf.h> #include <inttypes.h> +#include <langinfo.h> #include <libdwarf.h> #include <libebl.h> #include <libintl.h> @@ -38,6 +36,7 @@ #include <sys/param.h> #include <system.h> +#include "../libdwarf/libdwarfP.h" /* Name and version of program. */ @@ -61,6 +60,7 @@ static const struct argp_option options[] = { "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL, N_("Display DWARF section content. SECTION can be one of " "abbrev, aranges, frame, info, loc, line, pubnames, or str.") }, + { "notes", 'n', NULL, 0, N_("Display the core notes") }, { NULL, 0, NULL, 0, N_("Output control:") }, @@ -119,6 +119,9 @@ static bool print_section_groups; /* True if bucket list length histogram should be printed. */ static bool print_histogram; +/* True if note section content should be printed. */ +static bool print_notes; + /* Select printing of debugging sections. */ static enum section_e { @@ -166,6 +169,7 @@ static void handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr); static void print_debug (Ebl *ebl, GElf_Ehdr *ehdr); static void handle_hash (Ebl *ebl, GElf_Ehdr *ehdr); +static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr); int @@ -249,6 +253,7 @@ parse_opt (int key, char *arg, struct argp_state *state) print_dynamic_table = true; print_section_groups = true; print_histogram = true; + print_notes = true; any_control_option = true; break; case 'd': @@ -271,9 +276,13 @@ parse_opt (int key, char *arg, struct argp_state *state) print_program_header = true; any_control_option = true; break; + case 'n': + print_notes = true; + any_control_option = true; + break; case 'r': print_relocations = true; - any_control_option = true; + any_control_option = true; break; case 'S': print_section_header = true; @@ -340,7 +349,7 @@ print_version (FILE *stream, struct argp_state *state) Copyright (C) %s Red Hat, Inc.\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ -"), "2002"); +"), "2003"); fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); } @@ -475,6 +484,8 @@ process_elf_file (Elf *elf, const char *prefix, const char *fname, print_symtab (ebl, ehdr, SHT_SYMTAB); if (print_debug_sections != 0) print_debug (ebl, ehdr); + if (print_notes) + handle_notes (ebl, ehdr); ebl_closebackend (ebl); } @@ -547,8 +558,8 @@ print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr) ehdr->e_version, ehdr->e_version == EV_CURRENT ? gettext ("(current)") : "(\?\?\?)"); - fputs_unlocked (gettext (" Entry point address: "), stdout); - printf ("%#" PRIx64 "\n", ehdr->e_entry); + printf (gettext (" Entry point address: %#" PRIx64 "\n"), + ehdr->e_entry); printf (gettext (" Start of program headers: %" PRId64 " %s\n"), ehdr->e_phoff, gettext ("(bytes into file)")); @@ -636,7 +647,7 @@ static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr) { size_t cnt; - uint32_t shstrndx; + size_t shstrndx; if (! print_file_header) printf (gettext ("\ @@ -698,7 +709,7 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\ *cp++ = 'T'; *cp = '\0'; - printf ("[%2Zd] %-20s %-12s %0*" PRIx64 " %0*" PRIx64 " %0*" PRIx64 + printf ("[%2zu] %-20s %-12s %0*" PRIx64 " %0*" PRIx64 " %0*" PRIx64 " %2" PRId64 " %-5s %2" PRId32 " %3" PRId32 " %2" PRId64 "\n", cnt, @@ -721,7 +732,7 @@ static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr) { size_t cnt; - uint32_t shstrndx; + size_t shstrndx; if (ehdr->e_phnum == 0) /* No program header, this is OK in relocatable objects. */ @@ -788,7 +799,7 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr) size_t inner; /* Print the segment number. */ - printf (" %2.2Zd ", cnt); + printf (" %2.2zu ", cnt); /* This must not happen. */ if (phdr == NULL) @@ -845,7 +856,7 @@ handle_scngrp (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) Elf_Data *symdata; GElf_Sym sym_mem; size_t cnt; - uint32_t shstrndx; + size_t shstrndx; /* Get the data of the section. */ data = elf_getdata (scn, NULL); @@ -867,13 +878,13 @@ handle_scngrp (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) printf ((grpref[0] & GRP_COMDAT) ? ngettext ("\ -\nCOMDAT section group [%2d] '%s' with signature '%s' contains %zu entry:\n", +\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entry:\n", "\ -\nCOMDAT section group [%2d] '%s' with signature '%s' contains %zu entries:\n", +\nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entries:\n", data->d_size / sizeof (Elf32_Word) - 1) : ngettext ("\ -\nSection group [%2d] '%s' with signature '%s' contains %zu entry:\n", "\ -\nSection group [%2d] '%s' with signature '%s' contains %zu entries:\n", +\nSection group [%2zu] '%s' with signature '%s' contains %zu entry:\n", "\ +\nSection group [%2zu] '%s' with signature '%s' contains %zu entries:\n", data->d_size / sizeof (Elf32_Word) - 1), elf_ndxscn (scn), elf_strptr (ebl->elf, shstrndx, shdr->sh_name), @@ -891,9 +902,9 @@ handle_scngrp (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) &grpshdr_mem); if (grpshdr == NULL) - printf (gettext (" [%2d] <INVALID SECTION>\n"), grpref[cnt]); + printf (gettext (" [%2u] <INVALID SECTION>\n"), grpref[cnt]); else - printf (" [%2d] %s\n", + printf (" [%2u] %s\n", grpref[cnt], elf_strptr (ebl->elf, shstrndx, grpshdr->sh_name) ?: gettext ("<INVALID SECTION>")); @@ -1035,7 +1046,7 @@ handle_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) GElf_Shdr glink; Elf_Data *data; int cnt; - uint32_t shstrndx; + size_t shstrndx; /* Get the data of the section. */ data = elf_getdata (scn, NULL); @@ -1048,15 +1059,13 @@ handle_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) gettext ("cannot get section header string table index")); printf (ngettext ("\ -\nDynamic segment contains %lu entry:\n Addr: ", "\ -\nDynamic segment contains %lu entries:\n Addr: ", +\nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + "\ +\nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", shdr->sh_size / shdr->sh_entsize), - (unsigned long int) (shdr->sh_size / shdr->sh_entsize)); - printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, shdr->sh_addr); - fputs_unlocked (gettext (" Offset: "), stdout); - printf ("%#08" PRIx64, shdr->sh_offset); - fputs_unlocked (gettext (" Link to section: "), stdout); - printf ("[%2d] '%s'\n", + (unsigned long int) (shdr->sh_size / shdr->sh_entsize), + class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, + shdr->sh_offset, (int) shdr->sh_link, elf_strptr (ebl->elf, shstrndx, gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), @@ -1224,7 +1233,7 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) GElf_Shdr *destshdr; Elf_Scn *xndxscn; Elf_Data *xndxdata = NULL; - uint32_t shstrndx; + size_t shstrndx; /* Get the data of the section. */ data = elf_getdata (scn, NULL); @@ -1242,8 +1251,7 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) if (symshdr == NULL || symdata == NULL || destshdr == NULL) { - fputs_unlocked (gettext ("\nInvalid symbol table at offset "), stdout); - printf ("%#0*" PRIx64 "\n", + printf (gettext ("\nInvalid symbol table at offset %#0*" PRIx64 "\n"), class == ELFCLASS32 ? 10 : 18, shdr->sh_offset); return; } @@ -1270,15 +1278,17 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) error (EXIT_FAILURE, 0, gettext ("cannot get section header string table index")); - printf (gettext ("\ -\nRelocation section [%2d] '%s' for section [%2d] '%s' at offset "), - (int) elf_ndxscn (scn), + printf (ngettext ("\ +\nRelocation section [%2u] '%s' for section [%2u] '%s' at offset %#0*" PRIx64 " contains %d entry:\n", + "\ +\nRelocation section [%2u] '%s' for section [%2u] '%s' at offset %#0*" PRIx64 " contains %d entries:\n", + nentries), + (unsigned int) elf_ndxscn (scn), elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (int) shdr->sh_info, - elf_strptr (ebl->elf, shstrndx, destshdr->sh_name)); - printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, shdr->sh_offset); - printf (ngettext (" contains %d entry:\n", " contains %d entries:\n", - nentries), nentries); + (unsigned int) shdr->sh_info, + elf_strptr (ebl->elf, shstrndx, destshdr->sh_name), + class == ELFCLASS32 ? 10 : 18, shdr->sh_offset, + nentries); fputs_unlocked (class == ELFCLASS32 ? gettext ("\ Offset Type Value Name\n") @@ -1375,7 +1385,7 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) GElf_Shdr *destshdr; Elf_Scn *xndxscn; Elf_Data *xndxdata = NULL; - uint32_t shstrndx; + size_t shstrndx; /* Get the data of the section. */ data = elf_getdata (scn, NULL); @@ -1393,8 +1403,7 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) if (symshdr == NULL || symdata == NULL || destshdr == NULL) { - fputs_unlocked (gettext ("\nInvalid symbol table at offset "), stdout); - printf ("%#0*" PRIx64 "\n", + printf (gettext ("\nInvalid symbol table at offset %#0*" PRIx64 "\n"), class == ELFCLASS32 ? 10 : 18, shdr->sh_offset); return; } @@ -1421,14 +1430,16 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) error (EXIT_FAILURE, 0, gettext ("cannot get section header string table index")); - printf (gettext ("\ -\nRelocation section '%s' for section [%2d] '%s' at offset "), + printf (ngettext ("\ +\nRelocation section '%s' for section [%2u] '%s' at offset %#0*" PRIx64 " contains %d entry:\n", + "\ +\nRelocation section '%s' for section [%2u] '%s' at offset %#0*" PRIx64 " contains %d entries:\n", + nentries), elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (int) shdr->sh_info, - elf_strptr (ebl->elf, shstrndx, destshdr->sh_name)); - printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, shdr->sh_offset); - printf (ngettext (" contains %d entry:\n", " contains %d entries:\n", - nentries), nentries); + (unsigned int) shdr->sh_info, + elf_strptr (ebl->elf, shstrndx, destshdr->sh_name), + class == ELFCLASS32 ? 10 : 18, shdr->sh_offset, + nentries); fputs_unlocked (class == ELFCLASS32 ? gettext ("\ Offset Type Value Addend Name\n") @@ -1544,12 +1555,12 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) Elf_Scn *runscn; Elf_Data *data; int class = gelf_getclass (ebl->elf); - int nsyms; - int cnt; + unsigned int nsyms; + unsigned int cnt; Elf32_Word verneed_stridx = 0; Elf32_Word verdef_stridx = 0; GElf_Shdr glink; - uint32_t shstrndx; + size_t shstrndx; /* Get the data of the section. */ data = elf_getdata (scn, NULL); @@ -1597,15 +1608,16 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) nsyms = data->d_size / (class == ELFCLASS32 ? sizeof (Elf32_Sym) : sizeof (Elf64_Sym)); - printf (ngettext ("\nSymbol table [%2d] '%s' contains %d entry:\n", - "\nSymbol table [%2d] '%s' contains %d entries:\n", + printf (ngettext ("\nSymbol table [%2u] '%s' contains %u entry:\n", + "\nSymbol table [%2u] '%s' contains %u entries:\n", nsyms), - (int) elf_ndxscn (scn), + (unsigned int) elf_ndxscn (scn), elf_strptr (ebl->elf, shstrndx, shdr->sh_name), nsyms); - printf (ngettext (" %lu local symbol String table: [%2d] '%s'\n", - " %lu local symbols String table: [%2d] '%s'\n", + printf (ngettext (" %lu local symbol String table: [%2u] '%s'\n", + " %lu local symbols String table: [%2u] '%s'\n", shdr->sh_info), - (unsigned long int) shdr->sh_info, shdr->sh_link, + (unsigned long int) shdr->sh_info, + (unsigned int) shdr->sh_link, elf_strptr (ebl->elf, shstrndx, gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink)->sh_name)); @@ -1633,7 +1645,8 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) if (sym->st_shndx != SHN_XINDEX) xndx = sym->st_shndx; - printf ("%5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s", + printf (gettext ("\ +%5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"), cnt, class == ELFCLASS32 ? 8 : 16, sym->st_value, @@ -1715,10 +1728,10 @@ handle_symtab (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) if (vernaux != NULL) { - printf ("@%s (%d)", + printf ("@%s (%u)", elf_strptr (ebl->elf, verneed_stridx, vernaux->vna_name), - vernaux->vna_other); + (unsigned int) vernaux->vna_other); check_def = 0; } else if (! is_nobits) @@ -1838,7 +1851,7 @@ handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) GElf_Shdr glink; int cnt; unsigned int offset; - uint32_t shstrndx; + size_t shstrndx; /* Get the data of the section. */ data = elf_getdata (scn, NULL); @@ -1851,17 +1864,15 @@ handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) gettext ("cannot get section header string table index")); printf (ngettext ("\ -\nVersion needs section [%2d] '%s' contains %d entry:\n Addr: ", "\ -\nVersion needs section [%2d] '%s' contains %d entries:\n Addr: ", +\nVersion needs section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + "\ +\nVersion needs section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", shdr->sh_info), - (int) elf_ndxscn (scn), - elf_strptr (ebl->elf, shstrndx, shdr->sh_name), shdr->sh_info); - printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, shdr->sh_addr); - fputs_unlocked (gettext (" Offset: "), stdout); - printf ("%#08" PRIx64, shdr->sh_offset); - fputs_unlocked (gettext (" Link to section: "), stdout); - printf ("[%2d] '%s'\n", - (int) shdr->sh_link, + (unsigned int) elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), shdr->sh_info, + class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, + shdr->sh_offset, + (unsigned int) shdr->sh_link, elf_strptr (ebl->elf, shstrndx, gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink)->sh_name)); @@ -1879,10 +1890,10 @@ handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) if (need == NULL) break; - printf (gettext (" %#06x: Version: %hd File: %s Cnt: %hd\n"), - offset, need->vn_version, + printf (gettext (" %#06x: Version: %hu File: %s Cnt: %hu\n"), + offset, (unsigned short int) need->vn_version, elf_strptr (ebl->elf, shdr->sh_link, need->vn_file), - need->vn_cnt); + (unsigned short int) need->vn_cnt); auxoffset = offset + need->vn_aux; for (cnt2 = need->vn_cnt; --cnt2 >= 0; ) @@ -1894,10 +1905,11 @@ handle_verneed (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) if (aux == NULL) break; - printf (gettext (" %#06x: Name: %s Flags: %s Version: %hd\n"), + printf (gettext (" %#06x: Name: %s Flags: %s Version: %hu\n"), auxoffset, elf_strptr (ebl->elf, shdr->sh_link, aux->vna_name), - get_ver_flags (aux->vna_flags), aux->vna_other); + get_ver_flags (aux->vna_flags), + (unsigned short int) aux->vna_other); auxoffset += aux->vna_next; } @@ -1916,7 +1928,7 @@ handle_verdef (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) GElf_Shdr glink; int cnt; unsigned int offset; - uint32_t shstrndx; + size_t shstrndx; /* Get the data of the section. */ data = elf_getdata (scn, NULL); @@ -1929,18 +1941,16 @@ handle_verdef (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) gettext ("cannot get section header string table index")); printf (ngettext ("\ -\nVersion definition section [%2d] '%s' contains %d entry:\n Addr: ", "\ -\nVersion definition section [%2d] '%s' contains %d entries:\n Addr: ", +\nVersion definition section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + "\ +\nVersion definition section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", shdr->sh_info), - (int) elf_ndxscn (scn), + (unsigned int) elf_ndxscn (scn), elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - shdr->sh_info); - printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, shdr->sh_addr); - fputs_unlocked (gettext (" Offset: "), stdout); - printf ("%#08" PRIx64, shdr->sh_offset); - fputs_unlocked (gettext (" Link to section: "), stdout); - printf ("[%2d] '%s'\n", - (int) shdr->sh_link, + shdr->sh_info, + class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, + shdr->sh_offset, + (unsigned int) shdr->sh_link, elf_strptr (ebl->elf, shstrndx, gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink)->sh_name)); @@ -2006,7 +2016,7 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) const char **filename; size_t nvername; unsigned int cnt; - uint32_t shstrndx; + size_t shstrndx; /* Get the data of the section. */ data = elf_getdata (scn, NULL); @@ -2229,18 +2239,16 @@ handle_versym (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) /* Print the header. */ printf (ngettext ("\ -\nVersion symbols section [%2d] '%s' contains %d entry:\n Addr: ", "\ -\nVersion symbols section [%2d] '%s' contains %d entries:\n Addr: ", +\nVersion symbols section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'", + "\ +\nVersion symbols section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'", shdr->sh_size / shdr->sh_entsize), - (int) elf_ndxscn (scn), + (unsigned int) elf_ndxscn (scn), elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (int) (shdr->sh_size / shdr->sh_entsize)); - printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, shdr->sh_addr); - fputs_unlocked (gettext (" Offset: "), stdout); - printf ("%#08" PRIx64, shdr->sh_offset); - fputs_unlocked (gettext (" Link to section: "), stdout); - printf ("[%2d] '%s'", - (int) shdr->sh_link, + (int) (shdr->sh_size / shdr->sh_entsize), + class == ELFCLASS32 ? 10 : 18, shdr->sh_addr, + shdr->sh_offset, + (unsigned int) shdr->sh_link, elf_strptr (ebl->elf, shstrndx, gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink)->sh_name)); @@ -2293,7 +2301,7 @@ handle_hash (Ebl *ebl, GElf_Ehdr *ehdr) /* Find the symbol table(s). For this we have to search through the section table. */ Elf_Scn *scn = NULL; - uint32_t shstrndx; + size_t shstrndx; /* Get the section header string table index. */ if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) @@ -2334,20 +2342,17 @@ handle_hash (Ebl *ebl, GElf_Ehdr *ehdr) chain = &((Elf32_Word *) data->d_buf)[2 + nbucket]; printf (ngettext ("\ -\nHistogram for bucket list length in section [%2d] '%s' (total of %d bucket):\n Addr: ", "\ -\nHistogram for bucket list length in section [%2d] '%s' (total of %d buckets):\n Addr: ", +\nHistogram for bucket list length in section [%2u] '%s' (total of %d bucket):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", + "\ +\nHistogram for bucket list length in section [%2u] '%s' (total of %d buckets):\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 " Link to section: [%2u] '%s'\n", nbucket), - (int) elf_ndxscn (scn), + (unsigned int) elf_ndxscn (scn), elf_strptr (ebl->elf, shstrndx, shdr->sh_name), - (int) nbucket); - printf ("%#0*" PRIx64, + (int) nbucket, gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18, - shdr->sh_addr); - fputs_unlocked (gettext (" Offset: "), stdout); - printf ("%#08" PRIx64, shdr->sh_offset); - fputs_unlocked (gettext (" Link to section: "), stdout); - printf ("[%2d] '%s'\n", - (int) shdr->sh_link, + shdr->sh_addr, + shdr->sh_offset, + (unsigned int) shdr->sh_link, elf_strptr (ebl->elf, shstrndx, gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), @@ -2382,13 +2387,14 @@ handle_hash (Ebl *ebl, GElf_Ehdr *ehdr) Elf32_Word acc; puts (gettext (" Length Number % of total Coverage")); - printf (" 0 %6" PRIu32 " %5.1f%%\n", + printf (gettext (" 0 %6" PRIu32 " %5.1f%%\n"), counts[0], (counts[0] * 100.0) / nbucket); for (cnt = 1; cnt <= maxlength; ++cnt) { nzero_counts += counts[cnt] * cnt; - printf ("%7d %6" PRIu32 " %5.1f%% %5.1f%%\n", + printf (gettext ("\ +%7d %6" PRIu32 " %5.1f%% %5.1f%%\n"), (int) cnt, counts[cnt], (counts[cnt] * 100.0) / nbucket, (nzero_counts * 100.0) / nsyms); @@ -2739,9 +2745,369 @@ dwarf_form_string (Dwarf_Signed form) } +static const char * +dwarf_lang_string (unsigned int lang) +{ + static const char *known[] = + { + [DW_LANG_C89] = "ISO C89", + [DW_LANG_C] = "C", + [DW_LANG_Ada83] = "Ada83", + [DW_LANG_C_plus_plus ] = "C++", + [DW_LANG_Cobol74] = "Cobol74", + [DW_LANG_Cobol85] = "Cobol85", + [DW_LANG_Fortran77] = "Fortran77", + [DW_LANG_Fortran90] = "Fortran90", + [DW_LANG_Pascal83] = "Pascal83", + [DW_LANG_Modula2] = "Modula2", + [DW_LANG_Java] = "Java", + [DW_LANG_C99] = "ISO C99", + [DW_LANG_Ada95] = "Ada95", + [DW_LANG_Fortran95] = "Fortran95", + [DW_LANG_PL1] = "PL1" + }; + + if (lang < sizeof (known) / sizeof (known[0])) + return known[lang]; + else if (lang == DW_LANG_Mips_Assembler) + /* This language tag is used for assembler in general. */ + return "Assembler"; + + if (lang >= DW_LANG_lo_user && lang <= DW_LANG_hi_user) + { + static char buf[100]; + snprintf (buf, sizeof (buf), "lo_user+%u", lang - DW_LANG_lo_user); + return buf; + } + + return "???"; +} + + +static void +print_ops (Dwarf_Debug dbg, int level, Dwarf_Half addrsize, Dwarf_Unsigned len, + Dwarf_Ptr data) +{ + static const char *known[] = + { + [DW_OP_addr] = "addr", + [DW_OP_deref] = "deref", + [DW_OP_const1u] = "const1u", + [DW_OP_const1s] = "const1s", + [DW_OP_const2u] = "const2u", + [DW_OP_const2s] = "const2s", + [DW_OP_const4u] = "const4u", + [DW_OP_const4s] = "const4s", + [DW_OP_const8u] = "const8u", + [DW_OP_const8s] = "const8s", + [DW_OP_constu] = "constu", + [DW_OP_consts] = "consts", + [DW_OP_dup] = "dup", + [DW_OP_drop] = "drop", + [DW_OP_over] = "over", + [DW_OP_pick] = "pick", + [DW_OP_swap] = "swap", + [DW_OP_rot] = "rot", + [DW_OP_xderef] = "xderef", + [DW_OP_abs] = "abs", + [DW_OP_and] = "and", + [DW_OP_div] = "div", + [DW_OP_minus] = "minus", + [DW_OP_mod] = "mod", + [DW_OP_mul] = "mul", + [DW_OP_neg] = "neg", + [DW_OP_not] = "not", + [DW_OP_or] = "or", + [DW_OP_plus] = "plus", + [DW_OP_plus_uconst] = "plus_uconst", + [DW_OP_shl] = "shl", + [DW_OP_shr] = "shr", + [DW_OP_shra] = "shra", + [DW_OP_xor] = "xor", + [DW_OP_bra] = "bra", + [DW_OP_eq] = "eq", + [DW_OP_ge] = "ge", + [DW_OP_gt] = "gt", + [DW_OP_le] = "le", + [DW_OP_lt] = "lt", + [DW_OP_ne] = "ne", + [DW_OP_skip] = "skip", + [DW_OP_lit0] = "lit0", + [DW_OP_lit1] = "lit1", + [DW_OP_lit2] = "lit2", + [DW_OP_lit3] = "lit3", + [DW_OP_lit4] = "lit4", + [DW_OP_lit5] = "lit5", + [DW_OP_lit6] = "lit6", + [DW_OP_lit7] = "lit7", + [DW_OP_lit8] = "lit8", + [DW_OP_lit9] = "lit9", + [DW_OP_lit10] = "lit10", + [DW_OP_lit11] = "lit11", + [DW_OP_lit12] = "lit12", + [DW_OP_lit13] = "lit13", + [DW_OP_lit14] = "lit14", + [DW_OP_lit15] = "lit15", + [DW_OP_lit16] = "lit16", + [DW_OP_lit17] = "lit17", + [DW_OP_lit18] = "lit18", + [DW_OP_lit19] = "lit19", + [DW_OP_lit20] = "lit20", + [DW_OP_lit21] = "lit21", + [DW_OP_lit22] = "lit22", + [DW_OP_lit23] = "lit23", + [DW_OP_lit24] = "lit24", + [DW_OP_lit25] = "lit25", + [DW_OP_lit26] = "lit26", + [DW_OP_lit27] = "lit27", + [DW_OP_lit28] = "lit28", + [DW_OP_lit29] = "lit29", + [DW_OP_lit30] = "lit30", + [DW_OP_lit31] = "lit31", + [DW_OP_reg0] = "reg0", + [DW_OP_reg1] = "reg1", + [DW_OP_reg2] = "reg2", + [DW_OP_reg3] = "reg3", + [DW_OP_reg4] = "reg4", + [DW_OP_reg5] = "reg5", + [DW_OP_reg6] = "reg6", + [DW_OP_reg7] = "reg7", + [DW_OP_reg8] = "reg8", + [DW_OP_reg9] = "reg9", + [DW_OP_reg10] = "reg10", + [DW_OP_reg11] = "reg11", + [DW_OP_reg12] = "reg12", + [DW_OP_reg13] = "reg13", + [DW_OP_reg14] = "reg14", + [DW_OP_reg15] = "reg15", + [DW_OP_reg16] = "reg16", + [DW_OP_reg17] = "reg17", + [DW_OP_reg18] = "reg18", + [DW_OP_reg19] = "reg19", + [DW_OP_reg20] = "reg20", + [DW_OP_reg21] = "reg21", + [DW_OP_reg22] = "reg22", + [DW_OP_reg23] = "reg23", + [DW_OP_reg24] = "reg24", + [DW_OP_reg25] = "reg25", + [DW_OP_reg26] = "reg26", + [DW_OP_reg27] = "reg27", + [DW_OP_reg28] = "reg28", + [DW_OP_reg29] = "reg29", + [DW_OP_reg30] = "reg30", + [DW_OP_reg31] = "reg31", + [DW_OP_breg0] = "breg0", + [DW_OP_breg1] = "breg1", + [DW_OP_breg2] = "breg2", + [DW_OP_breg3] = "breg3", + [DW_OP_breg4] = "breg4", + [DW_OP_breg5] = "breg5", + [DW_OP_breg6] = "breg6", + [DW_OP_breg7] = "breg7", + [DW_OP_breg8] = "breg8", + [DW_OP_breg9] = "breg9", + [DW_OP_breg10] = "breg10", + [DW_OP_breg11] = "breg11", + [DW_OP_breg12] = "breg12", + [DW_OP_breg13] = "breg13", + [DW_OP_breg14] = "breg14", + [DW_OP_breg15] = "breg15", + [DW_OP_breg16] = "breg16", + [DW_OP_breg17] = "breg17", + [DW_OP_breg18] = "breg18", + [DW_OP_breg19] = "breg19", + [DW_OP_breg20] = "breg20", + [DW_OP_breg21] = "breg21", + [DW_OP_breg22] = "breg22", + [DW_OP_breg23] = "breg23", + [DW_OP_breg24] = "breg24", + [DW_OP_breg25] = "breg25", + [DW_OP_breg26] = "breg26", + [DW_OP_breg27] = "breg27", + [DW_OP_breg28] = "breg28", + [DW_OP_breg29] = "breg29", + [DW_OP_breg30] = "breg30", + [DW_OP_breg31] = "breg31", + [DW_OP_regx] = "regx", + [DW_OP_fbreg] = "fbreg", + [DW_OP_bregx] = "bregx", + [DW_OP_piece] = "piece", + [DW_OP_deref_size] = "deref_size", + [DW_OP_xderef_size] = "xderef_size", + [DW_OP_nop] = "nop", + [DW_OP_push_object_address] = "push_object_address", + [DW_OP_call2] = "call2", + [DW_OP_call4] = "call4", + [DW_OP_call_ref] = "call_ref", + }; + + Dwarf_Unsigned offset = 0; + while (len-- > 0) + { + size_t op = *((unsigned char *) data)++; + Dwarf_Unsigned addr; + Dwarf_Ptr start; + unsigned int sleb; + unsigned int uleb; + + switch (op) + { + case DW_OP_call_ref: + case DW_OP_addr:; + /* Address operand. */ + if (addrsize == 4) + addr = read_4ubyte_unaligned (dbg, data); + else + { + assert (addrsize == 8); + addr = read_8ubyte_unaligned (dbg, data); + } + data += addrsize; + len -= addrsize; + + printf (" %*s [%4" PRIuMAX "] %s %" PRIuMAX "\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", (uintmax_t) addr); + offset += 1 + addrsize; + break; + + case DW_OP_deref_size: /* XXX Correct? */ + case DW_OP_xderef_size: /* XXX Correct? */ + case DW_OP_pick: + case DW_OP_const1u: + printf (" %*s [%4" PRIuMAX "] %s %" PRIu8 "\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", *((uint8_t *) data)++); + --len; + offset += 2; + break; + + case DW_OP_const2u: + printf (" %*s [%4" PRIuMAX "] %s %" PRIu16 "\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", read_2ubyte_unaligned (dbg, data)); + len -= 2; + data += 2; + offset += 3; + break; + + case DW_OP_const4u: + printf (" %*s [%4" PRIuMAX "] %s %" PRIu32 "\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", read_4ubyte_unaligned (dbg, data)); + len -= 4; + data += 4; + offset += 5; + break; + + case DW_OP_const8u: + printf (" %*s [%4" PRIuMAX "] %s %" PRIu64 "\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", read_8ubyte_unaligned (dbg, data)); + len -= 8; + data += 8; + offset += 9; + break; + + case DW_OP_const1s: + printf (" %*s [%4" PRIuMAX "] %s %" PRId8 "\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", *((int8_t *) data)++); + --len; + offset += 2; + break; + + case DW_OP_const2s: + printf (" %*s [%4" PRIuMAX "] %s %" PRId16 "\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", read_2sbyte_unaligned (dbg, data)); + len -= 2; + data += 2; + offset += 3; + break; + + case DW_OP_const4s: + printf (" %*s [%4" PRIuMAX "] %s %" PRId32 "\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", read_4sbyte_unaligned (dbg, data)); + len -= 4; + data += 4; + offset += 5; + break; + + case DW_OP_const8s: + printf (" %*s [%4" PRIuMAX "] %s %" PRId64 "\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", read_8sbyte_unaligned (dbg, data)); + len -= 8; + data += 8; + offset += 9; + break; + + case DW_OP_piece: /* XXX Correct? */ + case DW_OP_regx: + case DW_OP_plus_uconst: + case DW_OP_constu:; + start = data; + get_uleb128 (uleb, ((unsigned char *) data)); + printf (" %*s [%4" PRIuMAX "] %s %u\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", uleb); + len -= data - start; + offset += 1 + (data - start); + break; + + case DW_OP_fbreg: + case DW_OP_breg0 ... DW_OP_breg31: + case DW_OP_consts:; + start = data; + get_sleb128 (sleb, ((unsigned char *) data)); + printf (" %*s [%4" PRIuMAX "] %s %d\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", sleb); + len -= data - start; + offset += 1 + (data - start); + break; + + case DW_OP_bregx: + start = data; + get_uleb128 (uleb, ((unsigned char *) data)); + get_sleb128 (sleb, ((unsigned char *) data)); + printf (" %*s [%4" PRIuMAX "] %s %u %d\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", uleb, sleb); + len -= data - start; + offset += 1 + (data - start); + break; + + case DW_OP_call2: + case DW_OP_call4: + case DW_OP_skip: + case DW_OP_bra: + printf (" %*s [%4" PRIuMAX "] %s %" PRIuMAX "\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???", + (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data))); + len -= 2; + data += 2; + offset += 3; + break; + + default: + /* No Operand. */ + printf (" %*s [%4" PRIuMAX "] %s\n", + (int) (20 + level * 2), "", (uintmax_t) offset, + known[op] ?: "???"); + ++offset; + break; + } + } +} + + static void -print_debug_abbrev_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, - Dwarf_Debug dbg) +print_debug_abbrev_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, + GElf_Shdr *shdr, Dwarf_Debug dbg) { Dwarf_Unsigned offset; @@ -2831,8 +3197,8 @@ print_debug_abbrev_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, not have to know a bit about the structure of the section, libdwarf takes care of it. */ static void -print_debug_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, - Dwarf_Debug dbg) +print_debug_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, + GElf_Shdr *shdr, Dwarf_Debug dbg) { Dwarf_Arange *aranges; Dwarf_Arange *runp; @@ -2878,25 +3244,376 @@ print_debug_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, static void -print_debug_frame_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, - Dwarf_Debug dbg) +print_debug_frame_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, + GElf_Shdr *shdr, Dwarf_Debug dbg) { } static void -print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, - Dwarf_Debug dbg) +print_debug_info_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, + GElf_Shdr *shdr, Dwarf_Debug dbg) { + Dwarf_Error err; + Dwarf_Off offset = 0; + size_t maxdies = 20; + Dwarf_Die *dies; + Dwarf_Unsigned culen; + Dwarf_Half version; + Dwarf_Unsigned abbroffset; + Dwarf_Half addrsize; + Dwarf_Unsigned nextcu; + int ret; + Dwarf_Off cu_offset; + int level; + printf (gettext ("\ -\nDWARF section '%s' at offset %#" PRIx64 ":\n"), +\nDWARF section '%s' at offset %#" PRIx64 ":\n [Offset]\n"), ".debug_info", (uint64_t) shdr->sh_offset); + + /* If the section is empty we don't have to do anything. */ + if (shdr->sh_size == 0) + return; + + dies = (Dwarf_Die *) xmalloc (maxdies * sizeof (Dwarf_Die)); + + /* New compilation unit. */ + next_cu: + ret = dwarf_next_cu_header (dbg, &culen, &version, &abbroffset, &addrsize, + &nextcu, &err); + if (ret == DW_DLV_NO_ENTRY) + return; + if (unlikely (ret != DW_DLV_OK)) + { + error (0, 0, gettext ("cannot get CU header in section '%s': %s"), + ".debug_info", dwarf_errmsg (err)); + return; + } + + printf (gettext (" Compilation unit at offset %" PRIu64 ":\n" + " Version: %" PRIu16 ", Abbreviation section offset: %" + PRIu64 ", Address size: %" PRIu16 "\n"), + offset, version, abbroffset, addrsize); + + cu_offset = offset; + offset += culen; + + level = 0; + + if (unlikely (dwarf_offdie (dbg, offset, &dies[level], &err) != DW_DLV_OK)) + { + error (0, 0, gettext ("cannot get DIE at offset %" PRIu64 + " in section '%s': %s"), + (uint64_t) offset, ".debug_info", dwarf_errmsg (err)); + return; + } + + do + { + Dwarf_Half tag; + static const char *const lowtags[] = + { + [DW_TAG_array_type] = "array_type", + [DW_TAG_class_type] = "class_type", + [DW_TAG_entry_point] = "entry_point", + [DW_TAG_enumeration_type] = "enumeration_type", + [DW_TAG_formal_parameter] = "formal_parameter", + [DW_TAG_imported_declaration] = "imported_declaration", + [DW_TAG_label] = "label", + [DW_TAG_lexical_block] = "lexical_block", + [DW_TAG_member] = "member", + [DW_TAG_pointer_type] = "pointer_type", + [DW_TAG_reference_type] = "reference_type", + [DW_TAG_compile_unit] = "compile_unit", + [DW_TAG_string_type] = "string_type", + [DW_TAG_structure_type] = "structure_type", + [DW_TAG_subroutine_type] = "subroutine_type", + [DW_TAG_typedef] = "typedef", + [DW_TAG_union_type] = "union_type", + [DW_TAG_unspecified_parameters] = "unspecified_parameters", + [DW_TAG_variant] = "variant", + [DW_TAG_common_block] = "common_block", + [DW_TAG_common_inclusion] = "common_inclusion", + [DW_TAG_inheritance] = "inheritance", + [DW_TAG_inlined_subroutine] = "inlined_subroutine", + [DW_TAG_module] = "module", + [DW_TAG_ptr_to_member_type] = "ptr_to_member_type", + [DW_TAG_set_type] = "set_type", + [DW_TAG_subrange_type] = "subrange_type", + [DW_TAG_with_stmt] = "with_stmt", + [DW_TAG_access_declaration] = "access_declaration", + [DW_TAG_base_type] = "base_type", + [DW_TAG_catch_block] = "catch_block", + [DW_TAG_const_type] = "const_type", + [DW_TAG_constant] = "constant", + [DW_TAG_enumerator] = "enumerator", + [DW_TAG_file_type] = "file_type", + [DW_TAG_friend] = "friend", + [DW_TAG_namelist] = "namelist", + [DW_TAG_namelist_item] = "namelist_item", + [DW_TAG_packed_type] = "packed_type", + [DW_TAG_subprogram] = "subprogram", + [DW_TAG_template_type_param] = "template_type_param", + [DW_TAG_template_value_param] = "template_value_param", + [DW_TAG_thrown_type] = "thrown_type", + [DW_TAG_try_block] = "try_block", + [DW_TAG_variant_part] = "variant_part", + [DW_TAG_variable] = "variable", + [DW_TAG_volatile_type] = "volatile_type" + }; + const char *tagstr; + Dwarf_Attribute *attrs; + Dwarf_Signed nattrs; + size_t cnt; + Dwarf_Die child; + + if (unlikely (dwarf_dieoffset (dies[level], &offset, &err) != DW_DLV_OK)) + { + error (0, 0, gettext ("cannot get DIE offset: %s"), + dwarf_errmsg (err)); + return; + } + + if (unlikely (dwarf_tag (dies[level], &tag, &err) != DW_DLV_OK)) + { + error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64 + " in section '%s': %s"), + (uint64_t) offset, ".debug_info", dwarf_errmsg (err)); + return; + } + + switch (tag) + { + case DW_TAG_lo_user: + tagstr = "lo_user"; + break; + + case DW_TAG_MIPS_loop: + tagstr = "MIPS_loop"; + break; + + case DW_TAG_format_label: + tagstr = "format_label"; + break; + + case DW_TAG_function_template: + tagstr = "function_template"; + break; + + case DW_TAG_class_template: + tagstr = "class_template"; + break; + case DW_TAG_hi_user: + tagstr = "hi_user"; + break; + + default: + if (tag < sizeof (lowtags) / sizeof (lowtags[0])) + tagstr = lowtags[tag]; + else + tagstr = "???"; + break; + } + + printf (" [%6" PRIx64 "] %*s%s\n", + (uint64_t) offset, (int) (level * 2), "", tagstr); + + if (unlikely (dwarf_attrlist (dies[level], &attrs, &nattrs, &err) + == DW_DLV_ERROR)) + { + error (0, 0, gettext ("cannot get attributes of DIE: %s"), + dwarf_errmsg (err)); + return; + } + + for (cnt = 0; cnt < nattrs; ++cnt) + { + Dwarf_Half attr; + Dwarf_Half form; + + if (unlikely (dwarf_whatattr (attrs[cnt], &attr, &err) != DW_DLV_OK)) + { + error (0, 0, gettext ("cannot get attribute code: %s"), + dwarf_errmsg (err)); + return; + } + + if (unlikely (dwarf_whatform (attrs[cnt], &form, &err) != DW_DLV_OK)) + { + error (0, 0, gettext ("cannot get attribute form: %s"), + dwarf_errmsg (err)); + return; + } + + switch (form) + { + case DW_FORM_addr:; + { Dwarf_Addr addr; + if (unlikely (dwarf_formaddr (attrs[cnt], &addr, &err) + != DW_DLV_OK)) + { + attrval_out: + error (0, 0, gettext ("cannot get attribute value: %s"), + dwarf_errmsg (err)); + return; + } + printf (" %*s%-20s %#0*" PRIxMAX "\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (int) (addrsize * 2), (uintmax_t) addr); + } break; + + case DW_FORM_indirect: + case DW_FORM_strp: + case DW_FORM_string:; + { char *str; + if (unlikely (dwarf_formstring (attrs[cnt], &str, &err) + != DW_DLV_OK)) + goto attrval_out; + printf (" %*s%-20s \"%s\"\n", + (int) (level * 2), "", dwarf_attr_string (attr), str); + } break; + + case DW_FORM_ref_addr: + case DW_FORM_ref_udata: + case DW_FORM_ref8: + case DW_FORM_ref4: + case DW_FORM_ref2: + case DW_FORM_ref1:; + { Dwarf_Off ref; + if (unlikely (dwarf_formref (attrs[cnt], &ref, &err) + != DW_DLV_OK)) + goto attrval_out; + + printf (" %*s%-20s [%6" PRIxMAX "]\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (uintmax_t) (ref + cu_offset)); + } break; + + case DW_FORM_udata: + case DW_FORM_sdata: + case DW_FORM_data8: + case DW_FORM_data4: + case DW_FORM_data2: + case DW_FORM_data1:; + { Dwarf_Unsigned num; + if (unlikely (dwarf_formudata (attrs[cnt], &num, &err) + != DW_DLV_OK)) + goto attrval_out; + + if (attr == DW_AT_language) + { + + printf (" %*s%-20s %s (%d)\n", + (int) (level * 2), "", dwarf_attr_string (attr), + dwarf_lang_string (num), (int) num); + break; + } + + printf (" %*s%-20s %" PRIuMAX "\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (uintmax_t) num); + } break; + + case DW_FORM_flag:; + { Dwarf_Bool flag; + if (unlikely (dwarf_formflag (attrs[cnt], &flag, &err) + != DW_DLV_OK)) + goto attrval_out; + + printf (" %*s%-20s %s\n", + (int) (level * 2), "", dwarf_attr_string (attr), + nl_langinfo (flag ? YESSTR : NOSTR)); + } break; + + case DW_FORM_block4: + case DW_FORM_block2: + case DW_FORM_block1: + case DW_FORM_block:; + { Dwarf_Block *block; + if (unlikely (dwarf_formblock (attrs[cnt], &block, &err) + != DW_DLV_OK)) + goto attrval_out; + + printf (" %*s%-20s %" PRIxMAX " byte block\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (uintmax_t) block->bl_len); + + if (attr == DW_AT_data_member_location) + print_ops (dbg, level, addrsize, block->bl_len, + block->bl_data); + + dwarf_dealloc (dbg, block, DW_DLA_BLOCK); + } break; + + default: + printf (" %*s%-20s [form: %d] ???\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (int) form); + break; + } + + + /* We don't free the attribute since we got passed a + reference to the internal object. */ + } + + dwarf_dealloc (dbg, attrs, DW_DLA_LIST); + + + ret = dwarf_child (dies[level], &child, &err); + if (ret == DW_DLV_NO_ENTRY) + { + Dwarf_Die old = dies[level]; + + while ((ret = dwarf_siblingof (dbg, dies[level], &dies[level], &err)) + == DW_DLV_NO_ENTRY) + { + if (level-- == 0) + break; + + dwarf_dealloc (dbg, old, DW_DLA_DIE); + + old = dies[level]; + } + + dwarf_dealloc (dbg, old, DW_DLA_DIE); + + if (ret == DW_DLV_ERROR) + { + error (0, 0, gettext ("cannot get next DIE: %s\n"), + dwarf_errmsg (err)); + return; + } + } + else if (unlikely (ret != DW_DLV_OK)) + { + error (0, 0, gettext ("cannot get next DIE: %s"), + dwarf_errmsg (err)); + return; + } + else + { + if (level + 1 == maxdies) + dies = (Dwarf_Die *) xrealloc (dies, + (maxdies += 10) + * sizeof (Dwarf_Die)); + + dies[++level] = child; + } + } + while (level >= 0); + + offset = nextcu; + if (offset != 0) + goto next_cu; + + free (dies); } static void -print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, - Dwarf_Debug dbg) +print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, + GElf_Shdr *shdr, Dwarf_Debug dbg) { printf (gettext ("\ \nDWARF section '%s' at offset %#" PRIx64 ":\n"), @@ -2905,8 +3622,8 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, static void -print_debug_loc_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, - Dwarf_Debug dbg) +print_debug_loc_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, + GElf_Shdr *shdr, Dwarf_Debug dbg) { printf (gettext ("\ \nDWARF section '%s' at offset %#" PRIx64 ":\n"), @@ -2916,8 +3633,8 @@ print_debug_loc_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, /* Print the known exported symbols in the DWARF section '.debug_pubnames'. */ static void -print_debug_pubnames_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, - Dwarf_Debug dbg) +print_debug_pubnames_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, + GElf_Shdr *shdr, Dwarf_Debug dbg) { Dwarf_Global *globals; Dwarf_Global *runp; @@ -2962,8 +3679,8 @@ print_debug_pubnames_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, /* Print the content of the DWARF string section '.debug_str'. */ static void -print_debug_str_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, - Dwarf_Debug dbg) +print_debug_str_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, + GElf_Shdr *shdr, Dwarf_Debug dbg) { int res; Dwarf_Off offset = 0; @@ -2996,7 +3713,7 @@ print_debug (Ebl *ebl, GElf_Ehdr *ehdr) Dwarf_Debug dbg; Dwarf_Error err; Elf_Scn *scn; - uint32_t shstrndx; + size_t shstrndx; /* Before we start the real work get a debug context descriptor. */ if (dwarf_elf_init (ebl->elf, DW_DLC_READ, NULL, NULL, &dbg, &err) @@ -3025,7 +3742,8 @@ print_debug (Ebl *ebl, GElf_Ehdr *ehdr) { const char *name; enum section_e bitmask; - void (*fp) (Ebl *, GElf_Ehdr *, GElf_Shdr *, Dwarf_Debug); + void (*fp) (Ebl *, GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, + Dwarf_Debug); } debug_sections[] = { #define NEW_SECTION(name) \ @@ -3050,9 +3768,112 @@ print_debug (Ebl *ebl, GElf_Ehdr *ehdr) if (strcmp (name, debug_sections[n].name) == 0) { if (print_debug_sections & debug_sections[n].bitmask) - debug_sections[n].fp (ebl, ehdr, shdr, dbg); + debug_sections[n].fp (ebl, ehdr, scn, shdr, dbg); break; } } } } + + +static void +handle_notes (Ebl *ebl, GElf_Ehdr *ehdr) +{ + int class = gelf_getclass (ebl->elf); + size_t cnt; + + /* We have to look through the program header to find the note + sections. There can be more than one. */ + for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + { + GElf_Phdr mem; + GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem); + char *notemem; + size_t align; + size_t idx; + + if (phdr == NULL || phdr->p_type != PT_NOTE) + /* Not what we are looking for. */ + continue; + + printf (gettext ("\ +\nNote segment of %" PRId64 " bytes at offset %#0*" PRIx64 ":\n"), + phdr->p_filesz, class == ELFCLASS32 ? 10 : 18, phdr->p_offset); + + notemem = gelf_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz); + if (notemem == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot get content of note section: %s"), + elf_errmsg (-1)); + + fputs_unlocked (gettext (" Owner Data size Type\n"), stdout); + + + /* Handle the note section content. It consists of one or more + entries each of which consists of five parts: + + - a 32-bit name length + - a 32-bit descriptor length + - a 32-bit type field + - the NUL-terminated name, length as specified in the first field + - the descriptor, length as specified in the second field + + The variable sized fields are padded to 32- or 64-bits + depending on whether the file is a 32- or 64-bit ELF file. + */ + align = class == ELFCLASS32 ? 4 : 8; +#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1)) + + idx = 0; + while (idx < phdr->p_filesz) + { + /* XXX Handle 64-bit note section entries correctly. */ + struct + { + uint32_t namesz; + uint32_t descsz; + uint32_t type; + char name[0]; + } *noteentry = (__typeof (noteentry)) (notemem + idx); + char buf[100]; + char buf2[100]; + + if (idx + 12 > phdr->p_filesz + || (idx + 12 + ALIGNED_LEN (noteentry->namesz) + + ALIGNED_LEN (noteentry->descsz) > phdr->p_filesz)) + /* This entry isn't completely contained in the note + section. Ignore it. */ + break; + + printf (gettext (" %-13.*s %9" PRId32 " %s\n"), + (int) noteentry->namesz, noteentry->name, + noteentry->descsz, + ehdr->e_type == ET_CORE + ? ebl_core_note_type_name (ebl, noteentry->type, + buf, sizeof (buf)) + : ebl_object_note_type_name (ebl, noteentry->type, + buf2, sizeof (buf2))); + + /* Filter out invalid entries. */ + if (memchr (noteentry->name, '\0', noteentry->namesz) != NULL + /* XXX For now help broken Linux kernels. */ + || 1) + { + if (ehdr->e_type == ET_CORE) + ebl_core_note (ebl, noteentry->name, noteentry->type, + noteentry->descsz, + ¬eentry->name[ALIGNED_LEN (noteentry->namesz)]); + else + ebl_object_note (ebl, noteentry->name, noteentry->type, + noteentry->descsz, + ¬eentry->name[ALIGNED_LEN (noteentry->namesz)]); + } + + /* Move to the next entry. */ + idx += (12 + ALIGNED_LEN (noteentry->namesz) + + ALIGNED_LEN (noteentry->descsz)); + } + + gelf_freechunk (ebl->elf, notemem); + } +} diff --git a/elfutils/src/strip.c b/elfutils/src/strip.c index 765d2ace0..faf937625 100644 --- a/elfutils/src/strip.c +++ b/elfutils/src/strip.c @@ -1,19 +1,16 @@ /* Discard section not used at runtime from object files. - Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2003 Red Hat, Inc. Written by Ulrich Drepper <drepper@redhat.com>, 2000. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -21,6 +18,7 @@ #include <argp.h> #include <assert.h> +#include <byteswap.h> #include <error.h> #include <fcntl.h> #include <gelf.h> @@ -28,6 +26,7 @@ #include <libintl.h> #include <locale.h> #include <mcheck.h> +#include <stdbool.h> #include <stdio.h> #include <stdio_ext.h> #include <stdlib.h> @@ -48,14 +47,24 @@ void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; /* Values for the parameters which have no short form. */ #define OPT_REMOVE_COMMENT 0x100 +#define OPT_PERMISSIVE 0x101 /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = { + { NULL, 0, NULL, 0, N_("Output selection:") }, { NULL, 'o', "FILE", 0, N_("Place stripped output into FILE") }, - { "preserve-dates", 'p', NULL, 0, N_("Copy modified/access timestamps to the output") }, - { "remove-comment", OPT_REMOVE_COMMENT, NULL, 0, N_("Remove .comment section") }, + { NULL, 'f', "FILE", 0, N_("Extract the removed sections into FILE") }, + + { NULL, 0, NULL, 0, N_("Output options:") }, + { "strip-debug", 'g', NULL, 0, N_("Remove all debugging symbols") }, + { "preserve-dates", 'p', NULL, 0, + N_("Copy modified/access timestamps to the output") }, + { "remove-comment", OPT_REMOVE_COMMENT, NULL, 0, + N_("Remove .comment section") }, + { "permissive", OPT_PERMISSIVE, NULL, 0, + N_("Relax a few rules to handle slightly broken ELF files") }, { NULL, 0, NULL, 0, NULL } }; @@ -93,11 +102,20 @@ static int handle_elf (int fd, Elf *elf, const char *prefix, /* Name of the output file. */ static const char *output_fname; -/* If nonzero output files shall have same date as the input file. */ -static int preserve_dates; +/* Name of the debug output file. */ +static const char *debug_fname; + +/* If true output files shall have same date as the input file. */ +static bool preserve_dates; + +/* If true .comment sections will be removed. */ +static bool remove_comment; + +/* If true remove all debug sections. */ +static bool remove_debug; -/* If nonzero .comment sections will be removed. */ -static int remove_comment; +/* If true relax some ELF rules for input files. */ +static bool permissive; int @@ -134,11 +152,12 @@ main (int argc, char *argv[]) result = process_file ("a.out"); else { - /* If we have seen the `-o' option there must be exactly one + /* If we have seen the `-o' or '-f' option there must be exactly one input file. */ - if (output_fname != NULL && remaining + 1 < argc) - error (EXIT_FAILURE, 0, - gettext ("Only one input file allowed together with `-o'")); + if ((output_fname != NULL || debug_fname != NULL) + && remaining + 1 < argc) + error (EXIT_FAILURE, 0, gettext ("\ +Only one input file allowed together with '-o' and '-f'")); /* Process all the remaining files. */ do @@ -159,7 +178,7 @@ print_version (FILE *stream, struct argp_state *state) Copyright (C) %s Red Hat, Inc.\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ -"), "2001"); +"), "2003"); fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); } @@ -170,16 +189,28 @@ parse_opt (int key, char *arg, struct argp_state *state) { switch (key) { + case 'f': + debug_fname = arg; + break; + case 'o': output_fname = arg; break; case 'p': - preserve_dates = 1; + preserve_dates = true; break; case OPT_REMOVE_COMMENT: - remove_comment = 1; + remove_comment = true; + break; + + case 'g': + remove_debug = true; + break; + + case OPT_PERMISSIVE: + permissive = true; break; default: @@ -275,6 +306,31 @@ cannot set access and modification date of \"%s\""), } +/* Maximum size of array allocated on stack. */ +#define MAX_STACK_ALLOC (400 * 1024) + + +static uint32_t +crc32_file (const char *filename) +{ + char buffer[1024 * 8]; + uint32_t crc = 0; + ssize_t count; + int fd; + + fd = open (filename, O_RDONLY); + if (fd < 0) + return 0; + + while ((count = TEMP_FAILURE_RETRY (read (fd, buffer, sizeof (buffer)))) > 0) + crc = crc32 (crc, buffer, count); + + close (fd); + + return crc; +} + + static int handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, mode_t mode) @@ -284,27 +340,42 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, char fullname[prefix_len + 1 + fname_len]; char *cp = fullname; Elf *newelf; + Elf *debugelf = NULL; int result = 0; GElf_Ehdr ehdr_mem; GElf_Ehdr *ehdr; - uint32_t shstrndx; + size_t shstrndx; size_t shnum; - GElf_Ehdr newehdr_mem; - GElf_Ehdr *newehdr; struct shdr_info { Elf_Scn *scn; GElf_Shdr shdr; Elf_Data *data; const char *name; - GElf_Section idx; /* Index in new file. */ + Elf32_Word idx; /* Index in new file. */ + Elf_Scn *newscn; + size_t symtab_idx; + size_t version_idx; + size_t group_idx; + size_t group_cnt; struct Ebl_Strent *se; - } *shdr_info; - struct Ebl_Strtab *shst; + } *shdr_info = NULL; Elf_Scn *scn; - int changes; size_t cnt; size_t idx; + bool changes; + GElf_Ehdr newehdr_mem; + GElf_Ehdr *newehdr; + GElf_Ehdr debugehdr_mem; + GElf_Ehdr *debugehdr; + struct Ebl_Strtab *shst; + uint32_t debug_crc; + size_t shdridx; + Ebl *ebl; + int debug_fd = -1; + Elf_Data *shstrtab_data; + GElf_Off lastoffset; + size_t offsize; /* Create the full name of the file. */ if (prefix != NULL) @@ -318,20 +389,46 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (output_fname != NULL) { fd = open (output_fname, O_RDWR | O_CREAT, mode); - if (fd == -1) + if (unlikely (fd == -1)) { error (0, errno, gettext ("cannot open `%s'"), output_fname); return 1; } } + /* Get the EBL handling. The -g option is currently the only reason + we need EBL so dont open the backend unless necessary. */ + ebl = NULL; + if (remove_debug) + { + ebl = ebl_openbackend (elf); + if (ebl == NULL) + { + error (0, errno, gettext ("cannot open EBL backend")); + result = 1; + goto fail; + } + } + + /* Open the additional file the debug information will be stored in. */ + if (debug_fname != NULL) + { + debug_fd = open (debug_fname, O_RDWR | O_CREAT, mode); + if (unlikely (debug_fd == -1)) + { + error (0, errno, gettext ("cannot open `%s'"), debug_fname); + result = 1; + goto fail; + } + } + /* Get the information from the old file. */ ehdr = gelf_getehdr (elf, &ehdr_mem); if (ehdr == NULL) INTERNAL_ERROR (fname); /* Get the section header string table index. */ - if (elf_getshstrndx (elf, &shstrndx) < 0) + if (unlikely (elf_getshstrndx (elf, &shstrndx) < 0)) error (EXIT_FAILURE, 0, gettext ("cannot get section header string table index")); @@ -360,26 +457,64 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, INTERNAL_ERROR (fname); } + if (debug_fname != NULL) + { + /* Also create an ELF descriptor for the debug file */ + debugelf = elf_begin (debug_fd, ELF_C_WRITE_MMAP, NULL); + if (gelf_newehdr (debugelf, gelf_getclass (elf)) == 0 + || (ehdr->e_type != ET_REL + && gelf_newphdr (debugelf, ehdr->e_phnum) == 0)) + { + error (0, 0, gettext ("cannot create new file `%s': %s"), + debug_fname, elf_errmsg (-1)); + goto fail_close; + } + + /* Copy over the old program header if needed. */ + if (ehdr->e_type != ET_REL) + for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr; + + phdr = gelf_getphdr (elf, cnt, &phdr_mem); + if (phdr == NULL + || gelf_update_phdr (debugelf, cnt, phdr) == 0) + INTERNAL_ERROR (fname); + } + } + /* Number of sections. */ if (elf_getshnum (elf, &shnum) < 0) { error (0, 0, gettext ("cannot determine number of sections: %s"), elf_errmsg (-1)); - goto fail; + goto fail_close; } - /* Storage for section information. We leave room for one more - entry since we unconditionally create a section header string - table. Maybe some weird tool created an ELF file without one. */ - shdr_info = (struct shdr_info *) alloca ((shnum + 1) - * sizeof (struct shdr_info)); - memset (shdr_info, '\0', (shnum + 1) * sizeof (struct shdr_info)); + /* Storage for section information. We leave room for two more + entries since we unconditionally create a section header string + table. Maybe some weird tool created an ELF file without one. + The other one is used for the debug link section. */ + if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC) + shdr_info = (struct shdr_info *) xcalloc (shnum + 2, + sizeof (struct shdr_info)); + else + { + shdr_info = (struct shdr_info *) alloca ((shnum + 2) + * sizeof (struct shdr_info)); + memset (shdr_info, '\0', (shnum + 2) * sizeof (struct shdr_info)); + } /* Prepare section information data structure. */ scn = NULL; cnt = 1; while ((scn = elf_nextscn (elf, scn)) != NULL) { + /* This should always be true (i.e., there should not be any + holes in the numbering). */ + assert (elf_ndxscn (scn) == cnt); + shdr_info[cnt].scn = scn; /* Get the header. */ @@ -398,6 +533,65 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Mark them as present but not yet investigated. */ shdr_info[cnt].idx = 1; + /* Sections in files other than relocatable object files which + are not loaded can be freely moved by us. In relocatable + object files everything can be moved. */ + if (ehdr->e_type == ET_REL + || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0) + shdr_info[cnt].shdr.sh_offset = 0; + + /* If this is an extended section index table store an + appropriate reference. */ + if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX)) + { + assert (shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx == 0); + shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx = cnt; + } + else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GROUP)) + { + Elf32_Word *grpref; + size_t inner; + + /* Cross-reference the sections contained in the section + group. */ + shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); + if (shdr_info[cnt].data == NULL) + INTERNAL_ERROR (fname); + + /* XXX Fix for unaligned access. */ + grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; + for (inner = 1; + inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); + ++inner) + shdr_info[grpref[inner]].group_idx = cnt; + + if (inner == 1 || (inner == 2 && (grpref[0] & GRP_COMDAT) == 0)) + /* If the section group contains only one element and this + is n COMDAT section we can drop it right away. */ + shdr_info[cnt].idx = 0; + else + shdr_info[cnt].group_cnt = inner - 1; + } + else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym)) + { + assert (shdr_info[shdr_info[cnt].shdr.sh_link].version_idx == 0); + shdr_info[shdr_info[cnt].shdr.sh_link].version_idx = cnt; + } + + /* If this section is part of a group make sure it is not + discarded right away. */ + if ((shdr_info[cnt].shdr.sh_flags & SHF_GROUP) != 0) + { + assert (shdr_info[cnt].group_idx != 0); + + if (shdr_info[shdr_info[cnt].group_idx].idx == 0) + { + /* The section group section will be removed. */ + shdr_info[cnt].group_idx = 0; + shdr_info[cnt].shdr.sh_flags &= ~SHF_GROUP; + } + } + /* Increment the counter. */ ++cnt; } @@ -409,112 +603,146 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, - special sections named ".comment" and ".note" are kept - OS or architecture specific sections are kept since we might not know how to handle them - - section groups must be observed. If any section of a section - is not removed the entire group is not removed - if a section is referred to from a section which is not removed in the sh_link or sh_info element it cannot be removed either */ for (cnt = 1; cnt < shnum; ++cnt) -#if 1 /* Check whether the section can be removed. */ - if (SECTION_STRIP_P (&shdr_info[cnt].shdr, shdr_info[cnt].name, - remove_comment)) - /* For now assume this section will be removed. */ - shdr_info[cnt].idx = 0; -#else - if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0) + if (SECTION_STRIP_P (ebl, elf, ehdr, &shdr_info[cnt].shdr, + shdr_info[cnt].name, remove_comment, remove_debug)) { - /* We are never removing the .note section(s). */ - if (shdr_info[cnt].shdr.sh_type == SHT_NOTE) - continue; - - /* We are removing the .comment section(s) only if explicitly - told so. */ - if (shdr_info[cnt].shdr.sh_type == SHT_PROGBITS - && ! remove_comment - && strcmp (shdr_info[cnt].name, ".comment") == 0) - continue; - - /* Don't remove non-standard sections. - XXX Once we handle the non-standard sections this can be - extended . */ - if (shdr_info[cnt].shdr.sh_type >= SHT_NUM) - continue; - /* For now assume this section will be removed. */ shdr_info[cnt].idx = 0; + + idx = shdr_info[cnt].group_idx; + while (idx != 0) + { + /* If the references section group is a normal section + group and has one element remaining, or if it is an + empty COMDAT section group it is removed. */ + bool is_comdat; + + /* The section group data is already loaded. */ + assert (shdr_info[idx].data != NULL); + + is_comdat = (((Elf32_Word *) shdr_info[idx].data->d_buf)[0] + & GRP_COMDAT) != 0; + + --shdr_info[idx].group_cnt; + if ((!is_comdat && shdr_info[idx].group_cnt == 1) + || (is_comdat && shdr_info[idx].group_cnt == 0)) + { + shdr_info[idx].idx = 0; + /* Continue recursively. */ + idx = shdr_info[idx].group_idx; + } + else + break; + } } -#endif /* Mark the SHT_NULL section as handled. */ shdr_info[0].idx = 2; + /* Handle exceptions: section groups and cross-references. We might have to repeat this a few times since the resetting of the flag might propagate. */ do { - changes = 0; + changes = false; for (cnt = 1; cnt < shnum; ++cnt) - if (shdr_info[cnt].idx == 1) - { - /* The content of symbol tables we don't remove must not - reference any section which we do remove. Otherwise - we cannot remove the section. */ - if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM - || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) - { - size_t elsize; - size_t inner; + { + if (shdr_info[cnt].idx == 0) + { + /* If a relocation section is marked as being removed make + sure the section it is relocating is removed, too. */ + if ((shdr_info[cnt].shdr.sh_type == SHT_REL + || shdr_info[cnt].shdr.sh_type == SHT_RELA) + && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0) + shdr_info[cnt].idx = 1; + } - /* Make sure the data is loaded. */ - if (shdr_info[cnt].data == NULL) - { - shdr_info[cnt].data = - elf_getdata (shdr_info[cnt].scn, NULL); - if (shdr_info[cnt].data == NULL) - INTERNAL_ERROR (fname); - } + if (shdr_info[cnt].idx == 1) + { + /* The content of symbol tables we don't remove must not + reference any section which we do remove. Otherwise + we cannot remove the section. */ + if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM + || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) + { + Elf_Data *symdata; + Elf_Data *xndxdata; + size_t elsize; + size_t inner; - /* Go through all symbols and make sure the section they - reference is not removed. */ - elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); + /* Make sure the data is loaded. */ + if (shdr_info[cnt].data == NULL) + { + shdr_info[cnt].data + = elf_getdata (shdr_info[cnt].scn, NULL); + if (shdr_info[cnt].data == NULL) + INTERNAL_ERROR (fname); + } + symdata = shdr_info[cnt].data; - for (inner = 0; - inner < shdr_info[cnt].data->d_size / elsize; - ++inner) - { - GElf_Section scnidx; - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsym (shdr_info[cnt].data, inner, - &sym_mem); - if (sym == NULL) - INTERNAL_ERROR (fname); + /* If there is an extended section index table load it + as well. */ + if (shdr_info[cnt].symtab_idx != 0 + && shdr_info[shdr_info[cnt].symtab_idx].data == NULL) + { + assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB); - scnidx = sym->st_shndx; - if (scnidx == SHN_UNDEF || scnidx >= shnum) - /* This is no section index, leave it alone. */ - continue; + shdr_info[shdr_info[cnt].symtab_idx].data + = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn, + NULL); + if (shdr_info[shdr_info[cnt].symtab_idx].data == NULL) + INTERNAL_ERROR (fname); + } + xndxdata = shdr_info[shdr_info[cnt].symtab_idx].data; - if (shdr_info[scnidx].idx == 0) - { - /* Mark this section and all before it which are - unmarked as used. */ - shdr_info[scnidx].idx = 1; - while (scnidx-- > 1) - if (shdr_info[scnidx].idx == 0) - shdr_info[scnidx].idx = 1; - changes = 1; - } + /* Go through all symbols and make sure the section they + reference is not removed. */ + elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); - /* XXX We have to decide who to handle the extended - section index table. Maybe libelf does it itself. */ - } - } + for (inner = 0; + inner < shdr_info[cnt].data->d_size / elsize; + ++inner) + { + GElf_Sym sym_mem; + Elf32_Word xndx; + GElf_Sym *sym; + size_t scnidx; + + sym = gelf_getsymshndx (symdata, xndxdata, inner, + &sym_mem, &xndx); + if (sym == NULL) + INTERNAL_ERROR (fname); + + scnidx = sym->st_shndx; + if (scnidx == SHN_UNDEF || scnidx >= shnum + || (scnidx >= SHN_LORESERVE + && scnidx <= SHN_HIRESERVE + && scnidx != SHN_XINDEX) + /* Don't count in the section symbols. */ + || GELF_ST_TYPE (sym->st_info) == STT_SECTION) + /* This is no section index, leave it alone. */ + continue; + else if (scnidx == SHN_XINDEX) + scnidx = xndx; + + if (shdr_info[scnidx].idx == 0) + { + /* Mark this section as used. */ + shdr_info[scnidx].idx = 1; + changes |= scnidx < cnt; + } + } + } - /* Cross referencing happens: - - for the cases the ELF specification says. That are + /* Cross referencing happens: + - for the cases the ELF specification says. That are + SHT_DYNAMIC in sh_link to string table + SHT_HASH in sh_link to symbol table + SHT_REL and SHT_RELA in sh_link to symbol table @@ -523,129 +751,109 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, + SHT_SYMTAB_SHNDX in sh_link to symbol table Other (OS or architecture-specific) sections might as well use this field so we process it unconditionally. - - references inside section groups - - specially marked references in sh_info if the SHF_INFO_LINK + - references inside section groups + - specially marked references in sh_info if the SHF_INFO_LINK flag is set - */ + */ - if (shdr_info[shdr_info[cnt].shdr.sh_link].idx != 0) - { - size_t inner = shdr_info[cnt].shdr.sh_link; + if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0) + { + shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1; + changes |= shdr_info[cnt].shdr.sh_link < cnt; + } - shdr_info[inner].idx = 1; - while (inner-- > 1) - if (shdr_info[inner].idx == 0) - shdr_info[inner].idx = 1; + /* Handle references through sh_info. */ + if (SH_INFO_LINK_P (&shdr_info[cnt].shdr) + && shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) + { + shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1; + changes |= shdr_info[cnt].shdr.sh_info < cnt; + } - changes = 1; - } + /* Mark the section as investigated. */ + shdr_info[cnt].idx = 2; + } + } + } + while (changes); - if (shdr_info[cnt].shdr.sh_type == SHT_GROUP) - { - size_t inner; - Elf32_Word *grpref; + /* Write out a copy of all the sections to the debug output file. + The ones that are not removed in the stripped file are SHT_NOBITS */ + if (debug_fname != NULL) + { + for (cnt = 1; cnt < shnum; ++cnt) + { + Elf_Data *debugdata; + GElf_Shdr debugshdr; + int discard_section; - if (shdr_info[cnt].data == NULL) - { - shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, - NULL); - if (shdr_info[cnt].data == NULL) - INTERNAL_ERROR (fname); - } + scn = elf_newscn (debugelf); + if (scn == NULL) + error (EXIT_FAILURE, 0, + gettext ("while generating output file: %s"), + elf_errmsg (-1)); - grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; - /* The first word of the section is a flag which we can - ignore here. */ - for (inner = 1; - inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); - ++inner) - if (shdr_info[grpref[inner]].idx == 0) - { - size_t inner2 = grpref[inner]; - - shdr_info[inner2].idx = 1; -#if 0 - /* XXX This isn't correct. Is it possible to - leave out sections in the middle? If not we - have to add all sections before the one we - just added as well. But "before" means in - the address space and not in the section - header table (which is what the current code - does). */ - while (inner2-- > 1) - if (shdr_info[inner2].idx == 0) - shdr_info[inner2].idx = 1; -#endif - changes = 1; - } - } + discard_section = shdr_info[cnt].idx > 0 && cnt != ehdr->e_shstrndx; - /* Handle references through sh_info. */ - if (SH_INFO_LINK_P (&shdr_info[cnt].shdr) - && shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) - { - size_t inner = shdr_info[cnt].shdr.sh_info; + /* Set the section header in the new file. */ + debugshdr = shdr_info[cnt].shdr; + if (discard_section) + debugshdr.sh_type = SHT_NOBITS; - shdr_info[inner].idx = 1; - while (inner-- > 1) - if (shdr_info[inner].idx == 0) - shdr_info[inner].idx = 1; + if (unlikely (gelf_update_shdr (scn, &debugshdr)) == 0) + /* There cannot be any overflows. */ + INTERNAL_ERROR (fname); - changes = 1; - } + /* Get the data from the old file if necessary. */ + if (shdr_info[cnt].data == NULL) + { + shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); + if (shdr_info[cnt].data == NULL) + INTERNAL_ERROR (fname); + } - /* Mark the section as investigated. */ - shdr_info[cnt].idx = 2; - } - else if (shdr_info[cnt].idx == 0 - && shdr_info[cnt].shdr.sh_type == SHT_GROUP) - { - /* If any member of the group isn't removed all of the group - stays. */ - size_t inner; - size_t maxidx = 0; - Elf32_Word *grpref; - int newval = -1; + /* Set the data. This is done by copying from the old file. */ + debugdata = elf_newdata (scn); + if (debugdata == NULL) + INTERNAL_ERROR (fname); - if (shdr_info[cnt].data == NULL) - { - shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); - if (shdr_info[cnt].data == NULL) - INTERNAL_ERROR (fname); - } + /* Copy the structure. */ + *debugdata = *shdr_info[cnt].data; + if (discard_section) + debugdata->d_buf = NULL; + } - grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; - for (inner = 1; - inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); - ++inner) - if (shdr_info[grpref[inner]].idx > 0) - { - /* The whole group must stay. Except for debugging - sections and the relocations for those sections. */ - for (inner = 1; - inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); - ++inner) - { - shdr_info[grpref[inner]].idx = 1; - maxidx = MAX (maxidx, grpref[inner]); - } + /* Finish the ELF header. Fill in the fields not handled by + libelf from the old file. */ + debugehdr = gelf_getehdr (debugelf, &debugehdr_mem); + if (debugehdr == NULL) + INTERNAL_ERROR (fname); - /* XXX This is wrong. We must check for file offsets - and not section header table indeces. */ - while (maxidx-- > 1) - if (shdr_info[maxidx].idx == 0) - shdr_info[maxidx].idx = 1; + memcpy (debugehdr->e_ident, ehdr->e_ident, EI_NIDENT); + debugehdr->e_type = ehdr->e_type; + debugehdr->e_machine = ehdr->e_machine; + debugehdr->e_version = ehdr->e_version; + debugehdr->e_entry = ehdr->e_entry; + debugehdr->e_flags = ehdr->e_flags; + debugehdr->e_shstrndx = ehdr->e_shstrndx; - newval = 2; - changes = 1; - break; - } + if (unlikely (gelf_update_ehdr (debugelf, debugehdr)) == 0) + { + error (0, 0, gettext ("%s: error while creating ELF header: %s"), + debug_fname, elf_errmsg (-1)); + goto fail_close; + } - /* Mark section as used or verified to be not used. */ - shdr_info[cnt].idx = newval; - } + /* Finally write the file. */ + if (unlikely (elf_update (debugelf, ELF_C_WRITE)) == -1) + { + error (0, 0, gettext ("while writing `%s': %s"), + debug_fname, elf_errmsg (-1)); + goto fail_close; + } + + debug_crc = crc32_file (debug_fname); } - while (changes); /* Mark the section header string table as unused, we will create a new one. */ @@ -658,10 +866,19 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, output_fname ?: fname); /* Assign new section numbers. */ + shdr_info[0].idx = 0; for (cnt = idx = 1; cnt < shnum; ++cnt) if (shdr_info[cnt].idx > 0) { - shdr_info[cnt].idx = idx; + shdr_info[cnt].idx = idx++; + + /* Create a new section. */ + shdr_info[cnt].newscn = elf_newscn (newelf); + if (shdr_info[cnt].newscn == NULL) + error (EXIT_FAILURE, 0, gettext ("while generating output file: %s"), + elf_errmsg (-1)); + + assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx); /* Add this name to the section header string table. */ shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0); @@ -672,6 +889,69 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Nope, all removable sections are already gone. */ goto fail_close; + /* Create the reference to the file with the debug info. */ + if (debug_fname != NULL) + { + char *debug_basename; + off_t crc_offset; + + /* Add the section header string table section name. */ + shdr_info[cnt].se = ebl_strtabadd (shst, ".gnu_debuglink", 15); + shdr_info[cnt].idx = idx++; + + /* Create the section header. */ + shdr_info[cnt].shdr.sh_type = SHT_PROGBITS; + shdr_info[cnt].shdr.sh_flags = 0; + shdr_info[cnt].shdr.sh_addr = 0; + shdr_info[cnt].shdr.sh_link = SHN_UNDEF; + shdr_info[cnt].shdr.sh_info = SHN_UNDEF; + shdr_info[cnt].shdr.sh_entsize = 0; + shdr_info[cnt].shdr.sh_addralign = 4; + /* We set the offset to zero here. Before we write the ELF file the + field must have the correct value. This is done in the final + loop over all section. Then we have all the information needed. */ + shdr_info[cnt].shdr.sh_offset = 0; + + /* Create the section. */ + shdr_info[cnt].newscn = elf_newscn (newelf); + if (shdr_info[cnt].newscn == NULL) + error (EXIT_FAILURE, 0, + gettext ("while create section header section: %s"), + elf_errmsg (-1)); + assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx); + + shdr_info[cnt].data = elf_newdata (shdr_info[cnt].newscn); + if (shdr_info[cnt].data == NULL) + error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"), + elf_errmsg (-1)); + + debug_basename = basename (debug_fname); + crc_offset = strlen (debug_basename) + 1; + /* Align to 4 byte boundary */ + crc_offset = ((crc_offset - 1) & ~3) + 4; + + shdr_info[cnt].data->d_align = 4; + shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size + = crc_offset + 4; + shdr_info[cnt].data->d_buf = xcalloc (1, shdr_info[cnt].data->d_size); + + strcpy (shdr_info[cnt].data->d_buf, debug_basename); + /* Store the crc value in the correct byteorder */ + if ((__BYTE_ORDER == __LITTLE_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + || (__BYTE_ORDER == __BIG_ENDIAN + && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) + debug_crc = bswap_32 (debug_crc); + memcpy ((char *)shdr_info[cnt].data->d_buf + crc_offset, + (char *) &debug_crc, 4); + + /* One more section done. */ + ++cnt; + } + + /* Index of the section header table in the shdr_info array. */ + shdridx = cnt; + /* Add the section header string table section name. */ shdr_info[cnt].se = ebl_strtabadd (shst, ".shstrtab", 10); shdr_info[cnt].idx = idx; @@ -682,37 +962,35 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, shdr_info[cnt].shdr.sh_addr = 0; shdr_info[cnt].shdr.sh_link = SHN_UNDEF; shdr_info[cnt].shdr.sh_info = SHN_UNDEF; - shdr_info[cnt].shdr.sh_entsize = 1; - /* We have to initialize these fields because they might contain - values which later get rejected by the `gelf_update_shdr' - function. The values we are using don't matter, they must only - be representable. */ + shdr_info[cnt].shdr.sh_entsize = 0; + /* We set the offset to zero here. Before we write the ELF file the + field must have the correct value. This is done in the final + loop over all section. Then we have all the information needed. */ shdr_info[cnt].shdr.sh_offset = 0; - shdr_info[cnt].shdr.sh_size = 0; - shdr_info[cnt].shdr.sh_addralign = 0; + shdr_info[cnt].shdr.sh_addralign = 1; /* Create the section. */ - for (cnt = 1; cnt <= shnum; ++cnt) - if (shdr_info[cnt].idx > 0) - { - /* Create a new section. */ - scn = elf_newscn (newelf); - if (scn == NULL) - error (EXIT_FAILURE, 0, gettext ("while generating output file: %s"), - elf_errmsg (-1)); - - assert (elf_ndxscn (scn) == shdr_info[cnt].idx); - } + shdr_info[cnt].newscn = elf_newscn (newelf); + if (shdr_info[cnt].newscn == NULL) + error (EXIT_FAILURE, 0, + gettext ("while create section header section: %s"), + elf_errmsg (-1)); + assert (elf_ndxscn (shdr_info[cnt].newscn) == idx); /* Finalize the string table and fill in the correct indices in the section headers. */ - assert (scn == elf_getscn (newelf, idx)); - ebl_strtabfinalize (shst, elf_newdata (scn)); + shstrtab_data = elf_newdata (shdr_info[cnt].newscn); + ebl_strtabfinalize (shst, shstrtab_data); + + /* We have to set the section size. */ + shdr_info[cnt].shdr.sh_size = shstrtab_data->d_size; /* Update the section information. */ - for (cnt = 1; cnt <= shnum; ++cnt) + lastoffset = 0; + for (cnt = 1; cnt <= shdridx; ++cnt) if (shdr_info[cnt].idx > 0) { + GElf_Off filesz; Elf_Data *newdata; scn = elf_getscn (newelf, shdr_info[cnt].idx); @@ -746,11 +1024,6 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, shdr_info[cnt].shdr.sh_info = shdr_info[shdr_info[cnt].shdr.sh_info].idx; - /* Set the section header in the new file. */ - if (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0) - /* There cannot be any overflows. */ - INTERNAL_ERROR (fname); - /* Get the data from the old file if necessary. We already created the data for the section header string table. */ if (cnt < shnum) @@ -770,6 +1043,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Copy the structure. */ *newdata = *shdr_info[cnt].data; + /* We know the size. */ + shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size; + /* We have to adjust symtol tables. The st_shndx member might have to be updated. */ if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM @@ -777,41 +1053,133 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, { size_t elsize; size_t inner; + Elf_Data *versiondata = NULL; + Elf_Data *shndxdata = NULL; elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); - for (inner = 0; + if (shdr_info[cnt].symtab_idx != 0) + { + assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX); + /* This section has extended section information. + We have to modify that information, too. */ + shndxdata = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn, + NULL); + + assert ((versiondata->d_size / sizeof (Elf32_Word)) + >= shdr_info[cnt].data->d_size / elsize); + } + + if (shdr_info[cnt].version_idx != 0) + { + assert (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM); + /* This section has associated version + information. We have to modify that + information, too. */ + versiondata = elf_getdata (shdr_info[shdr_info[cnt].version_idx].scn, + NULL); + + assert ((versiondata->d_size / sizeof (GElf_Versym)) + >= shdr_info[cnt].data->d_size / elsize); + } + + for (inner = 1; inner < shdr_info[cnt].data->d_size / elsize; ++inner) { - GElf_Section sec; + Elf32_Word sec; GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsym (shdr_info[cnt].data, inner, - &sym_mem); + Elf32_Word xshndx; + GElf_Sym *sym = gelf_getsymshndx (shdr_info[cnt].data, + shndxdata, inner, + &sym_mem, &xshndx); if (sym == NULL) INTERNAL_ERROR (fname); if (sym->st_shndx == SHN_UNDEF - || sym->st_shndx >= shnum) + || (sym->st_shndx >= shnum + && sym->st_shndx != SHN_XINDEX)) /* This is no section index, leave it alone. */ continue; - sec = shdr_info[sym->st_shndx].idx; - assert (sec != 0); - if (sec != sym->st_shndx) + if (sym->st_shndx != SHN_XINDEX) + sec = shdr_info[sym->st_shndx].idx; + else + { + assert (shndxdata != NULL); + + sec = shdr_info[xshndx].idx; + } + + if (sec != 0) { - sym->st_shndx = sec; - if (gelf_update_sym (shdr_info[cnt].data, inner, sym) - == 0) + GElf_Section nshndx; + Elf32_Word nxshndx; + + if (sec < SHN_LORESERVE) + { + nshndx = sec; + nxshndx = 0; + } + else + { + nshndx = SHN_XINDEX; + nxshndx = sec; + } + + assert (sec < SHN_LORESERVE || shndxdata != NULL); + + if ((nshndx != sym->st_shndx + || (shndxdata != NULL && nxshndx != xshndx)) + && (sym->st_shndx = nshndx, + gelf_update_symshndx (shdr_info[cnt].data, + shndxdata, + inner, sym, + nxshndx) == 0)) INTERNAL_ERROR (fname); } + else + { + assert (GELF_ST_TYPE (sym->st_info) == STT_SECTION); - /* XXX We have to update the extended index section - table as well once we decide how to handle it. Maybe - libelf will do it itself. */ + /* Clear the symbol table entry. */ + memset (&sym_mem, '\0', sizeof (sym_mem)); + if (gelf_update_symshndx (shdr_info[cnt].data, + shndxdata, inner, + &sym_mem, 0) == 0) + INTERNAL_ERROR (fname); + + if (versiondata != NULL) + { + /* Zero out the version information. It + should already be zero but who knows. */ + GElf_Versym versym_mem = 0; + + if (gelf_update_versym (versiondata, inner, + &versym_mem) == 0) + INTERNAL_ERROR (fname); + } + } } } } + + /* If we have to, compute the offset of the section. */ + if (shdr_info[cnt].shdr.sh_offset == 0) + shdr_info[cnt].shdr.sh_offset + = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1) + & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1))); + + /* Set the section header in the new file. */ + if (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0) + /* There cannot be any overflows. */ + INTERNAL_ERROR (fname); + + /* Remember the last section written so far. */ + filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS + ? shdr_info[cnt].shdr.sh_size : 0); + if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz) + lastoffset = shdr_info[cnt].shdr.sh_offset + filesz; } /* Finally finish the ELF header. Fill in the fields not handled by @@ -826,6 +1194,13 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, newehdr->e_version = ehdr->e_version; newehdr->e_entry = ehdr->e_entry; newehdr->e_flags = ehdr->e_flags; + newehdr->e_phoff = ehdr->e_phoff; + /* We need to position the section header table. */ + offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT); + newehdr->e_shoff = ((shdr_info[shdridx].shdr.sh_offset + + shdr_info[shdridx].shdr.sh_size + offsize - 1) + & ~((GElf_Off) (offsize - 1))); + newehdr->e_shentsize = gelf_fsize (elf, ELF_T_SHDR, 1, EV_CURRENT); /* The new section header string table index. */ if (likely (idx < SHN_HIRESERVE) && likely (idx != SHN_XINDEX)) @@ -859,6 +1234,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, return 1; } + /* The ELF library better follows our layout when this is not a + relocatable object file. */ + elf_flagelf (newelf, ELF_C_SET, + (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0) + | (permissive ? ELF_F_PERMISSIVE : 0)); + /* Finally write the file. */ if (elf_update (newelf, ELF_C_WRITE) == -1) { @@ -867,8 +1248,13 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, result = 1; } + fail_close: - /* That was it. Close the descriptor. */ + /* Free the memory. */ + if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC) + free (shdr_info); + + /* That was it. Close the descriptors. */ if (elf_end (newelf) != 0) { error (0, 0, gettext ("error while finishing `%s': %s"), fname, @@ -876,7 +1262,22 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, result = 1; } + if (debugelf != NULL && elf_end (debugelf) != 0) + { + error (0, 0, gettext ("error while finishing `%s': %s"), debug_fname, + elf_errmsg (-1)); + result = 1; + } + fail: + /* Close the EBL backend. */ + if (ebl != NULL) + ebl_closebackend (ebl); + + /* Close debug file descriptor, if opened */ + if (debug_fd >= 0) + close (debug_fd); + /* Close the file descriptor if we created a new file. */ if (output_fname != NULL) close (fd); diff --git a/elfutils/tests/ecp.c b/elfutils/tests/ecp.c index 15bc71cc3..ef231d8a8 100644 --- a/elfutils/tests/ecp.c +++ b/elfutils/tests/ecp.c @@ -21,33 +21,39 @@ int main (int argc, char *argv[]) { + int infd; + Elf *inelf; + int outfd; + Elf *outelf; + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + Elf_Scn *scn = NULL; + if (argc < 3) error (EXIT_FAILURE, 0, "usage: %s FROMNAME TONAME", argv[0]); elf_version (EV_CURRENT); - int infd = open (argv[1], O_RDONLY); + infd = open (argv[1], O_RDONLY); if (infd == -1) error (EXIT_FAILURE, errno, "cannot open input file '%s'", argv[1]); - Elf *inelf = elf_begin (infd, ELF_C_READ, NULL); + inelf = elf_begin (infd, ELF_C_READ, NULL); if (inelf == NULL) error (EXIT_FAILURE, 0, "problems opening '%s' as ELF file: %s", argv[1], elf_errmsg (-1)); - int outfd = creat (argv[2], 0666); + outfd = creat (argv[2], 0666); if (outfd == -1) error (EXIT_FAILURE, errno, "cannot open output file '%s'", argv[2]); - Elf *outelf = elf_begin (outfd, ELF_C_WRITE, NULL); + outelf = elf_begin (outfd, ELF_C_WRITE, NULL); if (outelf == NULL) error (EXIT_FAILURE, 0, "problems opening '%s' as ELF file: %s", argv[2], elf_errmsg (-1)); gelf_newehdr (outelf, gelf_getclass (inelf)); - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr; gelf_update_ehdr (outelf, (ehdr = gelf_getehdr (inelf, &ehdr_mem))); if (ehdr->e_phnum > 0) @@ -66,7 +72,6 @@ main (int argc, char *argv[]) } } - Elf_Scn *scn = NULL; while ((scn = elf_nextscn (inelf, scn)) != NULL) { Elf_Scn *newscn = elf_newscn (outelf); diff --git a/elfutils/tests/get-pubnames2.c b/elfutils/tests/get-pubnames2.c index 9aa6451a1..2fa32edb1 100644 --- a/elfutils/tests/get-pubnames2.c +++ b/elfutils/tests/get-pubnames2.c @@ -28,8 +28,11 @@ callback (Dwarf *dbg, Dwarf_Global *gl, void *arg) (unsigned long long int) gl->cu_offset); #if 0 + { Dwarf_Die cu_die; const char *cuname; + const char *diename; + if (dwarf_offdie (dbg, gl->cu_offset, &cu_die) == NULL || (cuname = dwarf_diename (&cu_die)) == NULL) { @@ -42,7 +45,6 @@ callback (Dwarf *dbg, Dwarf_Global *gl, void *arg) dwarf_dealloc (dbg, cuname, DW_DLA_STRING); } - const char *diename; if (dwarf_offdie (dbg, gl->die_offset, &die) == NULL || (diename = dwarf_diename (&die)) == NULL) { @@ -54,6 +56,7 @@ callback (Dwarf *dbg, Dwarf_Global *gl, void *arg) printf ("object name: \"%s\"\n", diename); dwarf_dealloc (dbg, diename, DW_DLA_STRING); } + } #endif return DWARF_CB_OK; } diff --git a/elfutils/tests/newscn.c b/elfutils/tests/newscn.c index 58cffe3dd..6196831cf 100644 --- a/elfutils/tests/newscn.c +++ b/elfutils/tests/newscn.c @@ -6,7 +6,7 @@ You should have received a copy of the Open Software License along with this program; if not, you may obtain a copy of the Open Software - License version 1.0 from http://www.opensource.org/license/osl.php or + License version 1.0 from http://www.opensource.org/licenses/osl.php or by writing the Open Source Initiative c/o Lawrence Rosen, Esq., 3001 King Ranch Road, Ukiah, CA 95482. */ @@ -24,6 +24,7 @@ main (int argc, char *argv[]) Elf *elf; int fd; Elf_Scn *section; + char name[] = "test.XXXXXX"; if (elf_version (EV_CURRENT) == EV_NONE) { @@ -31,7 +32,6 @@ main (int argc, char *argv[]) exit (1); } - char name[] = "test.XXXXXX"; fd = mkstemp (name); if (fd < 0) { |