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