xref: /illumos-gate/usr/src/cmd/sgs/libld/common/map_v2.c (revision 6ba597c5)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Map file parsing, Version 2 syntax (solaris).
29  */
30 #include	<stdio.h>
31 #include	<unistd.h>
32 #include	<ctype.h>
33 #include	<sys/elf_amd64.h>   /* SHF_AMD64_LARGE */
34 #include	<elfcap.h>
35 #include	"msg.h"
36 #include	"_libld.h"
37 #include	"_map.h"
38 
39 /*
40  * Use a case insensitive string match when looking up capability mask
41  * values by name, and omit the AV_ prefix.
42  */
43 #define	ELFCAP_STYLE ELFCAP_STYLE_LC | ELFCAP_STYLE_F_ICMP
44 
45 /*
46  * Signature for functions used to parse top level mapfile directives
47  */
48 typedef Token (*dir_func_t)(Mapfile *mf);
49 
50 /*
51  * Signature for functions used to parse attribute level assignments
52  *	mf - Mapfile descriptor
53  *	eq_tok - One of the equal tokens (TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ)
54  *		or TK_ERROR. See the comment for attr_fmt_t below.
55  *	uvalue - An arbitrary pointer "user value" passed by the
56  *		caller to parse_attributes() for use by the function.
57  */
58 typedef Token (* attr_func_t)(Mapfile *mf, Token eq_tok, void *uvalue);
59 
60 /*
61  * Signature for gettoken_str() err_func argument. This is a function
62  * called to issue an appropriate error message.
63  *
64  * The gts prefix stands for "Get Token Str"
65  */
66 typedef void (* gts_efunc_t)(Mapfile *mf, Token tok, ld_map_tkval_t *tkv);
67 
68 /*
69  * The attr_fmt_t tells parse_attributes how far to go in parsing
70  * an attribute before it calls the at_func function to take over:
71  *
72  *	ATTR_FMT_NAME - Parse the name, and immediately call the function.
73  *		This is useful in cases where there is more than
74  *		one possible syntax for a given attribute. The value of
75  *		eq_tok passed to the at_func function will be TK_ERROR,
76  *		reflecting the fact that it has no meaning in this context.
77  *
78  *	ATTR_FMT_EQ - Parse the name, and the following '=', and then call
79  *		the function. The value passed to the at_func function for
80  *		eq_tok will be TK_EQUAL.
81  *
82  *	ATTR_FMT_EQ_PEQ - Parse the name, and a following equal token which
83  *		can be '=' or '+=', and then call the function. The value
84  *		passed to the at_func function for eq_tok will be one of
85  *		TK_EQUAL, or TK_PLUSEQ.
86  *
87  *	ATTR_FMT_EQ_ALL - Parse the name, and a following equal token which
88  *		can be any of the three forms (=, +=, -=), and then call
89  *		the function. The value passed to the at_func function for
90  *		eq_tok will be one of TK_EQUAL, TK_PLUSEQ, or TK_MINUSEQ.
91  */
92 typedef enum {
93 	ATTR_FMT_NAME,
94 	ATTR_FMT_EQ,
95 	ATTR_FMT_EQ_PEQ,
96 	ATTR_FMT_EQ_ALL,
97 } attr_fmt_t;
98 
99 /*
100  * Type used to describe a set of valid attributes to parse_attributes():
101  *	at_name - Name of attribute
102  *	at_func - Function to call when attribute is recognized,
103  *	at_all_eq - True if attribute allows the '+=' and '-=' forms of
104  *		assignment token, and False to only allow '='.
105  *
106  * The array of these structs passed to parse_attributes() must be
107  * NULL terminated (the at_name field must be set to NULL).
108  */
109 typedef struct {
110 	const char	*at_name;	/* Name of attribute */
111 	attr_func_t	at_func;	/* Function to call */
112 	attr_fmt_t	at_fmt;		/* How much to parse before calling */
113 					/*	at_func */
114 } attr_t;
115 
116 /*
117  * Mapfile version and symbol state are separate but related concepts
118  * that are best represented using two different types. However, our
119  * style of passing a single uvalue via parse_attributes() makes it
120  * convenient to be able to reference them from a single address.
121  */
122 typedef struct {
123 	ld_map_ver_t	ss_mv;
124 	ld_map_sym_t	ss_ms;
125 } symbol_state_t;
126 
127 /*
128  * Process an expected equal operator. Deals with the fact that we
129  * have three variants.
130  *
131  * entry:
132  *	mf - Mapfile descriptor
133  *	eq_type - Types of equal operators accepted. One of ATTR_FMT_EQ,
134  *		ATTR_FMT_EQ_PEQ, or ATTR_FMT_EQ_ALL.
135  *	lhs - Name that appears on the left hand side of the expected
136  *		equal operator.
137  *
138  * exit:
139  *	Returns one of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, or TK_ERROR.
140  */
141 static Token
142 gettoken_eq(Mapfile *mf, attr_fmt_t eq_type, const char *lhs)
143 {
144 	Token		tok;
145 	ld_map_tkval_t	tkv;
146 	const char	*err;
147 	Conv_inv_buf_t	inv_buf;
148 
149 	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
150 	case TK_ERROR:
151 	case TK_EQUAL:
152 		return (tok);
153 
154 	case TK_PLUSEQ:
155 		switch (eq_type) {
156 		case ATTR_FMT_EQ_PEQ:
157 		case ATTR_FMT_EQ_ALL:
158 			return (tok);
159 		}
160 		break;
161 
162 	case TK_MINUSEQ:
163 		if (eq_type == ATTR_FMT_EQ_ALL)
164 			return (tok);
165 		break;
166 	}
167 
168 	switch (eq_type) {
169 	case ATTR_FMT_EQ:
170 		err = MSG_INTL(MSG_MAP_EXP_EQ);
171 		break;
172 	case ATTR_FMT_EQ_PEQ:
173 		err = MSG_INTL(MSG_MAP_EXP_EQ_PEQ);
174 		break;
175 	case ATTR_FMT_EQ_ALL:
176 		err = MSG_INTL(MSG_MAP_EXP_EQ_ALL);
177 		break;
178 	default:
179 		/*NOTREACHED*/
180 		assert(0);
181 	}
182 	mf_fatal(mf, err, lhs, ld_map_tokenstr(tok, &tkv, &inv_buf));
183 	return (TK_ERROR);
184 }
185 
186 /*
187  * Apply one of the three equal tokens to a bitmask value
188  *
189  * entry:
190  *	dst - Address of bitmask variable to alter
191  *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
192  *		the operation to carry out.
193  *	value - Value for right hand side
194  *
195  * exit:
196  *	The operation has been carried out:
197  *
198  *	TK_EQUAL - *dst is set to value
199  *	TK_PLUSEQ - Bits in value have been set in *dst
200  *	TK_MINUSEQ - Bits in value have been removed from *dst
201  */
202 static void
203 setflags_eq(Word *dst, Token eq_tok, Word value)
204 {
205 	switch (eq_tok) {
206 	case TK_EQUAL:
207 		*dst = value;
208 		break;
209 	case TK_PLUSEQ:
210 		*dst |= value;
211 		break;
212 	case TK_MINUSEQ:
213 		*dst &= ~value;
214 		break;
215 	default:
216 		/*NOTREACHED*/
217 		assert(0);
218 	}
219 }
220 
221 /*
222  * Apply one of the three equal tokens to a capabilities CapMask.
223  *
224  * entry:
225  *	mf - Mapfile descriptor
226  *	capmask - Address of CapMask variable to alter
227  *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
228  *		the operation to carry out.
229  *	type - Capability type (CA_SUNW_*)
230  *	value - Value for right hand side
231  *	title - True if a title is needed, False otherwise.
232  *
233  * exit:
234  *	On success, returns TRUE (1), otherwise FALSE (0)
235  */
236 static Boolean
237 set_capmask(Mapfile *mf, CapMask *capmask, Token eq_tok,
238     Word type, elfcap_mask_t value, Boolean title)
239 {
240 	if (title)
241 		DBG_CALL(Dbg_cap_mapfile_title(mf->mf_ofl->ofl_lml,
242 		    mf->mf_lineno));
243 	DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml, DBG_STATE_CURRENT,
244 	    type, capmask, ld_targ.t_m.m_mach));
245 
246 	switch (eq_tok) {
247 	case TK_EQUAL:
248 		capmask->cm_value = value;
249 		capmask->cm_exclude = 0;
250 		ld_map_cap_set_ovflag(mf, type);
251 		DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml,
252 		    DBG_STATE_RESET, type, capmask, ld_targ.t_m.m_mach));
253 		break;
254 	case TK_PLUSEQ:
255 		DBG_CALL(Dbg_cap_entry(mf->mf_ofl->ofl_lml, DBG_STATE_ADD,
256 		    type, value, ld_targ.t_m.m_mach));
257 		capmask->cm_value |= value;
258 		capmask->cm_exclude &= ~value;
259 		break;
260 	case TK_MINUSEQ:
261 		DBG_CALL(Dbg_cap_entry(mf->mf_ofl->ofl_lml, DBG_STATE_EXCLUDE,
262 		    type, value, ld_targ.t_m.m_mach));
263 		capmask->cm_value &= ~value;
264 		capmask->cm_exclude |= value;
265 		break;
266 	default:
267 		/*NOTREACHED*/
268 		assert(0);
269 	}
270 
271 	/* Sanity check the resulting bits */
272 	if (!ld_map_cap_sanitize(mf, type, capmask))
273 		return (FALSE);
274 
275 	/* Report the final configuration */
276 	DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml,
277 	    DBG_STATE_RESOLVED, type, capmask, ld_targ.t_m.m_mach));
278 
279 	return (TRUE);
280 }
281 
282 /*
283  * Process the next token, which is expected to start an optional
284  * nesting of attributes (';' or '{').
285  *
286  * entry:
287  *	mf - Mapfile descriptor
288  *	lhs - Name of the directive or attribute being processed.
289  *
290  * exit:
291  *	Returns TK_SEMICOLON or TK_LEFTBKT for success, and TK_ERROR otherwise.
292  */
293 static Token
294 gettoken_optattr(Mapfile *mf, const char *lhs)
295 {
296 	Token		tok;
297 	ld_map_tkval_t	tkv;
298 	Conv_inv_buf_t	inv_buf;
299 
300 	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
301 	case TK_ERROR:
302 	case TK_SEMICOLON:
303 	case TK_LEFTBKT:
304 		return (tok);
305 	}
306 
307 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMLBKT), lhs,
308 	    ld_map_tokenstr(tok, &tkv, &inv_buf));
309 	return (TK_ERROR);
310 }
311 
312 /*
313  * Process the next token, which is expected to be a line terminator
314  * (';' or '}').
315  *
316  * entry:
317  *	mf - Mapfile descriptor
318  *	lhs - Name of the directive or attribute being processed.
319  *
320  * exit:
321  *	Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
322  */
323 static Token
324 gettoken_term(Mapfile *mf, const char *lhs)
325 {
326 	Token		tok;
327 	ld_map_tkval_t	tkv;
328 	Conv_inv_buf_t	inv_buf;
329 
330 	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
331 	case TK_ERROR:
332 	case TK_SEMICOLON:
333 	case TK_RIGHTBKT:
334 		return (tok);
335 	}
336 
337 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMRBKT), lhs,
338 	    ld_map_tokenstr(tok, &tkv, &inv_buf));
339 	return (TK_ERROR);
340 }
341 
342 /*
343  * Process the next token, which is expected to be a semicolon.
344  *
345  * entry:
346  *	mf - Mapfile descriptor
347  *	lhs - Name of the directive or attribute being processed.
348  *
349  * exit:
350  *	Returns TK_SEMICOLON for success, and TK_ERROR otherwise.
351  */
352 static Token
353 gettoken_semicolon(Mapfile *mf, const char *lhs)
354 {
355 	Token		tok;
356 	ld_map_tkval_t	tkv;
357 	Conv_inv_buf_t	inv_buf;
358 
359 	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
360 	case TK_ERROR:
361 	case TK_SEMICOLON:
362 		return (tok);
363 	}
364 
365 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEM), lhs,
366 	    ld_map_tokenstr(tok, &tkv, &inv_buf));
367 	return (TK_ERROR);
368 }
369 
370 /*
371  * Process the next token, which is expected to be a '{'
372  *
373  * entry:
374  *	mf - Mapfile descriptor
375  *	lhs - Name of the item directly to the left of the expected left
376  *		bracket.
377  *
378  * exit:
379  *	Returns TK_LEFTBKT for success, and TK_ERROR otherwise.
380  */
381 static Token
382 gettoken_leftbkt(Mapfile *mf, const char *lhs)
383 {
384 	Token		tok;
385 	ld_map_tkval_t	tkv;
386 	Conv_inv_buf_t	inv_buf;
387 
388 	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
389 	case TK_ERROR:
390 	case TK_LEFTBKT:
391 		return (tok);
392 	}
393 
394 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_LBKT), lhs,
395 	    ld_map_tokenstr(tok, &tkv, &inv_buf));
396 	return (TK_ERROR);
397 }
398 
399 /*
400  * Process the next token, which is expected to be an integer
401  *
402  * entry:
403  *	mf - Mapfile descriptor
404  *	lhs - Name of the directive or attribute being processed.
405  *	tkv - Address of token value struct to be filled in
406  *
407  * exit:
408  *	Updates *tkv and returns TK_INT for success, TK_ERROR otherwise.
409  */
410 static Token
411 gettoken_int(Mapfile *mf, const char *lhs, ld_map_tkval_t *tkv)
412 {
413 	Token		tok;
414 	Conv_inv_buf_t	inv_buf;
415 
416 	switch (tok = ld_map_gettoken(mf, 0, tkv)) {
417 	case TK_ERROR:
418 	case TK_INT:
419 		return (tok);
420 	}
421 
422 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_INT), lhs,
423 	    ld_map_tokenstr(tok, tkv, &inv_buf));
424 	return (TK_ERROR);
425 }
426 
427 /*
428  * Process the next token, which is expected to be a string
429  *
430  * entry:
431  *	mf - Mapfile descriptor
432  *	lhs - Name of the directive or attribute being processed.
433  *	tkv - Address of token value struct to be filled in
434  *	err_func - Function to call if an error occurs
435  *
436  * exit:
437  *	Updates *tkv and returns TK_STRING for success. Calls the
438  *	supplied err_func function and returns TK_ERROR otherwise.
439  */
440 static Token
441 gettoken_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv, gts_efunc_t efunc)
442 {
443 	Token		tok;
444 
445 	switch (tok = ld_map_gettoken(mf, flags, tkv)) {
446 	case TK_ERROR:
447 	case TK_STRING:
448 		return (tok);
449 	}
450 
451 	/* User supplied function reports the error */
452 	(* efunc)(mf, tok, tkv);
453 
454 	return (TK_ERROR);
455 }
456 
457 /*
458  * Given a construct of the following common form:
459  *
460  *	item_name {
461  *		attribute = ...;
462  *		...
463  *	}
464  *
465  * where the caller has detected the item_name and opening bracket,
466  * parse the construct and call the attribute functions for each
467  * attribute detected, stopping when the closing '}' is seen.
468  *
469  * entry:
470  *	mf - Mapfile descriptor
471  *	item_name - Already detected name of item for which attributes
472  *		are being parsed.
473  *	attr_list - NULL terminated array of attr_t structures describing the
474  *		valid attributes for the item.
475  *	expect_str - Comma separated string listing the names of expected
476  *		attributes.
477  *	uvalue - User value, passed to the attribute functions without
478  *		examination by parse_attributes(), usable for maintaining
479  *		shared state between the caller and the functions.
480  *
481  * exit:
482  *	parse_attributes() reads the attribute name and equality token,
483  *	and then calls the attribute function given by the attr_list array
484  *	to handle everything up to and including the terminating ';'.
485  *	This continues until the closing '}' is seen.
486  *
487  *	If everything is successful, TK_RIGHTBKT is returned. Otherwise,
488  *	a suitable error is issued and TK_ERROR is returned.
489  */
490 static Token
491 parse_attributes(Mapfile *mf, const char *item_name, attr_t *attr_list,
492     size_t attr_list_bufsize, void *uvalue)
493 {
494 	attr_t		*attr;
495 	Token		tok, op_tok;
496 	ld_map_tkval_t	tkv;
497 	int		done;
498 	int		attr_cnt = 0;
499 	Conv_inv_buf_t	inv_buf;
500 
501 	/* Read attributes until the closing '}' is seen */
502 	for (done = 0; done == 0; ) {
503 		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
504 		case TK_ERROR:
505 			return (TK_ERROR);
506 
507 		case TK_STRING:
508 			attr = ld_map_kwfind(tkv.tkv_str, attr_list,
509 			    SGSOFFSETOF(attr_t, at_name), sizeof (attr[0]));
510 			if (attr == NULL)
511 				goto bad_attr;
512 
513 			/*
514 			 * Depending on the value of at_fmt, there are
515 			 * fout different actions to take:
516 			 *	ATTR_FMT_NAME - Call at_func function
517 			 *	ATTR_FMT_EQ - Read and verify a TK_EQUAL
518 			 *	ATTR_FMT_EQ_PEQ - Read and verify a TK_EQUAL
519 			 *		or TK_PLUSEQ.
520 			 *	ATTR_FMT_EQ_ALL - Read/Verify one of the
521 			 *		three possible equal tokens
522 			 *		(TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ).
523 			 */
524 			if (attr->at_fmt == ATTR_FMT_NAME) {
525 				/* Arbitrary value to pass to at_func */
526 				op_tok = TK_ERROR;
527 			} else {
528 				/* Read/Verify appropriate equal operator */
529 				op_tok = gettoken_eq(mf, attr->at_fmt,
530 				    attr->at_name);
531 				if (op_tok == TK_ERROR)
532 					return (TK_ERROR);
533 			}
534 
535 			/* Call the associated function */
536 			switch (tok = attr->at_func(mf, op_tok, uvalue)) {
537 			default:
538 				return (TK_ERROR);
539 			case TK_SEMICOLON:
540 				break;
541 			case TK_RIGHTBKT:
542 				done = 1;
543 				break;
544 			}
545 			attr_cnt++;
546 			break;
547 
548 		case TK_RIGHTBKT:
549 			done = 1;
550 			break;
551 
552 		case TK_SEMICOLON:
553 			break;		/* Ignore empty statement */
554 
555 		default:
556 		bad_attr:
557 			{
558 				char buf[attr_list_bufsize];
559 
560 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_ATTR),
561 				    ld_map_kwnames(attr_list,
562 				    SGSOFFSETOF(attr_t, at_name),
563 				    sizeof (attr[0]), buf, attr_list_bufsize),
564 				    ld_map_tokenstr(tok, &tkv, &inv_buf));
565 			}
566 			return (TK_ERROR);
567 		}
568 	}
569 
570 	/* Make sure there was at least one attribute between the {} brackets */
571 	if (attr_cnt == 0) {
572 		mf_fatal(mf, MSG_INTL(MSG_MAP_NOATTR), item_name);
573 		return (TK_ERROR);
574 	}
575 
576 	return (tok);
577 }
578 
579 /*
580  * Read whitespace delimited segment flags from the input and convert into
581  * bitmask of PF_ values they represent. Flags are terminated by a semicolon
582  * or right bracket.
583  *
584  * entry:
585  *	mf - Mapfile descriptor
586  *	flags - Address of variable to be set to resulting flags value
587  *
588  * exit:
589  *	Returns the terminator token (TK_SEMICOLON or TK_LEFTBKT) on success,
590  *	and TK_ERROR otherwise.
591  */
592 static Token
593 parse_segment_flags(Mapfile *mf, Xword *flags)
594 {
595 	/*
596 	 * Map flag names to their values. Since DATA and STACK have
597 	 * platform dependent values, we have to determine them at runtime.
598 	 * We indicate this by setting the top bit.
599 	 */
600 #define	PF_DATA		0x80000000
601 #define	PF_STACK	0x80000001
602 	typedef struct {
603 		const char	*name;
604 		Word		value;
605 	} segflag_t;
606 	static segflag_t flag_list[] = {
607 		{ MSG_ORIG(MSG_MAPKW_DATA),	PF_DATA },
608 		{ MSG_ORIG(MSG_MAPKW_EXECUTE),	PF_X },
609 		{ MSG_ORIG(MSG_MAPKW_READ),	PF_R },
610 		{ MSG_ORIG(MSG_MAPKW_STACK),	PF_STACK },
611 		{ MSG_ORIG(MSG_MAPKW_WRITE),	PF_W },
612 
613 		/* List must be null terminated */
614 		{ 0 },
615 	};
616 
617 	/*
618 	 * Size of buffer needed to format the names in flag_list[]. Must
619 	 * be kept in sync with flag_list.
620 	 */
621 	static size_t	flag_list_bufsize =
622 	    KW_NAME_SIZE(MSG_MAPKW_DATA) +
623 	    KW_NAME_SIZE(MSG_MAPKW_EXECUTE) +
624 	    KW_NAME_SIZE(MSG_MAPKW_READ) +
625 	    KW_NAME_SIZE(MSG_MAPKW_STACK) +
626 	    KW_NAME_SIZE(MSG_MAPKW_WRITE);
627 
628 	Token		tok;
629 	ld_map_tkval_t	tkv;
630 	segflag_t	*flag;
631 	size_t		cnt = 0;
632 	int		done;
633 	Conv_inv_buf_t	inv_buf;
634 
635 	*flags = 0;
636 
637 	/* Read attributes until the ';' terminator is seen */
638 	for (done = 0; done == 0; ) {
639 		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
640 		case TK_ERROR:
641 			return (TK_ERROR);
642 
643 		case TK_STRING:
644 			flag = ld_map_kwfind(tkv.tkv_str, flag_list,
645 			    SGSOFFSETOF(segflag_t, name),
646 			    sizeof (flag_list[0]));
647 			if (flag == NULL)
648 				goto bad_flag;
649 			switch (flag->value) {
650 			case PF_DATA:
651 				*flags |= ld_targ.t_m.m_dataseg_perm;
652 				break;
653 			case PF_STACK:
654 				*flags |= ld_targ.t_m.m_stack_perm;
655 				break;
656 			default:
657 				*flags |= flag->value;
658 			}
659 			cnt++;
660 			break;
661 
662 		case TK_INT:
663 			/*
664 			 * Accept 0 for notational convenience, but refuse
665 			 * any other value. Note that we don't actually have
666 			 * to set the flags to 0 here, because there are
667 			 * already initialized to that before the main loop.
668 			 */
669 			if (tkv.tkv_int.tkvi_value != 0)
670 				goto bad_flag;
671 			cnt++;
672 			break;
673 
674 		case TK_SEMICOLON:
675 		case TK_RIGHTBKT:
676 			done = 1;
677 			break;
678 
679 		default:
680 		bad_flag:
681 			{
682 				char buf[flag_list_bufsize];
683 
684 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGFLAG),
685 				    ld_map_kwnames(flag_list,
686 				    SGSOFFSETOF(segflag_t, name),
687 				    sizeof (flag[0]), buf, flag_list_bufsize),
688 				    ld_map_tokenstr(tok, &tkv, &inv_buf));
689 			}
690 			return (TK_ERROR);
691 		}
692 	}
693 
694 	/* Make sure there was at least one flag */
695 	if (cnt == 0) {
696 		mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
697 		    MSG_ORIG(MSG_MAPKW_FLAGS));
698 		return (TK_ERROR);
699 	}
700 
701 	return (tok);
702 
703 #undef PF_DATA
704 #undef PF_STACK
705 }
706 
707 
708 /*
709  * Parse one of the capabilities attributes that corresponds directly
710  * to a capabilities bitmask value (HW_xxx, SF_xxx). Values can be
711  * integers, or symbolic names that correspond to the capabilities mask
712  * in question.
713  *
714  * entry:
715  *	mf - Mapfile descriptor
716  *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
717  *		the operation to carry out.
718  *	capmask - CapMask from output descriptor for capability being processed.
719  *	type - Capability type (CA_SUNW_*)
720  *	elfcap_from_str_func - pointer to elfcap-string-to-value function
721  *		for capability being processed.
722  *
723  * exit:
724  *	Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
725  */
726 static Token
727 parse_cap_mask(Mapfile *mf, Token eq_tok, CapMask *capmask,
728     Word type, elfcap_from_str_func_t *elfcap_from_str_func)
729 {
730 	int		done;
731 	Token		tok;
732 	ld_map_tkval_t	tkv;
733 	Conv_inv_buf_t	inv_buf;
734 	elfcap_mask_t	value = 0;
735 	uint64_t	v;
736 
737 	for (done = 0; done == 0; ) {
738 		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
739 		case TK_ERROR:
740 			return (TK_ERROR);
741 
742 		case TK_STRING:
743 			if ((v = (* elfcap_from_str_func)(ELFCAP_STYLE,
744 			    tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
745 				value |= v;
746 				break;
747 			}
748 			goto bad_flag;
749 
750 		case TK_INT:
751 			value |= tkv.tkv_int.tkvi_value;
752 			break;
753 
754 		case TK_SEMICOLON:
755 		case TK_RIGHTBKT:
756 			done = 1;
757 			break;
758 
759 		default:
760 		bad_flag:
761 			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPMASK),
762 			    ld_map_tokenstr(tok, &tkv, &inv_buf));
763 			return (TK_ERROR);
764 		}
765 	}
766 
767 	if (!set_capmask(mf, capmask, eq_tok, type, value, TRUE))
768 		return (TK_ERROR);
769 	return (tok);
770 }
771 
772 /*
773  * XXXRIEXXX
774  *
775  * This routine is the name version of parse_cap_mask. You need to
776  * add the argument that corresponds to capmask. Also, remove the
777  * ARGSUSED lint comment.
778  */
779 /*
780  * Parse one of the capabilities attributes that manages lists of names
781  * (CA_SUNW_PLATFORM, CA_SUNW_MACHINE).
782  *
783  * entry:
784  *	mf - Mapfile descriptor
785  *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
786  *		the operation to carry out.
787  *	type - Capability type (CA_SUNW_*)
788  *
789  * exit:
790  *	Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
791  */
792 /*ARGSUSED*/
793 static Token
794 parse_cap_list(Mapfile *mf, Token eq_tok, Word type)
795 {
796 	int		done;
797 	Token		tok;
798 	ld_map_tkval_t	tkv;
799 	Conv_inv_buf_t	inv_buf;
800 
801 	/*
802 	 * XXXRIEXXX
803 	 *
804 	 * If eq_tok is TK_EQUAL, you must clear the value and exclude lists,
805 	 * and set the 'override' bit so that the capability from the input
806 	 * objects is ignored. See set_capmask() for the logic used for
807 	 * bitmasks.
808 	 */
809 	for (done = 0; done == 0; ) {
810 		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
811 		case TK_ERROR:
812 			return (TK_ERROR);
813 
814 		case TK_STRING:
815 			/*
816 			 * XXXRIEXXX
817 			 *
818 			 * The name is in tkv.tkv_str. If eq_tok is TK_MINUSEQ,
819 			 * you add the name to the exclude list, and remove it
820 			 * from the value list. Otherwise, you add it to the
821 			 * value list and remove it from the exclude list.
822 			 */
823 			break;
824 
825 		case TK_SEMICOLON:
826 		case TK_RIGHTBKT:
827 			done = 1;
828 			break;
829 
830 		default:
831 			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPNAME),
832 			    ld_map_tokenstr(tok, &tkv, &inv_buf));
833 			return (TK_ERROR);
834 		}
835 	}
836 
837 	return (tok);
838 }
839 
840 /*
841  * CAPABILITY [capid] { HW = hwcap_flags...
842  * -------------------------^
843  */
844 /* ARGSUSED 2 */
845 static Token
846 at_cap_hw(Mapfile *mf, Token eq_tok, void *uvalue)
847 {
848 	int		done;
849 	Token		tok;
850 	ld_map_tkval_t	tkv;
851 	Conv_inv_buf_t	inv_buf;
852 	Word		hw1 = 0, hw2 = 0;
853 	uint64_t	v;
854 
855 	for (done = 0; done == 0; ) {
856 		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
857 		case TK_ERROR:
858 			return (TK_ERROR);
859 
860 		case TK_STRING:
861 			if ((v = elfcap_hw1_from_str(ELFCAP_STYLE,
862 			    tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
863 				hw1 |= v;
864 				break;
865 			}
866 			if ((v = elfcap_hw2_from_str(ELFCAP_STYLE,
867 			    tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
868 				hw2 |= v;
869 				break;
870 			}
871 			goto bad_flag;
872 
873 		case TK_SEMICOLON:
874 		case TK_RIGHTBKT:
875 			done = 1;
876 			break;
877 
878 		default:
879 		bad_flag:
880 			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPHW),
881 			    ld_map_tokenstr(tok, &tkv, &inv_buf));
882 			return (TK_ERROR);
883 		}
884 	}
885 
886 	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_hw_1, eq_tok,
887 	    CA_SUNW_HW_1, hw1, TRUE))
888 		return (TK_ERROR);
889 	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_hw_2, eq_tok,
890 	    CA_SUNW_HW_2, hw2, FALSE))
891 		return (TK_ERROR);
892 	return (tok);
893 }
894 
895 /*
896  * CAPABILITY [capid] { HW_1 = value ;
897  * ---------------------------^
898  */
899 /* ARGSUSED 2 */
900 static Token
901 at_cap_hw_1(Mapfile *mf, Token eq_tok, void *uvalue)
902 {
903 	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_hw_1,
904 	    CA_SUNW_HW_1, elfcap_hw1_from_str));
905 }
906 
907 /*
908  * CAPABILITY [capid] { HW_2 = value ;
909  * ---------------------------^
910  */
911 /* ARGSUSED 2 */
912 static Token
913 at_cap_hw_2(Mapfile *mf, Token eq_tok, void *uvalue)
914 {
915 	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_hw_2,
916 	    CA_SUNW_HW_2, elfcap_hw2_from_str));
917 }
918 
919 /*
920  * CAPABILITY [capid] { SF = sfcap_flags...
921  * -------------------------^
922  */
923 /* ARGSUSED 2 */
924 static Token
925 at_cap_sf(Mapfile *mf, Token eq_tok, void *uvalue)
926 {
927 	int		done;
928 	Token		tok;
929 	ld_map_tkval_t	tkv;
930 	Conv_inv_buf_t	inv_buf;
931 	Word		sf1 = 0;
932 	uint64_t	v;
933 
934 	for (done = 0; done == 0; ) {
935 		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
936 		case TK_ERROR:
937 			return (TK_ERROR);
938 
939 		case TK_STRING:
940 			if ((v = elfcap_sf1_from_str(ELFCAP_STYLE,
941 			    tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
942 				sf1 |= v;
943 				break;
944 			}
945 			goto bad_flag;
946 
947 		case TK_SEMICOLON:
948 		case TK_RIGHTBKT:
949 			done = 1;
950 			break;
951 
952 		default:
953 		bad_flag:
954 			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPSF),
955 			    ld_map_tokenstr(tok, &tkv, &inv_buf));
956 			return (TK_ERROR);
957 		}
958 	}
959 
960 	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_sf_1, eq_tok,
961 	    CA_SUNW_SF_1, sf1, TRUE))
962 		return (TK_ERROR);
963 
964 	return (tok);
965 }
966 
967 /*
968  * CAPABILITY [capid] { SF_1 = value ;
969  * ---------------------------^
970  */
971 /* ARGSUSED 2 */
972 static Token
973 at_cap_sf_1(Mapfile *mf, Token eq_tok, void *uvalue)
974 {
975 	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_sf_1,
976 	    CA_SUNW_SF_1, elfcap_sf1_from_str));
977 }
978 
979 /*
980  * CAPABILITY [capid] { MACHINE = value ;
981  * ------------------------------^
982  */
983 /* ARGSUSED 2 */
984 static Token
985 at_cap_mach(Mapfile *mf, Token eq_tok, void *uvalue)
986 {
987 	/*
988 	 * XXXRIEXXX
989 	 *
990 	 * Add the missing argument, and replace the 0 with
991 	 * CA_SUNW_MACH.
992 	 */
993 	return (parse_cap_list(mf, eq_tok, /* cap-list-goes-here, */
994 	    /* CA_SUNW_MACH */0));
995 }
996 
997 /*
998  * CAPABILITY [capid] { PLATFORM = value ;
999  * -------------------------------^
1000  */
1001 /* ARGSUSED 2 */
1002 static Token
1003 at_cap_plat(Mapfile *mf, Token eq_tok, void *uvalue)
1004 {
1005 	/*
1006 	 * XXXRIEXXX
1007 	 *
1008 	 * Add the missing argument, and replace the 0 with
1009 	 * CA_SUNW_PLAT.
1010 	 */
1011 	return (parse_cap_list(mf, eq_tok, /* cap-list-goes-here, */
1012 	    /* CA_SUNW_PLAT */0));
1013 }
1014 
1015 /*
1016  * Top Level Directive:
1017  *
1018  * CAPABILITY [capid] { ...
1019  * ----------^
1020  */
1021 static Token
1022 dir_capability(Mapfile *mf)
1023 {
1024 	/* CAPABILITY attributes */
1025 	static attr_t attr_list[] = {
1026 		{ MSG_ORIG(MSG_MAPKW_HW),	at_cap_hw, ATTR_FMT_EQ_ALL },
1027 		{ MSG_ORIG(MSG_MAPKW_HW_1),	at_cap_hw_1, ATTR_FMT_EQ_ALL },
1028 		{ MSG_ORIG(MSG_MAPKW_HW_2),	at_cap_hw_2, ATTR_FMT_EQ_ALL },
1029 
1030 		{ MSG_ORIG(MSG_MAPKW_MACHINE),	at_cap_mach, ATTR_FMT_EQ_ALL },
1031 		{ MSG_ORIG(MSG_MAPKW_PLATFORM),	at_cap_plat, ATTR_FMT_EQ_ALL },
1032 
1033 		{ MSG_ORIG(MSG_MAPKW_SF),	at_cap_sf, ATTR_FMT_EQ_ALL },
1034 		{ MSG_ORIG(MSG_MAPKW_SF_1),	at_cap_sf_1, ATTR_FMT_EQ_ALL },
1035 		/* List must be null terminated */
1036 		{ 0 }
1037 	};
1038 
1039 	/*
1040 	 * Size of buffer needed to format the names in attr_list[]. Must
1041 	 * be kept in sync with attr_list.
1042 	 */
1043 	static size_t	attr_list_bufsize =
1044 	    KW_NAME_SIZE(MSG_MAPKW_HW) +
1045 	    KW_NAME_SIZE(MSG_MAPKW_HW_1) +
1046 	    KW_NAME_SIZE(MSG_MAPKW_HW_2) +
1047 	    KW_NAME_SIZE(MSG_MAPKW_MACHINE) +
1048 	    KW_NAME_SIZE(MSG_MAPKW_PLATFORM) +
1049 	    KW_NAME_SIZE(MSG_MAPKW_SF) +
1050 	    KW_NAME_SIZE(MSG_MAPKW_SF_1);
1051 
1052 	const char	*capid = NULL;
1053 	Token		tok;
1054 	ld_map_tkval_t	tkv;
1055 	Conv_inv_buf_t	inv_buf;
1056 
1057 	/*
1058 	 * The first token can be one of:
1059 	 * -	An opening '{'
1060 	 * -	A name, followed by a '{', or a ';'.
1061 	 * Read this initial sequence.
1062 	 */
1063 
1064 	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
1065 	case TK_ERROR:
1066 		return (TK_ERROR);
1067 
1068 	case TK_STRING:
1069 		/*
1070 		 * XXXRIEXXX
1071 		 *
1072 		 * The ID name is in tkv.tkv_str. It needs to be saved,
1073 		 * and eventually converted into a CA_SUNW_ID entry.
1074 		 */
1075 		capid = tkv.tkv_str;
1076 
1077 		/*
1078 		 * The name can be followed by an opening '{', or a
1079 		 * terminating ';'
1080 		 */
1081 		switch (tok = gettoken_optattr(mf, capid)) {
1082 		case TK_SEMICOLON:
1083 			return (TK_SEMICOLON);
1084 		case TK_LEFTBKT:
1085 			break;
1086 		default:
1087 			return (TK_ERROR);
1088 		}
1089 		break;
1090 
1091 	case TK_LEFTBKT:
1092 		/* Directive has no capid, but does supply attributes */
1093 		break;
1094 
1095 	default:
1096 		mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPID),
1097 		    MSG_ORIG(MSG_MAPKW_CAPABILITY),
1098 		    ld_map_tokenstr(tok, &tkv, &inv_buf));
1099 		return (TK_ERROR);
1100 	}
1101 
1102 	/* Parse the attributes */
1103 	if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_CAPABILITY),
1104 	    attr_list, attr_list_bufsize, NULL) == TK_ERROR)
1105 		return (TK_ERROR);
1106 
1107 	/* Terminating ';' */
1108 	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_CAPABILITY)));
1109 }
1110 
1111 /*
1112  * at_dv_allow(): Value for ALLOW= is not a version string
1113  */
1114 static void
1115 gts_efunc_at_dv_allow(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
1116 {
1117 	Conv_inv_buf_t	inv_buf;
1118 
1119 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
1120 	    MSG_ORIG(MSG_MAPKW_ALLOW), ld_map_tokenstr(tok, tkv, &inv_buf));
1121 }
1122 
1123 /*
1124  * DEPEND_VERSIONS object_name { ALLOW = version
1125  * -------------------------------------^
1126  */
1127 /* ARGSUSED 1 */
1128 static Token
1129 at_dv_allow(Mapfile *mf, Token eq_tok, void *uvalue)
1130 {
1131 	ld_map_tkval_t	tkv;
1132 
1133 	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_dv_allow) == TK_ERROR)
1134 		return (TK_ERROR);
1135 
1136 	/* Enter the version. uvalue points at the Sdf_desc descriptor */
1137 	if (!ld_map_dv_entry(mf, uvalue, FALSE, tkv.tkv_str))
1138 		return (TK_ERROR);
1139 
1140 	/* terminator */
1141 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ALLOW)));
1142 }
1143 
1144 /*
1145  * at_dv_allow(): Value for REQUIRE= is not a version string
1146  */
1147 static void
1148 gts_efunc_at_dv_require(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
1149 {
1150 	Conv_inv_buf_t	inv_buf;
1151 
1152 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
1153 	    MSG_ORIG(MSG_MAPKW_REQUIRE), ld_map_tokenstr(tok, tkv, &inv_buf));
1154 }
1155 
1156 /*
1157  * DEPEND_VERSIONS object_name { REQURE = version
1158  * --------------------------------------^
1159  */
1160 /* ARGSUSED 1 */
1161 static Token
1162 at_dv_require(Mapfile *mf, Token eq_tok, void *uvalue)
1163 {
1164 	ld_map_tkval_t	tkv;
1165 
1166 	/* version_name */
1167 	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_dv_require) == TK_ERROR)
1168 		return (TK_ERROR);
1169 
1170 	/* Enter the version. uvalue points at the Sdf_desc descriptor */
1171 	if (!ld_map_dv_entry(mf, uvalue, TRUE, tkv.tkv_str))
1172 		return (TK_ERROR);
1173 
1174 	/* terminator */
1175 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_REQUIRE)));
1176 }
1177 
1178 /*
1179  * dir_depend_versions(): Expected object name is not present
1180  */
1181 static void
1182 gts_efunc_dir_depend_versions(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
1183 {
1184 	Conv_inv_buf_t	inv_buf;
1185 
1186 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
1187 	    MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS),
1188 	    ld_map_tokenstr(tok, tkv, &inv_buf));
1189 }
1190 
1191 /*
1192  * Top Level Directive:
1193  *
1194  * DEPEND_VERSIONS object_name { ATTR = ...
1195  * ---------------^
1196  */
1197 static Token
1198 dir_depend_versions(Mapfile *mf)
1199 {
1200 	/* DEPEND_VERSIONS attributes */
1201 	static attr_t attr_list[] = {
1202 		{ MSG_ORIG(MSG_MAPKW_ALLOW),	at_dv_allow,	ATTR_FMT_EQ },
1203 		{ MSG_ORIG(MSG_MAPKW_REQUIRE),	at_dv_require,	ATTR_FMT_EQ },
1204 
1205 		/* List must be null terminated */
1206 		{ 0 }
1207 	};
1208 
1209 	/*
1210 	 * Size of buffer needed to format the names in attr_list[]. Must
1211 	 * be kept in sync with attr_list.
1212 	 */
1213 	static size_t	attr_list_bufsize =
1214 	    KW_NAME_SIZE(MSG_MAPKW_ALLOW) +
1215 	    KW_NAME_SIZE(MSG_MAPKW_REQUIRE);
1216 
1217 	ld_map_tkval_t	tkv;
1218 	Sdf_desc	*sdf;
1219 
1220 	/* object_name */
1221 	if (gettoken_str(mf, 0, &tkv, gts_efunc_dir_depend_versions) ==
1222 	    TK_ERROR)
1223 		return (TK_ERROR);
1224 
1225 	/* Get descriptor for dependency */
1226 	if ((sdf = ld_map_dv(mf, tkv.tkv_str)) == NULL)
1227 		return (TK_ERROR);
1228 
1229 	/* Opening '{' token */
1230 	if (gettoken_leftbkt(mf, tkv.tkv_str) == TK_ERROR)
1231 		return (TK_ERROR);
1232 
1233 	/* Parse the attributes */
1234 	if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS),
1235 	    attr_list, attr_list_bufsize, sdf) == TK_ERROR)
1236 		return (TK_ERROR);
1237 
1238 	/* Terminating ';' */
1239 	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS)));
1240 }
1241 
1242 /*
1243  * Top Level Directive:
1244  *
1245  * HDR_NOALLOC ;
1246  * -----------^
1247  */
1248 static Token
1249 dir_hdr_noalloc(Mapfile *mf)
1250 {
1251 	mf->mf_ofl->ofl_dtflags_1 |= DF_1_NOHDR;
1252 	DBG_CALL(Dbg_map_hdr_noalloc(mf->mf_ofl->ofl_lml, mf->mf_lineno));
1253 
1254 	/* ';' terminator token */
1255 	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_HDR_NOALLOC)));
1256 }
1257 
1258 /*
1259  * Top Level Directive:
1260  *
1261  * PHDR_ADD_NULL = cnt ;
1262  * -------------^
1263  */
1264 static Token
1265 dir_phdr_add_null(Mapfile *mf)
1266 {
1267 	Sg_desc		*sgp;
1268 	ld_map_tkval_t	tkv;		/* Value of token */
1269 
1270 	/* '=' token */
1271 	if (gettoken_eq(mf, ATTR_FMT_EQ,
1272 	    MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL)) == TK_ERROR)
1273 		return (TK_ERROR);
1274 
1275 	/* integer token */
1276 	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL), &tkv) ==
1277 	    TK_ERROR)
1278 		return (TK_ERROR);
1279 
1280 	while (tkv.tkv_int.tkvi_value-- > 0) {
1281 		if ((sgp = ld_map_seg_alloc(NULL, PT_NULL,
1282 		    FLG_SG_P_TYPE | FLG_SG_EMPTY)) == NULL)
1283 			return (TK_ERROR);
1284 		if (ld_map_seg_insert(mf, DBG_STATE_NEW, sgp, 0) ==
1285 		    SEG_INS_FAIL)
1286 			return (TK_ERROR);
1287 	}
1288 
1289 	/* ';' terminator token */
1290 	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL)));
1291 }
1292 
1293 /*
1294  * segment_directive segment_name { ALIGN = value
1295  * ----------------------------------------^
1296  */
1297 /* ARGSUSED 1 */
1298 static Token
1299 at_seg_align(Mapfile *mf, Token eq_tok, void *uvalue)
1300 {
1301 	Sg_desc		*sgp = uvalue;
1302 	ld_map_tkval_t	tkv;
1303 
1304 	/* value */
1305 	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_ALIGN), &tkv) == TK_ERROR)
1306 		return (TK_ERROR);
1307 
1308 	sgp->sg_phdr.p_align = tkv.tkv_int.tkvi_value;
1309 	sgp->sg_flags |= FLG_SG_P_ALIGN;
1310 
1311 	/* terminator */
1312 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ALIGN)));
1313 }
1314 
1315 /*
1316  * at_seg_assign_file_basename(): Value for FILE_BASENAME= is not a file name
1317  */
1318 static void
1319 gts_efunc_at_seg_assign_file_basename(Mapfile *mf, Token tok,
1320     ld_map_tkval_t *tkv)
1321 {
1322 	Conv_inv_buf_t	inv_buf;
1323 
1324 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_FILNAM),
1325 	    MSG_ORIG(MSG_MAPKW_FILE_BASENAME),
1326 	    ld_map_tokenstr(tok, tkv, &inv_buf));
1327 }
1328 
1329 /*
1330  * segment_directive segment_name { ASSIGN { FILE_BASENAME = file_name
1331  * ---------------------------------------------------------^
1332  */
1333 /* ARGSUSED 1 */
1334 static Token
1335 at_seg_assign_file_basename(Mapfile *mf, Token eq_tok, void *uvalue)
1336 {
1337 	Ent_desc	*enp = uvalue;
1338 	ld_map_tkval_t	tkv;
1339 
1340 	/* file_name */
1341 	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_basename) ==
1342 	    TK_ERROR)
1343 		return (TK_ERROR);
1344 
1345 	if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_BASENAME, tkv.tkv_str))
1346 		return (TK_ERROR);
1347 
1348 	/* terminator */
1349 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_BASENAME)));
1350 }
1351 
1352 /*
1353  * at_seg_assign_file_objname(): Value for FILE_OBJNAME= is not an object name
1354  */
1355 static void
1356 gts_efunc_at_seg_assign_file_objname(Mapfile *mf, Token tok,
1357     ld_map_tkval_t *tkv)
1358 {
1359 	Conv_inv_buf_t	inv_buf;
1360 
1361 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
1362 	    MSG_ORIG(MSG_MAPKW_FILE_OBJNAME),
1363 	    ld_map_tokenstr(tok, tkv, &inv_buf));
1364 }
1365 
1366 /*
1367  * segment_directive segment_name { ASSIGN { FILE_OBJNAME = name
1368  * --------------------------------------------------------^
1369  */
1370 /* ARGSUSED 1 */
1371 static Token
1372 at_seg_assign_file_objname(Mapfile *mf, Token eq_tok, void *uvalue)
1373 {
1374 	Ent_desc	*enp = uvalue;
1375 	ld_map_tkval_t	tkv;
1376 
1377 	/* file_objname */
1378 	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_objname) ==
1379 	    TK_ERROR)
1380 		return (TK_ERROR);
1381 
1382 	if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_OBJNAME, tkv.tkv_str))
1383 		return (TK_ERROR);
1384 
1385 	/* terminator */
1386 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_OBJNAME)));
1387 }
1388 
1389 /*
1390  * at_seg_assign_file_path(): Value for FILE_PATH= is not a file path
1391  */
1392 static void
1393 gts_efunc_at_seg_assign_file_path(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
1394 {
1395 	Conv_inv_buf_t	inv_buf;
1396 
1397 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_FILPATH),
1398 	    MSG_ORIG(MSG_MAPKW_FILE_PATH),
1399 	    ld_map_tokenstr(tok, tkv, &inv_buf));
1400 }
1401 
1402 /*
1403  * segment_directive segment_name { ASSIGN { FILE_PATH = file_path
1404  * -----------------------------------------------------^
1405  */
1406 /* ARGSUSED 1 */
1407 static Token
1408 at_seg_assign_file_path(Mapfile *mf, Token eq_tok, void *uvalue)
1409 {
1410 	Ent_desc	*enp = uvalue;
1411 	ld_map_tkval_t	tkv;
1412 
1413 	/* file_path */
1414 	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_path) ==
1415 	    TK_ERROR)
1416 		return (TK_ERROR);
1417 
1418 	if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_PATH, tkv.tkv_str))
1419 		return (TK_ERROR);
1420 
1421 	/* terminator */
1422 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_PATH)));
1423 }
1424 
1425 /*
1426  * segment_directive segment_name { ASSIGN { FLAGS = ... ;
1427  * -------------------------------------------------^
1428  */
1429 /* ARGSUSED 1 */
1430 static Token
1431 at_seg_assign_flags(Mapfile *mf, Token eq_tok, void *uvalue)
1432 {
1433 	typedef struct {
1434 		const char	*name;
1435 		Word		value;
1436 	} secflag_t;
1437 	static secflag_t flag_list[] = {
1438 		{ MSG_ORIG(MSG_MAPKW_ALLOC),		SHF_ALLOC },
1439 		{ MSG_ORIG(MSG_MAPKW_EXECUTE),		SHF_EXECINSTR },
1440 		{ MSG_ORIG(MSG_MAPKW_WRITE),		SHF_WRITE },
1441 		{ MSG_ORIG(MSG_MAPKW_AMD64_LARGE),	SHF_AMD64_LARGE },
1442 
1443 		/* List must be null terminated */
1444 		{ 0 },
1445 	};
1446 
1447 	/*
1448 	 * Size of buffer needed to format the names in flag_list[]. Must
1449 	 * be kept in sync with flag_list.
1450 	 */
1451 	static size_t	flag_list_bufsize =
1452 	    KW_NAME_SIZE(MSG_MAPKW_ALLOC) +
1453 	    KW_NAME_SIZE(MSG_MAPKW_EXECUTE) +
1454 	    KW_NAME_SIZE(MSG_MAPKW_WRITE) +
1455 	    KW_NAME_SIZE(MSG_MAPKW_AMD64_LARGE);
1456 
1457 	Ent_desc	*enp = uvalue;
1458 	int		bcnt = 0, cnt = 0;
1459 	secflag_t	*flag;
1460 	int		done;
1461 	Token		tok;
1462 	ld_map_tkval_t	tkv;
1463 	Conv_inv_buf_t	inv_buf;
1464 
1465 	/* Read and process tokens until the closing terminator is seen */
1466 	for (done = 0; done == 0; ) {
1467 		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
1468 		case TK_ERROR:
1469 			return (TK_ERROR);
1470 
1471 		case TK_BANG:
1472 			/* Ensure ! only specified once per flag */
1473 			if (bcnt != 0) {
1474 				mf_fatal0(mf, MSG_INTL(MSG_MAP_SFLG_ONEBANG));
1475 				return (TK_ERROR);
1476 			}
1477 			bcnt++;
1478 			break;
1479 
1480 		case TK_STRING:
1481 			flag = ld_map_kwfind(tkv.tkv_str, flag_list,
1482 			    SGSOFFSETOF(secflag_t, name), sizeof (flag[0]));
1483 			if (flag == NULL)
1484 				goto bad_flag;
1485 			cnt++;
1486 			enp->ec_attrmask |= flag->value;
1487 			if (bcnt == 0)
1488 				enp->ec_attrbits |=  flag->value;
1489 			bcnt = 0;
1490 			break;
1491 
1492 		case TK_RIGHTBKT:
1493 		case TK_SEMICOLON:
1494 			done = 1;
1495 			break;
1496 
1497 		default:
1498 		bad_flag:
1499 			{
1500 				char buf[flag_list_bufsize];
1501 
1502 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECFLAG),
1503 				    ld_map_kwnames(flag_list,
1504 				    SGSOFFSETOF(secflag_t, name),
1505 				    sizeof (flag[0]), buf, flag_list_bufsize),
1506 				    ld_map_tokenstr(tok, &tkv, &inv_buf));
1507 			}
1508 			return (TK_ERROR);
1509 		}
1510 	}
1511 
1512 	/*
1513 	 * Ensure that a trailing '!' was not left at the end of the line
1514 	 * without a corresponding flag to apply it to.
1515 	 */
1516 	if (bcnt != 0) {
1517 		mf_fatal0(mf, MSG_INTL(MSG_MAP_SFLG_EXBANG));
1518 		return (TK_ERROR);
1519 	}
1520 
1521 	/* Make sure there was at least one flag */
1522 	if (cnt == 0) {
1523 		mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
1524 		    MSG_ORIG(MSG_MAPKW_FLAGS));
1525 		return (TK_ERROR);
1526 	}
1527 
1528 	return (tok);		/* Either TK_SEMICOLON or TK_RIGHTBKT */
1529 }
1530 
1531 /*
1532  * at_seg_assign_is_name(): Value for IS_NAME= is not a section name
1533  */
1534 static void
1535 gts_efunc_at_seg_assign_is_name(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
1536 {
1537 	Conv_inv_buf_t	inv_buf;
1538 
1539 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECNAM),
1540 	    MSG_ORIG(MSG_MAPKW_IS_NAME), ld_map_tokenstr(tok, tkv, &inv_buf));
1541 }
1542 
1543 /*
1544  * segment_directive segment_name { ASSIGN { IS_NAME = section_name ;
1545  * ---------------------------------------------------^
1546  */
1547 /* ARGSUSED 1 */
1548 static Token
1549 at_seg_assign_is_name(Mapfile *mf, Token eq_tok, void *uvalue)
1550 {
1551 	Ent_desc	*enp = uvalue;
1552 	ld_map_tkval_t	tkv;
1553 
1554 	/* section_name */
1555 	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_is_name) ==
1556 	    TK_ERROR)
1557 		return (TK_ERROR);
1558 	enp->ec_is_name = tkv.tkv_str;
1559 
1560 	/* terminator */
1561 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_IS_NAME)));
1562 }
1563 
1564 /*
1565  * at_seg_assign_type(): Value for TYPE= is not a section type
1566  */
1567 static void
1568 gts_efunc_at_seg_assign_type(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
1569 {
1570 	Conv_inv_buf_t	inv_buf;
1571 
1572 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SHTYPE),
1573 	    ld_map_tokenstr(tok, tkv, &inv_buf));
1574 }
1575 
1576 /*
1577  * segment_directive segment_name { ASSIGN { TYPE = section_type ;
1578  * ------------------------------------------------^
1579  */
1580 /* ARGSUSED 1 */
1581 static Token
1582 at_seg_assign_type(Mapfile *mf, Token eq_tok, void *uvalue)
1583 {
1584 	Ent_desc		*enp = uvalue;
1585 	ld_map_tkval_t		tkv;
1586 	conv_strtol_uvalue_t	conv_uvalue;
1587 
1588 	/* section type */
1589 	if (gettoken_str(mf, TK_F_KEYWORD, &tkv,
1590 	    gts_efunc_at_seg_assign_type) == TK_ERROR)
1591 		return (TK_ERROR);
1592 
1593 	/*
1594 	 * Use the libconv iteration facility to map the given name to
1595 	 * its value. This allows us to keep up with any new sections
1596 	 * without having to change this code.
1597 	 */
1598 	if (conv_iter_strtol_init(tkv.tkv_str, &conv_uvalue) != 0) {
1599 		conv_iter_ret_t	status;
1600 
1601 		/* Look at the canonical form */
1602 		status = conv_iter_sec_type(CONV_OSABI_ALL, CONV_MACH_ALL,
1603 		    CONV_FMT_ALT_CF, conv_iter_strtol, &conv_uvalue);
1604 
1605 		/* Failing that, look at the normal form */
1606 		if (status != CONV_ITER_DONE)
1607 			(void) conv_iter_sec_type(CONV_OSABI_ALL,
1608 			    CONV_MACH_ALL, CONV_FMT_ALT_NF, conv_iter_strtol,
1609 			    &conv_uvalue);
1610 
1611 		/* If we didn't match anything report error */
1612 		if (!conv_uvalue.csl_found) {
1613 			gts_efunc_at_seg_assign_type(mf, TK_STRING, &tkv);
1614 			return (TK_ERROR);
1615 		}
1616 	}
1617 
1618 	enp->ec_type = conv_uvalue.csl_value;
1619 
1620 	/* terminator */
1621 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_TYPE)));
1622 }
1623 
1624 /*
1625  * segment_directive segment_name { ASSIGN { ...
1626  * -----------------------------------------^
1627  */
1628 /* ARGSUSED 1 */
1629 static Token
1630 at_seg_assign(Mapfile *mf, Token eq_tok, void *uvalue)
1631 {
1632 	/* segment_directive ASSIGN sub-attributes */
1633 	static attr_t attr_list[] = {
1634 		{ MSG_ORIG(MSG_MAPKW_FILE_BASENAME),
1635 		    at_seg_assign_file_basename,	ATTR_FMT_EQ },
1636 		{ MSG_ORIG(MSG_MAPKW_FILE_OBJNAME),
1637 		    at_seg_assign_file_objname,		ATTR_FMT_EQ },
1638 		{ MSG_ORIG(MSG_MAPKW_FILE_PATH),
1639 		    at_seg_assign_file_path,		ATTR_FMT_EQ },
1640 		{ MSG_ORIG(MSG_MAPKW_FLAGS),
1641 		    at_seg_assign_flags,		ATTR_FMT_EQ_ALL },
1642 		{ MSG_ORIG(MSG_MAPKW_IS_NAME),
1643 		    at_seg_assign_is_name,		ATTR_FMT_EQ },
1644 		{ MSG_ORIG(MSG_MAPKW_TYPE),
1645 		    at_seg_assign_type,			ATTR_FMT_EQ },
1646 
1647 		/* List must be null terminated */
1648 		{ 0 }
1649 	};
1650 
1651 	/*
1652 	 * Size of buffer needed to format the names in attr_list[]. Must
1653 	 * be kept in sync with attr_list.
1654 	 */
1655 	static size_t	attr_list_bufsize =
1656 	    KW_NAME_SIZE(MSG_MAPKW_FILE_BASENAME) +
1657 	    KW_NAME_SIZE(MSG_MAPKW_FILE_PATH) +
1658 	    KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
1659 	    KW_NAME_SIZE(MSG_MAPKW_FILE_OBJNAME) +
1660 	    KW_NAME_SIZE(MSG_MAPKW_IS_NAME) +
1661 	    KW_NAME_SIZE(MSG_MAPKW_TYPE);
1662 
1663 	Sg_desc		*sgp = uvalue;
1664 	Token		tok;
1665 	ld_map_tkval_t	tkv;
1666 	Conv_inv_buf_t	inv_buf;
1667 	const char	*name = NULL;
1668 	Ent_desc	*enp;
1669 
1670 	/*
1671 	 * ASSIGN takes an optional name, plus attributes are optional,
1672 	 * so expect a name, an opening '{', or a ';'.
1673 	 */
1674 	tok = ld_map_gettoken(mf, 0, &tkv);
1675 	switch (tok) {
1676 	case TK_ERROR:
1677 		return (TK_ERROR);
1678 
1679 	case TK_STRING:
1680 		name = tkv.tkv_str;
1681 		tok = ld_map_gettoken(mf, 0, &tkv);
1682 		break;
1683 	}
1684 
1685 	/* Add a new entrance criteria descriptor to the segment */
1686 	if ((enp = ld_map_seg_ent_add(mf, sgp, name)) == NULL)
1687 		return (TK_ERROR);
1688 
1689 	/* Having handled the name, expect either '{' or ';' */
1690 	switch (tok) {
1691 	default:
1692 		mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMLBKT),
1693 		    MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
1694 		    ld_map_tokenstr(tok, &tkv, &inv_buf));
1695 		return (TK_ERROR);
1696 	case TK_ERROR:
1697 		return (TK_ERROR);
1698 	case TK_SEMICOLON:
1699 	case TK_RIGHTBKT:
1700 		/* No attributes: It will match anything */
1701 		enp->ec_flags |= FLG_EC_CATCHALL;
1702 		break;
1703 	case TK_LEFTBKT:
1704 		/* Parse the attributes */
1705 		if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
1706 		    attr_list, attr_list_bufsize, enp) == TK_ERROR)
1707 			return (TK_ERROR);
1708 
1709 		/* Terminating ';',  or '}' which also terminates caller */
1710 		tok = gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION));
1711 		if (tok == TK_ERROR)
1712 			return (TK_ERROR);
1713 		break;
1714 	}
1715 
1716 	DBG_CALL(Dbg_map_ent(mf->mf_ofl->ofl_lml, enp, mf->mf_ofl,
1717 	    mf->mf_lineno));
1718 	return (tok);
1719 }
1720 
1721 /*
1722  * segment_directive segment_name { DISABLE ;
1723  * ----------------------------------------^
1724  */
1725 /* ARGSUSED 1 */
1726 static Token
1727 at_seg_disable(Mapfile *mf, Token eq_tok, void *uvalue)
1728 {
1729 	Sg_desc		*sgp = uvalue;
1730 
1731 	/* If the segment cannot be disabled, issue error */
1732 	if (sgp->sg_flags & FLG_SG_NODISABLE) {
1733 		mf_fatal(mf, MSG_INTL(MSG_MAP_CNTDISSEG), sgp->sg_name);
1734 		return (TK_ERROR);
1735 	}
1736 
1737 	/* Disable the segment */
1738 	sgp->sg_flags |= FLG_SG_DISABLED;
1739 
1740 	/* terminator */
1741 	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_DISABLE)));
1742 }
1743 
1744 /*
1745  * segment_directive segment_name { FLAGS eq-op ...
1746  * --------------------------------------------^
1747  *
1748  * Note that this routine is also used for the STACK directive,
1749  * as STACK also manipulates a segment descriptor.
1750  *
1751  * STACK { FLAGS eq-op ... ;
1752  * -------------------^
1753  */
1754 /* ARGSUSED 2 */
1755 static Token
1756 at_seg_flags(Mapfile *mf, Token eq_tok, void *uvalue)
1757 {
1758 	Sg_desc		*sgp = uvalue;
1759 	Token		tok;
1760 	Xword		flags;
1761 
1762 	tok = parse_segment_flags(mf, &flags);
1763 	if (tok == TK_ERROR)
1764 		return (TK_ERROR);
1765 
1766 	setflags_eq(&sgp->sg_phdr.p_flags, eq_tok, flags);
1767 	sgp->sg_flags |= FLG_SG_P_FLAGS;
1768 
1769 	return (tok);
1770 }
1771 
1772 /*
1773  * segment_directive segment_name { IS_ORDER eq_op value
1774  * -----------------------------------------------^
1775  */
1776 /* ARGSUSED 2 */
1777 static Token
1778 at_seg_is_order(Mapfile *mf, Token eq_tok, void *uvalue)
1779 {
1780 	Sg_desc		*sgp = uvalue;
1781 	Token		tok;
1782 	ld_map_tkval_t	tkv;
1783 	Conv_inv_buf_t	inv_buf;
1784 	int		done;
1785 	Aliste		idx;
1786 	Ent_desc	*enp, *enp2;
1787 
1788 	/*
1789 	 * The '=' form of assignment resets the list. The list contains
1790 	 * pointers to our mapfile text, so we do not have to free anything.
1791 	 */
1792 	if (eq_tok == TK_EQUAL)
1793 		aplist_reset(sgp->sg_is_order);
1794 
1795 	/*
1796 	 * One or more ASSIGN names, terminated by a semicolon.
1797 	 */
1798 	for (done = 0; done == 0; ) {
1799 		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
1800 		case TK_ERROR:
1801 			return (TK_ERROR);
1802 
1803 		case TK_STRING:
1804 			/*
1805 			 * The referenced entrance criteria must have
1806 			 * already been defined.
1807 			 */
1808 			enp = ld_ent_lookup(mf->mf_ofl, tkv.tkv_str, NULL);
1809 			if (enp == NULL) {
1810 				mf_fatal(mf, MSG_INTL(MSG_MAP_UNKENT),
1811 				    tkv.tkv_str);
1812 				return (TK_ERROR);
1813 			}
1814 
1815 			/*
1816 			 * Make sure it's not already on the list
1817 			 */
1818 			for (APLIST_TRAVERSE(sgp->sg_is_order, idx, enp2))
1819 				if (enp == enp2) {
1820 					mf_fatal(mf,
1821 					    MSG_INTL(MSG_MAP_DUP_IS_ORD),
1822 					    tkv.tkv_str);
1823 					return (TK_ERROR);
1824 				}
1825 
1826 			/* Put it at the end of the order list */
1827 			if (aplist_append(&sgp->sg_is_order, enp,
1828 			    AL_CNT_SG_IS_ORDER) == NULL)
1829 				return (TK_ERROR);
1830 			break;
1831 
1832 		case TK_SEMICOLON:
1833 		case TK_RIGHTBKT:
1834 			done = 1;
1835 			break;
1836 
1837 		default:
1838 			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_ECNAM),
1839 			    ld_map_tokenstr(tok, &tkv, &inv_buf));
1840 			return (TK_ERROR);
1841 		}
1842 	}
1843 
1844 	return (tok);
1845 }
1846 
1847 /*
1848  * segment_directive segment_name { MAX_SIZE = value
1849  * -------------------------------------------^
1850  */
1851 /* ARGSUSED 1 */
1852 static Token
1853 at_seg_max_size(Mapfile *mf, Token eq_tok, void *uvalue)
1854 {
1855 	Sg_desc		*sgp = uvalue;
1856 	ld_map_tkval_t	tkv;
1857 
1858 	/* value */
1859 	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_MAX_SIZE), &tkv) == TK_ERROR)
1860 		return (TK_ERROR);
1861 
1862 	sgp->sg_length = tkv.tkv_int.tkvi_value;
1863 	sgp->sg_flags |= FLG_SG_LENGTH;
1864 
1865 	/* terminator */
1866 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_MAX_SIZE)));
1867 }
1868 
1869 /*
1870  * segment_directive segment_name { NOHDR ;
1871  * --------------------------------------^
1872  */
1873 /* ARGSUSED 1 */
1874 static Token
1875 at_seg_nohdr(Mapfile *mf, Token eq_tok, void *uvalue)
1876 {
1877 	Sg_desc		*sgp = uvalue;
1878 
1879 	/*
1880 	 * Set the nohdr flag on the segment. If this segment is the
1881 	 * first loadable segment, the ELF and program headers will
1882 	 * not be included.
1883 	 *
1884 	 * The HDR_NOALLOC top level directive is preferred. This feature
1885 	 * exists to give 1:1 feature parity with version 1 mapfiles that
1886 	 * use the ?N segment flag and expect it to only take effect
1887 	 * if that segment ends up being first.
1888 	 */
1889 	sgp->sg_flags |= FLG_SG_NOHDR;
1890 
1891 	/* terminator */
1892 	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_NOHDR)));
1893 }
1894 
1895 /*
1896  * segment_directive segment_name { OS_ORDER eq_op assign_name...
1897  * -----------------------------------------------^
1898  */
1899 /* ARGSUSED 2 */
1900 static Token
1901 at_seg_os_order(Mapfile *mf, Token eq_tok, void *uvalue)
1902 {
1903 	Sg_desc		*sgp = uvalue;
1904 	Token		tok;
1905 	ld_map_tkval_t	tkv;
1906 	Conv_inv_buf_t	inv_buf;
1907 	int		done;
1908 
1909 	/*
1910 	 * The '=' form of assignment resets the list. The list contains
1911 	 * pointers to our mapfile text, so we do not have to free anything.
1912 	 */
1913 	if (eq_tok == TK_EQUAL)
1914 		alist_reset(sgp->sg_os_order);
1915 
1916 	/*
1917 	 * One or more section names, terminated by a semicolon.
1918 	 */
1919 	for (done = 0; done == 0; ) {
1920 		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
1921 		case TK_ERROR:
1922 			return (TK_ERROR);
1923 
1924 		case TK_STRING:
1925 			if (!ld_map_seg_os_order_add(mf, sgp, tkv.tkv_str))
1926 				return (TK_ERROR);
1927 			break;
1928 
1929 		case TK_SEMICOLON:
1930 		case TK_RIGHTBKT:
1931 			done = 1;
1932 			break;
1933 
1934 		default:
1935 			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECNAM),
1936 			    ld_map_tokenstr(tok, &tkv, &inv_buf));
1937 			return (TK_ERROR);
1938 		}
1939 	}
1940 
1941 	return (tok);
1942 }
1943 
1944 /*
1945  * segment_directive segment_name { PADDR = paddr
1946  * ----------------------------------------^
1947  */
1948 /* ARGSUSED 1 */
1949 static Token
1950 at_seg_paddr(Mapfile *mf, Token eq_tok, void *uvalue)
1951 {
1952 	Sg_desc		*sgp = uvalue, *sgp2;
1953 	Aliste		idx;
1954 	ld_map_tkval_t	tkv;
1955 
1956 	/*
1957 	 * Ensure that the segment isn't in the segment order list.
1958 	 */
1959 	for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order, idx, sgp2))
1960 		if (sgp == sgp2) {
1961 			mf_fatal(mf,
1962 			    MSG_INTL(MSG_MAP_CNTADDRORDER), sgp->sg_name);
1963 			return (TK_ERROR);
1964 		}
1965 
1966 	/* value */
1967 	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_PADDR), &tkv) == TK_ERROR)
1968 		return (TK_ERROR);
1969 
1970 	sgp->sg_phdr.p_paddr = tkv.tkv_int.tkvi_value;
1971 	sgp->sg_flags |= FLG_SG_P_PADDR;
1972 
1973 	/* terminator */
1974 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_PADDR)));
1975 }
1976 
1977 /*
1978  * segment_directive segment_name { ROUND = value
1979  * ----------------------------------------^
1980  */
1981 /* ARGSUSED 1 */
1982 static Token
1983 at_seg_round(Mapfile *mf, Token eq_tok, void *uvalue)
1984 {
1985 	Sg_desc		*sgp = uvalue;
1986 	ld_map_tkval_t	tkv;
1987 
1988 	/* value */
1989 	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_ROUND), &tkv) == TK_ERROR)
1990 		return (TK_ERROR);
1991 
1992 	sgp->sg_round = tkv.tkv_int.tkvi_value;
1993 	sgp->sg_flags |= FLG_SG_ROUND;
1994 
1995 	/* terminator */
1996 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ROUND)));
1997 }
1998 
1999 /*
2000  * segment_directive segment_name { SIZE_SYMBOL = symbol_name
2001  * ----------------------------------------------^
2002  */
2003 /* ARGSUSED 2 */
2004 static Token
2005 at_seg_size_symbol(Mapfile *mf, Token eq_tok, void *uvalue)
2006 {
2007 	Sg_desc		*sgp = uvalue;
2008 	Token		tok;
2009 	ld_map_tkval_t	tkv;
2010 	Conv_inv_buf_t	inv_buf;
2011 	int		done, cnt = 0;
2012 
2013 	/*
2014 	 * One or more symbol names, terminated by a semicolon.
2015 	 */
2016 	for (done = 0; done == 0; ) {
2017 		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
2018 		case TK_ERROR:
2019 			return (TK_ERROR);
2020 
2021 		case TK_STRING:
2022 			if (!ld_map_seg_size_symbol(mf, sgp, eq_tok,
2023 			    tkv.tkv_str))
2024 				return (TK_ERROR);
2025 			cnt++;
2026 
2027 			/*
2028 			 * If the operator is TK_EQUAL, turn it into
2029 			 * TK_PLUSEQ for any symbol names after the first.
2030 			 * These additional symbols are added, and are not
2031 			 * replacements for the first one.
2032 			 */
2033 			eq_tok = TK_PLUSEQ;
2034 			break;
2035 
2036 		case TK_SEMICOLON:
2037 		case TK_RIGHTBKT:
2038 			done = 1;
2039 			break;
2040 
2041 		default:
2042 			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMNAM),
2043 			    MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL),
2044 			    ld_map_tokenstr(tok, &tkv, &inv_buf));
2045 			return (TK_ERROR);
2046 		}
2047 	}
2048 
2049 	/* Make sure there was at least one name */
2050 	if (cnt == 0) {
2051 		mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
2052 		    MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL));
2053 		return (TK_ERROR);
2054 	}
2055 
2056 	return (tok);
2057 }
2058 
2059 /*
2060  * segment_directive segment_name { VADDR = vaddr
2061  * ----------------------------------------^
2062  */
2063 /* ARGSUSED 1 */
2064 static Token
2065 at_seg_vaddr(Mapfile *mf, Token eq_tok, void *uvalue)
2066 {
2067 	Sg_desc		*sgp = uvalue, *sgp2;
2068 	Aliste		idx;
2069 	ld_map_tkval_t	tkv;
2070 
2071 	/*
2072 	 * Ensure that the segment isn't in the segment order list.
2073 	 */
2074 	for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order, idx, sgp2))
2075 		if (sgp == sgp2) {
2076 			mf_fatal(mf,
2077 			    MSG_INTL(MSG_MAP_CNTADDRORDER), sgp->sg_name);
2078 			return (TK_ERROR);
2079 		}
2080 
2081 	/* value */
2082 	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_VADDR), &tkv) == TK_ERROR)
2083 		return (TK_ERROR);
2084 
2085 	sgp->sg_phdr.p_vaddr = tkv.tkv_int.tkvi_value;
2086 	sgp->sg_flags |= FLG_SG_P_VADDR;
2087 
2088 	/* terminator */
2089 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_VADDR)));
2090 }
2091 
2092 /*
2093  * Top Level Directive:
2094  *
2095  * {LOAD|NOTE|NULL}_SEGMENT segment_name { ...
2096  * ------------------------^
2097  *
2098  * Common implementation body for the family of segment directives. These
2099  * take the same syntax, and share a common subset of attributes. They differ
2100  * in the type of segments they handle and the specific attributes accepted.
2101  *
2102  * entry:
2103  *	mf - Mapfile descriptor ({LOAD|NOTE|NULL}_SEGMENT)
2104  *	dir_name - Name of directive.
2105  *	seg_type - Type of segment (PT_LOAD, PT_NOTE, PT_NULL).
2106  *	attr_list - NULL terminated attribute array
2107  *	attr_list_bufsize - Size of required buffer to format all the
2108  *		names in attr_list.
2109  *	gts_efunc - Error function to pass to gettoken_str() when trying
2110  *		to obtain a segment name token.
2111  */
2112 static Token
2113 dir_segment_inner(Mapfile *mf, const char *dir_name, Word seg_type,
2114     attr_t *attr_list, size_t attr_list_bufsize, gts_efunc_t gts_efunc)
2115 {
2116 	Token		tok;
2117 	ld_map_tkval_t	tkv;
2118 	Sg_desc		*sgp;
2119 	Boolean		new_segment;
2120 	Xword		ndx;
2121 	avl_index_t	where;
2122 
2123 	/* segment_name */
2124 	if (gettoken_str(mf, 0, &tkv, gts_efunc) == TK_ERROR)
2125 		return (TK_ERROR);
2126 	sgp = ld_seg_lookup(mf->mf_ofl, tkv.tkv_str, &where);
2127 	new_segment = (sgp == NULL);
2128 
2129 	if (new_segment) {
2130 		/* Allocate a descriptor for new segment */
2131 		if ((sgp = ld_map_seg_alloc(tkv.tkv_str, seg_type,
2132 		    FLG_SG_P_TYPE)) == NULL)
2133 			return (TK_ERROR);
2134 	} else {
2135 		/* Make sure it's the right type of segment */
2136 		if (sgp->sg_phdr.p_type != seg_type) {
2137 			Conv_inv_buf_t	inv_buf;
2138 
2139 			mf_fatal(mf, MSG_INTL(MSG_MAP_EXPSEGTYPE),
2140 			    conv_phdr_type(ELFOSABI_SOLARIS, ld_targ.t_m.m_mach,
2141 			    sgp->sg_phdr.p_type, CONV_FMT_ALT_CF, &inv_buf),
2142 			    dir_name, tkv.tkv_str);
2143 			return (TK_ERROR);
2144 		}
2145 
2146 		/* If it was disabled, being referenced enables it */
2147 		sgp->sg_flags &= ~FLG_SG_DISABLED;
2148 
2149 		if (DBG_ENABLED) {
2150 			/*
2151 			 * Not a new segment, so show the initial value
2152 			 * before modifying it.
2153 			 */
2154 			ndx = ld_map_seg_index(mf, sgp);
2155 			DBG_CALL(Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_BEFORE,
2156 			    ndx, sgp, mf->mf_lineno));
2157 		}
2158 	}
2159 
2160 	/*
2161 	 * Attributes are optional, so expect an opening '{', or a ';'.
2162 	 */
2163 	switch (tok = gettoken_optattr(mf, dir_name)) {
2164 	default:
2165 		tok = TK_ERROR;
2166 		break;
2167 	case TK_SEMICOLON:
2168 		break;
2169 	case TK_LEFTBKT:
2170 		/* Parse the attributes */
2171 		if (parse_attributes(mf, dir_name,
2172 		    attr_list, attr_list_bufsize, sgp) == TK_ERROR)
2173 			return (TK_ERROR);
2174 
2175 		/* Terminating ';' */
2176 		tok = gettoken_semicolon(mf, dir_name);
2177 		if (tok == TK_ERROR)
2178 			return (TK_ERROR);
2179 
2180 		break;
2181 	}
2182 
2183 	/*
2184 	 * If this is a new segment, finish its initialization
2185 	 * and insert it into the segment list.
2186 	 */
2187 	if (new_segment) {
2188 		if (ld_map_seg_insert(mf, DBG_STATE_NEW, sgp, where) ==
2189 		    SEG_INS_FAIL)
2190 			return (TK_ERROR);
2191 	} else {
2192 		/* Not new. Show what's changed */
2193 		DBG_CALL(Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_AFTER,
2194 		    ndx, sgp, mf->mf_lineno));
2195 	}
2196 
2197 	return (tok);
2198 }
2199 
2200 /*
2201  * dir_load_segment(): Expected loadable segment name is not present
2202  */
2203 static void
2204 gts_efunc_dir_load_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
2205 {
2206 	Conv_inv_buf_t	inv_buf;
2207 
2208 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
2209 	    MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT),
2210 	    ld_map_tokenstr(tok, tkv, &inv_buf));
2211 }
2212 
2213 /*
2214  * Top Level Directive:
2215  *
2216  * LOAD_SEGMENT segment_name { ...
2217  * ------------^
2218  */
2219 static Token
2220 dir_load_segment(Mapfile *mf)
2221 {
2222 	/* LOAD_SEGMENT attributes */
2223 	static attr_t attr_list[] = {
2224 		{ MSG_ORIG(MSG_MAPKW_ALIGN),	at_seg_align,	ATTR_FMT_EQ },
2225 		{ MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
2226 		    at_seg_assign,	ATTR_FMT_NAME },
2227 		{ MSG_ORIG(MSG_MAPKW_DISABLE),	at_seg_disable,	ATTR_FMT_NAME },
2228 		{ MSG_ORIG(MSG_MAPKW_FLAGS),	at_seg_flags,
2229 		    ATTR_FMT_EQ_ALL },
2230 		{ MSG_ORIG(MSG_MAPKW_IS_ORDER),	at_seg_is_order,
2231 		    ATTR_FMT_EQ_PEQ },
2232 		{ MSG_ORIG(MSG_MAPKW_MAX_SIZE),	at_seg_max_size, ATTR_FMT_EQ },
2233 		{ MSG_ORIG(MSG_MAPKW_NOHDR),	at_seg_nohdr,	ATTR_FMT_NAME },
2234 		{ MSG_ORIG(MSG_MAPKW_OS_ORDER),	at_seg_os_order,
2235 		    ATTR_FMT_EQ_PEQ },
2236 		{ MSG_ORIG(MSG_MAPKW_PADDR),	at_seg_paddr,	ATTR_FMT_EQ },
2237 		{ MSG_ORIG(MSG_MAPKW_ROUND),	at_seg_round,	ATTR_FMT_EQ },
2238 		{ MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL),
2239 		    at_seg_size_symbol,	ATTR_FMT_EQ_PEQ },
2240 		{ MSG_ORIG(MSG_MAPKW_VADDR),	at_seg_vaddr,	ATTR_FMT_EQ },
2241 
2242 		/* List must be null terminated */
2243 		{ 0 }
2244 	};
2245 
2246 	/*
2247 	 * Size of buffer needed to format the names in attr_list[]. Must
2248 	 * be kept in sync with attr_list.
2249 	 */
2250 	static size_t	attr_list_bufsize =
2251 	    KW_NAME_SIZE(MSG_MAPKW_ALIGN) +
2252 	    KW_NAME_SIZE(MSG_MAPKW_ASSIGN_SECTION) +
2253 	    KW_NAME_SIZE(MSG_MAPKW_DISABLE) +
2254 	    KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
2255 	    KW_NAME_SIZE(MSG_MAPKW_IS_ORDER) +
2256 	    KW_NAME_SIZE(MSG_MAPKW_MAX_SIZE) +
2257 	    KW_NAME_SIZE(MSG_MAPKW_PADDR) +
2258 	    KW_NAME_SIZE(MSG_MAPKW_ROUND) +
2259 	    KW_NAME_SIZE(MSG_MAPKW_OS_ORDER) +
2260 	    KW_NAME_SIZE(MSG_MAPKW_SIZE_SYMBOL) +
2261 	    KW_NAME_SIZE(MSG_MAPKW_VADDR);
2262 
2263 	return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT),
2264 	    PT_LOAD, attr_list, attr_list_bufsize, gts_efunc_dir_load_segment));
2265 
2266 }
2267 
2268 /*
2269  * Common shared segment directive attributes
2270  */
2271 static attr_t segment_core_attr_list[] = {
2272 	{ MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION), at_seg_assign, ATTR_FMT_NAME },
2273 	{ MSG_ORIG(MSG_MAPKW_DISABLE),	at_seg_disable,	 ATTR_FMT_NAME },
2274 	{ MSG_ORIG(MSG_MAPKW_IS_ORDER),	at_seg_is_order, ATTR_FMT_EQ_PEQ },
2275 	{ MSG_ORIG(MSG_MAPKW_OS_ORDER),	at_seg_os_order, ATTR_FMT_EQ_PEQ },
2276 
2277 	/* List must be null terminated */
2278 	{ 0 }
2279 };
2280 
2281 /*
2282  * Size of buffer needed to format the names in segment_core_attr_list[].
2283  * Must be kept in sync with segment_core_attr_list.
2284  */
2285 static size_t	segment_core_attr_list_bufsize =
2286 	KW_NAME_SIZE(MSG_MAPKW_ASSIGN_SECTION) +
2287 	KW_NAME_SIZE(MSG_MAPKW_DISABLE) +
2288 	KW_NAME_SIZE(MSG_MAPKW_IS_ORDER) +
2289 	KW_NAME_SIZE(MSG_MAPKW_OS_ORDER);
2290 
2291 /*
2292  * dir_note_segment(): Expected note segment name is not present
2293  */
2294 static void
2295 gts_efunc_dir_note_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
2296 {
2297 	Conv_inv_buf_t	inv_buf;
2298 
2299 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
2300 	    MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT),
2301 	    ld_map_tokenstr(tok, tkv, &inv_buf));
2302 }
2303 
2304 /*
2305  * Top Level Directive:
2306  *
2307  * NOTE_SEGMENT segment_name { ...
2308  * ------------^
2309  */
2310 static Token
2311 dir_note_segment(Mapfile *mf)
2312 {
2313 	return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT),
2314 	    PT_NOTE, segment_core_attr_list, segment_core_attr_list_bufsize,
2315 	    gts_efunc_dir_note_segment));
2316 
2317 }
2318 
2319 /*
2320  * dir_null_segment(): Expected null segment name is not present
2321  */
2322 static void
2323 gts_efunc_dir_null_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
2324 {
2325 	Conv_inv_buf_t	inv_buf;
2326 
2327 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
2328 	    MSG_ORIG(MSG_MAPKW_NULL_SEGMENT),
2329 	    ld_map_tokenstr(tok, tkv, &inv_buf));
2330 }
2331 
2332 /*
2333  * Top Level Directive:
2334  *
2335  * NULL_SEGMENT segment_name { ...
2336  * ------------^
2337  */
2338 static Token
2339 dir_null_segment(Mapfile *mf)
2340 {
2341 	return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_NULL_SEGMENT),
2342 	    PT_NULL, segment_core_attr_list, segment_core_attr_list_bufsize,
2343 	    gts_efunc_dir_null_segment));
2344 
2345 }
2346 
2347 /*
2348  * Top Level Directive:
2349  *
2350  * SEGMENT_ORDER segment_name ... ;
2351  */
2352 static Token
2353 dir_segment_order(Mapfile *mf)
2354 {
2355 	Token		tok;
2356 	ld_map_tkval_t	tkv;
2357 	Conv_inv_buf_t	inv_buf;
2358 	Aliste		idx;
2359 	Sg_desc		*sgp, *sgp2;
2360 	int		done;
2361 
2362 	/* Expect either a '=' or '+=' */
2363 	tok = gettoken_eq(mf, ATTR_FMT_EQ_PEQ,
2364 	    MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER));
2365 	if (tok == TK_ERROR)
2366 		return (TK_ERROR);
2367 
2368 	DBG_CALL(Dbg_map_seg_order(mf->mf_ofl, ELFOSABI_SOLARIS,
2369 	    ld_targ.t_m.m_mach, DBG_STATE_MOD_BEFORE, mf->mf_lineno));
2370 
2371 	/*
2372 	 * The '=' form of assignment resets the list. The list contains
2373 	 * pointers to our mapfile text, so we do not have to free anything.
2374 	 */
2375 	if (tok == TK_EQUAL)
2376 		aplist_reset(mf->mf_ofl->ofl_segs_order);
2377 
2378 	/* Read segment names, and add to list until terminator (';') is seen */
2379 	for (done = 0; done == 0; ) {
2380 		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
2381 		case TK_ERROR:
2382 			return (TK_ERROR);
2383 
2384 		case TK_STRING:
2385 			/*
2386 			 * The segment must have already been defined.
2387 			 */
2388 			sgp = ld_seg_lookup(mf->mf_ofl, tkv.tkv_str, NULL);
2389 			if (sgp == NULL) {
2390 				mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSEG),
2391 				    tkv.tkv_str);
2392 				return (TK_ERROR);
2393 			}
2394 
2395 			/*
2396 			 * Make sure it's not already on the list
2397 			 */
2398 			for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order,
2399 			    idx, sgp2))
2400 				if (sgp == sgp2) {
2401 					mf_fatal(mf,
2402 					    MSG_INTL(MSG_MAP_DUPORDSEG),
2403 					    MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER),
2404 					    tkv.tkv_str);
2405 					return (TK_ERROR);
2406 				}
2407 
2408 			/*
2409 			 * It can't be ordered and also have an explicit
2410 			 * paddr or vaddr.
2411 			 */
2412 			if (sgp->sg_flags & (FLG_SG_P_PADDR | FLG_SG_P_VADDR)) {
2413 				mf_fatal(mf, MSG_INTL(MSG_MAP_CNTADDRORDER),
2414 				    sgp->sg_name);
2415 				return (TK_ERROR);
2416 			}
2417 
2418 
2419 			/* Put it at the end of the list */
2420 			if (aplist_append(&mf->mf_ofl->ofl_segs_order, sgp,
2421 			    AL_CNT_SG_IS_ORDER) == NULL)
2422 				return (TK_ERROR);
2423 			break;
2424 
2425 		case TK_SEMICOLON:
2426 			done = 1;
2427 			break;
2428 
2429 		default:
2430 			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
2431 			    MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER),
2432 			    ld_map_tokenstr(tok, &tkv, &inv_buf));
2433 			return (TK_ERROR);
2434 		}
2435 	}
2436 
2437 	DBG_CALL(Dbg_map_seg_order(mf->mf_ofl, ELFOSABI_SOLARIS,
2438 	    ld_targ.t_m.m_mach, DBG_STATE_MOD_AFTER, mf->mf_lineno));
2439 
2440 	return (tok);
2441 }
2442 
2443 /*
2444  * Top Level Directive:
2445  *
2446  * STACK { ...
2447  * -----^
2448  */
2449 static Token
2450 dir_stack(Mapfile *mf)
2451 {
2452 	/* STACK attributes */
2453 	static attr_t attr_list[] = {
2454 		{ MSG_ORIG(MSG_MAPKW_FLAGS), at_seg_flags, ATTR_FMT_EQ_ALL },
2455 
2456 		/* List must be null terminated */
2457 		{ 0 }
2458 	};
2459 
2460 	/*
2461 	 * Size of buffer needed to format the names in attr_list[]. Must
2462 	 * be kept in sync with attr_list.
2463 	 */
2464 	static size_t	attr_list_bufsize =
2465 	    KW_NAME_SIZE(MSG_MAPKW_FLAGS);
2466 
2467 	Sg_desc	*sgp;
2468 	Token	tok;
2469 
2470 
2471 	/* Opening '{' token */
2472 	if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_STACK)) == TK_ERROR)
2473 		return (TK_ERROR);
2474 
2475 	/* Fetch the PT_SUNWSTACK segment descriptor */
2476 	sgp = ld_map_seg_stack(mf);
2477 
2478 	/* Parse the attributes */
2479 	if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_STACK),
2480 	    attr_list, attr_list_bufsize, sgp) == TK_ERROR)
2481 		return (TK_ERROR);
2482 
2483 	/* Terminating ';' */
2484 	tok = gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_STACK));
2485 	if (tok == TK_ERROR)
2486 		return (TK_ERROR);
2487 
2488 	if (DBG_ENABLED) {
2489 		Xword ndx = ld_map_seg_index(mf, sgp);
2490 
2491 		Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_AFTER, ndx, sgp,
2492 		    mf->mf_lineno);
2493 	}
2494 
2495 	return (tok);
2496 }
2497 
2498 /*
2499  * at_sym_aux(): Value for AUXILIARY= is not an object name
2500  */
2501 static void
2502 gts_efunc_at_sym_aux(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
2503 {
2504 	Conv_inv_buf_t	inv_buf;
2505 
2506 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
2507 	    MSG_ORIG(MSG_MAPKW_AUX), ld_map_tokenstr(tok, tkv, &inv_buf));
2508 }
2509 
2510 /*
2511  * SYMBOL [version_name] { symbol_name { AUXILIARY = soname
2512  * -------------------------------------------------^
2513  */
2514 /* ARGSUSED 1 */
2515 static Token
2516 at_sym_aux(Mapfile *mf, Token eq_tok, void *uvalue)
2517 {
2518 	symbol_state_t	*ss = uvalue;
2519 	ld_map_tkval_t	tkv;
2520 
2521 	/* auxiliary filter soname */
2522 	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_sym_aux) == TK_ERROR)
2523 		return (TK_ERROR);
2524 
2525 	ld_map_sym_filtee(mf, &ss->ss_mv, &ss->ss_ms, FLG_SY_AUXFLTR,
2526 	    tkv.tkv_str);
2527 
2528 	/* terminator */
2529 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_AUX)));
2530 }
2531 
2532 /*
2533  * at_sym_filter(): Value for FILTER= is not an object name
2534  */
2535 static void
2536 gts_efunc_at_sym_filter(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
2537 {
2538 	Conv_inv_buf_t	inv_buf;
2539 
2540 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
2541 	    MSG_ORIG(MSG_MAPKW_FILTER), ld_map_tokenstr(tok, tkv, &inv_buf));
2542 }
2543 
2544 /*
2545  * SYMBOL [version_name] { symbol_name { FILTER = soname
2546  * ----------------------------------------------^
2547  */
2548 /* ARGSUSED 1 */
2549 static Token
2550 at_sym_filter(Mapfile *mf, Token eq_tok, void *uvalue)
2551 {
2552 	symbol_state_t	*ss = uvalue;
2553 	ld_map_tkval_t	tkv;
2554 
2555 	/* filter soname */
2556 	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_sym_filter) == TK_ERROR)
2557 		return (TK_ERROR);
2558 
2559 	ld_map_sym_filtee(mf, &ss->ss_mv, &ss->ss_ms, FLG_SY_STDFLTR,
2560 	    tkv.tkv_str);
2561 
2562 	/* terminator */
2563 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILTER)));
2564 }
2565 
2566 /*
2567  * SYMBOL [version_name] { symbol_name { FLAGS = ...
2568  * ---------------------------------------------^
2569  */
2570 /* ARGSUSED 1 */
2571 static Token
2572 at_sym_flags(Mapfile *mf, Token eq_tok, void *uvalue)
2573 {
2574 	typedef struct {
2575 		const char	*name;
2576 		sd_flag_t	value;
2577 	} symflag_t;
2578 
2579 	static symflag_t symflag_list[] = {
2580 		{ MSG_ORIG(MSG_MAPKW_DIRECT),		FLG_SY_DIR },
2581 		{ MSG_ORIG(MSG_MAPKW_DYNSORT),		FLG_SY_DYNSORT },
2582 		{ MSG_ORIG(MSG_MAPKW_EXTERN),		FLG_SY_EXTERN },
2583 		{ MSG_ORIG(MSG_MAPKW_INTERPOSE),	FLG_SY_INTPOSE },
2584 		{ MSG_ORIG(MSG_MAPKW_NODIRECT),		FLG_SY_NDIR },
2585 		{ MSG_ORIG(MSG_MAPKW_NODYNSORT),	FLG_SY_NODYNSORT },
2586 		{ MSG_ORIG(MSG_MAPKW_PARENT),		FLG_SY_PARENT },
2587 
2588 		/* List must be null terminated */
2589 		{ 0 }
2590 	};
2591 
2592 	/*
2593 	 * Size of buffer needed to format the names in flag_list[]. Must
2594 	 * be kept in sync with flag_list.
2595 	 */
2596 	static size_t	symflag_list_bufsize =
2597 	    KW_NAME_SIZE(MSG_MAPKW_DIRECT) +
2598 	    KW_NAME_SIZE(MSG_MAPKW_DYNSORT) +
2599 	    KW_NAME_SIZE(MSG_MAPKW_EXTERN) +
2600 	    KW_NAME_SIZE(MSG_MAPKW_INTERPOSE) +
2601 	    KW_NAME_SIZE(MSG_MAPKW_NODIRECT) +
2602 	    KW_NAME_SIZE(MSG_MAPKW_NODYNSORT) +
2603 	    KW_NAME_SIZE(MSG_MAPKW_PARENT);
2604 
2605 	symbol_state_t	*ss = uvalue;
2606 	int		done;
2607 	symflag_t	*symflag;
2608 	int		cnt = 0;
2609 	Token		tok;
2610 	ld_map_tkval_t	tkv;
2611 	Conv_inv_buf_t	inv_buf;
2612 	Ofl_desc	*ofl = mf->mf_ofl;
2613 
2614 	for (done = 0; done == 0; ) {
2615 		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
2616 		case TK_ERROR:
2617 			return (TK_ERROR);
2618 
2619 		case TK_STRING:
2620 			symflag = ld_map_kwfind(tkv.tkv_str, symflag_list,
2621 			    SGSOFFSETOF(symflag_t, name), sizeof (symflag[0]));
2622 			if (symflag == NULL)
2623 				goto bad_flag;
2624 			cnt++;
2625 			/*
2626 			 * Apply the flag:
2627 			 *
2628 			 * Although tempting to make all of this table-driven
2629 			 * via added fields in symflag_t, there's enough
2630 			 * variation in what each flag does to make that
2631 			 * not quite worthwhile.
2632 			 *
2633 			 * Similarly, it is tempting to use common code to
2634 			 * to do this work from map_support.c. However, the
2635 			 * v1 code mixes unrelated things (flags, symbol types,
2636 			 * value, size, etc) in single cascading series of
2637 			 * strcmps, whereas our parsing separates those things
2638 			 * from each other. Merging the code would require doing
2639 			 * two strcmps for each item, or other complexity,
2640 			 * which I judge not to be worthwhile.
2641 			 */
2642 			switch (symflag->value) {
2643 			case FLG_SY_DIR:
2644 				ss->ss_ms.ms_sdflags |= FLG_SY_DIR;
2645 				ofl->ofl_flags |= FLG_OF_SYMINFO;
2646 				break;
2647 			case FLG_SY_DYNSORT:
2648 				ss->ss_ms.ms_sdflags |= FLG_SY_DYNSORT;
2649 				ss->ss_ms.ms_sdflags &= ~FLG_SY_NODYNSORT;
2650 				break;
2651 			case FLG_SY_EXTERN:
2652 				ss->ss_ms.ms_sdflags |= FLG_SY_EXTERN;
2653 				ofl->ofl_flags |= FLG_OF_SYMINFO;
2654 				break;
2655 			case FLG_SY_INTPOSE:
2656 				if (!(ofl->ofl_flags & FLG_OF_EXEC)) {
2657 					mf_fatal0(mf,
2658 					    MSG_INTL(MSG_MAP_NOINTPOSE));
2659 					ss->ss_mv.mv_errcnt++;
2660 					break;
2661 				}
2662 				ss->ss_ms.ms_sdflags |= FLG_SY_INTPOSE;
2663 				ofl->ofl_flags |= FLG_OF_SYMINFO;
2664 				ofl->ofl_dtflags_1 |= DF_1_SYMINTPOSE;
2665 				break;
2666 			case FLG_SY_NDIR:
2667 				ss->ss_ms.ms_sdflags |= FLG_SY_NDIR;
2668 				ofl->ofl_flags |= FLG_OF_SYMINFO;
2669 				ofl->ofl_flags1 |=
2670 				    (FLG_OF1_NDIRECT | FLG_OF1_NGLBDIR);
2671 				break;
2672 			case FLG_SY_NODYNSORT:
2673 				ss->ss_ms.ms_sdflags &= ~FLG_SY_DYNSORT;
2674 				ss->ss_ms.ms_sdflags |= FLG_SY_NODYNSORT;
2675 				break;
2676 			case FLG_SY_PARENT:
2677 				ss->ss_ms.ms_sdflags |= FLG_SY_PARENT;
2678 				ofl->ofl_flags |= FLG_OF_SYMINFO;
2679 				break;
2680 			}
2681 			break;
2682 		case TK_RIGHTBKT:
2683 		case TK_SEMICOLON:
2684 			done = 1;
2685 			break;
2686 
2687 		default:
2688 		bad_flag:
2689 			{
2690 				char buf[symflag_list_bufsize];
2691 
2692 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMFLAG),
2693 				    ld_map_kwnames(symflag_list,
2694 				    SGSOFFSETOF(symflag_t, name),
2695 				    sizeof (symflag[0]), buf,
2696 				    symflag_list_bufsize),
2697 				    ld_map_tokenstr(tok, &tkv, &inv_buf));
2698 			}
2699 			return (TK_ERROR);
2700 		}
2701 	}
2702 
2703 	/* Make sure there was at least one flag specified */
2704 	if (cnt == 0) {
2705 		mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
2706 		    MSG_ORIG(MSG_MAPKW_FLAGS));
2707 		return (TK_ERROR);
2708 	}
2709 
2710 	return (tok);		/* Either TK_SEMICOLON or TK_RIGHTBKT */
2711 }
2712 
2713 /*
2714  * SYMBOL [version_name] { symbol_name { SIZE = value
2715  * --------------------------------------------^
2716  */
2717 /* ARGSUSED 1 */
2718 static Token
2719 at_sym_size(Mapfile *mf, Token eq_tok, void *uvalue)
2720 {
2721 	symbol_state_t	*ss = uvalue;
2722 	ld_map_tkval_t	tkv;
2723 
2724 	/* value */
2725 	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_SIZE), &tkv) == TK_ERROR)
2726 		return (TK_ERROR);
2727 
2728 	ss->ss_ms.ms_size = tkv.tkv_int.tkvi_value;
2729 
2730 	/* terminator */
2731 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_SIZE)));
2732 }
2733 
2734 typedef struct {
2735 	const char	*name;		/* type name */
2736 	Word		ms_shndx;	/* symbol section index */
2737 	uchar_t		ms_type;	/* STT_ symbol type */
2738 } at_sym_type_t;
2739 
2740 static at_sym_type_t at_sym_type_list[] = {
2741 	{ MSG_ORIG(MSG_MAPKW_COMMON),	SHN_COMMON,	STT_OBJECT },
2742 	{ MSG_ORIG(MSG_MAPKW_DATA),	SHN_ABS,	STT_OBJECT },
2743 	{ MSG_ORIG(MSG_MAPKW_FUNCTION),	SHN_ABS,	STT_FUNC },
2744 
2745 	/* List must be null terminated */
2746 	{ 0 }
2747 };
2748 
2749 /*
2750  * Size of buffer needed to format the names in at_sym_type_list[]. Must
2751  * be kept in sync with at_sym_type_list.
2752  */
2753 static size_t	at_sym_type_list_bufsize =
2754     KW_NAME_SIZE(MSG_MAPKW_COMMON) +
2755     KW_NAME_SIZE(MSG_MAPKW_DATA) +
2756     KW_NAME_SIZE(MSG_MAPKW_FUNCTION);
2757 
2758 /*
2759  * at_sym_type(): Value for TYPE= is not a symbol type
2760  */
2761 static void
2762 gts_efunc_at_sym_type(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
2763 {
2764 	Conv_inv_buf_t	inv_buf;
2765 	char		buf[at_sym_type_list_bufsize];
2766 
2767 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMTYPE),
2768 	    ld_map_kwnames(at_sym_type_list, SGSOFFSETOF(at_sym_type_t, name),
2769 	    sizeof (at_sym_type_list[0]), buf, at_sym_type_list_bufsize),
2770 	    ld_map_tokenstr(tok, tkv, &inv_buf));
2771 }
2772 
2773 /*
2774  * SYMBOL [version_name] { symbol_name { TYPE = symbol_type
2775  * --------------------------------------------^
2776  */
2777 /* ARGSUSED 1 */
2778 static Token
2779 at_sym_type(Mapfile *mf, Token eq_tok, void *uvalue)
2780 {
2781 	symbol_state_t	*ss = uvalue;
2782 	at_sym_type_t	*type;
2783 	ld_map_tkval_t	tkv;
2784 
2785 	/* type keyword */
2786 	if (gettoken_str(mf, TK_F_KEYWORD, &tkv, gts_efunc_at_sym_type) ==
2787 	    TK_ERROR)
2788 		return (TK_ERROR);
2789 
2790 	type = ld_map_kwfind(tkv.tkv_str, at_sym_type_list,
2791 	    SGSOFFSETOF(at_sym_type_t, name), sizeof (type[0]));
2792 	if (type == NULL) {
2793 		gts_efunc_at_sym_type(mf, TK_STRING, &tkv);
2794 		return (TK_ERROR);
2795 	}
2796 
2797 	ss->ss_ms.ms_shndx = type->ms_shndx;
2798 	ss->ss_ms.ms_sdflags |= FLG_SY_SPECSEC;
2799 	ss->ss_ms.ms_type = type->ms_type;
2800 
2801 	/* terminator */
2802 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_TYPE)));
2803 }
2804 
2805 /*
2806  * SYMBOL [version_name] { symbol_name { VALUE = value
2807  * ---------------------------------------------^
2808  */
2809 /* ARGSUSED 1 */
2810 static Token
2811 at_sym_value(Mapfile *mf, Token eq_tok, void *uvalue)
2812 {
2813 	symbol_state_t	*ss = uvalue;
2814 	ld_map_tkval_t	tkv;
2815 
2816 	/* value */
2817 	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_VALUE), &tkv) == TK_ERROR)
2818 		return (TK_ERROR);
2819 
2820 	ss->ss_ms.ms_value = tkv.tkv_int.tkvi_value;
2821 	ss->ss_ms.ms_value_set = TRUE;
2822 
2823 
2824 	/* terminator */
2825 	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_VALUE)));
2826 }
2827 
2828 /*
2829  * Parse the attributes for a SCOPE or VERSION symbol directive.
2830  *
2831  * entry:
2832  *	mf - Mapfile descriptor
2833  *	dir_name - Name of directive.
2834  *	ss - Pointer to symbol state block that has had its ss_nv
2835  *		member initialzed via a call to ld_map_sym_ver_init().
2836  *
2837  * exit:
2838  *	parse_symbol_attributes() returns TK_RIGHTBKT on success, and TK_ERROR
2839  *	on failure.
2840  */
2841 static Token
2842 parse_symbol_attributes(Mapfile *mf, const char *dir_name, symbol_state_t *ss)
2843 {
2844 	/* Symbol attributes */
2845 	static attr_t attr_list[] = {
2846 		{ MSG_ORIG(MSG_MAPKW_AUX),	at_sym_aux,	ATTR_FMT_EQ },
2847 		{ MSG_ORIG(MSG_MAPKW_FILTER),	at_sym_filter,	ATTR_FMT_EQ },
2848 		{ MSG_ORIG(MSG_MAPKW_FLAGS),	at_sym_flags,	ATTR_FMT_EQ },
2849 		{ MSG_ORIG(MSG_MAPKW_SIZE),	at_sym_size,	ATTR_FMT_EQ },
2850 		{ MSG_ORIG(MSG_MAPKW_TYPE),	at_sym_type,	ATTR_FMT_EQ },
2851 		{ MSG_ORIG(MSG_MAPKW_VALUE),	at_sym_value,	ATTR_FMT_EQ },
2852 
2853 		/* List must be null terminated */
2854 		{ 0 }
2855 	};
2856 
2857 	/*
2858 	 * Size of buffer needed to format the names in attr_list[]. Must
2859 	 * be kept in sync with attr_list.
2860 	 */
2861 	static size_t	attr_list_bufsize =
2862 	    KW_NAME_SIZE(MSG_MAPKW_AUX) +
2863 	    KW_NAME_SIZE(MSG_MAPKW_FILTER) +
2864 	    KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
2865 	    KW_NAME_SIZE(MSG_MAPKW_SIZE) +
2866 	    KW_NAME_SIZE(MSG_MAPKW_TYPE) +
2867 	    KW_NAME_SIZE(MSG_MAPKW_VALUE);
2868 
2869 	Token		tok;
2870 	ld_map_tkval_t	tkv, tkv_sym;
2871 	int		done;
2872 	Conv_inv_buf_t	inv_buf;
2873 
2874 	/* Read attributes until the closing '}' is seen */
2875 	for (done = 0; done == 0; ) {
2876 		/*
2877 		 * We have to allow quotes around symbol names, but the
2878 		 * name we read may also be a symbol scope keyword. We won't
2879 		 * know which until we read the following token, and so have
2880 		 * to allow quotes for both. Hence, symbol scope names can
2881 		 * be quoted --- an unlikely occurrence and not worth
2882 		 * complicating the code.
2883 		 */
2884 		switch (tok = ld_map_gettoken(mf, 0, &tkv_sym)) {
2885 		case TK_ERROR:
2886 			return (TK_ERROR);
2887 
2888 		case TK_STRING:
2889 			/* Default value for all symbol attributes is 0 */
2890 			(void) memset(&ss->ss_ms, 0, sizeof (ss->ss_ms));
2891 			ss->ss_ms.ms_name = tkv_sym.tkv_str;
2892 
2893 			/*
2894 			 * Turn off the WEAK flag to indicate that definitions
2895 			 * are associated with this version. It would probably
2896 			 * be more accurate to only remove this flag with the
2897 			 * specification of global symbols, however setting it
2898 			 * here allows enough slop to compensate for the
2899 			 * various user inputs we've seen so far. Only if a
2900 			 * closed version is specified (i.e., "SUNW_1.x {};")
2901 			 * will a user get a weak version (which is how we
2902 			 * document the creation of weak versions).
2903 			 */
2904 			ss->ss_mv.mv_vdp->vd_flags &= ~VER_FLG_WEAK;
2905 
2906 			/*
2907 			 * The meaning of this name depends on the following
2908 			 * character:
2909 			 *
2910 			 *	:	Scope
2911 			 *	;	Symbol without attributes
2912 			 *	{	Symbol with attributes
2913 			 */
2914 			switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
2915 			case TK_ERROR:
2916 				return (TK_ERROR);
2917 
2918 			case TK_COLON:
2919 				ld_map_sym_scope(mf, tkv_sym.tkv_str,
2920 				    &ss->ss_mv);
2921 				break;
2922 			case TK_LEFTBKT:
2923 				/* name is a symbol with attributes */
2924 				if (parse_attributes(mf, tkv_sym.tkv_str,
2925 				    attr_list, attr_list_bufsize, ss) ==
2926 				    TK_ERROR)
2927 					return (TK_ERROR);
2928 				/* Terminating ';', or '}' */
2929 				tok = gettoken_term(mf,
2930 				    MSG_INTL(MSG_MAP_SYMATTR));
2931 				if (tok == TK_ERROR)
2932 					return (TK_ERROR);
2933 				if (tok == TK_RIGHTBKT)
2934 					done = 1;
2935 
2936 				/* FALLTHROUGH */
2937 			case TK_SEMICOLON:
2938 				/*
2939 				 * Add the new symbol. It should be noted that
2940 				 * all symbols added by the mapfile start out
2941 				 * with global scope, thus they will fall
2942 				 * through the normal symbol resolution
2943 				 * process.  Symbols defined as locals will
2944 				 * be reduced in scope after all input file
2945 				 * processing.
2946 				 */
2947 				if (!ld_map_sym_enter(mf, &ss->ss_mv,
2948 				    &ss->ss_ms))
2949 					return (TK_ERROR);
2950 				break;
2951 			default:
2952 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMDELIM),
2953 				    ld_map_tokenstr(tok, &tkv, &inv_buf));
2954 				return (TK_ERROR);
2955 			}
2956 			break;
2957 
2958 		case TK_RIGHTBKT:
2959 			done = 1;
2960 			break;
2961 
2962 		case TK_SEMICOLON:
2963 			break;		/* Ignore empty statement */
2964 
2965 		case TK_STAR:
2966 			/*
2967 			 * Turn off the WEAK flag, as explained above for
2968 			 * TK_STRING.
2969 			 */
2970 			ss->ss_mv.mv_vdp->vd_flags &= ~VER_FLG_WEAK;
2971 
2972 			ld_map_sym_autoreduce(mf, &ss->ss_mv);
2973 
2974 			/*
2975 			 * Following token must be ';' to terminate the stmt,
2976 			 * or '}' to terminate the whole directive.
2977 			 */
2978 			switch (tok = gettoken_term(mf, dir_name)) {
2979 			case TK_ERROR:
2980 				return (TK_ERROR);
2981 			case TK_RIGHTBKT:
2982 				done = 1;
2983 				break;
2984 			}
2985 			break;
2986 
2987 		default:
2988 			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYM),
2989 			    ld_map_tokenstr(tok, &tkv_sym, &inv_buf));
2990 			return (TK_ERROR);
2991 		}
2992 	}
2993 
2994 	/*
2995 	 * In the SYMBOL directive, we keep parsing in the face of
2996 	 * errors that don't involve resources, to maximize what we
2997 	 * can report in a single invocation. If we encountered such
2998 	 * an error, act on the error(s) now.
2999 	 */
3000 	if (ss->ss_mv.mv_errcnt)
3001 		return (TK_ERROR);
3002 
3003 	return (tok);
3004 }
3005 
3006 
3007 /*
3008  * Top Level Directive:
3009  *
3010  * SYMBOL_SCOPE { ...
3011  * ------------^
3012  */
3013 static Token
3014 dir_symbol_scope(Mapfile *mf)
3015 {
3016 	symbol_state_t	ss;
3017 
3018 	/* The first token must be a '{' */
3019 	if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE)) == TK_ERROR)
3020 		return (TK_ERROR);
3021 
3022 	/* Establish the version descriptor and related data */
3023 	if (!ld_map_sym_ver_init(mf, NULL, &ss.ss_mv))
3024 		return (TK_ERROR);
3025 
3026 	/* Read attributes until the closing '}' is seen */
3027 	if (parse_symbol_attributes(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE),
3028 	    &ss) == TK_ERROR)
3029 		return (TK_ERROR);
3030 
3031 	/* Terminating ';' */
3032 	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE)));
3033 }
3034 
3035 
3036 /*
3037  * at_dv_allow(): Value for ALLOW= is not a version string
3038  */
3039 static void
3040 gts_efunc_dir_symbol_version(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
3041 {
3042 	Conv_inv_buf_t	inv_buf;
3043 
3044 	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
3045 	    MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION),
3046 	    ld_map_tokenstr(tok, tkv, &inv_buf));
3047 }
3048 
3049 /*
3050  * Top Level Directive:
3051  *
3052  * SYMBOL_VERSION version_name { ...
3053  * --------------^
3054  */
3055 static Token
3056 dir_symbol_version(Mapfile *mf)
3057 {
3058 
3059 	ld_map_tkval_t	tkv;
3060 	symbol_state_t	ss;
3061 
3062 	/* The first token must be a version name */
3063 	if (gettoken_str(mf, 0, &tkv, gts_efunc_dir_symbol_version) == TK_ERROR)
3064 		return (TK_ERROR);
3065 
3066 	/* The next token is expected to be '{' */
3067 	if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION)) ==
3068 	    TK_ERROR)
3069 		return (TK_ERROR);
3070 
3071 	/* Establish the version descriptor and related data */
3072 	if (!ld_map_sym_ver_init(mf, tkv.tkv_str, &ss.ss_mv))
3073 		return (TK_ERROR);
3074 
3075 	/* Read attributes until the closing '}' is seen */
3076 	if (parse_symbol_attributes(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION),
3077 	    &ss) == TK_ERROR)
3078 		return (TK_ERROR);
3079 
3080 	/*
3081 	 * Determine if any version references are provided after the close
3082 	 * bracket, parsing up to the terminating ';'.
3083 	 */
3084 	if (!ld_map_sym_ver_fini(mf, &ss.ss_mv))
3085 		return (TK_ERROR);
3086 
3087 	return (TK_SEMICOLON);
3088 }
3089 
3090 
3091 /*
3092  * Parse the mapfile --- Solaris syntax
3093  */
3094 Boolean
3095 ld_map_parse_v2(Mapfile *mf)
3096 {
3097 	/* Valid top level mapfile directives */
3098 	typedef struct {
3099 		const char	*name;	/* Directive */
3100 		dir_func_t	func;	/* Function to parse directive */
3101 	} tldir_t;
3102 
3103 
3104 	tldir_t dirlist[] = {
3105 		{ MSG_ORIG(MSG_MAPKW_CAPABILITY),	dir_capability },
3106 		{ MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS),	dir_depend_versions },
3107 		{ MSG_ORIG(MSG_MAPKW_HDR_NOALLOC),	dir_hdr_noalloc },
3108 		{ MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT),	dir_load_segment },
3109 		{ MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT),	dir_note_segment },
3110 		{ MSG_ORIG(MSG_MAPKW_NULL_SEGMENT),	dir_null_segment },
3111 		{ MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL),	dir_phdr_add_null },
3112 		{ MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER),	dir_segment_order },
3113 		{ MSG_ORIG(MSG_MAPKW_STACK),		dir_stack },
3114 		{ MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE),	dir_symbol_scope },
3115 		{ MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION),	dir_symbol_version },
3116 
3117 		/* List must be null terminated */
3118 		{ 0 }
3119 	};
3120 
3121 	/*
3122 	 * Size of buffer needed to format the names in dirlist[]. Must
3123 	 * be kept in sync with dirlist.
3124 	 */
3125 	static size_t dirlist_bufsize =
3126 	    KW_NAME_SIZE(MSG_MAPKW_CAPABILITY) +
3127 	    KW_NAME_SIZE(MSG_MAPKW_DEPEND_VERSIONS) +
3128 	    KW_NAME_SIZE(MSG_MAPKW_HDR_NOALLOC) +
3129 	    KW_NAME_SIZE(MSG_MAPKW_LOAD_SEGMENT) +
3130 	    KW_NAME_SIZE(MSG_MAPKW_NOTE_SEGMENT) +
3131 	    KW_NAME_SIZE(MSG_MAPKW_NULL_SEGMENT) +
3132 	    KW_NAME_SIZE(MSG_MAPKW_PHDR_ADD_NULL) +
3133 	    KW_NAME_SIZE(MSG_MAPKW_SEGMENT_ORDER) +
3134 	    KW_NAME_SIZE(MSG_MAPKW_STACK) +
3135 	    KW_NAME_SIZE(MSG_MAPKW_SYMBOL_SCOPE) +
3136 	    KW_NAME_SIZE(MSG_MAPKW_SYMBOL_VERSION);
3137 
3138 	Token		tok;		/* current token. */
3139 	ld_map_tkval_t	tkv;		/* Value of token */
3140 	tldir_t		*tldir;
3141 	Conv_inv_buf_t	inv_buf;
3142 
3143 	for (;;) {
3144 		tok = ld_map_gettoken(mf, TK_F_EOFOK | TK_F_KEYWORD, &tkv);
3145 		switch (tok) {
3146 		case TK_ERROR:
3147 			return (FALSE);
3148 		case TK_EOF:
3149 			return (TRUE);
3150 		case TK_SEMICOLON: /* Terminator, or empty directive: Ignore */
3151 			break;
3152 		case TK_STRING:
3153 			/* Map name to entry in dirlist[] */
3154 			tldir = ld_map_kwfind(tkv.tkv_str, dirlist,
3155 			    SGSOFFSETOF(tldir_t, name), sizeof (dirlist[0]));
3156 
3157 			/* Not a directive we know? */
3158 			if (tldir == NULL)
3159 				goto bad_dirtok;
3160 
3161 			/* Call the function associated with this directive */
3162 			if (tldir->func(mf) == TK_ERROR)
3163 				return (FALSE);
3164 			break;
3165 		default:
3166 		bad_dirtok:
3167 			{
3168 				char buf[dirlist_bufsize];
3169 
3170 				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_DIR),
3171 				    ld_map_kwnames(dirlist,
3172 				    SGSOFFSETOF(tldir_t, name),
3173 				    sizeof (dirlist[0]), buf, dirlist_bufsize),
3174 				    ld_map_tokenstr(tok, &tkv, &inv_buf));
3175 			}
3176 			return (FALSE);
3177 		}
3178 	}
3179 
3180 	/*NOTREACHED*/
3181 	assert(0);
3182 	return (FALSE);
3183 }
3184