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