1 /*
2 * newscn.c - implementation of the elf_newscn(3) function.
3 * Copyright (C) 1995 - 2006 Michael Riepe
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <private.h>
21
22 #ifndef lint
23 static const char rcsid[] = "@(#) $Id: newscn.c,v 1.13 2008/05/23 08:15:35 michael Exp $";
24 #endif /* lint */
25
26 int
_elf_update_shnum(Elf * elf,size_t shnum)27 _elf_update_shnum(Elf *elf, size_t shnum) {
28 size_t extshnum = 0;
29 Elf_Scn *scn;
30
31 elf_assert(elf);
32 elf_assert(elf->e_ehdr);
33 scn = elf->e_scn_1;
34 elf_assert(scn);
35 elf_assert(scn->s_index == 0);
36 if (shnum >= SHN_LORESERVE) {
37 extshnum = shnum;
38 shnum = 0;
39 }
40 if (elf->e_class == ELFCLASS32) {
41 ((Elf32_Ehdr*)elf->e_ehdr)->e_shnum = shnum;
42 scn->s_shdr32.sh_size = extshnum;
43 }
44 #if __LIBELF64
45 else if (elf->e_class == ELFCLASS64) {
46 ((Elf64_Ehdr*)elf->e_ehdr)->e_shnum = shnum;
47 scn->s_shdr64.sh_size = extshnum;
48 }
49 #endif /* __LIBELF64 */
50 else {
51 if (valid_class(elf->e_class)) {
52 seterr(ERROR_UNIMPLEMENTED);
53 }
54 else {
55 seterr(ERROR_UNKNOWN_CLASS);
56 }
57 return -1;
58 }
59 elf->e_ehdr_flags |= ELF_F_DIRTY;
60 scn->s_shdr_flags |= ELF_F_DIRTY;
61 return 0;
62 }
63
64 static Elf_Scn*
_makescn(Elf * elf,size_t index)65 _makescn(Elf *elf, size_t index) {
66 Elf_Scn *scn;
67
68 elf_assert(elf);
69 elf_assert(elf->e_magic == ELF_MAGIC);
70 elf_assert(elf->e_ehdr);
71 elf_assert(_elf_scn_init.s_magic == SCN_MAGIC);
72 if (!(scn = (Elf_Scn*)malloc(sizeof(*scn)))) {
73 seterr(ERROR_MEM_SCN);
74 return NULL;
75 }
76 *scn = _elf_scn_init;
77 scn->s_elf = elf;
78 scn->s_scn_flags = ELF_F_DIRTY;
79 scn->s_shdr_flags = ELF_F_DIRTY;
80 scn->s_freeme = 1;
81 scn->s_index = index;
82 return scn;
83 }
84
85 Elf_Scn*
_elf_first_scn(Elf * elf)86 _elf_first_scn(Elf *elf) {
87 Elf_Scn *scn;
88
89 elf_assert(elf);
90 elf_assert(elf->e_magic == ELF_MAGIC);
91 if ((scn = elf->e_scn_1)) {
92 return scn;
93 }
94 if ((scn = _makescn(elf, 0))) {
95 elf->e_scn_1 = elf->e_scn_n = scn;
96 if (_elf_update_shnum(elf, 1)) {
97 free(scn);
98 elf->e_scn_1 = elf->e_scn_n = scn = NULL;
99 }
100 }
101 return scn;
102 }
103
104 static Elf_Scn*
_buildscn(Elf * elf)105 _buildscn(Elf *elf) {
106 Elf_Scn *scn;
107
108 if (!_elf_first_scn(elf)) {
109 return NULL;
110 }
111 scn = elf->e_scn_n;
112 elf_assert(scn);
113 if (!(scn = _makescn(elf, scn->s_index + 1))) {
114 return NULL;
115 }
116 if (_elf_update_shnum(elf, scn->s_index + 1)) {
117 free(scn);
118 return NULL;
119 }
120 elf->e_scn_n = elf->e_scn_n->s_link = scn;
121 return scn;
122 }
123
124 Elf_Scn*
elf_newscn(Elf * elf)125 elf_newscn(Elf *elf) {
126 Elf_Scn *scn;
127
128 if (!elf) {
129 return NULL;
130 }
131 elf_assert(elf->e_magic == ELF_MAGIC);
132 if (!elf->e_readable && !elf->e_ehdr) {
133 seterr(ERROR_NOEHDR);
134 }
135 else if (elf->e_kind != ELF_K_ELF) {
136 seterr(ERROR_NOTELF);
137 }
138 else if (!elf->e_ehdr && !_elf_cook(elf)) {
139 return NULL;
140 }
141 else if ((scn = _buildscn(elf))) {
142 return scn;
143 }
144 return NULL;
145 }
146