1 /* $NetBSD: elf_scn.c,v 1.6 2025/12/25 18:58:12 jkoshy Exp $ */ 2 3 /*- 4 * Copyright (c) 2006,2008-2010 Joseph Koshy 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #if HAVE_NBTOOL_CONFIG_H 30 # include "nbtool_config.h" 31 #endif 32 33 #include <sys/cdefs.h> 34 #include <sys/queue.h> 35 36 #include <assert.h> 37 #include <errno.h> 38 #include <gelf.h> 39 #include <libelf.h> 40 #include <stddef.h> 41 #include <stdint.h> 42 #include <stdlib.h> 43 44 #include "_libelf.h" 45 46 ELFTC_VCSID("Id: elf_scn.c 4074 2025-01-07 15:34:21Z jkoshy"); 47 48 __RCSID("$NetBSD: elf_scn.c,v 1.6 2025/12/25 18:58:12 jkoshy Exp $"); 49 50 /* 51 * Load an ELF section table and create a list of Elf_Scn structures. 52 */ 53 int 54 _libelf_load_section_headers(Elf *e, void *ehdr) 55 { 56 Elf_Scn *scn; 57 int swapbytes; 58 uint64_t shoff; 59 unsigned int ec; 60 Elf32_Ehdr *eh32; 61 Elf64_Ehdr *eh64; 62 unsigned char *src; 63 size_t fsz, i, shnum; 64 _libelf_translator_function *xlator; 65 66 assert(e != NULL); 67 assert(ehdr != NULL); 68 assert((e->e_flags & LIBELF_F_SHDRS_LOADED) == 0); 69 70 #define CHECK_EHDR(E,EH) do { \ 71 uintmax_t rawsize = (uintmax_t) e->e_rawsize; \ 72 if (shoff > (uintmax_t) e->e_rawsize || \ 73 fsz != (EH)->e_shentsize || \ 74 shnum > SIZE_MAX / fsz || \ 75 fsz * shnum > rawsize - shoff) { \ 76 LIBELF_SET_ERROR(HEADER, 0); \ 77 return (0); \ 78 } \ 79 } while (/* CONSTCOND */ 0) 80 81 ec = e->e_class; 82 fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1); 83 assert(fsz > 0); 84 85 shnum = e->e_u.e_elf.e_nscn; 86 87 if (ec == ELFCLASS32) { 88 eh32 = (Elf32_Ehdr *) ehdr; 89 shoff = (uint64_t) eh32->e_shoff; 90 CHECK_EHDR(e, eh32); 91 } else { 92 eh64 = (Elf64_Ehdr *) ehdr; 93 shoff = eh64->e_shoff; 94 CHECK_EHDR(e, eh64); 95 } 96 97 xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec, 98 _libelf_elfmachine(e)); 99 100 swapbytes = e->e_byteorder != LIBELF_PRIVATE(byteorder); 101 src = e->e_rawfile + shoff; 102 103 /* 104 * If the file is using extended numbering then section #0 105 * would have already been read in. 106 */ 107 108 i = 0; 109 if (!STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) { 110 assert(STAILQ_FIRST(&e->e_u.e_elf.e_scn) == 111 STAILQ_LAST(&e->e_u.e_elf.e_scn, _Elf_Scn, s_next)); 112 113 i = 1; 114 src += fsz; 115 } 116 117 for (; i < shnum; i++, src += fsz) { 118 if ((scn = _libelf_allocate_scn(e, i)) == NULL) 119 return (0); 120 121 (*xlator)((unsigned char *) &scn->s_shdr, sizeof(scn->s_shdr), 122 src, (size_t) 1, swapbytes); 123 124 if (ec == ELFCLASS32) { 125 scn->s_offset = scn->s_rawoff = 126 scn->s_shdr.s_shdr32.sh_offset; 127 scn->s_size = scn->s_shdr.s_shdr32.sh_size; 128 } else { 129 scn->s_offset = scn->s_rawoff = 130 scn->s_shdr.s_shdr64.sh_offset; 131 scn->s_size = scn->s_shdr.s_shdr64.sh_size; 132 } 133 } 134 135 e->e_flags |= LIBELF_F_SHDRS_LOADED; 136 137 return (1); 138 } 139 140 141 Elf_Scn * 142 elf_getscn(Elf *e, size_t index) 143 { 144 void *ehdr; 145 Elf_Scn *s; 146 unsigned int ec; 147 148 if (e == NULL || e->e_kind != ELF_K_ELF || 149 ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { 150 LIBELF_SET_ERROR(ARGUMENT, 0); 151 return (NULL); 152 } 153 154 if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) 155 return (NULL); 156 157 if (e->e_cmd != ELF_C_WRITE && 158 (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 && 159 _libelf_load_section_headers(e, ehdr) == 0) 160 return (NULL); 161 162 STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) 163 if (s->s_ndx == index) 164 return (s); 165 166 LIBELF_SET_ERROR(ARGUMENT, 0); 167 return (NULL); 168 } 169 170 size_t 171 elf_ndxscn(Elf_Scn *s) 172 { 173 if (s == NULL) { 174 LIBELF_SET_ERROR(ARGUMENT, 0); 175 return (SHN_UNDEF); 176 } 177 return (s->s_ndx); 178 } 179 180 Elf_Scn * 181 elf_newscn(Elf *e) 182 { 183 void *ehdr; 184 Elf_Scn *scn; 185 unsigned int ec; 186 187 if (e == NULL || e->e_kind != ELF_K_ELF) { 188 LIBELF_SET_ERROR(ARGUMENT, 0); 189 return (NULL); 190 } 191 192 if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) { 193 LIBELF_SET_ERROR(CLASS, 0); 194 return (NULL); 195 } 196 197 if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) 198 return (NULL); 199 200 /* 201 * The application may be asking for a new section descriptor 202 * on an ELF object opened with ELF_C_RDWR or ELF_C_READ. We 203 * need to bring in the existing section information before 204 * appending a new one to the list. 205 * 206 * Per the ELF(3) API, an application is allowed to open a 207 * file using ELF_C_READ, mess with its internal structure and 208 * use elf_update(...,ELF_C_NULL) to compute its new layout. 209 */ 210 if (e->e_cmd != ELF_C_WRITE && 211 (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 && 212 _libelf_load_section_headers(e, ehdr) == 0) 213 return (NULL); 214 215 if (STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) { 216 assert(e->e_u.e_elf.e_nscn == 0); 217 if ((scn = _libelf_allocate_scn(e, (size_t) SHN_UNDEF)) == 218 NULL) 219 return (NULL); 220 e->e_u.e_elf.e_nscn++; 221 } 222 223 assert(e->e_u.e_elf.e_nscn > 0); 224 225 if ((scn = _libelf_allocate_scn(e, e->e_u.e_elf.e_nscn)) == NULL) 226 return (NULL); 227 228 e->e_u.e_elf.e_nscn++; 229 230 (void) elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY); 231 232 return (scn); 233 } 234 235 Elf_Scn * 236 elf_nextscn(Elf *e, Elf_Scn *s) 237 { 238 if (e == NULL || (e->e_kind != ELF_K_ELF) || 239 (s && s->s_elf != e)) { 240 LIBELF_SET_ERROR(ARGUMENT, 0); 241 return (NULL); 242 } 243 244 return (s == NULL ? elf_getscn(e, (size_t) 1) : 245 STAILQ_NEXT(s, s_next)); 246 } 247