summaryrefslogtreecommitdiffstats
path: root/libelf/elf32_getshdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'libelf/elf32_getshdr.c')
-rw-r--r--libelf/elf32_getshdr.c340
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;
}