Branch data Line data Source code
1 : : /* Return converted data from raw chunk of ELF file. 2 : : Copyright (C) 2007, 2014, 2015 Red Hat, Inc. 3 : : Copyright (C) 2022, 2023 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 <search.h> 37 : : #include <stdlib.h> 38 : : #include <string.h> 39 : : 40 : : #include "libelfP.h" 41 : : #include "common.h" 42 : : 43 : : static int 44 : 3460 : chunk_compare (const void *a, const void *b) 45 : : { 46 : 3460 : Elf_Data_Chunk *da = (Elf_Data_Chunk *)a; 47 : 3460 : Elf_Data_Chunk *db = (Elf_Data_Chunk *)b; 48 : : 49 [ + + ]: 3460 : if (da->offset != db->offset) 50 : 3422 : return da->offset - db->offset; 51 : : 52 [ - + ]: 38 : if (da->data.d.d_size != db->data.d.d_size) 53 : 0 : return da->data.d.d_size - db->data.d.d_size; 54 : : 55 : 38 : return da->data.d.d_type - db->data.d.d_type; 56 : : } 57 : : 58 : : Elf_Data * 59 : 1068 : elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type) 60 : : { 61 [ - + ]: 1068 : if (unlikely (elf == NULL)) 62 : : return NULL; 63 : : 64 [ - + ]: 1068 : if (unlikely (elf->kind != ELF_K_ELF)) 65 : : { 66 : : /* No valid descriptor. */ 67 : 0 : __libelf_seterrno (ELF_E_INVALID_HANDLE); 68 : 0 : return NULL; 69 : : } 70 : : 71 [ + - + + : 1068 : if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size - + ] 72 : : || elf->maximum_size - (uint64_t) offset < size)) 73 : : 74 : : { 75 : : /* Invalid request. */ 76 : 12 : __libelf_seterrno (ELF_E_INVALID_OP); 77 : 12 : return NULL; 78 : : } 79 : : 80 [ - + ]: 1056 : if (type >= ELF_T_NUM) 81 : : { 82 : 0 : __libelf_seterrno (ELF_E_UNKNOWN_TYPE); 83 : 0 : return NULL; 84 : : } 85 : : 86 : : /* Get the raw bytes from the file. */ 87 : 1056 : void *rawchunk; 88 : 1056 : int flags = 0; 89 : 1056 : Elf_Data *result = NULL; 90 : : 91 : 1056 : rwlock_rdlock (elf->lock); 92 : : 93 : : /* Maybe we already got this chunk? */ 94 : 1056 : Elf_Data_Chunk key; 95 : 1056 : key.offset = offset; 96 : 1056 : key.data.d.d_size = size; 97 : 1056 : key.data.d.d_type = type; 98 : 1056 : Elf_Data_Chunk **found = tsearch (&key, &elf->state.elf.rawchunks, 99 : : &chunk_compare); 100 [ - + ]: 1056 : if (found == NULL) 101 : 0 : goto nomem; 102 : : 103 : : /* Existing entry. */ 104 [ + + + - ]: 1056 : if (*found != &key && *found != NULL) 105 : : { 106 : 38 : result = &(*found)->data.d; 107 : 38 : goto out; 108 : : } 109 : : 110 : : /* New entry. */ 111 : 1018 : *found = NULL; 112 : : 113 : 1018 : size_t align = __libelf_type_align (elf->class, type); 114 [ + + ]: 1018 : if (elf->map_address != NULL) 115 : : { 116 : : /* If the file is mmap'ed we can use it directly, if aligned for type. */ 117 : 777 : char *rawdata = elf->map_address + elf->start_offset + offset; 118 [ + + ]: 777 : if (((uintptr_t) rawdata & (align - 1)) == 0) 119 : : rawchunk = rawdata; 120 : : else 121 : : { 122 : : /* We allocate the memory and memcpy it to get aligned data. */ 123 : 2 : rawchunk = malloc (size); 124 [ - + ]: 2 : if (rawchunk == NULL) 125 : 0 : goto nomem; 126 : 2 : memcpy (rawchunk, rawdata, size); 127 : 2 : flags = ELF_F_MALLOCED; 128 : : } 129 : : } 130 : : else 131 : : { 132 : : /* We allocate the memory and read the data from the file. */ 133 : 241 : rawchunk = malloc (size); 134 [ - + ]: 241 : if (rawchunk == NULL) 135 : : { 136 : 0 : nomem: 137 : 0 : __libelf_seterrno (ELF_E_NOMEM); 138 : 0 : goto out; 139 : : } 140 : : 141 : : /* Read the file content. */ 142 [ - + ]: 241 : if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size, 143 : : elf->start_offset + offset) 144 : : != size)) 145 : : { 146 : : /* Something went wrong. */ 147 : 0 : free (rawchunk); 148 : 0 : __libelf_seterrno (ELF_E_READ_ERROR); 149 : 0 : goto out; 150 : : } 151 : : 152 : : flags = ELF_F_MALLOCED; 153 : : } 154 : : 155 : : /* Copy and/or convert the data as needed for aligned native-order access. */ 156 : 1018 : void *buffer; 157 [ + + ]: 1018 : if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA) 158 : : { 159 [ - + ]: 665 : if (((uintptr_t) rawchunk & (align - 1)) == 0) 160 : : /* No need to copy, we can use the raw data. */ 161 : : buffer = rawchunk; 162 : : else 163 : : { 164 : : /* A malloc'd block is always sufficiently aligned. */ 165 [ # # ]: 0 : assert (flags == 0); 166 : : 167 : 0 : buffer = malloc (size); 168 [ # # ]: 0 : if (unlikely (buffer == NULL)) 169 : 0 : goto nomem; 170 : 0 : flags = ELF_F_MALLOCED; 171 : : 172 : : /* The copy will be appropriately aligned for direct access. */ 173 : 0 : memcpy (buffer, rawchunk, size); 174 : : } 175 : : } 176 : : else 177 : : { 178 [ + + ]: 353 : if (flags) 179 : : buffer = rawchunk; 180 : : else 181 : : { 182 : 328 : buffer = malloc (size); 183 [ - + ]: 328 : if (unlikely (buffer == NULL)) 184 : 0 : goto nomem; 185 : : flags = ELF_F_MALLOCED; 186 : : } 187 : : 188 : : /* Call the conversion function. */ 189 : 353 : (*__elf_xfctstom[elf->class - 1][type])(buffer, rawchunk, size, 0); 190 : : } 191 : : 192 : : /* Allocate the dummy container to point at this buffer. */ 193 : 1018 : Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk); 194 [ - + ]: 1018 : if (chunk == NULL) 195 : : { 196 [ # # ]: 0 : if (flags) 197 : 0 : free (buffer); 198 : 0 : goto nomem; 199 : : } 200 : : 201 : 1018 : chunk->dummy_scn.elf = elf; 202 : 1018 : chunk->dummy_scn.flags = flags; 203 : 1018 : chunk->data.s = &chunk->dummy_scn; 204 : 1018 : chunk->data.d.d_buf = buffer; 205 : 1018 : chunk->data.d.d_size = size; 206 : 1018 : chunk->data.d.d_type = type; 207 : 1018 : chunk->data.d.d_align = align; 208 : 1018 : chunk->data.d.d_version = EV_CURRENT; 209 : 1018 : chunk->offset = offset; 210 : : 211 : 1018 : rwlock_unlock (elf->lock); 212 : 1018 : rwlock_wrlock (elf->lock); 213 : : 214 : 1018 : *found = chunk; 215 : 1018 : result = &chunk->data.d; 216 : : 217 : : out: 218 : : rwlock_unlock (elf->lock); 219 : : return result; 220 : : }