1*69112eddSAli Bahrami /*
2*69112eddSAli Bahrami  * CDDL HEADER START
3*69112eddSAli Bahrami  *
4*69112eddSAli Bahrami  * The contents of this file are subject to the terms of the
5*69112eddSAli Bahrami  * Common Development and Distribution License (the "License").
6*69112eddSAli Bahrami  * You may not use this file except in compliance with the License.
7*69112eddSAli Bahrami  *
8*69112eddSAli Bahrami  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*69112eddSAli Bahrami  * or http://www.opensolaris.org/os/licensing.
10*69112eddSAli Bahrami  * See the License for the specific language governing permissions
11*69112eddSAli Bahrami  * and limitations under the License.
12*69112eddSAli Bahrami  *
13*69112eddSAli Bahrami  * When distributing Covered Code, include this CDDL HEADER in each
14*69112eddSAli Bahrami  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*69112eddSAli Bahrami  * If applicable, add the following below this CDDL HEADER, with the
16*69112eddSAli Bahrami  * fields enclosed by brackets "[]" replaced with your own identifying
17*69112eddSAli Bahrami  * information: Portions Copyright [yyyy] [name of copyright owner]
18*69112eddSAli Bahrami  *
19*69112eddSAli Bahrami  * CDDL HEADER END
20*69112eddSAli Bahrami  */
21*69112eddSAli Bahrami 
22*69112eddSAli Bahrami /*
23*69112eddSAli Bahrami  *	Copyright (c) 1988 AT&T
24*69112eddSAli Bahrami  *	  All Rights Reserved
25*69112eddSAli Bahrami  *
26*69112eddSAli Bahrami  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
27*69112eddSAli Bahrami  * Use is subject to license terms.
28*69112eddSAli Bahrami  */
29*69112eddSAli Bahrami 
30*69112eddSAli Bahrami /*
31*69112eddSAli Bahrami  * Map file parsing (Shared Core Code).
32*69112eddSAli Bahrami  */
33*69112eddSAli Bahrami #include	<fcntl.h>
34*69112eddSAli Bahrami #include	<stdio.h>
35*69112eddSAli Bahrami #include	<unistd.h>
36*69112eddSAli Bahrami #include	<sys/stat.h>
37*69112eddSAli Bahrami #include	<errno.h>
38*69112eddSAli Bahrami #include	<limits.h>
39*69112eddSAli Bahrami #include	<dirent.h>
40*69112eddSAli Bahrami #include	<ctype.h>
41*69112eddSAli Bahrami #include	<debug.h>
42*69112eddSAli Bahrami #include	"msg.h"
43*69112eddSAli Bahrami #include	"_libld.h"
44*69112eddSAli Bahrami #include	"_map.h"
45*69112eddSAli Bahrami 
46*69112eddSAli Bahrami /*
47*69112eddSAli Bahrami  * There are two styles of mapfile supported by the link-editor:
48*69112eddSAli Bahrami  *
49*69112eddSAli Bahrami  * 1)	The original System V defined syntax, as augmented at Sun
50*69112eddSAli Bahrami  *	from Solaris 2.0 through Solaris 10. This style is also known
51*69112eddSAli Bahrami  *	as version 1.
52*69112eddSAli Bahrami  *
53*69112eddSAli Bahrami  * 2)	A newer syntax, currently at version 2.
54*69112eddSAli Bahrami  *
55*69112eddSAli Bahrami  * The original syntax uses special characters (=, :, -, |, etc) as
56*69112eddSAli Bahrami  * operators to indicate the operation being specified. Over the years,
57*69112eddSAli Bahrami  * this syntax has been problematic:
58*69112eddSAli Bahrami  *
59*69112eddSAli Bahrami  * 1)	Too cryptic: It's hard for people to remember which character
60*69112eddSAli Bahrami  *	means what.
61*69112eddSAli Bahrami  *
62*69112eddSAli Bahrami  * 2)	Limited expansion potential: There only a few special characters
63*69112eddSAli Bahrami  *	available on the keyboard for new features, and it is difficult to
64*69112eddSAli Bahrami  *	add options to existing ones.
65*69112eddSAli Bahrami  *
66*69112eddSAli Bahrami  * Adding new features into this framework (2) have the effect of
67*69112eddSAli Bahrami  * making the syntax even more cryptic (1). The newer syntax addresses
68*69112eddSAli Bahrami  * these issues by moving to an extendible identifier based syntax that
69*69112eddSAli Bahrami  * allows new features to be added without complicating old ones.
70*69112eddSAli Bahrami  *
71*69112eddSAli Bahrami  * The new syntax uses the following terminology:
72*69112eddSAli Bahrami  *
73*69112eddSAli Bahrami  * -	Control directives are the directives that start with a '$'.
74*69112eddSAli Bahrami  *	They control how the mapfile is interpreted. We use the 'cdir_'
75*69112eddSAli Bahrami  *	prefix on functions and variables related to these directives.
76*69112eddSAli Bahrami  *
77*69112eddSAli Bahrami  * -	Conditional Expressions are the expressions found in $if and $elif
78*69112eddSAli Bahrami  *	control directives. They evaluate to boolean true/false values.
79*69112eddSAli Bahrami  *	We use the 'cexp_' prefix for functions and variables related to
80*69112eddSAli Bahrami  *	these expressions.
81*69112eddSAli Bahrami  *
82*69112eddSAli Bahrami  * -	Regular Directives are names (SYMBOL, VERSION, etc) that convey
83*69112eddSAli Bahrami  *	directions to the link-editor for building the output object.
84*69112eddSAli Bahrami  *
85*69112eddSAli Bahrami  * This file contains core code used by both mapfile styles: File management,
86*69112eddSAli Bahrami  * lexical analysis, and other shared core functionality. It also contains
87*69112eddSAli Bahrami  * the code for control directives, as they are intrinsically part of
88*69112eddSAli Bahrami  * lexical analysis --- this is disabled when processing Sysv mapfiles.
89*69112eddSAli Bahrami  */
90*69112eddSAli Bahrami 
91*69112eddSAli Bahrami /*
92*69112eddSAli Bahrami  * We use a stack of cdir_level_t structs to manage $if/$elif/$else/$endif
93*69112eddSAli Bahrami  * processing. At each level, we keep track of the information needed to
94*69112eddSAli Bahrami  * determine whether or not to process nested input lines or skip them,
95*69112eddSAli Bahrami  * along with information needed to report errors.
96*69112eddSAli Bahrami  */
97*69112eddSAli Bahrami typedef struct {
98*69112eddSAli Bahrami 	Lineno		cdl_if_lineno;	/* Line number of opening $if */
99*69112eddSAli Bahrami 	Lineno		cdl_else_lineno; /* 0, or line on which $else seen */
100*69112eddSAli Bahrami 	int		cdl_done;	/* True if no longer accepts input */
101*69112eddSAli Bahrami 	int		cdl_pass;	/* True if currently accepting input */
102*69112eddSAli Bahrami } cdir_level_t;
103*69112eddSAli Bahrami 
104*69112eddSAli Bahrami /* Operators in the expressions accepted by $if/$elif */
105*69112eddSAli Bahrami typedef enum {
106*69112eddSAli Bahrami 	CEXP_OP_NONE,		/* Not an operator */
107*69112eddSAli Bahrami 	CEXP_OP_AND,		/* && */
108*69112eddSAli Bahrami 	CEXP_OP_OR,		/* || */
109*69112eddSAli Bahrami 	CEXP_OP_NEG,		/* ! */
110*69112eddSAli Bahrami 	CEXP_OP_OPAR,		/* ( */
111*69112eddSAli Bahrami 	CEXP_OP_CPAR		/* ) */
112*69112eddSAli Bahrami } cexp_op_t;
113*69112eddSAli Bahrami 
114*69112eddSAli Bahrami /*
115*69112eddSAli Bahrami  * Type of conditional expression identifier AVL tree nodes
116*69112eddSAli Bahrami  */
117*69112eddSAli Bahrami typedef struct cexp_name_node {
118*69112eddSAli Bahrami 	avl_node_t	ceid_avlnode;	/* AVL book-keeping */
119*69112eddSAli Bahrami 	const char	*ceid_name;	/* boolean identifier name */
120*69112eddSAli Bahrami } cexp_id_node_t;
121*69112eddSAli Bahrami 
122*69112eddSAli Bahrami 
123*69112eddSAli Bahrami /*
124*69112eddSAli Bahrami  * Declare a "stack" type, containing a pointer to data, a count of
125*69112eddSAli Bahrami  * allocated, and currently used items in the stack. The data type
126*69112eddSAli Bahrami  * is specified as the _type argument.
127*69112eddSAli Bahrami  */
128*69112eddSAli Bahrami #define	STACK(_type) \
129*69112eddSAli Bahrami 	struct { \
130*69112eddSAli Bahrami 		_type	*stk_s;		/* Stack array */ \
131*69112eddSAli Bahrami 		size_t	stk_n;		/* Current stack depth */ \
132*69112eddSAli Bahrami 		size_t	stk_n_alloc;	/* # of elements pointed at by s */ \
133*69112eddSAli Bahrami 	}
134*69112eddSAli Bahrami 
135*69112eddSAli Bahrami /*
136*69112eddSAli Bahrami  * The following type represents a "generic" stack, where the data
137*69112eddSAli Bahrami  * type is (void). This type is never instantiated. However, it has
138*69112eddSAli Bahrami  * the same struct layout as any other STACK(), and is therefore a good
139*69112eddSAli Bahrami  * generic type that can be used for stack_resize().
140*69112eddSAli Bahrami  */
141*69112eddSAli Bahrami typedef STACK(void) generic_stack_t;
142*69112eddSAli Bahrami 
143*69112eddSAli Bahrami /*
144*69112eddSAli Bahrami  * Ensure that the stack has enough room to push one more item
145*69112eddSAli Bahrami  */
146*69112eddSAli Bahrami #define	STACK_RESERVE(_stack, _n_default) \
147*69112eddSAli Bahrami 	(((_stack).stk_n < (_stack).stk_n_alloc) || \
148*69112eddSAli Bahrami 	stack_resize((generic_stack_t *)&(_stack).stk_s, _n_default, \
149*69112eddSAli Bahrami 	sizeof (*(_stack).stk_s)))
150*69112eddSAli Bahrami 
151*69112eddSAli Bahrami /*
152*69112eddSAli Bahrami  * Reset a stack to empty.
153*69112eddSAli Bahrami  */
154*69112eddSAli Bahrami #define	STACK_RESET(_stack) (_stack).stk_n = 0;
155*69112eddSAli Bahrami 
156*69112eddSAli Bahrami /*
157*69112eddSAli Bahrami  * True if stack is empty, False otherwise.
158*69112eddSAli Bahrami  */
159*69112eddSAli Bahrami #define	STACK_IS_EMPTY(_stack) ((_stack).stk_n == 0)
160*69112eddSAli Bahrami 
161*69112eddSAli Bahrami /*
162*69112eddSAli Bahrami  * Push a value onto a stack. Caller must ensure that stack has room.
163*69112eddSAli Bahrami  * This macro is intended to be used as the LHS of an assignment, the
164*69112eddSAli Bahrami  * RHS of which is the value:
165*69112eddSAli Bahrami  *
166*69112eddSAli Bahrami  *	STACK_PUSH(stack) = value;
167*69112eddSAli Bahrami  */
168*69112eddSAli Bahrami #define	STACK_PUSH(_stack) (_stack).stk_s[(_stack).stk_n++]
169*69112eddSAli Bahrami 
170*69112eddSAli Bahrami /*
171*69112eddSAli Bahrami  * Pop a value off a stack.  Caller must ensure
172*69112eddSAli Bahrami  * that stack is not empty.
173*69112eddSAli Bahrami  */
174*69112eddSAli Bahrami #define	STACK_POP(_stack) ((_stack).stk_s[--(_stack).stk_n])
175*69112eddSAli Bahrami 
176*69112eddSAli Bahrami /*
177*69112eddSAli Bahrami  * Access top element on stack without popping. Caller must ensure
178*69112eddSAli Bahrami  * that stack is not empty.
179*69112eddSAli Bahrami  */
180*69112eddSAli Bahrami #define	STACK_TOP(_stack) (((_stack).stk_s)[(_stack).stk_n - 1])
181*69112eddSAli Bahrami 
182*69112eddSAli Bahrami /*
183*69112eddSAli Bahrami  * Initial sizes used for the stacks: The stacks are allocated on demand
184*69112eddSAli Bahrami  * to these sizes, and then doubled as necessary until they are large enough.
185*69112eddSAli Bahrami  *
186*69112eddSAli Bahrami  * The ideal size would be large enough that only a single allocation
187*69112eddSAli Bahrami  * occurs, and our defaults should generally have that effect. However,
188*69112eddSAli Bahrami  * in doing so, we run the risk of a latent error in the resize code going
189*69112eddSAli Bahrami  * undetected until triggered by a large task in the field. For this reason,
190*69112eddSAli Bahrami  * we set the sizes to the smallest size possible when compiled for debug.
191*69112eddSAli Bahrami  */
192*69112eddSAli Bahrami #ifdef DEBUG
193*69112eddSAli Bahrami #define	CDIR_STACK_INIT		1
194*69112eddSAli Bahrami #define	CEXP_OP_STACK_INIT	1
195*69112eddSAli Bahrami #define	CEXP_VAL_STACK_INIT	1
196*69112eddSAli Bahrami #else
197*69112eddSAli Bahrami #define	CDIR_STACK_INIT 	16
198*69112eddSAli Bahrami #define	CEXP_OP_STACK_INIT	8
199*69112eddSAli Bahrami #define	CEXP_VAL_STACK_INIT	(CEXP_OP_STACK_INIT * 2) /* 2 vals per binop */
200*69112eddSAli Bahrami #endif
201*69112eddSAli Bahrami 
202*69112eddSAli Bahrami 
203*69112eddSAli Bahrami /*
204*69112eddSAli Bahrami  * Persistent state maintained by map module in between calls.
205*69112eddSAli Bahrami  *
206*69112eddSAli Bahrami  * This is kept as static file scope data, because it is only used
207*69112eddSAli Bahrami  * when libld is called by ld, and not by rtld. If that should change,
208*69112eddSAli Bahrami  * the code is designed so that it can become reentrant easily:
209*69112eddSAli Bahrami  *
210*69112eddSAli Bahrami  * -	Add a pointer to the output descriptor to a structure of this type,
211*69112eddSAli Bahrami  *	allocated dynamically on the first call to ld_map_parse().
212*69112eddSAli Bahrami  * -	Change all references to lms to instead reference the pointer in
213*69112eddSAli Bahrami  *	the output descriptor.
214*69112eddSAli Bahrami  *
215*69112eddSAli Bahrami  * Until then, it is simpler not to expose these details.
216*69112eddSAli Bahrami  */
217*69112eddSAli Bahrami typedef struct {
218*69112eddSAli Bahrami 	int	lms_cdir_valid;	/* Allow control dir. on entry to gettoken() */
219*69112eddSAli Bahrami 	STACK(cdir_level_t)	lms_cdir_stack;	/* Conditional input level */
220*69112eddSAli Bahrami 	STACK(cexp_op_t)	lms_cexp_op_stack; /* Cond. expr operators */
221*69112eddSAli Bahrami 	STACK(uchar_t)		lms_cexp_val_stack; /* Cond. expr values */
222*69112eddSAli Bahrami 	avl_tree_t		*lms_cexp_id;
223*69112eddSAli Bahrami } ld_map_state_t;
224*69112eddSAli Bahrami static ld_map_state_t lms;
225*69112eddSAli Bahrami 
226*69112eddSAli Bahrami 
227*69112eddSAli Bahrami /*
228*69112eddSAli Bahrami  * Version 1 (SysV) syntax dispatch table for ld_map_gettoken(). For each
229*69112eddSAli Bahrami  * of the 7-bit ASCII characters, determine how the lexical analyzer
230*69112eddSAli Bahrami  * should behave.
231*69112eddSAli Bahrami  *
232*69112eddSAli Bahrami  * This table must be kept in sync with tkid_attr[] below.
233*69112eddSAli Bahrami  *
234*69112eddSAli Bahrami  * Identifier Note:
235*69112eddSAli Bahrami  * The Linker and Libraries Guide states that the original syntax uses
236*69112eddSAli Bahrami  * C identifier rules, allowing '.' to be treated as a letter. However,
237*69112eddSAli Bahrami  * the implementation is considerably looser than that: Any character
238*69112eddSAli Bahrami  * with an ASCII code (0-127) which is printable and not used to start
239*69112eddSAli Bahrami  * another token is allowed to start an identifier, and they are terminated
240*69112eddSAli Bahrami  * by any of: space, double quote, tab, newline, ':', ';', '=', or '#'.
241*69112eddSAli Bahrami  * The original code has been replaced, but this table encodes the same
242*69112eddSAli Bahrami  * rules, to ensure backward compatibility.
243*69112eddSAli Bahrami  */
244*69112eddSAli Bahrami static const mf_tokdisp_t gettok_dispatch_v1 = {
245*69112eddSAli Bahrami 	TK_OP_EOF,			/* 0 - NUL */
246*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 1 - SOH */
247*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 2 - STX */
248*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 3 - ETX */
249*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 4 - EOT */
250*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 5 - ENQ */
251*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 6 - ACK */
252*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 7 - BEL */
253*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 8 - BS */
254*69112eddSAli Bahrami 	TK_OP_WS,			/* 9 - HT */
255*69112eddSAli Bahrami 	TK_OP_NL,			/* 10 - NL */
256*69112eddSAli Bahrami 	TK_OP_WS,			/* 11 - VT */
257*69112eddSAli Bahrami 	TK_OP_WS,			/* 12 - FF */
258*69112eddSAli Bahrami 	TK_OP_WS,			/* 13 - CR */
259*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 14 - SO */
260*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 15 - SI */
261*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 16 - DLE */
262*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 17 - DC1 */
263*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 18 - DC2 */
264*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 19 - DC3 */
265*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 20 - DC4 */
266*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 21 - NAK */
267*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 22 - SYN */
268*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 23 - ETB */
269*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 24 - CAN */
270*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 25 - EM */
271*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 26 - SUB */
272*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 27 - ESC */
273*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 28 - FS */
274*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 29 - GS */
275*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 30 - RS */
276*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 31 - US */
277*69112eddSAli Bahrami 	TK_OP_WS,			/* 32 - SP */
278*69112eddSAli Bahrami 	TK_OP_ID,			/* 33 - ! */
279*69112eddSAli Bahrami 	TK_OP_SIMQUOTE,			/* 34 - " */
280*69112eddSAli Bahrami 	TK_OP_CMT,			/* 35 - # */
281*69112eddSAli Bahrami 	TK_OP_ID,			/* 36 - $ */
282*69112eddSAli Bahrami 	TK_OP_ID,			/* 37 - % */
283*69112eddSAli Bahrami 	TK_OP_ID,			/* 38 - & */
284*69112eddSAli Bahrami 	TK_OP_ID,			/* 39 - ' */
285*69112eddSAli Bahrami 	TK_OP_ID,			/* 40 - ( */
286*69112eddSAli Bahrami 	TK_OP_ID,			/* 41 - ) */
287*69112eddSAli Bahrami 	TK_OP_ID,			/* 42 - * */
288*69112eddSAli Bahrami 	TK_OP_ID,			/* 43 - + */
289*69112eddSAli Bahrami 	TK_OP_ID,			/* 44 - , */
290*69112eddSAli Bahrami 	TK_DASH,			/* 45 - - */
291*69112eddSAli Bahrami 	TK_OP_ID,			/* 46 - . */
292*69112eddSAli Bahrami 	TK_OP_ID,			/* 47 - / */
293*69112eddSAli Bahrami 	TK_OP_ID,			/* 48 - 0 */
294*69112eddSAli Bahrami 	TK_OP_ID,			/* 49 - 1 */
295*69112eddSAli Bahrami 	TK_OP_ID,			/* 50 - 2 */
296*69112eddSAli Bahrami 	TK_OP_ID,			/* 51 - 3 */
297*69112eddSAli Bahrami 	TK_OP_ID,			/* 52 - 4 */
298*69112eddSAli Bahrami 	TK_OP_ID,			/* 53 - 5 */
299*69112eddSAli Bahrami 	TK_OP_ID,			/* 54 - 6 */
300*69112eddSAli Bahrami 	TK_OP_ID,			/* 55 - 7 */
301*69112eddSAli Bahrami 	TK_OP_ID,			/* 56 - 8 */
302*69112eddSAli Bahrami 	TK_OP_ID,			/* 57 - 9 */
303*69112eddSAli Bahrami 	TK_COLON,			/* 58 - : */
304*69112eddSAli Bahrami 	TK_SEMICOLON,			/* 59 - ; */
305*69112eddSAli Bahrami 	TK_OP_ID,			/* 60 - < */
306*69112eddSAli Bahrami 	TK_EQUAL,			/* 61 - = */
307*69112eddSAli Bahrami 	TK_OP_ID,			/* 62 - > */
308*69112eddSAli Bahrami 	TK_OP_ID,			/* 63 - ? */
309*69112eddSAli Bahrami 	TK_ATSIGN,			/* 64 - @ */
310*69112eddSAli Bahrami 	TK_OP_ID,			/* 65 - A */
311*69112eddSAli Bahrami 	TK_OP_ID,			/* 66 - B */
312*69112eddSAli Bahrami 	TK_OP_ID,			/* 67 - C */
313*69112eddSAli Bahrami 	TK_OP_ID,			/* 68 - D */
314*69112eddSAli Bahrami 	TK_OP_ID,			/* 69 - E */
315*69112eddSAli Bahrami 	TK_OP_ID,			/* 70 - F */
316*69112eddSAli Bahrami 	TK_OP_ID,			/* 71 - G */
317*69112eddSAli Bahrami 	TK_OP_ID,			/* 72 - H */
318*69112eddSAli Bahrami 	TK_OP_ID,			/* 73 - I */
319*69112eddSAli Bahrami 	TK_OP_ID,			/* 74 - J */
320*69112eddSAli Bahrami 	TK_OP_ID,			/* 75 - K */
321*69112eddSAli Bahrami 	TK_OP_ID,			/* 76 - L */
322*69112eddSAli Bahrami 	TK_OP_ID,			/* 77 - M */
323*69112eddSAli Bahrami 	TK_OP_ID,			/* 78 - N */
324*69112eddSAli Bahrami 	TK_OP_ID,			/* 79 - O */
325*69112eddSAli Bahrami 	TK_OP_ID,			/* 80 - P */
326*69112eddSAli Bahrami 	TK_OP_ID,			/* 81 - Q */
327*69112eddSAli Bahrami 	TK_OP_ID,			/* 82 - R */
328*69112eddSAli Bahrami 	TK_OP_ID,			/* 83 - S */
329*69112eddSAli Bahrami 	TK_OP_ID,			/* 84 - T */
330*69112eddSAli Bahrami 	TK_OP_ID,			/* 85 - U */
331*69112eddSAli Bahrami 	TK_OP_ID,			/* 86 - V */
332*69112eddSAli Bahrami 	TK_OP_ID,			/* 87 - W */
333*69112eddSAli Bahrami 	TK_OP_ID,			/* 88 - X */
334*69112eddSAli Bahrami 	TK_OP_ID,			/* 89 - Y */
335*69112eddSAli Bahrami 	TK_OP_ID,			/* 90 - Z */
336*69112eddSAli Bahrami 	TK_OP_ID,			/* 91 - [ */
337*69112eddSAli Bahrami 	TK_OP_ID,			/* 92 - \ */
338*69112eddSAli Bahrami 	TK_OP_ID,			/* 93 - ] */
339*69112eddSAli Bahrami 	TK_OP_ID,			/* 94 - ^ */
340*69112eddSAli Bahrami 	TK_OP_ID,			/* 95 - _ */
341*69112eddSAli Bahrami 	TK_OP_ID,			/* 96 - ` */
342*69112eddSAli Bahrami 	TK_OP_ID,			/* 97 - a */
343*69112eddSAli Bahrami 	TK_OP_ID,			/* 98 - b */
344*69112eddSAli Bahrami 	TK_OP_ID,			/* 99 - c */
345*69112eddSAli Bahrami 	TK_OP_ID,			/* 100 - d */
346*69112eddSAli Bahrami 	TK_OP_ID,			/* 101 - e */
347*69112eddSAli Bahrami 	TK_OP_ID,			/* 102 - f */
348*69112eddSAli Bahrami 	TK_OP_ID,			/* 103 - g */
349*69112eddSAli Bahrami 	TK_OP_ID,			/* 104 - h */
350*69112eddSAli Bahrami 	TK_OP_ID,			/* 105 - i */
351*69112eddSAli Bahrami 	TK_OP_ID,			/* 106 - j */
352*69112eddSAli Bahrami 	TK_OP_ID,			/* 107 - k */
353*69112eddSAli Bahrami 	TK_OP_ID,			/* 108 - l */
354*69112eddSAli Bahrami 	TK_OP_ID,			/* 109 - m */
355*69112eddSAli Bahrami 	TK_OP_ID,			/* 110 - n */
356*69112eddSAli Bahrami 	TK_OP_ID,			/* 111 - o */
357*69112eddSAli Bahrami 	TK_OP_ID,			/* 112 - p */
358*69112eddSAli Bahrami 	TK_OP_ID,			/* 113 - q */
359*69112eddSAli Bahrami 	TK_OP_ID,			/* 114 - r */
360*69112eddSAli Bahrami 	TK_OP_ID,			/* 115 - s */
361*69112eddSAli Bahrami 	TK_OP_ID,			/* 116 - t */
362*69112eddSAli Bahrami 	TK_OP_ID,			/* 117 - u */
363*69112eddSAli Bahrami 	TK_OP_ID,			/* 118 - v */
364*69112eddSAli Bahrami 	TK_OP_ID,			/* 119 - w */
365*69112eddSAli Bahrami 	TK_OP_ID,			/* 120 - x */
366*69112eddSAli Bahrami 	TK_OP_ID,			/* 121 - y */
367*69112eddSAli Bahrami 	TK_OP_ID,			/* 122 - z */
368*69112eddSAli Bahrami 	TK_LEFTBKT,			/* 123 - { */
369*69112eddSAli Bahrami 	TK_PIPE,			/* 124 - | */
370*69112eddSAli Bahrami 	TK_RIGHTBKT,			/* 125 - } */
371*69112eddSAli Bahrami 	TK_OP_ID,			/* 126 - ~ */
372*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 127 - DEL */
373*69112eddSAli Bahrami };
374*69112eddSAli Bahrami 
375*69112eddSAli Bahrami /*
376*69112eddSAli Bahrami  * Version 2 syntax dispatch table for ld_map_gettoken(). For each of the
377*69112eddSAli Bahrami  * 7-bit ASCII characters, determine how the lexical analyzer should behave.
378*69112eddSAli Bahrami  *
379*69112eddSAli Bahrami  * This table must be kept in sync with tkid_attr[] below.
380*69112eddSAli Bahrami  *
381*69112eddSAli Bahrami  * Identifier Note:
382*69112eddSAli Bahrami  * We define a letter as being one of the character [A-Z], [a-z], or [_%/.]
383*69112eddSAli Bahrami  * A digit is the numbers [0-9], or [$-]. An unquoted identifier is defined
384*69112eddSAli Bahrami  * as a letter, followed by any number of letters or digits. This is a loosened
385*69112eddSAli Bahrami  * version of the C definition of an identifier. The extra characters not
386*69112eddSAli Bahrami  * allowed by C are common in section names and/or file paths.
387*69112eddSAli Bahrami  */
388*69112eddSAli Bahrami static const mf_tokdisp_t gettok_dispatch_v2 = {
389*69112eddSAli Bahrami 	TK_OP_EOF,			/* 0 - NUL */
390*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 1 - SOH */
391*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 2 - STX */
392*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 3 - ETX */
393*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 4 - EOT */
394*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 5 - ENQ */
395*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 6 - ACK */
396*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 7 - BEL */
397*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 8 - BS */
398*69112eddSAli Bahrami 	TK_OP_WS,			/* 9 - HT */
399*69112eddSAli Bahrami 	TK_OP_NL,			/* 10 - NL */
400*69112eddSAli Bahrami 	TK_OP_WS,			/* 11 - VT */
401*69112eddSAli Bahrami 	TK_OP_WS,			/* 12 - FF */
402*69112eddSAli Bahrami 	TK_OP_WS,			/* 13 - CR */
403*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 14 - SO */
404*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 15 - SI */
405*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 16 - DLE */
406*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 17 - DC1 */
407*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 18 - DC2 */
408*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 19 - DC3 */
409*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 20 - DC4 */
410*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 21 - NAK */
411*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 22 - SYN */
412*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 23 - ETB */
413*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 24 - CAN */
414*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 25 - EM */
415*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 26 - SUB */
416*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 27 - ESC */
417*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 28 - FS */
418*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 29 - GS */
419*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 30 - RS */
420*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 31 - US */
421*69112eddSAli Bahrami 	TK_OP_WS,			/* 32 - SP */
422*69112eddSAli Bahrami 	TK_BANG,			/* 33 - ! */
423*69112eddSAli Bahrami 	TK_OP_CQUOTE,			/* 34 - " */
424*69112eddSAli Bahrami 	TK_OP_CMT,			/* 35 - # */
425*69112eddSAli Bahrami 	TK_OP_CDIR,			/* 36 - $ */
426*69112eddSAli Bahrami 	TK_OP_ID,			/* 37 - % */
427*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 38 - & */
428*69112eddSAli Bahrami 	TK_OP_SIMQUOTE,			/* 39 - ' */
429*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 40 - ( */
430*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 41 - ) */
431*69112eddSAli Bahrami 	TK_STAR,			/* 42 - * */
432*69112eddSAli Bahrami 	TK_OP_CEQUAL,			/* 43 - + */
433*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 44 - , */
434*69112eddSAli Bahrami 	TK_OP_CEQUAL,			/* 45 - - */
435*69112eddSAli Bahrami 	TK_OP_ID,			/* 46 - . */
436*69112eddSAli Bahrami 	TK_OP_ID,			/* 47 - / */
437*69112eddSAli Bahrami 	TK_OP_NUM,			/* 48 - 0 */
438*69112eddSAli Bahrami 	TK_OP_NUM,			/* 49 - 1 */
439*69112eddSAli Bahrami 	TK_OP_NUM,			/* 50 - 2 */
440*69112eddSAli Bahrami 	TK_OP_NUM,			/* 51 - 3 */
441*69112eddSAli Bahrami 	TK_OP_NUM,			/* 52 - 4 */
442*69112eddSAli Bahrami 	TK_OP_NUM,			/* 53 - 5 */
443*69112eddSAli Bahrami 	TK_OP_NUM,			/* 54 - 6 */
444*69112eddSAli Bahrami 	TK_OP_NUM,			/* 55 - 7 */
445*69112eddSAli Bahrami 	TK_OP_NUM,			/* 56 - 8 */
446*69112eddSAli Bahrami 	TK_OP_NUM,			/* 57 - 9 */
447*69112eddSAli Bahrami 	TK_COLON,			/* 58 - : */
448*69112eddSAli Bahrami 	TK_SEMICOLON,			/* 59 - ; */
449*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 60 - < */
450*69112eddSAli Bahrami 	TK_EQUAL,			/* 61 - = */
451*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 62 - > */
452*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 63 - ? */
453*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 64 - @ */
454*69112eddSAli Bahrami 	TK_OP_ID,			/* 65 - A */
455*69112eddSAli Bahrami 	TK_OP_ID,			/* 66 - B */
456*69112eddSAli Bahrami 	TK_OP_ID,			/* 67 - C */
457*69112eddSAli Bahrami 	TK_OP_ID,			/* 68 - D */
458*69112eddSAli Bahrami 	TK_OP_ID,			/* 69 - E */
459*69112eddSAli Bahrami 	TK_OP_ID,			/* 70 - F */
460*69112eddSAli Bahrami 	TK_OP_ID,			/* 71 - G */
461*69112eddSAli Bahrami 	TK_OP_ID,			/* 72 - H */
462*69112eddSAli Bahrami 	TK_OP_ID,			/* 73 - I */
463*69112eddSAli Bahrami 	TK_OP_ID,			/* 74 - J */
464*69112eddSAli Bahrami 	TK_OP_ID,			/* 75 - K */
465*69112eddSAli Bahrami 	TK_OP_ID,			/* 76 - L */
466*69112eddSAli Bahrami 	TK_OP_ID,			/* 77 - M */
467*69112eddSAli Bahrami 	TK_OP_ID,			/* 78 - N */
468*69112eddSAli Bahrami 	TK_OP_ID,			/* 79 - O */
469*69112eddSAli Bahrami 	TK_OP_ID,			/* 80 - P */
470*69112eddSAli Bahrami 	TK_OP_ID,			/* 81 - Q */
471*69112eddSAli Bahrami 	TK_OP_ID,			/* 82 - R */
472*69112eddSAli Bahrami 	TK_OP_ID,			/* 83 - S */
473*69112eddSAli Bahrami 	TK_OP_ID,			/* 84 - T */
474*69112eddSAli Bahrami 	TK_OP_ID,			/* 85 - U */
475*69112eddSAli Bahrami 	TK_OP_ID,			/* 86 - V */
476*69112eddSAli Bahrami 	TK_OP_ID,			/* 87 - W */
477*69112eddSAli Bahrami 	TK_OP_ID,			/* 88 - X */
478*69112eddSAli Bahrami 	TK_OP_ID,			/* 89 - Y */
479*69112eddSAli Bahrami 	TK_OP_ID,			/* 90 - Z */
480*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 91 - [ */
481*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 92 - \ */
482*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 93 - ] */
483*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 94 - ^ */
484*69112eddSAli Bahrami 	TK_OP_ID,			/* 95 - _ */
485*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 96 - ` */
486*69112eddSAli Bahrami 	TK_OP_ID,			/* 97 - a */
487*69112eddSAli Bahrami 	TK_OP_ID,			/* 98 - b */
488*69112eddSAli Bahrami 	TK_OP_ID,			/* 99 - c */
489*69112eddSAli Bahrami 	TK_OP_ID,			/* 100 - d */
490*69112eddSAli Bahrami 	TK_OP_ID,			/* 101 - e */
491*69112eddSAli Bahrami 	TK_OP_ID,			/* 102 - f */
492*69112eddSAli Bahrami 	TK_OP_ID,			/* 103 - g */
493*69112eddSAli Bahrami 	TK_OP_ID,			/* 104 - h */
494*69112eddSAli Bahrami 	TK_OP_ID,			/* 105 - i */
495*69112eddSAli Bahrami 	TK_OP_ID,			/* 106 - j */
496*69112eddSAli Bahrami 	TK_OP_ID,			/* 107 - k */
497*69112eddSAli Bahrami 	TK_OP_ID,			/* 108 - l */
498*69112eddSAli Bahrami 	TK_OP_ID,			/* 109 - m */
499*69112eddSAli Bahrami 	TK_OP_ID,			/* 110 - n */
500*69112eddSAli Bahrami 	TK_OP_ID,			/* 111 - o */
501*69112eddSAli Bahrami 	TK_OP_ID,			/* 112 - p */
502*69112eddSAli Bahrami 	TK_OP_ID,			/* 113 - q */
503*69112eddSAli Bahrami 	TK_OP_ID,			/* 114 - r */
504*69112eddSAli Bahrami 	TK_OP_ID,			/* 115 - s */
505*69112eddSAli Bahrami 	TK_OP_ID,			/* 116 - t */
506*69112eddSAli Bahrami 	TK_OP_ID,			/* 117 - u */
507*69112eddSAli Bahrami 	TK_OP_ID,			/* 118 - v */
508*69112eddSAli Bahrami 	TK_OP_ID,			/* 119 - w */
509*69112eddSAli Bahrami 	TK_OP_ID,			/* 120 - x */
510*69112eddSAli Bahrami 	TK_OP_ID,			/* 121 - y */
511*69112eddSAli Bahrami 	TK_OP_ID,			/* 122 - z */
512*69112eddSAli Bahrami 	TK_LEFTBKT,			/* 123 - { */
513*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 124 - | */
514*69112eddSAli Bahrami 	TK_RIGHTBKT,			/* 125 - } */
515*69112eddSAli Bahrami 	TK_OP_BADCHR,			/* 126 - ~ */
516*69112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 127 - DEL */
517*69112eddSAli Bahrami };
518*69112eddSAli Bahrami 
519*69112eddSAli Bahrami 
520*69112eddSAli Bahrami /*
521*69112eddSAli Bahrami  * Table used to identify unquoted identifiers. Each element of this array
522*69112eddSAli Bahrami  * contains a bitmask indicating whether the character it represents starts,
523*69112eddSAli Bahrami  * or continues an identifier, for each supported mapfile syntax version.
524*69112eddSAli Bahrami  */
525*69112eddSAli Bahrami static const char tkid_attr[128] = {
526*69112eddSAli Bahrami 	0,					/* 0 - NUL */
527*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 1 - SOH */
528*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 2 - STX */
529*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 3 - ETX */
530*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 4 - EOT */
531*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 5 - ENQ */
532*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 6 - ACK */
533*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 7 - BEL */
534*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 8 - BS */
535*69112eddSAli Bahrami 	0,					/* 9 - HT */
536*69112eddSAli Bahrami 	0,					/* 10 - NL */
537*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 11 - VT */
538*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 12 - FF */
539*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 13 - CR */
540*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 14 - SO */
541*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 15 - SI */
542*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 16 - DLE */
543*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 17 - DC1 */
544*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 18 - DC2 */
545*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 19 - DC3 */
546*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 20 - DC4 */
547*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 21 - NAK */
548*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 22 - SYN */
549*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 23 - ETB */
550*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 24 - CAN */
551*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 25 - EM */
552*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 26 - SUB */
553*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 27 - ESC */
554*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 28 - FS */
555*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 29 - GS */
556*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 30 - RS */
557*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 31 - US */
558*69112eddSAli Bahrami 	0,					/* 32 - SP */
559*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 33 - ! */
560*69112eddSAli Bahrami 	0,					/* 34 - " */
561*69112eddSAli Bahrami 	0,					/* 35 - # */
562*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 36 - $ */
563*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 37 - % */
564*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 38 - & */
565*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 39 - ' */
566*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 40 - ( */
567*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 41 - ) */
568*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 42 - * */
569*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 43 - + */
570*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 44 - , */
571*69112eddSAli Bahrami 	TKID_ATTR_CONT(1) | TKID_ATTR_CONT(2),	/* 45 - - */
572*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 46 - . */
573*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 47 - / */
574*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 48 - 0 */
575*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 49 - 1 */
576*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 50 - 2 */
577*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 51 - 3 */
578*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 52 - 4 */
579*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 53 - 5 */
580*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 54 - 6 */
581*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 55 - 7 */
582*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 56 - 8 */
583*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 57 - 9 */
584*69112eddSAli Bahrami 	0,					/* 58 - : */
585*69112eddSAli Bahrami 	0,					/* 59 - ; */
586*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 60 - < */
587*69112eddSAli Bahrami 	0,					/* 61 - = */
588*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 62 - > */
589*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 63 - ? */
590*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 64 - @ */
591*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 65 - A */
592*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 66 - B */
593*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 67 - C */
594*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 68 - D */
595*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 69 - E */
596*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 70 - F */
597*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 71 - G */
598*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 72 - H */
599*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 73 - I */
600*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 74 - J */
601*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 75 - K */
602*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 76 - L */
603*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 77 - M */
604*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 78 - N */
605*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 79 - O */
606*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 80 - P */
607*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 81 - Q */
608*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 82 - R */
609*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 83 - S */
610*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 84 - T */
611*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 85 - U */
612*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 86 - V */
613*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 87 - W */
614*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 88 - X */
615*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 89 - Y */
616*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 90 - Z */
617*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 91 - [ */
618*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 92 - \ */
619*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 93 - ] */
620*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 94 - ^ */
621*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 95 - _ */
622*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 96 - ` */
623*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 97 - a */
624*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 98 - b */
625*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 99 - c */
626*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 100 - d */
627*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 101 - e */
628*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 102 - f */
629*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 103 - g */
630*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 104 - h */
631*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 105 - i */
632*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 106 - j */
633*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 107 - k */
634*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 108 - l */
635*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 109 - m */
636*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 110 - n */
637*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 111 - o */
638*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 112 - p */
639*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 113 - q */
640*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 114 - r */
641*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 115 - s */
642*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 116 - t */
643*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 117 - u */
644*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 118 - v */
645*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 119 - w */
646*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 120 - x */
647*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 121 - y */
648*69112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 122 - z */
649*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 123 - { */
650*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 124 - | */
651*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 125 - } */
652*69112eddSAli Bahrami 	TKID_ATTR(1),				/* 126 - ~ */
653*69112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 127 - DEL */
654*69112eddSAli Bahrami };
655*69112eddSAli Bahrami 
656*69112eddSAli Bahrami 
657*69112eddSAli Bahrami /*
658*69112eddSAli Bahrami  * Advance the given string pointer to the next newline character,
659*69112eddSAli Bahrami  * or the terminating NULL if there is none.
660*69112eddSAli Bahrami  */
661*69112eddSAli Bahrami inline static void
662*69112eddSAli Bahrami advance_to_eol(char **str)
663*69112eddSAli Bahrami {
664*69112eddSAli Bahrami 	char	*s = *str;
665*69112eddSAli Bahrami 
666*69112eddSAli Bahrami 	while ((*s != '\n') && (*s != '\0'))
667*69112eddSAli Bahrami 		s++;
668*69112eddSAli Bahrami 	*str = s;
669*69112eddSAli Bahrami }
670*69112eddSAli Bahrami 
671*69112eddSAli Bahrami /*
672*69112eddSAli Bahrami  * Insert a NULL patch at the given address
673*69112eddSAli Bahrami  */
674*69112eddSAli Bahrami inline static void
675*69112eddSAli Bahrami null_patch_set(char *str, ld_map_npatch_t *np)
676*69112eddSAli Bahrami {
677*69112eddSAli Bahrami 	np->np_ptr = str;
678*69112eddSAli Bahrami 	np->np_ch = *str;
679*69112eddSAli Bahrami 	*str = '\0';
680*69112eddSAli Bahrami }
681*69112eddSAli Bahrami 
682*69112eddSAli Bahrami /*
683*69112eddSAli Bahrami  * Undo a NULL patch
684*69112eddSAli Bahrami  */
685*69112eddSAli Bahrami inline static void
686*69112eddSAli Bahrami null_patch_undo(ld_map_npatch_t *np)
687*69112eddSAli Bahrami {
688*69112eddSAli Bahrami 	*np->np_ptr = np->np_ch;
689*69112eddSAli Bahrami }
690*69112eddSAli Bahrami 
691*69112eddSAli Bahrami /*
692*69112eddSAli Bahrami  * Insert a NULL patch at the end of the line containing str.
693*69112eddSAli Bahrami  */
694*69112eddSAli Bahrami static void
695*69112eddSAli Bahrami null_patch_eol(char *str, ld_map_npatch_t *np)
696*69112eddSAli Bahrami {
697*69112eddSAli Bahrami 	advance_to_eol(&str);
698*69112eddSAli Bahrami 	null_patch_set(str, np);
699*69112eddSAli Bahrami }
700*69112eddSAli Bahrami 
701*69112eddSAli Bahrami /*
702*69112eddSAli Bahrami  * Locate the end of an unquoted identifier.
703*69112eddSAli Bahrami  *
704*69112eddSAli Bahrami  * entry:
705*69112eddSAli Bahrami  *	mf - Mapfile descriptor, positioned to first character
706*69112eddSAli Bahrami  *		of identifier.
707*69112eddSAli Bahrami  *
708*69112eddSAli Bahrami  * exit:
709*69112eddSAli Bahrami  *	If the item pointed at by mf is not an identifier, returns NULL.
710*69112eddSAli Bahrami  *	Otherwise, returns pointer to character after the last character
711*69112eddSAli Bahrami  *	of the identifier.
712*69112eddSAli Bahrami  */
713*69112eddSAli Bahrami inline static char *
714*69112eddSAli Bahrami ident_delimit(Mapfile *mf)
715*69112eddSAli Bahrami {
716*69112eddSAli Bahrami 	char		*str = mf->mf_next;
717*69112eddSAli Bahrami 	ld_map_npatch_t	np;
718*69112eddSAli Bahrami 	int		c = *str++;
719*69112eddSAli Bahrami 
720*69112eddSAli Bahrami 	/* If not a valid start character, report the error */
721*69112eddSAli Bahrami 	if ((c & 0x80) || !(tkid_attr[c] & mf->mf_tkid_start)) {
722*69112eddSAli Bahrami 		null_patch_set(str, &np);
723*69112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), str);
724*69112eddSAli Bahrami 		null_patch_undo(&np);
725*69112eddSAli Bahrami 		return (NULL);
726*69112eddSAli Bahrami 	}
727*69112eddSAli Bahrami 
728*69112eddSAli Bahrami 	/* Keep going until we hit a non-continuing character */
729*69112eddSAli Bahrami 	for (c = *str; !(c & 0x80) && (tkid_attr[c] & mf->mf_tkid_cont);
730*69112eddSAli Bahrami 	    c = *++str)
731*69112eddSAli Bahrami 		;
732*69112eddSAli Bahrami 
733*69112eddSAli Bahrami 	return (str);
734*69112eddSAli Bahrami }
735*69112eddSAli Bahrami 
736*69112eddSAli Bahrami /*
737*69112eddSAli Bahrami  * Allocate memory for a stack.
738*69112eddSAli Bahrami  *
739*69112eddSAli Bahrami  * entry:
740*69112eddSAli Bahrami  *	stack - Pointer to stack for which memory is required, cast
741*69112eddSAli Bahrami  *		to the generic stack type.
742*69112eddSAli Bahrami  *	n_default - Size to use for initial allocation.
743*69112eddSAli Bahrami  *	elt_size - sizeof(elt), where elt is the actual stack data type.
744*69112eddSAli Bahrami  *
745*69112eddSAli Bahrami  * exit:
746*69112eddSAli Bahrami  *	Returns (1) on success. On error (memory allocation), a message
747*69112eddSAli Bahrami  *	is printed and False (0) is returned.
748*69112eddSAli Bahrami  *
749*69112eddSAli Bahrami  * note:
750*69112eddSAli Bahrami  *	The caller casts the pointer to their actual datatype-specific stack
751*69112eddSAli Bahrami  *	to be a (generic_stack_t *). The C language will give all stack
752*69112eddSAli Bahrami  *	structs the same size and layout as long as the underlying platform
753*69112eddSAli Bahrami  *	uses a single integral type for pointers. Hence, this cast is safe,
754*69112eddSAli Bahrami  *	and lets a generic routine modify data-specific types without being
755*69112eddSAli Bahrami  *	aware of those types.
756*69112eddSAli Bahrami  */
757*69112eddSAli Bahrami static Boolean
758*69112eddSAli Bahrami stack_resize(generic_stack_t *stack, size_t n_default, size_t elt_size)
759*69112eddSAli Bahrami {
760*69112eddSAli Bahrami 	size_t	new_n_alloc;
761*69112eddSAli Bahrami 	void	*newaddr;
762*69112eddSAli Bahrami 
763*69112eddSAli Bahrami 	/* Use initial size first, and double the allocation on each call */
764*69112eddSAli Bahrami 	new_n_alloc = (stack->stk_n_alloc == 0) ?
765*69112eddSAli Bahrami 	    n_default : (stack->stk_n_alloc * 2);
766*69112eddSAli Bahrami 
767*69112eddSAli Bahrami 	newaddr = libld_realloc(stack->stk_s, new_n_alloc * elt_size);
768*69112eddSAli Bahrami 	if (newaddr == NULL)
769*69112eddSAli Bahrami 		return (FALSE);
770*69112eddSAli Bahrami 
771*69112eddSAli Bahrami 	stack->stk_s = newaddr;
772*69112eddSAli Bahrami 	stack->stk_n_alloc = new_n_alloc;
773*69112eddSAli Bahrami 	return (TRUE);
774*69112eddSAli Bahrami }
775*69112eddSAli Bahrami 
776*69112eddSAli Bahrami /*
777*69112eddSAli Bahrami  * AVL comparison function for cexp_id_node_t items.
778*69112eddSAli Bahrami  *
779*69112eddSAli Bahrami  * entry:
780*69112eddSAli Bahrami  *      n1, n2 - pointers to nodes to be compared
781*69112eddSAli Bahrami  *
782*69112eddSAli Bahrami  * exit:
783*69112eddSAli Bahrami  *      Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
784*69112eddSAli Bahrami  */
785*69112eddSAli Bahrami static int
786*69112eddSAli Bahrami cexp_ident_cmp(const void *n1, const void *n2)
787*69112eddSAli Bahrami {
788*69112eddSAli Bahrami 	int	rc;
789*69112eddSAli Bahrami 
790*69112eddSAli Bahrami 	rc = strcmp(((cexp_id_node_t *)n1)->ceid_name,
791*69112eddSAli Bahrami 	    ((cexp_id_node_t *)n2)->ceid_name);
792*69112eddSAli Bahrami 
793*69112eddSAli Bahrami 	if (rc > 0)
794*69112eddSAli Bahrami 		return (1);
795*69112eddSAli Bahrami 	if (rc < 0)
796*69112eddSAli Bahrami 		return (-1);
797*69112eddSAli Bahrami 	return (0);
798*69112eddSAli Bahrami }
799*69112eddSAli Bahrami 
800*69112eddSAli Bahrami 
801*69112eddSAli Bahrami /*
802*69112eddSAli Bahrami  * Returns True (1) if name is in the conditional expression identifier
803*69112eddSAli Bahrami  * AVL tree, and False (0) otherwise.
804*69112eddSAli Bahrami  */
805*69112eddSAli Bahrami static int
806*69112eddSAli Bahrami cexp_ident_test(const char *name)
807*69112eddSAli Bahrami {
808*69112eddSAli Bahrami 	cexp_id_node_t	node;
809*69112eddSAli Bahrami 
810*69112eddSAli Bahrami 	node.ceid_name = name;
811*69112eddSAli Bahrami 	return (avl_find(lms.lms_cexp_id, &node, 0) != NULL);
812*69112eddSAli Bahrami }
813*69112eddSAli Bahrami 
814*69112eddSAli Bahrami /*
815*69112eddSAli Bahrami  * Add a new boolean identifier to the conditional expression identifier
816*69112eddSAli Bahrami  * AVL tree.
817*69112eddSAli Bahrami  *
818*69112eddSAli Bahrami  * entry:
819*69112eddSAli Bahrami  *	mf - If non-NULL, the mapfile descriptor for the mapfile
820*69112eddSAli Bahrami  *		containing the $add directive. NULL if this is an
821*69112eddSAli Bahrami  *		initialization call.
822*69112eddSAli Bahrami  *	name - Name of identifier. Must point at stable storage that will
823*69112eddSAli Bahrami  *		not be moved or modified by the caller following this call.
824*69112eddSAli Bahrami  *
825*69112eddSAli Bahrami  * exit:
826*69112eddSAli Bahrami  *	On success, True (1) is returned and name has been entered.
827*69112eddSAli Bahrami  *	On failure, False (0) is returned and an error has been printed.
828*69112eddSAli Bahrami  */
829*69112eddSAli Bahrami static int
830*69112eddSAli Bahrami cexp_ident_add(Mapfile *mf, const char *name)
831*69112eddSAli Bahrami {
832*69112eddSAli Bahrami 	cexp_id_node_t	*node;
833*69112eddSAli Bahrami 
834*69112eddSAli Bahrami 	if (mf != NULL) {
835*69112eddSAli Bahrami 		DBG_CALL(Dbg_map_cexp_id(mf->mf_ofl->ofl_lml, 1,
836*69112eddSAli Bahrami 		    mf->mf_name, mf->mf_lineno, name));
837*69112eddSAli Bahrami 
838*69112eddSAli Bahrami 		/* If is already known, don't do it again */
839*69112eddSAli Bahrami 		if (cexp_ident_test(name))
840*69112eddSAli Bahrami 			return (1);
841*69112eddSAli Bahrami 	}
842*69112eddSAli Bahrami 
843*69112eddSAli Bahrami 	if ((node = libld_calloc(sizeof (*node), 1)) == NULL)
844*69112eddSAli Bahrami 		return (0);
845*69112eddSAli Bahrami 	node->ceid_name = name;
846*69112eddSAli Bahrami 	avl_add(lms.lms_cexp_id, node);
847*69112eddSAli Bahrami 	return (1);
848*69112eddSAli Bahrami }
849*69112eddSAli Bahrami 
850*69112eddSAli Bahrami /*
851*69112eddSAli Bahrami  * Remove a boolean identifier from the conditional expression identifier
852*69112eddSAli Bahrami  * AVL tree.
853*69112eddSAli Bahrami  *
854*69112eddSAli Bahrami  * entry:
855*69112eddSAli Bahrami  *	mf - Mapfile descriptor
856*69112eddSAli Bahrami  *	name - Name of identifier.
857*69112eddSAli Bahrami  *
858*69112eddSAli Bahrami  * exit:
859*69112eddSAli Bahrami  *	If the name was in the tree, it has been removed. If not,
860*69112eddSAli Bahrami  *	then this routine quietly returns.
861*69112eddSAli Bahrami  */
862*69112eddSAli Bahrami static void
863*69112eddSAli Bahrami cexp_ident_clear(Mapfile *mf, const char *name)
864*69112eddSAli Bahrami {
865*69112eddSAli Bahrami 	cexp_id_node_t	node;
866*69112eddSAli Bahrami 	cexp_id_node_t	*real_node;
867*69112eddSAli Bahrami 
868*69112eddSAli Bahrami 	DBG_CALL(Dbg_map_cexp_id(mf->mf_ofl->ofl_lml, 0,
869*69112eddSAli Bahrami 	    mf->mf_name, mf->mf_lineno, name));
870*69112eddSAli Bahrami 
871*69112eddSAli Bahrami 	node.ceid_name = name;
872*69112eddSAli Bahrami 	real_node = avl_find(lms.lms_cexp_id, &node, 0);
873*69112eddSAli Bahrami 	if (real_node != NULL)
874*69112eddSAli Bahrami 		avl_remove(lms.lms_cexp_id, real_node);
875*69112eddSAli Bahrami }
876*69112eddSAli Bahrami 
877*69112eddSAli Bahrami /*
878*69112eddSAli Bahrami  * Initialize the AVL tree that holds the names of the currently defined
879*69112eddSAli Bahrami  * boolean identifiers for conditional expressions ($if/$elif).
880*69112eddSAli Bahrami  *
881*69112eddSAli Bahrami  * entry:
882*69112eddSAli Bahrami  *	ofl - Output file descriptor
883*69112eddSAli Bahrami  *
884*69112eddSAli Bahrami  * exit:
885*69112eddSAli Bahrami  *	On success, TRUE (1) is returned and lms.lms_cexp_id is ready for use.
886*69112eddSAli Bahrami  *	On failure, FALSE (0) is returned.
887*69112eddSAli Bahrami  */
888*69112eddSAli Bahrami static Boolean
889*69112eddSAli Bahrami cexp_ident_init(void)
890*69112eddSAli Bahrami {
891*69112eddSAli Bahrami 	/* If already done, use it */
892*69112eddSAli Bahrami 	if (lms.lms_cexp_id != NULL)
893*69112eddSAli Bahrami 		return (TRUE);
894*69112eddSAli Bahrami 
895*69112eddSAli Bahrami 	lms.lms_cexp_id = libld_calloc(sizeof (*lms.lms_cexp_id), 1);
896*69112eddSAli Bahrami 	if (lms.lms_cexp_id == NULL)
897*69112eddSAli Bahrami 		return (FALSE);
898*69112eddSAli Bahrami 	avl_create(lms.lms_cexp_id, cexp_ident_cmp, sizeof (cexp_id_node_t),
899*69112eddSAli Bahrami 	    SGSOFFSETOF(cexp_id_node_t, ceid_avlnode));
900*69112eddSAli Bahrami 
901*69112eddSAli Bahrami 
902*69112eddSAli Bahrami 	/* ELFCLASS */
903*69112eddSAli Bahrami 	if (cexp_ident_add(NULL, (ld_targ.t_m.m_class == ELFCLASS32) ?
904*69112eddSAli Bahrami 	    MSG_ORIG(MSG_STR_UELF32) : MSG_ORIG(MSG_STR_UELF64)) == 0)
905*69112eddSAli Bahrami 		return (FALSE);
906*69112eddSAli Bahrami 
907*69112eddSAli Bahrami 	/* Machine */
908*69112eddSAli Bahrami 	switch (ld_targ.t_m.m_mach) {
909*69112eddSAli Bahrami 	case EM_386:
910*69112eddSAli Bahrami 	case EM_AMD64:
911*69112eddSAli Bahrami 		if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_UX86)) == 0)
912*69112eddSAli Bahrami 			return (FALSE);
913*69112eddSAli Bahrami 		break;
914*69112eddSAli Bahrami 
915*69112eddSAli Bahrami 	case EM_SPARC:
916*69112eddSAli Bahrami 	case EM_SPARCV9:
917*69112eddSAli Bahrami 		if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_USPARC)) == 0)
918*69112eddSAli Bahrami 			return (FALSE);
919*69112eddSAli Bahrami 		break;
920*69112eddSAli Bahrami 	}
921*69112eddSAli Bahrami 
922*69112eddSAli Bahrami 	/* true is always defined */
923*69112eddSAli Bahrami 	if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_TRUE)) == 0)
924*69112eddSAli Bahrami 		return (FALSE);
925*69112eddSAli Bahrami 
926*69112eddSAli Bahrami 	return (TRUE);
927*69112eddSAli Bahrami }
928*69112eddSAli Bahrami 
929*69112eddSAli Bahrami /*
930*69112eddSAli Bahrami  * Validate the string starting at mf->mf_next as being a
931*69112eddSAli Bahrami  * boolean conditional expression identifier.
932*69112eddSAli Bahrami  *
933*69112eddSAli Bahrami  * entry:
934*69112eddSAli Bahrami  *	mf - Mapfile descriptor
935*69112eddSAli Bahrami  *	len - NULL, or address of variable to receive strlen() of identifier
936*69112eddSAli Bahrami  *	directive - If (len == NULL), string giving name of directive being
937*69112eddSAli Bahrami  *		processed. Ignored if (len != NULL).
938*69112eddSAli Bahrami  *
939*69112eddSAli Bahrami  * exit:
940*69112eddSAli Bahrami  *	On success:
941*69112eddSAli Bahrami  *	-	If len is NULL, a NULL is inserted following the final
942*69112eddSAli Bahrami  *		character of the identifier, and the remainder of the string
943*69112eddSAli Bahrami  *		is tested to ensure it is empty, or only contains whitespace.
944*69112eddSAli Bahrami  *	-	If len is non-NULL, *len is set to the number of characters
945*69112eddSAli Bahrami  *		in the identifier, and the rest of the string is not modified.
946*69112eddSAli Bahrami  *	-	TRUE (1) is returned
947*69112eddSAli Bahrami  *
948*69112eddSAli Bahrami  *	On failure, returns FALSE (0).
949*69112eddSAli Bahrami  */
950*69112eddSAli Bahrami static Boolean
951*69112eddSAli Bahrami cexp_ident_validate(Mapfile *mf, size_t *len, const char *directive)
952*69112eddSAli Bahrami {
953*69112eddSAli Bahrami 	char	*tail;
954*69112eddSAli Bahrami 
955*69112eddSAli Bahrami 	if ((tail = ident_delimit(mf)) == NULL)
956*69112eddSAli Bahrami 		return (FALSE);
957*69112eddSAli Bahrami 
958*69112eddSAli Bahrami 	/*
959*69112eddSAli Bahrami 	 * If len is non-NULL, we simple count the number of characters
960*69112eddSAli Bahrami 	 * consumed by the identifier and are done. If len is NULL, then
961*69112eddSAli Bahrami 	 * ensure there's nothing left but whitespace, and NULL terminate
962*69112eddSAli Bahrami 	 * the identifier to remove it.
963*69112eddSAli Bahrami 	 */
964*69112eddSAli Bahrami 	if (len != NULL) {
965*69112eddSAli Bahrami 		*len = tail - mf->mf_next;
966*69112eddSAli Bahrami 	} else if (*tail != '\0') {
967*69112eddSAli Bahrami 		*tail++ = '\0';
968*69112eddSAli Bahrami 		while (isspace(*tail))
969*69112eddSAli Bahrami 			tail++;
970*69112eddSAli Bahrami 		if (*tail != '\0') {
971*69112eddSAli Bahrami 			mf_fatal(mf, MSG_INTL(MSG_MAP_BADEXTRA), directive);
972*69112eddSAli Bahrami 			return (FALSE);
973*69112eddSAli Bahrami 		}
974*69112eddSAli Bahrami 	}
975*69112eddSAli Bahrami 
976*69112eddSAli Bahrami 	return (TRUE);
977*69112eddSAli Bahrami }
978*69112eddSAli Bahrami 
979*69112eddSAli Bahrami /*
980*69112eddSAli Bahrami  * Push a new operator onto the conditional expression operator stack.
981*69112eddSAli Bahrami  *
982*69112eddSAli Bahrami  * entry:
983*69112eddSAli Bahrami  *	mf - Mapfile descriptor
984*69112eddSAli Bahrami  *	op - Operator to push
985*69112eddSAli Bahrami  *
986*69112eddSAli Bahrami  * exit:
987*69112eddSAli Bahrami  *	On success, TRUE (1) is returned, otherwise FALSE (0).
988*69112eddSAli Bahrami  */
989*69112eddSAli Bahrami static Boolean
990*69112eddSAli Bahrami cexp_push_op(cexp_op_t op)
991*69112eddSAli Bahrami {
992*69112eddSAli Bahrami 	if (STACK_RESERVE(lms.lms_cexp_op_stack, CEXP_OP_STACK_INIT) == 0)
993*69112eddSAli Bahrami 		return (FALSE);
994*69112eddSAli Bahrami 
995*69112eddSAli Bahrami 	STACK_PUSH(lms.lms_cexp_op_stack) = op;
996*69112eddSAli Bahrami 	return (TRUE);
997*69112eddSAli Bahrami }
998*69112eddSAli Bahrami 
999*69112eddSAli Bahrami /*
1000*69112eddSAli Bahrami  * Evaluate the basic operator (non-paren) at the top of lms.lms_cexp_op_stack,
1001*69112eddSAli Bahrami  * and push the results on lms.lms_cexp_val_stack.
1002*69112eddSAli Bahrami  *
1003*69112eddSAli Bahrami  * exit:
1004*69112eddSAli Bahrami  *	On success, returns TRUE (1). On error, FALSE (0) is returned,
1005*69112eddSAli Bahrami  *	and the caller is responsible for issuing the error.
1006*69112eddSAli Bahrami  */
1007*69112eddSAli Bahrami static Boolean
1008*69112eddSAli Bahrami cexp_eval_op(void)
1009*69112eddSAli Bahrami {
1010*69112eddSAli Bahrami 	cexp_op_t	op;
1011*69112eddSAli Bahrami 	uchar_t		val;
1012*69112eddSAli Bahrami 
1013*69112eddSAli Bahrami 	op = STACK_POP(lms.lms_cexp_op_stack);
1014*69112eddSAli Bahrami 	switch (op) {
1015*69112eddSAli Bahrami 	case CEXP_OP_AND:
1016*69112eddSAli Bahrami 		if (lms.lms_cexp_val_stack.stk_n < 2)
1017*69112eddSAli Bahrami 			return (FALSE);
1018*69112eddSAli Bahrami 		val = STACK_POP(lms.lms_cexp_val_stack);
1019*69112eddSAli Bahrami 		STACK_TOP(lms.lms_cexp_val_stack) = val &&
1020*69112eddSAli Bahrami 		    STACK_TOP(lms.lms_cexp_val_stack);
1021*69112eddSAli Bahrami 		break;
1022*69112eddSAli Bahrami 
1023*69112eddSAli Bahrami 	case CEXP_OP_OR:
1024*69112eddSAli Bahrami 		if (lms.lms_cexp_val_stack.stk_n < 2)
1025*69112eddSAli Bahrami 			return (FALSE);
1026*69112eddSAli Bahrami 		val = STACK_POP(lms.lms_cexp_val_stack);
1027*69112eddSAli Bahrami 		STACK_TOP(lms.lms_cexp_val_stack) = val ||
1028*69112eddSAli Bahrami 		    STACK_TOP(lms.lms_cexp_val_stack);
1029*69112eddSAli Bahrami 		break;
1030*69112eddSAli Bahrami 
1031*69112eddSAli Bahrami 	case CEXP_OP_NEG:
1032*69112eddSAli Bahrami 		if (lms.lms_cexp_val_stack.stk_n < 1)
1033*69112eddSAli Bahrami 			return (FALSE);
1034*69112eddSAli Bahrami 		STACK_TOP(lms.lms_cexp_val_stack) =
1035*69112eddSAli Bahrami 		    !STACK_TOP(lms.lms_cexp_val_stack);
1036*69112eddSAli Bahrami 		break;
1037*69112eddSAli Bahrami 	default:
1038*69112eddSAli Bahrami 		return (FALSE);
1039*69112eddSAli Bahrami 	}
1040*69112eddSAli Bahrami 
1041*69112eddSAli Bahrami 	return (TRUE);
1042*69112eddSAli Bahrami }
1043*69112eddSAli Bahrami 
1044*69112eddSAli Bahrami /*
1045*69112eddSAli Bahrami  * Evaluate an expression for a $if/$elif control directive.
1046*69112eddSAli Bahrami  *
1047*69112eddSAli Bahrami  * entry:
1048*69112eddSAli Bahrami  *	mf - Mapfile descriptor for NULL terminated string
1049*69112eddSAli Bahrami  *		containing the expression.
1050*69112eddSAli Bahrami  *
1051*69112eddSAli Bahrami  * exit:
1052*69112eddSAli Bahrami  *	The contents of str are modified by this routine.
1053*69112eddSAli Bahrami  *	One of the following values are returned:
1054*69112eddSAli Bahrami  *		-1	Syntax error encountered (an error is printed)
1055*69112eddSAli Bahrami  *		0	The expression evaluates to False
1056*69112eddSAli Bahrami  *		1	The expression evaluates to True.
1057*69112eddSAli Bahrami  *
1058*69112eddSAli Bahrami  * note:
1059*69112eddSAli Bahrami  *	A simplified version of Dijkstra's Shunting Yard algorithm is used
1060*69112eddSAli Bahrami  *	to convert this syntax into postfix form and then evaluate it.
1061*69112eddSAli Bahrami  *	Our version has no functions and a tiny set of operators.
1062*69112eddSAli Bahrami  *
1063*69112eddSAli Bahrami  *	The expressions consist of boolean identifiers, which can be
1064*69112eddSAli Bahrami  *	combined using the following operators, listed from highest
1065*69112eddSAli Bahrami  *	precedence to least:
1066*69112eddSAli Bahrami  *
1067*69112eddSAli Bahrami  *		Operator	Meaning
1068*69112eddSAli Bahrami  *		-------------------------------------------------
1069*69112eddSAli Bahrami  *		(expr)		sub-expression, non-associative
1070*69112eddSAli Bahrami  *		!		logical negation, prefix, left associative
1071*69112eddSAli Bahrami  *		&&  ||		logical and/or, binary, left associative
1072*69112eddSAli Bahrami  *
1073*69112eddSAli Bahrami  *	The operands manipulated by these operators are names, consisting of
1074*69112eddSAli Bahrami  *	a sequence of letters and digits. The first character must be a letter.
1075*69112eddSAli Bahrami  *	Underscore (_) and period (.) are also considered to be characters.
1076*69112eddSAli Bahrami  *	An operand is considered True if it is found in our set of known
1077*69112eddSAli Bahrami  *	names (lms.lms_cexp_id), and False otherwise.
1078*69112eddSAli Bahrami  *
1079*69112eddSAli Bahrami  *	The Shunting Yard algorithm works using two stacks, one for operators,
1080*69112eddSAli Bahrami  *	and a second for operands. The infix input expression is tokenized from
1081*69112eddSAli Bahrami  *	left to right and processed in order. Issues of associativity and
1082*69112eddSAli Bahrami  *	precedence are managed by reducing (poping and evaluating) items with
1083*69112eddSAli Bahrami  *	higer precedence before pushing additional tokens with lower precedence.
1084*69112eddSAli Bahrami  */
1085*69112eddSAli Bahrami static int
1086*69112eddSAli Bahrami cexp_eval_expr(Mapfile *mf)
1087*69112eddSAli Bahrami {
1088*69112eddSAli Bahrami 	char		*ident;
1089*69112eddSAli Bahrami 	size_t		len;
1090*69112eddSAli Bahrami 	cexp_op_t	new_op = CEXP_OP_AND;	/* to catch binop at start */
1091*69112eddSAli Bahrami 	ld_map_npatch_t	np;
1092*69112eddSAli Bahrami 	char		*str = mf->mf_next;
1093*69112eddSAli Bahrami 
1094*69112eddSAli Bahrami 	STACK_RESET(lms.lms_cexp_op_stack);
1095*69112eddSAli Bahrami 	STACK_RESET(lms.lms_cexp_val_stack);
1096*69112eddSAli Bahrami 
1097*69112eddSAli Bahrami 	for (; *str; str++) {
1098*69112eddSAli Bahrami 
1099*69112eddSAli Bahrami 		/* Skip whitespace */
1100*69112eddSAli Bahrami 		while (isspace(*str))
1101*69112eddSAli Bahrami 			str++;
1102*69112eddSAli Bahrami 		if (!*str)
1103*69112eddSAli Bahrami 			break;
1104*69112eddSAli Bahrami 
1105*69112eddSAli Bahrami 		switch (*str) {
1106*69112eddSAli Bahrami 		case '&':
1107*69112eddSAli Bahrami 		case '|':
1108*69112eddSAli Bahrami 			if (*(str + 1) != *str)
1109*69112eddSAli Bahrami 				goto token_error;
1110*69112eddSAli Bahrami 			if ((new_op != CEXP_OP_NONE) &&
1111*69112eddSAli Bahrami 			    (new_op != CEXP_OP_CPAR)) {
1112*69112eddSAli Bahrami 				mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_BADOPUSE));
1113*69112eddSAli Bahrami 				return (-1);
1114*69112eddSAli Bahrami 			}
1115*69112eddSAli Bahrami 			str++;
1116*69112eddSAli Bahrami 
1117*69112eddSAli Bahrami 			/*
1118*69112eddSAli Bahrami 			 * As this is a left associative binary operator, we
1119*69112eddSAli Bahrami 			 * need to process all operators of equal or higher
1120*69112eddSAli Bahrami 			 * precedence before pushing the new operator.
1121*69112eddSAli Bahrami 			 */
1122*69112eddSAli Bahrami 			while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack)) {
1123*69112eddSAli Bahrami 				cexp_op_t op = STACK_TOP(lms.lms_cexp_op_stack);
1124*69112eddSAli Bahrami 
1125*69112eddSAli Bahrami 
1126*69112eddSAli Bahrami 				if ((op != CEXP_OP_AND) && (op != CEXP_OP_OR) &&
1127*69112eddSAli Bahrami 				    (op != CEXP_OP_NEG))
1128*69112eddSAli Bahrami 					break;
1129*69112eddSAli Bahrami 
1130*69112eddSAli Bahrami 				if (!cexp_eval_op())
1131*69112eddSAli Bahrami 					goto semantic_error;
1132*69112eddSAli Bahrami 			}
1133*69112eddSAli Bahrami 
1134*69112eddSAli Bahrami 			new_op = (*str == '&') ? CEXP_OP_AND : CEXP_OP_OR;
1135*69112eddSAli Bahrami 			if (!cexp_push_op(new_op))
1136*69112eddSAli Bahrami 				return (-1);
1137*69112eddSAli Bahrami 			break;
1138*69112eddSAli Bahrami 
1139*69112eddSAli Bahrami 		case '!':
1140*69112eddSAli Bahrami 			new_op = CEXP_OP_NEG;
1141*69112eddSAli Bahrami 			if (!cexp_push_op(new_op))
1142*69112eddSAli Bahrami 				return (-1);
1143*69112eddSAli Bahrami 			break;
1144*69112eddSAli Bahrami 
1145*69112eddSAli Bahrami 		case '(':
1146*69112eddSAli Bahrami 			new_op = CEXP_OP_OPAR;
1147*69112eddSAli Bahrami 			if (!cexp_push_op(new_op))
1148*69112eddSAli Bahrami 				return (-1);
1149*69112eddSAli Bahrami 			break;
1150*69112eddSAli Bahrami 
1151*69112eddSAli Bahrami 		case ')':
1152*69112eddSAli Bahrami 			new_op = CEXP_OP_CPAR;
1153*69112eddSAli Bahrami 
1154*69112eddSAli Bahrami 			/* Evaluate the operator stack until reach '(' */
1155*69112eddSAli Bahrami 			while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack) &&
1156*69112eddSAli Bahrami 			    (STACK_TOP(lms.lms_cexp_op_stack) != CEXP_OP_OPAR))
1157*69112eddSAli Bahrami 				if (!cexp_eval_op())
1158*69112eddSAli Bahrami 					goto semantic_error;
1159*69112eddSAli Bahrami 
1160*69112eddSAli Bahrami 			/*
1161*69112eddSAli Bahrami 			 * If the top of operator stack is not an open paren,
1162*69112eddSAli Bahrami 			 * when we have an error. In this case, the operator
1163*69112eddSAli Bahrami 			 * stack will be empty due to the loop above.
1164*69112eddSAli Bahrami 			 */
1165*69112eddSAli Bahrami 			if (STACK_IS_EMPTY(lms.lms_cexp_op_stack))
1166*69112eddSAli Bahrami 				goto unbalpar_error;
1167*69112eddSAli Bahrami 			lms.lms_cexp_op_stack.stk_n--;   /* Pop OPAR */
1168*69112eddSAli Bahrami 			break;
1169*69112eddSAli Bahrami 
1170*69112eddSAli Bahrami 		default:
1171*69112eddSAli Bahrami 			/* Ensure there's room to push another operand */
1172*69112eddSAli Bahrami 			if (STACK_RESERVE(lms.lms_cexp_val_stack,
1173*69112eddSAli Bahrami 			    CEXP_VAL_STACK_INIT) == 0)
1174*69112eddSAli Bahrami 				return (0);
1175*69112eddSAli Bahrami 			new_op = CEXP_OP_NONE;
1176*69112eddSAli Bahrami 
1177*69112eddSAli Bahrami 			/*
1178*69112eddSAli Bahrami 			 * Operands cannot be numbers. However, we accept two
1179*69112eddSAli Bahrami 			 * special cases: '0' means false, and '1' is true.
1180*69112eddSAli Bahrami 			 * This is done to support the common C idiom of
1181*69112eddSAli Bahrami 			 * '#if 1' and '#if 0' to conditionalize code under
1182*69112eddSAli Bahrami 			 * development.
1183*69112eddSAli Bahrami 			 */
1184*69112eddSAli Bahrami 			if ((*str == '0') || (*str == '1')) {
1185*69112eddSAli Bahrami 				STACK_PUSH(lms.lms_cexp_val_stack) =
1186*69112eddSAli Bahrami 				    (*str == '1');
1187*69112eddSAli Bahrami 				break;
1188*69112eddSAli Bahrami 			}
1189*69112eddSAli Bahrami 
1190*69112eddSAli Bahrami 			/* Look up the identifier */
1191*69112eddSAli Bahrami 			ident = mf->mf_next = str;
1192*69112eddSAli Bahrami 			if (!cexp_ident_validate(mf, &len, NULL))
1193*69112eddSAli Bahrami 				return (-1);
1194*69112eddSAli Bahrami 			str += len - 1;	  /* loop will advance past final ch */
1195*69112eddSAli Bahrami 			null_patch_set(&ident[len], &np);
1196*69112eddSAli Bahrami 			STACK_PUSH(lms.lms_cexp_val_stack) =
1197*69112eddSAli Bahrami 			    cexp_ident_test(ident);
1198*69112eddSAli Bahrami 			null_patch_undo(&np);
1199*69112eddSAli Bahrami 
1200*69112eddSAli Bahrami 			break;
1201*69112eddSAli Bahrami 		}
1202*69112eddSAli Bahrami 	}
1203*69112eddSAli Bahrami 
1204*69112eddSAli Bahrami 	/* Evaluate the operator stack until empty */
1205*69112eddSAli Bahrami 	while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack)) {
1206*69112eddSAli Bahrami 		if (STACK_TOP(lms.lms_cexp_op_stack) == CEXP_OP_OPAR)
1207*69112eddSAli Bahrami 			goto unbalpar_error;
1208*69112eddSAli Bahrami 
1209*69112eddSAli Bahrami 		if (!cexp_eval_op())
1210*69112eddSAli Bahrami 			goto semantic_error;
1211*69112eddSAli Bahrami 	}
1212*69112eddSAli Bahrami 
1213*69112eddSAli Bahrami 	/* There should be exactly one value left */
1214*69112eddSAli Bahrami 	if (lms.lms_cexp_val_stack.stk_n != 1)
1215*69112eddSAli Bahrami 		goto semantic_error;
1216*69112eddSAli Bahrami 
1217*69112eddSAli Bahrami 	/* Final value is the result */
1218*69112eddSAli Bahrami 	return (lms.lms_cexp_val_stack.stk_s[0]);
1219*69112eddSAli Bahrami 
1220*69112eddSAli Bahrami 	/* Errors issued more than once are handled below, accessed via goto */
1221*69112eddSAli Bahrami 
1222*69112eddSAli Bahrami token_error:			/* unexpected characters in input stream */
1223*69112eddSAli Bahrami 	mf_fatal(mf, MSG_INTL(MSG_MAP_CEXP_TOKERR), str);
1224*69112eddSAli Bahrami 	return (-1);
1225*69112eddSAli Bahrami 
1226*69112eddSAli Bahrami semantic_error:			/* valid tokens, but in invalid arrangement */
1227*69112eddSAli Bahrami 	mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_SEMERR));
1228*69112eddSAli Bahrami 	return (-1);
1229*69112eddSAli Bahrami 
1230*69112eddSAli Bahrami unbalpar_error:			/* Extra or missing parenthesis */
1231*69112eddSAli Bahrami 	mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_UNBALPAR));
1232*69112eddSAli Bahrami 	return (-1);
1233*69112eddSAli Bahrami }
1234*69112eddSAli Bahrami 
1235*69112eddSAli Bahrami /*
1236*69112eddSAli Bahrami  * Process a mapfile control directive. These directives start with
1237*69112eddSAli Bahrami  * the dollar character, and are used to manage details of the mapfile
1238*69112eddSAli Bahrami  * itself, such as version and conditional input.
1239*69112eddSAli Bahrami  *
1240*69112eddSAli Bahrami  * entry:
1241*69112eddSAli Bahrami  *	mf - Mapfile descriptor
1242*69112eddSAli Bahrami  *
1243*69112eddSAli Bahrami  * exit:
1244*69112eddSAli Bahrami  *	Returns TRUE (1) for success, and FALSE (0) on error. In the
1245*69112eddSAli Bahrami  *	error case, a descriptive error is issued.
1246*69112eddSAli Bahrami  */
1247*69112eddSAli Bahrami static Boolean
1248*69112eddSAli Bahrami cdir_process(Mapfile *mf)
1249*69112eddSAli Bahrami {
1250*69112eddSAli Bahrami 	typedef enum {			/* Directive types */
1251*69112eddSAli Bahrami 		CDIR_T_UNKNOWN = 0,	/* Unrecognized control directive */
1252*69112eddSAli Bahrami 		CDIR_T_ADD,		/* $add */
1253*69112eddSAli Bahrami 		CDIR_T_CLEAR,		/* $clear */
1254*69112eddSAli Bahrami 		CDIR_T_ERROR,		/* $error */
1255*69112eddSAli Bahrami 		CDIR_T_VERSION,		/* $mapfile_version */
1256*69112eddSAli Bahrami 		CDIR_T_IF,		/* $if */
1257*69112eddSAli Bahrami 		CDIR_T_ELIF,		/* $elif */
1258*69112eddSAli Bahrami 		CDIR_T_ELSE,		/* $else */
1259*69112eddSAli Bahrami 		CDIR_T_ENDIF,		/* $endif */
1260*69112eddSAli Bahrami 	} cdir_t;
1261*69112eddSAli Bahrami 
1262*69112eddSAli Bahrami 	typedef enum {		/* Types of arguments accepted by directives */
1263*69112eddSAli Bahrami 		ARG_T_NONE,	/* Directive takes no arguments */
1264*69112eddSAli Bahrami 		ARG_T_EXPR,	/* Directive takes a conditional expression */
1265*69112eddSAli Bahrami 		ARG_T_ID,	/* Conditional expression identifier */
1266*69112eddSAli Bahrami 		ARG_T_STR,	/* Non-empty string */
1267*69112eddSAli Bahrami 		ARG_T_IGN	/* Ignore the argument */
1268*69112eddSAli Bahrami 	} cdir_arg_t;
1269*69112eddSAli Bahrami 
1270*69112eddSAli Bahrami 	typedef struct {
1271*69112eddSAli Bahrami 		const char	*md_name;	/* Directive name */
1272*69112eddSAli Bahrami 		size_t		md_size;	/* strlen(md_name) */
1273*69112eddSAli Bahrami 		cdir_arg_t	md_arg;		/* Type of arguments */
1274*69112eddSAli Bahrami 		cdir_t		md_op;		/* CDIR_T_ code */
1275*69112eddSAli Bahrami 	} cdir_match_t;
1276*69112eddSAli Bahrami 
1277*69112eddSAli Bahrami 	/* Control Directives: The most likely items are listed first */
1278*69112eddSAli Bahrami 	static cdir_match_t match_data[] = {
1279*69112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_IF),	MSG_STR_CDIR_IF_SIZE,
1280*69112eddSAli Bahrami 		    ARG_T_EXPR,			CDIR_T_IF },
1281*69112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_ENDIF),	MSG_STR_CDIR_ENDIF_SIZE,
1282*69112eddSAli Bahrami 		    ARG_T_NONE,			CDIR_T_ENDIF },
1283*69112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_ELSE),	MSG_STR_CDIR_ELSE_SIZE,
1284*69112eddSAli Bahrami 		    ARG_T_NONE,			CDIR_T_ELSE },
1285*69112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_ELIF),	MSG_STR_CDIR_ELIF_SIZE,
1286*69112eddSAli Bahrami 		    ARG_T_EXPR,			CDIR_T_ELIF },
1287*69112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_ERROR),	MSG_STR_CDIR_ERROR_SIZE,
1288*69112eddSAli Bahrami 		    ARG_T_STR,			CDIR_T_ERROR },
1289*69112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_ADD),	MSG_STR_CDIR_ADD_SIZE,
1290*69112eddSAli Bahrami 		    ARG_T_ID,			CDIR_T_ADD },
1291*69112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_CLEAR),	MSG_STR_CDIR_CLEAR_SIZE,
1292*69112eddSAli Bahrami 		    ARG_T_ID,			CDIR_T_CLEAR },
1293*69112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_MFVER),	MSG_STR_CDIR_MFVER_SIZE,
1294*69112eddSAli Bahrami 		    ARG_T_IGN,			CDIR_T_VERSION },
1295*69112eddSAli Bahrami 
1296*69112eddSAli Bahrami 		{ NULL,				0,
1297*69112eddSAli Bahrami 		    ARG_T_IGN,			CDIR_T_UNKNOWN }
1298*69112eddSAli Bahrami 	};
1299*69112eddSAli Bahrami 
1300*69112eddSAli Bahrami 	cdir_match_t	*mdptr;
1301*69112eddSAli Bahrami 	char		*tail;
1302*69112eddSAli Bahrami 	int		expr_eval;	/* Result of evaluating ARG_T_EXPR */
1303*69112eddSAli Bahrami 	Mapfile		arg_mf;
1304*69112eddSAli Bahrami 	cdir_level_t	*level;
1305*69112eddSAli Bahrami 	int		pass, parent_pass;	/* Currently accepting input */
1306*69112eddSAli Bahrami 
1307*69112eddSAli Bahrami restart:
1308*69112eddSAli Bahrami 	/* Is the immediate context passing input? */
1309*69112eddSAli Bahrami 	pass = STACK_IS_EMPTY(lms.lms_cdir_stack) ||
1310*69112eddSAli Bahrami 	    STACK_TOP(lms.lms_cdir_stack).cdl_pass;
1311*69112eddSAli Bahrami 
1312*69112eddSAli Bahrami 	/* Is the surrounding (parent) context passing input? */
1313*69112eddSAli Bahrami 	parent_pass = (lms.lms_cdir_stack.stk_n <= 1) ||
1314*69112eddSAli Bahrami 	    lms.lms_cdir_stack.stk_s[lms.lms_cdir_stack.stk_n - 2].cdl_pass;
1315*69112eddSAli Bahrami 
1316*69112eddSAli Bahrami 
1317*69112eddSAli Bahrami 	for (mdptr = match_data; mdptr->md_name; mdptr++) {
1318*69112eddSAli Bahrami 		/* Prefix must match, or we move on */
1319*69112eddSAli Bahrami 		if (strncmp(mf->mf_next, mdptr->md_name,
1320*69112eddSAli Bahrami 		    mdptr->md_size) != 0)
1321*69112eddSAli Bahrami 			continue;
1322*69112eddSAli Bahrami 		tail = mf->mf_next + mdptr->md_size;
1323*69112eddSAli Bahrami 
1324*69112eddSAli Bahrami 		/*
1325*69112eddSAli Bahrami 		 * If there isn't whitespace, or a NULL terminator following
1326*69112eddSAli Bahrami 		 * the prefix, then even though our prefix matched, the actual
1327*69112eddSAli Bahrami 		 * token is longer, and we don't have a match.
1328*69112eddSAli Bahrami 		 */
1329*69112eddSAli Bahrami 		if (!isspace(*tail) && (*tail != '\0'))
1330*69112eddSAli Bahrami 			continue;
1331*69112eddSAli Bahrami 
1332*69112eddSAli Bahrami 		/* We have matched a valid control directive */
1333*69112eddSAli Bahrami 		break;
1334*69112eddSAli Bahrami 	}
1335*69112eddSAli Bahrami 
1336*69112eddSAli Bahrami 	/* Advance input to end of the current line */
1337*69112eddSAli Bahrami 	advance_to_eol(&mf->mf_next);
1338*69112eddSAli Bahrami 
1339*69112eddSAli Bahrami 	/*
1340*69112eddSAli Bahrami 	 * Set up a temporary mapfile descriptor to reference the
1341*69112eddSAli Bahrami 	 * argument string. The benefit of this second block, is that
1342*69112eddSAli Bahrami 	 * we can advance the real one to the next line now, which allows
1343*69112eddSAli Bahrami 	 * us to return at any time knowing that the input has been moved
1344*69112eddSAli Bahrami 	 * to the proper spot. This simplifies the error cases.
1345*69112eddSAli Bahrami 	 *
1346*69112eddSAli Bahrami 	 * If we had a match, tail points at the start of the string.
1347*69112eddSAli Bahrami 	 * Otherwise, we want to point at the end of the line.
1348*69112eddSAli Bahrami 	 */
1349*69112eddSAli Bahrami 	arg_mf = *mf;
1350*69112eddSAli Bahrami 	if (mdptr->md_name == NULL)
1351*69112eddSAli Bahrami 		arg_mf.mf_text = arg_mf.mf_next;
1352*69112eddSAli Bahrami 	else
1353*69112eddSAli Bahrami 		arg_mf.mf_text = arg_mf.mf_next = tail;
1354*69112eddSAli Bahrami 
1355*69112eddSAli Bahrami 	/*
1356*69112eddSAli Bahrami 	 * Null terminate the arguments, and advance the main mapfile
1357*69112eddSAli Bahrami 	 * state block to the next line.
1358*69112eddSAli Bahrami 	 */
1359*69112eddSAli Bahrami 	if (*mf->mf_next == '\n') {
1360*69112eddSAli Bahrami 		*mf->mf_next++ = '\0';
1361*69112eddSAli Bahrami 		mf->mf_lineno++;
1362*69112eddSAli Bahrami 	}
1363*69112eddSAli Bahrami 
1364*69112eddSAli Bahrami 	/* Skip leading whitespace to arguments */
1365*69112eddSAli Bahrami 	while (isspace(*arg_mf.mf_next))
1366*69112eddSAli Bahrami 		arg_mf.mf_next++;
1367*69112eddSAli Bahrami 
1368*69112eddSAli Bahrami 	/* Strip off any comment present on the line */
1369*69112eddSAli Bahrami 	for (tail = arg_mf.mf_next; *tail; tail++)
1370*69112eddSAli Bahrami 		if (*tail == '#') {
1371*69112eddSAli Bahrami 			*tail = '\0';
1372*69112eddSAli Bahrami 			break;
1373*69112eddSAli Bahrami 		}
1374*69112eddSAli Bahrami 
1375*69112eddSAli Bahrami 	/*
1376*69112eddSAli Bahrami 	 * Process the arguments as necessary depending on their type.
1377*69112eddSAli Bahrami 	 * If this control directive is nested inside a surrounding context
1378*69112eddSAli Bahrami 	 * that is not currently passing text, then we skip the argument
1379*69112eddSAli Bahrami 	 * evaluation. This follows the behavior of the C preprocessor,
1380*69112eddSAli Bahrami 	 * which only examines enough to detect the operation within
1381*69112eddSAli Bahrami 	 * a disabled section, without issuing errors about the arguments.
1382*69112eddSAli Bahrami 	 */
1383*69112eddSAli Bahrami 	if (pass || (parent_pass && (mdptr->md_op == CDIR_T_ELIF))) {
1384*69112eddSAli Bahrami 		switch (mdptr->md_arg) {
1385*69112eddSAli Bahrami 		case ARG_T_NONE:
1386*69112eddSAli Bahrami 			if (*arg_mf.mf_next == '\0')
1387*69112eddSAli Bahrami 				break;
1388*69112eddSAli Bahrami 			/* Args are present, but not wanted */
1389*69112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REQNOARG),
1390*69112eddSAli Bahrami 			    mdptr->md_name);
1391*69112eddSAli Bahrami 			return (FALSE);
1392*69112eddSAli Bahrami 
1393*69112eddSAli Bahrami 		case ARG_T_EXPR:
1394*69112eddSAli Bahrami 			/* Ensure that arguments are present */
1395*69112eddSAli Bahrami 			if (*arg_mf.mf_next == '\0')
1396*69112eddSAli Bahrami 				goto error_reqarg;
1397*69112eddSAli Bahrami 			expr_eval = cexp_eval_expr(&arg_mf);
1398*69112eddSAli Bahrami 			if (expr_eval == -1)
1399*69112eddSAli Bahrami 				return (FALSE);
1400*69112eddSAli Bahrami 			break;
1401*69112eddSAli Bahrami 
1402*69112eddSAli Bahrami 		case ARG_T_ID:
1403*69112eddSAli Bahrami 			/* Ensure that arguments are present */
1404*69112eddSAli Bahrami 			if (*arg_mf.mf_next == '\0')
1405*69112eddSAli Bahrami 				goto error_reqarg;
1406*69112eddSAli Bahrami 			if (!cexp_ident_validate(&arg_mf, NULL,
1407*69112eddSAli Bahrami 			    mdptr->md_name))
1408*69112eddSAli Bahrami 				return (FALSE);
1409*69112eddSAli Bahrami 			break;
1410*69112eddSAli Bahrami 
1411*69112eddSAli Bahrami 		case ARG_T_STR:
1412*69112eddSAli Bahrami 			/* Ensure that arguments are present */
1413*69112eddSAli Bahrami 			if (*arg_mf.mf_next == '\0')
1414*69112eddSAli Bahrami 				goto error_reqarg;
1415*69112eddSAli Bahrami 			/* Remove trailing whitespace */
1416*69112eddSAli Bahrami 			tail = arg_mf.mf_next + strlen(arg_mf.mf_next);
1417*69112eddSAli Bahrami 			while ((tail > arg_mf.mf_next) &&
1418*69112eddSAli Bahrami 			    isspace(*(tail -1)))
1419*69112eddSAli Bahrami 				tail--;
1420*69112eddSAli Bahrami 			*tail = '\0';
1421*69112eddSAli Bahrami 			break;
1422*69112eddSAli Bahrami 		}
1423*69112eddSAli Bahrami 	}
1424*69112eddSAli Bahrami 
1425*69112eddSAli Bahrami 	/*
1426*69112eddSAli Bahrami 	 * Carry out the specified control directive:
1427*69112eddSAli Bahrami 	 */
1428*69112eddSAli Bahrami 	if (!STACK_IS_EMPTY(lms.lms_cdir_stack))
1429*69112eddSAli Bahrami 		level = &STACK_TOP(lms.lms_cdir_stack);
1430*69112eddSAli Bahrami 
1431*69112eddSAli Bahrami 	switch (mdptr->md_op) {
1432*69112eddSAli Bahrami 	case CDIR_T_UNKNOWN:		/* Unrecognized control directive */
1433*69112eddSAli Bahrami 		if (!pass)
1434*69112eddSAli Bahrami 			break;
1435*69112eddSAli Bahrami 		mf_fatal0(&arg_mf, MSG_INTL(MSG_MAP_CDIR_BAD));
1436*69112eddSAli Bahrami 		return (FALSE);
1437*69112eddSAli Bahrami 
1438*69112eddSAli Bahrami 	case CDIR_T_ADD:
1439*69112eddSAli Bahrami 		if (pass && !cexp_ident_add(&arg_mf, arg_mf.mf_next))
1440*69112eddSAli Bahrami 			return (FALSE);
1441*69112eddSAli Bahrami 		break;
1442*69112eddSAli Bahrami 
1443*69112eddSAli Bahrami 	case CDIR_T_CLEAR:
1444*69112eddSAli Bahrami 		if (pass)
1445*69112eddSAli Bahrami 			cexp_ident_clear(&arg_mf, arg_mf.mf_next);
1446*69112eddSAli Bahrami 		break;
1447*69112eddSAli Bahrami 
1448*69112eddSAli Bahrami 	case CDIR_T_ERROR:
1449*69112eddSAli Bahrami 		if (!pass)
1450*69112eddSAli Bahrami 			break;
1451*69112eddSAli Bahrami 		mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ERROR),
1452*69112eddSAli Bahrami 		    arg_mf.mf_next);
1453*69112eddSAli Bahrami 		return (FALSE);
1454*69112eddSAli Bahrami 
1455*69112eddSAli Bahrami 	case CDIR_T_VERSION:
1456*69112eddSAli Bahrami 		/*
1457*69112eddSAli Bahrami 		 * A $mapfile_version control directive can only appear
1458*69112eddSAli Bahrami 		 * as the first directive in a mapfile, and is used to
1459*69112eddSAli Bahrami 		 * determine the syntax for the rest of the file. It's
1460*69112eddSAli Bahrami 		 * too late to be using it here.
1461*69112eddSAli Bahrami 		 */
1462*69112eddSAli Bahrami 		if (!pass)
1463*69112eddSAli Bahrami 			break;
1464*69112eddSAli Bahrami 		mf_fatal0(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REPVER));
1465*69112eddSAli Bahrami 		return (FALSE);
1466*69112eddSAli Bahrami 
1467*69112eddSAli Bahrami 	case CDIR_T_IF:
1468*69112eddSAli Bahrami 		/* Push a new level on the conditional input stack */
1469*69112eddSAli Bahrami 		if (STACK_RESERVE(lms.lms_cdir_stack, CDIR_STACK_INIT) == 0)
1470*69112eddSAli Bahrami 			return (FALSE);
1471*69112eddSAli Bahrami 		level = &lms.lms_cdir_stack.stk_s[lms.lms_cdir_stack.stk_n++];
1472*69112eddSAli Bahrami 		level->cdl_if_lineno = arg_mf.mf_lineno;
1473*69112eddSAli Bahrami 		level->cdl_else_lineno = 0;
1474*69112eddSAli Bahrami 
1475*69112eddSAli Bahrami 		/*
1476*69112eddSAli Bahrami 		 * If previous level is not passing, this level is disabled.
1477*69112eddSAli Bahrami 		 * Otherwise, the expression value determines what happens.
1478*69112eddSAli Bahrami 		 */
1479*69112eddSAli Bahrami 		if (pass) {
1480*69112eddSAli Bahrami 			level->cdl_done = level->cdl_pass = expr_eval;
1481*69112eddSAli Bahrami 		} else {
1482*69112eddSAli Bahrami 			level->cdl_done = 1;
1483*69112eddSAli Bahrami 			level->cdl_pass = 0;
1484*69112eddSAli Bahrami 		}
1485*69112eddSAli Bahrami 		break;
1486*69112eddSAli Bahrami 
1487*69112eddSAli Bahrami 	case CDIR_T_ELIF:
1488*69112eddSAli Bahrami 		/* $elif requires an open $if construct */
1489*69112eddSAli Bahrami 		if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
1490*69112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
1491*69112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_ELIF));
1492*69112eddSAli Bahrami 			return (FALSE);
1493*69112eddSAli Bahrami 		}
1494*69112eddSAli Bahrami 
1495*69112eddSAli Bahrami 		/* $elif cannot follow $else */
1496*69112eddSAli Bahrami 		if (level->cdl_else_lineno > 0) {
1497*69112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ELSE),
1498*69112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_ELIF),
1499*69112eddSAli Bahrami 			    EC_LINENO(level->cdl_else_lineno));
1500*69112eddSAli Bahrami 			return (FALSE);
1501*69112eddSAli Bahrami 		}
1502*69112eddSAli Bahrami 
1503*69112eddSAli Bahrami 		/*
1504*69112eddSAli Bahrami 		 * Accept text from $elif if the level isn't already
1505*69112eddSAli Bahrami 		 * done and the expression evaluates to true.
1506*69112eddSAli Bahrami 		 */
1507*69112eddSAli Bahrami 		level->cdl_pass = !level->cdl_done && expr_eval;
1508*69112eddSAli Bahrami 		if (level->cdl_pass)
1509*69112eddSAli Bahrami 			level->cdl_done = 1;
1510*69112eddSAli Bahrami 		break;
1511*69112eddSAli Bahrami 
1512*69112eddSAli Bahrami 	case CDIR_T_ELSE:
1513*69112eddSAli Bahrami 		/* $else requires an open $if construct */
1514*69112eddSAli Bahrami 		if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
1515*69112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
1516*69112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_ELSE));
1517*69112eddSAli Bahrami 			return (FALSE);
1518*69112eddSAli Bahrami 		}
1519*69112eddSAli Bahrami 
1520*69112eddSAli Bahrami 		/* There can only be one $else in the chain */
1521*69112eddSAli Bahrami 		if (level->cdl_else_lineno > 0) {
1522*69112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ELSE),
1523*69112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_ELSE),
1524*69112eddSAli Bahrami 			    EC_LINENO(level->cdl_else_lineno));
1525*69112eddSAli Bahrami 			return (FALSE);
1526*69112eddSAli Bahrami 		}
1527*69112eddSAli Bahrami 		level->cdl_else_lineno = arg_mf.mf_lineno;
1528*69112eddSAli Bahrami 
1529*69112eddSAli Bahrami 		/* Accept text from $else if the level isn't already done */
1530*69112eddSAli Bahrami 		level->cdl_pass = !level->cdl_done;
1531*69112eddSAli Bahrami 		level->cdl_done = 1;
1532*69112eddSAli Bahrami 		break;
1533*69112eddSAli Bahrami 
1534*69112eddSAli Bahrami 	case CDIR_T_ENDIF:
1535*69112eddSAli Bahrami 		/* $endif requires an open $if construct */
1536*69112eddSAli Bahrami 		if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
1537*69112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
1538*69112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_ENDIF));
1539*69112eddSAli Bahrami 			return (FALSE);
1540*69112eddSAli Bahrami 		}
1541*69112eddSAli Bahrami 		if (--lms.lms_cdir_stack.stk_n > 0)
1542*69112eddSAli Bahrami 			level = &STACK_TOP(lms.lms_cdir_stack);
1543*69112eddSAli Bahrami 		break;
1544*69112eddSAli Bahrami 
1545*69112eddSAli Bahrami 	default:
1546*69112eddSAli Bahrami 		return (FALSE);
1547*69112eddSAli Bahrami 	}
1548*69112eddSAli Bahrami 
1549*69112eddSAli Bahrami 	/* Evaluating the control directive above can change pass status */
1550*69112eddSAli Bahrami 	expr_eval = STACK_IS_EMPTY(lms.lms_cdir_stack) ||
1551*69112eddSAli Bahrami 	    STACK_TOP(lms.lms_cdir_stack).cdl_pass;
1552*69112eddSAli Bahrami 	if (expr_eval != pass) {
1553*69112eddSAli Bahrami 		pass = expr_eval;
1554*69112eddSAli Bahrami 		DBG_CALL(Dbg_map_pass(arg_mf.mf_ofl->ofl_lml, pass,
1555*69112eddSAli Bahrami 		    arg_mf.mf_name, arg_mf.mf_lineno, mdptr->md_name));
1556*69112eddSAli Bahrami 	}
1557*69112eddSAli Bahrami 
1558*69112eddSAli Bahrami 	/*
1559*69112eddSAli Bahrami 	 * At this point, we have processed a control directive,
1560*69112eddSAli Bahrami 	 * updated our conditional state stack, and the input is
1561*69112eddSAli Bahrami 	 * positioned at the start of the line following the directive.
1562*69112eddSAli Bahrami 	 * If the current level is accepting input, then give control
1563*69112eddSAli Bahrami 	 * back to ld_map_gettoken() to resume its normal operation.
1564*69112eddSAli Bahrami 	 */
1565*69112eddSAli Bahrami 	if (pass)
1566*69112eddSAli Bahrami 		return (TRUE);
1567*69112eddSAli Bahrami 
1568*69112eddSAli Bahrami 	/*
1569*69112eddSAli Bahrami 	 * The current level is not accepting input. Only another
1570*69112eddSAli Bahrami 	 * control directive can change this, so read and discard input
1571*69112eddSAli Bahrami 	 * until we encounter one of the following:
1572*69112eddSAli Bahrami 	 *
1573*69112eddSAli Bahrami 	 * EOF:			Return and let ld_map_gettoken() report it
1574*69112eddSAli Bahrami 	 * Control Directive:	Restart this function / evaluate new directive
1575*69112eddSAli Bahrami 	 */
1576*69112eddSAli Bahrami 	while (*mf->mf_next != '\0') {
1577*69112eddSAli Bahrami 		/* Skip leading whitespace */
1578*69112eddSAli Bahrami 		while (isspace_nonl(*mf->mf_next))
1579*69112eddSAli Bahrami 			mf->mf_next++;
1580*69112eddSAli Bahrami 
1581*69112eddSAli Bahrami 		/*
1582*69112eddSAli Bahrami 		 * Control directives start with a '$'. If we hit
1583*69112eddSAli Bahrami 		 * one, restart the function at this point
1584*69112eddSAli Bahrami 		 */
1585*69112eddSAli Bahrami 		if (*mf->mf_next == '$')
1586*69112eddSAli Bahrami 			goto restart;
1587*69112eddSAli Bahrami 
1588*69112eddSAli Bahrami 		/* Not a control directive, so advance input to next line */
1589*69112eddSAli Bahrami 		advance_to_eol(&mf->mf_next);
1590*69112eddSAli Bahrami 		if (*mf->mf_next == '\n') {
1591*69112eddSAli Bahrami 			mf->mf_lineno++;
1592*69112eddSAli Bahrami 			mf->mf_next++;
1593*69112eddSAli Bahrami 		}
1594*69112eddSAli Bahrami 	}
1595*69112eddSAli Bahrami 
1596*69112eddSAli Bahrami 	assert(mf->mf_next == '\0');
1597*69112eddSAli Bahrami 	return (TRUE);
1598*69112eddSAli Bahrami 
1599*69112eddSAli Bahrami 	/*
1600*69112eddSAli Bahrami 	 * Control directives that require an argument that is not present
1601*69112eddSAli Bahrami 	 * jump here to report the error and exit.
1602*69112eddSAli Bahrami 	 */
1603*69112eddSAli Bahrami error_reqarg:
1604*69112eddSAli Bahrami 	mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REQARG), mdptr->md_name);
1605*69112eddSAli Bahrami 	return (FALSE);
1606*69112eddSAli Bahrami 
1607*69112eddSAli Bahrami }
1608*69112eddSAli Bahrami 
1609*69112eddSAli Bahrami #ifndef _ELF64
1610*69112eddSAli Bahrami /*
1611*69112eddSAli Bahrami  * Convert a string to lowercase.
1612*69112eddSAli Bahrami  */
1613*69112eddSAli Bahrami void
1614*69112eddSAli Bahrami ld_map_lowercase(char *str)
1615*69112eddSAli Bahrami {
1616*69112eddSAli Bahrami 	while (*str = tolower(*str))
1617*69112eddSAli Bahrami 		str++;
1618*69112eddSAli Bahrami }
1619*69112eddSAli Bahrami #endif
1620*69112eddSAli Bahrami 
1621*69112eddSAli Bahrami /*
1622*69112eddSAli Bahrami  * Wrappper on strtoul()/strtoull(), adapted to return an Xword.
1623*69112eddSAli Bahrami  *
1624*69112eddSAli Bahrami  * entry:
1625*69112eddSAli Bahrami  *	str - Pointer to string to be converted.
1626*69112eddSAli Bahrami  *	endptr - As documented for strtoul(3C). Either NULL, or
1627*69112eddSAli Bahrami  *		address of pointer to receive the address of the first
1628*69112eddSAli Bahrami  *		unused character in str (called "final" in strtoul(3C)).
1629*69112eddSAli Bahrami  *	ret_value - Address of Xword variable to receive result.
1630*69112eddSAli Bahrami  *
1631*69112eddSAli Bahrami  * exit:
1632*69112eddSAli Bahrami  *	On success, *ret_value receives the result, *endptr is updated if
1633*69112eddSAli Bahrami  *	endptr is non-NULL, and STRTOXWORD_OK is returned.
1634*69112eddSAli Bahrami  *	On failure, STRTOXWORD_TOBIG is returned if an otherwise valid
1635*69112eddSAli Bahrami  *	value was too large, and STRTOXWORD_BAD is returned if the string
1636*69112eddSAli Bahrami  *	is malformed.
1637*69112eddSAli Bahrami  */
1638*69112eddSAli Bahrami ld_map_strtoxword_t
1639*69112eddSAli Bahrami ld_map_strtoxword(const char *restrict str, char **restrict endptr,
1640*69112eddSAli Bahrami     Xword *ret_value)
1641*69112eddSAli Bahrami {
1642*69112eddSAli Bahrami #if	defined(_ELF64)			/* _ELF64 */
1643*69112eddSAli Bahrami #define	FUNC		strtoull	/* Function to use */
1644*69112eddSAli Bahrami #define	FUNC_MAX	ULLONG_MAX	/* Largest value returned by FUNC */
1645*69112eddSAli Bahrami #define	XWORD_MAX	ULLONG_MAX	/* Largest Xword value */
1646*69112eddSAli Bahrami 	uint64_t	value;		/* Variable of FUNC return type  */
1647*69112eddSAli Bahrami #else					/* _ELF32 */
1648*69112eddSAli Bahrami #define	FUNC		strtoul
1649*69112eddSAli Bahrami #define	FUNC_MAX	ULONG_MAX
1650*69112eddSAli Bahrami #define	XWORD_MAX	UINT_MAX
1651*69112eddSAli Bahrami 	ulong_t		value;
1652*69112eddSAli Bahrami #endif
1653*69112eddSAli Bahrami 
1654*69112eddSAli Bahrami 	char	*endptr_local;		/* Used if endptr is NULL */
1655*69112eddSAli Bahrami 
1656*69112eddSAli Bahrami 	if (endptr == NULL)
1657*69112eddSAli Bahrami 		endptr = &endptr_local;
1658*69112eddSAli Bahrami 
1659*69112eddSAli Bahrami 	errno = 0;
1660*69112eddSAli Bahrami 	value = FUNC(str, endptr, 0);
1661*69112eddSAli Bahrami 	if ((errno != 0) || (str == *endptr)) {
1662*69112eddSAli Bahrami 		if (value  == FUNC_MAX)
1663*69112eddSAli Bahrami 			return (STRTOXWORD_TOOBIG);
1664*69112eddSAli Bahrami 		else
1665*69112eddSAli Bahrami 			return (STRTOXWORD_BAD);
1666*69112eddSAli Bahrami 	}
1667*69112eddSAli Bahrami 
1668*69112eddSAli Bahrami 	/*
1669*69112eddSAli Bahrami 	 * If this is a 64-bit linker building an ELFCLASS32 object,
1670*69112eddSAli Bahrami 	 * the FUNC return type is a 64-bit value, while an Xword is
1671*69112eddSAli Bahrami 	 * 32-bit. It is possible for FUNC to be able to convert a value
1672*69112eddSAli Bahrami 	 * too large for our return type.
1673*69112eddSAli Bahrami 	 */
1674*69112eddSAli Bahrami #if FUNC_MAX != XWORD_MAX
1675*69112eddSAli Bahrami 	if (value > XWORD_MAX)
1676*69112eddSAli Bahrami 		return (STRTOXWORD_TOOBIG);
1677*69112eddSAli Bahrami #endif
1678*69112eddSAli Bahrami 
1679*69112eddSAli Bahrami 	*ret_value = value;
1680*69112eddSAli Bahrami 	return (STRTOXWORD_OK);
1681*69112eddSAli Bahrami 
1682*69112eddSAli Bahrami #undef FUNC
1683*69112eddSAli Bahrami #undef FUNC_MAX
1684*69112eddSAli Bahrami #undef XWORD_MAC
1685*69112eddSAli Bahrami }
1686*69112eddSAli Bahrami 
1687*69112eddSAli Bahrami /*
1688*69112eddSAli Bahrami  * Convert the unsigned integer value at the current mapfile input
1689*69112eddSAli Bahrami  * into binary form. All numeric values in mapfiles are treated as
1690*69112eddSAli Bahrami  * unsigned integers of the appropriate width for an address on the
1691*69112eddSAli Bahrami  * given target. Values can be decimal, hex, or octal.
1692*69112eddSAli Bahrami  *
1693*69112eddSAli Bahrami  * entry:
1694*69112eddSAli Bahrami  *	str - String to process.
1695*69112eddSAli Bahrami  *	value - Address of variable to receive resulting value.
1696*69112eddSAli Bahrami  *	notail - If TRUE, an error is issued if non-whitespace
1697*69112eddSAli Bahrami  *		characters other than '#' (comment) are found following
1698*69112eddSAli Bahrami  *		the numeric value before the end of line.
1699*69112eddSAli Bahrami  *
1700*69112eddSAli Bahrami  * exit:
1701*69112eddSAli Bahrami  *	On success:
1702*69112eddSAli Bahrami  *		- *str is advanced to the next character following the value
1703*69112eddSAli Bahrami  *		- *value receives the value
1704*69112eddSAli Bahrami  *		- Returns TRUE (1).
1705*69112eddSAli Bahrami  *	On failure, returns FALSE (0).
1706*69112eddSAli Bahrami  */
1707*69112eddSAli Bahrami static Boolean
1708*69112eddSAli Bahrami ld_map_getint(Mapfile *mf, ld_map_tkval_t *value, Boolean notail)
1709*69112eddSAli Bahrami {
1710*69112eddSAli Bahrami 	ld_map_strtoxword_t	s2xw_ret;
1711*69112eddSAli Bahrami 	ld_map_npatch_t	np;
1712*69112eddSAli Bahrami 	char		*endptr;
1713*69112eddSAli Bahrami 	char		*errstr = mf->mf_next;
1714*69112eddSAli Bahrami 
1715*69112eddSAli Bahrami 	value->tkv_int.tkvi_str = mf->mf_next;
1716*69112eddSAli Bahrami 	s2xw_ret = ld_map_strtoxword(mf->mf_next, &endptr,
1717*69112eddSAli Bahrami 	    &value->tkv_int.tkvi_value);
1718*69112eddSAli Bahrami 	if (s2xw_ret != STRTOXWORD_OK) {
1719*69112eddSAli Bahrami 		null_patch_eol(mf->mf_next, &np);
1720*69112eddSAli Bahrami 		if (s2xw_ret == STRTOXWORD_TOOBIG)
1721*69112eddSAli Bahrami 			mf_fatal(mf, MSG_INTL(MSG_MAP_VALUELIMIT), errstr);
1722*69112eddSAli Bahrami 		else
1723*69112eddSAli Bahrami 			mf_fatal(mf, MSG_INTL(MSG_MAP_MALVALUE), errstr);
1724*69112eddSAli Bahrami 		null_patch_undo(&np);
1725*69112eddSAli Bahrami 		return (FALSE);
1726*69112eddSAli Bahrami 	}
1727*69112eddSAli Bahrami 
1728*69112eddSAli Bahrami 	/* Advance position to item following value, skipping whitespace */
1729*69112eddSAli Bahrami 	value->tkv_int.tkvi_cnt = endptr - mf->mf_next;
1730*69112eddSAli Bahrami 	mf->mf_next = endptr;
1731*69112eddSAli Bahrami 	while (isspace_nonl(*mf->mf_next))
1732*69112eddSAli Bahrami 		mf->mf_next++;
1733*69112eddSAli Bahrami 
1734*69112eddSAli Bahrami 	/* If requested, ensure there's nothing left */
1735*69112eddSAli Bahrami 	if (notail && (*mf->mf_next != '\n') && (*mf->mf_next != '#') &&
1736*69112eddSAli Bahrami 	    (*mf->mf_next != '\0')) {
1737*69112eddSAli Bahrami 		null_patch_eol(mf->mf_next, &np);
1738*69112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_BADVALUETAIL), errstr);
1739*69112eddSAli Bahrami 		null_patch_undo(&np);
1740*69112eddSAli Bahrami 		return (FALSE);
1741*69112eddSAli Bahrami 	}
1742*69112eddSAli Bahrami 
1743*69112eddSAli Bahrami 	return (TRUE);
1744*69112eddSAli Bahrami }
1745*69112eddSAli Bahrami 
1746*69112eddSAli Bahrami /*
1747*69112eddSAli Bahrami  * Convert a an unquoted identifier into a TK_STRING token, using the
1748*69112eddSAli Bahrami  * rules for syntax version in use. Used exclusively by ld_map_gettoken().
1749*69112eddSAli Bahrami  *
1750*69112eddSAli Bahrami  * entry:
1751*69112eddSAli Bahrami  *	mf - Mapfile descriptor, positioned to the first character of
1752*69112eddSAli Bahrami  *		the string.
1753*69112eddSAli Bahrami  *	flags - Bitmask of options to control ld_map_gettoken()s behavior
1754*69112eddSAli Bahrami  *	tkv- Address of pointer to variable to receive token value.
1755*69112eddSAli Bahrami  *
1756*69112eddSAli Bahrami  * exit:
1757*69112eddSAli Bahrami  *	On success, mf is advanced past the token, tkv is updated with
1758*69112eddSAli Bahrami  *	the string, and TK_STRING is returned. On error, TK_ERROR is returned.
1759*69112eddSAli Bahrami  */
1760*69112eddSAli Bahrami inline static Token
1761*69112eddSAli Bahrami gettoken_ident(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
1762*69112eddSAli Bahrami {
1763*69112eddSAli Bahrami 	char	*end;
1764*69112eddSAli Bahrami 	Token	tok;
1765*69112eddSAli Bahrami 	ld_map_npatch_t	np;
1766*69112eddSAli Bahrami 
1767*69112eddSAli Bahrami 	tkv->tkv_str = mf->mf_next;
1768*69112eddSAli Bahrami 	if ((end = ident_delimit(mf)) == NULL)
1769*69112eddSAli Bahrami 		return (TK_ERROR);
1770*69112eddSAli Bahrami 	mf->mf_next = end;
1771*69112eddSAli Bahrami 
1772*69112eddSAli Bahrami 	/*
1773*69112eddSAli Bahrami 	 * One advantage of reading the entire mapfile into memory is that
1774*69112eddSAli Bahrami 	 * we can access the strings within it without having to allocate
1775*69112eddSAli Bahrami 	 * more memory or make copies. In order to do that, we need to NULL
1776*69112eddSAli Bahrami 	 * terminate this identifier. That is going to overwrite the
1777*69112eddSAli Bahrami 	 * following character. The problem this presents is that the next
1778*69112eddSAli Bahrami 	 * character may well be the first character of a subsequent token.
1779*69112eddSAli Bahrami 	 * The solution to this is:
1780*69112eddSAli Bahrami 	 *
1781*69112eddSAli Bahrami 	 * 1)	Disallow the case where the next character is able to
1782*69112eddSAli Bahrami 	 *	start a string. This is not legal mapfile syntax anyway,
1783*69112eddSAli Bahrami 	 *	so catching it here simplifies matters.
1784*69112eddSAli Bahrami 	 * 2)	Copy the character into the special mf->mf_next_ch
1785*69112eddSAli Bahrami 	 * 3)	The next call to ld_map_gettoken() checks mf->mf_next_ch,
1786*69112eddSAli Bahrami 	 *	and if it is non-0, uses it instead of dereferencing the
1787*69112eddSAli Bahrami 	 *	mf_next pointer.
1788*69112eddSAli Bahrami 	 */
1789*69112eddSAli Bahrami 	tok = (*mf->mf_next & 0x80) ?
1790*69112eddSAli Bahrami 	    TK_OP_ILLCHR : mf->mf_tokdisp[*mf->mf_next];
1791*69112eddSAli Bahrami 	switch (tok) {
1792*69112eddSAli Bahrami 	case TK_OP_BADCHR:
1793*69112eddSAli Bahrami 		null_patch_eol(mf->mf_next, &np);
1794*69112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next);
1795*69112eddSAli Bahrami 		null_patch_undo(&np);
1796*69112eddSAli Bahrami 		return (TK_ERROR);
1797*69112eddSAli Bahrami 
1798*69112eddSAli Bahrami 	case TK_OP_SIMQUOTE:
1799*69112eddSAli Bahrami 	case TK_OP_CQUOTE:
1800*69112eddSAli Bahrami 	case TK_OP_CDIR:
1801*69112eddSAli Bahrami 	case TK_OP_NUM:
1802*69112eddSAli Bahrami 	case TK_OP_ID:
1803*69112eddSAli Bahrami 		null_patch_eol(mf->mf_next, &np);
1804*69112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_WSNEEDED), mf->mf_next);
1805*69112eddSAli Bahrami 		null_patch_undo(&np);
1806*69112eddSAli Bahrami 		return (TK_ERROR);
1807*69112eddSAli Bahrami 	}
1808*69112eddSAli Bahrami 
1809*69112eddSAli Bahrami 	/* Null terminate, saving the replaced character */
1810*69112eddSAli Bahrami 	mf->mf_next_ch = *mf->mf_next;
1811*69112eddSAli Bahrami 	*mf->mf_next = '\0';
1812*69112eddSAli Bahrami 
1813*69112eddSAli Bahrami 	if (flags & TK_F_STRLC)
1814*69112eddSAli Bahrami 		ld_map_lowercase(tkv->tkv_str);
1815*69112eddSAli Bahrami 	return (TK_STRING);
1816*69112eddSAli Bahrami }
1817*69112eddSAli Bahrami 
1818*69112eddSAli Bahrami /*
1819*69112eddSAli Bahrami  * Convert a quoted string into a TK_STRING token, using simple
1820*69112eddSAli Bahrami  * quoting rules:
1821*69112eddSAli Bahrami  *	- Start and end quotes must be present and match
1822*69112eddSAli Bahrami  *	- There are no special characters or escape sequences.
1823*69112eddSAli Bahrami  * This function is used exclusively by ld_map_gettoken().
1824*69112eddSAli Bahrami  *
1825*69112eddSAli Bahrami  * entry:
1826*69112eddSAli Bahrami  *	mf - Mapfile descriptor, positioned to the opening quote character.
1827*69112eddSAli Bahrami  *	flags - Bitmask of options to control ld_map_gettoken()s behavior
1828*69112eddSAli Bahrami  *	tkv- Address of pointer to variable to receive token value.
1829*69112eddSAli Bahrami  *
1830*69112eddSAli Bahrami  * exit:
1831*69112eddSAli Bahrami  *	On success, mf is advanced past the token, tkv is updated with
1832*69112eddSAli Bahrami  *	the string, and TK_STRING is returned. On error, TK_ERROR is returned.
1833*69112eddSAli Bahrami  */
1834*69112eddSAli Bahrami inline static Token
1835*69112eddSAli Bahrami gettoken_simquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
1836*69112eddSAli Bahrami {
1837*69112eddSAli Bahrami 	char	*str, *end;
1838*69112eddSAli Bahrami 	char	quote;
1839*69112eddSAli Bahrami 
1840*69112eddSAli Bahrami 	str = mf->mf_next++;
1841*69112eddSAli Bahrami 	quote = *str;
1842*69112eddSAli Bahrami 	end = mf->mf_next;
1843*69112eddSAli Bahrami 	while ((*end != '\0') && (*end != '\n') && (*end != quote))
1844*69112eddSAli Bahrami 		end++;
1845*69112eddSAli Bahrami 	if (*end != quote) {
1846*69112eddSAli Bahrami 		ld_map_npatch_t	np;
1847*69112eddSAli Bahrami 
1848*69112eddSAli Bahrami 		null_patch_eol(end, &np);
1849*69112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str);
1850*69112eddSAli Bahrami 		null_patch_undo(&np);
1851*69112eddSAli Bahrami 		return (TK_ERROR);
1852*69112eddSAli Bahrami 	}
1853*69112eddSAli Bahrami 
1854*69112eddSAli Bahrami 	/*
1855*69112eddSAli Bahrami 	 * end is pointing at the closing quote. We can turn that into NULL
1856*69112eddSAli Bahrami 	 * termination for the string without needing to restore it later.
1857*69112eddSAli Bahrami 	 */
1858*69112eddSAli Bahrami 	*end = '\0';
1859*69112eddSAli Bahrami 	mf->mf_next = end + 1;
1860*69112eddSAli Bahrami 	tkv->tkv_str = str + 1;		/* Skip opening quote */
1861*69112eddSAli Bahrami 	if (flags & TK_F_STRLC)
1862*69112eddSAli Bahrami 		ld_map_lowercase(tkv->tkv_str);
1863*69112eddSAli Bahrami 	return (TK_STRING);
1864*69112eddSAli Bahrami }
1865*69112eddSAli Bahrami 
1866*69112eddSAli Bahrami /*
1867*69112eddSAli Bahrami  * Convert a quoted string into a TK_STRING token, using C string literal
1868*69112eddSAli Bahrami  * quoting rules:
1869*69112eddSAli Bahrami  *	- Start and end quotes must be present and match
1870*69112eddSAli Bahrami  *	- Backslash is an escape, used to introduce  special characters
1871*69112eddSAli Bahrami  * This function is used exclusively by ld_map_gettoken().
1872*69112eddSAli Bahrami  *
1873*69112eddSAli Bahrami  * entry:
1874*69112eddSAli Bahrami  *	mf - Mapfile descriptor, positioned to the opening quote character.
1875*69112eddSAli Bahrami  *	flags - Bitmask of options to control ld_map_gettoken()s behavior
1876*69112eddSAli Bahrami  *	tkv- Address of pointer to variable to receive token value.
1877*69112eddSAli Bahrami  *
1878*69112eddSAli Bahrami  * exit:
1879*69112eddSAli Bahrami  *	On success, mf is advanced past the token, tkv is updated with
1880*69112eddSAli Bahrami  *	the string, and TK_STRING is returned. On error, TK_ERROR is returned.
1881*69112eddSAli Bahrami  */
1882*69112eddSAli Bahrami inline static Token
1883*69112eddSAli Bahrami gettoken_cquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
1884*69112eddSAli Bahrami {
1885*69112eddSAli Bahrami 	char	*str, *cur, *end;
1886*69112eddSAli Bahrami 	char	quote;
1887*69112eddSAli Bahrami 	int	c;
1888*69112eddSAli Bahrami 
1889*69112eddSAli Bahrami 	/*
1890*69112eddSAli Bahrami 	 * This function goes through the quoted string and copies
1891*69112eddSAli Bahrami 	 * it on top of itself, replacing escape sequences with the
1892*69112eddSAli Bahrami 	 * characters they denote. There is always enough room for this,
1893*69112eddSAli Bahrami 	 * because escapes are multi-character sequences that are converted
1894*69112eddSAli Bahrami 	 * to single character results.
1895*69112eddSAli Bahrami 	 */
1896*69112eddSAli Bahrami 	str = mf->mf_next++;
1897*69112eddSAli Bahrami 	quote = *str;
1898*69112eddSAli Bahrami 	cur = end = mf->mf_next;
1899*69112eddSAli Bahrami 	for (c = *end++; (c != '\0') && (c != '\n') && (c != quote);
1900*69112eddSAli Bahrami 	    c = *end++) {
1901*69112eddSAli Bahrami 		if (c == '\\') {
1902*69112eddSAli Bahrami 			c = conv_translate_c_esc(&end);
1903*69112eddSAli Bahrami 			if (c == -1) {
1904*69112eddSAli Bahrami 				mf_fatal(mf, MSG_INTL(MSG_MAP_BADCESC), *end);
1905*69112eddSAli Bahrami 				return (TK_ERROR);
1906*69112eddSAli Bahrami 			}
1907*69112eddSAli Bahrami 		}
1908*69112eddSAli Bahrami 		*cur++ = c;
1909*69112eddSAli Bahrami 	}
1910*69112eddSAli Bahrami 	*cur = '\0';		/* terminate the result */
1911*69112eddSAli Bahrami 	if (c != quote) {
1912*69112eddSAli Bahrami 		ld_map_npatch_t	np;
1913*69112eddSAli Bahrami 
1914*69112eddSAli Bahrami 		null_patch_eol(end, &np);
1915*69112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str);
1916*69112eddSAli Bahrami 		null_patch_undo(&np);
1917*69112eddSAli Bahrami 		return (TK_ERROR);
1918*69112eddSAli Bahrami 	}
1919*69112eddSAli Bahrami 
1920*69112eddSAli Bahrami 	/* end is pointing one character past the closing quote */
1921*69112eddSAli Bahrami 	mf->mf_next = end;
1922*69112eddSAli Bahrami 	tkv->tkv_str = str + 1;		/* Skip opening quote */
1923*69112eddSAli Bahrami 	if (flags & TK_F_STRLC)
1924*69112eddSAli Bahrami 		ld_map_lowercase(tkv->tkv_str);
1925*69112eddSAli Bahrami 	return (TK_STRING);
1926*69112eddSAli Bahrami }
1927*69112eddSAli Bahrami 
1928*69112eddSAli Bahrami /*
1929*69112eddSAli Bahrami  * Get a token from the mapfile.
1930*69112eddSAli Bahrami  *
1931*69112eddSAli Bahrami  * entry:
1932*69112eddSAli Bahrami  *	mf - Mapfile descriptor
1933*69112eddSAli Bahrami  *	flags - Bitmask of options to control ld_map_gettoken()s behavior
1934*69112eddSAli Bahrami  *	tkv- Address of pointer to variable to receive token value.
1935*69112eddSAli Bahrami  *
1936*69112eddSAli Bahrami  * exit:
1937*69112eddSAli Bahrami  *	Returns one of the TK_* values, to report the result. If the resulting
1938*69112eddSAli Bahrami  *	token has a value (TK_STRING / TK_INT), and tkv is non-NULL, tkv
1939*69112eddSAli Bahrami  *	is filled in with the resulting value.
1940*69112eddSAli Bahrami  */
1941*69112eddSAli Bahrami Token
1942*69112eddSAli Bahrami ld_map_gettoken(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
1943*69112eddSAli Bahrami {
1944*69112eddSAli Bahrami 	int		cdir_allow, ch;
1945*69112eddSAli Bahrami 	Token		tok;
1946*69112eddSAli Bahrami 	ld_map_npatch_t	np;
1947*69112eddSAli Bahrami 
1948*69112eddSAli Bahrami 	/*
1949*69112eddSAli Bahrami 	 * Mapfile control directives all start with a '$' character. However,
1950*69112eddSAli Bahrami 	 * they are only valid when they are the first thing on a line. That
1951*69112eddSAli Bahrami 	 * happens on the first call to ld_map_gettoken() for a new a new
1952*69112eddSAli Bahrami 	 * mapfile, as tracked with lms.lms_cdir_valid, and immediately
1953*69112eddSAli Bahrami 	 * following each newline seen in the file.
1954*69112eddSAli Bahrami 	 */
1955*69112eddSAli Bahrami 	cdir_allow = lms.lms_cdir_valid;
1956*69112eddSAli Bahrami 	lms.lms_cdir_valid = 0;
1957*69112eddSAli Bahrami 
1958*69112eddSAli Bahrami 	/* Cycle through the characters looking for tokens. */
1959*69112eddSAli Bahrami 	for (;;) {
1960*69112eddSAli Bahrami 		/*
1961*69112eddSAli Bahrami 		 * Process the next character. This is normally *mf->mf_next,
1962*69112eddSAli Bahrami 		 * but if mf->mf_next_ch is non-0, then it contains the
1963*69112eddSAli Bahrami 		 * character, and *mf->mf_next contains a NULL termination
1964*69112eddSAli Bahrami 		 * from the TK_STRING token returned on the previous call.
1965*69112eddSAli Bahrami 		 *
1966*69112eddSAli Bahrami 		 * gettoken_ident() ensures that this is never done to
1967*69112eddSAli Bahrami 		 * a character that starts a string.
1968*69112eddSAli Bahrami 		 */
1969*69112eddSAli Bahrami 		if (mf->mf_next_ch == 0) {
1970*69112eddSAli Bahrami 			ch = *mf->mf_next;
1971*69112eddSAli Bahrami 		} else {
1972*69112eddSAli Bahrami 			ch = mf->mf_next_ch;
1973*69112eddSAli Bahrami 			mf->mf_next_ch = 0;	/* Reset */
1974*69112eddSAli Bahrami 		}
1975*69112eddSAli Bahrami 
1976*69112eddSAli Bahrami 		/* Map the character to a dispatch action */
1977*69112eddSAli Bahrami 		tok = (ch & 0x80) ? TK_OP_ILLCHR : mf->mf_tokdisp[ch];
1978*69112eddSAli Bahrami 
1979*69112eddSAli Bahrami 		/*
1980*69112eddSAli Bahrami 		 * Items that require processing are identified as OP tokens.
1981*69112eddSAli Bahrami 		 * We process them, and return a result non-OP token.
1982*69112eddSAli Bahrami 		 *
1983*69112eddSAli Bahrami 		 * Non-OP tokens are single character tokens, and we return
1984*69112eddSAli Bahrami 		 * them immediately.
1985*69112eddSAli Bahrami 		 */
1986*69112eddSAli Bahrami 		switch (tok) {
1987*69112eddSAli Bahrami 		case TK_OP_EOF:
1988*69112eddSAli Bahrami 			/* If EOFOK is set, quietly report it as TK_EOF */
1989*69112eddSAli Bahrami 			if ((flags & TK_F_EOFOK) != 0)
1990*69112eddSAli Bahrami 				return (TK_EOF);
1991*69112eddSAli Bahrami 
1992*69112eddSAli Bahrami 			/* Treat it as a standard error */
1993*69112eddSAli Bahrami 			mf_fatal0(mf, MSG_INTL(MSG_MAP_PREMEOF));
1994*69112eddSAli Bahrami 			return (TK_ERROR);
1995*69112eddSAli Bahrami 
1996*69112eddSAli Bahrami 		case TK_OP_ILLCHR:
1997*69112eddSAli Bahrami 			mf_fatal(mf, MSG_INTL(MSG_MAP_ILLCHAR), ch);
1998*69112eddSAli Bahrami 			mf->mf_next++;
1999*69112eddSAli Bahrami 			return (TK_ERROR);
2000*69112eddSAli Bahrami 
2001*69112eddSAli Bahrami 		case TK_OP_BADCHR:
2002*69112eddSAli Bahrami 			tk_op_badchr:
2003*69112eddSAli Bahrami 			null_patch_eol(mf->mf_next, &np);
2004*69112eddSAli Bahrami 			mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next);
2005*69112eddSAli Bahrami 			null_patch_undo(&np);
2006*69112eddSAli Bahrami 			mf->mf_next++;
2007*69112eddSAli Bahrami 			return (TK_ERROR);
2008*69112eddSAli Bahrami 
2009*69112eddSAli Bahrami 		case TK_OP_WS:	/* White space */
2010*69112eddSAli Bahrami 			mf->mf_next++;
2011*69112eddSAli Bahrami 			break;
2012*69112eddSAli Bahrami 
2013*69112eddSAli Bahrami 		case TK_OP_NL:	/* White space too, but bump line number. */
2014*69112eddSAli Bahrami 			mf->mf_next++;
2015*69112eddSAli Bahrami 			mf->mf_lineno++;
2016*69112eddSAli Bahrami 			cdir_allow = 1;
2017*69112eddSAli Bahrami 			break;
2018*69112eddSAli Bahrami 
2019*69112eddSAli Bahrami 		case TK_OP_SIMQUOTE:
2020*69112eddSAli Bahrami 			if (flags & TK_F_KEYWORD)
2021*69112eddSAli Bahrami 				goto tk_op_badkwquote;
2022*69112eddSAli Bahrami 			return (gettoken_simquote_str(mf, flags, tkv));
2023*69112eddSAli Bahrami 
2024*69112eddSAli Bahrami 		case TK_OP_CQUOTE:
2025*69112eddSAli Bahrami 			if (flags & TK_F_KEYWORD) {
2026*69112eddSAli Bahrami 			tk_op_badkwquote:
2027*69112eddSAli Bahrami 				null_patch_eol(mf->mf_next, &np);
2028*69112eddSAli Bahrami 				mf_fatal(mf, MSG_INTL(MSG_MAP_BADKWQUOTE),
2029*69112eddSAli Bahrami 				    mf->mf_next);
2030*69112eddSAli Bahrami 				null_patch_undo(&np);
2031*69112eddSAli Bahrami 				mf->mf_next++;
2032*69112eddSAli Bahrami 				return (TK_ERROR);
2033*69112eddSAli Bahrami 			}
2034*69112eddSAli Bahrami 			return (gettoken_cquote_str(mf, flags, tkv));
2035*69112eddSAli Bahrami 
2036*69112eddSAli Bahrami 		case TK_OP_CMT:
2037*69112eddSAli Bahrami 			advance_to_eol(&mf->mf_next);
2038*69112eddSAli Bahrami 			break;
2039*69112eddSAli Bahrami 
2040*69112eddSAli Bahrami 		case TK_OP_CDIR:
2041*69112eddSAli Bahrami 			/*
2042*69112eddSAli Bahrami 			 * Control directives are only valid at the start
2043*69112eddSAli Bahrami 			 * of a line.
2044*69112eddSAli Bahrami 			 */
2045*69112eddSAli Bahrami 			if (!cdir_allow) {
2046*69112eddSAli Bahrami 				null_patch_eol(mf->mf_next, &np);
2047*69112eddSAli Bahrami 				mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOTBOL),
2048*69112eddSAli Bahrami 				    mf->mf_next);
2049*69112eddSAli Bahrami 				null_patch_undo(&np);
2050*69112eddSAli Bahrami 				mf->mf_next++;
2051*69112eddSAli Bahrami 				return (TK_ERROR);
2052*69112eddSAli Bahrami 			}
2053*69112eddSAli Bahrami 			if (!cdir_process(mf))
2054*69112eddSAli Bahrami 				return (TK_ERROR);
2055*69112eddSAli Bahrami 			break;
2056*69112eddSAli Bahrami 
2057*69112eddSAli Bahrami 		case TK_OP_NUM:	/* Decimal, hex(0x...), or octal (0...) value */
2058*69112eddSAli Bahrami 			if (!ld_map_getint(mf, tkv, FALSE))
2059*69112eddSAli Bahrami 				return (TK_ERROR);
2060*69112eddSAli Bahrami 			return (TK_INT);
2061*69112eddSAli Bahrami 
2062*69112eddSAli Bahrami 		case TK_OP_ID:		/* Unquoted identifier */
2063*69112eddSAli Bahrami 			return (gettoken_ident(mf, flags, tkv));
2064*69112eddSAli Bahrami 
2065*69112eddSAli Bahrami 		case TK_OP_CEQUAL:	/* += or -= */
2066*69112eddSAli Bahrami 			if (*(mf->mf_next + 1) != '=')
2067*69112eddSAli Bahrami 				goto tk_op_badchr;
2068*69112eddSAli Bahrami 			tok = (ch == '+') ? TK_PLUSEQ : TK_MINUSEQ;
2069*69112eddSAli Bahrami 			mf->mf_next += 2;
2070*69112eddSAli Bahrami 			return (tok);
2071*69112eddSAli Bahrami 
2072*69112eddSAli Bahrami 		default:	/* Non-OP token */
2073*69112eddSAli Bahrami 			mf->mf_next++;
2074*69112eddSAli Bahrami 			return (tok);
2075*69112eddSAli Bahrami 		}
2076*69112eddSAli Bahrami 	}
2077*69112eddSAli Bahrami 
2078*69112eddSAli Bahrami 	/*NOTREACHED*/
2079*69112eddSAli Bahrami 	assert(0);
2080*69112eddSAli Bahrami 	return (TK_ERROR);
2081*69112eddSAli Bahrami }
2082*69112eddSAli Bahrami 
2083*69112eddSAli Bahrami /*
2084*69112eddSAli Bahrami  * Given a token and value returned by ld_map_gettoken(), return a string
2085*69112eddSAli Bahrami  * representation of it suitable for use in an error message.
2086*69112eddSAli Bahrami  *
2087*69112eddSAli Bahrami  * entry:
2088*69112eddSAli Bahrami  *	tok - Token code. Must not be an OP-token
2089*69112eddSAli Bahrami  *	tkv - Token value
2090*69112eddSAli Bahrami  */
2091*69112eddSAli Bahrami const char *
2092*69112eddSAli Bahrami ld_map_tokenstr(Token tok, ld_map_tkval_t *tkv, Conv_inv_buf_t *inv_buf)
2093*69112eddSAli Bahrami {
2094*69112eddSAli Bahrami 	size_t	cnt;
2095*69112eddSAli Bahrami 
2096*69112eddSAli Bahrami 	switch (tok) {
2097*69112eddSAli Bahrami 	case TK_ERROR:
2098*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_STR_ERROR));
2099*69112eddSAli Bahrami 	case TK_EOF:
2100*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_STR_EOF));
2101*69112eddSAli Bahrami 	case TK_STRING:
2102*69112eddSAli Bahrami 		return (tkv->tkv_str);
2103*69112eddSAli Bahrami 	case TK_COLON:
2104*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_COLON));
2105*69112eddSAli Bahrami 	case TK_SEMICOLON:
2106*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_SEMICOLON));
2107*69112eddSAli Bahrami 	case TK_EQUAL:
2108*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_EQUAL));
2109*69112eddSAli Bahrami 	case TK_PLUSEQ:
2110*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_PLUSEQ));
2111*69112eddSAli Bahrami 	case TK_MINUSEQ:
2112*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_MINUSEQ));
2113*69112eddSAli Bahrami 	case TK_ATSIGN:
2114*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_ATSIGN));
2115*69112eddSAli Bahrami 	case TK_DASH:
2116*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_DASH));
2117*69112eddSAli Bahrami 	case TK_LEFTBKT:
2118*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_LEFTBKT));
2119*69112eddSAli Bahrami 	case TK_RIGHTBKT:
2120*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_RIGHTBKT));
2121*69112eddSAli Bahrami 	case TK_PIPE:
2122*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_PIPE));
2123*69112eddSAli Bahrami 	case TK_INT:
2124*69112eddSAli Bahrami 		cnt = tkv->tkv_int.tkvi_cnt;
2125*69112eddSAli Bahrami 		if (cnt >= sizeof (inv_buf->buf))
2126*69112eddSAli Bahrami 			cnt = sizeof (inv_buf->buf) - 1;
2127*69112eddSAli Bahrami 		(void) memcpy(inv_buf->buf, tkv->tkv_int.tkvi_str, cnt);
2128*69112eddSAli Bahrami 		inv_buf->buf[cnt] = '\0';
2129*69112eddSAli Bahrami 		return (inv_buf->buf);
2130*69112eddSAli Bahrami 	case TK_STAR:
2131*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_STAR));
2132*69112eddSAli Bahrami 	case TK_BANG:
2133*69112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_BANG));
2134*69112eddSAli Bahrami 	default:
2135*69112eddSAli Bahrami 		assert(0);
2136*69112eddSAli Bahrami 		break;
2137*69112eddSAli Bahrami 	}
2138*69112eddSAli Bahrami 
2139*69112eddSAli Bahrami 	/*NOTREACHED*/
2140*69112eddSAli Bahrami 	return (MSG_INTL(MSG_MAP_INTERR));
2141*69112eddSAli Bahrami }
2142*69112eddSAli Bahrami 
2143*69112eddSAli Bahrami /*
2144*69112eddSAli Bahrami  * Advance the input to the first non-empty line, and determine
2145*69112eddSAli Bahrami  * the mapfile version. The version is specified by the mapfile
2146*69112eddSAli Bahrami  * using a $mapfile_version directive. The original System V
2147*69112eddSAli Bahrami  * syntax lacks this directive, and we use that fact to identify
2148*69112eddSAli Bahrami  * such files. SysV mapfile are implicitly defined to have version 1.
2149*69112eddSAli Bahrami  *
2150*69112eddSAli Bahrami  * entry:
2151*69112eddSAli Bahrami  *	ofl - Output file descriptor
2152*69112eddSAli Bahrami  *	mf - Mapfile block
2153*69112eddSAli Bahrami  *
2154*69112eddSAli Bahrami  * exit:
2155*69112eddSAli Bahrami  *	On success, updates mf->mf_version, and returns TRUE (1).
2156*69112eddSAli Bahrami  *	On failure, returns FALSE (0).
2157*69112eddSAli Bahrami  */
2158*69112eddSAli Bahrami static Boolean
2159*69112eddSAli Bahrami mapfile_version(Mapfile *mf)
2160*69112eddSAli Bahrami {
2161*69112eddSAli Bahrami 	char	*line_start = mf->mf_next;
2162*69112eddSAli Bahrami 	Boolean	cont = TRUE;
2163*69112eddSAli Bahrami 	Boolean	status = TRUE;	/* Assume success */
2164*69112eddSAli Bahrami 	Token	tok;
2165*69112eddSAli Bahrami 
2166*69112eddSAli Bahrami 	mf->mf_version = MFV_SYSV;
2167*69112eddSAli Bahrami 
2168*69112eddSAli Bahrami 	/*
2169*69112eddSAli Bahrami 	 * Cycle through the characters looking for tokens. Although the
2170*69112eddSAli Bahrami 	 * true version is not known yet, we use the v2 dispatch table.
2171*69112eddSAli Bahrami 	 * It contains control directives, which we need for this search,
2172*69112eddSAli Bahrami 	 * and the other TK_OP_ tokens we will recognize and act on are the
2173*69112eddSAli Bahrami 	 * same for both tables.
2174*69112eddSAli Bahrami 	 *
2175*69112eddSAli Bahrami 	 * It is important not to process any tokens that would lead to
2176*69112eddSAli Bahrami 	 * a non-OP token:
2177*69112eddSAli Bahrami 	 *
2178*69112eddSAli Bahrami 	 * -	The version is required to interpret them
2179*69112eddSAli Bahrami 	 * -	Our mapfile descriptor is not fully initialized,
2180*69112eddSAli Bahrami 	 *	attempts to run that code will crash the program.
2181*69112eddSAli Bahrami 	 */
2182*69112eddSAli Bahrami 	while (cont) {
2183*69112eddSAli Bahrami 		/* Map the character to a dispatch action */
2184*69112eddSAli Bahrami 		tok = (*mf->mf_next & 0x80) ?
2185*69112eddSAli Bahrami 		    TK_OP_ILLCHR : gettok_dispatch_v2[*mf->mf_next];
2186*69112eddSAli Bahrami 
2187*69112eddSAli Bahrami 		switch (tok) {
2188*69112eddSAli Bahrami 		case TK_OP_WS:	/* White space */
2189*69112eddSAli Bahrami 			mf->mf_next++;
2190*69112eddSAli Bahrami 			break;
2191*69112eddSAli Bahrami 
2192*69112eddSAli Bahrami 		case TK_OP_NL:	/* White space too, but bump line number. */
2193*69112eddSAli Bahrami 			mf->mf_next++;
2194*69112eddSAli Bahrami 			mf->mf_lineno++;
2195*69112eddSAli Bahrami 			break;
2196*69112eddSAli Bahrami 
2197*69112eddSAli Bahrami 		case TK_OP_CMT:
2198*69112eddSAli Bahrami 			advance_to_eol(&mf->mf_next);
2199*69112eddSAli Bahrami 			break;
2200*69112eddSAli Bahrami 
2201*69112eddSAli Bahrami 		case TK_OP_CDIR:
2202*69112eddSAli Bahrami 			/*
2203*69112eddSAli Bahrami 			 * Control directives are only valid at the start
2204*69112eddSAli Bahrami 			 * of a line. However, as we have not yet seen
2205*69112eddSAli Bahrami 			 * a token, we do not need to test for this, and
2206*69112eddSAli Bahrami 			 * can safely assume that we are at the start.
2207*69112eddSAli Bahrami 			 */
2208*69112eddSAli Bahrami 			if (!strncasecmp(mf->mf_next,
2209*69112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_MFVER),
2210*69112eddSAli Bahrami 			    MSG_STR_CDIR_MFVER_SIZE) &&
2211*69112eddSAli Bahrami 			    isspace_nonl(*(mf->mf_next +
2212*69112eddSAli Bahrami 			    MSG_STR_CDIR_MFVER_SIZE))) {
2213*69112eddSAli Bahrami 				ld_map_tkval_t	ver;
2214*69112eddSAli Bahrami 
2215*69112eddSAli Bahrami 				mf->mf_next += MSG_STR_CDIR_MFVER_SIZE + 1;
2216*69112eddSAli Bahrami 				if (!ld_map_getint(mf, &ver, TRUE)) {
2217*69112eddSAli Bahrami 					status = cont = FALSE;
2218*69112eddSAli Bahrami 					break;
2219*69112eddSAli Bahrami 				}
2220*69112eddSAli Bahrami 				/*
2221*69112eddSAli Bahrami 				 * Is it a valid version? Note that we
2222*69112eddSAli Bahrami 				 * intentionally do not allow you to
2223*69112eddSAli Bahrami 				 * specify version 1 using the $mapfile_version
2224*69112eddSAli Bahrami 				 * syntax, because that's reserved to version
2225*69112eddSAli Bahrami 				 * 2 and up.
2226*69112eddSAli Bahrami 				 */
2227*69112eddSAli Bahrami 				if ((ver.tkv_int.tkvi_value < 2) ||
2228*69112eddSAli Bahrami 				    (ver.tkv_int.tkvi_value >= MFV_NUM)) {
2229*69112eddSAli Bahrami 					const char *fmt;
2230*69112eddSAli Bahrami 
2231*69112eddSAli Bahrami 					fmt = (ver.tkv_int.tkvi_value < 2) ?
2232*69112eddSAli Bahrami 					    MSG_INTL(MSG_MAP_CDIR_BADVDIR) :
2233*69112eddSAli Bahrami 					    MSG_INTL(MSG_MAP_CDIR_BADVER);
2234*69112eddSAli Bahrami 					mf_fatal(mf, fmt,
2235*69112eddSAli Bahrami 					    EC_WORD(ver.tkv_int.tkvi_value));
2236*69112eddSAli Bahrami 					status = cont = FALSE;
2237*69112eddSAli Bahrami 					break;
2238*69112eddSAli Bahrami 				}
2239*69112eddSAli Bahrami 				mf->mf_version = ver.tkv_int.tkvi_value;
2240*69112eddSAli Bahrami 				cont = FALSE; /* Version recovered. All done */
2241*69112eddSAli Bahrami 				break;
2242*69112eddSAli Bahrami 			}
2243*69112eddSAli Bahrami 			/*
2244*69112eddSAli Bahrami 			 * Not a version directive. Reset the current position
2245*69112eddSAli Bahrami 			 * to the start of the current line and stop here.
2246*69112eddSAli Bahrami 			 * SysV syntax applies.
2247*69112eddSAli Bahrami 			 */
2248*69112eddSAli Bahrami 			mf->mf_next = line_start;
2249*69112eddSAli Bahrami 			cont = FALSE;
2250*69112eddSAli Bahrami 			break;
2251*69112eddSAli Bahrami 
2252*69112eddSAli Bahrami 		default:
2253*69112eddSAli Bahrami 			/*
2254*69112eddSAli Bahrami 			 * If we see anything else, then stop at this point.
2255*69112eddSAli Bahrami 			 * The file has System V syntax (version 1), and the
2256*69112eddSAli Bahrami 			 * next token should be interpreted as such.
2257*69112eddSAli Bahrami 			 */
2258*69112eddSAli Bahrami 			cont = FALSE;
2259*69112eddSAli Bahrami 			break;
2260*69112eddSAli Bahrami 		}
2261*69112eddSAli Bahrami 	}
2262*69112eddSAli Bahrami 
2263*69112eddSAli Bahrami 	return (status);
2264*69112eddSAli Bahrami }
2265*69112eddSAli Bahrami 
2266*69112eddSAli Bahrami /*
2267*69112eddSAli Bahrami  * Parse the mapfile.
2268*69112eddSAli Bahrami  */
2269*69112eddSAli Bahrami Boolean
2270*69112eddSAli Bahrami ld_map_parse(const char *mapfile, Ofl_desc *ofl)
2271*69112eddSAli Bahrami {
2272*69112eddSAli Bahrami 	struct stat	stat_buf;	/* stat of mapfile */
2273*69112eddSAli Bahrami 	int		mapfile_fd;	/* descriptor for mapfile */
2274*69112eddSAli Bahrami 	int		err;
2275*69112eddSAli Bahrami 	Mapfile		*mf;		/* Mapfile descriptor */
2276*69112eddSAli Bahrami 	size_t		name_len;	/* strlen(mapfile) */
2277*69112eddSAli Bahrami 
2278*69112eddSAli Bahrami 	/*
2279*69112eddSAli Bahrami 	 * Determine if we're dealing with a file or a directory.
2280*69112eddSAli Bahrami 	 */
2281*69112eddSAli Bahrami 	if (stat(mapfile, &stat_buf) == -1) {
2282*69112eddSAli Bahrami 		err = errno;
2283*69112eddSAli Bahrami 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_STAT),
2284*69112eddSAli Bahrami 		    mapfile, strerror(err));
2285*69112eddSAli Bahrami 		return (FALSE);
2286*69112eddSAli Bahrami 	}
2287*69112eddSAli Bahrami 	if (S_ISDIR(stat_buf.st_mode)) {
2288*69112eddSAli Bahrami 		DIR		*dirp;
2289*69112eddSAli Bahrami 		struct dirent	*denp;
2290*69112eddSAli Bahrami 
2291*69112eddSAli Bahrami 		/*
2292*69112eddSAli Bahrami 		 * Open the directory and interpret each visible file as a
2293*69112eddSAli Bahrami 		 * mapfile.
2294*69112eddSAli Bahrami 		 */
2295*69112eddSAli Bahrami 		if ((dirp = opendir(mapfile)) == NULL)
2296*69112eddSAli Bahrami 			return (TRUE);
2297*69112eddSAli Bahrami 
2298*69112eddSAli Bahrami 		while ((denp = readdir(dirp)) != NULL) {
2299*69112eddSAli Bahrami 			char	path[PATH_MAX];
2300*69112eddSAli Bahrami 
2301*69112eddSAli Bahrami 			/*
2302*69112eddSAli Bahrami 			 * Ignore any hidden filenames.  Construct the full
2303*69112eddSAli Bahrami 			 * pathname to the new mapfile.
2304*69112eddSAli Bahrami 			 */
2305*69112eddSAli Bahrami 			if (*denp->d_name == '.')
2306*69112eddSAli Bahrami 				continue;
2307*69112eddSAli Bahrami 			(void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_STR_PATH),
2308*69112eddSAli Bahrami 			    mapfile, denp->d_name);
2309*69112eddSAli Bahrami 			if (!ld_map_parse(path, ofl))
2310*69112eddSAli Bahrami 				return (FALSE);
2311*69112eddSAli Bahrami 		}
2312*69112eddSAli Bahrami 		(void) closedir(dirp);
2313*69112eddSAli Bahrami 		return (TRUE);
2314*69112eddSAli Bahrami 	} else if (!S_ISREG(stat_buf.st_mode)) {
2315*69112eddSAli Bahrami 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_NOTREG),
2316*69112eddSAli Bahrami 		    mapfile);
2317*69112eddSAli Bahrami 		return (FALSE);
2318*69112eddSAli Bahrami 	}
2319*69112eddSAli Bahrami 
2320*69112eddSAli Bahrami 	/* Open file */
2321*69112eddSAli Bahrami 	if ((mapfile_fd = open(mapfile, O_RDONLY)) == -1) {
2322*69112eddSAli Bahrami 		err = errno;
2323*69112eddSAli Bahrami 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN),
2324*69112eddSAli Bahrami 		    mapfile, strerror(err));
2325*69112eddSAli Bahrami 		return (FALSE);
2326*69112eddSAli Bahrami 	}
2327*69112eddSAli Bahrami 
2328*69112eddSAli Bahrami 	/*
2329*69112eddSAli Bahrami 	 * Allocate enough memory to hold the state block, mapfile name,
2330*69112eddSAli Bahrami 	 * and mapfile text. Text has alignment 1, so it can follow the
2331*69112eddSAli Bahrami 	 * state block without padding.
2332*69112eddSAli Bahrami 	 */
2333*69112eddSAli Bahrami 	name_len = strlen(mapfile) + 1;
2334*69112eddSAli Bahrami 	mf = libld_malloc(sizeof (*mf) + name_len + stat_buf.st_size + 1);
2335*69112eddSAli Bahrami 	if (mf == NULL)
2336*69112eddSAli Bahrami 		return (FALSE);
2337*69112eddSAli Bahrami 	mf->mf_ofl = ofl;
2338*69112eddSAli Bahrami 	mf->mf_name = (char *)(mf + 1);
2339*69112eddSAli Bahrami 	(void) strcpy(mf->mf_name, mapfile);
2340*69112eddSAli Bahrami 	mf->mf_text = mf->mf_name + name_len;
2341*69112eddSAli Bahrami 	if (read(mapfile_fd, mf->mf_text, stat_buf.st_size) !=
2342*69112eddSAli Bahrami 	    stat_buf.st_size) {
2343*69112eddSAli Bahrami 		err = errno;
2344*69112eddSAli Bahrami 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_READ),
2345*69112eddSAli Bahrami 		    mapfile, strerror(err));
2346*69112eddSAli Bahrami 		(void) close(mapfile_fd);
2347*69112eddSAli Bahrami 		return (FALSE);
2348*69112eddSAli Bahrami 	}
2349*69112eddSAli Bahrami 	(void) close(mapfile_fd);
2350*69112eddSAli Bahrami 	mf->mf_text[stat_buf.st_size] = '\0';
2351*69112eddSAli Bahrami 	mf->mf_next = mf->mf_text;
2352*69112eddSAli Bahrami 	mf->mf_lineno = 1;
2353*69112eddSAli Bahrami 	mf->mf_next_ch = 0;		/* No "lookahead" character yet */
2354*69112eddSAli Bahrami 	mf->mf_ec_insndx = 0;		/* Insert entrace criteria at top */
2355*69112eddSAli Bahrami 
2356*69112eddSAli Bahrami 	/*
2357*69112eddSAli Bahrami 	 * Read just enough from the mapfile to determine the version,
2358*69112eddSAli Bahrami 	 * and then dispatch to the appropriate code for further processing
2359*69112eddSAli Bahrami 	 */
2360*69112eddSAli Bahrami 	if (!mapfile_version(mf))
2361*69112eddSAli Bahrami 		return (FALSE);
2362*69112eddSAli Bahrami 
2363*69112eddSAli Bahrami 	/*
2364*69112eddSAli Bahrami 	 * Start and continuation masks for unquoted identifier at this
2365*69112eddSAli Bahrami 	 * mapfile version level.
2366*69112eddSAli Bahrami 	 */
2367*69112eddSAli Bahrami 	mf->mf_tkid_start = TKID_ATTR_START(mf->mf_version);
2368*69112eddSAli Bahrami 	mf->mf_tkid_cont = TKID_ATTR_CONT(mf->mf_version);
2369*69112eddSAli Bahrami 
2370*69112eddSAli Bahrami 	DBG_CALL(Dbg_map_parse(ofl->ofl_lml, mapfile, mf->mf_version));
2371*69112eddSAli Bahrami 
2372*69112eddSAli Bahrami 	switch (mf->mf_version) {
2373*69112eddSAli Bahrami 	case MFV_SYSV:
2374*69112eddSAli Bahrami 		mf->mf_tokdisp = gettok_dispatch_v1;
2375*69112eddSAli Bahrami 		if (!ld_map_parse_v1(mf))
2376*69112eddSAli Bahrami 			return (FALSE);
2377*69112eddSAli Bahrami 		break;
2378*69112eddSAli Bahrami 
2379*69112eddSAli Bahrami 	case MFV_SOLARIS:
2380*69112eddSAli Bahrami 		mf->mf_tokdisp = gettok_dispatch_v2;
2381*69112eddSAli Bahrami 		STACK_RESET(lms.lms_cdir_stack);
2382*69112eddSAli Bahrami 
2383*69112eddSAli Bahrami 		/*
2384*69112eddSAli Bahrami 		 * If the conditional expression identifier tree has not been
2385*69112eddSAli Bahrami 		 * initialized, set it up. This is only done on the first
2386*69112eddSAli Bahrami 		 * mapfile, because the identifier control directives accumulate
2387*69112eddSAli Bahrami 		 * across all the mapfiles.
2388*69112eddSAli Bahrami 		 */
2389*69112eddSAli Bahrami 		if ((lms.lms_cexp_id == NULL) && !cexp_ident_init())
2390*69112eddSAli Bahrami 			return (FALSE);
2391*69112eddSAli Bahrami 
2392*69112eddSAli Bahrami 		/*
2393*69112eddSAli Bahrami 		 * Tell ld_map_gettoken() we will accept a '$' as starting a
2394*69112eddSAli Bahrami 		 * control directive on the first call. Normally, they are
2395*69112eddSAli Bahrami 		 * only allowed after a newline.
2396*69112eddSAli Bahrami 		 */
2397*69112eddSAli Bahrami 		lms.lms_cdir_valid = 1;
2398*69112eddSAli Bahrami 
2399*69112eddSAli Bahrami 		if (!ld_map_parse_v2(mf))
2400*69112eddSAli Bahrami 			return (FALSE);
2401*69112eddSAli Bahrami 
2402*69112eddSAli Bahrami 		/* Did we leave any open $if control directives? */
2403*69112eddSAli Bahrami 		if (!STACK_IS_EMPTY(lms.lms_cdir_stack)) {
2404*69112eddSAli Bahrami 			while (!STACK_IS_EMPTY(lms.lms_cdir_stack)) {
2405*69112eddSAli Bahrami 				cdir_level_t *level =
2406*69112eddSAli Bahrami 				    &STACK_POP(lms.lms_cdir_stack);
2407*69112eddSAli Bahrami 
2408*69112eddSAli Bahrami 				mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOEND),
2409*69112eddSAli Bahrami 				    EC_LINENO(level->cdl_if_lineno));
2410*69112eddSAli Bahrami 			}
2411*69112eddSAli Bahrami 			return (FALSE);
2412*69112eddSAli Bahrami 		}
2413*69112eddSAli Bahrami 		break;
2414*69112eddSAli Bahrami 	}
2415*69112eddSAli Bahrami 
2416*69112eddSAli Bahrami 	return (TRUE);
2417*69112eddSAli Bahrami }
2418*69112eddSAli Bahrami 
2419*69112eddSAli Bahrami /*
2420*69112eddSAli Bahrami  * Sort the segment list. This is necessary if a mapfile has set explicit
2421*69112eddSAli Bahrami  * virtual addresses for segments, or defined a SEGMENT_ORDER directive.
2422*69112eddSAli Bahrami  *
2423*69112eddSAli Bahrami  * Only PT_LOAD segments can be assigned a virtual address.  These segments can
2424*69112eddSAli Bahrami  * be one of two types:
2425*69112eddSAli Bahrami  *
2426*69112eddSAli Bahrami  *  -	Standard segments for text, data or bss.  These segments will have been
2427*69112eddSAli Bahrami  *	inserted before the default text (first PT_LOAD) segment.
2428*69112eddSAli Bahrami  *
2429*69112eddSAli Bahrami  *  -	Empty (reservation) segments.  These segment will have been inserted at
2430*69112eddSAli Bahrami  *	the end of any default PT_LOAD segments.
2431*69112eddSAli Bahrami  *
2432*69112eddSAli Bahrami  * Any standard segments that are assigned a virtual address will be sorted,
2433*69112eddSAli Bahrami  * and as their definitions precede any default PT_LOAD segments, these segments
2434*69112eddSAli Bahrami  * will be assigned sections before any defaults.
2435*69112eddSAli Bahrami  *
2436*69112eddSAli Bahrami  * Any reservation segments are also sorted amoung themselves, as these segments
2437*69112eddSAli Bahrami  * must still follow the standard default segments.
2438*69112eddSAli Bahrami  */
2439*69112eddSAli Bahrami static Boolean
2440*69112eddSAli Bahrami sort_seg_list(Ofl_desc *ofl)
2441*69112eddSAli Bahrami {
2442*69112eddSAli Bahrami 	APlist	*sort_segs = NULL, *load_segs = NULL;
2443*69112eddSAli Bahrami 	Sg_desc	*sgp1;
2444*69112eddSAli Bahrami 	Aliste	idx1;
2445*69112eddSAli Bahrami 	Aliste	nsegs;
2446*69112eddSAli Bahrami 
2447*69112eddSAli Bahrami 
2448*69112eddSAli Bahrami 	/*
2449*69112eddSAli Bahrami 	 * We know the number of elements in the sorted list will be
2450*69112eddSAli Bahrami 	 * the same as the original, so use this as the initial allocation
2451*69112eddSAli Bahrami 	 * size for the replacement aplist.
2452*69112eddSAli Bahrami 	 */
2453*69112eddSAli Bahrami 	nsegs = aplist_nitems(ofl->ofl_segs);
2454*69112eddSAli Bahrami 
2455*69112eddSAli Bahrami 
2456*69112eddSAli Bahrami 	/* Add the items below SGID_TEXT to the list */
2457*69112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
2458*69112eddSAli Bahrami 		if (sgp1->sg_id >= SGID_TEXT)
2459*69112eddSAli Bahrami 			break;
2460*69112eddSAli Bahrami 
2461*69112eddSAli Bahrami 		if (aplist_append(&sort_segs, sgp1, nsegs) == NULL)
2462*69112eddSAli Bahrami 				return (FALSE);
2463*69112eddSAli Bahrami 	}
2464*69112eddSAli Bahrami 
2465*69112eddSAli Bahrami 	/*
2466*69112eddSAli Bahrami 	 * If there are any SEGMENT_ORDER items, add them, and set their
2467*69112eddSAli Bahrami 	 * FLG_SG_ORDERED flag to identify them in debug output, and to
2468*69112eddSAli Bahrami 	 * prevent them from being added again below.
2469*69112eddSAli Bahrami 	 */
2470*69112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_segs_order, idx1, sgp1)) {
2471*69112eddSAli Bahrami 		if (aplist_append(&sort_segs, sgp1, nsegs) == NULL)
2472*69112eddSAli Bahrami 			return (FALSE);
2473*69112eddSAli Bahrami 		sgp1->sg_flags |= FLG_SG_ORDERED;
2474*69112eddSAli Bahrami 	}
2475*69112eddSAli Bahrami 
2476*69112eddSAli Bahrami 	/*
2477*69112eddSAli Bahrami 	 * Add the loadable segments to another list in sorted order.
2478*69112eddSAli Bahrami 	 */
2479*69112eddSAli Bahrami 	DBG_CALL(Dbg_map_sort_title(ofl->ofl_lml, TRUE));
2480*69112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
2481*69112eddSAli Bahrami 		DBG_CALL(Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS,
2482*69112eddSAli Bahrami 		    ld_targ.t_m.m_mach, sgp1));
2483*69112eddSAli Bahrami 
2484*69112eddSAli Bahrami 		/* Only interested in PT_LOAD items not in SEGMENT_ORDER list */
2485*69112eddSAli Bahrami 		if ((sgp1->sg_phdr.p_type != PT_LOAD) ||
2486*69112eddSAli Bahrami 		    (sgp1->sg_flags & FLG_SG_ORDERED))
2487*69112eddSAli Bahrami 			continue;
2488*69112eddSAli Bahrami 
2489*69112eddSAli Bahrami 		/*
2490*69112eddSAli Bahrami 		 * If the loadable segment does not contain a vaddr, simply
2491*69112eddSAli Bahrami 		 * append it to the new list.
2492*69112eddSAli Bahrami 		 */
2493*69112eddSAli Bahrami 		if ((sgp1->sg_flags & FLG_SG_P_VADDR) == 0) {
2494*69112eddSAli Bahrami 			if (aplist_append(&load_segs, sgp1, AL_CNT_SEGMENTS) ==
2495*69112eddSAli Bahrami 			    NULL)
2496*69112eddSAli Bahrami 				return (FALSE);
2497*69112eddSAli Bahrami 
2498*69112eddSAli Bahrami 		} else {
2499*69112eddSAli Bahrami 			Aliste		idx2;
2500*69112eddSAli Bahrami 			Sg_desc		*sgp2;
2501*69112eddSAli Bahrami 			int		inserted = 0;
2502*69112eddSAli Bahrami 
2503*69112eddSAli Bahrami 			/*
2504*69112eddSAli Bahrami 			 * Traverse the segment list we are creating, looking
2505*69112eddSAli Bahrami 			 * for a segment that defines a vaddr.
2506*69112eddSAli Bahrami 			 */
2507*69112eddSAli Bahrami 			for (APLIST_TRAVERSE(load_segs, idx2, sgp2)) {
2508*69112eddSAli Bahrami 				/*
2509*69112eddSAli Bahrami 				 * Any real segments that contain vaddr's need
2510*69112eddSAli Bahrami 				 * to be sorted.  Any reservation segments also
2511*69112eddSAli Bahrami 				 * need to be sorted.  However, any reservation
2512*69112eddSAli Bahrami 				 * segments should be placed after any real
2513*69112eddSAli Bahrami 				 * segments.
2514*69112eddSAli Bahrami 				 */
2515*69112eddSAli Bahrami 				if (((sgp2->sg_flags &
2516*69112eddSAli Bahrami 				    (FLG_SG_P_VADDR | FLG_SG_EMPTY)) == 0) &&
2517*69112eddSAli Bahrami 				    (sgp1->sg_flags & FLG_SG_EMPTY))
2518*69112eddSAli Bahrami 					continue;
2519*69112eddSAli Bahrami 
2520*69112eddSAli Bahrami 				if ((sgp2->sg_flags & FLG_SG_P_VADDR) &&
2521*69112eddSAli Bahrami 				    ((sgp2->sg_flags & FLG_SG_EMPTY) ==
2522*69112eddSAli Bahrami 				    (sgp1->sg_flags & FLG_SG_EMPTY))) {
2523*69112eddSAli Bahrami 					if (sgp1->sg_phdr.p_vaddr ==
2524*69112eddSAli Bahrami 					    sgp2->sg_phdr.p_vaddr) {
2525*69112eddSAli Bahrami 						eprintf(ofl->ofl_lml, ERR_FATAL,
2526*69112eddSAli Bahrami 						    MSG_INTL(MSG_MAP_SEGSAME),
2527*69112eddSAli Bahrami 						    sgp1->sg_name,
2528*69112eddSAli Bahrami 						    sgp2->sg_name);
2529*69112eddSAli Bahrami 						return (FALSE);
2530*69112eddSAli Bahrami 					}
2531*69112eddSAli Bahrami 
2532*69112eddSAli Bahrami 					if (sgp1->sg_phdr.p_vaddr >
2533*69112eddSAli Bahrami 					    sgp2->sg_phdr.p_vaddr)
2534*69112eddSAli Bahrami 						continue;
2535*69112eddSAli Bahrami 				}
2536*69112eddSAli Bahrami 
2537*69112eddSAli Bahrami 				/*
2538*69112eddSAli Bahrami 				 * Insert this segment before the segment on
2539*69112eddSAli Bahrami 				 * the load_segs list.
2540*69112eddSAli Bahrami 				 */
2541*69112eddSAli Bahrami 				if (aplist_insert(&load_segs, sgp1,
2542*69112eddSAli Bahrami 				    AL_CNT_SEGMENTS, idx2) == NULL)
2543*69112eddSAli Bahrami 					return (FALSE);
2544*69112eddSAli Bahrami 				inserted = 1;
2545*69112eddSAli Bahrami 				break;
2546*69112eddSAli Bahrami 			}
2547*69112eddSAli Bahrami 
2548*69112eddSAli Bahrami 			/*
2549*69112eddSAli Bahrami 			 * If the segment being inspected has not been inserted
2550*69112eddSAli Bahrami 			 * in the segment list, simply append it to the list.
2551*69112eddSAli Bahrami 			 */
2552*69112eddSAli Bahrami 			if ((inserted == 0) && (aplist_append(&load_segs,
2553*69112eddSAli Bahrami 			    sgp1, AL_CNT_SEGMENTS) == NULL))
2554*69112eddSAli Bahrami 				return (FALSE);
2555*69112eddSAli Bahrami 		}
2556*69112eddSAli Bahrami 	}
2557*69112eddSAli Bahrami 
2558*69112eddSAli Bahrami 	/*
2559*69112eddSAli Bahrami 	 * Add the sorted loadable segments to our initial segment list.
2560*69112eddSAli Bahrami 	 */
2561*69112eddSAli Bahrami 	for (APLIST_TRAVERSE(load_segs, idx1, sgp1)) {
2562*69112eddSAli Bahrami 		if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL)
2563*69112eddSAli Bahrami 			return (FALSE);
2564*69112eddSAli Bahrami 	}
2565*69112eddSAli Bahrami 
2566*69112eddSAli Bahrami 	/*
2567*69112eddSAli Bahrami 	 * Add all other segments to our list.
2568*69112eddSAli Bahrami 	 */
2569*69112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
2570*69112eddSAli Bahrami 		if ((sgp1->sg_id < SGID_TEXT) ||
2571*69112eddSAli Bahrami 		    (sgp1->sg_phdr.p_type == PT_LOAD) ||
2572*69112eddSAli Bahrami 		    (sgp1->sg_flags & FLG_SG_ORDERED))
2573*69112eddSAli Bahrami 			continue;
2574*69112eddSAli Bahrami 
2575*69112eddSAli Bahrami 		if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL)
2576*69112eddSAli Bahrami 			return (FALSE);
2577*69112eddSAli Bahrami 	}
2578*69112eddSAli Bahrami 
2579*69112eddSAli Bahrami 	/*
2580*69112eddSAli Bahrami 	 * Free the original list, and the pt_load list, and use
2581*69112eddSAli Bahrami 	 * the new list as the segment list.
2582*69112eddSAli Bahrami 	 */
2583*69112eddSAli Bahrami 	free(ofl->ofl_segs);
2584*69112eddSAli Bahrami 	if (load_segs) free(load_segs);
2585*69112eddSAli Bahrami 	ofl->ofl_segs = sort_segs;
2586*69112eddSAli Bahrami 
2587*69112eddSAli Bahrami 	if (DBG_ENABLED) {
2588*69112eddSAli Bahrami 		Dbg_map_sort_title(ofl->ofl_lml, FALSE);
2589*69112eddSAli Bahrami 		for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
2590*69112eddSAli Bahrami 			Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS,
2591*69112eddSAli Bahrami 			    ld_targ.t_m.m_mach, sgp1);
2592*69112eddSAli Bahrami 			}
2593*69112eddSAli Bahrami 		}
2594*69112eddSAli Bahrami 
2595*69112eddSAli Bahrami 	return (TRUE);
2596*69112eddSAli Bahrami }
2597*69112eddSAli Bahrami 
2598*69112eddSAli Bahrami /*
2599*69112eddSAli Bahrami  * After all mapfiles have been processed, this routine is used to
2600*69112eddSAli Bahrami  * finish any remaining mapfile related work.
2601*69112eddSAli Bahrami  *
2602*69112eddSAli Bahrami  * exit:
2603*69112eddSAli Bahrami  *	Returns TRUE on success, and FALSE on failure.
2604*69112eddSAli Bahrami  */
2605*69112eddSAli Bahrami Boolean
2606*69112eddSAli Bahrami ld_map_post_process(Ofl_desc *ofl)
2607*69112eddSAli Bahrami {
2608*69112eddSAli Bahrami 	Aliste		idx, idx2;
2609*69112eddSAli Bahrami 	Is_desc		*isp;
2610*69112eddSAli Bahrami 	Sg_desc		*sgp;
2611*69112eddSAli Bahrami 	Ent_desc	*enp;
2612*69112eddSAli Bahrami 	Sg_desc		*first_seg = NULL;
2613*69112eddSAli Bahrami 
2614*69112eddSAli Bahrami 
2615*69112eddSAli Bahrami 	DBG_CALL(Dbg_map_post_title(ofl->ofl_lml));
2616*69112eddSAli Bahrami 
2617*69112eddSAli Bahrami 	/*
2618*69112eddSAli Bahrami 	 * Per-segment processing:
2619*69112eddSAli Bahrami 	 * -	Identify segments with explicit virtual address
2620*69112eddSAli Bahrami 	 * -	Details of input and output section order
2621*69112eddSAli Bahrami 	 */
2622*69112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) {
2623*69112eddSAli Bahrami 		/*
2624*69112eddSAli Bahrami 		 * We are looking for segments. Program headers that represent
2625*69112eddSAli Bahrami 		 * segments are required to have a non-NULL name pointer,
2626*69112eddSAli Bahrami 		 * while that those that do not are required to have a
2627*69112eddSAli Bahrami 		 * NULL name pointer.
2628*69112eddSAli Bahrami 		 */
2629*69112eddSAli Bahrami 		if (sgp->sg_name == NULL)
2630*69112eddSAli Bahrami 			continue;
2631*69112eddSAli Bahrami 
2632*69112eddSAli Bahrami 		/* Remember the first non-disabled segment */
2633*69112eddSAli Bahrami 		if ((first_seg == NULL) && !(sgp->sg_flags & FLG_SG_DISABLED))
2634*69112eddSAli Bahrami 			first_seg = sgp;
2635*69112eddSAli Bahrami 
2636*69112eddSAli Bahrami 		/*
2637*69112eddSAli Bahrami 		 * If a segment has an explicit virtual address, we will
2638*69112eddSAli Bahrami 		 * need to sort the segments.
2639*69112eddSAli Bahrami 		 */
2640*69112eddSAli Bahrami 		if (sgp->sg_flags & FLG_SG_P_VADDR)
2641*69112eddSAli Bahrami 			ofl->ofl_flags1 |= FLG_OF1_VADDR;
2642*69112eddSAli Bahrami 
2643*69112eddSAli Bahrami 		/*
2644*69112eddSAli Bahrami 		 * The FLG_OF_OS_ORDER flag enables the code that does
2645*69112eddSAli Bahrami 		 * output section ordering. Set if the segment has
2646*69112eddSAli Bahrami 		 * a non-empty output section order list.
2647*69112eddSAli Bahrami 		 */
2648*69112eddSAli Bahrami 		if (alist_nitems(sgp->sg_os_order) > 0)
2649*69112eddSAli Bahrami 			ofl->ofl_flags |= FLG_OF_OS_ORDER;
2650*69112eddSAli Bahrami 
2651*69112eddSAli Bahrami 		/*
2652*69112eddSAli Bahrami 		 * The version 1 and version 2 syntaxes for input section
2653*69112eddSAli Bahrami 		 * ordering are different and incompatible enough that we
2654*69112eddSAli Bahrami 		 * only allow the use of one or the other for a given segment:
2655*69112eddSAli Bahrami 		 *
2656*69112eddSAli Bahrami 		 * v1)	The version 1 syntax has the user set the ?O flag on
2657*69112eddSAli Bahrami 		 *	the segment. If this is done, all input sections placed
2658*69112eddSAli Bahrami 		 *	via an entrance criteria that has a section name are to
2659*69112eddSAli Bahrami 		 *	be sorted, using the order of the entrance criteria
2660*69112eddSAli Bahrami 		 *	as the sort key.
2661*69112eddSAli Bahrami 		 *
2662*69112eddSAli Bahrami 		 * v2)	The version 2 syntax has the user specify a name for
2663*69112eddSAli Bahrami 		 * 	the entry criteria, and then provide a list of entry
2664*69112eddSAli Bahrami 		 * 	criteria names via the IS_ORDER segment attribute.
2665*69112eddSAli Bahrami 		 * 	Sections placed via the criteria listed in IS_ORDER
2666*69112eddSAli Bahrami 		 * 	are sorted, and the others are not.
2667*69112eddSAli Bahrami 		 *
2668*69112eddSAli Bahrami 		 * Regardless of the syntax version used, the section sorting
2669*69112eddSAli Bahrami 		 * code expects the following:
2670*69112eddSAli Bahrami 		 *
2671*69112eddSAli Bahrami 		 * -	Segments requiring input section sorting have the
2672*69112eddSAli Bahrami 		 *	FLG_SG_IS_ORDER flag set
2673*69112eddSAli Bahrami 		 *
2674*69112eddSAli Bahrami 		 * -	Entrance criteria referencing the segment that
2675*69112eddSAli Bahrami 		 *	participate in input section sorting have a non-zero
2676*69112eddSAli Bahrami 		 *	sort key in their ec_ordndx field.
2677*69112eddSAli Bahrami 		 *
2678*69112eddSAli Bahrami 		 * At this point, the following are true:
2679*69112eddSAli Bahrami 		 *
2680*69112eddSAli Bahrami 		 * -	All entrance criteria have ec_ordndx set to 0.
2681*69112eddSAli Bahrami 		 * -	Segments that require the version 1 behavior have
2682*69112eddSAli Bahrami 		 *	the FLG_SG_IS_ORDER flag set, and the segments
2683*69112eddSAli Bahrami 		 *	sg_is_order list is empty.
2684*69112eddSAli Bahrami 		 * -	Segments that require the version 2 behavior do not
2685*69112eddSAli Bahrami 		 *	have FLG_SG_IS_ORDER set, and the sg_is_order list is
2686*69112eddSAli Bahrami 		 *	non-empty. This list contains the names of the entrance
2687*69112eddSAli Bahrami 		 *	criteria that will participate in input section sorting,
2688*69112eddSAli Bahrami 		 *	and their relative order in the list provides the
2689*69112eddSAli Bahrami 		 *	sort key to use.
2690*69112eddSAli Bahrami 		 *
2691*69112eddSAli Bahrami 		 * We must detect these two cases, set the FLG_SG_IS_ORDER
2692*69112eddSAli Bahrami 		 * flag as necessary, and fill in all entrance criteria
2693*69112eddSAli Bahrami 		 * sort keys. If any input section sorting is to be done,
2694*69112eddSAli Bahrami 		 * we also set the FLG_OF_IS_ORDER flag on the output descriptor
2695*69112eddSAli Bahrami 		 * to enable the code that does that work.
2696*69112eddSAli Bahrami 		 */
2697*69112eddSAli Bahrami 
2698*69112eddSAli Bahrami 		/* Version 1: ?O flag? */
2699*69112eddSAli Bahrami 		if (sgp->sg_flags & FLG_SG_IS_ORDER) {
2700*69112eddSAli Bahrami 			Word	index = 0;
2701*69112eddSAli Bahrami 
2702*69112eddSAli Bahrami 			ofl->ofl_flags |= FLG_OF_IS_ORDER;
2703*69112eddSAli Bahrami 			DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml,
2704*69112eddSAli Bahrami 			    sgp->sg_name));
2705*69112eddSAli Bahrami 
2706*69112eddSAli Bahrami 			/*
2707*69112eddSAli Bahrami 			 * Give each user defined entrance criteria for this
2708*69112eddSAli Bahrami 			 * segment that specifies a section name a
2709*69112eddSAli Bahrami 			 * monotonically increasing sort key.
2710*69112eddSAli Bahrami 			 */
2711*69112eddSAli Bahrami 			for (APLIST_TRAVERSE(ofl->ofl_ents, idx2, enp))
2712*69112eddSAli Bahrami 				if ((enp->ec_segment == sgp) &&
2713*69112eddSAli Bahrami 				    (enp->ec_is_name != NULL) &&
2714*69112eddSAli Bahrami 				    ((enp->ec_flags & FLG_EC_BUILTIN) == 0))
2715*69112eddSAli Bahrami 					enp->ec_ordndx = ++index;
2716*69112eddSAli Bahrami 			continue;
2717*69112eddSAli Bahrami 		}
2718*69112eddSAli Bahrami 
2719*69112eddSAli Bahrami 		/* Version 2: SEGMENT IS_ORDER list? */
2720*69112eddSAli Bahrami 		if (aplist_nitems(sgp->sg_is_order) > 0) {
2721*69112eddSAli Bahrami 			Word	index = 0;
2722*69112eddSAli Bahrami 
2723*69112eddSAli Bahrami 			ofl->ofl_flags |= FLG_OF_IS_ORDER;
2724*69112eddSAli Bahrami 			DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml,
2725*69112eddSAli Bahrami 			    sgp->sg_name));
2726*69112eddSAli Bahrami 
2727*69112eddSAli Bahrami 			/*
2728*69112eddSAli Bahrami 			 * Give each entrance criteria in the sg_is_order
2729*69112eddSAli Bahrami 			 * list a monotonically increasing sort key.
2730*69112eddSAli Bahrami 			 */
2731*69112eddSAli Bahrami 			for (APLIST_TRAVERSE(sgp->sg_is_order, idx2, enp)) {
2732*69112eddSAli Bahrami 				enp->ec_ordndx = ++index;
2733*69112eddSAli Bahrami 				enp->ec_segment->sg_flags |= FLG_SG_IS_ORDER;
2734*69112eddSAli Bahrami 			}
2735*69112eddSAli Bahrami 		}
2736*69112eddSAli Bahrami 	}
2737*69112eddSAli Bahrami 
2738*69112eddSAli Bahrami 	/* Sort the segment descriptors if necessary */
2739*69112eddSAli Bahrami 	if (((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
2740*69112eddSAli Bahrami 	    (aplist_nitems(ofl->ofl_segs_order) > 0)) &&
2741*69112eddSAli Bahrami 	    !sort_seg_list(ofl))
2742*69112eddSAli Bahrami 		return (FALSE);
2743*69112eddSAli Bahrami 
2744*69112eddSAli Bahrami 	/*
2745*69112eddSAli Bahrami 	 * If the output file is a static file without an interpreter, and
2746*69112eddSAli Bahrami 	 * if any virtual address is specified, then set the NOHDR flag for
2747*69112eddSAli Bahrami 	 * backward compatibility.
2748*69112eddSAli Bahrami 	 */
2749*69112eddSAli Bahrami 	if (!(ofl->ofl_flags & (FLG_OF_DYNAMIC | FLG_OF_RELOBJ)) &&
2750*69112eddSAli Bahrami 	    !(ofl->ofl_osinterp) && (ofl->ofl_flags1 & FLG_OF1_VADDR))
2751*69112eddSAli Bahrami 		ofl->ofl_dtflags_1 |= DF_1_NOHDR;
2752*69112eddSAli Bahrami 
2753*69112eddSAli Bahrami 	if (ofl->ofl_flags & FLG_OF_RELOBJ) {
2754*69112eddSAli Bahrami 		/*
2755*69112eddSAli Bahrami 		 * NOHDR has no effect on a relocatable file.
2756*69112eddSAli Bahrami 		 * Make sure this flag isn't set.
2757*69112eddSAli Bahrami 		 */
2758*69112eddSAli Bahrami 		ofl->ofl_dtflags_1 &= ~DF_1_NOHDR;
2759*69112eddSAli Bahrami 	} else if (first_seg != NULL) {
2760*69112eddSAli Bahrami 		/*
2761*69112eddSAli Bahrami 		 * DF_1_NOHDR might have been set globally by the HDR_NOALLOC
2762*69112eddSAli Bahrami 		 * directive. If not, then we want to check the per-segment
2763*69112eddSAli Bahrami 		 * flag for the first loadable segment and propagate it
2764*69112eddSAli Bahrami 		 * if set.
2765*69112eddSAli Bahrami 		 */
2766*69112eddSAli Bahrami 		if ((ofl->ofl_dtflags_1 & DF_1_NOHDR) == 0) {
2767*69112eddSAli Bahrami 			/*
2768*69112eddSAli Bahrami 			 * If we sorted the segments, the first segment
2769*69112eddSAli Bahrami 			 * may have changed.
2770*69112eddSAli Bahrami 			 */
2771*69112eddSAli Bahrami 			if ((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
2772*69112eddSAli Bahrami 			    (aplist_nitems(ofl->ofl_segs_order) > 0)) {
2773*69112eddSAli Bahrami 				for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) {
2774*69112eddSAli Bahrami 					if (sgp->sg_name == NULL)
2775*69112eddSAli Bahrami 						continue;
2776*69112eddSAli Bahrami 					if ((sgp->sg_flags & FLG_SG_DISABLED) ==
2777*69112eddSAli Bahrami 					    0) {
2778*69112eddSAli Bahrami 						first_seg = sgp;
2779*69112eddSAli Bahrami 						break;
2780*69112eddSAli Bahrami 					}
2781*69112eddSAli Bahrami 				}
2782*69112eddSAli Bahrami 			}
2783*69112eddSAli Bahrami 
2784*69112eddSAli Bahrami 			/*
2785*69112eddSAli Bahrami 			 * If the per-segment NOHDR flag is set on our first
2786*69112eddSAli Bahrami 			 * segment, then make it take effect.
2787*69112eddSAli Bahrami 			 */
2788*69112eddSAli Bahrami 			if (first_seg->sg_flags & FLG_SG_NOHDR)
2789*69112eddSAli Bahrami 				ofl->ofl_dtflags_1 |= DF_1_NOHDR;
2790*69112eddSAli Bahrami 		}
2791*69112eddSAli Bahrami 
2792*69112eddSAli Bahrami 		/*
2793*69112eddSAli Bahrami 		 * For executable and shared objects, the first segment must
2794*69112eddSAli Bahrami 		 * be loadable unless NOHDR was specified, because the ELF
2795*69112eddSAli Bahrami 		 * header must simultaneously lie at offset 0 of the file and
2796*69112eddSAli Bahrami 		 * be included in the first loadable segment. This isn't
2797*69112eddSAli Bahrami 		 * possible if some other segment type starts the file
2798*69112eddSAli Bahrami 		 */
2799*69112eddSAli Bahrami 		if (!(ofl->ofl_dtflags_1 & DF_1_NOHDR) &&
2800*69112eddSAli Bahrami 		    (first_seg->sg_phdr.p_type != PT_LOAD)) {
2801*69112eddSAli Bahrami 			Conv_inv_buf_t	inv_buf;
2802*69112eddSAli Bahrami 
2803*69112eddSAli Bahrami 			eprintf(ofl->ofl_lml, ERR_FATAL,
2804*69112eddSAli Bahrami 			    MSG_INTL(MSG_SEG_FIRNOTLOAD),
2805*69112eddSAli Bahrami 			    conv_phdr_type(ELFOSABI_SOLARIS, ld_targ.t_m.m_mach,
2806*69112eddSAli Bahrami 			    first_seg->sg_phdr.p_type, 0, &inv_buf),
2807*69112eddSAli Bahrami 			    first_seg->sg_name);
2808*69112eddSAli Bahrami 			return (FALSE);
2809*69112eddSAli Bahrami 		}
2810*69112eddSAli Bahrami 	}
2811*69112eddSAli Bahrami 
2812*69112eddSAli Bahrami 	/*
2813*69112eddSAli Bahrami 	 * Mapfiles may have been used to create symbol definitions
2814*69112eddSAli Bahrami 	 * with backing storage.  Although the backing storage is
2815*69112eddSAli Bahrami 	 * associated with an input section, the association of the
2816*69112eddSAli Bahrami 	 * section to an output section (and segment) is initially
2817*69112eddSAli Bahrami 	 * deferred.  Now that all mapfile processing is complete, any
2818*69112eddSAli Bahrami 	 * entrance criteria requirements have been processed, and
2819*69112eddSAli Bahrami 	 * these backing storage sections can be associated with the
2820*69112eddSAli Bahrami 	 * appropriate output section (and segment).
2821*69112eddSAli Bahrami 	 */
2822*69112eddSAli Bahrami 	if (ofl->ofl_maptext || ofl->ofl_mapdata)
2823*69112eddSAli Bahrami 		DBG_CALL(Dbg_sec_backing(ofl->ofl_lml));
2824*69112eddSAli Bahrami 
2825*69112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_maptext, idx, isp)) {
2826*69112eddSAli Bahrami 		if (ld_place_section(ofl, isp, NULL,
2827*69112eddSAli Bahrami 		    ld_targ.t_id.id_text, NULL) == (Os_desc *)S_ERROR)
2828*69112eddSAli Bahrami 			return (FALSE);
2829*69112eddSAli Bahrami 	}
2830*69112eddSAli Bahrami 
2831*69112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_mapdata, idx, isp)) {
2832*69112eddSAli Bahrami 		if (ld_place_section(ofl, isp, NULL,
2833*69112eddSAli Bahrami 		    ld_targ.t_id.id_data, NULL) == (Os_desc *)S_ERROR)
2834*69112eddSAli Bahrami 			return (FALSE);
2835*69112eddSAli Bahrami 	}
2836*69112eddSAli Bahrami 
2837*69112eddSAli Bahrami 	return (TRUE);
2838*69112eddSAli Bahrami }
2839