1/*-
2 * Copyright (c) 2016 Kai Wang
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <errno.h>
28#include <string.h>
29
30#include "_libpe.h"
31
32ELFTC_VCSID("$Id: pe_section.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
33
34PE_Scn *
35pe_getscn(PE *pe, size_t ndx)
36{
37	PE_Scn *ps;
38
39	if (pe == NULL || ndx < 1 || ndx > 0xFFFFU) {
40		errno = EINVAL;
41		return (NULL);
42	}
43
44	STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
45		if (ps->ps_ndx == ndx)
46			return (ps);
47	}
48
49	errno = ENOENT;
50
51	return (NULL);
52}
53
54size_t
55pe_ndxscn(PE_Scn *ps)
56{
57
58	if (ps == NULL) {
59		errno = EINVAL;
60		return (0);
61	}
62
63	return (ps->ps_ndx);
64}
65
66PE_Scn *
67pe_nextscn(PE *pe, PE_Scn *ps)
68{
69
70	if (pe == NULL) {
71		errno = EINVAL;
72		return (NULL);
73	}
74
75	if (ps == NULL)
76		ps = STAILQ_FIRST(&pe->pe_scn);
77	else
78		ps = STAILQ_NEXT(ps, ps_next);
79
80	while (ps != NULL) {
81		if (ps->ps_ndx >= 1 && ps->ps_ndx <= 0xFFFFU)
82			return (ps);
83		ps = STAILQ_NEXT(ps, ps_next);
84	}
85
86	return (NULL);
87}
88
89PE_Scn *
90pe_newscn(PE *pe)
91{
92	PE_Scn *ps, *tps, *_tps;
93
94	if (pe == NULL) {
95		errno = EINVAL;
96		return (NULL);
97	}
98
99	if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
100		errno = EACCES;
101		return (NULL);
102	}
103
104	if ((ps = libpe_alloc_scn(pe)) == NULL)
105		return (NULL);
106
107	if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER) {
108		STAILQ_FOREACH_SAFE(tps, &pe->pe_scn, ps_next, _tps)
109			libpe_release_scn(tps);
110		pe->pe_flags &= ~LIBPE_F_BAD_SEC_HEADER;
111	}
112
113	STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
114
115	ps->ps_flags |= PE_F_DIRTY | LIBPE_F_LOAD_SECTION;
116	pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
117
118	return (ps);
119}
120
121PE_Scn *
122pe_insertscn(PE *pe, size_t ndx)
123{
124	PE_Scn *ps, *a, *b;
125
126	if (pe == NULL || ndx < 1 || ndx > 0xFFFFU) {
127		errno = EINVAL;
128		return (NULL);
129	}
130
131	if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
132		errno = EACCES;
133		return (NULL);
134	}
135
136	if ((ps = libpe_alloc_scn(pe)) == NULL)
137		return (NULL);
138
139	if (pe->pe_flags & LIBPE_F_BAD_SEC_HEADER) {
140		STAILQ_FOREACH_SAFE(a, &pe->pe_scn, ps_next, b)
141			libpe_release_scn(a);
142		pe->pe_flags &= ~LIBPE_F_BAD_SEC_HEADER;
143	}
144
145	b = NULL;
146	STAILQ_FOREACH(a, &pe->pe_scn, ps_next) {
147		if (a->ps_ndx & 0xFFFF0000U)
148			continue;
149		if (a->ps_ndx == ndx)
150			break;
151		b = a;
152	}
153
154	if (a == NULL) {
155		STAILQ_INSERT_TAIL(&pe->pe_scn, ps, ps_next);
156		if (b == NULL)
157			ps->ps_ndx = 1;
158		else
159			ps->ps_ndx = b->ps_ndx + 1;
160	} else if (b == NULL) {
161		STAILQ_INSERT_HEAD(&pe->pe_scn, ps, ps_next);
162		ps->ps_ndx = 1;
163	} else {
164		STAILQ_INSERT_AFTER(&pe->pe_scn, b, ps, ps_next);
165		ps->ps_ndx = ndx;
166	}
167
168	a = ps;
169	while ((a = STAILQ_NEXT(a, ps_next)) != NULL) {
170		if ((a->ps_ndx & 0xFFFF0000U) == 0)
171			a->ps_ndx++;
172	}
173
174	ps->ps_flags |= PE_F_DIRTY | LIBPE_F_LOAD_SECTION;
175	pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
176
177	return (ps);
178}
179
180PE_SecHdr *
181pe_section_header(PE_Scn *ps)
182{
183
184	if (ps == NULL) {
185		errno = EINVAL;
186		return (NULL);
187	}
188
189	return (&ps->ps_sh);
190}
191
192int
193pe_update_section_header(PE_Scn *ps, PE_SecHdr *sh)
194{
195	PE *pe;
196
197	if (ps == NULL || sh == NULL) {
198		errno = EINVAL;
199		return (-1);
200	}
201
202	pe = ps->ps_pe;
203
204	if (pe->pe_cmd == PE_C_READ || pe->pe_flags & LIBPE_F_FD_DONE) {
205		errno = EACCES;
206		return (-1);
207	}
208
209	ps->ps_sh = *sh;
210	pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
211
212	return (0);
213}
214