105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh/* Return converted data from raw chunk of ELF file. 205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh Copyright (C) 2007, 2014, 2015 Red Hat, Inc. 305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh This file is part of elfutils. 405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh This file is free software; you can redistribute it and/or modify 605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh it under the terms of either 705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh * the GNU Lesser General Public License as published by the Free 905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh Software Foundation; either version 3 of the License, or (at 1005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh your option) any later version 1105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 1205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh or 13b158b93a7d941a52bedd64ca6b78ff18de9b6ca3Nguyen Anh Quynh 1405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh * the GNU General Public License as published by the Free 1505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh Software Foundation; either version 2 of the License, or (at 1605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh your option) any later version 1705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 1805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh or both in parallel, as here. 1905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 2005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh elfutils is distributed in the hope that it will be useful, but 2105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh WITHOUT ANY WARRANTY; without even the implied warranty of 2205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh General Public License for more details. 2405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 2505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh You should have received copies of the GNU General Public License and 2605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh the GNU Lesser General Public License along with this program. If 2705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh not, see <http://www.gnu.org/licenses/>. */ 2805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 2905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#ifdef HAVE_CONFIG_H 3005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh# include <config.h> 3105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#endif 3205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 3305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <assert.h> 3405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <errno.h> 3505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <stdlib.h> 3605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <string.h> 3705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <unistd.h> 3805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 3905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include <system.h> 40159ddbd99fae8c435f815aa5251bb6466160cb91Nguyen Anh Quynh#include "libelfP.h" 4105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh#include "common.h" 4205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 4305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh QuynhElf_Data * 4405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynhelf_getdata_rawchunk (Elf *elf, off_t offset, size_t size, Elf_Type type) 4505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh{ 4605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (unlikely (elf == NULL)) 4705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh return NULL; 4805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 4905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (unlikely (elf->kind != ELF_K_ELF)) 5005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 5105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* No valid descriptor. */ 5205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh __libelf_seterrno (ELF_E_INVALID_HANDLE); 5305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh return NULL; 5405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 5505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 5605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size 5705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh || elf->maximum_size - (uint64_t) offset < size)) 5805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 5905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 6005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* Invalid request. */ 6105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh __libelf_seterrno (ELF_E_INVALID_OP); 6205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh return NULL; 6305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 6405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 6505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (type >= ELF_T_NUM) 6605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 6705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh __libelf_seterrno (ELF_E_UNKNOWN_TYPE); 6805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh return NULL; 6905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 7005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 7105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* Get the raw bytes from the file. */ 7205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh void *rawchunk; 7305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh int flags = 0; 7405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh Elf_Data *result = NULL; 7505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 7605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh rwlock_rdlock (elf->lock); 7705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 7805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh size_t align = __libelf_type_align (elf->class, type); 7905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (elf->map_address != NULL) 8005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 8105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* If the file is mmap'ed we can use it directly, if aligned for type. */ 8205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh char *rawdata = elf->map_address + elf->start_offset + offset; 8305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (ALLOW_UNALIGNED || 8405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh ((uintptr_t) rawdata & (align - 1)) == 0) 8505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh rawchunk = rawdata; 8605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh else 8705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 8805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* We allocate the memory and memcpy it to get aligned data. */ 8905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh rawchunk = malloc (size); 9005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (rawchunk == NULL) 9105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh goto nomem; 9205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh memcpy (rawchunk, rawdata, size); 9305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh flags = ELF_F_MALLOCED; 9405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 9505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 9605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh else 9705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 9805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* We allocate the memory and read the data from the file. */ 9905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh rawchunk = malloc (size); 10005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (rawchunk == NULL) 10105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 10205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh nomem: 10305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh __libelf_seterrno (ELF_E_NOMEM); 10405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh goto out; 10505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 10605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 10705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* Read the file content. */ 10805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size, 10905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh elf->start_offset + offset) 11005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh != size)) 11105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 11205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* Something went wrong. */ 11305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh free (rawchunk); 11405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh __libelf_seterrno (ELF_E_READ_ERROR); 11505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh goto out; 11605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 11705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 11805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh flags = ELF_F_MALLOCED; 11905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 12005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 12105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* Copy and/or convert the data as needed for aligned native-order access. */ 12205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh void *buffer; 12305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA) 12405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 12505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (((uintptr_t) rawchunk & (align - 1)) == 0) 12605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* No need to copy, we can use the raw data. */ 12705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh buffer = rawchunk; 12805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh else 12905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 13005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* A malloc'd block is always sufficiently aligned. */ 13105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh assert (flags == 0); 13205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 13305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh buffer = malloc (size); 13405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (unlikely (buffer == NULL)) 13505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh goto nomem; 13605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh flags = ELF_F_MALLOCED; 13705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 13805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* The copy will be appropriately aligned for direct access. */ 13905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh memcpy (buffer, rawchunk, size); 14005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 14105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 14205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh else 14305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 14405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (flags) 14505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh buffer = rawchunk; 14605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh else 14705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 14805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh buffer = malloc (size); 14905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (unlikely (buffer == NULL)) 15005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh goto nomem; 15105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh flags = ELF_F_MALLOCED; 15205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 15305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 15405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* Call the conversion function. */ 15505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh (*__elf_xfctstom[LIBELF_EV_IDX][LIBELF_EV_IDX][elf->class - 1][type]) 15605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh (buffer, rawchunk, size, 0); 15705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 15805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 15905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh /* Allocate the dummy container to point at this buffer. */ 16005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk); 16105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (chunk == NULL) 16205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh { 16305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh if (flags) 16405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh free (buffer); 16505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh goto nomem; 16605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh } 16705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 16805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh chunk->dummy_scn.elf = elf; 16905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh chunk->dummy_scn.flags = flags; 17005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh chunk->data.s = &chunk->dummy_scn; 17105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh chunk->data.d.d_buf = buffer; 17205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh chunk->data.d.d_size = size; 17305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh chunk->data.d.d_type = type; 17405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh chunk->data.d.d_align = align; 17505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh chunk->data.d.d_version = __libelf_version; 17605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 17705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh rwlock_unlock (elf->lock); 17805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh rwlock_wrlock (elf->lock); 17905e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 18005e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh chunk->next = elf->state.elf.rawchunks; 18105e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh elf->state.elf.rawchunks = chunk; 18205e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh result = &chunk->data.d; 18305e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh 18405e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh out: 18505e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh rwlock_unlock (elf->lock); 18605e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh return result; 18705e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh} 18805e27138aef5dea54576d2916d92d2f7bd1f3956Nguyen Anh Quynh