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