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