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