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