map_v2.c revision 11827:d7ef53deac3f
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 */
48typedef 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 */
58typedef 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 */
66typedef 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 */
92typedef 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 */
109typedef 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 */
122typedef 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 */
141static Token
142gettoken_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 */
202static void
203setflags_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 */
236static Boolean
237set_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 */
298static Boolean
299set_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 */
445static Token
446gettoken_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 */
475static Token
476gettoken_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 */
504static Token
505gettoken_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 */
533static Token
534gettoken_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 */
562static Token
563gettoken_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 */
592static Token
593gettoken_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 */
642static Token
643parse_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 */
744static Token
745parse_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 */
877static Token
878parse_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 */
938static Token
939parse_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 */
993static Token
994at_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 */
1048static Token
1049at_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 */
1060static Token
1061at_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 */
1072static Token
1073at_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 */
1120static Token
1121at_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 */
1132static Token
1133at_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 */
1144static Token
1145at_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 */
1157static Token
1158dir_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 */
1256static void
1257gts_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 */
1270static Token
1271at_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 */
1289static void
1290gts_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 */
1303static Token
1304at_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 */
1323static void
1324gts_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 */
1339static Token
1340dir_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 */
1390static Token
1391dir_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 */
1406static Token
1407dir_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 */
1440static Token
1441at_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 */
1460static void
1461gts_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 */
1476static Token
1477at_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 */
1497static void
1498gts_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 */
1513static Token
1514at_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 */
1534static void
1535gts_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 */
1549static Token
1550at_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 */
1572static Token
1573at_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 */
1676static void
1677gts_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 */
1690static Token
1691at_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 */
1709static void
1710gts_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 */
1723static Token
1724at_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 */
1771static Token
1772at_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 */
1868static Token
1869at_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 */
1897static Token
1898at_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 */
1919static Token
1920at_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 */
1994static Token
1995at_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 */
2016static Token
2017at_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 */
2042static Token
2043at_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 */
2091static Token
2092at_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 */
2124static Token
2125at_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 */
2146static Token
2147at_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 */
2206static Token
2207at_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 */
2254static Token
2255dir_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 */
2345static void
2346gts_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 */
2361static Token
2362dir_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 */
2413static 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 */
2427static 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 */
2436static void
2437gts_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 */
2452static Token
2453dir_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 */
2464static void
2465gts_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 */
2480static Token
2481dir_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 */
2494static Token
2495dir_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 */
2591static Token
2592dir_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 */
2643static void
2644gts_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 */
2657static Token
2658at_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 */
2677static void
2678gts_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 */
2691static Token
2692at_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 */
2713static Token
2714at_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 */
2860static Token
2861at_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
2876typedef 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
2882static 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 */
2895static 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 */
2903static void
2904gts_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 */
2920static Token
2921at_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 */
2952static Token
2953at_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 */
2983static Token
2984parse_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 */
3155static Token
3156dir_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 */
3181static void
3182gts_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 */
3197static Token
3198dir_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 */
3236Boolean
3237ld_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