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