/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Map file parsing, Version 2 syntax (solaris).
*/
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <elfcap.h>
#include "msg.h"
#include "_libld.h"
#include "_map.h"
/*
* Use a case insensitive string match when looking up capability mask
* values by name, and omit the AV_ prefix.
*/
/*
* Signature for functions used to parse top level mapfile directives
*/
/*
* Signature for functions used to parse attribute level assignments
* mf - Mapfile descriptor
* eq_tok - One of the equal tokens (TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ)
* or TK_ERROR. See the comment for attr_fmt_t below.
* uvalue - An arbitrary pointer "user value" passed by the
* caller to parse_attributes() for use by the function.
*/
/*
* Signature for gettoken_str() err_func argument. This is a function
* called to issue an appropriate error message.
*
* The gts prefix stands for "Get Token Str"
*/
/*
* The attr_fmt_t tells parse_attributes how far to go in parsing
* an attribute before it calls the at_func function to take over:
*
* ATTR_FMT_NAME - Parse the name, and immediately call the function.
* This is useful in cases where there is more than
* one possible syntax for a given attribute. The value of
* eq_tok passed to the at_func function will be TK_ERROR,
* reflecting the fact that it has no meaning in this context.
*
* ATTR_FMT_EQ - Parse the name, and the following '=', and then call
* the function. The value passed to the at_func function for
* eq_tok will be TK_EQUAL.
*
* ATTR_FMT_EQ_PEQ - Parse the name, and a following equal token which
* can be '=' or '+=', and then call the function. The value
* passed to the at_func function for eq_tok will be one of
* TK_EQUAL, or TK_PLUSEQ.
*
* ATTR_FMT_EQ_ALL - Parse the name, and a following equal token which
* can be any of the three forms (=, +=, -=), and then call
* the function. The value passed to the at_func function for
* eq_tok will be one of TK_EQUAL, TK_PLUSEQ, or TK_MINUSEQ.
*/
typedef enum {
} attr_fmt_t;
/*
* Type used to describe a set of valid attributes to parse_attributes():
* at_name - Name of attribute
* at_func - Function to call when attribute is recognized,
* at_all_eq - True if attribute allows the '+=' and '-=' forms of
* assignment token, and False to only allow '='.
*
* The array of these structs passed to parse_attributes() must be
* NULL terminated (the at_name field must be set to NULL).
*/
typedef struct {
/* at_func */
} attr_t;
/*
* Mapfile version and symbol state are separate but related concepts
* that are best represented using two different types. However, our
* style of passing a single uvalue via parse_attributes() makes it
* convenient to be able to reference them from a single address.
*/
typedef struct {
/*
* Process an expected equal operator. Deals with the fact that we
* have three variants.
*
* entry:
* mf - Mapfile descriptor
* eq_type - Types of equal operators accepted. One of ATTR_FMT_EQ,
* ATTR_FMT_EQ_PEQ, or ATTR_FMT_EQ_ALL.
* lhs - Name that appears on the left hand side of the expected
* equal operator.
*
* exit:
* Returns one of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, or TK_ERROR.
*/
static Token
{
const char *err;
case TK_ERROR:
case TK_EQUAL:
return (tok);
case TK_PLUSEQ:
switch (eq_type) {
case ATTR_FMT_EQ_PEQ:
case ATTR_FMT_EQ_ALL:
return (tok);
}
break;
case TK_MINUSEQ:
if (eq_type == ATTR_FMT_EQ_ALL)
return (tok);
break;
}
switch (eq_type) {
case ATTR_FMT_EQ:
break;
case ATTR_FMT_EQ_PEQ:
break;
case ATTR_FMT_EQ_ALL:
break;
default:
/*NOTREACHED*/
assert(0);
}
return (TK_ERROR);
}
/*
* Apply one of the three equal tokens to a bitmask value
*
* entry:
* dst - Address of bitmask variable to alter
* eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
* the operation to carry out.
* value - Value for right hand side
*
* exit:
* The operation has been carried out:
*
* TK_EQUAL - *dst is set to value
* TK_PLUSEQ - Bits in value have been set in *dst
* TK_MINUSEQ - Bits in value have been removed from *dst
*/
static void
{
switch (eq_tok) {
case TK_EQUAL:
break;
case TK_PLUSEQ:
break;
case TK_MINUSEQ:
break;
default:
/*NOTREACHED*/
assert(0);
}
}
/*
* Apply one of the three equal tokens to a capabilities Capmask.
*
* entry:
* mf - Mapfile descriptor
* capmask - Address of Capmask variable to alter
* eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
* the operation to carry out.
* type - Capability type (CA_SUNW_*)
* value - Value for right hand side
* title - True if a title is needed, False otherwise.
*
* exit:
* On success, returns TRUE (1), otherwise FALSE (0)
*/
static Boolean
{
if (title)
switch (eq_tok) {
case TK_EQUAL:
break;
case TK_PLUSEQ:
break;
case TK_MINUSEQ:
break;
default:
/*NOTREACHED*/
assert(0);
}
/* Sanity check the resulting bits */
return (FALSE);
/* Report the final configuration */
return (TRUE);
}
/*
* Apply one of the three equal tokens to a capabilities Caplist.
*
* entry:
* mf - Mapfile descriptor
* caplist - Address of Caplist variable to alter
* eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
* the operation to carry out.
* type - Capability type (CA_SUNW_*)
* str - String for right hand side
* title - True if a title is needed, False otherwise.
*
* exit:
* On success, returns TRUE (1), otherwise FALSE (0)
*/
static Boolean
{
char *str;
} else {
}
}
switch (eq_tok) {
case TK_EQUAL:
}
}
if (strs) {
AL_CNT_CAP_NAMES)) == NULL)
return (FALSE);
}
} else {
}
break;
case TK_PLUSEQ:
const char *ostr;
int found = 0;
/*
* Add this name to the list of names, provided the
* name doesn't already exist.
*/
found++;
break;
}
}
return (FALSE);
/*
* Remove this name from the list of excluded names,
* provided the name already exists.
*/
break;
}
}
}
break;
case TK_MINUSEQ:
const char *ostr;
int found = 0;
/*
* Delete this name from the list of names, provided
* the name already exists.
*/
break;
}
}
/*
* Add this name to the list of excluded names,
* provided the name already exists.
*/
found++;
break;
}
}
return (FALSE);
}
break;
default:
/*NOTREACHED*/
assert(0);
}
/* Report the final configuration */
} else {
}
}
return (TRUE);
}
/*
* Process the next token, which is expected to start an optional
* nesting of attributes (';' or '{').
*
* entry:
* mf - Mapfile descriptor
* lhs - Name of the directive or attribute being processed.
*
* exit:
* Returns TK_SEMICOLON or TK_LEFTBKT for success, and TK_ERROR otherwise.
*/
static Token
{
case TK_ERROR:
case TK_SEMICOLON:
case TK_LEFTBKT:
return (tok);
}
return (TK_ERROR);
}
/*
* Process the next token, which is expected to be a line terminator
* (';' or '}').
*
* entry:
* mf - Mapfile descriptor
* lhs - Name of the directive or attribute being processed.
*
* exit:
* Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
*/
static Token
{
case TK_ERROR:
case TK_SEMICOLON:
case TK_RIGHTBKT:
return (tok);
}
return (TK_ERROR);
}
/*
* Process the next token, which is expected to be a semicolon.
*
* entry:
* mf - Mapfile descriptor
* lhs - Name of the directive or attribute being processed.
*
* exit:
* Returns TK_SEMICOLON for success, and TK_ERROR otherwise.
*/
static Token
{
case TK_ERROR:
case TK_SEMICOLON:
return (tok);
}
return (TK_ERROR);
}
/*
* Process the next token, which is expected to be a '{'
*
* entry:
* mf - Mapfile descriptor
* lhs - Name of the item directly to the left of the expected left
* bracket.
*
* exit:
* Returns TK_LEFTBKT for success, and TK_ERROR otherwise.
*/
static Token
{
case TK_ERROR:
case TK_LEFTBKT:
return (tok);
}
return (TK_ERROR);
}
/*
* Process the next token, which is expected to be an integer
*
* entry:
* mf - Mapfile descriptor
* lhs - Name of the directive or attribute being processed.
* tkv - Address of token value struct to be filled in
*
* exit:
* Updates *tkv and returns TK_INT for success, TK_ERROR otherwise.
*/
static Token
{
case TK_ERROR:
case TK_INT:
return (tok);
}
return (TK_ERROR);
}
/*
* Process the next token, which is expected to be a string
*
* entry:
* mf - Mapfile descriptor
* lhs - Name of the directive or attribute being processed.
* tkv - Address of token value struct to be filled in
* err_func - Function to call if an error occurs
*
* exit:
* Updates *tkv and returns TK_STRING for success. Calls the
* supplied err_func function and returns TK_ERROR otherwise.
*/
static Token
{
case TK_ERROR:
case TK_STRING:
return (tok);
}
/* User supplied function reports the error */
return (TK_ERROR);
}
/*
* Given a construct of the following common form:
*
* item_name {
* attribute = ...;
* ...
* }
*
* where the caller has detected the item_name and opening bracket,
* parse the construct and call the attribute functions for each
* attribute detected, stopping when the closing '}' is seen.
*
* entry:
* mf - Mapfile descriptor
* item_name - Already detected name of item for which attributes
* are being parsed.
* attr_list - NULL terminated array of attr_t structures describing the
* valid attributes for the item.
* expect_str - Comma separated string listing the names of expected
* attributes.
* uvalue - User value, passed to the attribute functions without
* examination by parse_attributes(), usable for maintaining
* shared state between the caller and the functions.
*
* exit:
* parse_attributes() reads the attribute name and equality token,
* and then calls the attribute function given by the attr_list array
* to handle everything up to and including the terminating ';'.
* This continues until the closing '}' is seen.
*
* If everything is successful, TK_RIGHTBKT is returned. Otherwise,
* a suitable error is issued and TK_ERROR is returned.
*/
static Token
{
int done;
int attr_cnt = 0;
/* Read attributes until the closing '}' is seen */
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
goto bad_attr;
/*
* Depending on the value of at_fmt, there are
* fout different actions to take:
* ATTR_FMT_NAME - Call at_func function
* ATTR_FMT_EQ - Read and verify a TK_EQUAL
* ATTR_FMT_EQ_PEQ - Read and verify a TK_EQUAL
* or TK_PLUSEQ.
* three possible equal tokens
* (TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ).
*/
/* Arbitrary value to pass to at_func */
} else {
return (TK_ERROR);
}
/* Call the associated function */
default:
return (TK_ERROR);
case TK_SEMICOLON:
break;
case TK_RIGHTBKT:
done = 1;
break;
}
attr_cnt++;
break;
case TK_RIGHTBKT:
done = 1;
break;
case TK_SEMICOLON:
break; /* Ignore empty statement */
default:
{
}
return (TK_ERROR);
}
}
/* Make sure there was at least one attribute between the {} brackets */
if (attr_cnt == 0) {
return (TK_ERROR);
}
return (tok);
}
/*
* Read whitespace delimited segment flags from the input and convert into
* bitmask of PF_ values they represent. Flags are terminated by a semicolon
* or right bracket.
*
* entry:
* mf - Mapfile descriptor
* flags - Address of variable to be set to resulting flags value
*
* exit:
* Returns the terminator token (TK_SEMICOLON or TK_LEFTBKT) on success,
* and TK_ERROR otherwise.
*/
static Token
{
/*
* Map flag names to their values. Since DATA and STACK have
* platform dependent values, we have to determine them at runtime.
* We indicate this by setting the top bit.
*/
typedef struct {
const char *name;
} segflag_t;
/* List must be null terminated */
{ 0 },
};
/*
* Size of buffer needed to format the names in flag_list[]. Must
* be kept in sync with flag_list.
*/
int done;
*flags = 0;
/* Read attributes until the ';' terminator is seen */
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
sizeof (flag_list[0]));
goto bad_flag;
case PF_DATA:
break;
case PF_STACK:
break;
default:
}
cnt++;
break;
case TK_INT:
/*
* Accept 0 for notational convenience, but refuse
* any other value. Note that we don't actually have
* to set the flags to 0 here, because there are
* already initialized to that before the main loop.
*/
goto bad_flag;
cnt++;
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
{
}
return (TK_ERROR);
}
}
/* Make sure there was at least one flag */
if (cnt == 0) {
return (TK_ERROR);
}
return (tok);
}
/*
* Parse one of the capabilities attributes that corresponds directly to a
* capabilities bitmask value (CA_SUNW_HW_x, CA_SUNW_SF_xx). Values can be
* integers, or symbolic names that correspond to the capabilities mask
* in question.
*
* entry:
* mf - Mapfile descriptor
* eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
* the operation to carry out.
* capmask - Capmask from output descriptor for capability being processed.
* type - Capability type (CA_SUNW_*)
* elfcap_from_str_func - pointer to elfcap-string-to-value function
* for capability being processed.
*
* exit:
* Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
*/
static Token
{
int done;
uint64_t v;
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
if ((v = (* elfcap_from_str_func)(ELFCAP_STYLE,
value |= v;
break;
}
goto bad_flag;
case TK_INT:
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
return (TK_ERROR);
}
}
return (TK_ERROR);
return (tok);
}
/*
* Parse one of the capabilities attributes that manages lists of names
* (CA_SUNW_PLAT and CA_SUNW_MACH). Values are symbolic names that correspond
* to the capabilities mask in question.
*
* entry:
* mf - Mapfile descriptor
* eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
* the operation to carry out.
* caplist - Caplist from output descriptor for capability being processed.
* type - Capability type (CA_SUNW_*)
*
* exit:
* Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
*/
static Token
{
const char *str;
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
/*
* The name is in tkv.tkv_str. Save this string for
* set_capstr() processing, but remove any duplicates.
*/
found++;
break;
}
}
AL_CNT_CAP_NAMES) == NULL))
return (TK_ERROR);
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
return (TK_ERROR);
}
}
return (TK_ERROR);
return (tok);
}
/*
* CAPABILITY [capid] { HW = hwcap_flags...
* -------------------------^
*/
/* ARGSUSED 2 */
static Token
{
int done;
uint64_t v;
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
if ((v = elfcap_hw1_from_str(ELFCAP_STYLE,
hw1 |= v;
break;
}
if ((v = elfcap_hw2_from_str(ELFCAP_STYLE,
hw2 |= v;
break;
}
goto bad_flag;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
return (TK_ERROR);
}
}
return (TK_ERROR);
return (TK_ERROR);
return (tok);
}
/*
* CAPABILITY [capid] { HW_1 = value ;
* ---------------------------^
*/
/* ARGSUSED 2 */
static Token
{
}
/*
* CAPABILITY [capid] { HW_2 = value ;
* ---------------------------^
*/
/* ARGSUSED 2 */
static Token
{
}
/*
* CAPABILITY [capid] { SF = sfcap_flags...
* -------------------------^
*/
/* ARGSUSED 2 */
static Token
{
int done;
uint64_t v;
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
if ((v = elfcap_sf1_from_str(ELFCAP_STYLE,
sf1 |= v;
break;
}
goto bad_flag;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
return (TK_ERROR);
}
}
return (TK_ERROR);
return (tok);
}
/*
* CAPABILITY [capid] { SF_1 = value ;
* ---------------------------^
*/
/* ARGSUSED 2 */
static Token
{
}
/*
* CAPABILITY [capid] { MACHINE = value ;
* ------------------------------^
*/
/* ARGSUSED 2 */
static Token
{
CA_SUNW_MACH));
}
/*
* CAPABILITY [capid] { PLATFORM = value ;
* -------------------------------^
*/
/* ARGSUSED 2 */
static Token
{
CA_SUNW_PLAT));
}
/*
* Top Level Directive:
*
* CAPABILITY [capid] { ...
* ----------^
*/
static Token
{
/* CAPABILITY attributes */
/* List must be null terminated */
{ 0 }
};
/*
* Size of buffer needed to format the names in attr_list[]. Must
* be kept in sync with attr_list.
*/
/*
* The first token can be one of:
* - An opening '{'
* - A name, followed by a '{', or a ';'.
* Read this initial sequence.
*/
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
/*
* The ID name is in tkv.tkv_str. Save this name in the output
* capabilities structure. Note, should multiple ID entries
* be encounterd, the last entry wins.
*/
/*
* The name can be followed by an opening '{', or a
* terminating ';'
*/
case TK_SEMICOLON:
return (TK_SEMICOLON);
case TK_LEFTBKT:
break;
default:
return (TK_ERROR);
}
break;
case TK_LEFTBKT:
/* Directive has no capid, but does supply attributes */
break;
default:
return (TK_ERROR);
}
/* Parse the attributes */
return (TK_ERROR);
/* Terminating ';' */
}
/*
* at_dv_allow(): Value for ALLOW= is not a version string
*/
static void
{
}
/*
* DEPEND_VERSIONS object_name { ALLOW = version
* -------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
return (TK_ERROR);
/* Enter the version. uvalue points at the Sdf_desc descriptor */
return (TK_ERROR);
/* terminator */
}
/*
* at_dv_allow(): Value for REQUIRE= is not a version string
*/
static void
{
}
/*
* DEPEND_VERSIONS object_name { REQURE = version
* --------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* version_name */
return (TK_ERROR);
/* Enter the version. uvalue points at the Sdf_desc descriptor */
return (TK_ERROR);
/* terminator */
}
/*
* dir_depend_versions(): Expected object name is not present
*/
static void
{
}
/*
* Top Level Directive:
*
* DEPEND_VERSIONS object_name { ATTR = ...
* ---------------^
*/
static Token
{
/* DEPEND_VERSIONS attributes */
/* List must be null terminated */
{ 0 }
};
/*
* Size of buffer needed to format the names in attr_list[]. Must
* be kept in sync with attr_list.
*/
/* object_name */
return (TK_ERROR);
/* Get descriptor for dependency */
return (TK_ERROR);
/* Opening '{' token */
return (TK_ERROR);
/* Parse the attributes */
return (TK_ERROR);
/* Terminating ';' */
}
/*
* Top Level Directive:
*
* HDR_NOALLOC ;
* -----------^
*/
static Token
{
/* ';' terminator token */
}
/*
* Top Level Directive:
*
* PHDR_ADD_NULL = cnt ;
* -------------^
*/
static Token
{
/* '=' token */
return (TK_ERROR);
/* integer token */
return (TK_ERROR);
return (TK_ERROR);
return (TK_ERROR);
}
/* ';' terminator token */
}
/*
* segment_directive segment_name { ALIGN = value
* ----------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* value */
return (TK_ERROR);
/* terminator */
}
/*
* at_seg_assign_file_basename(): Value for FILE_BASENAME= is not a file name
*/
static void
{
}
/*
* segment_directive segment_name { ASSIGN { FILE_BASENAME = file_name
* ---------------------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* file_name */
return (TK_ERROR);
return (TK_ERROR);
/* terminator */
}
/*
* at_seg_assign_file_objname(): Value for FILE_OBJNAME= is not an object name
*/
static void
{
}
/*
* segment_directive segment_name { ASSIGN { FILE_OBJNAME = name
* --------------------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* file_objname */
return (TK_ERROR);
return (TK_ERROR);
/* terminator */
}
/*
* at_seg_assign_file_path(): Value for FILE_PATH= is not a file path
*/
static void
{
}
/*
* segment_directive segment_name { ASSIGN { FILE_PATH = file_path
* -----------------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* file_path */
return (TK_ERROR);
return (TK_ERROR);
/* terminator */
}
/*
* segment_directive segment_name { ASSIGN { FLAGS = ... ;
* -------------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
typedef struct {
const char *name;
} secflag_t;
/* List must be null terminated */
{ 0 },
};
/*
* Size of buffer needed to format the names in flag_list[]. Must
* be kept in sync with flag_list.
*/
int done;
/* Read and process tokens until the closing terminator is seen */
case TK_ERROR:
return (TK_ERROR);
case TK_BANG:
/* Ensure ! only specified once per flag */
if (bcnt != 0) {
return (TK_ERROR);
}
bcnt++;
break;
case TK_STRING:
goto bad_flag;
cnt++;
if (bcnt == 0)
bcnt = 0;
break;
case TK_RIGHTBKT:
case TK_SEMICOLON:
done = 1;
break;
default:
{
}
return (TK_ERROR);
}
}
/*
* Ensure that a trailing '!' was not left at the end of the line
* without a corresponding flag to apply it to.
*/
if (bcnt != 0) {
return (TK_ERROR);
}
/* Make sure there was at least one flag */
if (cnt == 0) {
return (TK_ERROR);
}
return (tok); /* Either TK_SEMICOLON or TK_RIGHTBKT */
}
/*
* at_seg_assign_is_name(): Value for IS_NAME= is not a section name
*/
static void
{
}
/*
* segment_directive segment_name { ASSIGN { IS_NAME = section_name ;
* ---------------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* section_name */
return (TK_ERROR);
/* terminator */
}
/*
* at_seg_assign_type(): Value for TYPE= is not a section type
*/
static void
{
}
/*
* segment_directive segment_name { ASSIGN { TYPE = section_type ;
* ------------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* section type */
return (TK_ERROR);
/*
* Use the libconv iteration facility to map the given name to
* its value. This allows us to keep up with any new sections
* without having to change this code.
*/
/* Look at the canonical form */
/* Failing that, look at the normal form */
if (status != CONV_ITER_DONE)
(void) conv_iter_sec_type(CONV_OSABI_ALL,
&conv_uvalue);
/* If we didn't match anything report error */
if (!conv_uvalue.csl_found) {
return (TK_ERROR);
}
}
/* terminator */
}
/*
* segment_directive segment_name { ASSIGN { ...
* -----------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* segment_directive ASSIGN sub-attributes */
/* List must be null terminated */
{ 0 }
};
/*
* Size of buffer needed to format the names in attr_list[]. Must
* be kept in sync with attr_list.
*/
/*
* ASSIGN takes an optional name, plus attributes are optional,
* so expect a name, an opening '{', or a ';'.
*/
switch (tok) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
break;
}
/* Add a new entrance criteria descriptor to the segment */
return (TK_ERROR);
/* Having handled the name, expect either '{' or ';' */
switch (tok) {
default:
return (TK_ERROR);
case TK_ERROR:
return (TK_ERROR);
case TK_SEMICOLON:
case TK_RIGHTBKT:
/* No attributes: It will match anything */
break;
case TK_LEFTBKT:
/* Parse the attributes */
return (TK_ERROR);
/* Terminating ';', or '}' which also terminates caller */
return (TK_ERROR);
break;
}
return (tok);
}
/*
* segment_directive segment_name { DISABLE ;
* ----------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* If the segment cannot be disabled, issue error */
return (TK_ERROR);
}
/* Disable the segment */
/* terminator */
}
/*
* segment_directive segment_name { FLAGS eq-op ...
* --------------------------------------------^
*
* Note that this routine is also used for the STACK directive,
* as STACK also manipulates a segment descriptor.
*
* STACK { FLAGS eq-op ... ;
* -------------------^
*/
/* ARGSUSED 2 */
static Token
{
return (TK_ERROR);
return (tok);
}
/*
* segment_directive segment_name { IS_ORDER eq_op value
* -----------------------------------------------^
*/
/* ARGSUSED 2 */
static Token
{
int done;
/*
* The '=' form of assignment resets the list. The list contains
* pointers to our mapfile text, so we do not have to free anything.
*/
/*
* One or more ASSIGN names, terminated by a semicolon.
*/
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
/*
* The referenced entrance criteria must have
* already been defined.
*/
return (TK_ERROR);
}
/*
* Make sure it's not already on the list
*/
return (TK_ERROR);
}
/* Put it at the end of the order list */
AL_CNT_SG_IS_ORDER) == NULL)
return (TK_ERROR);
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
return (TK_ERROR);
}
}
return (tok);
}
/*
* segment_directive segment_name { MAX_SIZE = value
* -------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* value */
return (TK_ERROR);
/* terminator */
}
/*
* segment_directive segment_name { NOHDR ;
* --------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/*
* Set the nohdr flag on the segment. If this segment is the
* first loadable segment, the ELF and program headers will
* not be included.
*
* The HDR_NOALLOC top level directive is preferred. This feature
* exists to give 1:1 feature parity with version 1 mapfiles that
* use the ?N segment flag and expect it to only take effect
* if that segment ends up being first.
*/
/* terminator */
}
/*
* segment_directive segment_name { OS_ORDER eq_op assign_name...
* -----------------------------------------------^
*/
/* ARGSUSED 2 */
static Token
{
int done;
/*
* The '=' form of assignment resets the list. The list contains
* pointers to our mapfile text, so we do not have to free anything.
*/
/*
* One or more section names, terminated by a semicolon.
*/
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
return (TK_ERROR);
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
return (TK_ERROR);
}
}
return (tok);
}
/*
* segment_directive segment_name { PADDR = paddr
* ----------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/*
* Ensure that the segment isn't in the segment order list.
*/
return (TK_ERROR);
}
/* value */
return (TK_ERROR);
/* terminator */
}
/*
* segment_directive segment_name { ROUND = value
* ----------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* value */
return (TK_ERROR);
/* terminator */
}
/*
* segment_directive segment_name { SIZE_SYMBOL = symbol_name
* ----------------------------------------------^
*/
/* ARGSUSED 2 */
static Token
{
/*
* One or more symbol names, terminated by a semicolon.
*/
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
return (TK_ERROR);
cnt++;
/*
* If the operator is TK_EQUAL, turn it into
* TK_PLUSEQ for any symbol names after the first.
* These additional symbols are added, and are not
* replacements for the first one.
*/
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
return (TK_ERROR);
}
}
/* Make sure there was at least one name */
if (cnt == 0) {
return (TK_ERROR);
}
return (tok);
}
/*
* segment_directive segment_name { VADDR = vaddr
* ----------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/*
* Ensure that the segment isn't in the segment order list.
*/
return (TK_ERROR);
}
/* value */
return (TK_ERROR);
/* terminator */
}
/*
* Top Level Directive:
*
* {LOAD|NOTE|NULL}_SEGMENT segment_name { ...
* ------------------------^
*
* Common implementation body for the family of segment directives. These
* take the same syntax, and share a common subset of attributes. They differ
* in the type of segments they handle and the specific attributes accepted.
*
* entry:
* mf - Mapfile descriptor ({LOAD|NOTE|NULL}_SEGMENT)
* dir_name - Name of directive.
* seg_type - Type of segment (PT_LOAD, PT_NOTE, PT_NULL).
* attr_list - NULL terminated attribute array
* attr_list_bufsize - Size of required buffer to format all the
* names in attr_list.
* gts_efunc - Error function to pass to gettoken_str() when trying
* to obtain a segment name token.
*/
static Token
{
/* segment_name */
return (TK_ERROR);
if (new_segment) {
/* Allocate a descriptor for new segment */
FLG_SG_P_TYPE)) == NULL)
return (TK_ERROR);
} else {
/* Make sure it's the right type of segment */
return (TK_ERROR);
}
/* If it was disabled, being referenced enables it */
if (DBG_ENABLED) {
/*
* Not a new segment, so show the initial value
* before modifying it.
*/
}
}
/*
* Attributes are optional, so expect an opening '{', or a ';'.
*/
default:
break;
case TK_SEMICOLON:
break;
case TK_LEFTBKT:
/* Parse the attributes */
return (TK_ERROR);
/* Terminating ';' */
return (TK_ERROR);
break;
}
/*
* If this is a new segment, finish its initialization
* and insert it into the segment list.
*/
if (new_segment) {
return (TK_ERROR);
} else {
/* Not new. Show what's changed */
}
return (tok);
}
/*
* dir_load_segment(): Expected loadable segment name is not present
*/
static void
{
}
/*
* Top Level Directive:
*
* LOAD_SEGMENT segment_name { ...
* ------------^
*/
static Token
{
/* LOAD_SEGMENT attributes */
/* List must be null terminated */
{ 0 }
};
/*
* Size of buffer needed to format the names in attr_list[]. Must
* be kept in sync with attr_list.
*/
}
/*
* Common shared segment directive attributes
*/
/* List must be null terminated */
{ 0 }
};
/*
* Size of buffer needed to format the names in segment_core_attr_list[].
* Must be kept in sync with segment_core_attr_list.
*/
/*
* dir_note_segment(): Expected note segment name is not present
*/
static void
{
}
/*
* Top Level Directive:
*
* NOTE_SEGMENT segment_name { ...
* ------------^
*/
static Token
{
}
/*
* dir_null_segment(): Expected null segment name is not present
*/
static void
{
}
/*
* Top Level Directive:
*
* NULL_SEGMENT segment_name { ...
* ------------^
*/
static Token
{
}
/*
* Top Level Directive:
*
* SEGMENT_ORDER segment_name ... ;
*/
static Token
{
int done;
/* Expect either a '=' or '+=' */
return (TK_ERROR);
/*
* The '=' form of assignment resets the list. The list contains
* pointers to our mapfile text, so we do not have to free anything.
*/
/* Read segment names, and add to list until terminator (';') is seen */
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
/*
* The segment must have already been defined.
*/
return (TK_ERROR);
}
/*
* Make sure it's not already on the list
*/
return (TK_ERROR);
}
/*
* It can't be ordered and also have an explicit
* paddr or vaddr.
*/
return (TK_ERROR);
}
/* Put it at the end of the list */
AL_CNT_SG_IS_ORDER) == NULL)
return (TK_ERROR);
break;
case TK_SEMICOLON:
done = 1;
break;
default:
return (TK_ERROR);
}
}
return (tok);
}
/*
* Top Level Directive:
*
* STACK { ...
* -----^
*/
static Token
{
/* STACK attributes */
/* List must be null terminated */
{ 0 }
};
/*
* Size of buffer needed to format the names in attr_list[]. Must
* be kept in sync with attr_list.
*/
/* Opening '{' token */
return (TK_ERROR);
/* Fetch the PT_SUNWSTACK segment descriptor */
/* Parse the attributes */
return (TK_ERROR);
/* Terminating ';' */
return (TK_ERROR);
if (DBG_ENABLED) {
}
return (tok);
}
/*
* at_sym_aux(): Value for AUXILIARY= is not an object name
*/
static void
{
}
/*
* SYMBOL [version_name] { symbol_name { AUXILIARY = soname
* -------------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* auxiliary filter soname */
return (TK_ERROR);
/* terminator */
}
/*
* at_sym_filter(): Value for FILTER= is not an object name
*/
static void
{
}
/*
* SYMBOL [version_name] { symbol_name { FILTER = soname
* ----------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* filter soname */
return (TK_ERROR);
/* terminator */
}
/*
* SYMBOL [version_name] { symbol_name { FLAGS = ...
* ---------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
typedef struct {
const char *name;
} symflag_t;
/* List must be null terminated */
{ 0 }
};
/*
* Size of buffer needed to format the names in flag_list[]. Must
* be kept in sync with flag_list.
*/
int done;
int cnt = 0;
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
goto bad_flag;
cnt++;
/*
* Apply the flag:
*
* Although tempting to make all of this table-driven
* via added fields in symflag_t, there's enough
* variation in what each flag does to make that
* not quite worthwhile.
*
* Similarly, it is tempting to use common code to
* to do this work from map_support.c. However, the
* v1 code mixes unrelated things (flags, symbol types,
* value, size, etc) in single cascading series of
* strcmps, whereas our parsing separates those things
* from each other. Merging the code would require doing
* two strcmps for each item, or other complexity,
* which I judge not to be worthwhile.
*/
case FLG_SY_DIR:
break;
case FLG_SY_DYNSORT:
break;
case FLG_SY_EXTERN:
break;
case FLG_SY_INTPOSE:
break;
}
break;
case FLG_SY_NDIR:
ofl->ofl_flags1 |=
break;
case FLG_SY_NODYNSORT:
break;
case FLG_SY_PARENT:
break;
}
break;
case TK_RIGHTBKT:
case TK_SEMICOLON:
done = 1;
break;
default:
{
}
return (TK_ERROR);
}
}
/* Make sure there was at least one flag specified */
if (cnt == 0) {
return (TK_ERROR);
}
return (tok); /* Either TK_SEMICOLON or TK_RIGHTBKT */
}
/*
* SYMBOL [version_name] { symbol_name { SIZE = value
* --------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* value */
return (TK_ERROR);
/* terminator */
}
typedef struct {
/* List must be null terminated */
{ 0 }
};
/*
* Size of buffer needed to format the names in at_sym_type_list[]. Must
* be kept in sync with at_sym_type_list.
*/
/*
* at_sym_type(): Value for TYPE= is not a symbol type
*/
static void
{
}
/*
* SYMBOL [version_name] { symbol_name { TYPE = symbol_type
* --------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* type keyword */
return (TK_ERROR);
return (TK_ERROR);
}
/* terminator */
}
/*
* SYMBOL [version_name] { symbol_name { VALUE = value
* ---------------------------------------------^
*/
/* ARGSUSED 1 */
static Token
{
/* value */
return (TK_ERROR);
/* terminator */
}
/*
* Parse the attributes for a SCOPE or VERSION symbol directive.
*
* entry:
* mf - Mapfile descriptor
* dir_name - Name of directive.
* ss - Pointer to symbol state block that has had its ss_nv
* member initialzed via a call to ld_map_sym_ver_init().
*
* exit:
* parse_symbol_attributes() returns TK_RIGHTBKT on success, and TK_ERROR
* on failure.
*/
static Token
{
/* Symbol attributes */
/* List must be null terminated */
{ 0 }
};
/*
* Size of buffer needed to format the names in attr_list[]. Must
* be kept in sync with attr_list.
*/
int done;
/* Read attributes until the closing '}' is seen */
/*
* We have to allow quotes around symbol names, but the
* name we read may also be a symbol scope keyword. We won't
* know which until we read the following token, and so have
* to allow quotes for both. Hence, symbol scope names can
* be quoted --- an unlikely occurrence and not worth
* complicating the code.
*/
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
/* Default value for all symbol attributes is 0 */
/*
* Turn off the WEAK flag to indicate that definitions
* are associated with this version. It would probably
* be more accurate to only remove this flag with the
* specification of global symbols, however setting it
* here allows enough slop to compensate for the
* various user inputs we've seen so far. Only if a
* closed version is specified (i.e., "SUNW_1.x {};")
* will a user get a weak version (which is how we
* document the creation of weak versions).
*/
/*
* The meaning of this name depends on the following
* character:
*
* : Scope
* ; Symbol without attributes
* { Symbol with attributes
*/
case TK_ERROR:
return (TK_ERROR);
case TK_COLON:
break;
case TK_LEFTBKT:
/* name is a symbol with attributes */
return (TK_ERROR);
/* Terminating ';', or '}' */
return (TK_ERROR);
if (tok == TK_RIGHTBKT)
done = 1;
/* FALLTHROUGH */
case TK_SEMICOLON:
/*
* Add the new symbol. It should be noted that
* all symbols added by the mapfile start out
* with global scope, thus they will fall
* through the normal symbol resolution
* process. Symbols defined as locals will
* be reduced in scope after all input file
* processing.
*/
return (TK_ERROR);
break;
default:
return (TK_ERROR);
}
break;
case TK_RIGHTBKT:
done = 1;
break;
case TK_SEMICOLON:
break; /* Ignore empty statement */
case TK_STAR:
/*
* Turn off the WEAK flag, as explained above for
* TK_STRING.
*/
/*
* Following token must be ';' to terminate the stmt,
* or '}' to terminate the whole directive.
*/
case TK_ERROR:
return (TK_ERROR);
case TK_RIGHTBKT:
done = 1;
break;
}
break;
default:
return (TK_ERROR);
}
}
/*
* In the SYMBOL directive, we keep parsing in the face of
* errors that don't involve resources, to maximize what we
* can report in a single invocation. If we encountered such
* an error, act on the error(s) now.
*/
return (TK_ERROR);
return (tok);
}
/*
* Top Level Directive:
*
* SYMBOL_SCOPE { ...
* ------------^
*/
static Token
{
/* The first token must be a '{' */
return (TK_ERROR);
/* Establish the version descriptor and related data */
return (TK_ERROR);
/* Read attributes until the closing '}' is seen */
return (TK_ERROR);
/* Terminating ';' */
}
/*
* at_dv_allow(): Value for ALLOW= is not a version string
*/
static void
{
}
/*
* Top Level Directive:
*
* SYMBOL_VERSION version_name { ...
* --------------^
*/
static Token
{
/* The first token must be a version name */
return (TK_ERROR);
/* The next token is expected to be '{' */
return (TK_ERROR);
/* Establish the version descriptor and related data */
return (TK_ERROR);
/* Read attributes until the closing '}' is seen */
return (TK_ERROR);
/*
* Determine if any version references are provided after the close
* bracket, parsing up to the terminating ';'.
*/
return (TK_ERROR);
return (TK_SEMICOLON);
}
/*
* Parse the mapfile --- Solaris syntax
*/
{
/* Valid top level mapfile directives */
typedef struct {
} tldir_t;
/* List must be null terminated */
{ 0 }
};
/*
* Size of buffer needed to format the names in dirlist[]. Must
* be kept in sync with dirlist.
*/
for (;;) {
switch (tok) {
case TK_ERROR:
return (FALSE);
case TK_EOF:
return (TRUE);
case TK_SEMICOLON: /* Terminator, or empty directive: Ignore */
break;
case TK_STRING:
/* Map name to entry in dirlist[] */
/* Not a directive we know? */
goto bad_dirtok;
/* Call the function associated with this directive */
return (FALSE);
break;
default:
{
}
return (FALSE);
}
}
/*NOTREACHED*/
assert(0);
return (FALSE);
}