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