12de3b87aSKai Wang /*- 22de3b87aSKai Wang * Copyright (c) 2006,2008,2011 Joseph Koshy 32de3b87aSKai Wang * All rights reserved. 42de3b87aSKai Wang * 52de3b87aSKai Wang * Redistribution and use in source and binary forms, with or without 62de3b87aSKai Wang * modification, are permitted provided that the following conditions 72de3b87aSKai Wang * are met: 82de3b87aSKai Wang * 1. Redistributions of source code must retain the above copyright 92de3b87aSKai Wang * notice, this list of conditions and the following disclaimer. 102de3b87aSKai Wang * 2. Redistributions in binary form must reproduce the above copyright 112de3b87aSKai Wang * notice, this list of conditions and the following disclaimer in the 122de3b87aSKai Wang * documentation and/or other materials provided with the distribution. 132de3b87aSKai Wang * 142de3b87aSKai Wang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152de3b87aSKai Wang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162de3b87aSKai Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172de3b87aSKai Wang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182de3b87aSKai Wang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192de3b87aSKai Wang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202de3b87aSKai Wang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212de3b87aSKai Wang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222de3b87aSKai Wang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232de3b87aSKai Wang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242de3b87aSKai Wang * SUCH DAMAGE. 252de3b87aSKai Wang */ 262de3b87aSKai Wang 272de3b87aSKai Wang #include <assert.h> 282de3b87aSKai Wang #include <errno.h> 292de3b87aSKai Wang #include <libelf.h> 30b4e9f239SEd Maste #include <stdint.h> 312de3b87aSKai Wang #include <stdlib.h> 322de3b87aSKai Wang 332de3b87aSKai Wang #include "_libelf.h" 342de3b87aSKai Wang 35*95fd7f26SEd Maste ELFTC_VCSID("$Id: elf_data.c 3258 2015-11-20 18:59:43Z emaste $"); 362de3b87aSKai Wang 372de3b87aSKai Wang Elf_Data * 382de3b87aSKai Wang elf_getdata(Elf_Scn *s, Elf_Data *ed) 392de3b87aSKai Wang { 402de3b87aSKai Wang Elf *e; 412de3b87aSKai Wang unsigned int sh_type; 422de3b87aSKai Wang int elfclass, elftype; 43cf781b2eSEd Maste size_t count, fsz, msz; 442de3b87aSKai Wang struct _Libelf_Data *d; 452de3b87aSKai Wang uint64_t sh_align, sh_offset, sh_size; 46cf781b2eSEd Maste int (*xlate)(unsigned char *_d, size_t _dsz, unsigned char *_s, 47cf781b2eSEd Maste size_t _c, int _swap); 482de3b87aSKai Wang 492de3b87aSKai Wang d = (struct _Libelf_Data *) ed; 502de3b87aSKai Wang 512de3b87aSKai Wang if (s == NULL || (e = s->s_elf) == NULL || 522de3b87aSKai Wang (d != NULL && s != d->d_scn)) { 532de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0); 542de3b87aSKai Wang return (NULL); 552de3b87aSKai Wang } 562de3b87aSKai Wang 572de3b87aSKai Wang assert(e->e_kind == ELF_K_ELF); 582de3b87aSKai Wang 592de3b87aSKai Wang if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL) 602de3b87aSKai Wang return (&d->d_data); 612de3b87aSKai Wang 622de3b87aSKai Wang if (d != NULL) 632de3b87aSKai Wang return (&STAILQ_NEXT(d, d_next)->d_data); 642de3b87aSKai Wang 652de3b87aSKai Wang if (e->e_rawfile == NULL) { 662de3b87aSKai Wang /* 672de3b87aSKai Wang * In the ELF_C_WRITE case, there is no source that 682de3b87aSKai Wang * can provide data for the section. 692de3b87aSKai Wang */ 702de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0); 712de3b87aSKai Wang return (NULL); 722de3b87aSKai Wang } 732de3b87aSKai Wang 742de3b87aSKai Wang elfclass = e->e_class; 752de3b87aSKai Wang 762de3b87aSKai Wang assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); 772de3b87aSKai Wang 782de3b87aSKai Wang if (elfclass == ELFCLASS32) { 792de3b87aSKai Wang sh_type = s->s_shdr.s_shdr32.sh_type; 802de3b87aSKai Wang sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; 812de3b87aSKai Wang sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 822de3b87aSKai Wang sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; 832de3b87aSKai Wang } else { 842de3b87aSKai Wang sh_type = s->s_shdr.s_shdr64.sh_type; 852de3b87aSKai Wang sh_offset = s->s_shdr.s_shdr64.sh_offset; 862de3b87aSKai Wang sh_size = s->s_shdr.s_shdr64.sh_size; 872de3b87aSKai Wang sh_align = s->s_shdr.s_shdr64.sh_addralign; 882de3b87aSKai Wang } 892de3b87aSKai Wang 902de3b87aSKai Wang if (sh_type == SHT_NULL) { 912de3b87aSKai Wang LIBELF_SET_ERROR(SECTION, 0); 922de3b87aSKai Wang return (NULL); 932de3b87aSKai Wang } 942de3b87aSKai Wang 952de3b87aSKai Wang if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST || 962de3b87aSKai Wang elftype > ELF_T_LAST || (sh_type != SHT_NOBITS && 972de3b87aSKai Wang sh_offset + sh_size > (uint64_t) e->e_rawsize)) { 982de3b87aSKai Wang LIBELF_SET_ERROR(SECTION, 0); 992de3b87aSKai Wang return (NULL); 1002de3b87aSKai Wang } 1012de3b87aSKai Wang 1022de3b87aSKai Wang if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) 1032de3b87aSKai Wang (elftype, (size_t) 1, e->e_version)) == 0) { 1042de3b87aSKai Wang LIBELF_SET_ERROR(UNIMPL, 0); 1052de3b87aSKai Wang return (NULL); 1062de3b87aSKai Wang } 1072de3b87aSKai Wang 1082de3b87aSKai Wang if (sh_size % fsz) { 1092de3b87aSKai Wang LIBELF_SET_ERROR(SECTION, 0); 1102de3b87aSKai Wang return (NULL); 1112de3b87aSKai Wang } 1122de3b87aSKai Wang 113cf781b2eSEd Maste if (sh_size / fsz > SIZE_MAX) { 114cf781b2eSEd Maste LIBELF_SET_ERROR(RANGE, 0); 115cf781b2eSEd Maste return (NULL); 116cf781b2eSEd Maste } 117cf781b2eSEd Maste 118cf781b2eSEd Maste count = (size_t) (sh_size / fsz); 1192de3b87aSKai Wang 1202de3b87aSKai Wang msz = _libelf_msize(elftype, elfclass, e->e_version); 1212de3b87aSKai Wang 122cf781b2eSEd Maste if (count > 0 && msz > SIZE_MAX / count) { 123cf781b2eSEd Maste LIBELF_SET_ERROR(RANGE, 0); 124cf781b2eSEd Maste return (NULL); 125cf781b2eSEd Maste } 126cf781b2eSEd Maste 1272de3b87aSKai Wang assert(msz > 0); 128cf781b2eSEd Maste assert(count <= SIZE_MAX); 129cf781b2eSEd Maste assert(msz * count <= SIZE_MAX); 1302de3b87aSKai Wang 1312de3b87aSKai Wang if ((d = _libelf_allocate_data(s)) == NULL) 1322de3b87aSKai Wang return (NULL); 1332de3b87aSKai Wang 1342de3b87aSKai Wang d->d_data.d_buf = NULL; 1352de3b87aSKai Wang d->d_data.d_off = 0; 1362de3b87aSKai Wang d->d_data.d_align = sh_align; 1372de3b87aSKai Wang d->d_data.d_size = msz * count; 1382de3b87aSKai Wang d->d_data.d_type = elftype; 1392de3b87aSKai Wang d->d_data.d_version = e->e_version; 1402de3b87aSKai Wang 1412de3b87aSKai Wang if (sh_type == SHT_NOBITS || sh_size == 0) { 1422de3b87aSKai Wang STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 1432de3b87aSKai Wang return (&d->d_data); 1442de3b87aSKai Wang } 1452de3b87aSKai Wang 1462de3b87aSKai Wang if ((d->d_data.d_buf = malloc(msz * count)) == NULL) { 1472de3b87aSKai Wang (void) _libelf_release_data(d); 1482de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, 0); 1492de3b87aSKai Wang return (NULL); 1502de3b87aSKai Wang } 1512de3b87aSKai Wang 1522de3b87aSKai Wang d->d_flags |= LIBELF_F_DATA_MALLOCED; 1532de3b87aSKai Wang 1542de3b87aSKai Wang xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass); 155cf781b2eSEd Maste if (!(*xlate)(d->d_data.d_buf, (size_t) d->d_data.d_size, 1562de3b87aSKai Wang e->e_rawfile + sh_offset, count, 1572de3b87aSKai Wang e->e_byteorder != LIBELF_PRIVATE(byteorder))) { 1582de3b87aSKai Wang _libelf_release_data(d); 1592de3b87aSKai Wang LIBELF_SET_ERROR(DATA, 0); 1602de3b87aSKai Wang return (NULL); 1612de3b87aSKai Wang } 1622de3b87aSKai Wang 1632de3b87aSKai Wang STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 1642de3b87aSKai Wang 1652de3b87aSKai Wang return (&d->d_data); 1662de3b87aSKai Wang } 1672de3b87aSKai Wang 1682de3b87aSKai Wang Elf_Data * 1692de3b87aSKai Wang elf_newdata(Elf_Scn *s) 1702de3b87aSKai Wang { 1712de3b87aSKai Wang Elf *e; 1722de3b87aSKai Wang struct _Libelf_Data *d; 1732de3b87aSKai Wang 1742de3b87aSKai Wang if (s == NULL || (e = s->s_elf) == NULL) { 1752de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0); 1762de3b87aSKai Wang return (NULL); 1772de3b87aSKai Wang } 1782de3b87aSKai Wang 1792de3b87aSKai Wang assert(e->e_kind == ELF_K_ELF); 1802de3b87aSKai Wang 1812de3b87aSKai Wang /* 1822de3b87aSKai Wang * elf_newdata() has to append a data descriptor, so 1832de3b87aSKai Wang * bring in existing section data if not already present. 1842de3b87aSKai Wang */ 1852de3b87aSKai Wang if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data)) 1862de3b87aSKai Wang if (elf_getdata(s, NULL) == NULL) 1872de3b87aSKai Wang return (NULL); 1882de3b87aSKai Wang 1892de3b87aSKai Wang if ((d = _libelf_allocate_data(s)) == NULL) 1902de3b87aSKai Wang return (NULL); 1912de3b87aSKai Wang 1922de3b87aSKai Wang STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 1932de3b87aSKai Wang 1942de3b87aSKai Wang d->d_data.d_align = 1; 1952de3b87aSKai Wang d->d_data.d_buf = NULL; 1962de3b87aSKai Wang d->d_data.d_off = (uint64_t) ~0; 1972de3b87aSKai Wang d->d_data.d_size = 0; 1982de3b87aSKai Wang d->d_data.d_type = ELF_T_BYTE; 1992de3b87aSKai Wang d->d_data.d_version = LIBELF_PRIVATE(version); 2002de3b87aSKai Wang 2012de3b87aSKai Wang (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY); 2022de3b87aSKai Wang 2032de3b87aSKai Wang return (&d->d_data); 2042de3b87aSKai Wang } 2052de3b87aSKai Wang 2062de3b87aSKai Wang /* 2072de3b87aSKai Wang * Retrieve a data descriptor for raw (untranslated) data for section 2082de3b87aSKai Wang * `s'. 2092de3b87aSKai Wang */ 2102de3b87aSKai Wang 2112de3b87aSKai Wang Elf_Data * 2122de3b87aSKai Wang elf_rawdata(Elf_Scn *s, Elf_Data *ed) 2132de3b87aSKai Wang { 2142de3b87aSKai Wang Elf *e; 2152de3b87aSKai Wang int elf_class; 2162de3b87aSKai Wang uint32_t sh_type; 2172de3b87aSKai Wang struct _Libelf_Data *d; 2182de3b87aSKai Wang uint64_t sh_align, sh_offset, sh_size; 2192de3b87aSKai Wang 2202de3b87aSKai Wang if (s == NULL || (e = s->s_elf) == NULL || e->e_rawfile == NULL) { 2212de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0); 2222de3b87aSKai Wang return (NULL); 2232de3b87aSKai Wang } 2242de3b87aSKai Wang 2252de3b87aSKai Wang assert(e->e_kind == ELF_K_ELF); 2262de3b87aSKai Wang 2272de3b87aSKai Wang d = (struct _Libelf_Data *) ed; 2282de3b87aSKai Wang 2292de3b87aSKai Wang if (d == NULL && (d = STAILQ_FIRST(&s->s_rawdata)) != NULL) 2302de3b87aSKai Wang return (&d->d_data); 2312de3b87aSKai Wang 2322de3b87aSKai Wang if (d != NULL) 2332de3b87aSKai Wang return (&STAILQ_NEXT(d, d_next)->d_data); 2342de3b87aSKai Wang 2352de3b87aSKai Wang elf_class = e->e_class; 2362de3b87aSKai Wang 2372de3b87aSKai Wang assert(elf_class == ELFCLASS32 || elf_class == ELFCLASS64); 2382de3b87aSKai Wang 2392de3b87aSKai Wang if (elf_class == ELFCLASS32) { 2402de3b87aSKai Wang sh_type = s->s_shdr.s_shdr32.sh_type; 2412de3b87aSKai Wang sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; 2422de3b87aSKai Wang sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 2432de3b87aSKai Wang sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; 2442de3b87aSKai Wang } else { 2452de3b87aSKai Wang sh_type = s->s_shdr.s_shdr64.sh_type; 2462de3b87aSKai Wang sh_offset = s->s_shdr.s_shdr64.sh_offset; 2472de3b87aSKai Wang sh_size = s->s_shdr.s_shdr64.sh_size; 2482de3b87aSKai Wang sh_align = s->s_shdr.s_shdr64.sh_addralign; 2492de3b87aSKai Wang } 2502de3b87aSKai Wang 2512de3b87aSKai Wang if (sh_type == SHT_NULL) { 2522de3b87aSKai Wang LIBELF_SET_ERROR(SECTION, 0); 2532de3b87aSKai Wang return (NULL); 2542de3b87aSKai Wang } 2552de3b87aSKai Wang 256*95fd7f26SEd Maste if (sh_type != SHT_NOBITS && 257*95fd7f26SEd Maste sh_offset + sh_size > (uint64_t) e->e_rawsize) { 258*95fd7f26SEd Maste LIBELF_SET_ERROR(SECTION, 0); 259*95fd7f26SEd Maste return (NULL); 260*95fd7f26SEd Maste } 261*95fd7f26SEd Maste 2622de3b87aSKai Wang if ((d = _libelf_allocate_data(s)) == NULL) 2632de3b87aSKai Wang return (NULL); 2642de3b87aSKai Wang 2652de3b87aSKai Wang d->d_data.d_buf = (sh_type == SHT_NOBITS || sh_size == 0) ? NULL : 2662de3b87aSKai Wang e->e_rawfile + sh_offset; 2672de3b87aSKai Wang d->d_data.d_off = 0; 2682de3b87aSKai Wang d->d_data.d_align = sh_align; 2692de3b87aSKai Wang d->d_data.d_size = sh_size; 2702de3b87aSKai Wang d->d_data.d_type = ELF_T_BYTE; 2712de3b87aSKai Wang d->d_data.d_version = e->e_version; 2722de3b87aSKai Wang 2732de3b87aSKai Wang STAILQ_INSERT_TAIL(&s->s_rawdata, d, d_next); 2742de3b87aSKai Wang 2752de3b87aSKai Wang return (&d->d_data); 2762de3b87aSKai Wang } 277