diff options
| author | Ulrich Drepper <[email protected]> | 2005-08-29 16:27:10 +0000 |
|---|---|---|
| committer | Ulrich Drepper <[email protected]> | 2005-08-29 16:27:10 +0000 |
| commit | fbe998a0b1be1f006bc72e5138fb38c188cc0433 (patch) | |
| tree | bc00ddfec68454b8987056fbc1f1ace2da2597fa /libelf/elf_begin.c | |
| parent | b0bc2788cfa2012bfbcc68cac74cd39e3f5a8085 (diff) | |
merge of 333c187506c852455e9f7be44fa9adc360416217
and 79955b942e3f0ddc71117feea5754df61edcc42a
Diffstat (limited to 'libelf/elf_begin.c')
| -rw-r--r-- | libelf/elf_begin.c | 294 |
1 files changed, 123 insertions, 171 deletions
diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c index c4b33595..c21a52b5 100644 --- a/libelf/elf_begin.c +++ b/libelf/elf_begin.c @@ -31,6 +31,7 @@ #include <sys/param.h> #include <sys/stat.h> +#include <system.h> #include "libelfP.h" #include "common.h" @@ -77,41 +78,40 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset, bool is32 = e_ident[EI_CLASS] == ELFCLASS32; /* Make the ELF header available. */ - if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA - && (ALLOW_UNALIGNED - || (((size_t) ((char *) map_address + offset)) - & ((is32 ? __alignof__ (Elf32_Ehdr) : __alignof__ (Elf64_Ehdr)) - - 1)) == 0)) - ehdr.p = (char *) map_address + offset; + if (e_ident[EI_DATA] == MY_ELFDATA) + ehdr.p = e_ident; else { - /* We have to read the data from the file. */ - size_t len = is32 ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr); + /* We already read the ELF header. We have to copy the header + since we possibly modify the data here and the caller + expects the memory it passes in to be preserved. */ + ehdr.p = &ehdr_mem; - if (likely (map_address != NULL)) - ehdr.p = memcpy (&ehdr_mem, (char *) map_address + offset, len); - else - { - /* Fill it. */ - if ((size_t) TEMP_FAILURE_RETRY (pread (fildes, &ehdr_mem, len, - offset)) != len) - /* Failed reading. */ - return (size_t) -1l; - ehdr.p = &ehdr_mem; - } - - if (e_ident[EI_DATA] != MY_ELFDATA) + if (is32) { - if (is32) + if (ALLOW_UNALIGNED) { - CONVERT (ehdr.e32->e_shnum); - CONVERT (ehdr.e32->e_shoff); + ehdr_mem.e32.e_shnum = ((Elf32_Ehdr *) e_ident)->e_shnum; + ehdr_mem.e32.e_shoff = ((Elf32_Ehdr *) e_ident)->e_shoff; } else + memcpy (&ehdr_mem, e_ident, sizeof (Elf32_Ehdr)); + + CONVERT (ehdr_mem.e32.e_shnum); + CONVERT (ehdr_mem.e32.e_shoff); + } + else + { + if (ALLOW_UNALIGNED) { - CONVERT (ehdr.e64->e_shnum); - CONVERT (ehdr.e64->e_shoff); + ehdr_mem.e64.e_shnum = ((Elf64_Ehdr *) e_ident)->e_shnum; + ehdr_mem.e64.e_shoff = ((Elf64_Ehdr *) e_ident)->e_shoff; } + else + memcpy (&ehdr_mem, e_ident, sizeof (Elf64_Ehdr)); + + CONVERT (ehdr_mem.e64.e_shnum); + CONVERT (ehdr_mem.e64.e_shoff); } } @@ -145,12 +145,10 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset, + offset))->sh_size, sizeof (Elf32_Word)); else - if (TEMP_FAILURE_RETRY (pread (fildes, &size, - sizeof (Elf32_Word), - offset + ehdr.e32->e_shoff - + offsetof (Elf32_Shdr, - sh_size))) - != sizeof (Elf32_Word)) + if (unlikely (pread_retry (fildes, &size, sizeof (Elf32_Word), + offset + ehdr.e32->e_shoff + + offsetof (Elf32_Shdr, sh_size)) + != sizeof (Elf32_Word))) return (size_t) -1l; if (e_ident[EI_DATA] != MY_ELFDATA) @@ -189,12 +187,10 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset, + offset))->sh_size, sizeof (Elf64_Xword)); else - if (TEMP_FAILURE_RETRY (pread (fildes, &size, - sizeof (Elf64_Word), - offset + ehdr.e64->e_shoff - + offsetof (Elf64_Shdr, - sh_size))) - != sizeof (Elf64_Xword)) + if (unlikely (pread_retry (fildes, &size, sizeof (Elf64_Word), + offset + ehdr.e64->e_shoff + + offsetof (Elf64_Shdr, sh_size)) + != sizeof (Elf64_Xword))) return (size_t) -1l; if (e_ident[EI_DATA] != MY_ELFDATA) @@ -215,37 +211,15 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset, /* Create descriptor for ELF file in memory. */ static Elf * -file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, - Elf_Cmd cmd, Elf *parent) +file_read_elf (int fildes, void *map_address, unsigned char *e_ident, + off_t offset, size_t maxsize, Elf_Cmd cmd, Elf *parent) { - /* We only read the ELF header now. */ - unsigned char *e_ident; - unsigned char e_ident_mem[EI_NIDENT]; - size_t scncnt; - Elf *elf; - - if (map_address != NULL) - /* It's right at the beginning of the file. No word access - required, just bytes. */ - e_ident = (unsigned char *) map_address + offset; - else - { - e_ident = e_ident_mem; - - if (TEMP_FAILURE_RETRY (pread (fildes, e_ident, EI_NIDENT, offset)) - != EI_NIDENT) - { - __libelf_seterrno (ELF_E_READ_ERROR); - return NULL; - } - } - /* Verify the binary is of the class we can handle. */ - if ((e_ident[EI_CLASS] != ELFCLASS32 - && e_ident[EI_CLASS] != ELFCLASS64) - /* We also can only handle two encodings. */ - || (e_ident[EI_DATA] != ELFDATA2LSB - && e_ident[EI_DATA] != ELFDATA2MSB)) + if (unlikely ((e_ident[EI_CLASS] != ELFCLASS32 + && e_ident[EI_CLASS] != ELFCLASS64) + /* We also can only handle two encodings. */ + || (e_ident[EI_DATA] != ELFDATA2LSB + && e_ident[EI_DATA] != ELFDATA2MSB))) { /* Cannot handle this. */ __libelf_seterrno (ELF_E_INVALID_FILE); @@ -253,14 +227,14 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, } /* Determine the number of sections. */ - scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize); + size_t scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize); if (scncnt == (size_t) -1l) /* Could not determine the number of sections. */ return NULL; /* We can now allocate the memory. */ - elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, - ELF_K_ELF, scncnt * sizeof (Elf_Scn)); + Elf *elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, + ELF_K_ELF, scncnt * sizeof (Elf_Scn)); if (elf == NULL) /* Not enough memory. */ return NULL; @@ -268,6 +242,9 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, /* Some more or less arbitrary value. */ elf->state.elf.scnincr = 10; + /* Make the class easily available. */ + elf->class = e_ident[EI_CLASS]; + if (e_ident[EI_CLASS] == ELFCLASS32) { /* This pointer might not be directly usable if the alignment is @@ -287,17 +264,14 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, & (__alignof__ (Elf32_Phdr) - 1)) == 0))) { /* We can use the mmapped memory. */ - elf->state.elf32.ehdr = - (Elf32_Ehdr *) ((char *) map_address + offset); - elf->state.elf32.shdr = - (Elf32_Shdr *) ((char *) map_address + offset - + elf->state.elf32.ehdr->e_shoff); - if (elf->state.elf32.ehdr->e_phnum) + elf->state.elf32.ehdr = ehdr; + elf->state.elf32.shdr + = (Elf32_Shdr *) ((char *) ehdr + ehdr->e_shoff); + if (ehdr->e_phnum > 0) /* Assign a value only if there really is a program header. Otherwise the value remains NULL. */ elf->state.elf32.phdr - = (Elf32_Phdr *) ((char *) map_address + offset - + elf->state.elf32.ehdr->e_phoff); + = (Elf32_Phdr *) ((char *) ehdr + ehdr->e_phoff); for (size_t cnt = 0; cnt < scncnt; ++cnt) { @@ -314,21 +288,9 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, } else { - if (likely (map_address != NULL)) - /* Copy the data. */ - memcpy (&elf->state.elf32.ehdr_mem, - (char *) map_address + offset, sizeof (Elf32_Ehdr)); - else - /* Read the data. */ - if (TEMP_FAILURE_RETRY (pread (elf->fildes, - &elf->state.elf32.ehdr_mem, - sizeof (Elf32_Ehdr), offset)) - != sizeof (Elf32_Ehdr)) - { - /* We must be able to read the ELF header. */ - __libelf_seterrno (ELF_E_INVALID_FILE); - return NULL; - } + /* Copy the ELF header. */ + elf->state.elf32.ehdr = memcpy (&elf->state.elf32.ehdr_mem, e_ident, + sizeof (Elf32_Ehdr)); if (e_ident[EI_DATA] != MY_ELFDATA) { @@ -347,8 +309,6 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, CONVERT (elf->state.elf32.ehdr_mem.e_shstrndx); } - elf->state.elf32.ehdr = &elf->state.elf32.ehdr_mem; - for (size_t cnt = 0; cnt < scncnt; ++cnt) { elf->state.elf32.scns.data[cnt].index = cnt; @@ -379,17 +339,14 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, & (__alignof__ (Elf64_Phdr) - 1)) == 0))) { /* We can use the mmapped memory. */ - elf->state.elf64.ehdr = - (Elf64_Ehdr *) ((char *) map_address + offset); - elf->state.elf64.shdr = - (Elf64_Shdr *) ((char *) map_address + offset - + elf->state.elf64.ehdr->e_shoff); - if (elf->state.elf64.ehdr->e_phnum) + elf->state.elf64.ehdr = ehdr; + elf->state.elf64.shdr + = (Elf64_Shdr *) ((char *) ehdr + ehdr->e_shoff); + if (ehdr->e_phnum > 0) /* Assign a value only if there really is a program header. Otherwise the value remains NULL. */ elf->state.elf64.phdr - = (Elf64_Phdr *) ((char *) map_address + offset - + elf->state.elf64.ehdr->e_phoff); + = (Elf64_Phdr *) ((char *) ehdr + ehdr->e_phoff); for (size_t cnt = 0; cnt < scncnt; ++cnt) { @@ -406,21 +363,9 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, } else { - if (likely (map_address != NULL)) - /* Copy the data. */ - memcpy (&elf->state.elf64.ehdr_mem, - (char *) map_address + offset, sizeof (Elf64_Ehdr)); - else - /* Read the data. */ - if (TEMP_FAILURE_RETRY (pread (elf->fildes, - &elf->state.elf64.ehdr_mem, - sizeof (Elf64_Ehdr), offset)) - != sizeof (Elf64_Ehdr)) - { - /* We must be able to read the ELF header. */ - __libelf_seterrno (ELF_E_INVALID_FILE); - return NULL; - } + /* Copy the ELF header. */ + elf->state.elf64.ehdr = memcpy (&elf->state.elf64.ehdr_mem, e_ident, + sizeof (Elf64_Ehdr)); if (e_ident[EI_DATA] != MY_ELFDATA) { @@ -439,8 +384,6 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, CONVERT (elf->state.elf64.ehdr_mem.e_shstrndx); } - elf->state.elf64.ehdr = &elf->state.elf64.ehdr_mem; - for (size_t cnt = 0; cnt < scncnt; ++cnt) { elf->state.elf64.scns.data[cnt].index = cnt; @@ -453,9 +396,6 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize, elf->state.elf64.scns_last = &elf->state.elf64.scns; } - /* Make the class easily available. */ - elf->class = e_ident[EI_CLASS]; - return elf; } @@ -469,15 +409,16 @@ __libelf_read_mmaped_file (int fildes, void *map_address, off_t offset, files and archives. To find out what we have we must look at the header. The header for an ELF file is EI_NIDENT bytes in size, the header for an archive file SARMAG bytes long. */ - Elf_Kind kind; + unsigned char *e_ident = (unsigned char *) map_address + offset; /* See what kind of object we have here. */ - kind = determine_kind (map_address + offset, maxsize); + Elf_Kind kind = determine_kind (e_ident, maxsize); switch (kind) { case ELF_K_ELF: - return file_read_elf (fildes, map_address, offset, maxsize, cmd, parent); + return file_read_elf (fildes, map_address, e_ident, offset, maxsize, + cmd, parent); case ELF_K_AR: return file_read_ar (fildes, map_address, offset, maxsize, cmd, parent); @@ -499,25 +440,33 @@ read_unmmaped_file (int fildes, off_t offset, size_t maxsize, Elf_Cmd cmd, { /* We have to find out what kind of file this is. We handle ELF files and archives. To find out what we have we must read the - header. The header for an ELF file is EI_NIDENT bytes in size, - the header for an archive file SARMAG bytes long. Read the - maximum of these numbers. + header. The identification header for an ELF file is EI_NIDENT + bytes in size, but we read the whole ELF header since we will + need it anyway later. For archives the header in SARMAG bytes + long. Read the maximum of these numbers. + + XXX We have to change this for the extended `ar' format some day. - XXX We have to change this for the extended `ar' format some day. */ - unsigned char header[MAX (EI_NIDENT, SARMAG)]; - ssize_t nread; - Elf_Kind kind; + Use a union to ensure alignment. We might later access the + memory as a ElfXX_Ehdr. */ + union + { + Elf64_Ehdr ehdr; + unsigned char header[MAX (sizeof (Elf64_Ehdr), SARMAG)]; + } mem; /* Read the head of the file. */ - nread = pread (fildes, header, MIN (MAX (EI_NIDENT, SARMAG), maxsize), - offset); - if (nread == -1) + ssize_t nread = pread_retry (fildes, mem.header, + MIN (MAX (sizeof (Elf64_Ehdr), SARMAG), + maxsize), + offset); + if (unlikely (nread == -1)) /* We cannot even read the head of the file. Maybe FILDES is associated with an unseekable device. This is nothing we can handle. */ return NULL; /* See what kind of object we have here. */ - kind = determine_kind (header, nread); + Elf_Kind kind = determine_kind (mem.header, nread); switch (kind) { @@ -526,9 +475,10 @@ read_unmmaped_file (int fildes, off_t offset, size_t maxsize, Elf_Cmd cmd, case ELF_K_ELF: /* Make sure at least the ELF header is contained in the file. */ - if (maxsize >= (header[EI_CLASS] == ELFCLASS32 - ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))) - return file_read_elf (fildes, NULL, offset, maxsize, cmd, parent); + if ((size_t) nread >= (mem.header[EI_CLASS] == ELFCLASS32 + ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))) + return file_read_elf (fildes, NULL, mem.header, offset, maxsize, cmd, + parent); /* FALLTHROUGH */ default: @@ -596,10 +546,11 @@ read_file (int fildes, off_t offset, size_t maxsize, /* If we have the file in memory optimize the access. */ if (map_address != NULL) { - struct Elf *result; + assert (map_address != MAP_FAILED); - result = __libelf_read_mmaped_file (fildes, map_address, offset, maxsize, - cmd, parent); + struct Elf *result = __libelf_read_mmaped_file (fildes, map_address, + offset, maxsize, cmd, + parent); /* If something went wrong during the initialization unmap the memory if we mmaped here. */ @@ -643,8 +594,9 @@ read_long_names (Elf *elf) else { /* Read the header from the file. */ - if (pread (elf->fildes, &hdrm, sizeof (hdrm), - elf->start_offset + offset) != sizeof (hdrm)) + if (unlikely (pread_retry (elf->fildes, &hdrm, sizeof (hdrm), + elf->start_offset + offset) + != sizeof (hdrm))) return NULL; hdr = &hdrm; @@ -674,10 +626,10 @@ read_long_names (Elf *elf) len); else { - if ((size_t) pread (elf->fildes, newp, len, - elf->start_offset + offset - + sizeof (struct ar_hdr)) - != len) + if (unlikely ((size_t) pread_retry (elf->fildes, newp, len, + elf->start_offset + offset + + sizeof (struct ar_hdr)) + != len)) { /* We were not able to read all data. */ free (newp); @@ -727,8 +679,8 @@ __libelf_next_arhdr (elf) if (elf->map_address != NULL) { /* See whether this entry is in the file. */ - if (elf->state.ar.offset + sizeof (struct ar_hdr) - > elf->start_offset + elf->maximum_size) + if (unlikely (elf->state.ar.offset + sizeof (struct ar_hdr) + > elf->start_offset + elf->maximum_size)) { /* This record is not anymore in the file. */ __libelf_seterrno (ELF_E_RANGE); @@ -740,10 +692,9 @@ __libelf_next_arhdr (elf) { ar_hdr = &elf->state.ar.ar_hdr; - if (TEMP_FAILURE_RETRY (pread (elf->fildes, ar_hdr, - sizeof (struct ar_hdr), - elf->state.ar.offset)) - != sizeof (struct ar_hdr)) + if (unlikely (pread_retry (elf->fildes, ar_hdr, sizeof (struct ar_hdr), + elf->state.ar.offset) + != sizeof (struct ar_hdr))) { /* Something went wrong while reading the file. */ __libelf_seterrno (ELF_E_RANGE); @@ -752,7 +703,7 @@ __libelf_next_arhdr (elf) } /* One little consistency check. */ - if (memcmp (ar_hdr->ar_fmag, ARFMAG, 2) != 0) + if (unlikely (memcmp (ar_hdr->ar_fmag, ARFMAG, 2) != 0)) { /* This is no valid archive. */ __libelf_seterrno (ELF_E_ARCHIVE_FMAG); @@ -776,14 +727,14 @@ __libelf_next_arhdr (elf) && memcmp (ar_hdr->ar_name, "// ", 16) == 0) /* This is the array with the long names. */ elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "//", 3); - else if (isdigit (ar_hdr->ar_name[1])) + else if (likely (isdigit (ar_hdr->ar_name[1]))) { size_t offset; /* This is a long name. First we have to read the long name table, if this hasn't happened already. */ - if (elf->state.ar.long_names == NULL - && read_long_names (elf) == NULL) + if (unlikely (elf->state.ar.long_names == NULL + && read_long_names (elf) == NULL)) { /* No long name table although it is reference. The archive is broken. */ @@ -792,7 +743,7 @@ __libelf_next_arhdr (elf) } offset = atol (ar_hdr->ar_name + 1); - if (offset >= elf->state.ar.long_names_len) + if (unlikely (offset >= elf->state.ar.long_names_len)) { /* The index in the long name table is larger than the table. */ __libelf_seterrno (ELF_E_INVALID_ARCHIVE); @@ -906,7 +857,7 @@ __libelf_next_arhdr (elf) if (ar_hdr->ar_size[sizeof (ar_hdr->ar_size) - 1] == ' ') { - if (ar_hdr->ar_size[0] == ' ') + if (unlikely (ar_hdr->ar_size[0] == ' ')) /* Something is really wrong. We cannot live without a size for the member since it will not be possible to find the next archive member. */ @@ -946,7 +897,7 @@ dup_elf (int fildes, Elf_Cmd cmd, Elf *ref) fildes = ref->fildes; /* The file descriptor better should be the same. If it was disconnected already (using `elf_cntl') we do not test it. */ - else if (ref->fildes != -1 && fildes != ref->fildes) + else if (unlikely (ref->fildes != -1 && fildes != ref->fildes)) { __libelf_seterrno (ELF_E_FD_MISMATCH); return NULL; @@ -955,10 +906,10 @@ dup_elf (int fildes, Elf_Cmd cmd, Elf *ref) /* The mode must allow reading. I.e., a descriptor creating with a command different then ELF_C_READ, ELF_C_WRITE and ELF_C_RDWR is not allowed. */ - if (ref->cmd != ELF_C_READ && ref->cmd != ELF_C_READ_MMAP - && ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP - && ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP - && ref->cmd != ELF_C_READ_MMAP_PRIVATE) + if (unlikely (ref->cmd != ELF_C_READ && ref->cmd != ELF_C_READ_MMAP + && ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP + && ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP + && ref->cmd != ELF_C_READ_MMAP_PRIVATE)) { __libelf_seterrno (ELF_E_INVALID_OP); return NULL; @@ -1035,7 +986,7 @@ elf_begin (fildes, cmd, ref) { Elf *retval; - if (! __libelf_version_initialized) + if (unlikely (! __libelf_version_initialized)) { /* Version wasn't set so far. */ __libelf_seterrno (ELF_E_NO_VERSION); @@ -1045,7 +996,7 @@ elf_begin (fildes, cmd, ref) if (ref != NULL) /* Make sure the descriptor is not suddenly going away. */ rwlock_rdlock (ref->lock); - else if (fcntl (fildes, F_GETFL) == -1 && errno == EBADF) + else if (unlikely (fcntl (fildes, F_GETFL) == -1 && errno == EBADF)) { /* We cannot do anything productive without a file descriptor. */ __libelf_seterrno (ELF_E_INVALID_FILE); @@ -1061,7 +1012,7 @@ elf_begin (fildes, cmd, ref) case ELF_C_READ_MMAP_PRIVATE: /* If we have a reference it must also be opened this way. */ - if (ref != NULL && ref->cmd != ELF_C_READ_MMAP_PRIVATE) + if (unlikely (ref != NULL && ref->cmd != ELF_C_READ_MMAP_PRIVATE)) { __libelf_seterrno (ELF_E_INVALID_CMD); retval = NULL; @@ -1085,8 +1036,9 @@ elf_begin (fildes, cmd, ref) command. */ if (ref != NULL) { - if (ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP - && ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP) + if (unlikely (ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP + && ref->cmd != ELF_C_WRITE + && ref->cmd != ELF_C_WRITE_MMAP)) { /* This is not ok. REF must also be opened for writing. */ __libelf_seterrno (ELF_E_INVALID_CMD); |
