elf_data.c
1 /*- 2 * Copyright (c) 2006,2008,2011 Joseph Koshy 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <assert.h> 28 #include <errno.h> 29 #include <libelf.h> 30 #include <stdlib.h> 31 32 #include "_libelf.h" 33 34 ELFTC_VCSID("$Id$"); 35 36 Elf_Data * 37 elf_getdata(Elf_Scn *s, Elf_Data *ed) 38 { 39 Elf *e; 40 unsigned int sh_type; 41 int elfclass, elftype; 42 size_t count, fsz, msz; 43 struct _Libelf_Data *d; 44 uint64_t sh_align, sh_offset, sh_size; 45 int (*xlate)(unsigned char *_d, size_t _dsz, unsigned char *_s, 46 size_t _c, int _swap); 47 48 d = (struct _Libelf_Data *) ed; 49 50 if (s == NULL || (e = s->s_elf) == NULL || 51 (d != NULL && s != d->d_scn)) { 52 LIBELF_SET_ERROR(ARGUMENT, 0); 53 return (NULL); 54 } 55 56 assert(e->e_kind == ELF_K_ELF); 57 58 if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL) 59 return (&d->d_data); 60 61 if (d != NULL) 62 return (&STAILQ_NEXT(d, d_next)->d_data); 63 64 if (e->e_rawfile == NULL) { 65 /* 66 * In the ELF_C_WRITE case, there is no source that 67 * can provide data for the section. 68 */ 69 LIBELF_SET_ERROR(ARGUMENT, 0); 70 return (NULL); 71 } 72 73 elfclass = e->e_class; 74 75 assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); 76 77 if (elfclass == ELFCLASS32) { 78 sh_type = s->s_shdr.s_shdr32.sh_type; 79 sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; 80 sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 81 sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; 82 } else { 83 sh_type = s->s_shdr.s_shdr64.sh_type; 84 sh_offset = s->s_shdr.s_shdr64.sh_offset; 85 sh_size = s->s_shdr.s_shdr64.sh_size; 86 sh_align = s->s_shdr.s_shdr64.sh_addralign; 87 } 88 89 if (sh_type == SHT_NULL) { 90 LIBELF_SET_ERROR(SECTION, 0); 91 return (NULL); 92 } 93 94 if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST || 95 elftype > ELF_T_LAST || (sh_type != SHT_NOBITS && 96 sh_offset + sh_size > (uint64_t) e->e_rawsize)) { 97 LIBELF_SET_ERROR(SECTION, 0); 98 return (NULL); 99 } 100 101 if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) 102 (elftype, (size_t) 1, e->e_version)) == 0) { 103 LIBELF_SET_ERROR(UNIMPL, 0); 104 return (NULL); 105 } 106 107 if (sh_size % fsz) { 108 LIBELF_SET_ERROR(SECTION, 0); 109 return (NULL); 110 } 111 112 if (sh_size / fsz > SIZE_MAX) { 113 LIBELF_SET_ERROR(RANGE, 0); 114 return (NULL); 115 } 116 117 count = (size_t) (sh_size / fsz); 118 119 msz = _libelf_msize(elftype, elfclass, e->e_version); 120 121 if (count > 0 && msz > SIZE_MAX / count) { 122 LIBELF_SET_ERROR(RANGE, 0); 123 return (NULL); 124 } 125 126 assert(msz > 0); 127 assert(count <= SIZE_MAX); 128 assert(msz * count <= SIZE_MAX); 129 130 if ((d = _libelf_allocate_data(s)) == NULL) 131 return (NULL); 132 133 d->d_data.d_buf = NULL; 134 d->d_data.d_off = 0; 135 d->d_data.d_align = sh_align; 136 d->d_data.d_size = msz * count; 137 d->d_data.d_type = elftype; 138 d->d_data.d_version = e->e_version; 139 140 if (sh_type == SHT_NOBITS || sh_size == 0) { 141 STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 142 return (&d->d_data); 143 } 144 145 if ((d->d_data.d_buf = malloc(msz * count)) == NULL) { 146 (void) _libelf_release_data(d); 147 LIBELF_SET_ERROR(RESOURCE, 0); 148 return (NULL); 149 } 150 151 d->d_flags |= LIBELF_F_DATA_MALLOCED; 152 153 xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass); 154 if (!(*xlate)(d->d_data.d_buf, (size_t) d->d_data.d_size, 155 e->e_rawfile + sh_offset, count, 156 e->e_byteorder != LIBELF_PRIVATE(byteorder))) { 157 _libelf_release_data(d); 158 LIBELF_SET_ERROR(DATA, 0); 159 return (NULL); 160 } 161 162 STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 163 164 return (&d->d_data); 165 } 166 167 Elf_Data * 168 elf_newdata(Elf_Scn *s) 169 { 170 Elf *e; 171 struct _Libelf_Data *d; 172 173 if (s == NULL || (e = s->s_elf) == NULL) { 174 LIBELF_SET_ERROR(ARGUMENT, 0); 175 return (NULL); 176 } 177 178 assert(e->e_kind == ELF_K_ELF); 179 180 /* 181 * elf_newdata() has to append a data descriptor, so 182 * bring in existing section data if not already present. 183 */ 184 if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data)) 185 if (elf_getdata(s, NULL) == NULL) 186 return (NULL); 187 188 if ((d = _libelf_allocate_data(s)) == NULL) 189 return (NULL); 190 191 STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 192 193 d->d_data.d_align = 1; 194 d->d_data.d_buf = NULL; 195 d->d_data.d_off = (uint64_t) ~0; 196 d->d_data.d_size = 0; 197 d->d_data.d_type = ELF_T_BYTE; 198 d->d_data.d_version = LIBELF_PRIVATE(version); 199 200 (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY); 201 202 return (&d->d_data); 203 } 204 205 /* 206 * Retrieve a data descriptor for raw (untranslated) data for section 207 * `s'. 208 */ 209 210 Elf_Data * 211 elf_rawdata(Elf_Scn *s, Elf_Data *ed) 212 { 213 Elf *e; 214 int elf_class; 215 uint32_t sh_type; 216 struct _Libelf_Data *d; 217 uint64_t sh_align, sh_offset, sh_size; 218 219 if (s == NULL || (e = s->s_elf) == NULL || e->e_rawfile == NULL) { 220 LIBELF_SET_ERROR(ARGUMENT, 0); 221 return (NULL); 222 } 223 224 assert(e->e_kind == ELF_K_ELF); 225 226 d = (struct _Libelf_Data *) ed; 227 228 if (d == NULL && (d = STAILQ_FIRST(&s->s_rawdata)) != NULL) 229 return (&d->d_data); 230 231 if (d != NULL) 232 return (&STAILQ_NEXT(d, d_next)->d_data); 233 234 elf_class = e->e_class; 235 236 assert(elf_class == ELFCLASS32 || elf_class == ELFCLASS64); 237 238 if (elf_class == ELFCLASS32) { 239 sh_type = s->s_shdr.s_shdr32.sh_type; 240 sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; 241 sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 242 sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; 243 } else { 244 sh_type = s->s_shdr.s_shdr64.sh_type; 245 sh_offset = s->s_shdr.s_shdr64.sh_offset; 246 sh_size = s->s_shdr.s_shdr64.sh_size; 247 sh_align = s->s_shdr.s_shdr64.sh_addralign; 248 } 249 250 if (sh_type == SHT_NULL) { 251 LIBELF_SET_ERROR(SECTION, 0); 252 return (NULL); 253 } 254 255 if ((d = _libelf_allocate_data(s)) == NULL) 256 return (NULL); 257 258 d->d_data.d_buf = (sh_type == SHT_NOBITS || sh_size == 0) ? NULL : 259 e->e_rawfile + sh_offset; 260 d->d_data.d_off = 0; 261 d->d_data.d_align = sh_align; 262 d->d_data.d_size = sh_size; 263 d->d_data.d_type = ELF_T_BYTE; 264 d->d_data.d_version = e->e_version; 265 266 STAILQ_INSERT_TAIL(&s->s_rawdata, d, d_next); 267 268 return (&d->d_data); 269 }