169112eddSAli Bahrami /*
269112eddSAli Bahrami  * CDDL HEADER START
369112eddSAli Bahrami  *
469112eddSAli Bahrami  * The contents of this file are subject to the terms of the
569112eddSAli Bahrami  * Common Development and Distribution License (the "License").
669112eddSAli Bahrami  * You may not use this file except in compliance with the License.
769112eddSAli Bahrami  *
869112eddSAli Bahrami  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
969112eddSAli Bahrami  * or http://www.opensolaris.org/os/licensing.
1069112eddSAli Bahrami  * See the License for the specific language governing permissions
1169112eddSAli Bahrami  * and limitations under the License.
1269112eddSAli Bahrami  *
1369112eddSAli Bahrami  * When distributing Covered Code, include this CDDL HEADER in each
1469112eddSAli Bahrami  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1569112eddSAli Bahrami  * If applicable, add the following below this CDDL HEADER, with the
1669112eddSAli Bahrami  * fields enclosed by brackets "[]" replaced with your own identifying
1769112eddSAli Bahrami  * information: Portions Copyright [yyyy] [name of copyright owner]
1869112eddSAli Bahrami  *
1969112eddSAli Bahrami  * CDDL HEADER END
2069112eddSAli Bahrami  */
2169112eddSAli Bahrami 
2269112eddSAli Bahrami /*
2369112eddSAli Bahrami  *	Copyright (c) 1988 AT&T
2469112eddSAli Bahrami  *	  All Rights Reserved
2569112eddSAli Bahrami  *
261007fd6fSAli Bahrami  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
27*44bf619dSJohn Levon  *
28*44bf619dSJohn Levon  * Copyright 2019 Joyent, Inc.
2969112eddSAli Bahrami  */
3069112eddSAli Bahrami 
3169112eddSAli Bahrami /*
3269112eddSAli Bahrami  * Map file parsing (Shared Core Code).
3369112eddSAli Bahrami  */
3469112eddSAli Bahrami #include	<fcntl.h>
3569112eddSAli Bahrami #include	<stdio.h>
3669112eddSAli Bahrami #include	<unistd.h>
3769112eddSAli Bahrami #include	<sys/stat.h>
3869112eddSAli Bahrami #include	<errno.h>
3969112eddSAli Bahrami #include	<limits.h>
4069112eddSAli Bahrami #include	<dirent.h>
4169112eddSAli Bahrami #include	<ctype.h>
4269112eddSAli Bahrami #include	<debug.h>
4369112eddSAli Bahrami #include	"msg.h"
4469112eddSAli Bahrami #include	"_libld.h"
4569112eddSAli Bahrami #include	"_map.h"
4669112eddSAli Bahrami 
4769112eddSAli Bahrami /*
4869112eddSAli Bahrami  * There are two styles of mapfile supported by the link-editor:
4969112eddSAli Bahrami  *
5069112eddSAli Bahrami  * 1)	The original System V defined syntax, as augmented at Sun
5169112eddSAli Bahrami  *	from Solaris 2.0 through Solaris 10. This style is also known
5269112eddSAli Bahrami  *	as version 1.
5369112eddSAli Bahrami  *
5469112eddSAli Bahrami  * 2)	A newer syntax, currently at version 2.
5569112eddSAli Bahrami  *
5669112eddSAli Bahrami  * The original syntax uses special characters (=, :, -, |, etc) as
5769112eddSAli Bahrami  * operators to indicate the operation being specified. Over the years,
5869112eddSAli Bahrami  * this syntax has been problematic:
5969112eddSAli Bahrami  *
6069112eddSAli Bahrami  * 1)	Too cryptic: It's hard for people to remember which character
6169112eddSAli Bahrami  *	means what.
6269112eddSAli Bahrami  *
6369112eddSAli Bahrami  * 2)	Limited expansion potential: There only a few special characters
6469112eddSAli Bahrami  *	available on the keyboard for new features, and it is difficult to
6569112eddSAli Bahrami  *	add options to existing ones.
6669112eddSAli Bahrami  *
6769112eddSAli Bahrami  * Adding new features into this framework (2) have the effect of
6869112eddSAli Bahrami  * making the syntax even more cryptic (1). The newer syntax addresses
6969112eddSAli Bahrami  * these issues by moving to an extendible identifier based syntax that
7069112eddSAli Bahrami  * allows new features to be added without complicating old ones.
7169112eddSAli Bahrami  *
7269112eddSAli Bahrami  * The new syntax uses the following terminology:
7369112eddSAli Bahrami  *
7469112eddSAli Bahrami  * -	Control directives are the directives that start with a '$'.
7569112eddSAli Bahrami  *	They control how the mapfile is interpreted. We use the 'cdir_'
7669112eddSAli Bahrami  *	prefix on functions and variables related to these directives.
7769112eddSAli Bahrami  *
7869112eddSAli Bahrami  * -	Conditional Expressions are the expressions found in $if and $elif
7969112eddSAli Bahrami  *	control directives. They evaluate to boolean true/false values.
8069112eddSAli Bahrami  *	We use the 'cexp_' prefix for functions and variables related to
8169112eddSAli Bahrami  *	these expressions.
8269112eddSAli Bahrami  *
8369112eddSAli Bahrami  * -	Regular Directives are names (SYMBOL, VERSION, etc) that convey
8469112eddSAli Bahrami  *	directions to the link-editor for building the output object.
8569112eddSAli Bahrami  *
8669112eddSAli Bahrami  * This file contains core code used by both mapfile styles: File management,
8769112eddSAli Bahrami  * lexical analysis, and other shared core functionality. It also contains
8869112eddSAli Bahrami  * the code for control directives, as they are intrinsically part of
8969112eddSAli Bahrami  * lexical analysis --- this is disabled when processing Sysv mapfiles.
9069112eddSAli Bahrami  */
9169112eddSAli Bahrami 
9269112eddSAli Bahrami /*
9369112eddSAli Bahrami  * We use a stack of cdir_level_t structs to manage $if/$elif/$else/$endif
9469112eddSAli Bahrami  * processing. At each level, we keep track of the information needed to
9569112eddSAli Bahrami  * determine whether or not to process nested input lines or skip them,
9669112eddSAli Bahrami  * along with information needed to report errors.
9769112eddSAli Bahrami  */
9869112eddSAli Bahrami typedef struct {
9969112eddSAli Bahrami 	Lineno		cdl_if_lineno;	/* Line number of opening $if */
10069112eddSAli Bahrami 	Lineno		cdl_else_lineno; /* 0, or line on which $else seen */
10169112eddSAli Bahrami 	int		cdl_done;	/* True if no longer accepts input */
10269112eddSAli Bahrami 	int		cdl_pass;	/* True if currently accepting input */
10369112eddSAli Bahrami } cdir_level_t;
10469112eddSAli Bahrami 
10569112eddSAli Bahrami /* Operators in the expressions accepted by $if/$elif */
10669112eddSAli Bahrami typedef enum {
10769112eddSAli Bahrami 	CEXP_OP_NONE,		/* Not an operator */
10869112eddSAli Bahrami 	CEXP_OP_AND,		/* && */
10969112eddSAli Bahrami 	CEXP_OP_OR,		/* || */
11069112eddSAli Bahrami 	CEXP_OP_NEG,		/* ! */
11169112eddSAli Bahrami 	CEXP_OP_OPAR,		/* ( */
11269112eddSAli Bahrami 	CEXP_OP_CPAR		/* ) */
11369112eddSAli Bahrami } cexp_op_t;
11469112eddSAli Bahrami 
11569112eddSAli Bahrami /*
11669112eddSAli Bahrami  * Type of conditional expression identifier AVL tree nodes
11769112eddSAli Bahrami  */
11869112eddSAli Bahrami typedef struct cexp_name_node {
11969112eddSAli Bahrami 	avl_node_t	ceid_avlnode;	/* AVL book-keeping */
12069112eddSAli Bahrami 	const char	*ceid_name;	/* boolean identifier name */
12169112eddSAli Bahrami } cexp_id_node_t;
12269112eddSAli Bahrami 
12369112eddSAli Bahrami 
12469112eddSAli Bahrami /*
12569112eddSAli Bahrami  * Declare a "stack" type, containing a pointer to data, a count of
12669112eddSAli Bahrami  * allocated, and currently used items in the stack. The data type
12769112eddSAli Bahrami  * is specified as the _type argument.
12869112eddSAli Bahrami  */
12969112eddSAli Bahrami #define	STACK(_type) \
13069112eddSAli Bahrami 	struct { \
13169112eddSAli Bahrami 		_type	*stk_s;		/* Stack array */ \
13269112eddSAli Bahrami 		size_t	stk_n;		/* Current stack depth */ \
13369112eddSAli Bahrami 		size_t	stk_n_alloc;	/* # of elements pointed at by s */ \
13469112eddSAli Bahrami 	}
13569112eddSAli Bahrami 
13669112eddSAli Bahrami /*
13769112eddSAli Bahrami  * The following type represents a "generic" stack, where the data
13869112eddSAli Bahrami  * type is (void). This type is never instantiated. However, it has
13969112eddSAli Bahrami  * the same struct layout as any other STACK(), and is therefore a good
14069112eddSAli Bahrami  * generic type that can be used for stack_resize().
14169112eddSAli Bahrami  */
14269112eddSAli Bahrami typedef STACK(void) generic_stack_t;
14369112eddSAli Bahrami 
14469112eddSAli Bahrami /*
14569112eddSAli Bahrami  * Ensure that the stack has enough room to push one more item
14669112eddSAli Bahrami  */
14769112eddSAli Bahrami #define	STACK_RESERVE(_stack, _n_default) \
14869112eddSAli Bahrami 	(((_stack).stk_n < (_stack).stk_n_alloc) || \
14969112eddSAli Bahrami 	stack_resize((generic_stack_t *)&(_stack).stk_s, _n_default, \
15069112eddSAli Bahrami 	sizeof (*(_stack).stk_s)))
15169112eddSAli Bahrami 
15269112eddSAli Bahrami /*
15369112eddSAli Bahrami  * Reset a stack to empty.
15469112eddSAli Bahrami  */
15569112eddSAli Bahrami #define	STACK_RESET(_stack) (_stack).stk_n = 0;
15669112eddSAli Bahrami 
15769112eddSAli Bahrami /*
15869112eddSAli Bahrami  * True if stack is empty, False otherwise.
15969112eddSAli Bahrami  */
16069112eddSAli Bahrami #define	STACK_IS_EMPTY(_stack) ((_stack).stk_n == 0)
16169112eddSAli Bahrami 
16269112eddSAli Bahrami /*
16369112eddSAli Bahrami  * Push a value onto a stack. Caller must ensure that stack has room.
16469112eddSAli Bahrami  * This macro is intended to be used as the LHS of an assignment, the
16569112eddSAli Bahrami  * RHS of which is the value:
16669112eddSAli Bahrami  *
16769112eddSAli Bahrami  *	STACK_PUSH(stack) = value;
16869112eddSAli Bahrami  */
16969112eddSAli Bahrami #define	STACK_PUSH(_stack) (_stack).stk_s[(_stack).stk_n++]
17069112eddSAli Bahrami 
17169112eddSAli Bahrami /*
17269112eddSAli Bahrami  * Pop a value off a stack.  Caller must ensure
17369112eddSAli Bahrami  * that stack is not empty.
17469112eddSAli Bahrami  */
17569112eddSAli Bahrami #define	STACK_POP(_stack) ((_stack).stk_s[--(_stack).stk_n])
17669112eddSAli Bahrami 
17769112eddSAli Bahrami /*
17869112eddSAli Bahrami  * Access top element on stack without popping. Caller must ensure
17969112eddSAli Bahrami  * that stack is not empty.
18069112eddSAli Bahrami  */
18169112eddSAli Bahrami #define	STACK_TOP(_stack) (((_stack).stk_s)[(_stack).stk_n - 1])
18269112eddSAli Bahrami 
18369112eddSAli Bahrami /*
18469112eddSAli Bahrami  * Initial sizes used for the stacks: The stacks are allocated on demand
18569112eddSAli Bahrami  * to these sizes, and then doubled as necessary until they are large enough.
18669112eddSAli Bahrami  *
18769112eddSAli Bahrami  * The ideal size would be large enough that only a single allocation
18869112eddSAli Bahrami  * occurs, and our defaults should generally have that effect. However,
18969112eddSAli Bahrami  * in doing so, we run the risk of a latent error in the resize code going
19069112eddSAli Bahrami  * undetected until triggered by a large task in the field. For this reason,
19169112eddSAli Bahrami  * we set the sizes to the smallest size possible when compiled for debug.
19269112eddSAli Bahrami  */
19369112eddSAli Bahrami #ifdef DEBUG
19469112eddSAli Bahrami #define	CDIR_STACK_INIT		1
19569112eddSAli Bahrami #define	CEXP_OP_STACK_INIT	1
19669112eddSAli Bahrami #define	CEXP_VAL_STACK_INIT	1
19769112eddSAli Bahrami #else
19869112eddSAli Bahrami #define	CDIR_STACK_INIT 	16
19969112eddSAli Bahrami #define	CEXP_OP_STACK_INIT	8
20069112eddSAli Bahrami #define	CEXP_VAL_STACK_INIT	(CEXP_OP_STACK_INIT * 2) /* 2 vals per binop */
20169112eddSAli Bahrami #endif
20269112eddSAli Bahrami 
20369112eddSAli Bahrami 
20469112eddSAli Bahrami /*
20569112eddSAli Bahrami  * Persistent state maintained by map module in between calls.
20669112eddSAli Bahrami  *
20769112eddSAli Bahrami  * This is kept as static file scope data, because it is only used
20869112eddSAli Bahrami  * when libld is called by ld, and not by rtld. If that should change,
20969112eddSAli Bahrami  * the code is designed so that it can become reentrant easily:
21069112eddSAli Bahrami  *
21169112eddSAli Bahrami  * -	Add a pointer to the output descriptor to a structure of this type,
21269112eddSAli Bahrami  *	allocated dynamically on the first call to ld_map_parse().
21369112eddSAli Bahrami  * -	Change all references to lms to instead reference the pointer in
21469112eddSAli Bahrami  *	the output descriptor.
21569112eddSAli Bahrami  *
21669112eddSAli Bahrami  * Until then, it is simpler not to expose these details.
21769112eddSAli Bahrami  */
21869112eddSAli Bahrami typedef struct {
21969112eddSAli Bahrami 	int	lms_cdir_valid;	/* Allow control dir. on entry to gettoken() */
22069112eddSAli Bahrami 	STACK(cdir_level_t)	lms_cdir_stack;	/* Conditional input level */
22169112eddSAli Bahrami 	STACK(cexp_op_t)	lms_cexp_op_stack; /* Cond. expr operators */
22269112eddSAli Bahrami 	STACK(uchar_t)		lms_cexp_val_stack; /* Cond. expr values */
22369112eddSAli Bahrami 	avl_tree_t		*lms_cexp_id;
22469112eddSAli Bahrami } ld_map_state_t;
22569112eddSAli Bahrami static ld_map_state_t lms;
22669112eddSAli Bahrami 
22769112eddSAli Bahrami 
22869112eddSAli Bahrami /*
22969112eddSAli Bahrami  * Version 1 (SysV) syntax dispatch table for ld_map_gettoken(). For each
23069112eddSAli Bahrami  * of the 7-bit ASCII characters, determine how the lexical analyzer
23169112eddSAli Bahrami  * should behave.
23269112eddSAli Bahrami  *
23369112eddSAli Bahrami  * This table must be kept in sync with tkid_attr[] below.
23469112eddSAli Bahrami  *
23569112eddSAli Bahrami  * Identifier Note:
23669112eddSAli Bahrami  * The Linker and Libraries Guide states that the original syntax uses
23769112eddSAli Bahrami  * C identifier rules, allowing '.' to be treated as a letter. However,
23869112eddSAli Bahrami  * the implementation is considerably looser than that: Any character
23969112eddSAli Bahrami  * with an ASCII code (0-127) which is printable and not used to start
24069112eddSAli Bahrami  * another token is allowed to start an identifier, and they are terminated
24169112eddSAli Bahrami  * by any of: space, double quote, tab, newline, ':', ';', '=', or '#'.
24269112eddSAli Bahrami  * The original code has been replaced, but this table encodes the same
24369112eddSAli Bahrami  * rules, to ensure backward compatibility.
24469112eddSAli Bahrami  */
24569112eddSAli Bahrami static const mf_tokdisp_t gettok_dispatch_v1 = {
24669112eddSAli Bahrami 	TK_OP_EOF,			/* 0 - NUL */
24769112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 1 - SOH */
24869112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 2 - STX */
24969112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 3 - ETX */
25069112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 4 - EOT */
25169112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 5 - ENQ */
25269112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 6 - ACK */
25369112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 7 - BEL */
25469112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 8 - BS */
25569112eddSAli Bahrami 	TK_OP_WS,			/* 9 - HT */
25669112eddSAli Bahrami 	TK_OP_NL,			/* 10 - NL */
25769112eddSAli Bahrami 	TK_OP_WS,			/* 11 - VT */
25869112eddSAli Bahrami 	TK_OP_WS,			/* 12 - FF */
25969112eddSAli Bahrami 	TK_OP_WS,			/* 13 - CR */
26069112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 14 - SO */
26169112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 15 - SI */
26269112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 16 - DLE */
26369112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 17 - DC1 */
26469112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 18 - DC2 */
26569112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 19 - DC3 */
26669112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 20 - DC4 */
26769112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 21 - NAK */
26869112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 22 - SYN */
26969112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 23 - ETB */
27069112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 24 - CAN */
27169112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 25 - EM */
27269112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 26 - SUB */
27369112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 27 - ESC */
27469112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 28 - FS */
27569112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 29 - GS */
27669112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 30 - RS */
27769112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 31 - US */
27869112eddSAli Bahrami 	TK_OP_WS,			/* 32 - SP */
27969112eddSAli Bahrami 	TK_OP_ID,			/* 33 - ! */
28069112eddSAli Bahrami 	TK_OP_SIMQUOTE,			/* 34 - " */
28169112eddSAli Bahrami 	TK_OP_CMT,			/* 35 - # */
28269112eddSAli Bahrami 	TK_OP_ID,			/* 36 - $ */
28369112eddSAli Bahrami 	TK_OP_ID,			/* 37 - % */
28469112eddSAli Bahrami 	TK_OP_ID,			/* 38 - & */
28569112eddSAli Bahrami 	TK_OP_ID,			/* 39 - ' */
28669112eddSAli Bahrami 	TK_OP_ID,			/* 40 - ( */
28769112eddSAli Bahrami 	TK_OP_ID,			/* 41 - ) */
28869112eddSAli Bahrami 	TK_OP_ID,			/* 42 - * */
28969112eddSAli Bahrami 	TK_OP_ID,			/* 43 - + */
29069112eddSAli Bahrami 	TK_OP_ID,			/* 44 - , */
29169112eddSAli Bahrami 	TK_DASH,			/* 45 - - */
29269112eddSAli Bahrami 	TK_OP_ID,			/* 46 - . */
29369112eddSAli Bahrami 	TK_OP_ID,			/* 47 - / */
29469112eddSAli Bahrami 	TK_OP_ID,			/* 48 - 0 */
29569112eddSAli Bahrami 	TK_OP_ID,			/* 49 - 1 */
29669112eddSAli Bahrami 	TK_OP_ID,			/* 50 - 2 */
29769112eddSAli Bahrami 	TK_OP_ID,			/* 51 - 3 */
29869112eddSAli Bahrami 	TK_OP_ID,			/* 52 - 4 */
29969112eddSAli Bahrami 	TK_OP_ID,			/* 53 - 5 */
30069112eddSAli Bahrami 	TK_OP_ID,			/* 54 - 6 */
30169112eddSAli Bahrami 	TK_OP_ID,			/* 55 - 7 */
30269112eddSAli Bahrami 	TK_OP_ID,			/* 56 - 8 */
30369112eddSAli Bahrami 	TK_OP_ID,			/* 57 - 9 */
30469112eddSAli Bahrami 	TK_COLON,			/* 58 - : */
30569112eddSAli Bahrami 	TK_SEMICOLON,			/* 59 - ; */
30669112eddSAli Bahrami 	TK_OP_ID,			/* 60 - < */
30769112eddSAli Bahrami 	TK_EQUAL,			/* 61 - = */
30869112eddSAli Bahrami 	TK_OP_ID,			/* 62 - > */
30969112eddSAli Bahrami 	TK_OP_ID,			/* 63 - ? */
31069112eddSAli Bahrami 	TK_ATSIGN,			/* 64 - @ */
31169112eddSAli Bahrami 	TK_OP_ID,			/* 65 - A */
31269112eddSAli Bahrami 	TK_OP_ID,			/* 66 - B */
31369112eddSAli Bahrami 	TK_OP_ID,			/* 67 - C */
31469112eddSAli Bahrami 	TK_OP_ID,			/* 68 - D */
31569112eddSAli Bahrami 	TK_OP_ID,			/* 69 - E */
31669112eddSAli Bahrami 	TK_OP_ID,			/* 70 - F */
31769112eddSAli Bahrami 	TK_OP_ID,			/* 71 - G */
31869112eddSAli Bahrami 	TK_OP_ID,			/* 72 - H */
31969112eddSAli Bahrami 	TK_OP_ID,			/* 73 - I */
32069112eddSAli Bahrami 	TK_OP_ID,			/* 74 - J */
32169112eddSAli Bahrami 	TK_OP_ID,			/* 75 - K */
32269112eddSAli Bahrami 	TK_OP_ID,			/* 76 - L */
32369112eddSAli Bahrami 	TK_OP_ID,			/* 77 - M */
32469112eddSAli Bahrami 	TK_OP_ID,			/* 78 - N */
32569112eddSAli Bahrami 	TK_OP_ID,			/* 79 - O */
32669112eddSAli Bahrami 	TK_OP_ID,			/* 80 - P */
32769112eddSAli Bahrami 	TK_OP_ID,			/* 81 - Q */
32869112eddSAli Bahrami 	TK_OP_ID,			/* 82 - R */
32969112eddSAli Bahrami 	TK_OP_ID,			/* 83 - S */
33069112eddSAli Bahrami 	TK_OP_ID,			/* 84 - T */
33169112eddSAli Bahrami 	TK_OP_ID,			/* 85 - U */
33269112eddSAli Bahrami 	TK_OP_ID,			/* 86 - V */
33369112eddSAli Bahrami 	TK_OP_ID,			/* 87 - W */
33469112eddSAli Bahrami 	TK_OP_ID,			/* 88 - X */
33569112eddSAli Bahrami 	TK_OP_ID,			/* 89 - Y */
33669112eddSAli Bahrami 	TK_OP_ID,			/* 90 - Z */
33769112eddSAli Bahrami 	TK_OP_ID,			/* 91 - [ */
33869112eddSAli Bahrami 	TK_OP_ID,			/* 92 - \ */
33969112eddSAli Bahrami 	TK_OP_ID,			/* 93 - ] */
34069112eddSAli Bahrami 	TK_OP_ID,			/* 94 - ^ */
34169112eddSAli Bahrami 	TK_OP_ID,			/* 95 - _ */
34269112eddSAli Bahrami 	TK_OP_ID,			/* 96 - ` */
34369112eddSAli Bahrami 	TK_OP_ID,			/* 97 - a */
34469112eddSAli Bahrami 	TK_OP_ID,			/* 98 - b */
34569112eddSAli Bahrami 	TK_OP_ID,			/* 99 - c */
34669112eddSAli Bahrami 	TK_OP_ID,			/* 100 - d */
34769112eddSAli Bahrami 	TK_OP_ID,			/* 101 - e */
34869112eddSAli Bahrami 	TK_OP_ID,			/* 102 - f */
34969112eddSAli Bahrami 	TK_OP_ID,			/* 103 - g */
35069112eddSAli Bahrami 	TK_OP_ID,			/* 104 - h */
35169112eddSAli Bahrami 	TK_OP_ID,			/* 105 - i */
35269112eddSAli Bahrami 	TK_OP_ID,			/* 106 - j */
35369112eddSAli Bahrami 	TK_OP_ID,			/* 107 - k */
35469112eddSAli Bahrami 	TK_OP_ID,			/* 108 - l */
35569112eddSAli Bahrami 	TK_OP_ID,			/* 109 - m */
35669112eddSAli Bahrami 	TK_OP_ID,			/* 110 - n */
35769112eddSAli Bahrami 	TK_OP_ID,			/* 111 - o */
35869112eddSAli Bahrami 	TK_OP_ID,			/* 112 - p */
35969112eddSAli Bahrami 	TK_OP_ID,			/* 113 - q */
36069112eddSAli Bahrami 	TK_OP_ID,			/* 114 - r */
36169112eddSAli Bahrami 	TK_OP_ID,			/* 115 - s */
36269112eddSAli Bahrami 	TK_OP_ID,			/* 116 - t */
36369112eddSAli Bahrami 	TK_OP_ID,			/* 117 - u */
36469112eddSAli Bahrami 	TK_OP_ID,			/* 118 - v */
36569112eddSAli Bahrami 	TK_OP_ID,			/* 119 - w */
36669112eddSAli Bahrami 	TK_OP_ID,			/* 120 - x */
36769112eddSAli Bahrami 	TK_OP_ID,			/* 121 - y */
36869112eddSAli Bahrami 	TK_OP_ID,			/* 122 - z */
36969112eddSAli Bahrami 	TK_LEFTBKT,			/* 123 - { */
37069112eddSAli Bahrami 	TK_PIPE,			/* 124 - | */
37169112eddSAli Bahrami 	TK_RIGHTBKT,			/* 125 - } */
37269112eddSAli Bahrami 	TK_OP_ID,			/* 126 - ~ */
37369112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 127 - DEL */
37469112eddSAli Bahrami };
37569112eddSAli Bahrami 
37669112eddSAli Bahrami /*
37769112eddSAli Bahrami  * Version 2 syntax dispatch table for ld_map_gettoken(). For each of the
37869112eddSAli Bahrami  * 7-bit ASCII characters, determine how the lexical analyzer should behave.
37969112eddSAli Bahrami  *
38069112eddSAli Bahrami  * This table must be kept in sync with tkid_attr[] below.
38169112eddSAli Bahrami  *
38269112eddSAli Bahrami  * Identifier Note:
38369112eddSAli Bahrami  * We define a letter as being one of the character [A-Z], [a-z], or [_%/.]
38469112eddSAli Bahrami  * A digit is the numbers [0-9], or [$-]. An unquoted identifier is defined
38569112eddSAli Bahrami  * as a letter, followed by any number of letters or digits. This is a loosened
38669112eddSAli Bahrami  * version of the C definition of an identifier. The extra characters not
38769112eddSAli Bahrami  * allowed by C are common in section names and/or file paths.
38869112eddSAli Bahrami  */
38969112eddSAli Bahrami static const mf_tokdisp_t gettok_dispatch_v2 = {
39069112eddSAli Bahrami 	TK_OP_EOF,			/* 0 - NUL */
39169112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 1 - SOH */
39269112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 2 - STX */
39369112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 3 - ETX */
39469112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 4 - EOT */
39569112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 5 - ENQ */
39669112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 6 - ACK */
39769112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 7 - BEL */
39869112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 8 - BS */
39969112eddSAli Bahrami 	TK_OP_WS,			/* 9 - HT */
40069112eddSAli Bahrami 	TK_OP_NL,			/* 10 - NL */
40169112eddSAli Bahrami 	TK_OP_WS,			/* 11 - VT */
40269112eddSAli Bahrami 	TK_OP_WS,			/* 12 - FF */
40369112eddSAli Bahrami 	TK_OP_WS,			/* 13 - CR */
40469112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 14 - SO */
40569112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 15 - SI */
40669112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 16 - DLE */
40769112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 17 - DC1 */
40869112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 18 - DC2 */
40969112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 19 - DC3 */
41069112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 20 - DC4 */
41169112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 21 - NAK */
41269112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 22 - SYN */
41369112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 23 - ETB */
41469112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 24 - CAN */
41569112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 25 - EM */
41669112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 26 - SUB */
41769112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 27 - ESC */
41869112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 28 - FS */
41969112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 29 - GS */
42069112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 30 - RS */
42169112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 31 - US */
42269112eddSAli Bahrami 	TK_OP_WS,			/* 32 - SP */
42369112eddSAli Bahrami 	TK_BANG,			/* 33 - ! */
42469112eddSAli Bahrami 	TK_OP_CQUOTE,			/* 34 - " */
42569112eddSAli Bahrami 	TK_OP_CMT,			/* 35 - # */
42669112eddSAli Bahrami 	TK_OP_CDIR,			/* 36 - $ */
42769112eddSAli Bahrami 	TK_OP_ID,			/* 37 - % */
42869112eddSAli Bahrami 	TK_OP_BADCHR,			/* 38 - & */
42969112eddSAli Bahrami 	TK_OP_SIMQUOTE,			/* 39 - ' */
43069112eddSAli Bahrami 	TK_OP_BADCHR,			/* 40 - ( */
43169112eddSAli Bahrami 	TK_OP_BADCHR,			/* 41 - ) */
43269112eddSAli Bahrami 	TK_STAR,			/* 42 - * */
43369112eddSAli Bahrami 	TK_OP_CEQUAL,			/* 43 - + */
43469112eddSAli Bahrami 	TK_OP_BADCHR,			/* 44 - , */
43569112eddSAli Bahrami 	TK_OP_CEQUAL,			/* 45 - - */
43669112eddSAli Bahrami 	TK_OP_ID,			/* 46 - . */
43769112eddSAli Bahrami 	TK_OP_ID,			/* 47 - / */
43869112eddSAli Bahrami 	TK_OP_NUM,			/* 48 - 0 */
43969112eddSAli Bahrami 	TK_OP_NUM,			/* 49 - 1 */
44069112eddSAli Bahrami 	TK_OP_NUM,			/* 50 - 2 */
44169112eddSAli Bahrami 	TK_OP_NUM,			/* 51 - 3 */
44269112eddSAli Bahrami 	TK_OP_NUM,			/* 52 - 4 */
44369112eddSAli Bahrami 	TK_OP_NUM,			/* 53 - 5 */
44469112eddSAli Bahrami 	TK_OP_NUM,			/* 54 - 6 */
44569112eddSAli Bahrami 	TK_OP_NUM,			/* 55 - 7 */
44669112eddSAli Bahrami 	TK_OP_NUM,			/* 56 - 8 */
44769112eddSAli Bahrami 	TK_OP_NUM,			/* 57 - 9 */
44869112eddSAli Bahrami 	TK_COLON,			/* 58 - : */
44969112eddSAli Bahrami 	TK_SEMICOLON,			/* 59 - ; */
45069112eddSAli Bahrami 	TK_OP_BADCHR,			/* 60 - < */
45169112eddSAli Bahrami 	TK_EQUAL,			/* 61 - = */
45269112eddSAli Bahrami 	TK_OP_BADCHR,			/* 62 - > */
45369112eddSAli Bahrami 	TK_OP_BADCHR,			/* 63 - ? */
45469112eddSAli Bahrami 	TK_OP_BADCHR,			/* 64 - @ */
45569112eddSAli Bahrami 	TK_OP_ID,			/* 65 - A */
45669112eddSAli Bahrami 	TK_OP_ID,			/* 66 - B */
45769112eddSAli Bahrami 	TK_OP_ID,			/* 67 - C */
45869112eddSAli Bahrami 	TK_OP_ID,			/* 68 - D */
45969112eddSAli Bahrami 	TK_OP_ID,			/* 69 - E */
46069112eddSAli Bahrami 	TK_OP_ID,			/* 70 - F */
46169112eddSAli Bahrami 	TK_OP_ID,			/* 71 - G */
46269112eddSAli Bahrami 	TK_OP_ID,			/* 72 - H */
46369112eddSAli Bahrami 	TK_OP_ID,			/* 73 - I */
46469112eddSAli Bahrami 	TK_OP_ID,			/* 74 - J */
46569112eddSAli Bahrami 	TK_OP_ID,			/* 75 - K */
46669112eddSAli Bahrami 	TK_OP_ID,			/* 76 - L */
46769112eddSAli Bahrami 	TK_OP_ID,			/* 77 - M */
46869112eddSAli Bahrami 	TK_OP_ID,			/* 78 - N */
46969112eddSAli Bahrami 	TK_OP_ID,			/* 79 - O */
47069112eddSAli Bahrami 	TK_OP_ID,			/* 80 - P */
47169112eddSAli Bahrami 	TK_OP_ID,			/* 81 - Q */
47269112eddSAli Bahrami 	TK_OP_ID,			/* 82 - R */
47369112eddSAli Bahrami 	TK_OP_ID,			/* 83 - S */
47469112eddSAli Bahrami 	TK_OP_ID,			/* 84 - T */
47569112eddSAli Bahrami 	TK_OP_ID,			/* 85 - U */
47669112eddSAli Bahrami 	TK_OP_ID,			/* 86 - V */
47769112eddSAli Bahrami 	TK_OP_ID,			/* 87 - W */
47869112eddSAli Bahrami 	TK_OP_ID,			/* 88 - X */
47969112eddSAli Bahrami 	TK_OP_ID,			/* 89 - Y */
48069112eddSAli Bahrami 	TK_OP_ID,			/* 90 - Z */
48169112eddSAli Bahrami 	TK_OP_BADCHR,			/* 91 - [ */
48269112eddSAli Bahrami 	TK_OP_BADCHR,			/* 92 - \ */
48369112eddSAli Bahrami 	TK_OP_BADCHR,			/* 93 - ] */
48469112eddSAli Bahrami 	TK_OP_BADCHR,			/* 94 - ^ */
48569112eddSAli Bahrami 	TK_OP_ID,			/* 95 - _ */
48669112eddSAli Bahrami 	TK_OP_BADCHR,			/* 96 - ` */
48769112eddSAli Bahrami 	TK_OP_ID,			/* 97 - a */
48869112eddSAli Bahrami 	TK_OP_ID,			/* 98 - b */
48969112eddSAli Bahrami 	TK_OP_ID,			/* 99 - c */
49069112eddSAli Bahrami 	TK_OP_ID,			/* 100 - d */
49169112eddSAli Bahrami 	TK_OP_ID,			/* 101 - e */
49269112eddSAli Bahrami 	TK_OP_ID,			/* 102 - f */
49369112eddSAli Bahrami 	TK_OP_ID,			/* 103 - g */
49469112eddSAli Bahrami 	TK_OP_ID,			/* 104 - h */
49569112eddSAli Bahrami 	TK_OP_ID,			/* 105 - i */
49669112eddSAli Bahrami 	TK_OP_ID,			/* 106 - j */
49769112eddSAli Bahrami 	TK_OP_ID,			/* 107 - k */
49869112eddSAli Bahrami 	TK_OP_ID,			/* 108 - l */
49969112eddSAli Bahrami 	TK_OP_ID,			/* 109 - m */
50069112eddSAli Bahrami 	TK_OP_ID,			/* 110 - n */
50169112eddSAli Bahrami 	TK_OP_ID,			/* 111 - o */
50269112eddSAli Bahrami 	TK_OP_ID,			/* 112 - p */
50369112eddSAli Bahrami 	TK_OP_ID,			/* 113 - q */
50469112eddSAli Bahrami 	TK_OP_ID,			/* 114 - r */
50569112eddSAli Bahrami 	TK_OP_ID,			/* 115 - s */
50669112eddSAli Bahrami 	TK_OP_ID,			/* 116 - t */
50769112eddSAli Bahrami 	TK_OP_ID,			/* 117 - u */
50869112eddSAli Bahrami 	TK_OP_ID,			/* 118 - v */
50969112eddSAli Bahrami 	TK_OP_ID,			/* 119 - w */
51069112eddSAli Bahrami 	TK_OP_ID,			/* 120 - x */
51169112eddSAli Bahrami 	TK_OP_ID,			/* 121 - y */
51269112eddSAli Bahrami 	TK_OP_ID,			/* 122 - z */
51369112eddSAli Bahrami 	TK_LEFTBKT,			/* 123 - { */
51469112eddSAli Bahrami 	TK_OP_BADCHR,			/* 124 - | */
51569112eddSAli Bahrami 	TK_RIGHTBKT,			/* 125 - } */
51669112eddSAli Bahrami 	TK_OP_BADCHR,			/* 126 - ~ */
51769112eddSAli Bahrami 	TK_OP_ILLCHR,			/* 127 - DEL */
51869112eddSAli Bahrami };
51969112eddSAli Bahrami 
52069112eddSAli Bahrami 
52169112eddSAli Bahrami /*
52269112eddSAli Bahrami  * Table used to identify unquoted identifiers. Each element of this array
52369112eddSAli Bahrami  * contains a bitmask indicating whether the character it represents starts,
52469112eddSAli Bahrami  * or continues an identifier, for each supported mapfile syntax version.
52569112eddSAli Bahrami  */
52669112eddSAli Bahrami static const char tkid_attr[128] = {
52769112eddSAli Bahrami 	0,					/* 0 - NUL */
52869112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 1 - SOH */
52969112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 2 - STX */
53069112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 3 - ETX */
53169112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 4 - EOT */
53269112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 5 - ENQ */
53369112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 6 - ACK */
53469112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 7 - BEL */
53569112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 8 - BS */
53669112eddSAli Bahrami 	0,					/* 9 - HT */
53769112eddSAli Bahrami 	0,					/* 10 - NL */
53869112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 11 - VT */
53969112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 12 - FF */
54069112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 13 - CR */
54169112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 14 - SO */
54269112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 15 - SI */
54369112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 16 - DLE */
54469112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 17 - DC1 */
54569112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 18 - DC2 */
54669112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 19 - DC3 */
54769112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 20 - DC4 */
54869112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 21 - NAK */
54969112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 22 - SYN */
55069112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 23 - ETB */
55169112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 24 - CAN */
55269112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 25 - EM */
55369112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 26 - SUB */
55469112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 27 - ESC */
55569112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 28 - FS */
55669112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 29 - GS */
55769112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 30 - RS */
55869112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 31 - US */
55969112eddSAli Bahrami 	0,					/* 32 - SP */
56069112eddSAli Bahrami 	TKID_ATTR(1),				/* 33 - ! */
56169112eddSAli Bahrami 	0,					/* 34 - " */
56269112eddSAli Bahrami 	0,					/* 35 - # */
56369112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 36 - $ */
56469112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 37 - % */
56569112eddSAli Bahrami 	TKID_ATTR(1),				/* 38 - & */
56669112eddSAli Bahrami 	TKID_ATTR(1),				/* 39 - ' */
56769112eddSAli Bahrami 	TKID_ATTR(1),				/* 40 - ( */
56869112eddSAli Bahrami 	TKID_ATTR(1),				/* 41 - ) */
56969112eddSAli Bahrami 	TKID_ATTR(1),				/* 42 - * */
57069112eddSAli Bahrami 	TKID_ATTR(1),				/* 43 - + */
57169112eddSAli Bahrami 	TKID_ATTR(1),				/* 44 - , */
57269112eddSAli Bahrami 	TKID_ATTR_CONT(1) | TKID_ATTR_CONT(2),	/* 45 - - */
57369112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 46 - . */
57469112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 47 - / */
57569112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 48 - 0 */
57669112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 49 - 1 */
57769112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 50 - 2 */
57869112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 51 - 3 */
57969112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 52 - 4 */
58069112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 53 - 5 */
58169112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 54 - 6 */
58269112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 55 - 7 */
58369112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 56 - 8 */
58469112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 57 - 9 */
58569112eddSAli Bahrami 	0,					/* 58 - : */
58669112eddSAli Bahrami 	0,					/* 59 - ; */
58769112eddSAli Bahrami 	TKID_ATTR(1),				/* 60 - < */
58869112eddSAli Bahrami 	0,					/* 61 - = */
58969112eddSAli Bahrami 	TKID_ATTR(1),				/* 62 - > */
59069112eddSAli Bahrami 	TKID_ATTR(1),				/* 63 - ? */
59169112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 64 - @ */
59269112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 65 - A */
59369112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 66 - B */
59469112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 67 - C */
59569112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 68 - D */
59669112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 69 - E */
59769112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 70 - F */
59869112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 71 - G */
59969112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 72 - H */
60069112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 73 - I */
60169112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 74 - J */
60269112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 75 - K */
60369112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 76 - L */
60469112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 77 - M */
60569112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 78 - N */
60669112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 79 - O */
60769112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 80 - P */
60869112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 81 - Q */
60969112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 82 - R */
61069112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 83 - S */
61169112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 84 - T */
61269112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 85 - U */
61369112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 86 - V */
61469112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 87 - W */
61569112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 88 - X */
61669112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 89 - Y */
61769112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 90 - Z */
61869112eddSAli Bahrami 	TKID_ATTR(1),				/* 91 - [ */
61969112eddSAli Bahrami 	TKID_ATTR(1),				/* 92 - \ */
62069112eddSAli Bahrami 	TKID_ATTR(1),				/* 93 - ] */
62169112eddSAli Bahrami 	TKID_ATTR(1),				/* 94 - ^ */
62269112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 95 - _ */
62369112eddSAli Bahrami 	TKID_ATTR(1),				/* 96 - ` */
62469112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 97 - a */
62569112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 98 - b */
62669112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 99 - c */
62769112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 100 - d */
62869112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 101 - e */
62969112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 102 - f */
63069112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 103 - g */
63169112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 104 - h */
63269112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 105 - i */
63369112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 106 - j */
63469112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 107 - k */
63569112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 108 - l */
63669112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 109 - m */
63769112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 110 - n */
63869112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 111 - o */
63969112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 112 - p */
64069112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 113 - q */
64169112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 114 - r */
64269112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 115 - s */
64369112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 116 - t */
64469112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 117 - u */
64569112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 118 - v */
64669112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 119 - w */
64769112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 120 - x */
64869112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 121 - y */
64969112eddSAli Bahrami 	TKID_ATTR(1) | TKID_ATTR(2),		/* 122 - z */
65069112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 123 - { */
65169112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 124 - | */
65269112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 125 - } */
65369112eddSAli Bahrami 	TKID_ATTR(1),				/* 126 - ~ */
65469112eddSAli Bahrami 	TKID_ATTR_CONT(1),			/* 127 - DEL */
65569112eddSAli Bahrami };
65669112eddSAli Bahrami 
65769112eddSAli Bahrami 
65869112eddSAli Bahrami /*
65969112eddSAli Bahrami  * Advance the given string pointer to the next newline character,
66069112eddSAli Bahrami  * or the terminating NULL if there is none.
66169112eddSAli Bahrami  */
66269112eddSAli Bahrami inline static void
66369112eddSAli Bahrami advance_to_eol(char **str)
66469112eddSAli Bahrami {
66569112eddSAli Bahrami 	char	*s = *str;
66669112eddSAli Bahrami 
66769112eddSAli Bahrami 	while ((*s != '\n') && (*s != '\0'))
66869112eddSAli Bahrami 		s++;
66969112eddSAli Bahrami 	*str = s;
67069112eddSAli Bahrami }
67169112eddSAli Bahrami 
67269112eddSAli Bahrami /*
67369112eddSAli Bahrami  * Insert a NULL patch at the given address
67469112eddSAli Bahrami  */
67569112eddSAli Bahrami inline static void
67669112eddSAli Bahrami null_patch_set(char *str, ld_map_npatch_t *np)
67769112eddSAli Bahrami {
67869112eddSAli Bahrami 	np->np_ptr = str;
67969112eddSAli Bahrami 	np->np_ch = *str;
68069112eddSAli Bahrami 	*str = '\0';
68169112eddSAli Bahrami }
68269112eddSAli Bahrami 
68369112eddSAli Bahrami /*
68469112eddSAli Bahrami  * Undo a NULL patch
68569112eddSAli Bahrami  */
68669112eddSAli Bahrami inline static void
68769112eddSAli Bahrami null_patch_undo(ld_map_npatch_t *np)
68869112eddSAli Bahrami {
68969112eddSAli Bahrami 	*np->np_ptr = np->np_ch;
69069112eddSAli Bahrami }
69169112eddSAli Bahrami 
69269112eddSAli Bahrami /*
69369112eddSAli Bahrami  * Insert a NULL patch at the end of the line containing str.
69469112eddSAli Bahrami  */
69569112eddSAli Bahrami static void
69669112eddSAli Bahrami null_patch_eol(char *str, ld_map_npatch_t *np)
69769112eddSAli Bahrami {
69869112eddSAli Bahrami 	advance_to_eol(&str);
69969112eddSAli Bahrami 	null_patch_set(str, np);
70069112eddSAli Bahrami }
70169112eddSAli Bahrami 
70269112eddSAli Bahrami /*
70369112eddSAli Bahrami  * Locate the end of an unquoted identifier.
70469112eddSAli Bahrami  *
70569112eddSAli Bahrami  * entry:
70669112eddSAli Bahrami  *	mf - Mapfile descriptor, positioned to first character
70769112eddSAli Bahrami  *		of identifier.
70869112eddSAli Bahrami  *
70969112eddSAli Bahrami  * exit:
71069112eddSAli Bahrami  *	If the item pointed at by mf is not an identifier, returns NULL.
71169112eddSAli Bahrami  *	Otherwise, returns pointer to character after the last character
71269112eddSAli Bahrami  *	of the identifier.
71369112eddSAli Bahrami  */
71469112eddSAli Bahrami inline static char *
71569112eddSAli Bahrami ident_delimit(Mapfile *mf)
71669112eddSAli Bahrami {
71769112eddSAli Bahrami 	char		*str = mf->mf_next;
71869112eddSAli Bahrami 	ld_map_npatch_t	np;
71969112eddSAli Bahrami 	int		c = *str++;
72069112eddSAli Bahrami 
72169112eddSAli Bahrami 	/* If not a valid start character, report the error */
72269112eddSAli Bahrami 	if ((c & 0x80) || !(tkid_attr[c] & mf->mf_tkid_start)) {
72369112eddSAli Bahrami 		null_patch_set(str, &np);
72469112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), str);
72569112eddSAli Bahrami 		null_patch_undo(&np);
72669112eddSAli Bahrami 		return (NULL);
72769112eddSAli Bahrami 	}
72869112eddSAli Bahrami 
72969112eddSAli Bahrami 	/* Keep going until we hit a non-continuing character */
73069112eddSAli Bahrami 	for (c = *str; !(c & 0x80) && (tkid_attr[c] & mf->mf_tkid_cont);
73169112eddSAli Bahrami 	    c = *++str)
73269112eddSAli Bahrami 		;
73369112eddSAli Bahrami 
73469112eddSAli Bahrami 	return (str);
73569112eddSAli Bahrami }
73669112eddSAli Bahrami 
73769112eddSAli Bahrami /*
73869112eddSAli Bahrami  * Allocate memory for a stack.
73969112eddSAli Bahrami  *
74069112eddSAli Bahrami  * entry:
74169112eddSAli Bahrami  *	stack - Pointer to stack for which memory is required, cast
74269112eddSAli Bahrami  *		to the generic stack type.
74369112eddSAli Bahrami  *	n_default - Size to use for initial allocation.
74469112eddSAli Bahrami  *	elt_size - sizeof(elt), where elt is the actual stack data type.
74569112eddSAli Bahrami  *
74669112eddSAli Bahrami  * exit:
74769112eddSAli Bahrami  *	Returns (1) on success. On error (memory allocation), a message
74869112eddSAli Bahrami  *	is printed and False (0) is returned.
74969112eddSAli Bahrami  *
75069112eddSAli Bahrami  * note:
75169112eddSAli Bahrami  *	The caller casts the pointer to their actual datatype-specific stack
75269112eddSAli Bahrami  *	to be a (generic_stack_t *). The C language will give all stack
75369112eddSAli Bahrami  *	structs the same size and layout as long as the underlying platform
75469112eddSAli Bahrami  *	uses a single integral type for pointers. Hence, this cast is safe,
75569112eddSAli Bahrami  *	and lets a generic routine modify data-specific types without being
75669112eddSAli Bahrami  *	aware of those types.
75769112eddSAli Bahrami  */
75869112eddSAli Bahrami static Boolean
75969112eddSAli Bahrami stack_resize(generic_stack_t *stack, size_t n_default, size_t elt_size)
76069112eddSAli Bahrami {
76169112eddSAli Bahrami 	size_t	new_n_alloc;
76269112eddSAli Bahrami 	void	*newaddr;
76369112eddSAli Bahrami 
76469112eddSAli Bahrami 	/* Use initial size first, and double the allocation on each call */
76569112eddSAli Bahrami 	new_n_alloc = (stack->stk_n_alloc == 0) ?
76669112eddSAli Bahrami 	    n_default : (stack->stk_n_alloc * 2);
76769112eddSAli Bahrami 
76869112eddSAli Bahrami 	newaddr = libld_realloc(stack->stk_s, new_n_alloc * elt_size);
76969112eddSAli Bahrami 	if (newaddr == NULL)
77069112eddSAli Bahrami 		return (FALSE);
77169112eddSAli Bahrami 
77269112eddSAli Bahrami 	stack->stk_s = newaddr;
77369112eddSAli Bahrami 	stack->stk_n_alloc = new_n_alloc;
77469112eddSAli Bahrami 	return (TRUE);
77569112eddSAli Bahrami }
77669112eddSAli Bahrami 
77769112eddSAli Bahrami /*
77869112eddSAli Bahrami  * AVL comparison function for cexp_id_node_t items.
77969112eddSAli Bahrami  *
78069112eddSAli Bahrami  * entry:
78169112eddSAli Bahrami  *      n1, n2 - pointers to nodes to be compared
78269112eddSAli Bahrami  *
78369112eddSAli Bahrami  * exit:
78469112eddSAli Bahrami  *      Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
78569112eddSAli Bahrami  */
78669112eddSAli Bahrami static int
78769112eddSAli Bahrami cexp_ident_cmp(const void *n1, const void *n2)
78869112eddSAli Bahrami {
78969112eddSAli Bahrami 	int	rc;
79069112eddSAli Bahrami 
79169112eddSAli Bahrami 	rc = strcmp(((cexp_id_node_t *)n1)->ceid_name,
79269112eddSAli Bahrami 	    ((cexp_id_node_t *)n2)->ceid_name);
79369112eddSAli Bahrami 
79469112eddSAli Bahrami 	if (rc > 0)
79569112eddSAli Bahrami 		return (1);
79669112eddSAli Bahrami 	if (rc < 0)
79769112eddSAli Bahrami 		return (-1);
79869112eddSAli Bahrami 	return (0);
79969112eddSAli Bahrami }
80069112eddSAli Bahrami 
80169112eddSAli Bahrami 
80269112eddSAli Bahrami /*
80369112eddSAli Bahrami  * Returns True (1) if name is in the conditional expression identifier
80469112eddSAli Bahrami  * AVL tree, and False (0) otherwise.
80569112eddSAli Bahrami  */
80669112eddSAli Bahrami static int
80769112eddSAli Bahrami cexp_ident_test(const char *name)
80869112eddSAli Bahrami {
80969112eddSAli Bahrami 	cexp_id_node_t	node;
81069112eddSAli Bahrami 
81169112eddSAli Bahrami 	node.ceid_name = name;
81269112eddSAli Bahrami 	return (avl_find(lms.lms_cexp_id, &node, 0) != NULL);
81369112eddSAli Bahrami }
81469112eddSAli Bahrami 
81569112eddSAli Bahrami /*
81669112eddSAli Bahrami  * Add a new boolean identifier to the conditional expression identifier
81769112eddSAli Bahrami  * AVL tree.
81869112eddSAli Bahrami  *
81969112eddSAli Bahrami  * entry:
82069112eddSAli Bahrami  *	mf - If non-NULL, the mapfile descriptor for the mapfile
82169112eddSAli Bahrami  *		containing the $add directive. NULL if this is an
82269112eddSAli Bahrami  *		initialization call.
82369112eddSAli Bahrami  *	name - Name of identifier. Must point at stable storage that will
82469112eddSAli Bahrami  *		not be moved or modified by the caller following this call.
82569112eddSAli Bahrami  *
82669112eddSAli Bahrami  * exit:
82769112eddSAli Bahrami  *	On success, True (1) is returned and name has been entered.
82869112eddSAli Bahrami  *	On failure, False (0) is returned and an error has been printed.
82969112eddSAli Bahrami  */
83069112eddSAli Bahrami static int
83169112eddSAli Bahrami cexp_ident_add(Mapfile *mf, const char *name)
83269112eddSAli Bahrami {
83369112eddSAli Bahrami 	cexp_id_node_t	*node;
83469112eddSAli Bahrami 
83569112eddSAli Bahrami 	if (mf != NULL) {
83669112eddSAli Bahrami 		DBG_CALL(Dbg_map_cexp_id(mf->mf_ofl->ofl_lml, 1,
83769112eddSAli Bahrami 		    mf->mf_name, mf->mf_lineno, name));
83869112eddSAli Bahrami 
83969112eddSAli Bahrami 		/* If is already known, don't do it again */
84069112eddSAli Bahrami 		if (cexp_ident_test(name))
84169112eddSAli Bahrami 			return (1);
84269112eddSAli Bahrami 	}
84369112eddSAli Bahrami 
84469112eddSAli Bahrami 	if ((node = libld_calloc(sizeof (*node), 1)) == NULL)
84569112eddSAli Bahrami 		return (0);
84669112eddSAli Bahrami 	node->ceid_name = name;
84769112eddSAli Bahrami 	avl_add(lms.lms_cexp_id, node);
84869112eddSAli Bahrami 	return (1);
84969112eddSAli Bahrami }
85069112eddSAli Bahrami 
85169112eddSAli Bahrami /*
85269112eddSAli Bahrami  * Remove a boolean identifier from the conditional expression identifier
85369112eddSAli Bahrami  * AVL tree.
85469112eddSAli Bahrami  *
85569112eddSAli Bahrami  * entry:
85669112eddSAli Bahrami  *	mf - Mapfile descriptor
85769112eddSAli Bahrami  *	name - Name of identifier.
85869112eddSAli Bahrami  *
85969112eddSAli Bahrami  * exit:
86069112eddSAli Bahrami  *	If the name was in the tree, it has been removed. If not,
86169112eddSAli Bahrami  *	then this routine quietly returns.
86269112eddSAli Bahrami  */
86369112eddSAli Bahrami static void
86469112eddSAli Bahrami cexp_ident_clear(Mapfile *mf, const char *name)
86569112eddSAli Bahrami {
86669112eddSAli Bahrami 	cexp_id_node_t	node;
86769112eddSAli Bahrami 	cexp_id_node_t	*real_node;
86869112eddSAli Bahrami 
86969112eddSAli Bahrami 	DBG_CALL(Dbg_map_cexp_id(mf->mf_ofl->ofl_lml, 0,
87069112eddSAli Bahrami 	    mf->mf_name, mf->mf_lineno, name));
87169112eddSAli Bahrami 
87269112eddSAli Bahrami 	node.ceid_name = name;
87369112eddSAli Bahrami 	real_node = avl_find(lms.lms_cexp_id, &node, 0);
87469112eddSAli Bahrami 	if (real_node != NULL)
87569112eddSAli Bahrami 		avl_remove(lms.lms_cexp_id, real_node);
87669112eddSAli Bahrami }
87769112eddSAli Bahrami 
87869112eddSAli Bahrami /*
87969112eddSAli Bahrami  * Initialize the AVL tree that holds the names of the currently defined
88069112eddSAli Bahrami  * boolean identifiers for conditional expressions ($if/$elif).
88169112eddSAli Bahrami  *
88269112eddSAli Bahrami  * entry:
88369112eddSAli Bahrami  *	ofl - Output file descriptor
88469112eddSAli Bahrami  *
88569112eddSAli Bahrami  * exit:
88669112eddSAli Bahrami  *	On success, TRUE (1) is returned and lms.lms_cexp_id is ready for use.
88769112eddSAli Bahrami  *	On failure, FALSE (0) is returned.
88869112eddSAli Bahrami  */
88969112eddSAli Bahrami static Boolean
89069112eddSAli Bahrami cexp_ident_init(void)
89169112eddSAli Bahrami {
89269112eddSAli Bahrami 	/* If already done, use it */
89369112eddSAli Bahrami 	if (lms.lms_cexp_id != NULL)
89469112eddSAli Bahrami 		return (TRUE);
89569112eddSAli Bahrami 
89669112eddSAli Bahrami 	lms.lms_cexp_id = libld_calloc(sizeof (*lms.lms_cexp_id), 1);
89769112eddSAli Bahrami 	if (lms.lms_cexp_id == NULL)
89869112eddSAli Bahrami 		return (FALSE);
89969112eddSAli Bahrami 	avl_create(lms.lms_cexp_id, cexp_ident_cmp, sizeof (cexp_id_node_t),
90069112eddSAli Bahrami 	    SGSOFFSETOF(cexp_id_node_t, ceid_avlnode));
90169112eddSAli Bahrami 
90269112eddSAli Bahrami 
90369112eddSAli Bahrami 	/* ELFCLASS */
90469112eddSAli Bahrami 	if (cexp_ident_add(NULL, (ld_targ.t_m.m_class == ELFCLASS32) ?
90569112eddSAli Bahrami 	    MSG_ORIG(MSG_STR_UELF32) : MSG_ORIG(MSG_STR_UELF64)) == 0)
90669112eddSAli Bahrami 		return (FALSE);
90769112eddSAli Bahrami 
90869112eddSAli Bahrami 	/* Machine */
90969112eddSAli Bahrami 	switch (ld_targ.t_m.m_mach) {
91069112eddSAli Bahrami 	case EM_386:
91169112eddSAli Bahrami 	case EM_AMD64:
91269112eddSAli Bahrami 		if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_UX86)) == 0)
91369112eddSAli Bahrami 			return (FALSE);
91469112eddSAli Bahrami 		break;
91569112eddSAli Bahrami 
91669112eddSAli Bahrami 	case EM_SPARC:
91769112eddSAli Bahrami 	case EM_SPARCV9:
91869112eddSAli Bahrami 		if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_USPARC)) == 0)
91969112eddSAli Bahrami 			return (FALSE);
92069112eddSAli Bahrami 		break;
92169112eddSAli Bahrami 	}
92269112eddSAli Bahrami 
92369112eddSAli Bahrami 	/* true is always defined */
92469112eddSAli Bahrami 	if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_TRUE)) == 0)
92569112eddSAli Bahrami 		return (FALSE);
92669112eddSAli Bahrami 
92769112eddSAli Bahrami 	return (TRUE);
92869112eddSAli Bahrami }
92969112eddSAli Bahrami 
93069112eddSAli Bahrami /*
93169112eddSAli Bahrami  * Validate the string starting at mf->mf_next as being a
93269112eddSAli Bahrami  * boolean conditional expression identifier.
93369112eddSAli Bahrami  *
93469112eddSAli Bahrami  * entry:
93569112eddSAli Bahrami  *	mf - Mapfile descriptor
93669112eddSAli Bahrami  *	len - NULL, or address of variable to receive strlen() of identifier
93769112eddSAli Bahrami  *	directive - If (len == NULL), string giving name of directive being
93869112eddSAli Bahrami  *		processed. Ignored if (len != NULL).
93969112eddSAli Bahrami  *
94069112eddSAli Bahrami  * exit:
94169112eddSAli Bahrami  *	On success:
94269112eddSAli Bahrami  *	-	If len is NULL, a NULL is inserted following the final
94369112eddSAli Bahrami  *		character of the identifier, and the remainder of the string
94469112eddSAli Bahrami  *		is tested to ensure it is empty, or only contains whitespace.
94569112eddSAli Bahrami  *	-	If len is non-NULL, *len is set to the number of characters
94669112eddSAli Bahrami  *		in the identifier, and the rest of the string is not modified.
94769112eddSAli Bahrami  *	-	TRUE (1) is returned
94869112eddSAli Bahrami  *
94969112eddSAli Bahrami  *	On failure, returns FALSE (0).
95069112eddSAli Bahrami  */
95169112eddSAli Bahrami static Boolean
95269112eddSAli Bahrami cexp_ident_validate(Mapfile *mf, size_t *len, const char *directive)
95369112eddSAli Bahrami {
95469112eddSAli Bahrami 	char	*tail;
95569112eddSAli Bahrami 
95669112eddSAli Bahrami 	if ((tail = ident_delimit(mf)) == NULL)
95769112eddSAli Bahrami 		return (FALSE);
95869112eddSAli Bahrami 
95969112eddSAli Bahrami 	/*
96069112eddSAli Bahrami 	 * If len is non-NULL, we simple count the number of characters
96169112eddSAli Bahrami 	 * consumed by the identifier and are done. If len is NULL, then
96269112eddSAli Bahrami 	 * ensure there's nothing left but whitespace, and NULL terminate
96369112eddSAli Bahrami 	 * the identifier to remove it.
96469112eddSAli Bahrami 	 */
96569112eddSAli Bahrami 	if (len != NULL) {
96669112eddSAli Bahrami 		*len = tail - mf->mf_next;
96769112eddSAli Bahrami 	} else if (*tail != '\0') {
96869112eddSAli Bahrami 		*tail++ = '\0';
96969112eddSAli Bahrami 		while (isspace(*tail))
97069112eddSAli Bahrami 			tail++;
97169112eddSAli Bahrami 		if (*tail != '\0') {
97269112eddSAli Bahrami 			mf_fatal(mf, MSG_INTL(MSG_MAP_BADEXTRA), directive);
97369112eddSAli Bahrami 			return (FALSE);
97469112eddSAli Bahrami 		}
97569112eddSAli Bahrami 	}
97669112eddSAli Bahrami 
97769112eddSAli Bahrami 	return (TRUE);
97869112eddSAli Bahrami }
97969112eddSAli Bahrami 
98069112eddSAli Bahrami /*
98169112eddSAli Bahrami  * Push a new operator onto the conditional expression operator stack.
98269112eddSAli Bahrami  *
98369112eddSAli Bahrami  * entry:
98469112eddSAli Bahrami  *	mf - Mapfile descriptor
98569112eddSAli Bahrami  *	op - Operator to push
98669112eddSAli Bahrami  *
98769112eddSAli Bahrami  * exit:
98869112eddSAli Bahrami  *	On success, TRUE (1) is returned, otherwise FALSE (0).
98969112eddSAli Bahrami  */
99069112eddSAli Bahrami static Boolean
99169112eddSAli Bahrami cexp_push_op(cexp_op_t op)
99269112eddSAli Bahrami {
99369112eddSAli Bahrami 	if (STACK_RESERVE(lms.lms_cexp_op_stack, CEXP_OP_STACK_INIT) == 0)
99469112eddSAli Bahrami 		return (FALSE);
99569112eddSAli Bahrami 
99669112eddSAli Bahrami 	STACK_PUSH(lms.lms_cexp_op_stack) = op;
99769112eddSAli Bahrami 	return (TRUE);
99869112eddSAli Bahrami }
99969112eddSAli Bahrami 
100069112eddSAli Bahrami /*
100169112eddSAli Bahrami  * Evaluate the basic operator (non-paren) at the top of lms.lms_cexp_op_stack,
100269112eddSAli Bahrami  * and push the results on lms.lms_cexp_val_stack.
100369112eddSAli Bahrami  *
100469112eddSAli Bahrami  * exit:
100569112eddSAli Bahrami  *	On success, returns TRUE (1). On error, FALSE (0) is returned,
100669112eddSAli Bahrami  *	and the caller is responsible for issuing the error.
100769112eddSAli Bahrami  */
100869112eddSAli Bahrami static Boolean
100969112eddSAli Bahrami cexp_eval_op(void)
101069112eddSAli Bahrami {
101169112eddSAli Bahrami 	cexp_op_t	op;
101269112eddSAli Bahrami 	uchar_t		val;
101369112eddSAli Bahrami 
101469112eddSAli Bahrami 	op = STACK_POP(lms.lms_cexp_op_stack);
101569112eddSAli Bahrami 	switch (op) {
101669112eddSAli Bahrami 	case CEXP_OP_AND:
101769112eddSAli Bahrami 		if (lms.lms_cexp_val_stack.stk_n < 2)
101869112eddSAli Bahrami 			return (FALSE);
101969112eddSAli Bahrami 		val = STACK_POP(lms.lms_cexp_val_stack);
102069112eddSAli Bahrami 		STACK_TOP(lms.lms_cexp_val_stack) = val &&
102169112eddSAli Bahrami 		    STACK_TOP(lms.lms_cexp_val_stack);
102269112eddSAli Bahrami 		break;
102369112eddSAli Bahrami 
102469112eddSAli Bahrami 	case CEXP_OP_OR:
102569112eddSAli Bahrami 		if (lms.lms_cexp_val_stack.stk_n < 2)
102669112eddSAli Bahrami 			return (FALSE);
102769112eddSAli Bahrami 		val = STACK_POP(lms.lms_cexp_val_stack);
102869112eddSAli Bahrami 		STACK_TOP(lms.lms_cexp_val_stack) = val ||
102969112eddSAli Bahrami 		    STACK_TOP(lms.lms_cexp_val_stack);
103069112eddSAli Bahrami 		break;
103169112eddSAli Bahrami 
103269112eddSAli Bahrami 	case CEXP_OP_NEG:
103369112eddSAli Bahrami 		if (lms.lms_cexp_val_stack.stk_n < 1)
103469112eddSAli Bahrami 			return (FALSE);
103569112eddSAli Bahrami 		STACK_TOP(lms.lms_cexp_val_stack) =
103669112eddSAli Bahrami 		    !STACK_TOP(lms.lms_cexp_val_stack);
103769112eddSAli Bahrami 		break;
103869112eddSAli Bahrami 	default:
103969112eddSAli Bahrami 		return (FALSE);
104069112eddSAli Bahrami 	}
104169112eddSAli Bahrami 
104269112eddSAli Bahrami 	return (TRUE);
104369112eddSAli Bahrami }
104469112eddSAli Bahrami 
104569112eddSAli Bahrami /*
104669112eddSAli Bahrami  * Evaluate an expression for a $if/$elif control directive.
104769112eddSAli Bahrami  *
104869112eddSAli Bahrami  * entry:
104969112eddSAli Bahrami  *	mf - Mapfile descriptor for NULL terminated string
105069112eddSAli Bahrami  *		containing the expression.
105169112eddSAli Bahrami  *
105269112eddSAli Bahrami  * exit:
105369112eddSAli Bahrami  *	The contents of str are modified by this routine.
105469112eddSAli Bahrami  *	One of the following values are returned:
105569112eddSAli Bahrami  *		-1	Syntax error encountered (an error is printed)
105669112eddSAli Bahrami  *		0	The expression evaluates to False
105769112eddSAli Bahrami  *		1	The expression evaluates to True.
105869112eddSAli Bahrami  *
105969112eddSAli Bahrami  * note:
106069112eddSAli Bahrami  *	A simplified version of Dijkstra's Shunting Yard algorithm is used
106169112eddSAli Bahrami  *	to convert this syntax into postfix form and then evaluate it.
106269112eddSAli Bahrami  *	Our version has no functions and a tiny set of operators.
106369112eddSAli Bahrami  *
106469112eddSAli Bahrami  *	The expressions consist of boolean identifiers, which can be
106569112eddSAli Bahrami  *	combined using the following operators, listed from highest
106669112eddSAli Bahrami  *	precedence to least:
106769112eddSAli Bahrami  *
106869112eddSAli Bahrami  *		Operator	Meaning
106969112eddSAli Bahrami  *		-------------------------------------------------
107069112eddSAli Bahrami  *		(expr)		sub-expression, non-associative
107169112eddSAli Bahrami  *		!		logical negation, prefix, left associative
107269112eddSAli Bahrami  *		&&  ||		logical and/or, binary, left associative
107369112eddSAli Bahrami  *
107469112eddSAli Bahrami  *	The operands manipulated by these operators are names, consisting of
107569112eddSAli Bahrami  *	a sequence of letters and digits. The first character must be a letter.
107669112eddSAli Bahrami  *	Underscore (_) and period (.) are also considered to be characters.
107769112eddSAli Bahrami  *	An operand is considered True if it is found in our set of known
107869112eddSAli Bahrami  *	names (lms.lms_cexp_id), and False otherwise.
107969112eddSAli Bahrami  *
108069112eddSAli Bahrami  *	The Shunting Yard algorithm works using two stacks, one for operators,
108169112eddSAli Bahrami  *	and a second for operands. The infix input expression is tokenized from
108269112eddSAli Bahrami  *	left to right and processed in order. Issues of associativity and
108369112eddSAli Bahrami  *	precedence are managed by reducing (poping and evaluating) items with
108469112eddSAli Bahrami  *	higer precedence before pushing additional tokens with lower precedence.
108569112eddSAli Bahrami  */
108669112eddSAli Bahrami static int
108769112eddSAli Bahrami cexp_eval_expr(Mapfile *mf)
108869112eddSAli Bahrami {
108969112eddSAli Bahrami 	char		*ident;
109069112eddSAli Bahrami 	size_t		len;
109169112eddSAli Bahrami 	cexp_op_t	new_op = CEXP_OP_AND;	/* to catch binop at start */
109269112eddSAli Bahrami 	ld_map_npatch_t	np;
109369112eddSAli Bahrami 	char		*str = mf->mf_next;
109469112eddSAli Bahrami 
109569112eddSAli Bahrami 	STACK_RESET(lms.lms_cexp_op_stack);
109669112eddSAli Bahrami 	STACK_RESET(lms.lms_cexp_val_stack);
109769112eddSAli Bahrami 
109869112eddSAli Bahrami 	for (; *str; str++) {
109969112eddSAli Bahrami 
110069112eddSAli Bahrami 		/* Skip whitespace */
110169112eddSAli Bahrami 		while (isspace(*str))
110269112eddSAli Bahrami 			str++;
110369112eddSAli Bahrami 		if (!*str)
110469112eddSAli Bahrami 			break;
110569112eddSAli Bahrami 
110669112eddSAli Bahrami 		switch (*str) {
110769112eddSAli Bahrami 		case '&':
110869112eddSAli Bahrami 		case '|':
110969112eddSAli Bahrami 			if (*(str + 1) != *str)
111069112eddSAli Bahrami 				goto token_error;
111169112eddSAli Bahrami 			if ((new_op != CEXP_OP_NONE) &&
111269112eddSAli Bahrami 			    (new_op != CEXP_OP_CPAR)) {
111369112eddSAli Bahrami 				mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_BADOPUSE));
111469112eddSAli Bahrami 				return (-1);
111569112eddSAli Bahrami 			}
111669112eddSAli Bahrami 			str++;
111769112eddSAli Bahrami 
111869112eddSAli Bahrami 			/*
111969112eddSAli Bahrami 			 * As this is a left associative binary operator, we
112069112eddSAli Bahrami 			 * need to process all operators of equal or higher
112169112eddSAli Bahrami 			 * precedence before pushing the new operator.
112269112eddSAli Bahrami 			 */
112369112eddSAli Bahrami 			while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack)) {
112469112eddSAli Bahrami 				cexp_op_t op = STACK_TOP(lms.lms_cexp_op_stack);
112569112eddSAli Bahrami 
112669112eddSAli Bahrami 
112769112eddSAli Bahrami 				if ((op != CEXP_OP_AND) && (op != CEXP_OP_OR) &&
112869112eddSAli Bahrami 				    (op != CEXP_OP_NEG))
112969112eddSAli Bahrami 					break;
113069112eddSAli Bahrami 
113169112eddSAli Bahrami 				if (!cexp_eval_op())
113269112eddSAli Bahrami 					goto semantic_error;
113369112eddSAli Bahrami 			}
113469112eddSAli Bahrami 
113569112eddSAli Bahrami 			new_op = (*str == '&') ? CEXP_OP_AND : CEXP_OP_OR;
113669112eddSAli Bahrami 			if (!cexp_push_op(new_op))
113769112eddSAli Bahrami 				return (-1);
113869112eddSAli Bahrami 			break;
113969112eddSAli Bahrami 
114069112eddSAli Bahrami 		case '!':
114169112eddSAli Bahrami 			new_op = CEXP_OP_NEG;
114269112eddSAli Bahrami 			if (!cexp_push_op(new_op))
114369112eddSAli Bahrami 				return (-1);
114469112eddSAli Bahrami 			break;
114569112eddSAli Bahrami 
114669112eddSAli Bahrami 		case '(':
114769112eddSAli Bahrami 			new_op = CEXP_OP_OPAR;
114869112eddSAli Bahrami 			if (!cexp_push_op(new_op))
114969112eddSAli Bahrami 				return (-1);
115069112eddSAli Bahrami 			break;
115169112eddSAli Bahrami 
115269112eddSAli Bahrami 		case ')':
115369112eddSAli Bahrami 			new_op = CEXP_OP_CPAR;
115469112eddSAli Bahrami 
115569112eddSAli Bahrami 			/* Evaluate the operator stack until reach '(' */
115669112eddSAli Bahrami 			while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack) &&
115769112eddSAli Bahrami 			    (STACK_TOP(lms.lms_cexp_op_stack) != CEXP_OP_OPAR))
115869112eddSAli Bahrami 				if (!cexp_eval_op())
115969112eddSAli Bahrami 					goto semantic_error;
116069112eddSAli Bahrami 
116169112eddSAli Bahrami 			/*
116269112eddSAli Bahrami 			 * If the top of operator stack is not an open paren,
116369112eddSAli Bahrami 			 * when we have an error. In this case, the operator
116469112eddSAli Bahrami 			 * stack will be empty due to the loop above.
116569112eddSAli Bahrami 			 */
116669112eddSAli Bahrami 			if (STACK_IS_EMPTY(lms.lms_cexp_op_stack))
116769112eddSAli Bahrami 				goto unbalpar_error;
116869112eddSAli Bahrami 			lms.lms_cexp_op_stack.stk_n--;   /* Pop OPAR */
116969112eddSAli Bahrami 			break;
117069112eddSAli Bahrami 
117169112eddSAli Bahrami 		default:
117269112eddSAli Bahrami 			/* Ensure there's room to push another operand */
117369112eddSAli Bahrami 			if (STACK_RESERVE(lms.lms_cexp_val_stack,
117469112eddSAli Bahrami 			    CEXP_VAL_STACK_INIT) == 0)
117569112eddSAli Bahrami 				return (0);
117669112eddSAli Bahrami 			new_op = CEXP_OP_NONE;
117769112eddSAli Bahrami 
117869112eddSAli Bahrami 			/*
117969112eddSAli Bahrami 			 * Operands cannot be numbers. However, we accept two
118069112eddSAli Bahrami 			 * special cases: '0' means false, and '1' is true.
118169112eddSAli Bahrami 			 * This is done to support the common C idiom of
118269112eddSAli Bahrami 			 * '#if 1' and '#if 0' to conditionalize code under
118369112eddSAli Bahrami 			 * development.
118469112eddSAli Bahrami 			 */
118569112eddSAli Bahrami 			if ((*str == '0') || (*str == '1')) {
118669112eddSAli Bahrami 				STACK_PUSH(lms.lms_cexp_val_stack) =
118769112eddSAli Bahrami 				    (*str == '1');
118869112eddSAli Bahrami 				break;
118969112eddSAli Bahrami 			}
119069112eddSAli Bahrami 
119169112eddSAli Bahrami 			/* Look up the identifier */
119269112eddSAli Bahrami 			ident = mf->mf_next = str;
119369112eddSAli Bahrami 			if (!cexp_ident_validate(mf, &len, NULL))
119469112eddSAli Bahrami 				return (-1);
119569112eddSAli Bahrami 			str += len - 1;	  /* loop will advance past final ch */
119669112eddSAli Bahrami 			null_patch_set(&ident[len], &np);
119769112eddSAli Bahrami 			STACK_PUSH(lms.lms_cexp_val_stack) =
119869112eddSAli Bahrami 			    cexp_ident_test(ident);
119969112eddSAli Bahrami 			null_patch_undo(&np);
120069112eddSAli Bahrami 
120169112eddSAli Bahrami 			break;
120269112eddSAli Bahrami 		}
120369112eddSAli Bahrami 	}
120469112eddSAli Bahrami 
120569112eddSAli Bahrami 	/* Evaluate the operator stack until empty */
120669112eddSAli Bahrami 	while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack)) {
120769112eddSAli Bahrami 		if (STACK_TOP(lms.lms_cexp_op_stack) == CEXP_OP_OPAR)
120869112eddSAli Bahrami 			goto unbalpar_error;
120969112eddSAli Bahrami 
121069112eddSAli Bahrami 		if (!cexp_eval_op())
121169112eddSAli Bahrami 			goto semantic_error;
121269112eddSAli Bahrami 	}
121369112eddSAli Bahrami 
121469112eddSAli Bahrami 	/* There should be exactly one value left */
121569112eddSAli Bahrami 	if (lms.lms_cexp_val_stack.stk_n != 1)
121669112eddSAli Bahrami 		goto semantic_error;
121769112eddSAli Bahrami 
121869112eddSAli Bahrami 	/* Final value is the result */
121969112eddSAli Bahrami 	return (lms.lms_cexp_val_stack.stk_s[0]);
122069112eddSAli Bahrami 
122169112eddSAli Bahrami 	/* Errors issued more than once are handled below, accessed via goto */
122269112eddSAli Bahrami 
122369112eddSAli Bahrami token_error:			/* unexpected characters in input stream */
122469112eddSAli Bahrami 	mf_fatal(mf, MSG_INTL(MSG_MAP_CEXP_TOKERR), str);
122569112eddSAli Bahrami 	return (-1);
122669112eddSAli Bahrami 
122769112eddSAli Bahrami semantic_error:			/* valid tokens, but in invalid arrangement */
122869112eddSAli Bahrami 	mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_SEMERR));
122969112eddSAli Bahrami 	return (-1);
123069112eddSAli Bahrami 
123169112eddSAli Bahrami unbalpar_error:			/* Extra or missing parenthesis */
123269112eddSAli Bahrami 	mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_UNBALPAR));
123369112eddSAli Bahrami 	return (-1);
123469112eddSAli Bahrami }
123569112eddSAli Bahrami 
123669112eddSAli Bahrami /*
123769112eddSAli Bahrami  * Process a mapfile control directive. These directives start with
123869112eddSAli Bahrami  * the dollar character, and are used to manage details of the mapfile
123969112eddSAli Bahrami  * itself, such as version and conditional input.
124069112eddSAli Bahrami  *
124169112eddSAli Bahrami  * entry:
124269112eddSAli Bahrami  *	mf - Mapfile descriptor
124369112eddSAli Bahrami  *
124469112eddSAli Bahrami  * exit:
124569112eddSAli Bahrami  *	Returns TRUE (1) for success, and FALSE (0) on error. In the
124669112eddSAli Bahrami  *	error case, a descriptive error is issued.
124769112eddSAli Bahrami  */
124869112eddSAli Bahrami static Boolean
124969112eddSAli Bahrami cdir_process(Mapfile *mf)
125069112eddSAli Bahrami {
125169112eddSAli Bahrami 	typedef enum {			/* Directive types */
125269112eddSAli Bahrami 		CDIR_T_UNKNOWN = 0,	/* Unrecognized control directive */
125369112eddSAli Bahrami 		CDIR_T_ADD,		/* $add */
125469112eddSAli Bahrami 		CDIR_T_CLEAR,		/* $clear */
125569112eddSAli Bahrami 		CDIR_T_ERROR,		/* $error */
125669112eddSAli Bahrami 		CDIR_T_VERSION,		/* $mapfile_version */
125769112eddSAli Bahrami 		CDIR_T_IF,		/* $if */
125869112eddSAli Bahrami 		CDIR_T_ELIF,		/* $elif */
125969112eddSAli Bahrami 		CDIR_T_ELSE,		/* $else */
126069112eddSAli Bahrami 		CDIR_T_ENDIF,		/* $endif */
126169112eddSAli Bahrami 	} cdir_t;
126269112eddSAli Bahrami 
126369112eddSAli Bahrami 	typedef enum {		/* Types of arguments accepted by directives */
126469112eddSAli Bahrami 		ARG_T_NONE,	/* Directive takes no arguments */
126569112eddSAli Bahrami 		ARG_T_EXPR,	/* Directive takes a conditional expression */
126669112eddSAli Bahrami 		ARG_T_ID,	/* Conditional expression identifier */
126769112eddSAli Bahrami 		ARG_T_STR,	/* Non-empty string */
126869112eddSAli Bahrami 		ARG_T_IGN	/* Ignore the argument */
126969112eddSAli Bahrami 	} cdir_arg_t;
127069112eddSAli Bahrami 
127169112eddSAli Bahrami 	typedef struct {
127269112eddSAli Bahrami 		const char	*md_name;	/* Directive name */
127369112eddSAli Bahrami 		size_t		md_size;	/* strlen(md_name) */
127469112eddSAli Bahrami 		cdir_arg_t	md_arg;		/* Type of arguments */
127569112eddSAli Bahrami 		cdir_t		md_op;		/* CDIR_T_ code */
127669112eddSAli Bahrami 	} cdir_match_t;
127769112eddSAli Bahrami 
127869112eddSAli Bahrami 	/* Control Directives: The most likely items are listed first */
127969112eddSAli Bahrami 	static cdir_match_t match_data[] = {
128069112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_IF),	MSG_STR_CDIR_IF_SIZE,
128169112eddSAli Bahrami 		    ARG_T_EXPR,			CDIR_T_IF },
128269112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_ENDIF),	MSG_STR_CDIR_ENDIF_SIZE,
128369112eddSAli Bahrami 		    ARG_T_NONE,			CDIR_T_ENDIF },
128469112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_ELSE),	MSG_STR_CDIR_ELSE_SIZE,
128569112eddSAli Bahrami 		    ARG_T_NONE,			CDIR_T_ELSE },
128669112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_ELIF),	MSG_STR_CDIR_ELIF_SIZE,
128769112eddSAli Bahrami 		    ARG_T_EXPR,			CDIR_T_ELIF },
128869112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_ERROR),	MSG_STR_CDIR_ERROR_SIZE,
128969112eddSAli Bahrami 		    ARG_T_STR,			CDIR_T_ERROR },
129069112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_ADD),	MSG_STR_CDIR_ADD_SIZE,
129169112eddSAli Bahrami 		    ARG_T_ID,			CDIR_T_ADD },
129269112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_CLEAR),	MSG_STR_CDIR_CLEAR_SIZE,
129369112eddSAli Bahrami 		    ARG_T_ID,			CDIR_T_CLEAR },
129469112eddSAli Bahrami 		{ MSG_ORIG(MSG_STR_CDIR_MFVER),	MSG_STR_CDIR_MFVER_SIZE,
129569112eddSAli Bahrami 		    ARG_T_IGN,			CDIR_T_VERSION },
129669112eddSAli Bahrami 
129769112eddSAli Bahrami 		{ NULL,				0,
129869112eddSAli Bahrami 		    ARG_T_IGN,			CDIR_T_UNKNOWN }
129969112eddSAli Bahrami 	};
130069112eddSAli Bahrami 
130169112eddSAli Bahrami 	cdir_match_t	*mdptr;
130269112eddSAli Bahrami 	char		*tail;
130369112eddSAli Bahrami 	int		expr_eval;	/* Result of evaluating ARG_T_EXPR */
130469112eddSAli Bahrami 	Mapfile		arg_mf;
130569112eddSAli Bahrami 	cdir_level_t	*level;
130669112eddSAli Bahrami 	int		pass, parent_pass;	/* Currently accepting input */
130769112eddSAli Bahrami 
130869112eddSAli Bahrami restart:
130969112eddSAli Bahrami 	/* Is the immediate context passing input? */
131069112eddSAli Bahrami 	pass = STACK_IS_EMPTY(lms.lms_cdir_stack) ||
131169112eddSAli Bahrami 	    STACK_TOP(lms.lms_cdir_stack).cdl_pass;
131269112eddSAli Bahrami 
131369112eddSAli Bahrami 	/* Is the surrounding (parent) context passing input? */
131469112eddSAli Bahrami 	parent_pass = (lms.lms_cdir_stack.stk_n <= 1) ||
131569112eddSAli Bahrami 	    lms.lms_cdir_stack.stk_s[lms.lms_cdir_stack.stk_n - 2].cdl_pass;
131669112eddSAli Bahrami 
131769112eddSAli Bahrami 
131869112eddSAli Bahrami 	for (mdptr = match_data; mdptr->md_name; mdptr++) {
131969112eddSAli Bahrami 		/* Prefix must match, or we move on */
132069112eddSAli Bahrami 		if (strncmp(mf->mf_next, mdptr->md_name,
132169112eddSAli Bahrami 		    mdptr->md_size) != 0)
132269112eddSAli Bahrami 			continue;
132369112eddSAli Bahrami 		tail = mf->mf_next + mdptr->md_size;
132469112eddSAli Bahrami 
132569112eddSAli Bahrami 		/*
132669112eddSAli Bahrami 		 * If there isn't whitespace, or a NULL terminator following
132769112eddSAli Bahrami 		 * the prefix, then even though our prefix matched, the actual
132869112eddSAli Bahrami 		 * token is longer, and we don't have a match.
132969112eddSAli Bahrami 		 */
133069112eddSAli Bahrami 		if (!isspace(*tail) && (*tail != '\0'))
133169112eddSAli Bahrami 			continue;
133269112eddSAli Bahrami 
133369112eddSAli Bahrami 		/* We have matched a valid control directive */
133469112eddSAli Bahrami 		break;
133569112eddSAli Bahrami 	}
133669112eddSAli Bahrami 
133769112eddSAli Bahrami 	/* Advance input to end of the current line */
133869112eddSAli Bahrami 	advance_to_eol(&mf->mf_next);
133969112eddSAli Bahrami 
134069112eddSAli Bahrami 	/*
134169112eddSAli Bahrami 	 * Set up a temporary mapfile descriptor to reference the
134269112eddSAli Bahrami 	 * argument string. The benefit of this second block, is that
134369112eddSAli Bahrami 	 * we can advance the real one to the next line now, which allows
134469112eddSAli Bahrami 	 * us to return at any time knowing that the input has been moved
134569112eddSAli Bahrami 	 * to the proper spot. This simplifies the error cases.
134669112eddSAli Bahrami 	 *
134769112eddSAli Bahrami 	 * If we had a match, tail points at the start of the string.
134869112eddSAli Bahrami 	 * Otherwise, we want to point at the end of the line.
134969112eddSAli Bahrami 	 */
135069112eddSAli Bahrami 	arg_mf = *mf;
135169112eddSAli Bahrami 	if (mdptr->md_name == NULL)
135269112eddSAli Bahrami 		arg_mf.mf_text = arg_mf.mf_next;
135369112eddSAli Bahrami 	else
135469112eddSAli Bahrami 		arg_mf.mf_text = arg_mf.mf_next = tail;
135569112eddSAli Bahrami 
135669112eddSAli Bahrami 	/*
135769112eddSAli Bahrami 	 * Null terminate the arguments, and advance the main mapfile
135869112eddSAli Bahrami 	 * state block to the next line.
135969112eddSAli Bahrami 	 */
136069112eddSAli Bahrami 	if (*mf->mf_next == '\n') {
136169112eddSAli Bahrami 		*mf->mf_next++ = '\0';
136269112eddSAli Bahrami 		mf->mf_lineno++;
136369112eddSAli Bahrami 	}
136469112eddSAli Bahrami 
136569112eddSAli Bahrami 	/* Skip leading whitespace to arguments */
136669112eddSAli Bahrami 	while (isspace(*arg_mf.mf_next))
136769112eddSAli Bahrami 		arg_mf.mf_next++;
136869112eddSAli Bahrami 
136969112eddSAli Bahrami 	/* Strip off any comment present on the line */
137069112eddSAli Bahrami 	for (tail = arg_mf.mf_next; *tail; tail++)
137169112eddSAli Bahrami 		if (*tail == '#') {
137269112eddSAli Bahrami 			*tail = '\0';
137369112eddSAli Bahrami 			break;
137469112eddSAli Bahrami 		}
137569112eddSAli Bahrami 
137669112eddSAli Bahrami 	/*
137769112eddSAli Bahrami 	 * Process the arguments as necessary depending on their type.
137869112eddSAli Bahrami 	 * If this control directive is nested inside a surrounding context
137969112eddSAli Bahrami 	 * that is not currently passing text, then we skip the argument
138069112eddSAli Bahrami 	 * evaluation. This follows the behavior of the C preprocessor,
138169112eddSAli Bahrami 	 * which only examines enough to detect the operation within
138269112eddSAli Bahrami 	 * a disabled section, without issuing errors about the arguments.
138369112eddSAli Bahrami 	 */
138469112eddSAli Bahrami 	if (pass || (parent_pass && (mdptr->md_op == CDIR_T_ELIF))) {
138569112eddSAli Bahrami 		switch (mdptr->md_arg) {
138669112eddSAli Bahrami 		case ARG_T_NONE:
138769112eddSAli Bahrami 			if (*arg_mf.mf_next == '\0')
138869112eddSAli Bahrami 				break;
138969112eddSAli Bahrami 			/* Args are present, but not wanted */
139069112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REQNOARG),
139169112eddSAli Bahrami 			    mdptr->md_name);
139269112eddSAli Bahrami 			return (FALSE);
139369112eddSAli Bahrami 
139469112eddSAli Bahrami 		case ARG_T_EXPR:
139569112eddSAli Bahrami 			/* Ensure that arguments are present */
139669112eddSAli Bahrami 			if (*arg_mf.mf_next == '\0')
139769112eddSAli Bahrami 				goto error_reqarg;
139869112eddSAli Bahrami 			expr_eval = cexp_eval_expr(&arg_mf);
139969112eddSAli Bahrami 			if (expr_eval == -1)
140069112eddSAli Bahrami 				return (FALSE);
140169112eddSAli Bahrami 			break;
140269112eddSAli Bahrami 
140369112eddSAli Bahrami 		case ARG_T_ID:
140469112eddSAli Bahrami 			/* Ensure that arguments are present */
140569112eddSAli Bahrami 			if (*arg_mf.mf_next == '\0')
140669112eddSAli Bahrami 				goto error_reqarg;
140769112eddSAli Bahrami 			if (!cexp_ident_validate(&arg_mf, NULL,
140869112eddSAli Bahrami 			    mdptr->md_name))
140969112eddSAli Bahrami 				return (FALSE);
141069112eddSAli Bahrami 			break;
141169112eddSAli Bahrami 
141269112eddSAli Bahrami 		case ARG_T_STR:
141369112eddSAli Bahrami 			/* Ensure that arguments are present */
141469112eddSAli Bahrami 			if (*arg_mf.mf_next == '\0')
141569112eddSAli Bahrami 				goto error_reqarg;
141669112eddSAli Bahrami 			/* Remove trailing whitespace */
141769112eddSAli Bahrami 			tail = arg_mf.mf_next + strlen(arg_mf.mf_next);
141869112eddSAli Bahrami 			while ((tail > arg_mf.mf_next) &&
141969112eddSAli Bahrami 			    isspace(*(tail -1)))
142069112eddSAli Bahrami 				tail--;
142169112eddSAli Bahrami 			*tail = '\0';
142269112eddSAli Bahrami 			break;
142369112eddSAli Bahrami 		}
142469112eddSAli Bahrami 	}
142569112eddSAli Bahrami 
142669112eddSAli Bahrami 	/*
142769112eddSAli Bahrami 	 * Carry out the specified control directive:
142869112eddSAli Bahrami 	 */
142969112eddSAli Bahrami 	if (!STACK_IS_EMPTY(lms.lms_cdir_stack))
143069112eddSAli Bahrami 		level = &STACK_TOP(lms.lms_cdir_stack);
143169112eddSAli Bahrami 
143269112eddSAli Bahrami 	switch (mdptr->md_op) {
143369112eddSAli Bahrami 	case CDIR_T_UNKNOWN:		/* Unrecognized control directive */
143469112eddSAli Bahrami 		if (!pass)
143569112eddSAli Bahrami 			break;
143669112eddSAli Bahrami 		mf_fatal0(&arg_mf, MSG_INTL(MSG_MAP_CDIR_BAD));
143769112eddSAli Bahrami 		return (FALSE);
143869112eddSAli Bahrami 
143969112eddSAli Bahrami 	case CDIR_T_ADD:
144069112eddSAli Bahrami 		if (pass && !cexp_ident_add(&arg_mf, arg_mf.mf_next))
144169112eddSAli Bahrami 			return (FALSE);
144269112eddSAli Bahrami 		break;
144369112eddSAli Bahrami 
144469112eddSAli Bahrami 	case CDIR_T_CLEAR:
144569112eddSAli Bahrami 		if (pass)
144669112eddSAli Bahrami 			cexp_ident_clear(&arg_mf, arg_mf.mf_next);
144769112eddSAli Bahrami 		break;
144869112eddSAli Bahrami 
144969112eddSAli Bahrami 	case CDIR_T_ERROR:
145069112eddSAli Bahrami 		if (!pass)
145169112eddSAli Bahrami 			break;
145269112eddSAli Bahrami 		mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ERROR),
145369112eddSAli Bahrami 		    arg_mf.mf_next);
145469112eddSAli Bahrami 		return (FALSE);
145569112eddSAli Bahrami 
145669112eddSAli Bahrami 	case CDIR_T_VERSION:
145769112eddSAli Bahrami 		/*
145869112eddSAli Bahrami 		 * A $mapfile_version control directive can only appear
145969112eddSAli Bahrami 		 * as the first directive in a mapfile, and is used to
146069112eddSAli Bahrami 		 * determine the syntax for the rest of the file. It's
146169112eddSAli Bahrami 		 * too late to be using it here.
146269112eddSAli Bahrami 		 */
146369112eddSAli Bahrami 		if (!pass)
146469112eddSAli Bahrami 			break;
146569112eddSAli Bahrami 		mf_fatal0(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REPVER));
146669112eddSAli Bahrami 		return (FALSE);
146769112eddSAli Bahrami 
146869112eddSAli Bahrami 	case CDIR_T_IF:
146969112eddSAli Bahrami 		/* Push a new level on the conditional input stack */
147069112eddSAli Bahrami 		if (STACK_RESERVE(lms.lms_cdir_stack, CDIR_STACK_INIT) == 0)
147169112eddSAli Bahrami 			return (FALSE);
147269112eddSAli Bahrami 		level = &lms.lms_cdir_stack.stk_s[lms.lms_cdir_stack.stk_n++];
147369112eddSAli Bahrami 		level->cdl_if_lineno = arg_mf.mf_lineno;
147469112eddSAli Bahrami 		level->cdl_else_lineno = 0;
147569112eddSAli Bahrami 
147669112eddSAli Bahrami 		/*
147769112eddSAli Bahrami 		 * If previous level is not passing, this level is disabled.
147869112eddSAli Bahrami 		 * Otherwise, the expression value determines what happens.
147969112eddSAli Bahrami 		 */
148069112eddSAli Bahrami 		if (pass) {
148169112eddSAli Bahrami 			level->cdl_done = level->cdl_pass = expr_eval;
148269112eddSAli Bahrami 		} else {
148369112eddSAli Bahrami 			level->cdl_done = 1;
148469112eddSAli Bahrami 			level->cdl_pass = 0;
148569112eddSAli Bahrami 		}
148669112eddSAli Bahrami 		break;
148769112eddSAli Bahrami 
148869112eddSAli Bahrami 	case CDIR_T_ELIF:
148969112eddSAli Bahrami 		/* $elif requires an open $if construct */
149069112eddSAli Bahrami 		if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
149169112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
149269112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_ELIF));
149369112eddSAli Bahrami 			return (FALSE);
149469112eddSAli Bahrami 		}
149569112eddSAli Bahrami 
149669112eddSAli Bahrami 		/* $elif cannot follow $else */
149769112eddSAli Bahrami 		if (level->cdl_else_lineno > 0) {
149869112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ELSE),
149969112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_ELIF),
150069112eddSAli Bahrami 			    EC_LINENO(level->cdl_else_lineno));
150169112eddSAli Bahrami 			return (FALSE);
150269112eddSAli Bahrami 		}
150369112eddSAli Bahrami 
150469112eddSAli Bahrami 		/*
150569112eddSAli Bahrami 		 * Accept text from $elif if the level isn't already
150669112eddSAli Bahrami 		 * done and the expression evaluates to true.
150769112eddSAli Bahrami 		 */
150869112eddSAli Bahrami 		level->cdl_pass = !level->cdl_done && expr_eval;
150969112eddSAli Bahrami 		if (level->cdl_pass)
151069112eddSAli Bahrami 			level->cdl_done = 1;
151169112eddSAli Bahrami 		break;
151269112eddSAli Bahrami 
151369112eddSAli Bahrami 	case CDIR_T_ELSE:
151469112eddSAli Bahrami 		/* $else requires an open $if construct */
151569112eddSAli Bahrami 		if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
151669112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
151769112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_ELSE));
151869112eddSAli Bahrami 			return (FALSE);
151969112eddSAli Bahrami 		}
152069112eddSAli Bahrami 
152169112eddSAli Bahrami 		/* There can only be one $else in the chain */
152269112eddSAli Bahrami 		if (level->cdl_else_lineno > 0) {
152369112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ELSE),
152469112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_ELSE),
152569112eddSAli Bahrami 			    EC_LINENO(level->cdl_else_lineno));
152669112eddSAli Bahrami 			return (FALSE);
152769112eddSAli Bahrami 		}
152869112eddSAli Bahrami 		level->cdl_else_lineno = arg_mf.mf_lineno;
152969112eddSAli Bahrami 
153069112eddSAli Bahrami 		/* Accept text from $else if the level isn't already done */
153169112eddSAli Bahrami 		level->cdl_pass = !level->cdl_done;
153269112eddSAli Bahrami 		level->cdl_done = 1;
153369112eddSAli Bahrami 		break;
153469112eddSAli Bahrami 
153569112eddSAli Bahrami 	case CDIR_T_ENDIF:
153669112eddSAli Bahrami 		/* $endif requires an open $if construct */
153769112eddSAli Bahrami 		if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
153869112eddSAli Bahrami 			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
153969112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_ENDIF));
154069112eddSAli Bahrami 			return (FALSE);
154169112eddSAli Bahrami 		}
154269112eddSAli Bahrami 		if (--lms.lms_cdir_stack.stk_n > 0)
154369112eddSAli Bahrami 			level = &STACK_TOP(lms.lms_cdir_stack);
154469112eddSAli Bahrami 		break;
154569112eddSAli Bahrami 
154669112eddSAli Bahrami 	default:
154769112eddSAli Bahrami 		return (FALSE);
154869112eddSAli Bahrami 	}
154969112eddSAli Bahrami 
155069112eddSAli Bahrami 	/* Evaluating the control directive above can change pass status */
155169112eddSAli Bahrami 	expr_eval = STACK_IS_EMPTY(lms.lms_cdir_stack) ||
155269112eddSAli Bahrami 	    STACK_TOP(lms.lms_cdir_stack).cdl_pass;
155369112eddSAli Bahrami 	if (expr_eval != pass) {
155469112eddSAli Bahrami 		pass = expr_eval;
155569112eddSAli Bahrami 		DBG_CALL(Dbg_map_pass(arg_mf.mf_ofl->ofl_lml, pass,
155669112eddSAli Bahrami 		    arg_mf.mf_name, arg_mf.mf_lineno, mdptr->md_name));
155769112eddSAli Bahrami 	}
155869112eddSAli Bahrami 
155969112eddSAli Bahrami 	/*
156069112eddSAli Bahrami 	 * At this point, we have processed a control directive,
156169112eddSAli Bahrami 	 * updated our conditional state stack, and the input is
156269112eddSAli Bahrami 	 * positioned at the start of the line following the directive.
156369112eddSAli Bahrami 	 * If the current level is accepting input, then give control
156469112eddSAli Bahrami 	 * back to ld_map_gettoken() to resume its normal operation.
156569112eddSAli Bahrami 	 */
156669112eddSAli Bahrami 	if (pass)
156769112eddSAli Bahrami 		return (TRUE);
156869112eddSAli Bahrami 
156969112eddSAli Bahrami 	/*
157069112eddSAli Bahrami 	 * The current level is not accepting input. Only another
157169112eddSAli Bahrami 	 * control directive can change this, so read and discard input
157269112eddSAli Bahrami 	 * until we encounter one of the following:
157369112eddSAli Bahrami 	 *
157469112eddSAli Bahrami 	 * EOF:			Return and let ld_map_gettoken() report it
157569112eddSAli Bahrami 	 * Control Directive:	Restart this function / evaluate new directive
157669112eddSAli Bahrami 	 */
157769112eddSAli Bahrami 	while (*mf->mf_next != '\0') {
157869112eddSAli Bahrami 		/* Skip leading whitespace */
157969112eddSAli Bahrami 		while (isspace_nonl(*mf->mf_next))
158069112eddSAli Bahrami 			mf->mf_next++;
158169112eddSAli Bahrami 
158269112eddSAli Bahrami 		/*
158369112eddSAli Bahrami 		 * Control directives start with a '$'. If we hit
158469112eddSAli Bahrami 		 * one, restart the function at this point
158569112eddSAli Bahrami 		 */
158669112eddSAli Bahrami 		if (*mf->mf_next == '$')
158769112eddSAli Bahrami 			goto restart;
158869112eddSAli Bahrami 
158969112eddSAli Bahrami 		/* Not a control directive, so advance input to next line */
159069112eddSAli Bahrami 		advance_to_eol(&mf->mf_next);
159169112eddSAli Bahrami 		if (*mf->mf_next == '\n') {
159269112eddSAli Bahrami 			mf->mf_lineno++;
159369112eddSAli Bahrami 			mf->mf_next++;
159469112eddSAli Bahrami 		}
159569112eddSAli Bahrami 	}
159669112eddSAli Bahrami 
15976f459ff5SToomas Soome 	assert(*mf->mf_next == '\0');
159869112eddSAli Bahrami 	return (TRUE);
159969112eddSAli Bahrami 
160069112eddSAli Bahrami 	/*
160169112eddSAli Bahrami 	 * Control directives that require an argument that is not present
160269112eddSAli Bahrami 	 * jump here to report the error and exit.
160369112eddSAli Bahrami 	 */
160469112eddSAli Bahrami error_reqarg:
160569112eddSAli Bahrami 	mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REQARG), mdptr->md_name);
160669112eddSAli Bahrami 	return (FALSE);
160769112eddSAli Bahrami 
160869112eddSAli Bahrami }
160969112eddSAli Bahrami 
161069112eddSAli Bahrami #ifndef _ELF64
161169112eddSAli Bahrami /*
161269112eddSAli Bahrami  * Convert a string to lowercase.
161369112eddSAli Bahrami  */
161469112eddSAli Bahrami void
161569112eddSAli Bahrami ld_map_lowercase(char *str)
161669112eddSAli Bahrami {
161769112eddSAli Bahrami 	while (*str = tolower(*str))
161869112eddSAli Bahrami 		str++;
161969112eddSAli Bahrami }
162069112eddSAli Bahrami #endif
162169112eddSAli Bahrami 
162269112eddSAli Bahrami /*
162369112eddSAli Bahrami  * Wrappper on strtoul()/strtoull(), adapted to return an Xword.
162469112eddSAli Bahrami  *
162569112eddSAli Bahrami  * entry:
162669112eddSAli Bahrami  *	str - Pointer to string to be converted.
162769112eddSAli Bahrami  *	endptr - As documented for strtoul(3C). Either NULL, or
162869112eddSAli Bahrami  *		address of pointer to receive the address of the first
162969112eddSAli Bahrami  *		unused character in str (called "final" in strtoul(3C)).
163069112eddSAli Bahrami  *	ret_value - Address of Xword variable to receive result.
163169112eddSAli Bahrami  *
163269112eddSAli Bahrami  * exit:
163369112eddSAli Bahrami  *	On success, *ret_value receives the result, *endptr is updated if
163469112eddSAli Bahrami  *	endptr is non-NULL, and STRTOXWORD_OK is returned.
163569112eddSAli Bahrami  *	On failure, STRTOXWORD_TOBIG is returned if an otherwise valid
163669112eddSAli Bahrami  *	value was too large, and STRTOXWORD_BAD is returned if the string
163769112eddSAli Bahrami  *	is malformed.
163869112eddSAli Bahrami  */
163969112eddSAli Bahrami ld_map_strtoxword_t
164069112eddSAli Bahrami ld_map_strtoxword(const char *restrict str, char **restrict endptr,
164169112eddSAli Bahrami     Xword *ret_value)
164269112eddSAli Bahrami {
164369112eddSAli Bahrami #if	defined(_ELF64)			/* _ELF64 */
164469112eddSAli Bahrami #define	FUNC		strtoull	/* Function to use */
164569112eddSAli Bahrami #define	FUNC_MAX	ULLONG_MAX	/* Largest value returned by FUNC */
164669112eddSAli Bahrami #define	XWORD_MAX	ULLONG_MAX	/* Largest Xword value */
164769112eddSAli Bahrami 	uint64_t	value;		/* Variable of FUNC return type  */
164869112eddSAli Bahrami #else					/* _ELF32 */
164969112eddSAli Bahrami #define	FUNC		strtoul
165069112eddSAli Bahrami #define	FUNC_MAX	ULONG_MAX
165169112eddSAli Bahrami #define	XWORD_MAX	UINT_MAX
165269112eddSAli Bahrami 	ulong_t		value;
165369112eddSAli Bahrami #endif
165469112eddSAli Bahrami 
165569112eddSAli Bahrami 	char	*endptr_local;		/* Used if endptr is NULL */
165669112eddSAli Bahrami 
165769112eddSAli Bahrami 	if (endptr == NULL)
165869112eddSAli Bahrami 		endptr = &endptr_local;
165969112eddSAli Bahrami 
166069112eddSAli Bahrami 	errno = 0;
166169112eddSAli Bahrami 	value = FUNC(str, endptr, 0);
166269112eddSAli Bahrami 	if ((errno != 0) || (str == *endptr)) {
166369112eddSAli Bahrami 		if (value  == FUNC_MAX)
166469112eddSAli Bahrami 			return (STRTOXWORD_TOOBIG);
166569112eddSAli Bahrami 		else
166669112eddSAli Bahrami 			return (STRTOXWORD_BAD);
166769112eddSAli Bahrami 	}
166869112eddSAli Bahrami 
166969112eddSAli Bahrami 	/*
167069112eddSAli Bahrami 	 * If this is a 64-bit linker building an ELFCLASS32 object,
167169112eddSAli Bahrami 	 * the FUNC return type is a 64-bit value, while an Xword is
167269112eddSAli Bahrami 	 * 32-bit. It is possible for FUNC to be able to convert a value
167369112eddSAli Bahrami 	 * too large for our return type.
167469112eddSAli Bahrami 	 */
167569112eddSAli Bahrami #if FUNC_MAX != XWORD_MAX
167669112eddSAli Bahrami 	if (value > XWORD_MAX)
167769112eddSAli Bahrami 		return (STRTOXWORD_TOOBIG);
167869112eddSAli Bahrami #endif
167969112eddSAli Bahrami 
168069112eddSAli Bahrami 	*ret_value = value;
168169112eddSAli Bahrami 	return (STRTOXWORD_OK);
168269112eddSAli Bahrami 
168369112eddSAli Bahrami #undef FUNC
168469112eddSAli Bahrami #undef FUNC_MAX
168569112eddSAli Bahrami #undef XWORD_MAC
168669112eddSAli Bahrami }
168769112eddSAli Bahrami 
168869112eddSAli Bahrami /*
168969112eddSAli Bahrami  * Convert the unsigned integer value at the current mapfile input
169069112eddSAli Bahrami  * into binary form. All numeric values in mapfiles are treated as
169169112eddSAli Bahrami  * unsigned integers of the appropriate width for an address on the
169269112eddSAli Bahrami  * given target. Values can be decimal, hex, or octal.
169369112eddSAli Bahrami  *
169469112eddSAli Bahrami  * entry:
169569112eddSAli Bahrami  *	str - String to process.
169669112eddSAli Bahrami  *	value - Address of variable to receive resulting value.
169769112eddSAli Bahrami  *	notail - If TRUE, an error is issued if non-whitespace
169869112eddSAli Bahrami  *		characters other than '#' (comment) are found following
169969112eddSAli Bahrami  *		the numeric value before the end of line.
170069112eddSAli Bahrami  *
170169112eddSAli Bahrami  * exit:
170269112eddSAli Bahrami  *	On success:
170369112eddSAli Bahrami  *		- *str is advanced to the next character following the value
170469112eddSAli Bahrami  *		- *value receives the value
170569112eddSAli Bahrami  *		- Returns TRUE (1).
170669112eddSAli Bahrami  *	On failure, returns FALSE (0).
170769112eddSAli Bahrami  */
170869112eddSAli Bahrami static Boolean
170969112eddSAli Bahrami ld_map_getint(Mapfile *mf, ld_map_tkval_t *value, Boolean notail)
171069112eddSAli Bahrami {
171169112eddSAli Bahrami 	ld_map_strtoxword_t	s2xw_ret;
171269112eddSAli Bahrami 	ld_map_npatch_t	np;
171369112eddSAli Bahrami 	char		*endptr;
171469112eddSAli Bahrami 	char		*errstr = mf->mf_next;
171569112eddSAli Bahrami 
171669112eddSAli Bahrami 	value->tkv_int.tkvi_str = mf->mf_next;
171769112eddSAli Bahrami 	s2xw_ret = ld_map_strtoxword(mf->mf_next, &endptr,
171869112eddSAli Bahrami 	    &value->tkv_int.tkvi_value);
171969112eddSAli Bahrami 	if (s2xw_ret != STRTOXWORD_OK) {
172069112eddSAli Bahrami 		null_patch_eol(mf->mf_next, &np);
172169112eddSAli Bahrami 		if (s2xw_ret == STRTOXWORD_TOOBIG)
172269112eddSAli Bahrami 			mf_fatal(mf, MSG_INTL(MSG_MAP_VALUELIMIT), errstr);
172369112eddSAli Bahrami 		else
172469112eddSAli Bahrami 			mf_fatal(mf, MSG_INTL(MSG_MAP_MALVALUE), errstr);
172569112eddSAli Bahrami 		null_patch_undo(&np);
172669112eddSAli Bahrami 		return (FALSE);
172769112eddSAli Bahrami 	}
172869112eddSAli Bahrami 
172969112eddSAli Bahrami 	/* Advance position to item following value, skipping whitespace */
173069112eddSAli Bahrami 	value->tkv_int.tkvi_cnt = endptr - mf->mf_next;
173169112eddSAli Bahrami 	mf->mf_next = endptr;
173269112eddSAli Bahrami 	while (isspace_nonl(*mf->mf_next))
173369112eddSAli Bahrami 		mf->mf_next++;
173469112eddSAli Bahrami 
173569112eddSAli Bahrami 	/* If requested, ensure there's nothing left */
173669112eddSAli Bahrami 	if (notail && (*mf->mf_next != '\n') && (*mf->mf_next != '#') &&
173769112eddSAli Bahrami 	    (*mf->mf_next != '\0')) {
173869112eddSAli Bahrami 		null_patch_eol(mf->mf_next, &np);
173969112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_BADVALUETAIL), errstr);
174069112eddSAli Bahrami 		null_patch_undo(&np);
174169112eddSAli Bahrami 		return (FALSE);
174269112eddSAli Bahrami 	}
174369112eddSAli Bahrami 
174469112eddSAli Bahrami 	return (TRUE);
174569112eddSAli Bahrami }
174669112eddSAli Bahrami 
174769112eddSAli Bahrami /*
174869112eddSAli Bahrami  * Convert a an unquoted identifier into a TK_STRING token, using the
174969112eddSAli Bahrami  * rules for syntax version in use. Used exclusively by ld_map_gettoken().
175069112eddSAli Bahrami  *
175169112eddSAli Bahrami  * entry:
175269112eddSAli Bahrami  *	mf - Mapfile descriptor, positioned to the first character of
175369112eddSAli Bahrami  *		the string.
175469112eddSAli Bahrami  *	flags - Bitmask of options to control ld_map_gettoken()s behavior
175569112eddSAli Bahrami  *	tkv- Address of pointer to variable to receive token value.
175669112eddSAli Bahrami  *
175769112eddSAli Bahrami  * exit:
175869112eddSAli Bahrami  *	On success, mf is advanced past the token, tkv is updated with
175969112eddSAli Bahrami  *	the string, and TK_STRING is returned. On error, TK_ERROR is returned.
176069112eddSAli Bahrami  */
176169112eddSAli Bahrami inline static Token
176269112eddSAli Bahrami gettoken_ident(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
176369112eddSAli Bahrami {
176469112eddSAli Bahrami 	char	*end;
176569112eddSAli Bahrami 	Token	tok;
176669112eddSAli Bahrami 	ld_map_npatch_t	np;
176769112eddSAli Bahrami 
176869112eddSAli Bahrami 	tkv->tkv_str = mf->mf_next;
176969112eddSAli Bahrami 	if ((end = ident_delimit(mf)) == NULL)
177069112eddSAli Bahrami 		return (TK_ERROR);
177169112eddSAli Bahrami 	mf->mf_next = end;
177269112eddSAli Bahrami 
177369112eddSAli Bahrami 	/*
177469112eddSAli Bahrami 	 * One advantage of reading the entire mapfile into memory is that
177569112eddSAli Bahrami 	 * we can access the strings within it without having to allocate
177669112eddSAli Bahrami 	 * more memory or make copies. In order to do that, we need to NULL
177769112eddSAli Bahrami 	 * terminate this identifier. That is going to overwrite the
177869112eddSAli Bahrami 	 * following character. The problem this presents is that the next
177969112eddSAli Bahrami 	 * character may well be the first character of a subsequent token.
178069112eddSAli Bahrami 	 * The solution to this is:
178169112eddSAli Bahrami 	 *
178269112eddSAli Bahrami 	 * 1)	Disallow the case where the next character is able to
178369112eddSAli Bahrami 	 *	start a string. This is not legal mapfile syntax anyway,
178469112eddSAli Bahrami 	 *	so catching it here simplifies matters.
178569112eddSAli Bahrami 	 * 2)	Copy the character into the special mf->mf_next_ch
178669112eddSAli Bahrami 	 * 3)	The next call to ld_map_gettoken() checks mf->mf_next_ch,
178769112eddSAli Bahrami 	 *	and if it is non-0, uses it instead of dereferencing the
178869112eddSAli Bahrami 	 *	mf_next pointer.
178969112eddSAli Bahrami 	 */
179069112eddSAli Bahrami 	tok = (*mf->mf_next & 0x80) ?
179169112eddSAli Bahrami 	    TK_OP_ILLCHR : mf->mf_tokdisp[*mf->mf_next];
179269112eddSAli Bahrami 	switch (tok) {
179369112eddSAli Bahrami 	case TK_OP_BADCHR:
179469112eddSAli Bahrami 		null_patch_eol(mf->mf_next, &np);
179569112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next);
179669112eddSAli Bahrami 		null_patch_undo(&np);
179769112eddSAli Bahrami 		return (TK_ERROR);
179869112eddSAli Bahrami 
179969112eddSAli Bahrami 	case TK_OP_SIMQUOTE:
180069112eddSAli Bahrami 	case TK_OP_CQUOTE:
180169112eddSAli Bahrami 	case TK_OP_CDIR:
180269112eddSAli Bahrami 	case TK_OP_NUM:
180369112eddSAli Bahrami 	case TK_OP_ID:
180469112eddSAli Bahrami 		null_patch_eol(mf->mf_next, &np);
180569112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_WSNEEDED), mf->mf_next);
180669112eddSAli Bahrami 		null_patch_undo(&np);
180769112eddSAli Bahrami 		return (TK_ERROR);
180869112eddSAli Bahrami 	}
180969112eddSAli Bahrami 
181069112eddSAli Bahrami 	/* Null terminate, saving the replaced character */
181169112eddSAli Bahrami 	mf->mf_next_ch = *mf->mf_next;
181269112eddSAli Bahrami 	*mf->mf_next = '\0';
181369112eddSAli Bahrami 
181469112eddSAli Bahrami 	if (flags & TK_F_STRLC)
181569112eddSAli Bahrami 		ld_map_lowercase(tkv->tkv_str);
181669112eddSAli Bahrami 	return (TK_STRING);
181769112eddSAli Bahrami }
181869112eddSAli Bahrami 
181969112eddSAli Bahrami /*
182069112eddSAli Bahrami  * Convert a quoted string into a TK_STRING token, using simple
182169112eddSAli Bahrami  * quoting rules:
182269112eddSAli Bahrami  *	- Start and end quotes must be present and match
182369112eddSAli Bahrami  *	- There are no special characters or escape sequences.
182469112eddSAli Bahrami  * This function is used exclusively by ld_map_gettoken().
182569112eddSAli Bahrami  *
182669112eddSAli Bahrami  * entry:
182769112eddSAli Bahrami  *	mf - Mapfile descriptor, positioned to the opening quote character.
182869112eddSAli Bahrami  *	flags - Bitmask of options to control ld_map_gettoken()s behavior
182969112eddSAli Bahrami  *	tkv- Address of pointer to variable to receive token value.
183069112eddSAli Bahrami  *
183169112eddSAli Bahrami  * exit:
183269112eddSAli Bahrami  *	On success, mf is advanced past the token, tkv is updated with
183369112eddSAli Bahrami  *	the string, and TK_STRING is returned. On error, TK_ERROR is returned.
183469112eddSAli Bahrami  */
183569112eddSAli Bahrami inline static Token
183669112eddSAli Bahrami gettoken_simquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
183769112eddSAli Bahrami {
183869112eddSAli Bahrami 	char	*str, *end;
183969112eddSAli Bahrami 	char	quote;
184069112eddSAli Bahrami 
184169112eddSAli Bahrami 	str = mf->mf_next++;
184269112eddSAli Bahrami 	quote = *str;
184369112eddSAli Bahrami 	end = mf->mf_next;
184469112eddSAli Bahrami 	while ((*end != '\0') && (*end != '\n') && (*end != quote))
184569112eddSAli Bahrami 		end++;
184669112eddSAli Bahrami 	if (*end != quote) {
184769112eddSAli Bahrami 		ld_map_npatch_t	np;
184869112eddSAli Bahrami 
184969112eddSAli Bahrami 		null_patch_eol(end, &np);
185069112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str);
185169112eddSAli Bahrami 		null_patch_undo(&np);
185269112eddSAli Bahrami 		return (TK_ERROR);
185369112eddSAli Bahrami 	}
185469112eddSAli Bahrami 
185569112eddSAli Bahrami 	/*
185669112eddSAli Bahrami 	 * end is pointing at the closing quote. We can turn that into NULL
185769112eddSAli Bahrami 	 * termination for the string without needing to restore it later.
185869112eddSAli Bahrami 	 */
185969112eddSAli Bahrami 	*end = '\0';
186069112eddSAli Bahrami 	mf->mf_next = end + 1;
186169112eddSAli Bahrami 	tkv->tkv_str = str + 1;		/* Skip opening quote */
186269112eddSAli Bahrami 	if (flags & TK_F_STRLC)
186369112eddSAli Bahrami 		ld_map_lowercase(tkv->tkv_str);
186469112eddSAli Bahrami 	return (TK_STRING);
186569112eddSAli Bahrami }
186669112eddSAli Bahrami 
186769112eddSAli Bahrami /*
186869112eddSAli Bahrami  * Convert a quoted string into a TK_STRING token, using C string literal
186969112eddSAli Bahrami  * quoting rules:
187069112eddSAli Bahrami  *	- Start and end quotes must be present and match
187169112eddSAli Bahrami  *	- Backslash is an escape, used to introduce  special characters
187269112eddSAli Bahrami  * This function is used exclusively by ld_map_gettoken().
187369112eddSAli Bahrami  *
187469112eddSAli Bahrami  * entry:
187569112eddSAli Bahrami  *	mf - Mapfile descriptor, positioned to the opening quote character.
187669112eddSAli Bahrami  *	flags - Bitmask of options to control ld_map_gettoken()s behavior
187769112eddSAli Bahrami  *	tkv- Address of pointer to variable to receive token value.
187869112eddSAli Bahrami  *
187969112eddSAli Bahrami  * exit:
188069112eddSAli Bahrami  *	On success, mf is advanced past the token, tkv is updated with
188169112eddSAli Bahrami  *	the string, and TK_STRING is returned. On error, TK_ERROR is returned.
188269112eddSAli Bahrami  */
188369112eddSAli Bahrami inline static Token
188469112eddSAli Bahrami gettoken_cquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
188569112eddSAli Bahrami {
188669112eddSAli Bahrami 	char	*str, *cur, *end;
188769112eddSAli Bahrami 	char	quote;
188869112eddSAli Bahrami 	int	c;
188969112eddSAli Bahrami 
189069112eddSAli Bahrami 	/*
189169112eddSAli Bahrami 	 * This function goes through the quoted string and copies
189269112eddSAli Bahrami 	 * it on top of itself, replacing escape sequences with the
189369112eddSAli Bahrami 	 * characters they denote. There is always enough room for this,
189469112eddSAli Bahrami 	 * because escapes are multi-character sequences that are converted
189569112eddSAli Bahrami 	 * to single character results.
189669112eddSAli Bahrami 	 */
189769112eddSAli Bahrami 	str = mf->mf_next++;
189869112eddSAli Bahrami 	quote = *str;
189969112eddSAli Bahrami 	cur = end = mf->mf_next;
190069112eddSAli Bahrami 	for (c = *end++; (c != '\0') && (c != '\n') && (c != quote);
190169112eddSAli Bahrami 	    c = *end++) {
190269112eddSAli Bahrami 		if (c == '\\') {
190369112eddSAli Bahrami 			c = conv_translate_c_esc(&end);
190469112eddSAli Bahrami 			if (c == -1) {
190569112eddSAli Bahrami 				mf_fatal(mf, MSG_INTL(MSG_MAP_BADCESC), *end);
190669112eddSAli Bahrami 				return (TK_ERROR);
190769112eddSAli Bahrami 			}
190869112eddSAli Bahrami 		}
190969112eddSAli Bahrami 		*cur++ = c;
191069112eddSAli Bahrami 	}
191169112eddSAli Bahrami 	*cur = '\0';		/* terminate the result */
191269112eddSAli Bahrami 	if (c != quote) {
191369112eddSAli Bahrami 		ld_map_npatch_t	np;
191469112eddSAli Bahrami 
191569112eddSAli Bahrami 		null_patch_eol(end, &np);
191669112eddSAli Bahrami 		mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str);
191769112eddSAli Bahrami 		null_patch_undo(&np);
191869112eddSAli Bahrami 		return (TK_ERROR);
191969112eddSAli Bahrami 	}
192069112eddSAli Bahrami 
192169112eddSAli Bahrami 	/* end is pointing one character past the closing quote */
192269112eddSAli Bahrami 	mf->mf_next = end;
192369112eddSAli Bahrami 	tkv->tkv_str = str + 1;		/* Skip opening quote */
192469112eddSAli Bahrami 	if (flags & TK_F_STRLC)
192569112eddSAli Bahrami 		ld_map_lowercase(tkv->tkv_str);
192669112eddSAli Bahrami 	return (TK_STRING);
192769112eddSAli Bahrami }
192869112eddSAli Bahrami 
192969112eddSAli Bahrami /*
193069112eddSAli Bahrami  * Get a token from the mapfile.
193169112eddSAli Bahrami  *
193269112eddSAli Bahrami  * entry:
193369112eddSAli Bahrami  *	mf - Mapfile descriptor
193469112eddSAli Bahrami  *	flags - Bitmask of options to control ld_map_gettoken()s behavior
193569112eddSAli Bahrami  *	tkv- Address of pointer to variable to receive token value.
193669112eddSAli Bahrami  *
193769112eddSAli Bahrami  * exit:
193869112eddSAli Bahrami  *	Returns one of the TK_* values, to report the result. If the resulting
193969112eddSAli Bahrami  *	token has a value (TK_STRING / TK_INT), and tkv is non-NULL, tkv
194069112eddSAli Bahrami  *	is filled in with the resulting value.
194169112eddSAli Bahrami  */
194269112eddSAli Bahrami Token
194369112eddSAli Bahrami ld_map_gettoken(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
194469112eddSAli Bahrami {
194569112eddSAli Bahrami 	int		cdir_allow, ch;
194669112eddSAli Bahrami 	Token		tok;
194769112eddSAli Bahrami 	ld_map_npatch_t	np;
194869112eddSAli Bahrami 
194969112eddSAli Bahrami 	/*
195069112eddSAli Bahrami 	 * Mapfile control directives all start with a '$' character. However,
195169112eddSAli Bahrami 	 * they are only valid when they are the first thing on a line. That
195269112eddSAli Bahrami 	 * happens on the first call to ld_map_gettoken() for a new a new
195369112eddSAli Bahrami 	 * mapfile, as tracked with lms.lms_cdir_valid, and immediately
195469112eddSAli Bahrami 	 * following each newline seen in the file.
195569112eddSAli Bahrami 	 */
195669112eddSAli Bahrami 	cdir_allow = lms.lms_cdir_valid;
195769112eddSAli Bahrami 	lms.lms_cdir_valid = 0;
195869112eddSAli Bahrami 
195969112eddSAli Bahrami 	/* Cycle through the characters looking for tokens. */
196069112eddSAli Bahrami 	for (;;) {
196169112eddSAli Bahrami 		/*
196269112eddSAli Bahrami 		 * Process the next character. This is normally *mf->mf_next,
196369112eddSAli Bahrami 		 * but if mf->mf_next_ch is non-0, then it contains the
196469112eddSAli Bahrami 		 * character, and *mf->mf_next contains a NULL termination
196569112eddSAli Bahrami 		 * from the TK_STRING token returned on the previous call.
196669112eddSAli Bahrami 		 *
196769112eddSAli Bahrami 		 * gettoken_ident() ensures that this is never done to
196869112eddSAli Bahrami 		 * a character that starts a string.
196969112eddSAli Bahrami 		 */
197069112eddSAli Bahrami 		if (mf->mf_next_ch == 0) {
197169112eddSAli Bahrami 			ch = *mf->mf_next;
197269112eddSAli Bahrami 		} else {
197369112eddSAli Bahrami 			ch = mf->mf_next_ch;
197469112eddSAli Bahrami 			mf->mf_next_ch = 0;	/* Reset */
197569112eddSAli Bahrami 		}
197669112eddSAli Bahrami 
197769112eddSAli Bahrami 		/* Map the character to a dispatch action */
197869112eddSAli Bahrami 		tok = (ch & 0x80) ? TK_OP_ILLCHR : mf->mf_tokdisp[ch];
197969112eddSAli Bahrami 
198069112eddSAli Bahrami 		/*
198169112eddSAli Bahrami 		 * Items that require processing are identified as OP tokens.
198269112eddSAli Bahrami 		 * We process them, and return a result non-OP token.
198369112eddSAli Bahrami 		 *
198469112eddSAli Bahrami 		 * Non-OP tokens are single character tokens, and we return
198569112eddSAli Bahrami 		 * them immediately.
198669112eddSAli Bahrami 		 */
198769112eddSAli Bahrami 		switch (tok) {
198869112eddSAli Bahrami 		case TK_OP_EOF:
198969112eddSAli Bahrami 			/* If EOFOK is set, quietly report it as TK_EOF */
199069112eddSAli Bahrami 			if ((flags & TK_F_EOFOK) != 0)
199169112eddSAli Bahrami 				return (TK_EOF);
199269112eddSAli Bahrami 
199369112eddSAli Bahrami 			/* Treat it as a standard error */
199469112eddSAli Bahrami 			mf_fatal0(mf, MSG_INTL(MSG_MAP_PREMEOF));
199569112eddSAli Bahrami 			return (TK_ERROR);
199669112eddSAli Bahrami 
199769112eddSAli Bahrami 		case TK_OP_ILLCHR:
199869112eddSAli Bahrami 			mf_fatal(mf, MSG_INTL(MSG_MAP_ILLCHAR), ch);
199969112eddSAli Bahrami 			mf->mf_next++;
200069112eddSAli Bahrami 			return (TK_ERROR);
200169112eddSAli Bahrami 
200269112eddSAli Bahrami 		case TK_OP_BADCHR:
200369112eddSAli Bahrami 			tk_op_badchr:
200469112eddSAli Bahrami 			null_patch_eol(mf->mf_next, &np);
200569112eddSAli Bahrami 			mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next);
200669112eddSAli Bahrami 			null_patch_undo(&np);
200769112eddSAli Bahrami 			mf->mf_next++;
200869112eddSAli Bahrami 			return (TK_ERROR);
200969112eddSAli Bahrami 
201069112eddSAli Bahrami 		case TK_OP_WS:	/* White space */
201169112eddSAli Bahrami 			mf->mf_next++;
201269112eddSAli Bahrami 			break;
201369112eddSAli Bahrami 
201469112eddSAli Bahrami 		case TK_OP_NL:	/* White space too, but bump line number. */
201569112eddSAli Bahrami 			mf->mf_next++;
201669112eddSAli Bahrami 			mf->mf_lineno++;
201769112eddSAli Bahrami 			cdir_allow = 1;
201869112eddSAli Bahrami 			break;
201969112eddSAli Bahrami 
202069112eddSAli Bahrami 		case TK_OP_SIMQUOTE:
202169112eddSAli Bahrami 			if (flags & TK_F_KEYWORD)
202269112eddSAli Bahrami 				goto tk_op_badkwquote;
202369112eddSAli Bahrami 			return (gettoken_simquote_str(mf, flags, tkv));
202469112eddSAli Bahrami 
202569112eddSAli Bahrami 		case TK_OP_CQUOTE:
202669112eddSAli Bahrami 			if (flags & TK_F_KEYWORD) {
202769112eddSAli Bahrami 			tk_op_badkwquote:
202869112eddSAli Bahrami 				null_patch_eol(mf->mf_next, &np);
202969112eddSAli Bahrami 				mf_fatal(mf, MSG_INTL(MSG_MAP_BADKWQUOTE),
203069112eddSAli Bahrami 				    mf->mf_next);
203169112eddSAli Bahrami 				null_patch_undo(&np);
203269112eddSAli Bahrami 				mf->mf_next++;
203369112eddSAli Bahrami 				return (TK_ERROR);
203469112eddSAli Bahrami 			}
203569112eddSAli Bahrami 			return (gettoken_cquote_str(mf, flags, tkv));
203669112eddSAli Bahrami 
203769112eddSAli Bahrami 		case TK_OP_CMT:
203869112eddSAli Bahrami 			advance_to_eol(&mf->mf_next);
203969112eddSAli Bahrami 			break;
204069112eddSAli Bahrami 
204169112eddSAli Bahrami 		case TK_OP_CDIR:
204269112eddSAli Bahrami 			/*
204369112eddSAli Bahrami 			 * Control directives are only valid at the start
204469112eddSAli Bahrami 			 * of a line.
204569112eddSAli Bahrami 			 */
204669112eddSAli Bahrami 			if (!cdir_allow) {
204769112eddSAli Bahrami 				null_patch_eol(mf->mf_next, &np);
204869112eddSAli Bahrami 				mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOTBOL),
204969112eddSAli Bahrami 				    mf->mf_next);
205069112eddSAli Bahrami 				null_patch_undo(&np);
205169112eddSAli Bahrami 				mf->mf_next++;
205269112eddSAli Bahrami 				return (TK_ERROR);
205369112eddSAli Bahrami 			}
205469112eddSAli Bahrami 			if (!cdir_process(mf))
205569112eddSAli Bahrami 				return (TK_ERROR);
205669112eddSAli Bahrami 			break;
205769112eddSAli Bahrami 
205869112eddSAli Bahrami 		case TK_OP_NUM:	/* Decimal, hex(0x...), or octal (0...) value */
205969112eddSAli Bahrami 			if (!ld_map_getint(mf, tkv, FALSE))
206069112eddSAli Bahrami 				return (TK_ERROR);
206169112eddSAli Bahrami 			return (TK_INT);
206269112eddSAli Bahrami 
206369112eddSAli Bahrami 		case TK_OP_ID:		/* Unquoted identifier */
206469112eddSAli Bahrami 			return (gettoken_ident(mf, flags, tkv));
206569112eddSAli Bahrami 
206669112eddSAli Bahrami 		case TK_OP_CEQUAL:	/* += or -= */
206769112eddSAli Bahrami 			if (*(mf->mf_next + 1) != '=')
206869112eddSAli Bahrami 				goto tk_op_badchr;
206969112eddSAli Bahrami 			tok = (ch == '+') ? TK_PLUSEQ : TK_MINUSEQ;
207069112eddSAli Bahrami 			mf->mf_next += 2;
207169112eddSAli Bahrami 			return (tok);
207269112eddSAli Bahrami 
207369112eddSAli Bahrami 		default:	/* Non-OP token */
207469112eddSAli Bahrami 			mf->mf_next++;
207569112eddSAli Bahrami 			return (tok);
207669112eddSAli Bahrami 		}
207769112eddSAli Bahrami 	}
207869112eddSAli Bahrami }
207969112eddSAli Bahrami 
208069112eddSAli Bahrami /*
208169112eddSAli Bahrami  * Given a token and value returned by ld_map_gettoken(), return a string
208269112eddSAli Bahrami  * representation of it suitable for use in an error message.
208369112eddSAli Bahrami  *
208469112eddSAli Bahrami  * entry:
208569112eddSAli Bahrami  *	tok - Token code. Must not be an OP-token
208669112eddSAli Bahrami  *	tkv - Token value
208769112eddSAli Bahrami  */
208869112eddSAli Bahrami const char *
208969112eddSAli Bahrami ld_map_tokenstr(Token tok, ld_map_tkval_t *tkv, Conv_inv_buf_t *inv_buf)
209069112eddSAli Bahrami {
209169112eddSAli Bahrami 	size_t	cnt;
209269112eddSAli Bahrami 
209369112eddSAli Bahrami 	switch (tok) {
209469112eddSAli Bahrami 	case TK_ERROR:
209569112eddSAli Bahrami 		return (MSG_ORIG(MSG_STR_ERROR));
209669112eddSAli Bahrami 	case TK_EOF:
209769112eddSAli Bahrami 		return (MSG_ORIG(MSG_STR_EOF));
209869112eddSAli Bahrami 	case TK_STRING:
209969112eddSAli Bahrami 		return (tkv->tkv_str);
210069112eddSAli Bahrami 	case TK_COLON:
210169112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_COLON));
210269112eddSAli Bahrami 	case TK_SEMICOLON:
210369112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_SEMICOLON));
210469112eddSAli Bahrami 	case TK_EQUAL:
210569112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_EQUAL));
210669112eddSAli Bahrami 	case TK_PLUSEQ:
210769112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_PLUSEQ));
210869112eddSAli Bahrami 	case TK_MINUSEQ:
210969112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_MINUSEQ));
211069112eddSAli Bahrami 	case TK_ATSIGN:
211169112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_ATSIGN));
211269112eddSAli Bahrami 	case TK_DASH:
211369112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_DASH));
211469112eddSAli Bahrami 	case TK_LEFTBKT:
211569112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_LEFTBKT));
211669112eddSAli Bahrami 	case TK_RIGHTBKT:
211769112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_RIGHTBKT));
211869112eddSAli Bahrami 	case TK_PIPE:
211969112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_PIPE));
212069112eddSAli Bahrami 	case TK_INT:
212169112eddSAli Bahrami 		cnt = tkv->tkv_int.tkvi_cnt;
212269112eddSAli Bahrami 		if (cnt >= sizeof (inv_buf->buf))
212369112eddSAli Bahrami 			cnt = sizeof (inv_buf->buf) - 1;
212469112eddSAli Bahrami 		(void) memcpy(inv_buf->buf, tkv->tkv_int.tkvi_str, cnt);
212569112eddSAli Bahrami 		inv_buf->buf[cnt] = '\0';
212669112eddSAli Bahrami 		return (inv_buf->buf);
212769112eddSAli Bahrami 	case TK_STAR:
212869112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_STAR));
212969112eddSAli Bahrami 	case TK_BANG:
213069112eddSAli Bahrami 		return (MSG_ORIG(MSG_QSTR_BANG));
213169112eddSAli Bahrami 	default:
213269112eddSAli Bahrami 		assert(0);
213369112eddSAli Bahrami 		break;
213469112eddSAli Bahrami 	}
213569112eddSAli Bahrami 
213669112eddSAli Bahrami 	/*NOTREACHED*/
213769112eddSAli Bahrami 	return (MSG_INTL(MSG_MAP_INTERR));
213869112eddSAli Bahrami }
213969112eddSAli Bahrami 
214069112eddSAli Bahrami /*
214169112eddSAli Bahrami  * Advance the input to the first non-empty line, and determine
214269112eddSAli Bahrami  * the mapfile version. The version is specified by the mapfile
214369112eddSAli Bahrami  * using a $mapfile_version directive. The original System V
214469112eddSAli Bahrami  * syntax lacks this directive, and we use that fact to identify
214569112eddSAli Bahrami  * such files. SysV mapfile are implicitly defined to have version 1.
214669112eddSAli Bahrami  *
214769112eddSAli Bahrami  * entry:
214869112eddSAli Bahrami  *	ofl - Output file descriptor
214969112eddSAli Bahrami  *	mf - Mapfile block
215069112eddSAli Bahrami  *
215169112eddSAli Bahrami  * exit:
215269112eddSAli Bahrami  *	On success, updates mf->mf_version, and returns TRUE (1).
215369112eddSAli Bahrami  *	On failure, returns FALSE (0).
215469112eddSAli Bahrami  */
215569112eddSAli Bahrami static Boolean
215669112eddSAli Bahrami mapfile_version(Mapfile *mf)
215769112eddSAli Bahrami {
215869112eddSAli Bahrami 	char	*line_start = mf->mf_next;
215969112eddSAli Bahrami 	Boolean	cont = TRUE;
216069112eddSAli Bahrami 	Boolean	status = TRUE;	/* Assume success */
216169112eddSAli Bahrami 	Token	tok;
216269112eddSAli Bahrami 
216369112eddSAli Bahrami 	mf->mf_version = MFV_SYSV;
216469112eddSAli Bahrami 
216569112eddSAli Bahrami 	/*
216669112eddSAli Bahrami 	 * Cycle through the characters looking for tokens. Although the
216769112eddSAli Bahrami 	 * true version is not known yet, we use the v2 dispatch table.
216869112eddSAli Bahrami 	 * It contains control directives, which we need for this search,
216969112eddSAli Bahrami 	 * and the other TK_OP_ tokens we will recognize and act on are the
217069112eddSAli Bahrami 	 * same for both tables.
217169112eddSAli Bahrami 	 *
217269112eddSAli Bahrami 	 * It is important not to process any tokens that would lead to
217369112eddSAli Bahrami 	 * a non-OP token:
217469112eddSAli Bahrami 	 *
217569112eddSAli Bahrami 	 * -	The version is required to interpret them
217669112eddSAli Bahrami 	 * -	Our mapfile descriptor is not fully initialized,
217769112eddSAli Bahrami 	 *	attempts to run that code will crash the program.
217869112eddSAli Bahrami 	 */
217969112eddSAli Bahrami 	while (cont) {
218069112eddSAli Bahrami 		/* Map the character to a dispatch action */
218169112eddSAli Bahrami 		tok = (*mf->mf_next & 0x80) ?
218269112eddSAli Bahrami 		    TK_OP_ILLCHR : gettok_dispatch_v2[*mf->mf_next];
218369112eddSAli Bahrami 
218469112eddSAli Bahrami 		switch (tok) {
218569112eddSAli Bahrami 		case TK_OP_WS:	/* White space */
218669112eddSAli Bahrami 			mf->mf_next++;
218769112eddSAli Bahrami 			break;
218869112eddSAli Bahrami 
218969112eddSAli Bahrami 		case TK_OP_NL:	/* White space too, but bump line number. */
219069112eddSAli Bahrami 			mf->mf_next++;
219169112eddSAli Bahrami 			mf->mf_lineno++;
219269112eddSAli Bahrami 			break;
219369112eddSAli Bahrami 
219469112eddSAli Bahrami 		case TK_OP_CMT:
219569112eddSAli Bahrami 			advance_to_eol(&mf->mf_next);
219669112eddSAli Bahrami 			break;
219769112eddSAli Bahrami 
219869112eddSAli Bahrami 		case TK_OP_CDIR:
219969112eddSAli Bahrami 			/*
220069112eddSAli Bahrami 			 * Control directives are only valid at the start
220169112eddSAli Bahrami 			 * of a line. However, as we have not yet seen
220269112eddSAli Bahrami 			 * a token, we do not need to test for this, and
220369112eddSAli Bahrami 			 * can safely assume that we are at the start.
220469112eddSAli Bahrami 			 */
220569112eddSAli Bahrami 			if (!strncasecmp(mf->mf_next,
220669112eddSAli Bahrami 			    MSG_ORIG(MSG_STR_CDIR_MFVER),
220769112eddSAli Bahrami 			    MSG_STR_CDIR_MFVER_SIZE) &&
220869112eddSAli Bahrami 			    isspace_nonl(*(mf->mf_next +
220969112eddSAli Bahrami 			    MSG_STR_CDIR_MFVER_SIZE))) {
221069112eddSAli Bahrami 				ld_map_tkval_t	ver;
221169112eddSAli Bahrami 
221269112eddSAli Bahrami 				mf->mf_next += MSG_STR_CDIR_MFVER_SIZE + 1;
221369112eddSAli Bahrami 				if (!ld_map_getint(mf, &ver, TRUE)) {
221469112eddSAli Bahrami 					status = cont = FALSE;
221569112eddSAli Bahrami 					break;
221669112eddSAli Bahrami 				}
221769112eddSAli Bahrami 				/*
221869112eddSAli Bahrami 				 * Is it a valid version? Note that we
221969112eddSAli Bahrami 				 * intentionally do not allow you to
222069112eddSAli Bahrami 				 * specify version 1 using the $mapfile_version
222169112eddSAli Bahrami 				 * syntax, because that's reserved to version
222269112eddSAli Bahrami 				 * 2 and up.
222369112eddSAli Bahrami 				 */
222469112eddSAli Bahrami 				if ((ver.tkv_int.tkvi_value < 2) ||
222569112eddSAli Bahrami 				    (ver.tkv_int.tkvi_value >= MFV_NUM)) {
222669112eddSAli Bahrami 					const char *fmt;
222769112eddSAli Bahrami 
222869112eddSAli Bahrami 					fmt = (ver.tkv_int.tkvi_value < 2) ?
222969112eddSAli Bahrami 					    MSG_INTL(MSG_MAP_CDIR_BADVDIR) :
223069112eddSAli Bahrami 					    MSG_INTL(MSG_MAP_CDIR_BADVER);
223169112eddSAli Bahrami 					mf_fatal(mf, fmt,
223269112eddSAli Bahrami 					    EC_WORD(ver.tkv_int.tkvi_value));
223369112eddSAli Bahrami 					status = cont = FALSE;
223469112eddSAli Bahrami 					break;
223569112eddSAli Bahrami 				}
223669112eddSAli Bahrami 				mf->mf_version = ver.tkv_int.tkvi_value;
223769112eddSAli Bahrami 				cont = FALSE; /* Version recovered. All done */
223869112eddSAli Bahrami 				break;
223969112eddSAli Bahrami 			}
224069112eddSAli Bahrami 			/*
224169112eddSAli Bahrami 			 * Not a version directive. Reset the current position
224269112eddSAli Bahrami 			 * to the start of the current line and stop here.
224369112eddSAli Bahrami 			 * SysV syntax applies.
224469112eddSAli Bahrami 			 */
224569112eddSAli Bahrami 			mf->mf_next = line_start;
224669112eddSAli Bahrami 			cont = FALSE;
224769112eddSAli Bahrami 			break;
224869112eddSAli Bahrami 
224969112eddSAli Bahrami 		default:
225069112eddSAli Bahrami 			/*
225169112eddSAli Bahrami 			 * If we see anything else, then stop at this point.
225269112eddSAli Bahrami 			 * The file has System V syntax (version 1), and the
225369112eddSAli Bahrami 			 * next token should be interpreted as such.
225469112eddSAli Bahrami 			 */
225569112eddSAli Bahrami 			cont = FALSE;
225669112eddSAli Bahrami 			break;
225769112eddSAli Bahrami 		}
225869112eddSAli Bahrami 	}
225969112eddSAli Bahrami 
226069112eddSAli Bahrami 	return (status);
226169112eddSAli Bahrami }
226269112eddSAli Bahrami 
226369112eddSAli Bahrami /*
226469112eddSAli Bahrami  * Parse the mapfile.
226569112eddSAli Bahrami  */
226669112eddSAli Bahrami Boolean
226769112eddSAli Bahrami ld_map_parse(const char *mapfile, Ofl_desc *ofl)
226869112eddSAli Bahrami {
226969112eddSAli Bahrami 	struct stat	stat_buf;	/* stat of mapfile */
227069112eddSAli Bahrami 	int		mapfile_fd;	/* descriptor for mapfile */
227169112eddSAli Bahrami 	int		err;
227269112eddSAli Bahrami 	Mapfile		*mf;		/* Mapfile descriptor */
227369112eddSAli Bahrami 	size_t		name_len;	/* strlen(mapfile) */
227469112eddSAli Bahrami 
227569112eddSAli Bahrami 	/*
227669112eddSAli Bahrami 	 * Determine if we're dealing with a file or a directory.
227769112eddSAli Bahrami 	 */
227869112eddSAli Bahrami 	if (stat(mapfile, &stat_buf) == -1) {
227969112eddSAli Bahrami 		err = errno;
22801007fd6fSAli Bahrami 		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_STAT), mapfile,
22811007fd6fSAli Bahrami 		    strerror(err));
228269112eddSAli Bahrami 		return (FALSE);
228369112eddSAli Bahrami 	}
228469112eddSAli Bahrami 	if (S_ISDIR(stat_buf.st_mode)) {
228569112eddSAli Bahrami 		DIR		*dirp;
228669112eddSAli Bahrami 		struct dirent	*denp;
228769112eddSAli Bahrami 
228869112eddSAli Bahrami 		/*
228969112eddSAli Bahrami 		 * Open the directory and interpret each visible file as a
229069112eddSAli Bahrami 		 * mapfile.
229169112eddSAli Bahrami 		 */
229269112eddSAli Bahrami 		if ((dirp = opendir(mapfile)) == NULL)
229369112eddSAli Bahrami 			return (TRUE);
229469112eddSAli Bahrami 
229569112eddSAli Bahrami 		while ((denp = readdir(dirp)) != NULL) {
229669112eddSAli Bahrami 			char	path[PATH_MAX];
229769112eddSAli Bahrami 
229869112eddSAli Bahrami 			/*
229969112eddSAli Bahrami 			 * Ignore any hidden filenames.  Construct the full
230069112eddSAli Bahrami 			 * pathname to the new mapfile.
230169112eddSAli Bahrami 			 */
230269112eddSAli Bahrami 			if (*denp->d_name == '.')
230369112eddSAli Bahrami 				continue;
230469112eddSAli Bahrami 			(void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_STR_PATH),
230569112eddSAli Bahrami 			    mapfile, denp->d_name);
230669112eddSAli Bahrami 			if (!ld_map_parse(path, ofl))
230769112eddSAli Bahrami 				return (FALSE);
230869112eddSAli Bahrami 		}
230969112eddSAli Bahrami 		(void) closedir(dirp);
231069112eddSAli Bahrami 		return (TRUE);
231169112eddSAli Bahrami 	} else if (!S_ISREG(stat_buf.st_mode)) {
23121007fd6fSAli Bahrami 		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_NOTREG), mapfile);
231369112eddSAli Bahrami 		return (FALSE);
231469112eddSAli Bahrami 	}
231569112eddSAli Bahrami 
231669112eddSAli Bahrami 	/* Open file */
231769112eddSAli Bahrami 	if ((mapfile_fd = open(mapfile, O_RDONLY)) == -1) {
231869112eddSAli Bahrami 		err = errno;
23191007fd6fSAli Bahrami 		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), mapfile,
23201007fd6fSAli Bahrami 		    strerror(err));
232169112eddSAli Bahrami 		return (FALSE);
232269112eddSAli Bahrami 	}
232369112eddSAli Bahrami 
232469112eddSAli Bahrami 	/*
232569112eddSAli Bahrami 	 * Allocate enough memory to hold the state block, mapfile name,
232669112eddSAli Bahrami 	 * and mapfile text. Text has alignment 1, so it can follow the
232769112eddSAli Bahrami 	 * state block without padding.
232869112eddSAli Bahrami 	 */
232969112eddSAli Bahrami 	name_len = strlen(mapfile) + 1;
233069112eddSAli Bahrami 	mf = libld_malloc(sizeof (*mf) + name_len + stat_buf.st_size + 1);
233169112eddSAli Bahrami 	if (mf == NULL)
233269112eddSAli Bahrami 		return (FALSE);
233369112eddSAli Bahrami 	mf->mf_ofl = ofl;
233469112eddSAli Bahrami 	mf->mf_name = (char *)(mf + 1);
233569112eddSAli Bahrami 	(void) strcpy(mf->mf_name, mapfile);
233669112eddSAli Bahrami 	mf->mf_text = mf->mf_name + name_len;
233769112eddSAli Bahrami 	if (read(mapfile_fd, mf->mf_text, stat_buf.st_size) !=
233869112eddSAli Bahrami 	    stat_buf.st_size) {
233969112eddSAli Bahrami 		err = errno;
23401007fd6fSAli Bahrami 		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_READ), mapfile,
23411007fd6fSAli Bahrami 		    strerror(err));
234269112eddSAli Bahrami 		(void) close(mapfile_fd);
234369112eddSAli Bahrami 		return (FALSE);
234469112eddSAli Bahrami 	}
234569112eddSAli Bahrami 	(void) close(mapfile_fd);
234669112eddSAli Bahrami 	mf->mf_text[stat_buf.st_size] = '\0';
234769112eddSAli Bahrami 	mf->mf_next = mf->mf_text;
234869112eddSAli Bahrami 	mf->mf_lineno = 1;
234969112eddSAli Bahrami 	mf->mf_next_ch = 0;		/* No "lookahead" character yet */
235069112eddSAli Bahrami 	mf->mf_ec_insndx = 0;		/* Insert entrace criteria at top */
235169112eddSAli Bahrami 
235269112eddSAli Bahrami 	/*
235369112eddSAli Bahrami 	 * Read just enough from the mapfile to determine the version,
235469112eddSAli Bahrami 	 * and then dispatch to the appropriate code for further processing
235569112eddSAli Bahrami 	 */
235669112eddSAli Bahrami 	if (!mapfile_version(mf))
235769112eddSAli Bahrami 		return (FALSE);
235869112eddSAli Bahrami 
235969112eddSAli Bahrami 	/*
236069112eddSAli Bahrami 	 * Start and continuation masks for unquoted identifier at this
236169112eddSAli Bahrami 	 * mapfile version level.
236269112eddSAli Bahrami 	 */
236369112eddSAli Bahrami 	mf->mf_tkid_start = TKID_ATTR_START(mf->mf_version);
236469112eddSAli Bahrami 	mf->mf_tkid_cont = TKID_ATTR_CONT(mf->mf_version);
236569112eddSAli Bahrami 
236669112eddSAli Bahrami 	DBG_CALL(Dbg_map_parse(ofl->ofl_lml, mapfile, mf->mf_version));
236769112eddSAli Bahrami 
236869112eddSAli Bahrami 	switch (mf->mf_version) {
236969112eddSAli Bahrami 	case MFV_SYSV:
23701007fd6fSAli Bahrami 		/* Guidance: Use newer mapfile syntax */
23711007fd6fSAli Bahrami 		if (OFL_GUIDANCE(ofl, FLG_OFG_NO_MF))
23721007fd6fSAli Bahrami 			ld_eprintf(ofl, ERR_GUIDANCE,
23731007fd6fSAli Bahrami 			    MSG_INTL(MSG_GUIDE_MAPFILE), mapfile);
23741007fd6fSAli Bahrami 
237569112eddSAli Bahrami 		mf->mf_tokdisp = gettok_dispatch_v1;
237669112eddSAli Bahrami 		if (!ld_map_parse_v1(mf))
237769112eddSAli Bahrami 			return (FALSE);
237869112eddSAli Bahrami 		break;
237969112eddSAli Bahrami 
238069112eddSAli Bahrami 	case MFV_SOLARIS:
238169112eddSAli Bahrami 		mf->mf_tokdisp = gettok_dispatch_v2;
238269112eddSAli Bahrami 		STACK_RESET(lms.lms_cdir_stack);
238369112eddSAli Bahrami 
238469112eddSAli Bahrami 		/*
238569112eddSAli Bahrami 		 * If the conditional expression identifier tree has not been
238669112eddSAli Bahrami 		 * initialized, set it up. This is only done on the first
238769112eddSAli Bahrami 		 * mapfile, because the identifier control directives accumulate
238869112eddSAli Bahrami 		 * across all the mapfiles.
238969112eddSAli Bahrami 		 */
239069112eddSAli Bahrami 		if ((lms.lms_cexp_id == NULL) && !cexp_ident_init())
239169112eddSAli Bahrami 			return (FALSE);
239269112eddSAli Bahrami 
239369112eddSAli Bahrami 		/*
239469112eddSAli Bahrami 		 * Tell ld_map_gettoken() we will accept a '$' as starting a
239569112eddSAli Bahrami 		 * control directive on the first call. Normally, they are
239669112eddSAli Bahrami 		 * only allowed after a newline.
239769112eddSAli Bahrami 		 */
239869112eddSAli Bahrami 		lms.lms_cdir_valid = 1;
239969112eddSAli Bahrami 
240069112eddSAli Bahrami 		if (!ld_map_parse_v2(mf))
240169112eddSAli Bahrami 			return (FALSE);
240269112eddSAli Bahrami 
240369112eddSAli Bahrami 		/* Did we leave any open $if control directives? */
240469112eddSAli Bahrami 		if (!STACK_IS_EMPTY(lms.lms_cdir_stack)) {
240569112eddSAli Bahrami 			while (!STACK_IS_EMPTY(lms.lms_cdir_stack)) {
240669112eddSAli Bahrami 				cdir_level_t *level =
240769112eddSAli Bahrami 				    &STACK_POP(lms.lms_cdir_stack);
240869112eddSAli Bahrami 
240969112eddSAli Bahrami 				mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOEND),
241069112eddSAli Bahrami 				    EC_LINENO(level->cdl_if_lineno));
241169112eddSAli Bahrami 			}
241269112eddSAli Bahrami 			return (FALSE);
241369112eddSAli Bahrami 		}
241469112eddSAli Bahrami 		break;
241569112eddSAli Bahrami 	}
241669112eddSAli Bahrami 
241769112eddSAli Bahrami 	return (TRUE);
241869112eddSAli Bahrami }
241969112eddSAli Bahrami 
242069112eddSAli Bahrami /*
242169112eddSAli Bahrami  * Sort the segment list. This is necessary if a mapfile has set explicit
242269112eddSAli Bahrami  * virtual addresses for segments, or defined a SEGMENT_ORDER directive.
242369112eddSAli Bahrami  *
242469112eddSAli Bahrami  * Only PT_LOAD segments can be assigned a virtual address.  These segments can
242569112eddSAli Bahrami  * be one of two types:
242669112eddSAli Bahrami  *
242769112eddSAli Bahrami  *  -	Standard segments for text, data or bss.  These segments will have been
242869112eddSAli Bahrami  *	inserted before the default text (first PT_LOAD) segment.
242969112eddSAli Bahrami  *
243069112eddSAli Bahrami  *  -	Empty (reservation) segments.  These segment will have been inserted at
243169112eddSAli Bahrami  *	the end of any default PT_LOAD segments.
243269112eddSAli Bahrami  *
243369112eddSAli Bahrami  * Any standard segments that are assigned a virtual address will be sorted,
243469112eddSAli Bahrami  * and as their definitions precede any default PT_LOAD segments, these segments
243569112eddSAli Bahrami  * will be assigned sections before any defaults.
243669112eddSAli Bahrami  *
243769112eddSAli Bahrami  * Any reservation segments are also sorted amoung themselves, as these segments
243869112eddSAli Bahrami  * must still follow the standard default segments.
243969112eddSAli Bahrami  */
244069112eddSAli Bahrami static Boolean
244169112eddSAli Bahrami sort_seg_list(Ofl_desc *ofl)
244269112eddSAli Bahrami {
244369112eddSAli Bahrami 	APlist	*sort_segs = NULL, *load_segs = NULL;
244469112eddSAli Bahrami 	Sg_desc	*sgp1;
244569112eddSAli Bahrami 	Aliste	idx1;
244669112eddSAli Bahrami 	Aliste	nsegs;
244769112eddSAli Bahrami 
244869112eddSAli Bahrami 
244969112eddSAli Bahrami 	/*
245069112eddSAli Bahrami 	 * We know the number of elements in the sorted list will be
245169112eddSAli Bahrami 	 * the same as the original, so use this as the initial allocation
245269112eddSAli Bahrami 	 * size for the replacement aplist.
245369112eddSAli Bahrami 	 */
245469112eddSAli Bahrami 	nsegs = aplist_nitems(ofl->ofl_segs);
245569112eddSAli Bahrami 
245669112eddSAli Bahrami 
245769112eddSAli Bahrami 	/* Add the items below SGID_TEXT to the list */
245869112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
245969112eddSAli Bahrami 		if (sgp1->sg_id >= SGID_TEXT)
246069112eddSAli Bahrami 			break;
246169112eddSAli Bahrami 
246269112eddSAli Bahrami 		if (aplist_append(&sort_segs, sgp1, nsegs) == NULL)
246369112eddSAli Bahrami 				return (FALSE);
246469112eddSAli Bahrami 	}
246569112eddSAli Bahrami 
246669112eddSAli Bahrami 	/*
246769112eddSAli Bahrami 	 * If there are any SEGMENT_ORDER items, add them, and set their
246869112eddSAli Bahrami 	 * FLG_SG_ORDERED flag to identify them in debug output, and to
246969112eddSAli Bahrami 	 * prevent them from being added again below.
247069112eddSAli Bahrami 	 */
247169112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_segs_order, idx1, sgp1)) {
247269112eddSAli Bahrami 		if (aplist_append(&sort_segs, sgp1, nsegs) == NULL)
247369112eddSAli Bahrami 			return (FALSE);
247469112eddSAli Bahrami 		sgp1->sg_flags |= FLG_SG_ORDERED;
247569112eddSAli Bahrami 	}
247669112eddSAli Bahrami 
247769112eddSAli Bahrami 	/*
247869112eddSAli Bahrami 	 * Add the loadable segments to another list in sorted order.
247969112eddSAli Bahrami 	 */
248069112eddSAli Bahrami 	DBG_CALL(Dbg_map_sort_title(ofl->ofl_lml, TRUE));
248169112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
248269112eddSAli Bahrami 		DBG_CALL(Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS,
248369112eddSAli Bahrami 		    ld_targ.t_m.m_mach, sgp1));
248469112eddSAli Bahrami 
248569112eddSAli Bahrami 		/* Only interested in PT_LOAD items not in SEGMENT_ORDER list */
248669112eddSAli Bahrami 		if ((sgp1->sg_phdr.p_type != PT_LOAD) ||
248769112eddSAli Bahrami 		    (sgp1->sg_flags & FLG_SG_ORDERED))
248869112eddSAli Bahrami 			continue;
248969112eddSAli Bahrami 
249069112eddSAli Bahrami 		/*
249169112eddSAli Bahrami 		 * If the loadable segment does not contain a vaddr, simply
249269112eddSAli Bahrami 		 * append it to the new list.
249369112eddSAli Bahrami 		 */
249469112eddSAli Bahrami 		if ((sgp1->sg_flags & FLG_SG_P_VADDR) == 0) {
249569112eddSAli Bahrami 			if (aplist_append(&load_segs, sgp1, AL_CNT_SEGMENTS) ==
249669112eddSAli Bahrami 			    NULL)
249769112eddSAli Bahrami 				return (FALSE);
249869112eddSAli Bahrami 
249969112eddSAli Bahrami 		} else {
250069112eddSAli Bahrami 			Aliste		idx2;
250169112eddSAli Bahrami 			Sg_desc		*sgp2;
250269112eddSAli Bahrami 			int		inserted = 0;
250369112eddSAli Bahrami 
250469112eddSAli Bahrami 			/*
250569112eddSAli Bahrami 			 * Traverse the segment list we are creating, looking
250669112eddSAli Bahrami 			 * for a segment that defines a vaddr.
250769112eddSAli Bahrami 			 */
250869112eddSAli Bahrami 			for (APLIST_TRAVERSE(load_segs, idx2, sgp2)) {
250969112eddSAli Bahrami 				/*
251069112eddSAli Bahrami 				 * Any real segments that contain vaddr's need
251169112eddSAli Bahrami 				 * to be sorted.  Any reservation segments also
251269112eddSAli Bahrami 				 * need to be sorted.  However, any reservation
251369112eddSAli Bahrami 				 * segments should be placed after any real
251469112eddSAli Bahrami 				 * segments.
251569112eddSAli Bahrami 				 */
251669112eddSAli Bahrami 				if (((sgp2->sg_flags &
251769112eddSAli Bahrami 				    (FLG_SG_P_VADDR | FLG_SG_EMPTY)) == 0) &&
251869112eddSAli Bahrami 				    (sgp1->sg_flags & FLG_SG_EMPTY))
251969112eddSAli Bahrami 					continue;
252069112eddSAli Bahrami 
252169112eddSAli Bahrami 				if ((sgp2->sg_flags & FLG_SG_P_VADDR) &&
252269112eddSAli Bahrami 				    ((sgp2->sg_flags & FLG_SG_EMPTY) ==
252369112eddSAli Bahrami 				    (sgp1->sg_flags & FLG_SG_EMPTY))) {
252469112eddSAli Bahrami 					if (sgp1->sg_phdr.p_vaddr ==
252569112eddSAli Bahrami 					    sgp2->sg_phdr.p_vaddr) {
25261007fd6fSAli Bahrami 						ld_eprintf(ofl, ERR_FATAL,
252769112eddSAli Bahrami 						    MSG_INTL(MSG_MAP_SEGSAME),
252869112eddSAli Bahrami 						    sgp1->sg_name,
252969112eddSAli Bahrami 						    sgp2->sg_name);
253069112eddSAli Bahrami 						return (FALSE);
253169112eddSAli Bahrami 					}
253269112eddSAli Bahrami 
253369112eddSAli Bahrami 					if (sgp1->sg_phdr.p_vaddr >
253469112eddSAli Bahrami 					    sgp2->sg_phdr.p_vaddr)
253569112eddSAli Bahrami 						continue;
253669112eddSAli Bahrami 				}
253769112eddSAli Bahrami 
253869112eddSAli Bahrami 				/*
253969112eddSAli Bahrami 				 * Insert this segment before the segment on
254069112eddSAli Bahrami 				 * the load_segs list.
254169112eddSAli Bahrami 				 */
254269112eddSAli Bahrami 				if (aplist_insert(&load_segs, sgp1,
254369112eddSAli Bahrami 				    AL_CNT_SEGMENTS, idx2) == NULL)
254469112eddSAli Bahrami 					return (FALSE);
254569112eddSAli Bahrami 				inserted = 1;
254669112eddSAli Bahrami 				break;
254769112eddSAli Bahrami 			}
254869112eddSAli Bahrami 
254969112eddSAli Bahrami 			/*
255069112eddSAli Bahrami 			 * If the segment being inspected has not been inserted
255169112eddSAli Bahrami 			 * in the segment list, simply append it to the list.
255269112eddSAli Bahrami 			 */
255369112eddSAli Bahrami 			if ((inserted == 0) && (aplist_append(&load_segs,
255469112eddSAli Bahrami 			    sgp1, AL_CNT_SEGMENTS) == NULL))
255569112eddSAli Bahrami 				return (FALSE);
255669112eddSAli Bahrami 		}
255769112eddSAli Bahrami 	}
255869112eddSAli Bahrami 
255969112eddSAli Bahrami 	/*
256069112eddSAli Bahrami 	 * Add the sorted loadable segments to our initial segment list.
256169112eddSAli Bahrami 	 */
256269112eddSAli Bahrami 	for (APLIST_TRAVERSE(load_segs, idx1, sgp1)) {
256369112eddSAli Bahrami 		if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL)
256469112eddSAli Bahrami 			return (FALSE);
256569112eddSAli Bahrami 	}
256669112eddSAli Bahrami 
256769112eddSAli Bahrami 	/*
256869112eddSAli Bahrami 	 * Add all other segments to our list.
256969112eddSAli Bahrami 	 */
257069112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
257169112eddSAli Bahrami 		if ((sgp1->sg_id < SGID_TEXT) ||
257269112eddSAli Bahrami 		    (sgp1->sg_phdr.p_type == PT_LOAD) ||
257369112eddSAli Bahrami 		    (sgp1->sg_flags & FLG_SG_ORDERED))
257469112eddSAli Bahrami 			continue;
257569112eddSAli Bahrami 
257669112eddSAli Bahrami 		if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL)
257769112eddSAli Bahrami 			return (FALSE);
257869112eddSAli Bahrami 	}
257969112eddSAli Bahrami 
258069112eddSAli Bahrami 	/*
258169112eddSAli Bahrami 	 * Free the original list, and the pt_load list, and use
258269112eddSAli Bahrami 	 * the new list as the segment list.
258369112eddSAli Bahrami 	 */
258469112eddSAli Bahrami 	free(ofl->ofl_segs);
258569112eddSAli Bahrami 	if (load_segs) free(load_segs);
258669112eddSAli Bahrami 	ofl->ofl_segs = sort_segs;
258769112eddSAli Bahrami 
258869112eddSAli Bahrami 	if (DBG_ENABLED) {
258969112eddSAli Bahrami 		Dbg_map_sort_title(ofl->ofl_lml, FALSE);
259069112eddSAli Bahrami 		for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
259169112eddSAli Bahrami 			Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS,
259269112eddSAli Bahrami 			    ld_targ.t_m.m_mach, sgp1);
259369112eddSAli Bahrami 			}
259469112eddSAli Bahrami 		}
259569112eddSAli Bahrami 
259669112eddSAli Bahrami 	return (TRUE);
259769112eddSAli Bahrami }
259869112eddSAli Bahrami 
259969112eddSAli Bahrami /*
260069112eddSAli Bahrami  * After all mapfiles have been processed, this routine is used to
260169112eddSAli Bahrami  * finish any remaining mapfile related work.
260269112eddSAli Bahrami  *
260369112eddSAli Bahrami  * exit:
260469112eddSAli Bahrami  *	Returns TRUE on success, and FALSE on failure.
260569112eddSAli Bahrami  */
260669112eddSAli Bahrami Boolean
260769112eddSAli Bahrami ld_map_post_process(Ofl_desc *ofl)
260869112eddSAli Bahrami {
260969112eddSAli Bahrami 	Aliste		idx, idx2;
261069112eddSAli Bahrami 	Is_desc		*isp;
261169112eddSAli Bahrami 	Sg_desc		*sgp;
261269112eddSAli Bahrami 	Ent_desc	*enp;
261369112eddSAli Bahrami 	Sg_desc		*first_seg = NULL;
261469112eddSAli Bahrami 
261569112eddSAli Bahrami 
261669112eddSAli Bahrami 	DBG_CALL(Dbg_map_post_title(ofl->ofl_lml));
261769112eddSAli Bahrami 
261869112eddSAli Bahrami 	/*
261969112eddSAli Bahrami 	 * Per-segment processing:
262069112eddSAli Bahrami 	 * -	Identify segments with explicit virtual address
262169112eddSAli Bahrami 	 * -	Details of input and output section order
262269112eddSAli Bahrami 	 */
262369112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) {
262469112eddSAli Bahrami 		/*
262569112eddSAli Bahrami 		 * We are looking for segments. Program headers that represent
262669112eddSAli Bahrami 		 * segments are required to have a non-NULL name pointer,
262769112eddSAli Bahrami 		 * while that those that do not are required to have a
262869112eddSAli Bahrami 		 * NULL name pointer.
262969112eddSAli Bahrami 		 */
263069112eddSAli Bahrami 		if (sgp->sg_name == NULL)
263169112eddSAli Bahrami 			continue;
263269112eddSAli Bahrami 
263369112eddSAli Bahrami 		/* Remember the first non-disabled segment */
263469112eddSAli Bahrami 		if ((first_seg == NULL) && !(sgp->sg_flags & FLG_SG_DISABLED))
263569112eddSAli Bahrami 			first_seg = sgp;
263669112eddSAli Bahrami 
263769112eddSAli Bahrami 		/*
263869112eddSAli Bahrami 		 * If a segment has an explicit virtual address, we will
263969112eddSAli Bahrami 		 * need to sort the segments.
264069112eddSAli Bahrami 		 */
264169112eddSAli Bahrami 		if (sgp->sg_flags & FLG_SG_P_VADDR)
264269112eddSAli Bahrami 			ofl->ofl_flags1 |= FLG_OF1_VADDR;
264369112eddSAli Bahrami 
264469112eddSAli Bahrami 		/*
264569112eddSAli Bahrami 		 * The FLG_OF_OS_ORDER flag enables the code that does
264669112eddSAli Bahrami 		 * output section ordering. Set if the segment has
264769112eddSAli Bahrami 		 * a non-empty output section order list.
264869112eddSAli Bahrami 		 */
264969112eddSAli Bahrami 		if (alist_nitems(sgp->sg_os_order) > 0)
265069112eddSAli Bahrami 			ofl->ofl_flags |= FLG_OF_OS_ORDER;
265169112eddSAli Bahrami 
265269112eddSAli Bahrami 		/*
265369112eddSAli Bahrami 		 * The version 1 and version 2 syntaxes for input section
265469112eddSAli Bahrami 		 * ordering are different and incompatible enough that we
265569112eddSAli Bahrami 		 * only allow the use of one or the other for a given segment:
265669112eddSAli Bahrami 		 *
265769112eddSAli Bahrami 		 * v1)	The version 1 syntax has the user set the ?O flag on
265869112eddSAli Bahrami 		 *	the segment. If this is done, all input sections placed
265969112eddSAli Bahrami 		 *	via an entrance criteria that has a section name are to
266069112eddSAli Bahrami 		 *	be sorted, using the order of the entrance criteria
266169112eddSAli Bahrami 		 *	as the sort key.
266269112eddSAli Bahrami 		 *
266369112eddSAli Bahrami 		 * v2)	The version 2 syntax has the user specify a name for
266469112eddSAli Bahrami 		 * 	the entry criteria, and then provide a list of entry
266569112eddSAli Bahrami 		 * 	criteria names via the IS_ORDER segment attribute.
266669112eddSAli Bahrami 		 * 	Sections placed via the criteria listed in IS_ORDER
266769112eddSAli Bahrami 		 * 	are sorted, and the others are not.
266869112eddSAli Bahrami 		 *
266969112eddSAli Bahrami 		 * Regardless of the syntax version used, the section sorting
267069112eddSAli Bahrami 		 * code expects the following:
267169112eddSAli Bahrami 		 *
267269112eddSAli Bahrami 		 * -	Segments requiring input section sorting have the
267369112eddSAli Bahrami 		 *	FLG_SG_IS_ORDER flag set
267469112eddSAli Bahrami 		 *
267569112eddSAli Bahrami 		 * -	Entrance criteria referencing the segment that
267669112eddSAli Bahrami 		 *	participate in input section sorting have a non-zero
267769112eddSAli Bahrami 		 *	sort key in their ec_ordndx field.
267869112eddSAli Bahrami 		 *
267969112eddSAli Bahrami 		 * At this point, the following are true:
268069112eddSAli Bahrami 		 *
268169112eddSAli Bahrami 		 * -	All entrance criteria have ec_ordndx set to 0.
268269112eddSAli Bahrami 		 * -	Segments that require the version 1 behavior have
268369112eddSAli Bahrami 		 *	the FLG_SG_IS_ORDER flag set, and the segments
268469112eddSAli Bahrami 		 *	sg_is_order list is empty.
268569112eddSAli Bahrami 		 * -	Segments that require the version 2 behavior do not
268669112eddSAli Bahrami 		 *	have FLG_SG_IS_ORDER set, and the sg_is_order list is
268769112eddSAli Bahrami 		 *	non-empty. This list contains the names of the entrance
268869112eddSAli Bahrami 		 *	criteria that will participate in input section sorting,
268969112eddSAli Bahrami 		 *	and their relative order in the list provides the
269069112eddSAli Bahrami 		 *	sort key to use.
269169112eddSAli Bahrami 		 *
269269112eddSAli Bahrami 		 * We must detect these two cases, set the FLG_SG_IS_ORDER
269369112eddSAli Bahrami 		 * flag as necessary, and fill in all entrance criteria
269469112eddSAli Bahrami 		 * sort keys. If any input section sorting is to be done,
269569112eddSAli Bahrami 		 * we also set the FLG_OF_IS_ORDER flag on the output descriptor
269669112eddSAli Bahrami 		 * to enable the code that does that work.
269769112eddSAli Bahrami 		 */
269869112eddSAli Bahrami 
269969112eddSAli Bahrami 		/* Version 1: ?O flag? */
270069112eddSAli Bahrami 		if (sgp->sg_flags & FLG_SG_IS_ORDER) {
270169112eddSAli Bahrami 			Word	index = 0;
270269112eddSAli Bahrami 
270369112eddSAli Bahrami 			ofl->ofl_flags |= FLG_OF_IS_ORDER;
270469112eddSAli Bahrami 			DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml,
270569112eddSAli Bahrami 			    sgp->sg_name));
270669112eddSAli Bahrami 
270769112eddSAli Bahrami 			/*
270869112eddSAli Bahrami 			 * Give each user defined entrance criteria for this
270969112eddSAli Bahrami 			 * segment that specifies a section name a
271069112eddSAli Bahrami 			 * monotonically increasing sort key.
271169112eddSAli Bahrami 			 */
271269112eddSAli Bahrami 			for (APLIST_TRAVERSE(ofl->ofl_ents, idx2, enp))
271369112eddSAli Bahrami 				if ((enp->ec_segment == sgp) &&
271469112eddSAli Bahrami 				    (enp->ec_is_name != NULL) &&
271569112eddSAli Bahrami 				    ((enp->ec_flags & FLG_EC_BUILTIN) == 0))
271669112eddSAli Bahrami 					enp->ec_ordndx = ++index;
271769112eddSAli Bahrami 			continue;
271869112eddSAli Bahrami 		}
271969112eddSAli Bahrami 
272069112eddSAli Bahrami 		/* Version 2: SEGMENT IS_ORDER list? */
272169112eddSAli Bahrami 		if (aplist_nitems(sgp->sg_is_order) > 0) {
272269112eddSAli Bahrami 			Word	index = 0;
272369112eddSAli Bahrami 
272469112eddSAli Bahrami 			ofl->ofl_flags |= FLG_OF_IS_ORDER;
272569112eddSAli Bahrami 			DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml,
272669112eddSAli Bahrami 			    sgp->sg_name));
272769112eddSAli Bahrami 
272869112eddSAli Bahrami 			/*
272969112eddSAli Bahrami 			 * Give each entrance criteria in the sg_is_order
273069112eddSAli Bahrami 			 * list a monotonically increasing sort key.
273169112eddSAli Bahrami 			 */
273269112eddSAli Bahrami 			for (APLIST_TRAVERSE(sgp->sg_is_order, idx2, enp)) {
273369112eddSAli Bahrami 				enp->ec_ordndx = ++index;
273469112eddSAli Bahrami 				enp->ec_segment->sg_flags |= FLG_SG_IS_ORDER;
273569112eddSAli Bahrami 			}
273669112eddSAli Bahrami 		}
273769112eddSAli Bahrami 	}
273869112eddSAli Bahrami 
273969112eddSAli Bahrami 	/* Sort the segment descriptors if necessary */
274069112eddSAli Bahrami 	if (((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
274169112eddSAli Bahrami 	    (aplist_nitems(ofl->ofl_segs_order) > 0)) &&
274269112eddSAli Bahrami 	    !sort_seg_list(ofl))
274369112eddSAli Bahrami 		return (FALSE);
274469112eddSAli Bahrami 
274569112eddSAli Bahrami 	/*
274669112eddSAli Bahrami 	 * If the output file is a static file without an interpreter, and
274769112eddSAli Bahrami 	 * if any virtual address is specified, then set the NOHDR flag for
274869112eddSAli Bahrami 	 * backward compatibility.
274969112eddSAli Bahrami 	 */
275069112eddSAli Bahrami 	if (!(ofl->ofl_flags & (FLG_OF_DYNAMIC | FLG_OF_RELOBJ)) &&
275169112eddSAli Bahrami 	    !(ofl->ofl_osinterp) && (ofl->ofl_flags1 & FLG_OF1_VADDR))
275269112eddSAli Bahrami 		ofl->ofl_dtflags_1 |= DF_1_NOHDR;
275369112eddSAli Bahrami 
275469112eddSAli Bahrami 	if (ofl->ofl_flags & FLG_OF_RELOBJ) {
275569112eddSAli Bahrami 		/*
275669112eddSAli Bahrami 		 * NOHDR has no effect on a relocatable file.
275769112eddSAli Bahrami 		 * Make sure this flag isn't set.
275869112eddSAli Bahrami 		 */
275969112eddSAli Bahrami 		ofl->ofl_dtflags_1 &= ~DF_1_NOHDR;
276069112eddSAli Bahrami 	} else if (first_seg != NULL) {
276169112eddSAli Bahrami 		/*
276269112eddSAli Bahrami 		 * DF_1_NOHDR might have been set globally by the HDR_NOALLOC
276369112eddSAli Bahrami 		 * directive. If not, then we want to check the per-segment
276469112eddSAli Bahrami 		 * flag for the first loadable segment and propagate it
276569112eddSAli Bahrami 		 * if set.
276669112eddSAli Bahrami 		 */
276769112eddSAli Bahrami 		if ((ofl->ofl_dtflags_1 & DF_1_NOHDR) == 0) {
276869112eddSAli Bahrami 			/*
276969112eddSAli Bahrami 			 * If we sorted the segments, the first segment
277069112eddSAli Bahrami 			 * may have changed.
277169112eddSAli Bahrami 			 */
277269112eddSAli Bahrami 			if ((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
277369112eddSAli Bahrami 			    (aplist_nitems(ofl->ofl_segs_order) > 0)) {
277469112eddSAli Bahrami 				for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) {
277569112eddSAli Bahrami 					if (sgp->sg_name == NULL)
277669112eddSAli Bahrami 						continue;
277769112eddSAli Bahrami 					if ((sgp->sg_flags & FLG_SG_DISABLED) ==
277869112eddSAli Bahrami 					    0) {
277969112eddSAli Bahrami 						first_seg = sgp;
278069112eddSAli Bahrami 						break;
278169112eddSAli Bahrami 					}
278269112eddSAli Bahrami 				}
278369112eddSAli Bahrami 			}
278469112eddSAli Bahrami 
278569112eddSAli Bahrami 			/*
278669112eddSAli Bahrami 			 * If the per-segment NOHDR flag is set on our first
278769112eddSAli Bahrami 			 * segment, then make it take effect.
278869112eddSAli Bahrami 			 */
278969112eddSAli Bahrami 			if (first_seg->sg_flags & FLG_SG_NOHDR)
279069112eddSAli Bahrami 				ofl->ofl_dtflags_1 |= DF_1_NOHDR;
279169112eddSAli Bahrami 		}
279269112eddSAli Bahrami 
279369112eddSAli Bahrami 		/*
279469112eddSAli Bahrami 		 * For executable and shared objects, the first segment must
279569112eddSAli Bahrami 		 * be loadable unless NOHDR was specified, because the ELF
279669112eddSAli Bahrami 		 * header must simultaneously lie at offset 0 of the file and
279769112eddSAli Bahrami 		 * be included in the first loadable segment. This isn't
279869112eddSAli Bahrami 		 * possible if some other segment type starts the file
279969112eddSAli Bahrami 		 */
280069112eddSAli Bahrami 		if (!(ofl->ofl_dtflags_1 & DF_1_NOHDR) &&
280169112eddSAli Bahrami 		    (first_seg->sg_phdr.p_type != PT_LOAD)) {
280269112eddSAli Bahrami 			Conv_inv_buf_t	inv_buf;
280369112eddSAli Bahrami 
28041007fd6fSAli Bahrami 			ld_eprintf(ofl, ERR_FATAL,
280569112eddSAli Bahrami 			    MSG_INTL(MSG_SEG_FIRNOTLOAD),
280669112eddSAli Bahrami 			    conv_phdr_type(ELFOSABI_SOLARIS, ld_targ.t_m.m_mach,
280769112eddSAli Bahrami 			    first_seg->sg_phdr.p_type, 0, &inv_buf),
280869112eddSAli Bahrami 			    first_seg->sg_name);
280969112eddSAli Bahrami 			return (FALSE);
281069112eddSAli Bahrami 		}
281169112eddSAli Bahrami 	}
281269112eddSAli Bahrami 
281369112eddSAli Bahrami 	/*
281469112eddSAli Bahrami 	 * Mapfiles may have been used to create symbol definitions
281569112eddSAli Bahrami 	 * with backing storage.  Although the backing storage is
281669112eddSAli Bahrami 	 * associated with an input section, the association of the
281769112eddSAli Bahrami 	 * section to an output section (and segment) is initially
281869112eddSAli Bahrami 	 * deferred.  Now that all mapfile processing is complete, any
281969112eddSAli Bahrami 	 * entrance criteria requirements have been processed, and
282069112eddSAli Bahrami 	 * these backing storage sections can be associated with the
282169112eddSAli Bahrami 	 * appropriate output section (and segment).
282269112eddSAli Bahrami 	 */
282369112eddSAli Bahrami 	if (ofl->ofl_maptext || ofl->ofl_mapdata)
282469112eddSAli Bahrami 		DBG_CALL(Dbg_sec_backing(ofl->ofl_lml));
282569112eddSAli Bahrami 
282669112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_maptext, idx, isp)) {
282769112eddSAli Bahrami 		if (ld_place_section(ofl, isp, NULL,
282869112eddSAli Bahrami 		    ld_targ.t_id.id_text, NULL) == (Os_desc *)S_ERROR)
282969112eddSAli Bahrami 			return (FALSE);
283069112eddSAli Bahrami 	}
283169112eddSAli Bahrami 
283269112eddSAli Bahrami 	for (APLIST_TRAVERSE(ofl->ofl_mapdata, idx, isp)) {
283369112eddSAli Bahrami 		if (ld_place_section(ofl, isp, NULL,
283469112eddSAli Bahrami 		    ld_targ.t_id.id_data, NULL) == (Os_desc *)S_ERROR)
283569112eddSAli Bahrami 			return (FALSE);
283669112eddSAli Bahrami 	}
283769112eddSAli Bahrami 
283869112eddSAli Bahrami 	return (TRUE);
283969112eddSAli Bahrami }
2840