diff options
Diffstat (limited to 'libelf/elf32_getshdr.c')
| -rw-r--r-- | libelf/elf32_getshdr.c | 340 |
1 files changed, 192 insertions, 148 deletions
diff --git a/libelf/elf32_getshdr.c b/libelf/elf32_getshdr.c index 8d658752..b36e5437 100644 --- a/libelf/elf32_getshdr.c +++ b/libelf/elf32_getshdr.c @@ -54,6 +54,7 @@ #include <assert.h> #include <errno.h> +#include <stdbool.h> #include <unistd.h> #include <system.h> @@ -65,187 +66,230 @@ #endif -ElfW2(LIBELFBITS,Shdr) * -__elfw2(LIBELFBITS,getshdr_internal) (scn, locked) - Elf_Scn *scn; - lockstat_t locked; +static ElfW2(LIBELFBITS,Shdr) * +load_shdr_rwlock (Elf_Scn *scn) { - /* XXX: no read locking here, figure out why is it not necessary. */ ElfW2(LIBELFBITS,Shdr) *result; - if (scn == NULL) - return NULL; + /* Read the section header table. */ + Elf *elf = scn->elf; + ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; - if (unlikely (scn->elf->state.elf.ehdr == NULL)) + /* Try again, maybe the data is there now. */ + result = scn->shdr.ELFW(e,LIBELFBITS); + if (result != NULL) + goto out; + + size_t shnum; + if (__elf_getshnum_rdlock (elf, &shnum) != 0) + goto out; + size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr)); + + /* Allocate memory for the section headers. We know the number + of entries from the ELF header. */ + ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr = + (ElfW2(LIBELFBITS,Shdr) *) malloc (size); + if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL) { - __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); - return NULL; + __libelf_seterrno (ELF_E_NOMEM); + goto out; } + elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1; - if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS))) + if (elf->map_address != NULL) { - __libelf_seterrno (ELF_E_INVALID_CLASS); - return NULL; - } + ElfW2(LIBELFBITS,Shdr) *notcvt; - result = scn->shdr.ELFW(e,LIBELFBITS); - if (result == NULL) - { - /* Read the section header table. */ - Elf *elf = scn->elf; - ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; + /* All the data is already mapped. If we could use it + directly this would already have happened. */ + void *file_shdr = ((char *) elf->map_address + + elf->start_offset + ehdr->e_shoff); - rwlock_to_wrlock (locked, &elf->lock); + assert (ehdr->e_ident[EI_DATA] != MY_ELFDATA + || (! ALLOW_UNALIGNED + && ((uintptr_t) file_shdr + & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0)); - /* Try again, maybe the data is there now. */ - result = scn->shdr.ELFW(e,LIBELFBITS); - if (result != NULL) - goto out; - - size_t shnum; - if (__elf_getshnum_internal (elf, &shnum, LS_WRLOCKED) != 0) - goto out; - size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr)); - - /* Allocate memory for the section headers. We know the number - of entries from the ELF header. */ - ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr = - (ElfW2(LIBELFBITS,Shdr) *) malloc (size); - if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL) + /* Now copy the data and at the same time convert the byte order. */ + if (ehdr->e_ident[EI_DATA] == MY_ELFDATA) { - __libelf_seterrno (ELF_E_NOMEM); - goto out; + assert (! ALLOW_UNALIGNED); + memcpy (shdr, file_shdr, size); } - elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1; - - if (elf->map_address != NULL) + else { - ElfW2(LIBELFBITS,Shdr) *notcvt; - - /* All the data is already mapped. If we could use it - directly this would already have happened. */ - void *file_shdr = ((char *) elf->map_address - + elf->start_offset + ehdr->e_shoff); - - assert (ehdr->e_ident[EI_DATA] != MY_ELFDATA - || (! ALLOW_UNALIGNED - && ((uintptr_t) file_shdr - & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0)); - - /* Now copy the data and at the same time convert the byte order. */ - if (ehdr->e_ident[EI_DATA] == MY_ELFDATA) - { - assert (! ALLOW_UNALIGNED); - memcpy (shdr, file_shdr, size); - } + if (ALLOW_UNALIGNED + || ((uintptr_t) file_shdr + & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) == 0) + notcvt = (ElfW2(LIBELFBITS,Shdr) *) + ((char *) elf->map_address + + elf->start_offset + ehdr->e_shoff); else { - if (ALLOW_UNALIGNED - || ((uintptr_t) file_shdr - & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) == 0) - notcvt = (ElfW2(LIBELFBITS,Shdr) *) - ((char *) elf->map_address - + elf->start_offset + ehdr->e_shoff); - else - { - notcvt = (ElfW2(LIBELFBITS,Shdr) *) alloca (size); - memcpy (notcvt, ((char *) elf->map_address - + elf->start_offset + ehdr->e_shoff), - size); - } - - for (size_t cnt = 0; cnt < shnum; ++cnt) - { - CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name); - CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type); - CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags); - CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr); - CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset); - CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size); - CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link); - CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info); - CONVERT_TO (shdr[cnt].sh_addralign, - notcvt[cnt].sh_addralign); - CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize); - - /* If this is a section with an extended index add a - reference in the section which uses the extended - index. */ - if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX - && shdr[cnt].sh_link < shnum) - elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index - = cnt; - - /* Set the own shndx_index field in case it has not yet - been set. */ - if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0) - elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index - = -1; - } + notcvt = (ElfW2(LIBELFBITS,Shdr) *) alloca (size); + memcpy (notcvt, ((char *) elf->map_address + + elf->start_offset + ehdr->e_shoff), + size); } - } - else if (likely (elf->fildes != -1)) - { - /* Read the header. */ - ssize_t n = pread_retry (elf->fildes, - elf->state.ELFW(elf,LIBELFBITS).shdr, size, - elf->start_offset + ehdr->e_shoff); - if (unlikely ((size_t) n != size)) + + for (size_t cnt = 0; cnt < shnum; ++cnt) { - /* Severe problems. We cannot read the data. */ - __libelf_seterrno (ELF_E_READ_ERROR); - goto free_and_out; + CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name); + CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type); + CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags); + CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr); + CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset); + CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size); + CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link); + CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info); + CONVERT_TO (shdr[cnt].sh_addralign, + notcvt[cnt].sh_addralign); + CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize); + + /* If this is a section with an extended index add a + reference in the section which uses the extended + index. */ + if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX + && shdr[cnt].sh_link < shnum) + elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index + = cnt; + + /* Set the own shndx_index field in case it has not yet + been set. */ + if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0) + elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index + = -1; } - - /* If the byte order of the file is not the same as the one - of the host convert the data now. */ - if (ehdr->e_ident[EI_DATA] != MY_ELFDATA) - for (size_t cnt = 0; cnt < shnum; ++cnt) - { - CONVERT (shdr[cnt].sh_name); - CONVERT (shdr[cnt].sh_type); - CONVERT (shdr[cnt].sh_flags); - CONVERT (shdr[cnt].sh_addr); - CONVERT (shdr[cnt].sh_offset); - CONVERT (shdr[cnt].sh_size); - CONVERT (shdr[cnt].sh_link); - CONVERT (shdr[cnt].sh_info); - CONVERT (shdr[cnt].sh_addralign); - CONVERT (shdr[cnt].sh_entsize); - } } - else + } + else if (likely (elf->fildes != -1)) + { + /* Read the header. */ + ssize_t n = pread_retry (elf->fildes, + elf->state.ELFW(elf,LIBELFBITS).shdr, size, + elf->start_offset + ehdr->e_shoff); + if (unlikely ((size_t) n != size)) { - /* The file descriptor was already enabled and not all data was - read. Undo the allocation. */ - __libelf_seterrno (ELF_E_FD_DISABLED); + /* Severe problems. We cannot read the data. */ + __libelf_seterrno (ELF_E_READ_ERROR); + goto free_and_out; + } - free_and_out: - free (shdr); - elf->state.ELFW(elf,LIBELFBITS).shdr = NULL; - elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0; + /* If the byte order of the file is not the same as the one + of the host convert the data now. */ + if (ehdr->e_ident[EI_DATA] != MY_ELFDATA) + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + CONVERT (shdr[cnt].sh_name); + CONVERT (shdr[cnt].sh_type); + CONVERT (shdr[cnt].sh_flags); + CONVERT (shdr[cnt].sh_addr); + CONVERT (shdr[cnt].sh_offset); + CONVERT (shdr[cnt].sh_size); + CONVERT (shdr[cnt].sh_link); + CONVERT (shdr[cnt].sh_info); + CONVERT (shdr[cnt].sh_addralign); + CONVERT (shdr[cnt].sh_entsize); + } + } + else + { + /* The file descriptor was already enabled and not all data was + read. Undo the allocation. */ + __libelf_seterrno (ELF_E_FD_DISABLED); - goto out; - } + free_and_out: + free (shdr); + elf->state.ELFW(elf,LIBELFBITS).shdr = NULL; + elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0; - /* Set the pointers in the `scn's. */ - for (size_t cnt = 0; cnt < shnum; ++cnt) - elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS) - = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt]; + goto out; + } - result = scn->shdr.ELFW(e,LIBELFBITS); - assert (result != NULL); + /* Set the pointers in the `scn's. */ + for (size_t cnt = 0; cnt < shnum; ++cnt) + elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS) + = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt]; + + result = scn->shdr.ELFW(e,LIBELFBITS); + assert (result != NULL); + +out: + return result; +} + +static bool +scn_valid (Elf_Scn *scn) +{ + if (scn == NULL) + return false; - out: - rwlock_from_wrlock (locked, &elf->lock); + if (unlikely (scn->elf->state.elf.ehdr == NULL)) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + return false; + } + + if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS))) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + return false; + } + + return true; +} + +ElfW2(LIBELFBITS,Shdr) * +__elfw2(LIBELFBITS,getshdr_rdlock) (scn) + Elf_Scn *scn; +{ + /* XXX: no read locking here, figure out why is it not necessary. */ + ElfW2(LIBELFBITS,Shdr) *result; + + if (!scn_valid (scn)) + return NULL; + + result = scn->shdr.ELFW(e,LIBELFBITS); + if (result == NULL) + { + rwlock_unlock (scn->elf->lock); + rwlock_wrlock (scn->elf->lock); + result = scn->shdr.ELFW(e,LIBELFBITS); + if (result == NULL) + result = load_shdr_rwlock (scn); } return result; } ElfW2(LIBELFBITS,Shdr) * +__elfw2(LIBELFBITS,getshdr_wrlock) (scn) + Elf_Scn *scn; +{ + ElfW2(LIBELFBITS,Shdr) *result; + + if (!scn_valid (scn)) + return NULL; + + result = scn->shdr.ELFW(e,LIBELFBITS); + if (result == NULL) + result = load_shdr_rwlock (scn); + + return result; +} + +ElfW2(LIBELFBITS,Shdr) * elfw2(LIBELFBITS,getshdr) (scn) Elf_Scn *scn; { - return __elfw2(LIBELFBITS,getshdr_internal) (scn, LS_UNLOCKED); + ElfW2(LIBELFBITS,Shdr) *result; + + if (!scn_valid (scn)) + return NULL; + + rwlock_rdlock (scn->elf->lock); + result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn); + rwlock_unlock (scn->elf->lock); + + return result; } |
