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> 302de3b87aSKai Wang #include <stdlib.h> 312de3b87aSKai Wang 322de3b87aSKai Wang #include "_libelf.h" 332de3b87aSKai Wang 34*cf781b2eSEd Maste ELFTC_VCSID("$Id: elf_data.c 3009 2014-03-23 01:49:59Z jkoshy $"); 352de3b87aSKai Wang 362de3b87aSKai Wang Elf_Data * 372de3b87aSKai Wang elf_getdata(Elf_Scn *s, Elf_Data *ed) 382de3b87aSKai Wang { 392de3b87aSKai Wang Elf *e; 402de3b87aSKai Wang unsigned int sh_type; 412de3b87aSKai Wang int elfclass, elftype; 42*cf781b2eSEd Maste size_t count, fsz, msz; 432de3b87aSKai Wang struct _Libelf_Data *d; 442de3b87aSKai Wang uint64_t sh_align, sh_offset, sh_size; 45*cf781b2eSEd Maste int (*xlate)(unsigned char *_d, size_t _dsz, unsigned char *_s, 46*cf781b2eSEd Maste size_t _c, int _swap); 472de3b87aSKai Wang 482de3b87aSKai Wang d = (struct _Libelf_Data *) ed; 492de3b87aSKai Wang 502de3b87aSKai Wang if (s == NULL || (e = s->s_elf) == NULL || 512de3b87aSKai Wang (d != NULL && s != d->d_scn)) { 522de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0); 532de3b87aSKai Wang return (NULL); 542de3b87aSKai Wang } 552de3b87aSKai Wang 562de3b87aSKai Wang assert(e->e_kind == ELF_K_ELF); 572de3b87aSKai Wang 582de3b87aSKai Wang if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL) 592de3b87aSKai Wang return (&d->d_data); 602de3b87aSKai Wang 612de3b87aSKai Wang if (d != NULL) 622de3b87aSKai Wang return (&STAILQ_NEXT(d, d_next)->d_data); 632de3b87aSKai Wang 642de3b87aSKai Wang if (e->e_rawfile == NULL) { 652de3b87aSKai Wang /* 662de3b87aSKai Wang * In the ELF_C_WRITE case, there is no source that 672de3b87aSKai Wang * can provide data for the section. 682de3b87aSKai Wang */ 692de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0); 702de3b87aSKai Wang return (NULL); 712de3b87aSKai Wang } 722de3b87aSKai Wang 732de3b87aSKai Wang elfclass = e->e_class; 742de3b87aSKai Wang 752de3b87aSKai Wang assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); 762de3b87aSKai Wang 772de3b87aSKai Wang if (elfclass == ELFCLASS32) { 782de3b87aSKai Wang sh_type = s->s_shdr.s_shdr32.sh_type; 792de3b87aSKai Wang sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; 802de3b87aSKai Wang sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 812de3b87aSKai Wang sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; 822de3b87aSKai Wang } else { 832de3b87aSKai Wang sh_type = s->s_shdr.s_shdr64.sh_type; 842de3b87aSKai Wang sh_offset = s->s_shdr.s_shdr64.sh_offset; 852de3b87aSKai Wang sh_size = s->s_shdr.s_shdr64.sh_size; 862de3b87aSKai Wang sh_align = s->s_shdr.s_shdr64.sh_addralign; 872de3b87aSKai Wang } 882de3b87aSKai Wang 892de3b87aSKai Wang if (sh_type == SHT_NULL) { 902de3b87aSKai Wang LIBELF_SET_ERROR(SECTION, 0); 912de3b87aSKai Wang return (NULL); 922de3b87aSKai Wang } 932de3b87aSKai Wang 942de3b87aSKai Wang if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST || 952de3b87aSKai Wang elftype > ELF_T_LAST || (sh_type != SHT_NOBITS && 962de3b87aSKai Wang sh_offset + sh_size > (uint64_t) e->e_rawsize)) { 972de3b87aSKai Wang LIBELF_SET_ERROR(SECTION, 0); 982de3b87aSKai Wang return (NULL); 992de3b87aSKai Wang } 1002de3b87aSKai Wang 1012de3b87aSKai Wang if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) 1022de3b87aSKai Wang (elftype, (size_t) 1, e->e_version)) == 0) { 1032de3b87aSKai Wang LIBELF_SET_ERROR(UNIMPL, 0); 1042de3b87aSKai Wang return (NULL); 1052de3b87aSKai Wang } 1062de3b87aSKai Wang 1072de3b87aSKai Wang if (sh_size % fsz) { 1082de3b87aSKai Wang LIBELF_SET_ERROR(SECTION, 0); 1092de3b87aSKai Wang return (NULL); 1102de3b87aSKai Wang } 1112de3b87aSKai Wang 112*cf781b2eSEd Maste if (sh_size / fsz > SIZE_MAX) { 113*cf781b2eSEd Maste LIBELF_SET_ERROR(RANGE, 0); 114*cf781b2eSEd Maste return (NULL); 115*cf781b2eSEd Maste } 116*cf781b2eSEd Maste 117*cf781b2eSEd Maste count = (size_t) (sh_size / fsz); 1182de3b87aSKai Wang 1192de3b87aSKai Wang msz = _libelf_msize(elftype, elfclass, e->e_version); 1202de3b87aSKai Wang 121*cf781b2eSEd Maste if (count > 0 && msz > SIZE_MAX / count) { 122*cf781b2eSEd Maste LIBELF_SET_ERROR(RANGE, 0); 123*cf781b2eSEd Maste return (NULL); 124*cf781b2eSEd Maste } 125*cf781b2eSEd Maste 1262de3b87aSKai Wang assert(msz > 0); 127*cf781b2eSEd Maste assert(count <= SIZE_MAX); 128*cf781b2eSEd Maste assert(msz * count <= SIZE_MAX); 1292de3b87aSKai Wang 1302de3b87aSKai Wang if ((d = _libelf_allocate_data(s)) == NULL) 1312de3b87aSKai Wang return (NULL); 1322de3b87aSKai Wang 1332de3b87aSKai Wang d->d_data.d_buf = NULL; 1342de3b87aSKai Wang d->d_data.d_off = 0; 1352de3b87aSKai Wang d->d_data.d_align = sh_align; 1362de3b87aSKai Wang d->d_data.d_size = msz * count; 1372de3b87aSKai Wang d->d_data.d_type = elftype; 1382de3b87aSKai Wang d->d_data.d_version = e->e_version; 1392de3b87aSKai Wang 1402de3b87aSKai Wang if (sh_type == SHT_NOBITS || sh_size == 0) { 1412de3b87aSKai Wang STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 1422de3b87aSKai Wang return (&d->d_data); 1432de3b87aSKai Wang } 1442de3b87aSKai Wang 1452de3b87aSKai Wang if ((d->d_data.d_buf = malloc(msz * count)) == NULL) { 1462de3b87aSKai Wang (void) _libelf_release_data(d); 1472de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, 0); 1482de3b87aSKai Wang return (NULL); 1492de3b87aSKai Wang } 1502de3b87aSKai Wang 1512de3b87aSKai Wang d->d_flags |= LIBELF_F_DATA_MALLOCED; 1522de3b87aSKai Wang 1532de3b87aSKai Wang xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass); 154*cf781b2eSEd Maste if (!(*xlate)(d->d_data.d_buf, (size_t) d->d_data.d_size, 1552de3b87aSKai Wang e->e_rawfile + sh_offset, count, 1562de3b87aSKai Wang e->e_byteorder != LIBELF_PRIVATE(byteorder))) { 1572de3b87aSKai Wang _libelf_release_data(d); 1582de3b87aSKai Wang LIBELF_SET_ERROR(DATA, 0); 1592de3b87aSKai Wang return (NULL); 1602de3b87aSKai Wang } 1612de3b87aSKai Wang 1622de3b87aSKai Wang STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 1632de3b87aSKai Wang 1642de3b87aSKai Wang return (&d->d_data); 1652de3b87aSKai Wang } 1662de3b87aSKai Wang 1672de3b87aSKai Wang Elf_Data * 1682de3b87aSKai Wang elf_newdata(Elf_Scn *s) 1692de3b87aSKai Wang { 1702de3b87aSKai Wang Elf *e; 1712de3b87aSKai Wang struct _Libelf_Data *d; 1722de3b87aSKai Wang 1732de3b87aSKai Wang if (s == NULL || (e = s->s_elf) == NULL) { 1742de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0); 1752de3b87aSKai Wang return (NULL); 1762de3b87aSKai Wang } 1772de3b87aSKai Wang 1782de3b87aSKai Wang assert(e->e_kind == ELF_K_ELF); 1792de3b87aSKai Wang 1802de3b87aSKai Wang /* 1812de3b87aSKai Wang * elf_newdata() has to append a data descriptor, so 1822de3b87aSKai Wang * bring in existing section data if not already present. 1832de3b87aSKai Wang */ 1842de3b87aSKai Wang if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data)) 1852de3b87aSKai Wang if (elf_getdata(s, NULL) == NULL) 1862de3b87aSKai Wang return (NULL); 1872de3b87aSKai Wang 1882de3b87aSKai Wang if ((d = _libelf_allocate_data(s)) == NULL) 1892de3b87aSKai Wang return (NULL); 1902de3b87aSKai Wang 1912de3b87aSKai Wang STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 1922de3b87aSKai Wang 1932de3b87aSKai Wang d->d_data.d_align = 1; 1942de3b87aSKai Wang d->d_data.d_buf = NULL; 1952de3b87aSKai Wang d->d_data.d_off = (uint64_t) ~0; 1962de3b87aSKai Wang d->d_data.d_size = 0; 1972de3b87aSKai Wang d->d_data.d_type = ELF_T_BYTE; 1982de3b87aSKai Wang d->d_data.d_version = LIBELF_PRIVATE(version); 1992de3b87aSKai Wang 2002de3b87aSKai Wang (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY); 2012de3b87aSKai Wang 2022de3b87aSKai Wang return (&d->d_data); 2032de3b87aSKai Wang } 2042de3b87aSKai Wang 2052de3b87aSKai Wang /* 2062de3b87aSKai Wang * Retrieve a data descriptor for raw (untranslated) data for section 2072de3b87aSKai Wang * `s'. 2082de3b87aSKai Wang */ 2092de3b87aSKai Wang 2102de3b87aSKai Wang Elf_Data * 2112de3b87aSKai Wang elf_rawdata(Elf_Scn *s, Elf_Data *ed) 2122de3b87aSKai Wang { 2132de3b87aSKai Wang Elf *e; 2142de3b87aSKai Wang int elf_class; 2152de3b87aSKai Wang uint32_t sh_type; 2162de3b87aSKai Wang struct _Libelf_Data *d; 2172de3b87aSKai Wang uint64_t sh_align, sh_offset, sh_size; 2182de3b87aSKai Wang 2192de3b87aSKai Wang if (s == NULL || (e = s->s_elf) == NULL || e->e_rawfile == NULL) { 2202de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0); 2212de3b87aSKai Wang return (NULL); 2222de3b87aSKai Wang } 2232de3b87aSKai Wang 2242de3b87aSKai Wang assert(e->e_kind == ELF_K_ELF); 2252de3b87aSKai Wang 2262de3b87aSKai Wang d = (struct _Libelf_Data *) ed; 2272de3b87aSKai Wang 2282de3b87aSKai Wang if (d == NULL && (d = STAILQ_FIRST(&s->s_rawdata)) != NULL) 2292de3b87aSKai Wang return (&d->d_data); 2302de3b87aSKai Wang 2312de3b87aSKai Wang if (d != NULL) 2322de3b87aSKai Wang return (&STAILQ_NEXT(d, d_next)->d_data); 2332de3b87aSKai Wang 2342de3b87aSKai Wang elf_class = e->e_class; 2352de3b87aSKai Wang 2362de3b87aSKai Wang assert(elf_class == ELFCLASS32 || elf_class == ELFCLASS64); 2372de3b87aSKai Wang 2382de3b87aSKai Wang if (elf_class == ELFCLASS32) { 2392de3b87aSKai Wang sh_type = s->s_shdr.s_shdr32.sh_type; 2402de3b87aSKai Wang sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; 2412de3b87aSKai Wang sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 2422de3b87aSKai Wang sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; 2432de3b87aSKai Wang } else { 2442de3b87aSKai Wang sh_type = s->s_shdr.s_shdr64.sh_type; 2452de3b87aSKai Wang sh_offset = s->s_shdr.s_shdr64.sh_offset; 2462de3b87aSKai Wang sh_size = s->s_shdr.s_shdr64.sh_size; 2472de3b87aSKai Wang sh_align = s->s_shdr.s_shdr64.sh_addralign; 2482de3b87aSKai Wang } 2492de3b87aSKai Wang 2502de3b87aSKai Wang if (sh_type == SHT_NULL) { 2512de3b87aSKai Wang LIBELF_SET_ERROR(SECTION, 0); 2522de3b87aSKai Wang return (NULL); 2532de3b87aSKai Wang } 2542de3b87aSKai Wang 2552de3b87aSKai Wang if ((d = _libelf_allocate_data(s)) == NULL) 2562de3b87aSKai Wang return (NULL); 2572de3b87aSKai Wang 2582de3b87aSKai Wang d->d_data.d_buf = (sh_type == SHT_NOBITS || sh_size == 0) ? NULL : 2592de3b87aSKai Wang e->e_rawfile + sh_offset; 2602de3b87aSKai Wang d->d_data.d_off = 0; 2612de3b87aSKai Wang d->d_data.d_align = sh_align; 2622de3b87aSKai Wang d->d_data.d_size = sh_size; 2632de3b87aSKai Wang d->d_data.d_type = ELF_T_BYTE; 2642de3b87aSKai Wang d->d_data.d_version = e->e_version; 2652de3b87aSKai Wang 2662de3b87aSKai Wang STAILQ_INSERT_TAIL(&s->s_rawdata, d, d_next); 2672de3b87aSKai Wang 2682de3b87aSKai Wang return (&d->d_data); 2692de3b87aSKai Wang } 270