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