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