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.
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.
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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Map file parsing, Version 2 syntax (solaris).
33 #include <sys/elf_amd64.h> /* SHF_AMD64_LARGE */
40 * Use a case insensitive string match when looking up capability mask
41 * values by name, and omit the AV_ prefix.
43 #define ELFCAP_STYLE ELFCAP_STYLE_LC | ELFCAP_STYLE_F_ICMP
46 * Signature for functions used to parse top level mapfile directives
48 typedef Token (*dir_func_t
)(Mapfile
*mf
);
51 * Signature for functions used to parse attribute level assignments
52 * mf - Mapfile descriptor
53 * eq_tok - One of the equal tokens (TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ)
54 * or TK_ERROR. See the comment for attr_fmt_t below.
55 * uvalue - An arbitrary pointer "user value" passed by the
56 * caller to parse_attributes() for use by the function.
58 typedef Token (* attr_func_t
)(Mapfile
*mf
, Token eq_tok
, void *uvalue
);
61 * Signature for gettoken_str() err_func argument. This is a function
62 * called to issue an appropriate error message.
64 * The gts prefix stands for "Get Token Str"
66 typedef void (* gts_efunc_t
)(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
);
69 * The attr_fmt_t tells parse_attributes how far to go in parsing
70 * an attribute before it calls the at_func function to take over:
72 * ATTR_FMT_NAME - Parse the name, and immediately call the function.
73 * This is useful in cases where there is more than
74 * one possible syntax for a given attribute. The value of
75 * eq_tok passed to the at_func function will be TK_ERROR,
76 * reflecting the fact that it has no meaning in this context.
78 * ATTR_FMT_EQ - Parse the name, and the following '=', and then call
79 * the function. The value passed to the at_func function for
80 * eq_tok will be TK_EQUAL.
82 * ATTR_FMT_EQ_PEQ - Parse the name, and a following equal token which
83 * can be '=' or '+=', and then call the function. The value
84 * passed to the at_func function for eq_tok will be one of
85 * TK_EQUAL, or TK_PLUSEQ.
87 * ATTR_FMT_EQ_ALL - Parse the name, and a following equal token which
88 * can be any of the three forms (=, +=, -=), and then call
89 * the function. The value passed to the at_func function for
90 * eq_tok will be one of TK_EQUAL, TK_PLUSEQ, or TK_MINUSEQ.
100 * Type used to describe a set of valid attributes to parse_attributes():
101 * at_name - Name of attribute
102 * at_func - Function to call when attribute is recognized,
103 * at_all_eq - True if attribute allows the '+=' and '-=' forms of
104 * assignment token, and False to only allow '='.
106 * The array of these structs passed to parse_attributes() must be
107 * NULL terminated (the at_name field must be set to NULL).
110 const char *at_name
; /* Name of attribute */
111 attr_func_t at_func
; /* Function to call */
112 attr_fmt_t at_fmt
; /* How much to parse before calling */
117 * Mapfile version and symbol state are separate but related concepts
118 * that are best represented using two different types. However, our
119 * style of passing a single uvalue via parse_attributes() makes it
120 * convenient to be able to reference them from a single address.
128 * Process an expected equal operator. Deals with the fact that we
129 * have three variants.
132 * mf - Mapfile descriptor
133 * eq_type - Types of equal operators accepted. One of ATTR_FMT_EQ,
134 * ATTR_FMT_EQ_PEQ, or ATTR_FMT_EQ_ALL.
135 * lhs - Name that appears on the left hand side of the expected
139 * Returns one of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, or TK_ERROR.
142 gettoken_eq(Mapfile
*mf
, attr_fmt_t eq_type
, const char *lhs
)
147 Conv_inv_buf_t inv_buf
;
149 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
156 case ATTR_FMT_EQ_PEQ
:
157 case ATTR_FMT_EQ_ALL
:
163 if (eq_type
== ATTR_FMT_EQ_ALL
)
170 err
= MSG_INTL(MSG_MAP_EXP_EQ
);
172 case ATTR_FMT_EQ_PEQ
:
173 err
= MSG_INTL(MSG_MAP_EXP_EQ_PEQ
);
175 case ATTR_FMT_EQ_ALL
:
176 err
= MSG_INTL(MSG_MAP_EXP_EQ_ALL
);
182 mf_fatal(mf
, err
, lhs
, ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
187 * Apply one of the three equal tokens to a bitmask value
190 * dst - Address of bitmask variable to alter
191 * eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
192 * the operation to carry out.
193 * value - Value for right hand side
196 * The operation has been carried out:
198 * TK_EQUAL - *dst is set to value
199 * TK_PLUSEQ - Bits in value have been set in *dst
200 * TK_MINUSEQ - Bits in value have been removed from *dst
203 setflags_eq(Word
*dst
, Token eq_tok
, Word value
)
222 * Apply one of the three equal tokens to a capabilities Capmask.
225 * mf - Mapfile descriptor
226 * capmask - Address of Capmask variable to alter
227 * eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
228 * the operation to carry out.
229 * type - Capability type (CA_SUNW_*)
230 * value - Value for right hand side
231 * title - True if a title is needed, False otherwise.
234 * On success, returns TRUE (1), otherwise FALSE (0)
237 set_capmask(Mapfile
*mf
, Capmask
*capmask
, Token eq_tok
,
238 Word type
, elfcap_mask_t value
, Boolean title
)
241 DBG_CALL(Dbg_cap_mapfile_title(mf
->mf_ofl
->ofl_lml
,
243 DBG_CALL(Dbg_cap_val_entry(mf
->mf_ofl
->ofl_lml
, DBG_STATE_CURRENT
,
244 type
, capmask
->cm_val
, ld_targ
.t_m
.m_mach
));
248 capmask
->cm_val
= value
;
250 ld_map_cap_set_ovflag(mf
, type
);
251 DBG_CALL(Dbg_cap_val_entry(mf
->mf_ofl
->ofl_lml
,
252 DBG_STATE_RESET
, type
, capmask
->cm_val
,
253 ld_targ
.t_m
.m_mach
));
256 DBG_CALL(Dbg_cap_val_entry(mf
->mf_ofl
->ofl_lml
,
257 DBG_STATE_ADD
, type
, value
, ld_targ
.t_m
.m_mach
));
258 capmask
->cm_val
|= value
;
259 capmask
->cm_exc
&= ~value
;
262 DBG_CALL(Dbg_cap_val_entry(mf
->mf_ofl
->ofl_lml
,
263 DBG_STATE_EXCLUDE
, type
, value
, ld_targ
.t_m
.m_mach
));
264 capmask
->cm_val
&= ~value
;
265 capmask
->cm_exc
|= value
;
272 /* Sanity check the resulting bits */
273 if (!ld_map_cap_sanitize(mf
, type
, capmask
))
276 /* Report the final configuration */
277 DBG_CALL(Dbg_cap_val_entry(mf
->mf_ofl
->ofl_lml
,
278 DBG_STATE_RESOLVED
, type
, capmask
->cm_val
, ld_targ
.t_m
.m_mach
));
284 * Apply one of the three equal tokens to a capabilities Caplist.
287 * mf - Mapfile descriptor
288 * caplist - Address of Caplist variable to alter
289 * eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
290 * the operation to carry out.
291 * type - Capability type (CA_SUNW_*)
292 * str - String for right hand side
293 * title - True if a title is needed, False otherwise.
296 * On success, returns TRUE (1), otherwise FALSE (0)
299 set_capstr(Mapfile
*mf
, Caplist
*caplist
, Token eq_tok
,
300 Word type
, APlist
*strs
)
306 DBG_CALL(Dbg_cap_mapfile_title(mf
->mf_ofl
->ofl_lml
, mf
->mf_lineno
));
308 if ((caplist
->cl_val
== NULL
) || (alist_nitems(caplist
->cl_val
) == 0)) {
309 DBG_CALL(Dbg_cap_ptr_entry(mf
->mf_ofl
->ofl_lml
,
310 DBG_STATE_CURRENT
, type
, NULL
));
312 for (ALIST_TRAVERSE(caplist
->cl_val
, idx1
, capstr
)) {
313 DBG_CALL(Dbg_cap_ptr_entry(mf
->mf_ofl
->ofl_lml
,
314 DBG_STATE_CURRENT
, type
, capstr
->cs_str
));
320 if (caplist
->cl_val
) {
321 (void) free(caplist
->cl_val
);
322 caplist
->cl_val
= NULL
;
324 if (caplist
->cl_exc
) {
325 (void) free(caplist
->cl_exc
);
326 caplist
->cl_exc
= NULL
;
329 for (APLIST_TRAVERSE(strs
, idx1
, str
)) {
330 if ((capstr
= alist_append(&caplist
->cl_val
,
331 NULL
, sizeof (Capstr
),
332 AL_CNT_CAP_NAMES
)) == NULL
)
334 capstr
->cs_str
= str
;
335 DBG_CALL(Dbg_cap_ptr_entry(mf
->mf_ofl
->ofl_lml
,
336 DBG_STATE_RESET
, type
, capstr
->cs_str
));
339 DBG_CALL(Dbg_cap_ptr_entry(mf
->mf_ofl
->ofl_lml
,
340 DBG_STATE_RESET
, type
, NULL
));
342 ld_map_cap_set_ovflag(mf
, type
);
345 for (APLIST_TRAVERSE(strs
, idx1
, str
)) {
351 * Add this name to the list of names, provided the
352 * name doesn't already exist.
354 for (ALIST_TRAVERSE(caplist
->cl_val
, idx2
, capstr
)) {
355 if (strcmp(str
, capstr
->cs_str
) == 0) {
360 if ((found
== 0) && ((capstr
=
361 (Capstr
*)alist_append(&caplist
->cl_val
, NULL
,
362 sizeof (Capstr
), AL_CNT_CAP_NAMES
)) == NULL
))
364 capstr
->cs_str
= str
;
367 * Remove this name from the list of excluded names,
368 * provided the name already exists.
370 for (APLIST_TRAVERSE(caplist
->cl_exc
, idx2
, ostr
)) {
371 if (strcmp(str
, ostr
) == 0) {
372 aplist_delete(caplist
->cl_exc
, &idx2
);
376 DBG_CALL(Dbg_cap_ptr_entry(mf
->mf_ofl
->ofl_lml
,
377 DBG_STATE_ADD
, type
, str
));
381 for (APLIST_TRAVERSE(strs
, idx1
, str
)) {
387 * Delete this name from the list of names, provided
388 * the name already exists.
390 for (ALIST_TRAVERSE(caplist
->cl_val
, idx2
, capstr
)) {
391 if (strcmp(str
, capstr
->cs_str
) == 0) {
392 alist_delete(caplist
->cl_val
, &idx2
);
398 * Add this name to the list of excluded names,
399 * provided the name already exists.
401 for (APLIST_TRAVERSE(caplist
->cl_exc
, idx2
, ostr
)) {
402 if (strcmp(str
, ostr
) == 0) {
407 if ((found
== 0) && (aplist_append(&caplist
->cl_exc
,
408 str
, AL_CNT_CAP_NAMES
) == NULL
))
411 DBG_CALL(Dbg_cap_ptr_entry(mf
->mf_ofl
->ofl_lml
,
412 DBG_STATE_EXCLUDE
, type
, str
));
420 /* Report the final configuration */
421 if ((caplist
->cl_val
== NULL
) || (alist_nitems(caplist
->cl_val
) == 0)) {
422 DBG_CALL(Dbg_cap_ptr_entry(mf
->mf_ofl
->ofl_lml
,
423 DBG_STATE_RESOLVED
, type
, NULL
));
425 for (ALIST_TRAVERSE(caplist
->cl_val
, idx1
, capstr
)) {
426 DBG_CALL(Dbg_cap_ptr_entry(mf
->mf_ofl
->ofl_lml
,
427 DBG_STATE_RESOLVED
, type
, capstr
->cs_str
));
435 * Process the next token, which is expected to start an optional
436 * nesting of attributes (';' or '{').
439 * mf - Mapfile descriptor
440 * lhs - Name of the directive or attribute being processed.
443 * Returns TK_SEMICOLON or TK_LEFTBKT for success, and TK_ERROR otherwise.
446 gettoken_optattr(Mapfile
*mf
, const char *lhs
)
450 Conv_inv_buf_t inv_buf
;
452 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
459 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SEMLBKT
), lhs
,
460 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
465 * Process the next token, which is expected to be a line terminator
469 * mf - Mapfile descriptor
470 * lhs - Name of the directive or attribute being processed.
473 * Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
476 gettoken_term(Mapfile
*mf
, const char *lhs
)
480 Conv_inv_buf_t inv_buf
;
482 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
489 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SEMRBKT
), lhs
,
490 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
495 * Process the next token, which is expected to be a semicolon.
498 * mf - Mapfile descriptor
499 * lhs - Name of the directive or attribute being processed.
502 * Returns TK_SEMICOLON for success, and TK_ERROR otherwise.
505 gettoken_semicolon(Mapfile
*mf
, const char *lhs
)
509 Conv_inv_buf_t inv_buf
;
511 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
517 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SEM
), lhs
,
518 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
523 * Process the next token, which is expected to be a '{'
526 * mf - Mapfile descriptor
527 * lhs - Name of the item directly to the left of the expected left
531 * Returns TK_LEFTBKT for success, and TK_ERROR otherwise.
534 gettoken_leftbkt(Mapfile
*mf
, const char *lhs
)
538 Conv_inv_buf_t inv_buf
;
540 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
546 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_LBKT
), lhs
,
547 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
552 * Process the next token, which is expected to be an integer
555 * mf - Mapfile descriptor
556 * lhs - Name of the directive or attribute being processed.
557 * tkv - Address of token value struct to be filled in
560 * Updates *tkv and returns TK_INT for success, TK_ERROR otherwise.
563 gettoken_int(Mapfile
*mf
, const char *lhs
, ld_map_tkval_t
*tkv
)
566 Conv_inv_buf_t inv_buf
;
568 switch (tok
= ld_map_gettoken(mf
, 0, tkv
)) {
574 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_INT
), lhs
,
575 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
580 * Process the next token, which is expected to be a string
583 * mf - Mapfile descriptor
584 * lhs - Name of the directive or attribute being processed.
585 * tkv - Address of token value struct to be filled in
586 * err_func - Function to call if an error occurs
589 * Updates *tkv and returns TK_STRING for success. Calls the
590 * supplied err_func function and returns TK_ERROR otherwise.
593 gettoken_str(Mapfile
*mf
, int flags
, ld_map_tkval_t
*tkv
, gts_efunc_t efunc
)
597 switch (tok
= ld_map_gettoken(mf
, flags
, tkv
)) {
603 /* User supplied function reports the error */
604 (* efunc
)(mf
, tok
, tkv
);
610 * Given a construct of the following common form:
617 * where the caller has detected the item_name and opening bracket,
618 * parse the construct and call the attribute functions for each
619 * attribute detected, stopping when the closing '}' is seen.
622 * mf - Mapfile descriptor
623 * item_name - Already detected name of item for which attributes
625 * attr_list - NULL terminated array of attr_t structures describing the
626 * valid attributes for the item.
627 * expect_str - Comma separated string listing the names of expected
629 * uvalue - User value, passed to the attribute functions without
630 * examination by parse_attributes(), usable for maintaining
631 * shared state between the caller and the functions.
634 * parse_attributes() reads the attribute name and equality token,
635 * and then calls the attribute function given by the attr_list array
636 * to handle everything up to and including the terminating ';'.
637 * This continues until the closing '}' is seen.
639 * If everything is successful, TK_RIGHTBKT is returned. Otherwise,
640 * a suitable error is issued and TK_ERROR is returned.
643 parse_attributes(Mapfile
*mf
, const char *item_name
, attr_t
*attr_list
,
644 size_t attr_list_bufsize
, void *uvalue
)
651 Conv_inv_buf_t inv_buf
;
653 /* Read attributes until the closing '}' is seen */
654 for (done
= 0; done
== 0; ) {
655 switch (tok
= ld_map_gettoken(mf
, TK_F_KEYWORD
, &tkv
)) {
660 attr
= ld_map_kwfind(tkv
.tkv_str
, attr_list
,
661 SGSOFFSETOF(attr_t
, at_name
), sizeof (attr
[0]));
666 * Depending on the value of at_fmt, there are
667 * fout different actions to take:
668 * ATTR_FMT_NAME - Call at_func function
669 * ATTR_FMT_EQ - Read and verify a TK_EQUAL
670 * ATTR_FMT_EQ_PEQ - Read and verify a TK_EQUAL
672 * ATTR_FMT_EQ_ALL - Read/Verify one of the
673 * three possible equal tokens
674 * (TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ).
676 if (attr
->at_fmt
== ATTR_FMT_NAME
) {
677 /* Arbitrary value to pass to at_func */
680 /* Read/Verify appropriate equal operator */
681 op_tok
= gettoken_eq(mf
, attr
->at_fmt
,
683 if (op_tok
== TK_ERROR
)
687 /* Call the associated function */
688 switch (tok
= attr
->at_func(mf
, op_tok
, uvalue
)) {
705 break; /* Ignore empty statement */
710 char buf
[VLA_SIZE(attr_list_bufsize
)];
712 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_ATTR
),
713 ld_map_kwnames(attr_list
,
714 SGSOFFSETOF(attr_t
, at_name
),
715 sizeof (attr
[0]), buf
, attr_list_bufsize
),
716 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
722 /* Make sure there was at least one attribute between the {} brackets */
724 mf_fatal(mf
, MSG_INTL(MSG_MAP_NOATTR
), item_name
);
732 * Read whitespace delimited segment flags from the input and convert into
733 * bitmask of PF_ values they represent. Flags are terminated by a semicolon
737 * mf - Mapfile descriptor
738 * flags - Address of variable to be set to resulting flags value
741 * Returns the terminator token (TK_SEMICOLON or TK_LEFTBKT) on success,
742 * and TK_ERROR otherwise.
745 parse_segment_flags(Mapfile
*mf
, Xword
*flags
)
748 * Map flag names to their values. Since DATA and STACK have
749 * platform dependent values, we have to determine them at runtime.
750 * We indicate this by setting the top bit.
752 #define PF_DATA 0x80000000
753 #define PF_STACK 0x80000001
758 static segflag_t flag_list
[] = {
759 { MSG_ORIG(MSG_MAPKW_DATA
), PF_DATA
},
760 { MSG_ORIG(MSG_MAPKW_EXECUTE
), PF_X
},
761 { MSG_ORIG(MSG_MAPKW_READ
), PF_R
},
762 { MSG_ORIG(MSG_MAPKW_STACK
), PF_STACK
},
763 { MSG_ORIG(MSG_MAPKW_WRITE
), PF_W
},
765 /* List must be null terminated */
770 * Size of buffer needed to format the names in flag_list[]. Must
771 * be kept in sync with flag_list.
773 static size_t flag_list_bufsize
=
774 KW_NAME_SIZE(MSG_MAPKW_DATA
) +
775 KW_NAME_SIZE(MSG_MAPKW_EXECUTE
) +
776 KW_NAME_SIZE(MSG_MAPKW_READ
) +
777 KW_NAME_SIZE(MSG_MAPKW_STACK
) +
778 KW_NAME_SIZE(MSG_MAPKW_WRITE
);
785 Conv_inv_buf_t inv_buf
;
789 /* Read attributes until the ';' terminator is seen */
790 for (done
= 0; done
== 0; ) {
791 switch (tok
= ld_map_gettoken(mf
, TK_F_KEYWORD
, &tkv
)) {
796 flag
= ld_map_kwfind(tkv
.tkv_str
, flag_list
,
797 SGSOFFSETOF(segflag_t
, name
),
798 sizeof (flag_list
[0]));
801 switch (flag
->value
) {
803 *flags
|= ld_targ
.t_m
.m_dataseg_perm
;
806 *flags
|= ld_targ
.t_m
.m_stack_perm
;
809 *flags
|= flag
->value
;
816 * Accept 0 for notational convenience, but refuse
817 * any other value. Note that we don't actually have
818 * to set the flags to 0 here, because there are
819 * already initialized to that before the main loop.
821 if (tkv
.tkv_int
.tkvi_value
!= 0)
834 char buf
[VLA_SIZE(flag_list_bufsize
)];
836 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SEGFLAG
),
837 ld_map_kwnames(flag_list
,
838 SGSOFFSETOF(segflag_t
, name
),
839 sizeof (flag
[0]), buf
, flag_list_bufsize
),
840 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
846 /* Make sure there was at least one flag */
848 mf_fatal(mf
, MSG_INTL(MSG_MAP_NOVALUES
),
849 MSG_ORIG(MSG_MAPKW_FLAGS
));
860 * Parse one of the capabilities attributes that corresponds directly to a
861 * capabilities bitmask value (CA_SUNW_HW_x, CA_SUNW_SF_xx). Values can be
862 * integers, or symbolic names that correspond to the capabilities mask
866 * mf - Mapfile descriptor
867 * eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
868 * the operation to carry out.
869 * capmask - Capmask from output descriptor for capability being processed.
870 * type - Capability type (CA_SUNW_*)
871 * elfcap_from_str_func - pointer to elfcap-string-to-value function
872 * for capability being processed.
875 * Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
878 parse_cap_mask(Mapfile
*mf
, Token eq_tok
, Capmask
*capmask
,
879 Word type
, elfcap_from_str_func_t
*elfcap_from_str_func
)
884 Conv_inv_buf_t inv_buf
;
885 elfcap_mask_t value
= 0;
888 for (done
= 0; done
== 0; ) {
889 switch (tok
= ld_map_gettoken(mf
, TK_F_KEYWORD
, &tkv
)) {
894 if ((v
= (* elfcap_from_str_func
)(ELFCAP_STYLE
,
895 tkv
.tkv_str
, ld_targ
.t_m
.m_mach
)) != 0) {
902 value
|= tkv
.tkv_int
.tkvi_value
;
912 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_CAPMASK
),
913 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
918 if (!set_capmask(mf
, capmask
, eq_tok
, type
, value
, TRUE
))
924 * Parse one of the capabilities attributes that manages lists of names
925 * (CA_SUNW_PLAT and CA_SUNW_MACH). Values are symbolic names that correspond
926 * to the capabilities mask in question.
929 * mf - Mapfile descriptor
930 * eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
931 * the operation to carry out.
932 * caplist - Caplist from output descriptor for capability being processed.
933 * type - Capability type (CA_SUNW_*)
936 * Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
939 parse_cap_list(Mapfile
*mf
, Token eq_tok
, Caplist
*caplist
,
945 Conv_inv_buf_t inv_buf
;
950 for (done
= 0, found
= 0; done
== 0; found
= 0) {
951 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
957 * The name is in tkv.tkv_str. Save this string for
958 * set_capstr() processing, but remove any duplicates.
960 for (APLIST_TRAVERSE(strs
, idx
, str
)) {
961 if (strcmp(str
, tkv
.tkv_str
) == 0) {
966 if ((found
== 0) && (aplist_append(&strs
, tkv
.tkv_str
,
967 AL_CNT_CAP_NAMES
) == NULL
))
977 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_CAPNAME
),
978 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
983 if (!set_capstr(mf
, caplist
, eq_tok
, type
, strs
))
989 * CAPABILITY [capid] { HW = hwcap_flags...
990 * -------------------------^
994 at_cap_hw(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
999 Conv_inv_buf_t inv_buf
;
1000 Word hw1
= 0, hw2
= 0;
1003 for (done
= 0; done
== 0; ) {
1004 switch (tok
= ld_map_gettoken(mf
, TK_F_KEYWORD
, &tkv
)) {
1009 if ((v
= elfcap_hw1_from_str(ELFCAP_STYLE
,
1010 tkv
.tkv_str
, ld_targ
.t_m
.m_mach
)) != 0) {
1014 if ((v
= elfcap_hw2_from_str(ELFCAP_STYLE
,
1015 tkv
.tkv_str
, ld_targ
.t_m
.m_mach
)) != 0) {
1028 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_CAPHW
),
1029 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
1034 if (!set_capmask(mf
, &mf
->mf_ofl
->ofl_ocapset
.oc_hw_1
, eq_tok
,
1035 CA_SUNW_HW_1
, hw1
, TRUE
))
1037 if (!set_capmask(mf
, &mf
->mf_ofl
->ofl_ocapset
.oc_hw_2
, eq_tok
,
1038 CA_SUNW_HW_2
, hw2
, FALSE
))
1044 * CAPABILITY [capid] { HW_1 = value ;
1045 * ---------------------------^
1049 at_cap_hw_1(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1051 return (parse_cap_mask(mf
, eq_tok
, &mf
->mf_ofl
->ofl_ocapset
.oc_hw_1
,
1052 CA_SUNW_HW_1
, elfcap_hw1_from_str
));
1056 * CAPABILITY [capid] { HW_2 = value ;
1057 * ---------------------------^
1061 at_cap_hw_2(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1063 return (parse_cap_mask(mf
, eq_tok
, &mf
->mf_ofl
->ofl_ocapset
.oc_hw_2
,
1064 CA_SUNW_HW_2
, elfcap_hw2_from_str
));
1068 * CAPABILITY [capid] { SF = sfcap_flags...
1069 * -------------------------^
1073 at_cap_sf(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1078 Conv_inv_buf_t inv_buf
;
1082 for (done
= 0; done
== 0; ) {
1083 switch (tok
= ld_map_gettoken(mf
, TK_F_KEYWORD
, &tkv
)) {
1088 if ((v
= elfcap_sf1_from_str(ELFCAP_STYLE
,
1089 tkv
.tkv_str
, ld_targ
.t_m
.m_mach
)) != 0) {
1102 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_CAPSF
),
1103 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
1108 if (!set_capmask(mf
, &mf
->mf_ofl
->ofl_ocapset
.oc_sf_1
, eq_tok
,
1109 CA_SUNW_SF_1
, sf1
, TRUE
))
1116 * CAPABILITY [capid] { SF_1 = value ;
1117 * ---------------------------^
1121 at_cap_sf_1(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1123 return (parse_cap_mask(mf
, eq_tok
, &mf
->mf_ofl
->ofl_ocapset
.oc_sf_1
,
1124 CA_SUNW_SF_1
, elfcap_sf1_from_str
));
1128 * CAPABILITY [capid] { MACHINE = value ;
1129 * ------------------------------^
1133 at_cap_mach(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1135 return (parse_cap_list(mf
, eq_tok
, &mf
->mf_ofl
->ofl_ocapset
.oc_mach
,
1140 * CAPABILITY [capid] { PLATFORM = value ;
1141 * -------------------------------^
1145 at_cap_plat(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1147 return (parse_cap_list(mf
, eq_tok
, &mf
->mf_ofl
->ofl_ocapset
.oc_plat
,
1152 * Top Level Directive:
1154 * CAPABILITY [capid] { ...
1158 dir_capability(Mapfile
*mf
)
1160 /* CAPABILITY attributes */
1161 static attr_t attr_list
[] = {
1162 { MSG_ORIG(MSG_MAPKW_HW
), at_cap_hw
, ATTR_FMT_EQ_ALL
},
1163 { MSG_ORIG(MSG_MAPKW_HW_1
), at_cap_hw_1
, ATTR_FMT_EQ_ALL
},
1164 { MSG_ORIG(MSG_MAPKW_HW_2
), at_cap_hw_2
, ATTR_FMT_EQ_ALL
},
1166 { MSG_ORIG(MSG_MAPKW_MACHINE
), at_cap_mach
, ATTR_FMT_EQ_ALL
},
1167 { MSG_ORIG(MSG_MAPKW_PLATFORM
), at_cap_plat
, ATTR_FMT_EQ_ALL
},
1169 { MSG_ORIG(MSG_MAPKW_SF
), at_cap_sf
, ATTR_FMT_EQ_ALL
},
1170 { MSG_ORIG(MSG_MAPKW_SF_1
), at_cap_sf_1
, ATTR_FMT_EQ_ALL
},
1172 /* List must be null terminated */
1177 * Size of buffer needed to format the names in attr_list[]. Must
1178 * be kept in sync with attr_list.
1180 static size_t attr_list_bufsize
=
1181 KW_NAME_SIZE(MSG_MAPKW_HW
) +
1182 KW_NAME_SIZE(MSG_MAPKW_HW_1
) +
1183 KW_NAME_SIZE(MSG_MAPKW_HW_2
) +
1184 KW_NAME_SIZE(MSG_MAPKW_MACHINE
) +
1185 KW_NAME_SIZE(MSG_MAPKW_PLATFORM
) +
1186 KW_NAME_SIZE(MSG_MAPKW_SF
) +
1187 KW_NAME_SIZE(MSG_MAPKW_SF_1
);
1192 Conv_inv_buf_t inv_buf
;
1195 * The first token can be one of:
1197 * - A name, followed by a '{', or a ';'.
1198 * Read this initial sequence.
1201 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
1206 capstr
= &mf
->mf_ofl
->ofl_ocapset
.oc_id
;
1209 * The ID name is in tkv.tkv_str. Save this name in the output
1210 * capabilities structure. Note, should multiple ID entries
1211 * be encounterd, the last entry wins.
1213 DBG_CALL(Dbg_cap_id(mf
->mf_ofl
->ofl_lml
, mf
->mf_lineno
,
1214 capstr
->cs_str
, tkv
.tkv_str
));
1216 capstr
->cs_str
= tkv
.tkv_str
;
1217 mf
->mf_ofl
->ofl_ocapset
.oc_flags
|= FLG_OCS_USRDEFID
;
1220 * The name can be followed by an opening '{', or a
1223 switch (tok
= gettoken_optattr(mf
, capstr
->cs_str
)) {
1225 return (TK_SEMICOLON
);
1234 /* Directive has no capid, but does supply attributes */
1238 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_CAPID
),
1239 MSG_ORIG(MSG_MAPKW_CAPABILITY
),
1240 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
1244 /* Parse the attributes */
1245 if (parse_attributes(mf
, MSG_ORIG(MSG_MAPKW_CAPABILITY
),
1246 attr_list
, attr_list_bufsize
, NULL
) == TK_ERROR
)
1249 /* Terminating ';' */
1250 return (gettoken_semicolon(mf
, MSG_ORIG(MSG_MAPKW_CAPABILITY
)));
1254 * at_dv_allow(): Value for ALLOW= is not a version string
1257 gts_efunc_at_dv_allow(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
1259 Conv_inv_buf_t inv_buf
;
1261 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_VERSION
),
1262 MSG_ORIG(MSG_MAPKW_ALLOW
), ld_map_tokenstr(tok
, tkv
, &inv_buf
));
1266 * DEPEND_VERSIONS object_name { ALLOW = version
1267 * -------------------------------------^
1271 at_dv_allow(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1275 if (gettoken_str(mf
, 0, &tkv
, gts_efunc_at_dv_allow
) == TK_ERROR
)
1278 /* Enter the version. uvalue points at the Sdf_desc descriptor */
1279 if (!ld_map_dv_entry(mf
, uvalue
, FALSE
, tkv
.tkv_str
))
1283 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_ALLOW
)));
1287 * at_dv_allow(): Value for REQUIRE= is not a version string
1290 gts_efunc_at_dv_require(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
1292 Conv_inv_buf_t inv_buf
;
1294 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_VERSION
),
1295 MSG_ORIG(MSG_MAPKW_REQUIRE
), ld_map_tokenstr(tok
, tkv
, &inv_buf
));
1299 * DEPEND_VERSIONS object_name { REQURE = version
1300 * --------------------------------------^
1304 at_dv_require(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1309 if (gettoken_str(mf
, 0, &tkv
, gts_efunc_at_dv_require
) == TK_ERROR
)
1312 /* Enter the version. uvalue points at the Sdf_desc descriptor */
1313 if (!ld_map_dv_entry(mf
, uvalue
, TRUE
, tkv
.tkv_str
))
1317 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_REQUIRE
)));
1321 * dir_depend_versions(): Expected object name is not present
1324 gts_efunc_dir_depend_versions(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
1326 Conv_inv_buf_t inv_buf
;
1328 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_OBJNAM
),
1329 MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS
),
1330 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
1334 * Top Level Directive:
1336 * DEPEND_VERSIONS object_name { ATTR = ...
1340 dir_depend_versions(Mapfile
*mf
)
1342 /* DEPEND_VERSIONS attributes */
1343 static attr_t attr_list
[] = {
1344 { MSG_ORIG(MSG_MAPKW_ALLOW
), at_dv_allow
, ATTR_FMT_EQ
},
1345 { MSG_ORIG(MSG_MAPKW_REQUIRE
), at_dv_require
, ATTR_FMT_EQ
},
1347 /* List must be null terminated */
1352 * Size of buffer needed to format the names in attr_list[]. Must
1353 * be kept in sync with attr_list.
1355 static size_t attr_list_bufsize
=
1356 KW_NAME_SIZE(MSG_MAPKW_ALLOW
) +
1357 KW_NAME_SIZE(MSG_MAPKW_REQUIRE
);
1363 if (gettoken_str(mf
, 0, &tkv
, gts_efunc_dir_depend_versions
) ==
1367 /* Get descriptor for dependency */
1368 if ((sdf
= ld_map_dv(mf
, tkv
.tkv_str
)) == NULL
)
1371 /* Opening '{' token */
1372 if (gettoken_leftbkt(mf
, tkv
.tkv_str
) == TK_ERROR
)
1375 /* Parse the attributes */
1376 if (parse_attributes(mf
, MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS
),
1377 attr_list
, attr_list_bufsize
, sdf
) == TK_ERROR
)
1380 /* Terminating ';' */
1381 return (gettoken_semicolon(mf
, MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS
)));
1385 * Top Level Directive:
1391 dir_hdr_noalloc(Mapfile
*mf
)
1393 mf
->mf_ofl
->ofl_dtflags_1
|= DF_1_NOHDR
;
1394 DBG_CALL(Dbg_map_hdr_noalloc(mf
->mf_ofl
->ofl_lml
, mf
->mf_lineno
));
1396 /* ';' terminator token */
1397 return (gettoken_semicolon(mf
, MSG_ORIG(MSG_MAPKW_HDR_NOALLOC
)));
1401 * Top Level Directive:
1403 * PHDR_ADD_NULL = cnt ;
1407 dir_phdr_add_null(Mapfile
*mf
)
1410 ld_map_tkval_t tkv
; /* Value of token */
1413 if (gettoken_eq(mf
, ATTR_FMT_EQ
,
1414 MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL
)) == TK_ERROR
)
1418 if (gettoken_int(mf
, MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL
), &tkv
) ==
1422 while (tkv
.tkv_int
.tkvi_value
-- > 0) {
1423 if ((sgp
= ld_map_seg_alloc(NULL
, PT_NULL
,
1424 FLG_SG_P_TYPE
| FLG_SG_EMPTY
)) == NULL
)
1426 if (ld_map_seg_insert(mf
, DBG_STATE_NEW
, sgp
, 0) ==
1431 /* ';' terminator token */
1432 return (gettoken_semicolon(mf
, MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL
)));
1436 * segment_directive segment_name { ALIGN = value
1437 * ----------------------------------------^
1441 at_seg_align(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1443 Sg_desc
*sgp
= uvalue
;
1447 if (gettoken_int(mf
, MSG_ORIG(MSG_MAPKW_ALIGN
), &tkv
) == TK_ERROR
)
1450 sgp
->sg_phdr
.p_align
= tkv
.tkv_int
.tkvi_value
;
1451 sgp
->sg_flags
|= FLG_SG_P_ALIGN
;
1454 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_ALIGN
)));
1458 * at_seg_assign_file_basename(): Value for FILE_BASENAME= is not a file name
1461 gts_efunc_at_seg_assign_file_basename(Mapfile
*mf
, Token tok
,
1462 ld_map_tkval_t
*tkv
)
1464 Conv_inv_buf_t inv_buf
;
1466 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_FILNAM
),
1467 MSG_ORIG(MSG_MAPKW_FILE_BASENAME
),
1468 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
1472 * segment_directive segment_name { ASSIGN { FILE_BASENAME = file_name
1473 * ---------------------------------------------------------^
1477 at_seg_assign_file_basename(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1479 Ent_desc
*enp
= uvalue
;
1483 if (gettoken_str(mf
, 0, &tkv
, gts_efunc_at_seg_assign_file_basename
) ==
1487 if (!ld_map_seg_ent_files(mf
, enp
, TYP_ECF_BASENAME
, tkv
.tkv_str
))
1491 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_FILE_BASENAME
)));
1495 * at_seg_assign_file_objname(): Value for FILE_OBJNAME= is not an object name
1498 gts_efunc_at_seg_assign_file_objname(Mapfile
*mf
, Token tok
,
1499 ld_map_tkval_t
*tkv
)
1501 Conv_inv_buf_t inv_buf
;
1503 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_OBJNAM
),
1504 MSG_ORIG(MSG_MAPKW_FILE_OBJNAME
),
1505 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
1509 * segment_directive segment_name { ASSIGN { FILE_OBJNAME = name
1510 * --------------------------------------------------------^
1514 at_seg_assign_file_objname(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1516 Ent_desc
*enp
= uvalue
;
1520 if (gettoken_str(mf
, 0, &tkv
, gts_efunc_at_seg_assign_file_objname
) ==
1524 if (!ld_map_seg_ent_files(mf
, enp
, TYP_ECF_OBJNAME
, tkv
.tkv_str
))
1528 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_FILE_OBJNAME
)));
1532 * at_seg_assign_file_path(): Value for FILE_PATH= is not a file path
1535 gts_efunc_at_seg_assign_file_path(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
1537 Conv_inv_buf_t inv_buf
;
1539 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_FILPATH
),
1540 MSG_ORIG(MSG_MAPKW_FILE_PATH
),
1541 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
1545 * segment_directive segment_name { ASSIGN { FILE_PATH = file_path
1546 * -----------------------------------------------------^
1550 at_seg_assign_file_path(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1552 Ent_desc
*enp
= uvalue
;
1556 if (gettoken_str(mf
, 0, &tkv
, gts_efunc_at_seg_assign_file_path
) ==
1560 if (!ld_map_seg_ent_files(mf
, enp
, TYP_ECF_PATH
, tkv
.tkv_str
))
1564 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_FILE_PATH
)));
1568 * segment_directive segment_name { ASSIGN { FLAGS = ... ;
1569 * -------------------------------------------------^
1573 at_seg_assign_flags(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1579 static secflag_t flag_list
[] = {
1580 { MSG_ORIG(MSG_MAPKW_ALLOC
), SHF_ALLOC
},
1581 { MSG_ORIG(MSG_MAPKW_EXECUTE
), SHF_EXECINSTR
},
1582 { MSG_ORIG(MSG_MAPKW_WRITE
), SHF_WRITE
},
1583 { MSG_ORIG(MSG_MAPKW_AMD64_LARGE
), SHF_AMD64_LARGE
},
1585 /* List must be null terminated */
1590 * Size of buffer needed to format the names in flag_list[]. Must
1591 * be kept in sync with flag_list.
1593 static size_t flag_list_bufsize
=
1594 KW_NAME_SIZE(MSG_MAPKW_ALLOC
) +
1595 KW_NAME_SIZE(MSG_MAPKW_EXECUTE
) +
1596 KW_NAME_SIZE(MSG_MAPKW_WRITE
) +
1597 KW_NAME_SIZE(MSG_MAPKW_AMD64_LARGE
);
1599 Ent_desc
*enp
= uvalue
;
1600 int bcnt
= 0, cnt
= 0;
1605 Conv_inv_buf_t inv_buf
;
1607 /* Read and process tokens until the closing terminator is seen */
1608 for (done
= 0; done
== 0; ) {
1609 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
1614 /* Ensure ! only specified once per flag */
1616 mf_fatal0(mf
, MSG_INTL(MSG_MAP_SFLG_ONEBANG
));
1623 flag
= ld_map_kwfind(tkv
.tkv_str
, flag_list
,
1624 SGSOFFSETOF(secflag_t
, name
), sizeof (flag
[0]));
1628 enp
->ec_attrmask
|= flag
->value
;
1630 enp
->ec_attrbits
|= flag
->value
;
1642 char buf
[VLA_SIZE(flag_list_bufsize
)];
1644 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SECFLAG
),
1645 ld_map_kwnames(flag_list
,
1646 SGSOFFSETOF(secflag_t
, name
),
1647 sizeof (flag
[0]), buf
, flag_list_bufsize
),
1648 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
1655 * Ensure that a trailing '!' was not left at the end of the line
1656 * without a corresponding flag to apply it to.
1659 mf_fatal0(mf
, MSG_INTL(MSG_MAP_SFLG_EXBANG
));
1663 /* Make sure there was at least one flag */
1665 mf_fatal(mf
, MSG_INTL(MSG_MAP_NOVALUES
),
1666 MSG_ORIG(MSG_MAPKW_FLAGS
));
1670 return (tok
); /* Either TK_SEMICOLON or TK_RIGHTBKT */
1674 * at_seg_assign_is_name(): Value for IS_NAME= is not a section name
1677 gts_efunc_at_seg_assign_is_name(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
1679 Conv_inv_buf_t inv_buf
;
1681 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SECNAM
),
1682 MSG_ORIG(MSG_MAPKW_IS_NAME
), ld_map_tokenstr(tok
, tkv
, &inv_buf
));
1686 * segment_directive segment_name { ASSIGN { IS_NAME = section_name ;
1687 * ---------------------------------------------------^
1691 at_seg_assign_is_name(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1693 Ent_desc
*enp
= uvalue
;
1697 if (gettoken_str(mf
, 0, &tkv
, gts_efunc_at_seg_assign_is_name
) ==
1700 enp
->ec_is_name
= tkv
.tkv_str
;
1703 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_IS_NAME
)));
1707 * at_seg_assign_type(): Value for TYPE= is not a section type
1710 gts_efunc_at_seg_assign_type(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
1712 Conv_inv_buf_t inv_buf
;
1714 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SHTYPE
),
1715 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
1719 * segment_directive segment_name { ASSIGN { TYPE = section_type ;
1720 * ------------------------------------------------^
1724 at_seg_assign_type(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1726 Ent_desc
*enp
= uvalue
;
1728 conv_strtol_uvalue_t conv_uvalue
;
1731 if (gettoken_str(mf
, TK_F_KEYWORD
, &tkv
,
1732 gts_efunc_at_seg_assign_type
) == TK_ERROR
)
1736 * Use the libconv iteration facility to map the given name to
1737 * its value. This allows us to keep up with any new sections
1738 * without having to change this code.
1740 if (conv_iter_strtol_init(tkv
.tkv_str
, &conv_uvalue
) != 0) {
1741 conv_iter_ret_t status
;
1743 /* Look at the canonical form */
1744 status
= conv_iter_sec_type(CONV_OSABI_ALL
, CONV_MACH_ALL
,
1745 CONV_FMT_ALT_CF
, conv_iter_strtol
, &conv_uvalue
);
1747 /* Failing that, look at the normal form */
1748 if (status
!= CONV_ITER_DONE
)
1749 (void) conv_iter_sec_type(CONV_OSABI_ALL
,
1750 CONV_MACH_ALL
, CONV_FMT_ALT_NF
, conv_iter_strtol
,
1753 /* If we didn't match anything report error */
1754 if (!conv_uvalue
.csl_found
) {
1755 gts_efunc_at_seg_assign_type(mf
, TK_STRING
, &tkv
);
1760 enp
->ec_type
= conv_uvalue
.csl_value
;
1763 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_TYPE
)));
1767 * segment_directive segment_name { ASSIGN { ...
1768 * -----------------------------------------^
1772 at_seg_assign(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1774 /* segment_directive ASSIGN sub-attributes */
1775 static attr_t attr_list
[] = {
1776 { MSG_ORIG(MSG_MAPKW_FILE_BASENAME
),
1777 at_seg_assign_file_basename
, ATTR_FMT_EQ
},
1778 { MSG_ORIG(MSG_MAPKW_FILE_OBJNAME
),
1779 at_seg_assign_file_objname
, ATTR_FMT_EQ
},
1780 { MSG_ORIG(MSG_MAPKW_FILE_PATH
),
1781 at_seg_assign_file_path
, ATTR_FMT_EQ
},
1782 { MSG_ORIG(MSG_MAPKW_FLAGS
),
1783 at_seg_assign_flags
, ATTR_FMT_EQ_ALL
},
1784 { MSG_ORIG(MSG_MAPKW_IS_NAME
),
1785 at_seg_assign_is_name
, ATTR_FMT_EQ
},
1786 { MSG_ORIG(MSG_MAPKW_TYPE
),
1787 at_seg_assign_type
, ATTR_FMT_EQ
},
1789 /* List must be null terminated */
1794 * Size of buffer needed to format the names in attr_list[]. Must
1795 * be kept in sync with attr_list.
1797 static size_t attr_list_bufsize
=
1798 KW_NAME_SIZE(MSG_MAPKW_FILE_BASENAME
) +
1799 KW_NAME_SIZE(MSG_MAPKW_FILE_PATH
) +
1800 KW_NAME_SIZE(MSG_MAPKW_FLAGS
) +
1801 KW_NAME_SIZE(MSG_MAPKW_FILE_OBJNAME
) +
1802 KW_NAME_SIZE(MSG_MAPKW_IS_NAME
) +
1803 KW_NAME_SIZE(MSG_MAPKW_TYPE
);
1805 Sg_desc
*sgp
= uvalue
;
1808 Conv_inv_buf_t inv_buf
;
1809 const char *name
= NULL
;
1813 * ASSIGN takes an optional name, plus attributes are optional,
1814 * so expect a name, an opening '{', or a ';'.
1816 tok
= ld_map_gettoken(mf
, 0, &tkv
);
1823 tok
= ld_map_gettoken(mf
, 0, &tkv
);
1827 /* Add a new entrance criteria descriptor to the segment */
1828 if ((enp
= ld_map_seg_ent_add(mf
, sgp
, name
)) == NULL
)
1831 /* Having handled the name, expect either '{' or ';' */
1834 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SEMLBKT
),
1835 MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION
),
1836 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
1842 /* No attributes: It will match anything */
1843 enp
->ec_flags
|= FLG_EC_CATCHALL
;
1846 /* Parse the attributes */
1847 if (parse_attributes(mf
, MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION
),
1848 attr_list
, attr_list_bufsize
, enp
) == TK_ERROR
)
1851 /* Terminating ';', or '}' which also terminates caller */
1852 tok
= gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION
));
1853 if (tok
== TK_ERROR
)
1858 DBG_CALL(Dbg_map_ent(mf
->mf_ofl
->ofl_lml
, enp
, mf
->mf_ofl
,
1864 * segment_directive segment_name { DISABLE ;
1865 * ----------------------------------------^
1869 at_seg_disable(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1871 Sg_desc
*sgp
= uvalue
;
1873 /* If the segment cannot be disabled, issue error */
1874 if (sgp
->sg_flags
& FLG_SG_NODISABLE
) {
1875 mf_fatal(mf
, MSG_INTL(MSG_MAP_CNTDISSEG
), sgp
->sg_name
);
1879 /* Disable the segment */
1880 sgp
->sg_flags
|= FLG_SG_DISABLED
;
1883 return (gettoken_semicolon(mf
, MSG_ORIG(MSG_MAPKW_DISABLE
)));
1887 * segment_directive segment_name { FLAGS eq-op ...
1888 * --------------------------------------------^
1890 * Note that this routine is also used for the STACK directive,
1891 * as STACK also manipulates a segment descriptor.
1893 * STACK { FLAGS eq-op ... ;
1894 * -------------------^
1898 at_seg_flags(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1900 Sg_desc
*sgp
= uvalue
;
1904 tok
= parse_segment_flags(mf
, &flags
);
1905 if (tok
== TK_ERROR
)
1908 setflags_eq(&sgp
->sg_phdr
.p_flags
, eq_tok
, flags
);
1909 sgp
->sg_flags
|= FLG_SG_P_FLAGS
;
1915 * segment_directive segment_name { IS_ORDER eq_op value
1916 * -----------------------------------------------^
1920 at_seg_is_order(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1922 Sg_desc
*sgp
= uvalue
;
1925 Conv_inv_buf_t inv_buf
;
1928 Ent_desc
*enp
, *enp2
;
1931 * The '=' form of assignment resets the list. The list contains
1932 * pointers to our mapfile text, so we do not have to free anything.
1934 if (eq_tok
== TK_EQUAL
)
1935 aplist_reset(sgp
->sg_is_order
);
1938 * One or more ASSIGN names, terminated by a semicolon.
1940 for (done
= 0; done
== 0; ) {
1941 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
1947 * The referenced entrance criteria must have
1948 * already been defined.
1950 enp
= ld_ent_lookup(mf
->mf_ofl
, tkv
.tkv_str
, NULL
);
1952 mf_fatal(mf
, MSG_INTL(MSG_MAP_UNKENT
),
1958 * Make sure it's not already on the list
1960 for (APLIST_TRAVERSE(sgp
->sg_is_order
, idx
, enp2
))
1963 MSG_INTL(MSG_MAP_DUP_IS_ORD
),
1968 /* Put it at the end of the order list */
1969 if (aplist_append(&sgp
->sg_is_order
, enp
,
1970 AL_CNT_SG_IS_ORDER
) == NULL
)
1980 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_ECNAM
),
1981 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
1990 * segment_directive segment_name { MAX_SIZE = value
1991 * -------------------------------------------^
1995 at_seg_max_size(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
1997 Sg_desc
*sgp
= uvalue
;
2001 if (gettoken_int(mf
, MSG_ORIG(MSG_MAPKW_MAX_SIZE
), &tkv
) == TK_ERROR
)
2004 sgp
->sg_length
= tkv
.tkv_int
.tkvi_value
;
2005 sgp
->sg_flags
|= FLG_SG_LENGTH
;
2008 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_MAX_SIZE
)));
2012 * segment_directive segment_name { NOHDR ;
2013 * --------------------------------------^
2017 at_seg_nohdr(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2019 Sg_desc
*sgp
= uvalue
;
2022 * Set the nohdr flag on the segment. If this segment is the
2023 * first loadable segment, the ELF and program headers will
2026 * The HDR_NOALLOC top level directive is preferred. This feature
2027 * exists to give 1:1 feature parity with version 1 mapfiles that
2028 * use the ?N segment flag and expect it to only take effect
2029 * if that segment ends up being first.
2031 sgp
->sg_flags
|= FLG_SG_NOHDR
;
2034 return (gettoken_semicolon(mf
, MSG_ORIG(MSG_MAPKW_NOHDR
)));
2038 * segment_directive segment_name { OS_ORDER eq_op assign_name...
2039 * -----------------------------------------------^
2043 at_seg_os_order(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2045 Sg_desc
*sgp
= uvalue
;
2048 Conv_inv_buf_t inv_buf
;
2052 * The '=' form of assignment resets the list. The list contains
2053 * pointers to our mapfile text, so we do not have to free anything.
2055 if (eq_tok
== TK_EQUAL
)
2056 alist_reset(sgp
->sg_os_order
);
2059 * One or more section names, terminated by a semicolon.
2061 for (done
= 0; done
== 0; ) {
2062 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
2067 if (!ld_map_seg_os_order_add(mf
, sgp
, tkv
.tkv_str
))
2077 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SECNAM
),
2078 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
2087 * segment_directive segment_name { PADDR = paddr
2088 * ----------------------------------------^
2092 at_seg_paddr(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2094 Sg_desc
*sgp
= uvalue
, *sgp2
;
2099 * Ensure that the segment isn't in the segment order list.
2101 for (APLIST_TRAVERSE(mf
->mf_ofl
->ofl_segs_order
, idx
, sgp2
))
2104 MSG_INTL(MSG_MAP_CNTADDRORDER
), sgp
->sg_name
);
2109 if (gettoken_int(mf
, MSG_ORIG(MSG_MAPKW_PADDR
), &tkv
) == TK_ERROR
)
2112 sgp
->sg_phdr
.p_paddr
= tkv
.tkv_int
.tkvi_value
;
2113 sgp
->sg_flags
|= FLG_SG_P_PADDR
;
2116 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_PADDR
)));
2120 * segment_directive segment_name { ROUND = value
2121 * ----------------------------------------^
2125 at_seg_round(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2127 Sg_desc
*sgp
= uvalue
;
2131 if (gettoken_int(mf
, MSG_ORIG(MSG_MAPKW_ROUND
), &tkv
) == TK_ERROR
)
2134 sgp
->sg_round
= tkv
.tkv_int
.tkvi_value
;
2135 sgp
->sg_flags
|= FLG_SG_ROUND
;
2138 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_ROUND
)));
2142 * segment_directive segment_name { SIZE_SYMBOL = symbol_name
2143 * ----------------------------------------------^
2147 at_seg_size_symbol(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2149 Sg_desc
*sgp
= uvalue
;
2152 Conv_inv_buf_t inv_buf
;
2156 * One or more symbol names, terminated by a semicolon.
2158 for (done
= 0; done
== 0; ) {
2159 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
2164 if (!ld_map_seg_size_symbol(mf
, sgp
, eq_tok
,
2170 * If the operator is TK_EQUAL, turn it into
2171 * TK_PLUSEQ for any symbol names after the first.
2172 * These additional symbols are added, and are not
2173 * replacements for the first one.
2184 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SYMNAM
),
2185 MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL
),
2186 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
2191 /* Make sure there was at least one name */
2193 mf_fatal(mf
, MSG_INTL(MSG_MAP_NOVALUES
),
2194 MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL
));
2202 * segment_directive segment_name { VADDR = vaddr
2203 * ----------------------------------------^
2207 at_seg_vaddr(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2209 Sg_desc
*sgp
= uvalue
, *sgp2
;
2214 * Ensure that the segment isn't in the segment order list.
2216 for (APLIST_TRAVERSE(mf
->mf_ofl
->ofl_segs_order
, idx
, sgp2
))
2219 MSG_INTL(MSG_MAP_CNTADDRORDER
), sgp
->sg_name
);
2224 if (gettoken_int(mf
, MSG_ORIG(MSG_MAPKW_VADDR
), &tkv
) == TK_ERROR
)
2227 sgp
->sg_phdr
.p_vaddr
= tkv
.tkv_int
.tkvi_value
;
2228 sgp
->sg_flags
|= FLG_SG_P_VADDR
;
2231 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_VADDR
)));
2235 * Top Level Directive:
2237 * {LOAD|NOTE|NULL}_SEGMENT segment_name { ...
2238 * ------------------------^
2240 * Common implementation body for the family of segment directives. These
2241 * take the same syntax, and share a common subset of attributes. They differ
2242 * in the type of segments they handle and the specific attributes accepted.
2245 * mf - Mapfile descriptor ({LOAD|NOTE|NULL}_SEGMENT)
2246 * dir_name - Name of directive.
2247 * seg_type - Type of segment (PT_LOAD, PT_NOTE, PT_NULL).
2248 * attr_list - NULL terminated attribute array
2249 * attr_list_bufsize - Size of required buffer to format all the
2250 * names in attr_list.
2251 * gts_efunc - Error function to pass to gettoken_str() when trying
2252 * to obtain a segment name token.
2255 dir_segment_inner(Mapfile
*mf
, const char *dir_name
, Word seg_type
,
2256 attr_t
*attr_list
, size_t attr_list_bufsize
, gts_efunc_t gts_efunc
)
2261 Boolean new_segment
;
2266 if (gettoken_str(mf
, 0, &tkv
, gts_efunc
) == TK_ERROR
)
2268 sgp
= ld_seg_lookup(mf
->mf_ofl
, tkv
.tkv_str
, &where
);
2269 new_segment
= (sgp
== NULL
);
2272 /* Allocate a descriptor for new segment */
2273 if ((sgp
= ld_map_seg_alloc(tkv
.tkv_str
, seg_type
,
2274 FLG_SG_P_TYPE
)) == NULL
)
2277 /* Make sure it's the right type of segment */
2278 if (sgp
->sg_phdr
.p_type
!= seg_type
) {
2279 Conv_inv_buf_t inv_buf
;
2281 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXPSEGTYPE
),
2282 conv_phdr_type(ELFOSABI_SOLARIS
, ld_targ
.t_m
.m_mach
,
2283 sgp
->sg_phdr
.p_type
, CONV_FMT_ALT_CF
, &inv_buf
),
2284 dir_name
, tkv
.tkv_str
);
2288 /* If it was disabled, being referenced enables it */
2289 sgp
->sg_flags
&= ~FLG_SG_DISABLED
;
2293 * Not a new segment, so show the initial value
2294 * before modifying it.
2296 ndx
= ld_map_seg_index(mf
, sgp
);
2297 DBG_CALL(Dbg_map_seg(mf
->mf_ofl
, DBG_STATE_MOD_BEFORE
,
2298 ndx
, sgp
, mf
->mf_lineno
));
2303 * Attributes are optional, so expect an opening '{', or a ';'.
2305 switch (tok
= gettoken_optattr(mf
, dir_name
)) {
2312 /* Parse the attributes */
2313 if (parse_attributes(mf
, dir_name
,
2314 attr_list
, attr_list_bufsize
, sgp
) == TK_ERROR
)
2317 /* Terminating ';' */
2318 tok
= gettoken_semicolon(mf
, dir_name
);
2319 if (tok
== TK_ERROR
)
2326 * If this is a new segment, finish its initialization
2327 * and insert it into the segment list.
2330 if (ld_map_seg_insert(mf
, DBG_STATE_NEW
, sgp
, where
) ==
2334 /* Not new. Show what's changed */
2335 DBG_CALL(Dbg_map_seg(mf
->mf_ofl
, DBG_STATE_MOD_AFTER
,
2336 ndx
, sgp
, mf
->mf_lineno
));
2343 * dir_load_segment(): Expected loadable segment name is not present
2346 gts_efunc_dir_load_segment(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
2348 Conv_inv_buf_t inv_buf
;
2350 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SEGNAM
),
2351 MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT
),
2352 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
2356 * Top Level Directive:
2358 * LOAD_SEGMENT segment_name { ...
2362 dir_load_segment(Mapfile
*mf
)
2364 /* LOAD_SEGMENT attributes */
2365 static attr_t attr_list
[] = {
2366 { MSG_ORIG(MSG_MAPKW_ALIGN
), at_seg_align
, ATTR_FMT_EQ
},
2367 { MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION
),
2368 at_seg_assign
, ATTR_FMT_NAME
},
2369 { MSG_ORIG(MSG_MAPKW_DISABLE
), at_seg_disable
, ATTR_FMT_NAME
},
2370 { MSG_ORIG(MSG_MAPKW_FLAGS
), at_seg_flags
,
2372 { MSG_ORIG(MSG_MAPKW_IS_ORDER
), at_seg_is_order
,
2374 { MSG_ORIG(MSG_MAPKW_MAX_SIZE
), at_seg_max_size
, ATTR_FMT_EQ
},
2375 { MSG_ORIG(MSG_MAPKW_NOHDR
), at_seg_nohdr
, ATTR_FMT_NAME
},
2376 { MSG_ORIG(MSG_MAPKW_OS_ORDER
), at_seg_os_order
,
2378 { MSG_ORIG(MSG_MAPKW_PADDR
), at_seg_paddr
, ATTR_FMT_EQ
},
2379 { MSG_ORIG(MSG_MAPKW_ROUND
), at_seg_round
, ATTR_FMT_EQ
},
2380 { MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL
),
2381 at_seg_size_symbol
, ATTR_FMT_EQ_PEQ
},
2382 { MSG_ORIG(MSG_MAPKW_VADDR
), at_seg_vaddr
, ATTR_FMT_EQ
},
2384 /* List must be null terminated */
2389 * Size of buffer needed to format the names in attr_list[]. Must
2390 * be kept in sync with attr_list.
2392 static size_t attr_list_bufsize
=
2393 KW_NAME_SIZE(MSG_MAPKW_ALIGN
) +
2394 KW_NAME_SIZE(MSG_MAPKW_ASSIGN_SECTION
) +
2395 KW_NAME_SIZE(MSG_MAPKW_DISABLE
) +
2396 KW_NAME_SIZE(MSG_MAPKW_FLAGS
) +
2397 KW_NAME_SIZE(MSG_MAPKW_IS_ORDER
) +
2398 KW_NAME_SIZE(MSG_MAPKW_MAX_SIZE
) +
2399 KW_NAME_SIZE(MSG_MAPKW_PADDR
) +
2400 KW_NAME_SIZE(MSG_MAPKW_ROUND
) +
2401 KW_NAME_SIZE(MSG_MAPKW_OS_ORDER
) +
2402 KW_NAME_SIZE(MSG_MAPKW_SIZE_SYMBOL
) +
2403 KW_NAME_SIZE(MSG_MAPKW_VADDR
);
2405 return (dir_segment_inner(mf
, MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT
),
2406 PT_LOAD
, attr_list
, attr_list_bufsize
, gts_efunc_dir_load_segment
));
2411 * Common shared segment directive attributes
2413 static attr_t segment_core_attr_list
[] = {
2414 { MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION
), at_seg_assign
, ATTR_FMT_NAME
},
2415 { MSG_ORIG(MSG_MAPKW_DISABLE
), at_seg_disable
, ATTR_FMT_NAME
},
2416 { MSG_ORIG(MSG_MAPKW_IS_ORDER
), at_seg_is_order
, ATTR_FMT_EQ_PEQ
},
2417 { MSG_ORIG(MSG_MAPKW_OS_ORDER
), at_seg_os_order
, ATTR_FMT_EQ_PEQ
},
2419 /* List must be null terminated */
2424 * Size of buffer needed to format the names in segment_core_attr_list[].
2425 * Must be kept in sync with segment_core_attr_list.
2427 static size_t segment_core_attr_list_bufsize
=
2428 KW_NAME_SIZE(MSG_MAPKW_ASSIGN_SECTION
) +
2429 KW_NAME_SIZE(MSG_MAPKW_DISABLE
) +
2430 KW_NAME_SIZE(MSG_MAPKW_IS_ORDER
) +
2431 KW_NAME_SIZE(MSG_MAPKW_OS_ORDER
);
2434 * dir_note_segment(): Expected note segment name is not present
2437 gts_efunc_dir_note_segment(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
2439 Conv_inv_buf_t inv_buf
;
2441 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SEGNAM
),
2442 MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT
),
2443 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
2447 * Top Level Directive:
2449 * NOTE_SEGMENT segment_name { ...
2453 dir_note_segment(Mapfile
*mf
)
2455 return (dir_segment_inner(mf
, MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT
),
2456 PT_NOTE
, segment_core_attr_list
, segment_core_attr_list_bufsize
,
2457 gts_efunc_dir_note_segment
));
2462 * dir_null_segment(): Expected null segment name is not present
2465 gts_efunc_dir_null_segment(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
2467 Conv_inv_buf_t inv_buf
;
2469 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SEGNAM
),
2470 MSG_ORIG(MSG_MAPKW_NULL_SEGMENT
),
2471 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
2475 * Top Level Directive:
2477 * NULL_SEGMENT segment_name { ...
2481 dir_null_segment(Mapfile
*mf
)
2483 return (dir_segment_inner(mf
, MSG_ORIG(MSG_MAPKW_NULL_SEGMENT
),
2484 PT_NULL
, segment_core_attr_list
, segment_core_attr_list_bufsize
,
2485 gts_efunc_dir_null_segment
));
2490 * Top Level Directive:
2492 * SEGMENT_ORDER segment_name ... ;
2495 dir_segment_order(Mapfile
*mf
)
2499 Conv_inv_buf_t inv_buf
;
2501 Sg_desc
*sgp
, *sgp2
;
2504 /* Expect either a '=' or '+=' */
2505 tok
= gettoken_eq(mf
, ATTR_FMT_EQ_PEQ
,
2506 MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER
));
2507 if (tok
== TK_ERROR
)
2510 DBG_CALL(Dbg_map_seg_order(mf
->mf_ofl
, ELFOSABI_SOLARIS
,
2511 ld_targ
.t_m
.m_mach
, DBG_STATE_MOD_BEFORE
, mf
->mf_lineno
));
2514 * The '=' form of assignment resets the list. The list contains
2515 * pointers to our mapfile text, so we do not have to free anything.
2517 if (tok
== TK_EQUAL
)
2518 aplist_reset(mf
->mf_ofl
->ofl_segs_order
);
2520 /* Read segment names, and add to list until terminator (';') is seen */
2521 for (done
= 0; done
== 0; ) {
2522 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
2528 * The segment must have already been defined.
2530 sgp
= ld_seg_lookup(mf
->mf_ofl
, tkv
.tkv_str
, NULL
);
2532 mf_fatal(mf
, MSG_INTL(MSG_MAP_UNKSEG
),
2538 * Make sure it's not already on the list
2540 for (APLIST_TRAVERSE(mf
->mf_ofl
->ofl_segs_order
,
2544 MSG_INTL(MSG_MAP_DUPORDSEG
),
2545 MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER
),
2551 * It can't be ordered and also have an explicit
2554 if (sgp
->sg_flags
& (FLG_SG_P_PADDR
| FLG_SG_P_VADDR
)) {
2555 mf_fatal(mf
, MSG_INTL(MSG_MAP_CNTADDRORDER
),
2561 /* Put it at the end of the list */
2562 if (aplist_append(&mf
->mf_ofl
->ofl_segs_order
, sgp
,
2563 AL_CNT_SG_IS_ORDER
) == NULL
)
2572 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SEGNAM
),
2573 MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER
),
2574 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
2579 DBG_CALL(Dbg_map_seg_order(mf
->mf_ofl
, ELFOSABI_SOLARIS
,
2580 ld_targ
.t_m
.m_mach
, DBG_STATE_MOD_AFTER
, mf
->mf_lineno
));
2586 * Top Level Directive:
2592 dir_stack(Mapfile
*mf
)
2594 /* STACK attributes */
2595 static attr_t attr_list
[] = {
2596 { MSG_ORIG(MSG_MAPKW_FLAGS
), at_seg_flags
, ATTR_FMT_EQ_ALL
},
2598 /* List must be null terminated */
2603 * Size of buffer needed to format the names in attr_list[]. Must
2604 * be kept in sync with attr_list.
2606 static size_t attr_list_bufsize
=
2607 KW_NAME_SIZE(MSG_MAPKW_FLAGS
);
2613 /* Opening '{' token */
2614 if (gettoken_leftbkt(mf
, MSG_ORIG(MSG_MAPKW_STACK
)) == TK_ERROR
)
2617 /* Fetch the PT_SUNWSTACK segment descriptor */
2618 sgp
= ld_map_seg_stack(mf
);
2620 /* Parse the attributes */
2621 if (parse_attributes(mf
, MSG_ORIG(MSG_MAPKW_STACK
),
2622 attr_list
, attr_list_bufsize
, sgp
) == TK_ERROR
)
2625 /* Terminating ';' */
2626 tok
= gettoken_semicolon(mf
, MSG_ORIG(MSG_MAPKW_STACK
));
2627 if (tok
== TK_ERROR
)
2631 Xword ndx
= ld_map_seg_index(mf
, sgp
);
2633 Dbg_map_seg(mf
->mf_ofl
, DBG_STATE_MOD_AFTER
, ndx
, sgp
,
2641 * at_sym_aux(): Value for AUXILIARY= is not an object name
2644 gts_efunc_at_sym_aux(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
2646 Conv_inv_buf_t inv_buf
;
2648 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_OBJNAM
),
2649 MSG_ORIG(MSG_MAPKW_AUX
), ld_map_tokenstr(tok
, tkv
, &inv_buf
));
2653 * SYMBOL [version_name] { symbol_name { AUXILIARY = soname
2654 * -------------------------------------------------^
2658 at_sym_aux(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2660 symbol_state_t
*ss
= uvalue
;
2663 /* auxiliary filter soname */
2664 if (gettoken_str(mf
, 0, &tkv
, gts_efunc_at_sym_aux
) == TK_ERROR
)
2667 ld_map_sym_filtee(mf
, &ss
->ss_mv
, &ss
->ss_ms
, FLG_SY_AUXFLTR
,
2671 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_AUX
)));
2675 * at_sym_filter(): Value for FILTER= is not an object name
2678 gts_efunc_at_sym_filter(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
2680 Conv_inv_buf_t inv_buf
;
2682 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_OBJNAM
),
2683 MSG_ORIG(MSG_MAPKW_FILTER
), ld_map_tokenstr(tok
, tkv
, &inv_buf
));
2687 * SYMBOL [version_name] { symbol_name { FILTER = soname
2688 * ----------------------------------------------^
2692 at_sym_filter(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2694 symbol_state_t
*ss
= uvalue
;
2698 if (gettoken_str(mf
, 0, &tkv
, gts_efunc_at_sym_filter
) == TK_ERROR
)
2701 ld_map_sym_filtee(mf
, &ss
->ss_mv
, &ss
->ss_ms
, FLG_SY_STDFLTR
,
2705 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_FILTER
)));
2709 * SYMBOL [version_name] { symbol_name { FLAGS = ...
2710 * ---------------------------------------------^
2714 at_sym_flags(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2721 static symflag_t symflag_list
[] = {
2722 { MSG_ORIG(MSG_MAPKW_DIRECT
), FLG_SY_DIR
},
2723 { MSG_ORIG(MSG_MAPKW_DYNSORT
), FLG_SY_DYNSORT
},
2724 { MSG_ORIG(MSG_MAPKW_EXTERN
), FLG_SY_EXTERN
},
2725 { MSG_ORIG(MSG_MAPKW_INTERPOSE
), FLG_SY_INTPOSE
},
2726 { MSG_ORIG(MSG_MAPKW_NODIRECT
), FLG_SY_NDIR
},
2727 { MSG_ORIG(MSG_MAPKW_NODYNSORT
), FLG_SY_NODYNSORT
},
2728 { MSG_ORIG(MSG_MAPKW_PARENT
), FLG_SY_PARENT
},
2730 /* List must be null terminated */
2735 * Size of buffer needed to format the names in flag_list[]. Must
2736 * be kept in sync with flag_list.
2738 static size_t symflag_list_bufsize
=
2739 KW_NAME_SIZE(MSG_MAPKW_DIRECT
) +
2740 KW_NAME_SIZE(MSG_MAPKW_DYNSORT
) +
2741 KW_NAME_SIZE(MSG_MAPKW_EXTERN
) +
2742 KW_NAME_SIZE(MSG_MAPKW_INTERPOSE
) +
2743 KW_NAME_SIZE(MSG_MAPKW_NODIRECT
) +
2744 KW_NAME_SIZE(MSG_MAPKW_NODYNSORT
) +
2745 KW_NAME_SIZE(MSG_MAPKW_PARENT
);
2747 symbol_state_t
*ss
= uvalue
;
2753 Conv_inv_buf_t inv_buf
;
2754 Ofl_desc
*ofl
= mf
->mf_ofl
;
2756 for (done
= 0; done
== 0; ) {
2757 switch (tok
= ld_map_gettoken(mf
, TK_F_KEYWORD
, &tkv
)) {
2762 symflag
= ld_map_kwfind(tkv
.tkv_str
, symflag_list
,
2763 SGSOFFSETOF(symflag_t
, name
), sizeof (symflag
[0]));
2764 if (symflag
== NULL
)
2770 * Although tempting to make all of this table-driven
2771 * via added fields in symflag_t, there's enough
2772 * variation in what each flag does to make that
2773 * not quite worthwhile.
2775 * Similarly, it is tempting to use common code to
2776 * to do this work from map_support.c. However, the
2777 * v1 code mixes unrelated things (flags, symbol types,
2778 * value, size, etc) in single cascading series of
2779 * strcmps, whereas our parsing separates those things
2780 * from each other. Merging the code would require doing
2781 * two strcmps for each item, or other complexity,
2782 * which I judge not to be worthwhile.
2784 switch (symflag
->value
) {
2786 ss
->ss_ms
.ms_sdflags
|= FLG_SY_DIR
;
2787 ofl
->ofl_flags
|= FLG_OF_SYMINFO
;
2789 case FLG_SY_DYNSORT
:
2790 ss
->ss_ms
.ms_sdflags
|= FLG_SY_DYNSORT
;
2791 ss
->ss_ms
.ms_sdflags
&= ~FLG_SY_NODYNSORT
;
2794 ss
->ss_ms
.ms_sdflags
|= FLG_SY_EXTERN
;
2795 ofl
->ofl_flags
|= FLG_OF_SYMINFO
;
2797 case FLG_SY_INTPOSE
:
2798 if (!(ofl
->ofl_flags
& FLG_OF_EXEC
)) {
2800 MSG_INTL(MSG_MAP_NOINTPOSE
));
2801 ss
->ss_mv
.mv_errcnt
++;
2804 ss
->ss_ms
.ms_sdflags
|= FLG_SY_INTPOSE
;
2805 ofl
->ofl_flags
|= FLG_OF_SYMINFO
;
2806 ofl
->ofl_dtflags_1
|= DF_1_SYMINTPOSE
;
2809 ss
->ss_ms
.ms_sdflags
|= FLG_SY_NDIR
;
2810 ofl
->ofl_flags
|= FLG_OF_SYMINFO
;
2812 (FLG_OF1_NDIRECT
| FLG_OF1_NGLBDIR
);
2814 case FLG_SY_NODYNSORT
:
2815 ss
->ss_ms
.ms_sdflags
&= ~FLG_SY_DYNSORT
;
2816 ss
->ss_ms
.ms_sdflags
|= FLG_SY_NODYNSORT
;
2819 ss
->ss_ms
.ms_sdflags
|= FLG_SY_PARENT
;
2820 ofl
->ofl_flags
|= FLG_OF_SYMINFO
;
2832 char buf
[VLA_SIZE(symflag_list_bufsize
)];
2834 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SYMFLAG
),
2835 ld_map_kwnames(symflag_list
,
2836 SGSOFFSETOF(symflag_t
, name
),
2837 sizeof (symflag
[0]), buf
,
2838 symflag_list_bufsize
),
2839 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
2845 /* Make sure there was at least one flag specified */
2847 mf_fatal(mf
, MSG_INTL(MSG_MAP_NOVALUES
),
2848 MSG_ORIG(MSG_MAPKW_FLAGS
));
2852 return (tok
); /* Either TK_SEMICOLON or TK_RIGHTBKT */
2856 * SYMBOL [version_name] { symbol_name { SIZE = value
2857 * --------------------------------------------^
2861 at_sym_size(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2863 symbol_state_t
*ss
= uvalue
;
2867 if (gettoken_int(mf
, MSG_ORIG(MSG_MAPKW_SIZE
), &tkv
) == TK_ERROR
)
2870 ss
->ss_ms
.ms_size
= tkv
.tkv_int
.tkvi_value
;
2873 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_SIZE
)));
2877 const char *name
; /* type name */
2878 Word ms_shndx
; /* symbol section index */
2879 uchar_t ms_type
; /* STT_ symbol type */
2882 static at_sym_type_t at_sym_type_list
[] = {
2883 { MSG_ORIG(MSG_MAPKW_COMMON
), SHN_COMMON
, STT_OBJECT
},
2884 { MSG_ORIG(MSG_MAPKW_DATA
), SHN_ABS
, STT_OBJECT
},
2885 { MSG_ORIG(MSG_MAPKW_FUNCTION
), SHN_ABS
, STT_FUNC
},
2887 /* List must be null terminated */
2892 * Size of buffer needed to format the names in at_sym_type_list[]. Must
2893 * be kept in sync with at_sym_type_list.
2895 static size_t at_sym_type_list_bufsize
=
2896 KW_NAME_SIZE(MSG_MAPKW_COMMON
) +
2897 KW_NAME_SIZE(MSG_MAPKW_DATA
) +
2898 KW_NAME_SIZE(MSG_MAPKW_FUNCTION
);
2901 * at_sym_type(): Value for TYPE= is not a symbol type
2904 gts_efunc_at_sym_type(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
2906 Conv_inv_buf_t inv_buf
;
2907 char buf
[VLA_SIZE(at_sym_type_list_bufsize
)];
2909 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SYMTYPE
),
2910 ld_map_kwnames(at_sym_type_list
, SGSOFFSETOF(at_sym_type_t
, name
),
2911 sizeof (at_sym_type_list
[0]), buf
, at_sym_type_list_bufsize
),
2912 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
2916 * SYMBOL [version_name] { symbol_name { TYPE = symbol_type
2917 * --------------------------------------------^
2921 at_sym_type(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2923 symbol_state_t
*ss
= uvalue
;
2924 at_sym_type_t
*type
;
2928 if (gettoken_str(mf
, TK_F_KEYWORD
, &tkv
, gts_efunc_at_sym_type
) ==
2932 type
= ld_map_kwfind(tkv
.tkv_str
, at_sym_type_list
,
2933 SGSOFFSETOF(at_sym_type_t
, name
), sizeof (type
[0]));
2935 gts_efunc_at_sym_type(mf
, TK_STRING
, &tkv
);
2939 ss
->ss_ms
.ms_shndx
= type
->ms_shndx
;
2940 ss
->ss_ms
.ms_sdflags
|= FLG_SY_SPECSEC
;
2941 ss
->ss_ms
.ms_type
= type
->ms_type
;
2944 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_TYPE
)));
2948 * SYMBOL [version_name] { symbol_name { VALUE = value
2949 * ---------------------------------------------^
2953 at_sym_value(Mapfile
*mf
, Token eq_tok
, void *uvalue
)
2955 symbol_state_t
*ss
= uvalue
;
2959 if (gettoken_int(mf
, MSG_ORIG(MSG_MAPKW_VALUE
), &tkv
) == TK_ERROR
)
2962 ss
->ss_ms
.ms_value
= tkv
.tkv_int
.tkvi_value
;
2963 ss
->ss_ms
.ms_value_set
= TRUE
;
2967 return (gettoken_term(mf
, MSG_ORIG(MSG_MAPKW_VALUE
)));
2971 * Parse the attributes for a SCOPE or VERSION symbol directive.
2974 * mf - Mapfile descriptor
2975 * dir_name - Name of directive.
2976 * ss - Pointer to symbol state block that has had its ss_nv
2977 * member initialzed via a call to ld_map_sym_ver_init().
2980 * parse_symbol_attributes() returns TK_RIGHTBKT on success, and TK_ERROR
2984 parse_symbol_attributes(Mapfile
*mf
, const char *dir_name
, symbol_state_t
*ss
)
2986 /* Symbol attributes */
2987 static attr_t attr_list
[] = {
2988 { MSG_ORIG(MSG_MAPKW_AUX
), at_sym_aux
, ATTR_FMT_EQ
},
2989 { MSG_ORIG(MSG_MAPKW_FILTER
), at_sym_filter
, ATTR_FMT_EQ
},
2990 { MSG_ORIG(MSG_MAPKW_FLAGS
), at_sym_flags
, ATTR_FMT_EQ
},
2991 { MSG_ORIG(MSG_MAPKW_SIZE
), at_sym_size
, ATTR_FMT_EQ
},
2992 { MSG_ORIG(MSG_MAPKW_TYPE
), at_sym_type
, ATTR_FMT_EQ
},
2993 { MSG_ORIG(MSG_MAPKW_VALUE
), at_sym_value
, ATTR_FMT_EQ
},
2995 /* List must be null terminated */
3000 * Size of buffer needed to format the names in attr_list[]. Must
3001 * be kept in sync with attr_list.
3003 static size_t attr_list_bufsize
=
3004 KW_NAME_SIZE(MSG_MAPKW_AUX
) +
3005 KW_NAME_SIZE(MSG_MAPKW_FILTER
) +
3006 KW_NAME_SIZE(MSG_MAPKW_FLAGS
) +
3007 KW_NAME_SIZE(MSG_MAPKW_SIZE
) +
3008 KW_NAME_SIZE(MSG_MAPKW_TYPE
) +
3009 KW_NAME_SIZE(MSG_MAPKW_VALUE
);
3012 ld_map_tkval_t tkv
, tkv_sym
;
3014 Conv_inv_buf_t inv_buf
;
3016 /* Read attributes until the closing '}' is seen */
3017 for (done
= 0; done
== 0; ) {
3019 * We have to allow quotes around symbol names, but the
3020 * name we read may also be a symbol scope keyword. We won't
3021 * know which until we read the following token, and so have
3022 * to allow quotes for both. Hence, symbol scope names can
3023 * be quoted --- an unlikely occurrence and not worth
3024 * complicating the code.
3026 switch (tok
= ld_map_gettoken(mf
, 0, &tkv_sym
)) {
3031 /* Default value for all symbol attributes is 0 */
3032 (void) memset(&ss
->ss_ms
, 0, sizeof (ss
->ss_ms
));
3033 ss
->ss_ms
.ms_name
= tkv_sym
.tkv_str
;
3036 * Turn off the WEAK flag to indicate that definitions
3037 * are associated with this version. It would probably
3038 * be more accurate to only remove this flag with the
3039 * specification of global symbols, however setting it
3040 * here allows enough slop to compensate for the
3041 * various user inputs we've seen so far. Only if a
3042 * closed version is specified (i.e., "SUNW_1.x {};")
3043 * will a user get a weak version (which is how we
3044 * document the creation of weak versions).
3046 ss
->ss_mv
.mv_vdp
->vd_flags
&= ~VER_FLG_WEAK
;
3049 * The meaning of this name depends on the following
3053 * ; Symbol without attributes
3054 * { Symbol with attributes
3056 switch (tok
= ld_map_gettoken(mf
, 0, &tkv
)) {
3061 ld_map_sym_scope(mf
, tkv_sym
.tkv_str
,
3065 /* name is a symbol with attributes */
3066 if (parse_attributes(mf
, tkv_sym
.tkv_str
,
3067 attr_list
, attr_list_bufsize
, ss
) ==
3070 /* Terminating ';', or '}' */
3071 tok
= gettoken_term(mf
,
3072 MSG_INTL(MSG_MAP_SYMATTR
));
3073 if (tok
== TK_ERROR
)
3075 if (tok
== TK_RIGHTBKT
)
3081 * Add the new symbol. It should be noted that
3082 * all symbols added by the mapfile start out
3083 * with global scope, thus they will fall
3084 * through the normal symbol resolution
3085 * process. Symbols defined as locals will
3086 * be reduced in scope after all input file
3089 if (!ld_map_sym_enter(mf
, &ss
->ss_mv
,
3094 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SYMDELIM
),
3095 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));
3105 break; /* Ignore empty statement */
3109 * Turn off the WEAK flag, as explained above for
3112 ss
->ss_mv
.mv_vdp
->vd_flags
&= ~VER_FLG_WEAK
;
3114 ld_map_sym_autoreduce(mf
, &ss
->ss_mv
);
3117 * Following token must be ';' to terminate the stmt,
3118 * or '}' to terminate the whole directive.
3120 switch (tok
= gettoken_term(mf
, dir_name
)) {
3130 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_SYM
),
3131 ld_map_tokenstr(tok
, &tkv_sym
, &inv_buf
));
3137 * In the SYMBOL directive, we keep parsing in the face of
3138 * errors that don't involve resources, to maximize what we
3139 * can report in a single invocation. If we encountered such
3140 * an error, act on the error(s) now.
3142 if (ss
->ss_mv
.mv_errcnt
)
3150 * Top Level Directive:
3152 * SYMBOL_SCOPE { ...
3156 dir_symbol_scope(Mapfile
*mf
)
3160 /* The first token must be a '{' */
3161 if (gettoken_leftbkt(mf
, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE
)) == TK_ERROR
)
3164 /* Establish the version descriptor and related data */
3165 if (!ld_map_sym_ver_init(mf
, NULL
, &ss
.ss_mv
))
3168 /* Read attributes until the closing '}' is seen */
3169 if (parse_symbol_attributes(mf
, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE
),
3173 /* Terminating ';' */
3174 return (gettoken_semicolon(mf
, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE
)));
3179 * at_dv_allow(): Value for ALLOW= is not a version string
3182 gts_efunc_dir_symbol_version(Mapfile
*mf
, Token tok
, ld_map_tkval_t
*tkv
)
3184 Conv_inv_buf_t inv_buf
;
3186 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_VERSION
),
3187 MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION
),
3188 ld_map_tokenstr(tok
, tkv
, &inv_buf
));
3192 * Top Level Directive:
3194 * SYMBOL_VERSION version_name { ...
3198 dir_symbol_version(Mapfile
*mf
)
3204 /* The first token must be a version name */
3205 if (gettoken_str(mf
, 0, &tkv
, gts_efunc_dir_symbol_version
) == TK_ERROR
)
3208 /* The next token is expected to be '{' */
3209 if (gettoken_leftbkt(mf
, MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION
)) ==
3213 /* Establish the version descriptor and related data */
3214 if (!ld_map_sym_ver_init(mf
, tkv
.tkv_str
, &ss
.ss_mv
))
3217 /* Read attributes until the closing '}' is seen */
3218 if (parse_symbol_attributes(mf
, MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION
),
3223 * Determine if any version references are provided after the close
3224 * bracket, parsing up to the terminating ';'.
3226 if (!ld_map_sym_ver_fini(mf
, &ss
.ss_mv
))
3229 return (TK_SEMICOLON
);
3234 * Parse the mapfile --- Solaris syntax
3237 ld_map_parse_v2(Mapfile
*mf
)
3239 /* Valid top level mapfile directives */
3241 const char *name
; /* Directive */
3242 dir_func_t func
; /* Function to parse directive */
3246 tldir_t dirlist
[] = {
3247 { MSG_ORIG(MSG_MAPKW_CAPABILITY
), dir_capability
},
3248 { MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS
), dir_depend_versions
},
3249 { MSG_ORIG(MSG_MAPKW_HDR_NOALLOC
), dir_hdr_noalloc
},
3250 { MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT
), dir_load_segment
},
3251 { MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT
), dir_note_segment
},
3252 { MSG_ORIG(MSG_MAPKW_NULL_SEGMENT
), dir_null_segment
},
3253 { MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL
), dir_phdr_add_null
},
3254 { MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER
), dir_segment_order
},
3255 { MSG_ORIG(MSG_MAPKW_STACK
), dir_stack
},
3256 { MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE
), dir_symbol_scope
},
3257 { MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION
), dir_symbol_version
},
3259 /* List must be null terminated */
3264 * Size of buffer needed to format the names in dirlist[]. Must
3265 * be kept in sync with dirlist.
3267 static size_t dirlist_bufsize
=
3268 KW_NAME_SIZE(MSG_MAPKW_CAPABILITY
) +
3269 KW_NAME_SIZE(MSG_MAPKW_DEPEND_VERSIONS
) +
3270 KW_NAME_SIZE(MSG_MAPKW_HDR_NOALLOC
) +
3271 KW_NAME_SIZE(MSG_MAPKW_LOAD_SEGMENT
) +
3272 KW_NAME_SIZE(MSG_MAPKW_NOTE_SEGMENT
) +
3273 KW_NAME_SIZE(MSG_MAPKW_NULL_SEGMENT
) +
3274 KW_NAME_SIZE(MSG_MAPKW_PHDR_ADD_NULL
) +
3275 KW_NAME_SIZE(MSG_MAPKW_SEGMENT_ORDER
) +
3276 KW_NAME_SIZE(MSG_MAPKW_STACK
) +
3277 KW_NAME_SIZE(MSG_MAPKW_SYMBOL_SCOPE
) +
3278 KW_NAME_SIZE(MSG_MAPKW_SYMBOL_VERSION
);
3280 Token tok
; /* current token. */
3281 ld_map_tkval_t tkv
; /* Value of token */
3283 Conv_inv_buf_t inv_buf
;
3286 tok
= ld_map_gettoken(mf
, TK_F_EOFOK
| TK_F_KEYWORD
, &tkv
);
3292 case TK_SEMICOLON
: /* Terminator, or empty directive: Ignore */
3295 /* Map name to entry in dirlist[] */
3296 tldir
= ld_map_kwfind(tkv
.tkv_str
, dirlist
,
3297 SGSOFFSETOF(tldir_t
, name
), sizeof (dirlist
[0]));
3299 /* Not a directive we know? */
3303 /* Call the function associated with this directive */
3304 if (tldir
->func(mf
) == TK_ERROR
)
3310 char buf
[VLA_SIZE(dirlist_bufsize
)];
3312 mf_fatal(mf
, MSG_INTL(MSG_MAP_EXP_DIR
),
3313 ld_map_kwnames(dirlist
,
3314 SGSOFFSETOF(tldir_t
, name
),
3315 sizeof (dirlist
[0]), buf
, dirlist_bufsize
),
3316 ld_map_tokenstr(tok
, &tkv
, &inv_buf
));