1da0c48c4Sopenharmony_ci/* Return converted data from raw chunk of ELF file. 2da0c48c4Sopenharmony_ci Copyright (C) 2007, 2014, 2015 Red Hat, Inc. 3da0c48c4Sopenharmony_ci Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org> 4da0c48c4Sopenharmony_ci This file is part of elfutils. 5da0c48c4Sopenharmony_ci 6da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 7da0c48c4Sopenharmony_ci it under the terms of either 8da0c48c4Sopenharmony_ci 9da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 10da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 11da0c48c4Sopenharmony_ci your option) any later version 12da0c48c4Sopenharmony_ci 13da0c48c4Sopenharmony_ci or 14da0c48c4Sopenharmony_ci 15da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 16da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 17da0c48c4Sopenharmony_ci your option) any later version 18da0c48c4Sopenharmony_ci 19da0c48c4Sopenharmony_ci or both in parallel, as here. 20da0c48c4Sopenharmony_ci 21da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 22da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 23da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24da0c48c4Sopenharmony_ci General Public License for more details. 25da0c48c4Sopenharmony_ci 26da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 27da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 28da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 29da0c48c4Sopenharmony_ci 30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 31da0c48c4Sopenharmony_ci# include <config.h> 32da0c48c4Sopenharmony_ci#endif 33da0c48c4Sopenharmony_ci 34da0c48c4Sopenharmony_ci#include <assert.h> 35da0c48c4Sopenharmony_ci#include <errno.h> 36da0c48c4Sopenharmony_ci#include <stdlib.h> 37da0c48c4Sopenharmony_ci#include <string.h> 38da0c48c4Sopenharmony_ci 39da0c48c4Sopenharmony_ci#include "libelfP.h" 40da0c48c4Sopenharmony_ci#include "common.h" 41da0c48c4Sopenharmony_ci 42da0c48c4Sopenharmony_ciElf_Data * 43da0c48c4Sopenharmony_cielf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type) 44da0c48c4Sopenharmony_ci{ 45da0c48c4Sopenharmony_ci if (unlikely (elf == NULL)) 46da0c48c4Sopenharmony_ci return NULL; 47da0c48c4Sopenharmony_ci 48da0c48c4Sopenharmony_ci if (unlikely (elf->kind != ELF_K_ELF)) 49da0c48c4Sopenharmony_ci { 50da0c48c4Sopenharmony_ci /* No valid descriptor. */ 51da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_HANDLE); 52da0c48c4Sopenharmony_ci return NULL; 53da0c48c4Sopenharmony_ci } 54da0c48c4Sopenharmony_ci 55da0c48c4Sopenharmony_ci if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size 56da0c48c4Sopenharmony_ci || elf->maximum_size - (uint64_t) offset < size)) 57da0c48c4Sopenharmony_ci 58da0c48c4Sopenharmony_ci { 59da0c48c4Sopenharmony_ci /* Invalid request. */ 60da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_OP); 61da0c48c4Sopenharmony_ci return NULL; 62da0c48c4Sopenharmony_ci } 63da0c48c4Sopenharmony_ci 64da0c48c4Sopenharmony_ci if (type >= ELF_T_NUM) 65da0c48c4Sopenharmony_ci { 66da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_UNKNOWN_TYPE); 67da0c48c4Sopenharmony_ci return NULL; 68da0c48c4Sopenharmony_ci } 69da0c48c4Sopenharmony_ci 70da0c48c4Sopenharmony_ci /* Get the raw bytes from the file. */ 71da0c48c4Sopenharmony_ci void *rawchunk; 72da0c48c4Sopenharmony_ci int flags = 0; 73da0c48c4Sopenharmony_ci Elf_Data *result = NULL; 74da0c48c4Sopenharmony_ci 75da0c48c4Sopenharmony_ci rwlock_rdlock (elf->lock); 76da0c48c4Sopenharmony_ci 77da0c48c4Sopenharmony_ci /* Maybe we already got this chunk? */ 78da0c48c4Sopenharmony_ci Elf_Data_Chunk *rawchunks = elf->state.elf.rawchunks; 79da0c48c4Sopenharmony_ci while (rawchunks != NULL) 80da0c48c4Sopenharmony_ci { 81da0c48c4Sopenharmony_ci if ((rawchunks->offset == offset || size == 0) 82da0c48c4Sopenharmony_ci && rawchunks->data.d.d_size == size 83da0c48c4Sopenharmony_ci && rawchunks->data.d.d_type == type) 84da0c48c4Sopenharmony_ci { 85da0c48c4Sopenharmony_ci result = &rawchunks->data.d; 86da0c48c4Sopenharmony_ci goto out; 87da0c48c4Sopenharmony_ci } 88da0c48c4Sopenharmony_ci rawchunks = rawchunks->next; 89da0c48c4Sopenharmony_ci } 90da0c48c4Sopenharmony_ci 91da0c48c4Sopenharmony_ci size_t align = __libelf_type_align (elf->class, type); 92da0c48c4Sopenharmony_ci if (elf->map_address != NULL) 93da0c48c4Sopenharmony_ci { 94da0c48c4Sopenharmony_ci /* If the file is mmap'ed we can use it directly, if aligned for type. */ 95da0c48c4Sopenharmony_ci char *rawdata = elf->map_address + elf->start_offset + offset; 96da0c48c4Sopenharmony_ci if (((uintptr_t) rawdata & (align - 1)) == 0) 97da0c48c4Sopenharmony_ci rawchunk = rawdata; 98da0c48c4Sopenharmony_ci else 99da0c48c4Sopenharmony_ci { 100da0c48c4Sopenharmony_ci /* We allocate the memory and memcpy it to get aligned data. */ 101da0c48c4Sopenharmony_ci rawchunk = malloc (size); 102da0c48c4Sopenharmony_ci if (rawchunk == NULL) 103da0c48c4Sopenharmony_ci goto nomem; 104da0c48c4Sopenharmony_ci memcpy (rawchunk, rawdata, size); 105da0c48c4Sopenharmony_ci flags = ELF_F_MALLOCED; 106da0c48c4Sopenharmony_ci } 107da0c48c4Sopenharmony_ci } 108da0c48c4Sopenharmony_ci else 109da0c48c4Sopenharmony_ci { 110da0c48c4Sopenharmony_ci /* We allocate the memory and read the data from the file. */ 111da0c48c4Sopenharmony_ci rawchunk = malloc (size); 112da0c48c4Sopenharmony_ci if (rawchunk == NULL) 113da0c48c4Sopenharmony_ci { 114da0c48c4Sopenharmony_ci nomem: 115da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_NOMEM); 116da0c48c4Sopenharmony_ci goto out; 117da0c48c4Sopenharmony_ci } 118da0c48c4Sopenharmony_ci 119da0c48c4Sopenharmony_ci /* Read the file content. */ 120da0c48c4Sopenharmony_ci if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size, 121da0c48c4Sopenharmony_ci elf->start_offset + offset) 122da0c48c4Sopenharmony_ci != size)) 123da0c48c4Sopenharmony_ci { 124da0c48c4Sopenharmony_ci /* Something went wrong. */ 125da0c48c4Sopenharmony_ci free (rawchunk); 126da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_READ_ERROR); 127da0c48c4Sopenharmony_ci goto out; 128da0c48c4Sopenharmony_ci } 129da0c48c4Sopenharmony_ci 130da0c48c4Sopenharmony_ci flags = ELF_F_MALLOCED; 131da0c48c4Sopenharmony_ci } 132da0c48c4Sopenharmony_ci 133da0c48c4Sopenharmony_ci /* Copy and/or convert the data as needed for aligned native-order access. */ 134da0c48c4Sopenharmony_ci void *buffer; 135da0c48c4Sopenharmony_ci if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA) 136da0c48c4Sopenharmony_ci { 137da0c48c4Sopenharmony_ci if (((uintptr_t) rawchunk & (align - 1)) == 0) 138da0c48c4Sopenharmony_ci /* No need to copy, we can use the raw data. */ 139da0c48c4Sopenharmony_ci buffer = rawchunk; 140da0c48c4Sopenharmony_ci else 141da0c48c4Sopenharmony_ci { 142da0c48c4Sopenharmony_ci /* A malloc'd block is always sufficiently aligned. */ 143da0c48c4Sopenharmony_ci assert (flags == 0); 144da0c48c4Sopenharmony_ci 145da0c48c4Sopenharmony_ci buffer = malloc (size); 146da0c48c4Sopenharmony_ci if (unlikely (buffer == NULL)) 147da0c48c4Sopenharmony_ci goto nomem; 148da0c48c4Sopenharmony_ci flags = ELF_F_MALLOCED; 149da0c48c4Sopenharmony_ci 150da0c48c4Sopenharmony_ci /* The copy will be appropriately aligned for direct access. */ 151da0c48c4Sopenharmony_ci memcpy (buffer, rawchunk, size); 152da0c48c4Sopenharmony_ci } 153da0c48c4Sopenharmony_ci } 154da0c48c4Sopenharmony_ci else 155da0c48c4Sopenharmony_ci { 156da0c48c4Sopenharmony_ci if (flags) 157da0c48c4Sopenharmony_ci buffer = rawchunk; 158da0c48c4Sopenharmony_ci else 159da0c48c4Sopenharmony_ci { 160da0c48c4Sopenharmony_ci buffer = malloc (size); 161da0c48c4Sopenharmony_ci if (unlikely (buffer == NULL)) 162da0c48c4Sopenharmony_ci goto nomem; 163da0c48c4Sopenharmony_ci flags = ELF_F_MALLOCED; 164da0c48c4Sopenharmony_ci } 165da0c48c4Sopenharmony_ci 166da0c48c4Sopenharmony_ci /* Call the conversion function. */ 167da0c48c4Sopenharmony_ci (*__elf_xfctstom[elf->class - 1][type])(buffer, rawchunk, size, 0); 168da0c48c4Sopenharmony_ci } 169da0c48c4Sopenharmony_ci 170da0c48c4Sopenharmony_ci /* Allocate the dummy container to point at this buffer. */ 171da0c48c4Sopenharmony_ci Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk); 172da0c48c4Sopenharmony_ci if (chunk == NULL) 173da0c48c4Sopenharmony_ci { 174da0c48c4Sopenharmony_ci if (flags) 175da0c48c4Sopenharmony_ci free (buffer); 176da0c48c4Sopenharmony_ci goto nomem; 177da0c48c4Sopenharmony_ci } 178da0c48c4Sopenharmony_ci 179da0c48c4Sopenharmony_ci chunk->dummy_scn.elf = elf; 180da0c48c4Sopenharmony_ci chunk->dummy_scn.flags = flags; 181da0c48c4Sopenharmony_ci chunk->data.s = &chunk->dummy_scn; 182da0c48c4Sopenharmony_ci chunk->data.d.d_buf = buffer; 183da0c48c4Sopenharmony_ci chunk->data.d.d_size = size; 184da0c48c4Sopenharmony_ci chunk->data.d.d_type = type; 185da0c48c4Sopenharmony_ci chunk->data.d.d_align = align; 186da0c48c4Sopenharmony_ci chunk->data.d.d_version = EV_CURRENT; 187da0c48c4Sopenharmony_ci chunk->offset = offset; 188da0c48c4Sopenharmony_ci 189da0c48c4Sopenharmony_ci rwlock_unlock (elf->lock); 190da0c48c4Sopenharmony_ci rwlock_wrlock (elf->lock); 191da0c48c4Sopenharmony_ci 192da0c48c4Sopenharmony_ci chunk->next = elf->state.elf.rawchunks; 193da0c48c4Sopenharmony_ci elf->state.elf.rawchunks = chunk; 194da0c48c4Sopenharmony_ci result = &chunk->data.d; 195da0c48c4Sopenharmony_ci 196da0c48c4Sopenharmony_ci out: 197da0c48c4Sopenharmony_ci rwlock_unlock (elf->lock); 198da0c48c4Sopenharmony_ci return result; 199da0c48c4Sopenharmony_ci} 200