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