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