1*d29b2c44Sab196087 /*
2*d29b2c44Sab196087 * CDDL HEADER START
3*d29b2c44Sab196087 *
4*d29b2c44Sab196087 * The contents of this file are subject to the terms of the
5*d29b2c44Sab196087 * Common Development and Distribution License (the "License").
6*d29b2c44Sab196087 * You may not use this file except in compliance with the License.
7*d29b2c44Sab196087 *
8*d29b2c44Sab196087 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d29b2c44Sab196087 * or http://www.opensolaris.org/os/licensing.
10*d29b2c44Sab196087 * See the License for the specific language governing permissions
11*d29b2c44Sab196087 * and limitations under the License.
12*d29b2c44Sab196087 *
13*d29b2c44Sab196087 * When distributing Covered Code, include this CDDL HEADER in each
14*d29b2c44Sab196087 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d29b2c44Sab196087 * If applicable, add the following below this CDDL HEADER, with the
16*d29b2c44Sab196087 * fields enclosed by brackets "[]" replaced with your own identifying
17*d29b2c44Sab196087 * information: Portions Copyright [yyyy] [name of copyright owner]
18*d29b2c44Sab196087 *
19*d29b2c44Sab196087 * CDDL HEADER END
20*d29b2c44Sab196087 */
21*d29b2c44Sab196087
22*d29b2c44Sab196087 /*
23*d29b2c44Sab196087 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24*d29b2c44Sab196087 * Use is subject to license terms.
25*d29b2c44Sab196087 */
26*d29b2c44Sab196087 #pragma ident "%Z%%M% %I% %E% SMI"
27*d29b2c44Sab196087
28*d29b2c44Sab196087 #include <stdlib.h>
29*d29b2c44Sab196087 #include <stdio.h>
30*d29b2c44Sab196087 #include <unistd.h>
31*d29b2c44Sab196087 #include <libintl.h>
32*d29b2c44Sab196087 #include <libelf.h>
33*d29b2c44Sab196087 #include <sys/machelf.h>
34*d29b2c44Sab196087 #include <link.h>
35*d29b2c44Sab196087 #include <strings.h>
36*d29b2c44Sab196087 #include <ctype.h>
37*d29b2c44Sab196087 #include <elfedit.h>
38*d29b2c44Sab196087 #include <_elfedit.h>
39*d29b2c44Sab196087 #include <sys/elf_SPARC.h>
40*d29b2c44Sab196087 #include <sys/elf_amd64.h>
41*d29b2c44Sab196087 #include <msg.h>
42*d29b2c44Sab196087
43*d29b2c44Sab196087
44*d29b2c44Sab196087
45*d29b2c44Sab196087 /*
46*d29b2c44Sab196087 * This file contains utility functions that are of general use
47*d29b2c44Sab196087 * to different elfedit modules for solving common problems.
48*d29b2c44Sab196087 * The functions in this file are not ELFCLASS specific. Those
49*d29b2c44Sab196087 * functions are found in util_machelf.c
50*d29b2c44Sab196087 *
51*d29b2c44Sab196087 * NOTE: This module contains functions with names
52*d29b2c44Sab196087 * elfedit_atoi, and elfedit_atoui, that are otherwise identical.
53*d29b2c44Sab196087 * These functions are for signed, and unsigned integers, respectively.
54*d29b2c44Sab196087 * In general, I supply one comment header for each such pair,
55*d29b2c44Sab196087 * and put their implementations together.
56*d29b2c44Sab196087 *
57*d29b2c44Sab196087 * There are also functions with names elfedit_atoconst. These are
58*d29b2c44Sab196087 * convenience wrappers that use the corresponding elfedit_atoui()
59*d29b2c44Sab196087 * function to process an array of symbolic names provided by a call
60*d29b2c44Sab196087 * elfedit_const_to_atoui().
61*d29b2c44Sab196087 */
62*d29b2c44Sab196087
63*d29b2c44Sab196087
64*d29b2c44Sab196087
65*d29b2c44Sab196087
66*d29b2c44Sab196087 /*
67*d29b2c44Sab196087 * Given a value and an array of elfedit_ato[u]i items, return a pointer
68*d29b2c44Sab196087 * to the symbolic name for the value.
69*d29b2c44Sab196087 *
70*d29b2c44Sab196087 * entry:
71*d29b2c44Sab196087 * sym - NULL terminated array of name->value mappings.
72*d29b2c44Sab196087 * value - Value to be found
73*d29b2c44Sab196087 * required - If True, and value is not found, an error is issued.
74*d29b2c44Sab196087 * Callers should only set required to True when they know
75*d29b2c44Sab196087 * a priori that the value will be found --- the error
76*d29b2c44Sab196087 * is reported as an internal programming error.
77*d29b2c44Sab196087 *
78*d29b2c44Sab196087 * exit:
79*d29b2c44Sab196087 * If the array contains an entry with the given value, the
80*d29b2c44Sab196087 * name for the first such entry will be returned.
81*d29b2c44Sab196087 *
82*d29b2c44Sab196087 * If no entry is found: If required is True (1), an error is
83*d29b2c44Sab196087 * issued and this routine does not return to the caller. If required
84*d29b2c44Sab196087 * is False (0), then NULL is returned.
85*d29b2c44Sab196087 */
86*d29b2c44Sab196087 const char *
elfedit_atoi_value_to_str(const elfedit_atoi_sym_t * sym,elfedit_atoi_t value,int required)87*d29b2c44Sab196087 elfedit_atoi_value_to_str(const elfedit_atoi_sym_t *sym, elfedit_atoi_t value,
88*d29b2c44Sab196087 int required)
89*d29b2c44Sab196087 {
90*d29b2c44Sab196087 for (; sym->sym_name != NULL; sym++)
91*d29b2c44Sab196087 if (value == sym->sym_value)
92*d29b2c44Sab196087 return (sym->sym_name);
93*d29b2c44Sab196087
94*d29b2c44Sab196087 /* Value did not match any of the entries */
95*d29b2c44Sab196087 if (required)
96*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADGETVAL));
97*d29b2c44Sab196087 return (NULL);
98*d29b2c44Sab196087 }
99*d29b2c44Sab196087 const char *
elfedit_atoui_value_to_str(const elfedit_atoui_sym_t * sym,elfedit_atoui_t value,int required)100*d29b2c44Sab196087 elfedit_atoui_value_to_str(const elfedit_atoui_sym_t *sym,
101*d29b2c44Sab196087 elfedit_atoui_t value, int required)
102*d29b2c44Sab196087 {
103*d29b2c44Sab196087 for (; sym->sym_name != NULL; sym++)
104*d29b2c44Sab196087 if (value == sym->sym_value)
105*d29b2c44Sab196087 return (sym->sym_name);
106*d29b2c44Sab196087
107*d29b2c44Sab196087 /* Value did not match any of the entries */
108*d29b2c44Sab196087 if (required)
109*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADGETVAL));
110*d29b2c44Sab196087 return (NULL);
111*d29b2c44Sab196087 }
112*d29b2c44Sab196087 const char *
elfedit_atoconst_value_to_str(elfedit_const_t const_type,elfedit_atoui_t value,int required)113*d29b2c44Sab196087 elfedit_atoconst_value_to_str(elfedit_const_t const_type, elfedit_atoui_t value,
114*d29b2c44Sab196087 int required)
115*d29b2c44Sab196087 {
116*d29b2c44Sab196087 return (elfedit_atoui_value_to_str(elfedit_const_to_atoui(const_type),
117*d29b2c44Sab196087 value, required));
118*d29b2c44Sab196087 }
119*d29b2c44Sab196087
120*d29b2c44Sab196087
121*d29b2c44Sab196087 /*
122*d29b2c44Sab196087 * Process the symbolic name to value mappings passed to the
123*d29b2c44Sab196087 * atoi and atoui functions.
124*d29b2c44Sab196087 *
125*d29b2c44Sab196087 * entry:
126*d29b2c44Sab196087 * sym - NULL terminated array of name->value mappings.
127*d29b2c44Sab196087 * value - Address of variable to recieve corresponding value.
128*d29b2c44Sab196087 *
129*d29b2c44Sab196087 * exit:
130*d29b2c44Sab196087 * If a mapping is found, *value is set to it, and True is returned.
131*d29b2c44Sab196087 * Otherwise False is returned.
132*d29b2c44Sab196087 */
133*d29b2c44Sab196087 static int
atoi_sym_process(const char * str,const elfedit_atoi_sym_t * sym,elfedit_atoi_t * value)134*d29b2c44Sab196087 atoi_sym_process(const char *str, const elfedit_atoi_sym_t *sym,
135*d29b2c44Sab196087 elfedit_atoi_t *value)
136*d29b2c44Sab196087 {
137*d29b2c44Sab196087 size_t cmp_len;
138*d29b2c44Sab196087 const char *tail;
139*d29b2c44Sab196087
140*d29b2c44Sab196087 while (isspace(*str))
141*d29b2c44Sab196087 str++;
142*d29b2c44Sab196087
143*d29b2c44Sab196087 tail = str + strlen(str);
144*d29b2c44Sab196087 while ((tail > str) && isspace(*(tail - 1)))
145*d29b2c44Sab196087 tail--;
146*d29b2c44Sab196087
147*d29b2c44Sab196087 cmp_len = tail - str;
148*d29b2c44Sab196087
149*d29b2c44Sab196087 for (; sym->sym_name != NULL; sym++) {
150*d29b2c44Sab196087 if ((strlen(sym->sym_name) == cmp_len) &&
151*d29b2c44Sab196087 (strncasecmp(sym->sym_name, str, cmp_len) == 0)) {
152*d29b2c44Sab196087 *value = sym->sym_value;
153*d29b2c44Sab196087 return (1);
154*d29b2c44Sab196087 }
155*d29b2c44Sab196087 }
156*d29b2c44Sab196087
157*d29b2c44Sab196087 /* No symbolic mapping was found */
158*d29b2c44Sab196087 return (0);
159*d29b2c44Sab196087 }
160*d29b2c44Sab196087 static int
atoui_sym_process(const char * str,const elfedit_atoui_sym_t * sym,elfedit_atoui_t * value)161*d29b2c44Sab196087 atoui_sym_process(const char *str, const elfedit_atoui_sym_t *sym,
162*d29b2c44Sab196087 elfedit_atoui_t *value)
163*d29b2c44Sab196087 {
164*d29b2c44Sab196087 size_t cmp_len;
165*d29b2c44Sab196087 const char *tail;
166*d29b2c44Sab196087
167*d29b2c44Sab196087 while (isspace(*str))
168*d29b2c44Sab196087 str++;
169*d29b2c44Sab196087
170*d29b2c44Sab196087 tail = str + strlen(str);
171*d29b2c44Sab196087 while ((tail > str) && isspace(*(tail - 1)))
172*d29b2c44Sab196087 tail--;
173*d29b2c44Sab196087
174*d29b2c44Sab196087 cmp_len = tail - str;
175*d29b2c44Sab196087
176*d29b2c44Sab196087 for (; sym->sym_name != NULL; sym++) {
177*d29b2c44Sab196087 if ((strlen(sym->sym_name) == cmp_len) &&
178*d29b2c44Sab196087 (strncasecmp(sym->sym_name, str, cmp_len) == 0)) {
179*d29b2c44Sab196087 *value = sym->sym_value;
180*d29b2c44Sab196087 return (1);
181*d29b2c44Sab196087 }
182*d29b2c44Sab196087 }
183*d29b2c44Sab196087
184*d29b2c44Sab196087 /* No symbolic mapping was found */
185*d29b2c44Sab196087 return (0);
186*d29b2c44Sab196087 }
187*d29b2c44Sab196087
188*d29b2c44Sab196087
189*d29b2c44Sab196087
190*d29b2c44Sab196087 /*
191*d29b2c44Sab196087 * A command completion function for atoi and atoui mappings.
192*d29b2c44Sab196087 */
193*d29b2c44Sab196087 void
elfedit_cpl_atoi(void * cpldata,const elfedit_atoi_sym_t * sym)194*d29b2c44Sab196087 elfedit_cpl_atoi(void *cpldata, const elfedit_atoi_sym_t *sym)
195*d29b2c44Sab196087 {
196*d29b2c44Sab196087 for (; sym->sym_name != NULL; sym++)
197*d29b2c44Sab196087 elfedit_cpl_match(cpldata, sym->sym_name, 1);
198*d29b2c44Sab196087 }
199*d29b2c44Sab196087 void
elfedit_cpl_atoui(void * cpldata,const elfedit_atoui_sym_t * sym)200*d29b2c44Sab196087 elfedit_cpl_atoui(void *cpldata, const elfedit_atoui_sym_t *sym)
201*d29b2c44Sab196087 {
202*d29b2c44Sab196087 for (; sym->sym_name != NULL; sym++)
203*d29b2c44Sab196087 elfedit_cpl_match(cpldata, sym->sym_name, 1);
204*d29b2c44Sab196087 }
205*d29b2c44Sab196087 void
elfedit_cpl_atoconst(void * cpldata,elfedit_const_t const_type)206*d29b2c44Sab196087 elfedit_cpl_atoconst(void *cpldata, elfedit_const_t const_type)
207*d29b2c44Sab196087 {
208*d29b2c44Sab196087 elfedit_cpl_atoui(cpldata, elfedit_const_to_atoui(const_type));
209*d29b2c44Sab196087 }
210*d29b2c44Sab196087
211*d29b2c44Sab196087
212*d29b2c44Sab196087
213*d29b2c44Sab196087
214*d29b2c44Sab196087
215*d29b2c44Sab196087 /*
216*d29b2c44Sab196087 * Convert a string to a numeric value. Strings starting with '0'
217*d29b2c44Sab196087 * are taken to be octal, those staring with '0x' are hex, and all
218*d29b2c44Sab196087 * others are decimal.
219*d29b2c44Sab196087 *
220*d29b2c44Sab196087 * entry:
221*d29b2c44Sab196087 * str - String to be converted
222*d29b2c44Sab196087 * sym - NULL, or NULL terminated array of name/value pairs.
223*d29b2c44Sab196087 *
224*d29b2c44Sab196087 * [elfedit_atoi2() and elfedit_atoui2() only]
225*d29b2c44Sab196087 * v - Address of variable to receive resulting value.
226*d29b2c44Sab196087 *
227*d29b2c44Sab196087 * exit:
228*d29b2c44Sab196087 * elfedit_atoi2() and elfedit_atoui2():
229*d29b2c44Sab196087 * On success, returns True (1) and *v is set to the value.
230*d29b2c44Sab196087 * On failure, returns False (0) and *v is undefined.
231*d29b2c44Sab196087 *
232*d29b2c44Sab196087 * elfedit_atoi() and elfedit_atoui():
233*d29b2c44Sab196087 * If the string is convertable, the value is returned.
234*d29b2c44Sab196087 * Otherwise an error is issued and this routine does
235*d29b2c44Sab196087 * not return to the caller.
236*d29b2c44Sab196087 */
237*d29b2c44Sab196087 int
elfedit_atoi2(const char * str,const elfedit_atoi_sym_t * sym,elfedit_atoi_t * v)238*d29b2c44Sab196087 elfedit_atoi2(const char *str, const elfedit_atoi_sym_t *sym, elfedit_atoi_t *v)
239*d29b2c44Sab196087 {
240*d29b2c44Sab196087 char *endptr;
241*d29b2c44Sab196087
242*d29b2c44Sab196087 if (sym && atoi_sym_process(str, sym, v))
243*d29b2c44Sab196087 return (1);
244*d29b2c44Sab196087
245*d29b2c44Sab196087 *v = strtoll(str, &endptr, 0);
246*d29b2c44Sab196087
247*d29b2c44Sab196087 /* If the left over part contains anything but whitespace, fail */
248*d29b2c44Sab196087 for (; *endptr; endptr++)
249*d29b2c44Sab196087 if (!isspace(*endptr))
250*d29b2c44Sab196087 return (0);
251*d29b2c44Sab196087 return (1);
252*d29b2c44Sab196087 }
253*d29b2c44Sab196087 elfedit_atoi_t
elfedit_atoi(const char * str,const elfedit_atoi_sym_t * sym)254*d29b2c44Sab196087 elfedit_atoi(const char *str, const elfedit_atoi_sym_t *sym)
255*d29b2c44Sab196087 {
256*d29b2c44Sab196087 elfedit_atoi_t v;
257*d29b2c44Sab196087 if (elfedit_atoi2(str, sym, &v) == 0)
258*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_ERR,
259*d29b2c44Sab196087 MSG_INTL(MSG_ERR_BADATOISTR), str);
260*d29b2c44Sab196087 return (v);
261*d29b2c44Sab196087 }
262*d29b2c44Sab196087 int
elfedit_atoui2(const char * str,const elfedit_atoui_sym_t * sym,elfedit_atoui_t * v)263*d29b2c44Sab196087 elfedit_atoui2(const char *str, const elfedit_atoui_sym_t *sym,
264*d29b2c44Sab196087 elfedit_atoui_t *v)
265*d29b2c44Sab196087 {
266*d29b2c44Sab196087 char *endptr;
267*d29b2c44Sab196087
268*d29b2c44Sab196087 if (sym && atoui_sym_process(str, sym, v))
269*d29b2c44Sab196087 return (1);
270*d29b2c44Sab196087
271*d29b2c44Sab196087 *v = strtoull(str, &endptr, 0);
272*d29b2c44Sab196087
273*d29b2c44Sab196087 /* If the left over part contains anything but whitespace, fail */
274*d29b2c44Sab196087 for (; *endptr; endptr++)
275*d29b2c44Sab196087 if (!isspace(*endptr))
276*d29b2c44Sab196087 return (0);
277*d29b2c44Sab196087 return (1);
278*d29b2c44Sab196087 }
279*d29b2c44Sab196087 elfedit_atoui_t
elfedit_atoui(const char * str,const elfedit_atoui_sym_t * sym)280*d29b2c44Sab196087 elfedit_atoui(const char *str, const elfedit_atoui_sym_t *sym)
281*d29b2c44Sab196087 {
282*d29b2c44Sab196087 elfedit_atoui_t v;
283*d29b2c44Sab196087 if (elfedit_atoui2(str, sym, &v) == 0)
284*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_ERR,
285*d29b2c44Sab196087 MSG_INTL(MSG_ERR_BADATOISTR), str);
286*d29b2c44Sab196087 return (v);
287*d29b2c44Sab196087 }
288*d29b2c44Sab196087 int
elfedit_atoconst2(const char * str,elfedit_const_t const_type,elfedit_atoui_t * v)289*d29b2c44Sab196087 elfedit_atoconst2(const char *str, elfedit_const_t const_type,
290*d29b2c44Sab196087 elfedit_atoui_t *v)
291*d29b2c44Sab196087 {
292*d29b2c44Sab196087 return (elfedit_atoui2(str, elfedit_const_to_atoui(const_type), v));
293*d29b2c44Sab196087 }
294*d29b2c44Sab196087 elfedit_atoui_t
elfedit_atoconst(const char * str,elfedit_const_t const_type)295*d29b2c44Sab196087 elfedit_atoconst(const char *str, elfedit_const_t const_type)
296*d29b2c44Sab196087 {
297*d29b2c44Sab196087 return (elfedit_atoui(str, elfedit_const_to_atoui(const_type)));
298*d29b2c44Sab196087 }
299*d29b2c44Sab196087
300*d29b2c44Sab196087 /*
301*d29b2c44Sab196087 * Convert a string to a numeric value using elfedit_ato[u]i and
302*d29b2c44Sab196087 * ensure that the resulting value lies within a given range.
303*d29b2c44Sab196087 * elfedit_ato[u]i_range() requires values to be in the range
304*d29b2c44Sab196087 * (min <= value <= max).
305*d29b2c44Sab196087 *
306*d29b2c44Sab196087 * entry:
307*d29b2c44Sab196087 * str - String to be converted
308*d29b2c44Sab196087 * min, max - If check_range is true, the allowed range that the
309*d29b2c44Sab196087 * resulting value must lie in.
310*d29b2c44Sab196087 * sym - NULL, or NULL terminated array of name/value pairs.
311*d29b2c44Sab196087 *
312*d29b2c44Sab196087 * entry [elfedit_atoi_range() and elfedit_atoui_range() only]:
313*d29b2c44Sab196087 * item_name - String describing item for which value is being read.
314*d29b2c44Sab196087 *
315*d29b2c44Sab196087 * entry [elfedit_atoi_range2() and elfedit_atoui_range2() only]:
316*d29b2c44Sab196087 * v - Address of variable to receive resulting value.
317*d29b2c44Sab196087 *
318*d29b2c44Sab196087 * exit:
319*d29b2c44Sab196087 * elfedit_atoi_range2() and elfedit_atoui_range2():
320*d29b2c44Sab196087 * On success, returns True (1) and *v is set to the value.
321*d29b2c44Sab196087 * On failure, returns False (0) and *v is undefined.
322*d29b2c44Sab196087 *
323*d29b2c44Sab196087 * elfedit_atoi_range() and elfedit_atoui_range():
324*d29b2c44Sab196087 * If the string is convertable, the value is returned.
325*d29b2c44Sab196087 * Otherwise an error is issued and this routine does
326*d29b2c44Sab196087 * not return to the caller.
327*d29b2c44Sab196087 */
328*d29b2c44Sab196087 int
elfedit_atoi_range2(const char * str,elfedit_atoi_t min,elfedit_atoi_t max,const elfedit_atoi_sym_t * sym,elfedit_atoi_t * v)329*d29b2c44Sab196087 elfedit_atoi_range2(const char *str, elfedit_atoi_t min, elfedit_atoi_t max,
330*d29b2c44Sab196087 const elfedit_atoi_sym_t *sym, elfedit_atoi_t *v)
331*d29b2c44Sab196087 {
332*d29b2c44Sab196087 return ((elfedit_atoi2(str, sym, v) != 0) &&
333*d29b2c44Sab196087 (*v >= min) && (*v <= max));
334*d29b2c44Sab196087 }
335*d29b2c44Sab196087 elfedit_atoi_t
elfedit_atoi_range(const char * str,const char * item_name,elfedit_atoi_t min,elfedit_atoi_t max,const elfedit_atoi_sym_t * sym)336*d29b2c44Sab196087 elfedit_atoi_range(const char *str, const char *item_name,
337*d29b2c44Sab196087 elfedit_atoi_t min, elfedit_atoi_t max, const elfedit_atoi_sym_t *sym)
338*d29b2c44Sab196087 {
339*d29b2c44Sab196087 elfedit_atoi_t v = elfedit_atoi(str, sym);
340*d29b2c44Sab196087
341*d29b2c44Sab196087 if ((v < min) || (v > max))
342*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ATOIRANGE),
343*d29b2c44Sab196087 item_name, EC_XWORD(min), EC_XWORD(max), EC_XWORD(v));
344*d29b2c44Sab196087
345*d29b2c44Sab196087 return (v);
346*d29b2c44Sab196087 }
347*d29b2c44Sab196087 int
elfedit_atoui_range2(const char * str,elfedit_atoui_t min,elfedit_atoui_t max,const elfedit_atoui_sym_t * sym,elfedit_atoui_t * v)348*d29b2c44Sab196087 elfedit_atoui_range2(const char *str, elfedit_atoui_t min, elfedit_atoui_t max,
349*d29b2c44Sab196087 const elfedit_atoui_sym_t *sym, elfedit_atoui_t *v)
350*d29b2c44Sab196087 {
351*d29b2c44Sab196087 return ((elfedit_atoui2(str, sym, v) != 0) &&
352*d29b2c44Sab196087 (*v >= min) && (*v <= max));
353*d29b2c44Sab196087 }
354*d29b2c44Sab196087 elfedit_atoui_t
elfedit_atoui_range(const char * str,const char * item_name,elfedit_atoui_t min,elfedit_atoui_t max,const elfedit_atoui_sym_t * sym)355*d29b2c44Sab196087 elfedit_atoui_range(const char *str, const char *item_name,
356*d29b2c44Sab196087 elfedit_atoui_t min, elfedit_atoui_t max, const elfedit_atoui_sym_t *sym)
357*d29b2c44Sab196087 {
358*d29b2c44Sab196087 elfedit_atoui_t v = elfedit_atoui(str, sym);
359*d29b2c44Sab196087
360*d29b2c44Sab196087 if ((v < min) || (v > max))
361*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ATOUIRANGE),
362*d29b2c44Sab196087 item_name, EC_XWORD(min), EC_XWORD(max), EC_XWORD(v));
363*d29b2c44Sab196087
364*d29b2c44Sab196087 return (v);
365*d29b2c44Sab196087 }
366*d29b2c44Sab196087 int
elfedit_atoconst_range2(const char * str,elfedit_atoui_t min,elfedit_atoui_t max,elfedit_const_t const_type,elfedit_atoui_t * v)367*d29b2c44Sab196087 elfedit_atoconst_range2(const char *str, elfedit_atoui_t min,
368*d29b2c44Sab196087 elfedit_atoui_t max, elfedit_const_t const_type, elfedit_atoui_t *v)
369*d29b2c44Sab196087 {
370*d29b2c44Sab196087 return (elfedit_atoui_range2(str, min, max,
371*d29b2c44Sab196087 elfedit_const_to_atoui(const_type), v));
372*d29b2c44Sab196087 }
373*d29b2c44Sab196087 elfedit_atoui_t
elfedit_atoconst_range(const char * str,const char * item_name,elfedit_atoui_t min,elfedit_atoui_t max,elfedit_const_t const_type)374*d29b2c44Sab196087 elfedit_atoconst_range(const char *str, const char *item_name,
375*d29b2c44Sab196087 elfedit_atoui_t min, elfedit_atoui_t max, elfedit_const_t const_type)
376*d29b2c44Sab196087 {
377*d29b2c44Sab196087 return (elfedit_atoui_range(str, item_name, min, max,
378*d29b2c44Sab196087 elfedit_const_to_atoui(const_type)));
379*d29b2c44Sab196087 }
380*d29b2c44Sab196087
381*d29b2c44Sab196087
382*d29b2c44Sab196087 /*
383*d29b2c44Sab196087 * Convenience wrapper on elfedit_atoui_range() that expects to see
384*d29b2c44Sab196087 * boolean values. Returns 1 for true, and 0 for false.
385*d29b2c44Sab196087 */
386*d29b2c44Sab196087 int
elfedit_atobool(const char * str,const char * item_name)387*d29b2c44Sab196087 elfedit_atobool(const char *str, const char *item_name)
388*d29b2c44Sab196087 {
389*d29b2c44Sab196087
390*d29b2c44Sab196087 return (elfedit_atoconst_range(str, item_name, 0, 1,
391*d29b2c44Sab196087 ELFEDIT_CONST_BOOL) != 0);
392*d29b2c44Sab196087 }
393*d29b2c44Sab196087
394*d29b2c44Sab196087
395*d29b2c44Sab196087
396*d29b2c44Sab196087 /*
397*d29b2c44Sab196087 * Convenience wrapper on elfedit_atoui() to read a section index
398*d29b2c44Sab196087 * that understands the special SHN_ names.
399*d29b2c44Sab196087 *
400*d29b2c44Sab196087 * entry:
401*d29b2c44Sab196087 * str - String to process
402*d29b2c44Sab196087 * shnum - Number of sections in the ELF file
403*d29b2c44Sab196087 *
404*d29b2c44Sab196087 * exit:
405*d29b2c44Sab196087 * If it is possible to convert str to a number, that value
406*d29b2c44Sab196087 * is returned. If the value is out of range for the file,
407*d29b2c44Sab196087 * a warning message to that effect is issued. On failure,
408*d29b2c44Sab196087 * an error is issued and this routine does not return to
409*d29b2c44Sab196087 * the caller.
410*d29b2c44Sab196087 */
411*d29b2c44Sab196087 elfedit_atoui_t
elfedit_atoshndx(const char * str,size_t shnum)412*d29b2c44Sab196087 elfedit_atoshndx(const char *str, size_t shnum)
413*d29b2c44Sab196087 {
414*d29b2c44Sab196087 elfedit_atoui_t ndx;
415*d29b2c44Sab196087
416*d29b2c44Sab196087 ndx = elfedit_atoconst(str, ELFEDIT_CONST_SHN);
417*d29b2c44Sab196087 if ((ndx >= shnum) && ((ndx < SHN_LORESERVE) || (ndx > SHN_HIRESERVE)))
418*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SHNDX_RANGE),
419*d29b2c44Sab196087 EC_WORD(ndx), EC_WORD(shnum-1));
420*d29b2c44Sab196087
421*d29b2c44Sab196087 return (ndx);
422*d29b2c44Sab196087 }
423*d29b2c44Sab196087
424*d29b2c44Sab196087
425*d29b2c44Sab196087
426*d29b2c44Sab196087 /*
427*d29b2c44Sab196087 * Convert an output style string into it's integer constant. This
428*d29b2c44Sab196087 * routine reports success/failure via the return value rather than
429*d29b2c44Sab196087 * by throwing errors so that it can be used to process command
430*d29b2c44Sab196087 * line options at program startup, before
431*d29b2c44Sab196087 * the elfedit framework is initialized.
432*d29b2c44Sab196087 */
433*d29b2c44Sab196087 int
elfedit_atooutstyle(const char * str,elfedit_outstyle_t * outstyle)434*d29b2c44Sab196087 elfedit_atooutstyle(const char *str, elfedit_outstyle_t *outstyle)
435*d29b2c44Sab196087 {
436*d29b2c44Sab196087 int ret;
437*d29b2c44Sab196087 elfedit_atoui_t value;
438*d29b2c44Sab196087
439*d29b2c44Sab196087 ret = atoui_sym_process(str,
440*d29b2c44Sab196087 elfedit_const_to_atoui(ELFEDIT_CONST_OUTSTYLE), &value);
441*d29b2c44Sab196087 if (ret != 0)
442*d29b2c44Sab196087 *outstyle = value;
443*d29b2c44Sab196087 return (ret);
444*d29b2c44Sab196087 }
445*d29b2c44Sab196087
446*d29b2c44Sab196087
447*d29b2c44Sab196087
448*d29b2c44Sab196087
449*d29b2c44Sab196087 /*
450*d29b2c44Sab196087 * Initialize a state block for processing by elfedit_getopt().
451*d29b2c44Sab196087 *
452*d29b2c44Sab196087 * entry:
453*d29b2c44Sab196087 * state - State block to initialize
454*d29b2c44Sab196087 * cmd_name - NULL, or name of command for which we are processing
455*d29b2c44Sab196087 * options.
456*d29b2c44Sab196087 * argc, argv - Address of variables giving number of options and
457*d29b2c44Sab196087 * access to the option strings.
458*d29b2c44Sab196087 *
459*d29b2c44Sab196087 * note:
460*d29b2c44Sab196087 * cmd_name can only be set to NULL when this routine is called
461*d29b2c44Sab196087 * by, or below, a currently active command. Otherwise, results
462*d29b2c44Sab196087 * are undefined (crashing or corruption) if there isn't one.
463*d29b2c44Sab196087 */
464*d29b2c44Sab196087 void
elfedit_getopt_init(elfedit_getopt_state_t * state,int * argc,const char ** argv[])465*d29b2c44Sab196087 elfedit_getopt_init(elfedit_getopt_state_t *state,
466*d29b2c44Sab196087 int *argc, const char **argv[])
467*d29b2c44Sab196087 {
468*d29b2c44Sab196087 elfeditGC_cmd_t *cmd = elfedit_curcmd();
469*d29b2c44Sab196087
470*d29b2c44Sab196087 state->go_argc = argc;
471*d29b2c44Sab196087 state->go_argv = argv;
472*d29b2c44Sab196087 state->go_optarg = cmd->cmd_opt;
473*d29b2c44Sab196087 state->go_idmask = 0;
474*d29b2c44Sab196087 state->go_done = 0;
475*d29b2c44Sab196087 state->go_sglgrp = NULL;
476*d29b2c44Sab196087 }
477*d29b2c44Sab196087
478*d29b2c44Sab196087
479*d29b2c44Sab196087
480*d29b2c44Sab196087 /*
481*d29b2c44Sab196087 * elfedit-centric version of getopt()
482*d29b2c44Sab196087 *
483*d29b2c44Sab196087 * entry:
484*d29b2c44Sab196087 * state - Getopt state, which must have been previously initialized
485*d29b2c44Sab196087 * via a call to elfedit_getopt_init.
486*d29b2c44Sab196087 *
487*d29b2c44Sab196087 * exit:
488*d29b2c44Sab196087 * If an option is matched, this routine returns a pointer to an
489*d29b2c44Sab196087 * elfedit_getopt_ret_t buffer (which comes from the storage used
490*d29b2c44Sab196087 * for state). If there are no more options to process, NULL is returned.
491*d29b2c44Sab196087 *
492*d29b2c44Sab196087 * Syntax errors are reported via elfedit_command_usage(), and this
493*d29b2c44Sab196087 * routine does not return to the caller.
494*d29b2c44Sab196087 *
495*d29b2c44Sab196087 * note:
496*d29b2c44Sab196087 * - The caller should not access the contents of state directly.
497*d29b2c44Sab196087 * Those contents are private, and subject to change.
498*d29b2c44Sab196087 * - Once a call to this routine returns NULL, the argc/argv have
499*d29b2c44Sab196087 * have been ajusted so that they reference the plain arguments.
500*d29b2c44Sab196087 */
501*d29b2c44Sab196087 elfedit_getopt_ret_t *
elfedit_getopt(elfedit_getopt_state_t * state)502*d29b2c44Sab196087 elfedit_getopt(elfedit_getopt_state_t *state)
503*d29b2c44Sab196087 {
504*d29b2c44Sab196087 elfedit_cmd_optarg_t *optarg;
505*d29b2c44Sab196087 const char *argstr;
506*d29b2c44Sab196087 int argc = *(state->go_argc);
507*d29b2c44Sab196087 const char **argv = *(state->go_argv);
508*d29b2c44Sab196087 elfedit_optarg_item_t item;
509*d29b2c44Sab196087 struct {
510*d29b2c44Sab196087 int valid;
511*d29b2c44Sab196087 int is_outstyle;
512*d29b2c44Sab196087 elfedit_getopt_ret_t ret;
513*d29b2c44Sab196087 elfedit_cmd_oa_mask_t excmask;
514*d29b2c44Sab196087 } sgl_with_value;
515*d29b2c44Sab196087
516*d29b2c44Sab196087 if (state->go_sglgrp == NULL) {
517*d29b2c44Sab196087 /*
518*d29b2c44Sab196087 * Reasons to bail out immediately:
519*d29b2c44Sab196087 * - The command does not accept options
520*d29b2c44Sab196087 * - We've already reported the final option.
521*d29b2c44Sab196087 * - There are no more arguments.
522*d29b2c44Sab196087 * - The next argument does not start with '-'
523*d29b2c44Sab196087 */
524*d29b2c44Sab196087 if ((state->go_optarg == NULL) || state->go_done ||
525*d29b2c44Sab196087 (argc <= 0) || (*(argv[0]) != '-')) {
526*d29b2c44Sab196087 state->go_done = 1;
527*d29b2c44Sab196087 return (NULL);
528*d29b2c44Sab196087 }
529*d29b2c44Sab196087
530*d29b2c44Sab196087 argstr = argv[0];
531*d29b2c44Sab196087
532*d29b2c44Sab196087 /* A '-' by itself is a syntax error */
533*d29b2c44Sab196087 if (argstr[1] == '\0')
534*d29b2c44Sab196087 elfedit_command_usage();
535*d29b2c44Sab196087
536*d29b2c44Sab196087 /* A '--' option means we should stop at this point */
537*d29b2c44Sab196087 if ((argstr[1] == '-') && (argstr[2] == '\0')) {
538*d29b2c44Sab196087 (*state->go_argc)--;
539*d29b2c44Sab196087 (*state->go_argv)++;
540*d29b2c44Sab196087 return (NULL);
541*d29b2c44Sab196087 }
542*d29b2c44Sab196087
543*d29b2c44Sab196087 /*
544*d29b2c44Sab196087 * We have a string that starts with a '-'.
545*d29b2c44Sab196087 * Does it match an option?
546*d29b2c44Sab196087 */
547*d29b2c44Sab196087 sgl_with_value.valid = 0;
548*d29b2c44Sab196087 for (optarg = state->go_optarg; optarg->oa_name != NULL; ) {
549*d29b2c44Sab196087 int is_outstyle =
550*d29b2c44Sab196087 (optarg->oa_flags & ELFEDIT_CMDOA_F_INHERIT) &&
551*d29b2c44Sab196087 (optarg->oa_name == ELFEDIT_STDOA_OPT_O);
552*d29b2c44Sab196087 int need_value;
553*d29b2c44Sab196087
554*d29b2c44Sab196087 elfedit_next_optarg(&optarg, &item);
555*d29b2c44Sab196087 need_value = item.oai_flags & ELFEDIT_CMDOA_F_VALUE;
556*d29b2c44Sab196087
557*d29b2c44Sab196087 /*
558*d29b2c44Sab196087 * If the option is a single letter that accepts
559*d29b2c44Sab196087 * a value, then we allow the combined syntax
560*d29b2c44Sab196087 * -ovalue, where no space is reqired between the
561*d29b2c44Sab196087 * option flag and the value string.
562*d29b2c44Sab196087 */
563*d29b2c44Sab196087 if ((item.oai_name[2] == '\0') && need_value &&
564*d29b2c44Sab196087 (argstr[1] == item.oai_name[1]) &&
565*d29b2c44Sab196087 (argstr[2] != '\0')) {
566*d29b2c44Sab196087 /*
567*d29b2c44Sab196087 * We have a match. However, there may also
568*d29b2c44Sab196087 * be a straightforward match that we have
569*d29b2c44Sab196087 * not yet found. If so, we want to prefer that
570*d29b2c44Sab196087 * case over this one. So rather than return
571*d29b2c44Sab196087 * it immediately, we capture the information
572*d29b2c44Sab196087 * and keep looking. If nothing else surfaces,
573*d29b2c44Sab196087 * we'll use this later.
574*d29b2c44Sab196087 */
575*d29b2c44Sab196087 sgl_with_value.valid = 1;
576*d29b2c44Sab196087 sgl_with_value.ret.gor_idmask = item.oai_idmask;
577*d29b2c44Sab196087 sgl_with_value.excmask = item.oai_excmask;
578*d29b2c44Sab196087 sgl_with_value.ret.gor_value = argstr + 2;
579*d29b2c44Sab196087 sgl_with_value.is_outstyle = is_outstyle;
580*d29b2c44Sab196087 continue;
581*d29b2c44Sab196087 }
582*d29b2c44Sab196087
583*d29b2c44Sab196087 /* Try for a straightforward match */
584*d29b2c44Sab196087 if (strcmp(argstr, item.oai_name) == 0) {
585*d29b2c44Sab196087 (*state->go_argc) = --argc;
586*d29b2c44Sab196087 (*state->go_argv) = ++argv;
587*d29b2c44Sab196087
588*d29b2c44Sab196087 /* Mutually exclusive option already seen? */
589*d29b2c44Sab196087 if (item.oai_excmask & state->go_idmask)
590*d29b2c44Sab196087 elfedit_command_usage();
591*d29b2c44Sab196087
592*d29b2c44Sab196087 /* Return the match */
593*d29b2c44Sab196087 state->go_idmask |= item.oai_idmask;
594*d29b2c44Sab196087 state->go_ret.gor_idmask = item.oai_idmask;
595*d29b2c44Sab196087 if (need_value) {
596*d29b2c44Sab196087 /* If out of args, syntax error */
597*d29b2c44Sab196087 if (argc <= 0)
598*d29b2c44Sab196087 elfedit_command_usage();
599*d29b2c44Sab196087 state->go_ret.gor_value = argv[0];
600*d29b2c44Sab196087 (*state->go_argc)--;
601*d29b2c44Sab196087 (*state->go_argv)++;
602*d29b2c44Sab196087 } else {
603*d29b2c44Sab196087 state->go_ret.gor_value = NULL;
604*d29b2c44Sab196087 }
605*d29b2c44Sab196087 if (is_outstyle)
606*d29b2c44Sab196087 elfedit_set_cmd_outstyle(
607*d29b2c44Sab196087 state->go_ret.gor_value);
608*d29b2c44Sab196087 return (&state->go_ret);
609*d29b2c44Sab196087 }
610*d29b2c44Sab196087 }
611*d29b2c44Sab196087
612*d29b2c44Sab196087 /*
613*d29b2c44Sab196087 * No straightforward matches: Did we get a match with
614*d29b2c44Sab196087 * the special single letter and combined value? If so
615*d29b2c44Sab196087 * return that now.
616*d29b2c44Sab196087 */
617*d29b2c44Sab196087 if (sgl_with_value.valid) {
618*d29b2c44Sab196087 (*state->go_argc)--;
619*d29b2c44Sab196087 (*state->go_argv)++;
620*d29b2c44Sab196087
621*d29b2c44Sab196087 /* Mutually exclusive option already seen? */
622*d29b2c44Sab196087 if (sgl_with_value.excmask & state->go_idmask)
623*d29b2c44Sab196087 elfedit_command_usage();
624*d29b2c44Sab196087
625*d29b2c44Sab196087 state->go_idmask |= sgl_with_value.ret.gor_idmask;
626*d29b2c44Sab196087 state->go_ret = sgl_with_value.ret;
627*d29b2c44Sab196087 if (sgl_with_value.is_outstyle)
628*d29b2c44Sab196087 elfedit_set_cmd_outstyle(
629*d29b2c44Sab196087 state->go_ret.gor_value);
630*d29b2c44Sab196087
631*d29b2c44Sab196087 return (&state->go_ret);
632*d29b2c44Sab196087 }
633*d29b2c44Sab196087
634*d29b2c44Sab196087 /*
635*d29b2c44Sab196087 * If nothing above matched, make this option the single
636*d29b2c44Sab196087 * group string and see if the characters in it all match
637*d29b2c44Sab196087 * as single letter options without values.
638*d29b2c44Sab196087 */
639*d29b2c44Sab196087 state->go_sglgrp = argstr + 1; /* Skip '-' */
640*d29b2c44Sab196087 }
641*d29b2c44Sab196087
642*d29b2c44Sab196087 /*
643*d29b2c44Sab196087 * If there is a single group string, take the first character
644*d29b2c44Sab196087 * and try to match it to an 1-letter option that does not
645*d29b2c44Sab196087 * require a value.
646*d29b2c44Sab196087 */
647*d29b2c44Sab196087 if (state->go_sglgrp != NULL) {
648*d29b2c44Sab196087 int ch = *state->go_sglgrp++;
649*d29b2c44Sab196087
650*d29b2c44Sab196087 /* If that is the last character, clear single group mode */
651*d29b2c44Sab196087 if (*state->go_sglgrp == '\0') {
652*d29b2c44Sab196087 (*state->go_argc)--;
653*d29b2c44Sab196087 (*state->go_argv)++;
654*d29b2c44Sab196087 state->go_sglgrp = NULL;
655*d29b2c44Sab196087 }
656*d29b2c44Sab196087
657*d29b2c44Sab196087 for (optarg = state->go_optarg; optarg->oa_name != NULL; ) {
658*d29b2c44Sab196087 elfedit_next_optarg(&optarg, &item);
659*d29b2c44Sab196087
660*d29b2c44Sab196087 if ((item.oai_name[2] == '\0') &&
661*d29b2c44Sab196087 (ch == item.oai_name[1])) {
662*d29b2c44Sab196087 /*
663*d29b2c44Sab196087 * It matches. If the option requires a value
664*d29b2c44Sab196087 * then it cannot be in a group.
665*d29b2c44Sab196087 */
666*d29b2c44Sab196087 if (item.oai_flags & ELFEDIT_CMDOA_F_VALUE)
667*d29b2c44Sab196087 elfedit_command_usage();
668*d29b2c44Sab196087
669*d29b2c44Sab196087 /* Mutually exclusive option already seen? */
670*d29b2c44Sab196087 if (item.oai_excmask & state->go_idmask)
671*d29b2c44Sab196087 elfedit_command_usage();
672*d29b2c44Sab196087
673*d29b2c44Sab196087 /* Return the match */
674*d29b2c44Sab196087 state->go_idmask |= item.oai_idmask;
675*d29b2c44Sab196087 state->go_ret.gor_idmask = item.oai_idmask;
676*d29b2c44Sab196087 state->go_ret.gor_value = NULL;
677*d29b2c44Sab196087 return (&state->go_ret);
678*d29b2c44Sab196087 }
679*d29b2c44Sab196087 }
680*d29b2c44Sab196087 }
681*d29b2c44Sab196087
682*d29b2c44Sab196087 /* Nothing matched. We have a syntax error */
683*d29b2c44Sab196087 elfedit_command_usage();
684*d29b2c44Sab196087 /*NOTREACHED*/
685*d29b2c44Sab196087 return (NULL);
686*d29b2c44Sab196087 }
687*d29b2c44Sab196087
688*d29b2c44Sab196087
689*d29b2c44Sab196087 /*
690*d29b2c44Sab196087 * Return the count of non-zero bits in the value v.
691*d29b2c44Sab196087 *
692*d29b2c44Sab196087 * entry:
693*d29b2c44Sab196087 * v - Value to test
694*d29b2c44Sab196087 * sizeof_orig_v - The result of using the sizeof operator
695*d29b2c44Sab196087 * on the original value of v. The value received
696*d29b2c44Sab196087 * by this routine has been cast to an unsigned 64-bit
697*d29b2c44Sab196087 * integer, so having the caller use sizeof allows us to
698*d29b2c44Sab196087 * avoid testing bits that were not in the original.
699*d29b2c44Sab196087 */
700*d29b2c44Sab196087 int
elfedit_bits_set(u_longlong_t v,int sizeof_orig_v)701*d29b2c44Sab196087 elfedit_bits_set(u_longlong_t v, int sizeof_orig_v)
702*d29b2c44Sab196087 {
703*d29b2c44Sab196087 int nbits = sizeof_orig_v * 8;
704*d29b2c44Sab196087 int mask;
705*d29b2c44Sab196087 int cnt = 0;
706*d29b2c44Sab196087
707*d29b2c44Sab196087 for (mask = 1; (nbits-- > 0) && (cnt < 2); mask *= 2)
708*d29b2c44Sab196087 if (v & mask)
709*d29b2c44Sab196087 cnt++;
710*d29b2c44Sab196087
711*d29b2c44Sab196087 return (cnt);
712*d29b2c44Sab196087 }
713*d29b2c44Sab196087
714*d29b2c44Sab196087
715*d29b2c44Sab196087 /*
716*d29b2c44Sab196087 * "delete" items in an array by copying the following items up
717*d29b2c44Sab196087 * over the "deleted" items and then zero filling the vacated
718*d29b2c44Sab196087 * slots at the bottom.
719*d29b2c44Sab196087 *
720*d29b2c44Sab196087 * entry:
721*d29b2c44Sab196087 * name_str - Array identification prefix to use for debug message
722*d29b2c44Sab196087 * data_start - Address of 1st byte in array
723*d29b2c44Sab196087 * entsize - sizeof a single element of the array
724*d29b2c44Sab196087 * num_ent - # of elements in array
725*d29b2c44Sab196087 * start_ndx - Index of first item to be deleted
726*d29b2c44Sab196087 * cnt - # of items to delete
727*d29b2c44Sab196087 *
728*d29b2c44Sab196087 * exit:
729*d29b2c44Sab196087 * Any errors are issued and control does not return to the
730*d29b2c44Sab196087 * caller. On success, the items have been removed, zero filling
731*d29b2c44Sab196087 * has been done, and debug messages issued.
732*d29b2c44Sab196087 */
733*d29b2c44Sab196087 void
elfedit_array_elts_delete(const char * name_str,void * data_start,size_t entsize,size_t num_ent,size_t start_ndx,size_t cnt)734*d29b2c44Sab196087 elfedit_array_elts_delete(const char *name_str, void *data_start,
735*d29b2c44Sab196087 size_t entsize, size_t num_ent, size_t start_ndx, size_t cnt)
736*d29b2c44Sab196087 {
737*d29b2c44Sab196087 char *data = data_start;
738*d29b2c44Sab196087
739*d29b2c44Sab196087 /* The specified index and range must be in bounds */
740*d29b2c44Sab196087 if ((start_ndx + cnt) > num_ent)
741*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRBNDS),
742*d29b2c44Sab196087 name_str, EC_WORD(num_ent), EC_WORD(num_ent - 1));
743*d29b2c44Sab196087
744*d29b2c44Sab196087 /*
745*d29b2c44Sab196087 * Everything below the deleted items moves up.
746*d29b2c44Sab196087 * Note that bcopy() is documented to handle overlapping
747*d29b2c44Sab196087 * src/dst correctly, so we make no effort to handle this
748*d29b2c44Sab196087 * element by element, but issue a single operation.
749*d29b2c44Sab196087 *
750*d29b2c44Sab196087 * If we're doing the last element, there is nothing to
751*d29b2c44Sab196087 * move up, and we skip this step, moving on to the zeroing below.
752*d29b2c44Sab196087 */
753*d29b2c44Sab196087 if (start_ndx < (num_ent - 1)) {
754*d29b2c44Sab196087 size_t ncpy = num_ent - (start_ndx + cnt);
755*d29b2c44Sab196087
756*d29b2c44Sab196087 bcopy(data + ((start_ndx + cnt) * entsize),
757*d29b2c44Sab196087 data + (start_ndx * entsize), ncpy * entsize);
758*d29b2c44Sab196087 if (ncpy == 1) {
759*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG,
760*d29b2c44Sab196087 MSG_INTL(MSG_DEBUG_ARRCPY_1), name_str,
761*d29b2c44Sab196087 EC_WORD(start_ndx + cnt), EC_WORD(start_ndx));
762*d29b2c44Sab196087 } else {
763*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG,
764*d29b2c44Sab196087 MSG_INTL(MSG_DEBUG_ARRCPY_N), name_str,
765*d29b2c44Sab196087 EC_WORD(start_ndx + cnt),
766*d29b2c44Sab196087 EC_WORD(start_ndx + cnt + ncpy - 1),
767*d29b2c44Sab196087 EC_WORD(start_ndx),
768*d29b2c44Sab196087 EC_WORD(start_ndx + ncpy - 1));
769*d29b2c44Sab196087 }
770*d29b2c44Sab196087 }
771*d29b2c44Sab196087
772*d29b2c44Sab196087 /* Zero out the vacated elements at the end */
773*d29b2c44Sab196087 bzero(data + ((num_ent - cnt) * entsize), entsize * cnt);
774*d29b2c44Sab196087
775*d29b2c44Sab196087 if (cnt == 1) {
776*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRZERO_1),
777*d29b2c44Sab196087 name_str, EC_WORD(num_ent - 1));
778*d29b2c44Sab196087 } else {
779*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRZERO_N),
780*d29b2c44Sab196087 name_str, EC_WORD(num_ent - cnt),
781*d29b2c44Sab196087 EC_WORD(num_ent - 1), EC_WORD(cnt));
782*d29b2c44Sab196087 }
783*d29b2c44Sab196087 }
784*d29b2c44Sab196087
785*d29b2c44Sab196087
786*d29b2c44Sab196087 /*
787*d29b2c44Sab196087 * move the location of items in an array by shifting the surround
788*d29b2c44Sab196087 * items into the vacated hole and them putting the values into
789*d29b2c44Sab196087 * the new location.
790*d29b2c44Sab196087 *
791*d29b2c44Sab196087 * entry:
792*d29b2c44Sab196087 * name_str - Array identification prefix to use for debug message
793*d29b2c44Sab196087 * data_start - Address of 1st byte in array
794*d29b2c44Sab196087 * entsize - sizeof a single element of the array
795*d29b2c44Sab196087 * num_ent - # of elements in array
796*d29b2c44Sab196087 * start_ndx - Index of first item to be moved
797*d29b2c44Sab196087 * dst_ndx - Index to receive the moved block
798*d29b2c44Sab196087 * cnt - # of items to move
799*d29b2c44Sab196087 * scr_item - Space allocated by the caller sufficient to hold
800*d29b2c44Sab196087 * one item from the array. Used to swap elements.
801*d29b2c44Sab196087 *
802*d29b2c44Sab196087 * exit:
803*d29b2c44Sab196087 * Any errors are issued and control does not return to the
804*d29b2c44Sab196087 * caller. On success, the items have been moved, and debug
805*d29b2c44Sab196087 * messages issued.
806*d29b2c44Sab196087 */
807*d29b2c44Sab196087 void
elfedit_array_elts_move(const char * name_str,void * data_start,size_t entsize,size_t num_ent,size_t srcndx,size_t dstndx,size_t cnt,void * scr_item)808*d29b2c44Sab196087 elfedit_array_elts_move(const char *name_str, void *data_start,
809*d29b2c44Sab196087 size_t entsize, size_t num_ent, size_t srcndx,
810*d29b2c44Sab196087 size_t dstndx, size_t cnt, void *scr_item)
811*d29b2c44Sab196087 {
812*d29b2c44Sab196087 char *data = data_start;
813*d29b2c44Sab196087
814*d29b2c44Sab196087 /* The specified source and destination ranges must be in bounds */
815*d29b2c44Sab196087 if (((srcndx + cnt) > num_ent) || ((dstndx + cnt) > num_ent))
816*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRBNDS),
817*d29b2c44Sab196087 name_str, EC_WORD(num_ent), EC_WORD(num_ent - 1));
818*d29b2c44Sab196087
819*d29b2c44Sab196087 /* If source and destination are same, there's nothing to do */
820*d29b2c44Sab196087 if (srcndx == dstndx)
821*d29b2c44Sab196087 return;
822*d29b2c44Sab196087
823*d29b2c44Sab196087 /*
824*d29b2c44Sab196087 * It is meaningless to do a move where the source and destination
825*d29b2c44Sab196087 * are overlapping, because this "move" amounts to shifting
826*d29b2c44Sab196087 * the existing items around into a new position. If there is
827*d29b2c44Sab196087 * more than one element, then overlap is possible and we need
828*d29b2c44Sab196087 * to test for it.
829*d29b2c44Sab196087 */
830*d29b2c44Sab196087 if (cnt > 1) {
831*d29b2c44Sab196087 size_t low, hi;
832*d29b2c44Sab196087
833*d29b2c44Sab196087 if (srcndx > dstndx) {
834*d29b2c44Sab196087 low = dstndx;
835*d29b2c44Sab196087 hi = srcndx;
836*d29b2c44Sab196087 } else {
837*d29b2c44Sab196087 low = srcndx;
838*d29b2c44Sab196087 hi = dstndx;
839*d29b2c44Sab196087 }
840*d29b2c44Sab196087 /* Ensure that the src and dst don't overlap */
841*d29b2c44Sab196087 if ((low + cnt) > hi)
842*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_ERR,
843*d29b2c44Sab196087 MSG_INTL(MSG_ERR_ARRMVOVERLAP), name_str,
844*d29b2c44Sab196087 EC_WORD(srcndx), EC_WORD(srcndx + cnt - 1),
845*d29b2c44Sab196087 EC_WORD(dstndx), EC_WORD(dstndx + cnt - 1));
846*d29b2c44Sab196087 }
847*d29b2c44Sab196087
848*d29b2c44Sab196087 if (cnt == 1)
849*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRMOVE_1),
850*d29b2c44Sab196087 name_str, EC_WORD(srcndx), EC_WORD(dstndx));
851*d29b2c44Sab196087 else
852*d29b2c44Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRMOVE_N),
853*d29b2c44Sab196087 name_str, EC_WORD(cnt),
854*d29b2c44Sab196087 EC_WORD(srcndx), EC_WORD(srcndx + cnt - 1),
855*d29b2c44Sab196087 EC_WORD(dstndx), EC_WORD(dstndx + cnt - 1));
856*d29b2c44Sab196087
857*d29b2c44Sab196087 if (srcndx < dstndx) {
858*d29b2c44Sab196087 srcndx += cnt - 1;
859*d29b2c44Sab196087 dstndx += cnt - 1;
860*d29b2c44Sab196087 for (; cnt-- > 0; srcndx--, dstndx--) {
861*d29b2c44Sab196087 /*
862*d29b2c44Sab196087 * Copy item at srcndx to scratch location
863*d29b2c44Sab196087 *
864*d29b2c44Sab196087 * save = dyn[srcndx];
865*d29b2c44Sab196087 */
866*d29b2c44Sab196087 bcopy(data + (srcndx * entsize), scr_item, entsize);
867*d29b2c44Sab196087
868*d29b2c44Sab196087 /*
869*d29b2c44Sab196087 * Shift items after source up through destination
870*d29b2c44Sab196087 * to source. bcopy() handles overlapped copies.
871*d29b2c44Sab196087 *
872*d29b2c44Sab196087 * for (i = srcndx; i < dstndx; i++)
873*d29b2c44Sab196087 * dyn[i] = dyn[i + 1];
874*d29b2c44Sab196087 */
875*d29b2c44Sab196087 bcopy(data + ((srcndx + 1) * entsize),
876*d29b2c44Sab196087 data + (srcndx * entsize),
877*d29b2c44Sab196087 (dstndx - srcndx) * entsize);
878*d29b2c44Sab196087
879*d29b2c44Sab196087 /*
880*d29b2c44Sab196087 * Copy saved item into destination slot
881*d29b2c44Sab196087 *
882*d29b2c44Sab196087 * dyn[dstndx] = save;
883*d29b2c44Sab196087 */
884*d29b2c44Sab196087 bcopy(scr_item, data + (dstndx * entsize), entsize);
885*d29b2c44Sab196087 }
886*d29b2c44Sab196087 } else {
887*d29b2c44Sab196087 for (; cnt-- > 0; srcndx++, dstndx++) {
888*d29b2c44Sab196087 /*
889*d29b2c44Sab196087 * Copy item at srcndx to scratch location
890*d29b2c44Sab196087 *
891*d29b2c44Sab196087 * save = dyn[srcndx];
892*d29b2c44Sab196087 */
893*d29b2c44Sab196087 bcopy(data + (srcndx * entsize), scr_item, entsize);
894*d29b2c44Sab196087
895*d29b2c44Sab196087 /*
896*d29b2c44Sab196087 * Shift items from destination through item below
897*d29b2c44Sab196087 * source up one. bcopy() handles overlapped copies.
898*d29b2c44Sab196087 *
899*d29b2c44Sab196087 * for (i = srcndx; i > dstndx; i--)
900*d29b2c44Sab196087 * dyn[i] = dyn[i - 1];
901*d29b2c44Sab196087 */
902*d29b2c44Sab196087 bcopy(data + (dstndx * entsize),
903*d29b2c44Sab196087 data + ((dstndx + 1) * entsize),
904*d29b2c44Sab196087 (srcndx - dstndx) * entsize);
905*d29b2c44Sab196087
906*d29b2c44Sab196087 /*
907*d29b2c44Sab196087 * Copy saved item into destination slot
908*d29b2c44Sab196087 *
909*d29b2c44Sab196087 * dyn[dstndx] = save;
910*d29b2c44Sab196087 */
911*d29b2c44Sab196087 bcopy(scr_item, data + (dstndx * entsize), entsize);
912*d29b2c44Sab196087 }
913*d29b2c44Sab196087 }
914*d29b2c44Sab196087 }
915