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