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