#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/elf_amd64.h>
#include <elfcap.h>
#include "msg.h"
#include "_libld.h"
#include "_map.h"
#define ELFCAP_STYLE ELFCAP_STYLE_LC | ELFCAP_STYLE_F_ICMP
typedef Token (*dir_func_t)(Mapfile *mf);
typedef Token (* attr_func_t)(Mapfile *mf, Token eq_tok, void *uvalue);
typedef void (* gts_efunc_t)(Mapfile *mf, Token tok, ld_map_tkval_t *tkv);
typedef enum {
ATTR_FMT_NAME,
ATTR_FMT_EQ,
ATTR_FMT_EQ_PEQ,
ATTR_FMT_EQ_ALL,
} attr_fmt_t;
typedef struct {
const char *at_name;
attr_func_t at_func;
attr_fmt_t at_fmt;
} attr_t;
typedef struct {
ld_map_ver_t ss_mv;
ld_map_sym_t ss_ms;
Ass_desc ss_ma;
} symbol_state_t;
static Token
gettoken_eq(Mapfile *mf, attr_fmt_t eq_type, const char *lhs)
{
Token tok;
ld_map_tkval_t tkv;
const char *err;
Conv_inv_buf_t inv_buf;
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
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:
err = MSG_INTL(MSG_MAP_EXP_EQ);
break;
case ATTR_FMT_EQ_PEQ:
err = MSG_INTL(MSG_MAP_EXP_EQ_PEQ);
break;
case ATTR_FMT_EQ_ALL:
err = MSG_INTL(MSG_MAP_EXP_EQ_ALL);
break;
default:
assert(0);
}
mf_fatal(mf, err, lhs, ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
static void
setflags_eq(Word *dst, Token eq_tok, Word value)
{
switch (eq_tok) {
case TK_EQUAL:
*dst = value;
break;
case TK_PLUSEQ:
*dst |= value;
break;
case TK_MINUSEQ:
*dst &= ~value;
break;
default:
assert(0);
}
}
static Boolean
set_capmask(Mapfile *mf, Capmask *capmask, Token eq_tok,
Word type, elfcap_mask_t value, Boolean title)
{
if (title)
DBG_CALL(Dbg_cap_mapfile_title(mf->mf_ofl->ofl_lml,
mf->mf_lineno));
DBG_CALL(Dbg_cap_val_entry(mf->mf_ofl->ofl_lml, DBG_STATE_CURRENT,
type, capmask->cm_val, ld_targ.t_m.m_mach));
switch (eq_tok) {
case TK_EQUAL:
capmask->cm_val = value;
capmask->cm_exc = 0;
ld_map_cap_set_ovflag(mf, type);
DBG_CALL(Dbg_cap_val_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_RESET, type, capmask->cm_val,
ld_targ.t_m.m_mach));
break;
case TK_PLUSEQ:
DBG_CALL(Dbg_cap_val_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_ADD, type, value, ld_targ.t_m.m_mach));
capmask->cm_val |= value;
capmask->cm_exc &= ~value;
break;
case TK_MINUSEQ:
DBG_CALL(Dbg_cap_val_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_EXCLUDE, type, value, ld_targ.t_m.m_mach));
capmask->cm_val &= ~value;
capmask->cm_exc |= value;
break;
default:
assert(0);
}
if (!ld_map_cap_sanitize(mf, type, capmask))
return (FALSE);
DBG_CALL(Dbg_cap_val_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_RESOLVED, type, capmask->cm_val, ld_targ.t_m.m_mach));
return (TRUE);
}
static Boolean
set_capstr(Mapfile *mf, Caplist *caplist, Token eq_tok,
Word type, APlist *strs)
{
Capstr *capstr;
Aliste idx1;
char *str;
DBG_CALL(Dbg_cap_mapfile_title(mf->mf_ofl->ofl_lml, mf->mf_lineno));
if ((caplist->cl_val == NULL) || (alist_nitems(caplist->cl_val) == 0)) {
DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_CURRENT, type, NULL));
} else {
for (ALIST_TRAVERSE(caplist->cl_val, idx1, capstr)) {
DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_CURRENT, type, capstr->cs_str));
}
}
switch (eq_tok) {
case TK_EQUAL:
if (caplist->cl_val) {
(void) free(caplist->cl_val);
caplist->cl_val = NULL;
}
if (caplist->cl_exc) {
(void) free(caplist->cl_exc);
caplist->cl_exc = NULL;
}
if (strs) {
for (APLIST_TRAVERSE(strs, idx1, str)) {
if ((capstr = alist_append(&caplist->cl_val,
NULL, sizeof (Capstr),
AL_CNT_CAP_NAMES)) == NULL)
return (FALSE);
capstr->cs_str = str;
DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_RESET, type, capstr->cs_str));
}
} else {
DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_RESET, type, NULL));
}
ld_map_cap_set_ovflag(mf, type);
break;
case TK_PLUSEQ:
for (APLIST_TRAVERSE(strs, idx1, str)) {
Aliste idx2;
const char *ostr;
int found = 0;
for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
if (strcmp(str, capstr->cs_str) == 0) {
found++;
break;
}
}
if ((found == 0) && ((capstr =
(Capstr *)alist_append(&caplist->cl_val, NULL,
sizeof (Capstr), AL_CNT_CAP_NAMES)) == NULL))
return (FALSE);
capstr->cs_str = str;
for (APLIST_TRAVERSE(caplist->cl_exc, idx2, ostr)) {
if (strcmp(str, ostr) == 0) {
aplist_delete(caplist->cl_exc, &idx2);
break;
}
}
DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_ADD, type, str));
}
break;
case TK_MINUSEQ:
for (APLIST_TRAVERSE(strs, idx1, str)) {
Aliste idx2;
const char *ostr;
int found = 0;
for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
if (strcmp(str, capstr->cs_str) == 0) {
alist_delete(caplist->cl_val, &idx2);
break;
}
}
for (APLIST_TRAVERSE(caplist->cl_exc, idx2, ostr)) {
if (strcmp(str, ostr) == 0) {
found++;
break;
}
}
if ((found == 0) && (aplist_append(&caplist->cl_exc,
str, AL_CNT_CAP_NAMES) == NULL))
return (FALSE);
DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_EXCLUDE, type, str));
}
break;
default:
assert(0);
}
if ((caplist->cl_val == NULL) || (alist_nitems(caplist->cl_val) == 0)) {
DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_RESOLVED, type, NULL));
} else {
for (ALIST_TRAVERSE(caplist->cl_val, idx1, capstr)) {
DBG_CALL(Dbg_cap_ptr_entry(mf->mf_ofl->ofl_lml,
DBG_STATE_RESOLVED, type, capstr->cs_str));
}
}
return (TRUE);
}
static Token
gettoken_optattr(Mapfile *mf, const char *lhs)
{
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
case TK_SEMICOLON:
case TK_LEFTBKT:
return (tok);
}
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMLBKT), lhs,
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
static Token
gettoken_term(Mapfile *mf, const char *lhs)
{
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
case TK_SEMICOLON:
case TK_RIGHTBKT:
return (tok);
}
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMRBKT), lhs,
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
static Token
gettoken_semicolon(Mapfile *mf, const char *lhs)
{
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
case TK_SEMICOLON:
return (tok);
}
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEM), lhs,
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
static Token
gettoken_leftbkt(Mapfile *mf, const char *lhs)
{
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
case TK_LEFTBKT:
return (tok);
}
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_LBKT), lhs,
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
static Token
gettoken_int(Mapfile *mf, const char *lhs, ld_map_tkval_t *tkv, int flags)
{
Token tok;
Conv_inv_buf_t inv_buf;
char *start = mf->mf_next;
switch (tok = ld_map_gettoken(mf, flags, tkv)) {
case TK_ERROR:
return (tok);
case TK_STRING:
if (strcmp(MSG_ORIG(MSG_MAP_ADDRSIZE), tkv->tkv_str) == 0) {
tkv->tkv_int.tkvi_str = tkv->tkv_str;
switch (ld_targ.t_m.m_class) {
case ELFCLASS32:
tkv->tkv_int.tkvi_value = sizeof (Elf32_Addr);
break;
case ELFCLASS64:
tkv->tkv_int.tkvi_value = sizeof (Elf64_Addr);
break;
case ELFCLASSNONE:
tkv->tkv_int.tkvi_value = 0;
break;
default:
assert(0);
}
tkv->tkv_int.tkvi_cnt = MSG_MAP_ADDRSIZE_SIZE;
tok = TK_INT;
} else {
break;
}
case TK_INT:
if ((flags & TK_F_MULOK) &&
(ld_map_peektoken(mf) == TK_LEFTSQR)) {
ld_map_tkval_t mltplr;
Xword oldval;
(void) ld_map_gettoken(mf, flags, &mltplr);
if (ld_map_gettoken(mf, flags & ~TK_F_MULOK,
&mltplr) != TK_INT) {
tkv->tkv_int.tkvi_cnt = mf->mf_next - start;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_INT),
MSG_ORIG(MSG_QSTR_LEFTSQR),
ld_map_tokenstr(TK_INT, tkv, &inv_buf));
return (TK_ERROR);
}
if (ld_map_peektoken(mf) != TK_RIGHTSQR) {
tkv->tkv_int.tkvi_cnt = mf->mf_next - start;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_RIGHTSQ),
ld_map_tokenstr(TK_INT, tkv, &inv_buf));
return (TK_ERROR);
}
(void) ld_map_gettoken(mf, flags, NULL);
tkv->tkv_int.tkvi_cnt = mf->mf_next - start;
oldval = tkv->tkv_int.tkvi_value;
tkv->tkv_int.tkvi_value *= mltplr.tkv_int.tkvi_value;
if ((tkv->tkv_int.tkvi_value /
mltplr.tkv_int.tkvi_value) != oldval) {
mf_fatal(mf, MSG_INTL(MSG_MAP_MULOVERFLOW),
tkv->tkv_int.tkvi_value,
mltplr.tkv_int.tkvi_value);
return (TK_ERROR);
}
}
return (tok);
}
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_INT), lhs,
ld_map_tokenstr(tok, tkv, &inv_buf));
return (TK_ERROR);
}
static Token
gettoken_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv, gts_efunc_t efunc)
{
Token tok;
switch (tok = ld_map_gettoken(mf, flags, tkv)) {
case TK_ERROR:
case TK_STRING:
return (tok);
}
(* efunc)(mf, tok, tkv);
return (TK_ERROR);
}
static Token
parse_attributes(Mapfile *mf, const char *item_name, attr_t *attr_list,
size_t attr_list_bufsize, void *uvalue)
{
attr_t *attr;
Token tok, op_tok;
ld_map_tkval_t tkv;
int done;
int attr_cnt = 0;
Conv_inv_buf_t inv_buf;
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
attr = ld_map_kwfind(tkv.tkv_str, attr_list,
SGSOFFSETOF(attr_t, at_name), sizeof (attr[0]));
if (attr == NULL)
goto bad_attr;
if (attr->at_fmt == ATTR_FMT_NAME) {
op_tok = TK_ERROR;
} else {
op_tok = gettoken_eq(mf, attr->at_fmt,
attr->at_name);
if (op_tok == TK_ERROR)
return (TK_ERROR);
}
switch (tok = attr->at_func(mf, op_tok, uvalue)) {
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;
default:
bad_attr:
{
char buf[VLA_SIZE(attr_list_bufsize)];
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_ATTR),
ld_map_kwnames(attr_list,
SGSOFFSETOF(attr_t, at_name),
sizeof (attr[0]), buf, attr_list_bufsize),
ld_map_tokenstr(tok, &tkv, &inv_buf));
}
return (TK_ERROR);
}
}
if (attr_cnt == 0) {
mf_fatal(mf, MSG_INTL(MSG_MAP_NOATTR), item_name);
return (TK_ERROR);
}
return (tok);
}
static Token
parse_segment_flags(Mapfile *mf, Xword *flags)
{
#define PF_DATA 0x80000000
#define PF_STACK 0x80000001
typedef struct {
const char *name;
Word value;
} segflag_t;
static segflag_t flag_list[] = {
{ MSG_ORIG(MSG_MAPKW_DATA), PF_DATA },
{ MSG_ORIG(MSG_MAPKW_EXECUTE), PF_X },
{ MSG_ORIG(MSG_MAPKW_READ), PF_R },
{ MSG_ORIG(MSG_MAPKW_STACK), PF_STACK },
{ MSG_ORIG(MSG_MAPKW_WRITE), PF_W },
{ 0 },
};
static size_t flag_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_DATA) +
KW_NAME_SIZE(MSG_MAPKW_EXECUTE) +
KW_NAME_SIZE(MSG_MAPKW_READ) +
KW_NAME_SIZE(MSG_MAPKW_STACK) +
KW_NAME_SIZE(MSG_MAPKW_WRITE);
Token tok;
ld_map_tkval_t tkv;
segflag_t *flag;
size_t cnt = 0;
int done;
Conv_inv_buf_t inv_buf;
*flags = 0;
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
flag = ld_map_kwfind(tkv.tkv_str, flag_list,
SGSOFFSETOF(segflag_t, name),
sizeof (flag_list[0]));
if (flag == NULL)
goto bad_flag;
switch (flag->value) {
case PF_DATA:
*flags |= ld_targ.t_m.m_dataseg_perm;
break;
case PF_STACK:
*flags |= ld_targ.t_m.m_stack_perm;
break;
default:
*flags |= flag->value;
}
cnt++;
break;
case TK_INT:
if (tkv.tkv_int.tkvi_value != 0)
goto bad_flag;
cnt++;
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
bad_flag:
{
char buf[VLA_SIZE(flag_list_bufsize)];
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGFLAG),
ld_map_kwnames(flag_list,
SGSOFFSETOF(segflag_t, name),
sizeof (flag[0]), buf, flag_list_bufsize),
ld_map_tokenstr(tok, &tkv, &inv_buf));
}
return (TK_ERROR);
}
}
if (cnt == 0) {
mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
MSG_ORIG(MSG_MAPKW_FLAGS));
return (TK_ERROR);
}
return (tok);
#undef PF_DATA
#undef PF_STACK
}
static Token
parse_cap_mask(Mapfile *mf, Token eq_tok, Capmask *capmask,
Word type, elfcap_from_str_func_t *elfcap_from_str_func)
{
int done;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
elfcap_mask_t value = 0;
uint64_t v;
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
if ((v = (* elfcap_from_str_func)(ELFCAP_STYLE,
tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
value |= v;
break;
}
goto bad_flag;
case TK_INT:
value |= tkv.tkv_int.tkvi_value;
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
bad_flag:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPMASK),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
}
if (!set_capmask(mf, capmask, eq_tok, type, value, TRUE))
return (TK_ERROR);
return (tok);
}
static Token
parse_cap_list(Mapfile *mf, Token eq_tok, Caplist *caplist,
Word type)
{
int done, found;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
APlist *strs = NULL;
Aliste idx;
const char *str;
for (done = 0, found = 0; done == 0; found = 0) {
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
for (APLIST_TRAVERSE(strs, idx, str)) {
if (strcmp(str, tkv.tkv_str) == 0) {
found++;
break;
}
}
if ((found == 0) && (aplist_append(&strs, tkv.tkv_str,
AL_CNT_CAP_NAMES) == NULL))
return (TK_ERROR);
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPNAME),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
}
if (!set_capstr(mf, caplist, eq_tok, type, strs))
return (TK_ERROR);
return (tok);
}
static Token
at_cap_hw(Mapfile *mf, Token eq_tok, void *uvalue)
{
int done;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
Word hw1 = 0, hw2 = 0, hw3 = 0;
uint64_t v;
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
if ((v = elfcap_hw1_from_str(ELFCAP_STYLE,
tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
hw1 |= v;
break;
}
if ((v = elfcap_hw2_from_str(ELFCAP_STYLE,
tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
hw2 |= v;
break;
}
if ((v = elfcap_hw3_from_str(ELFCAP_STYLE,
tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
hw3 |= v;
break;
}
goto bad_flag;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
bad_flag:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPHW),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
}
if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.oc_hw_1, eq_tok,
CA_SUNW_HW_1, hw1, TRUE))
return (TK_ERROR);
if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.oc_hw_2, eq_tok,
CA_SUNW_HW_2, hw2, FALSE))
return (TK_ERROR);
if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.oc_hw_3, eq_tok,
CA_SUNW_HW_3, hw3, FALSE))
return (TK_ERROR);
return (tok);
}
static Token
at_cap_hw_1(Mapfile *mf, Token eq_tok, void *uvalue)
{
return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_hw_1,
CA_SUNW_HW_1, elfcap_hw1_from_str));
}
static Token
at_cap_hw_2(Mapfile *mf, Token eq_tok, void *uvalue)
{
return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_hw_2,
CA_SUNW_HW_2, elfcap_hw2_from_str));
}
static Token
at_cap_sf(Mapfile *mf, Token eq_tok, void *uvalue)
{
int done;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
Word sf1 = 0;
uint64_t v;
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
if ((v = elfcap_sf1_from_str(ELFCAP_STYLE,
tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
sf1 |= v;
break;
}
goto bad_flag;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
bad_flag:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPSF),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
}
if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.oc_sf_1, eq_tok,
CA_SUNW_SF_1, sf1, TRUE))
return (TK_ERROR);
return (tok);
}
static Token
at_cap_sf_1(Mapfile *mf, Token eq_tok, void *uvalue)
{
return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_sf_1,
CA_SUNW_SF_1, elfcap_sf1_from_str));
}
static Token
at_cap_mach(Mapfile *mf, Token eq_tok, void *uvalue)
{
return (parse_cap_list(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_mach,
CA_SUNW_MACH));
}
static Token
at_cap_plat(Mapfile *mf, Token eq_tok, void *uvalue)
{
return (parse_cap_list(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_plat,
CA_SUNW_PLAT));
}
static Token
at_cap_hw_3(Mapfile *mf, Token eq_tok, void *uvalue)
{
return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.oc_hw_3,
CA_SUNW_HW_3, elfcap_hw3_from_str));
}
static Token
dir_capability(Mapfile *mf)
{
static attr_t attr_list[] = {
{ MSG_ORIG(MSG_MAPKW_HW), at_cap_hw, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_HW_1), at_cap_hw_1, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_HW_2), at_cap_hw_2, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_HW_3), at_cap_hw_3, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_MACHINE), at_cap_mach, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_PLATFORM), at_cap_plat, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_SF), at_cap_sf, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_SF_1), at_cap_sf_1, ATTR_FMT_EQ_ALL },
{ 0 }
};
static size_t attr_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_HW) +
KW_NAME_SIZE(MSG_MAPKW_HW_1) +
KW_NAME_SIZE(MSG_MAPKW_HW_2) +
KW_NAME_SIZE(MSG_MAPKW_HW_3) +
KW_NAME_SIZE(MSG_MAPKW_MACHINE) +
KW_NAME_SIZE(MSG_MAPKW_PLATFORM) +
KW_NAME_SIZE(MSG_MAPKW_SF) +
KW_NAME_SIZE(MSG_MAPKW_SF_1);
Capstr *capstr;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
capstr = &mf->mf_ofl->ofl_ocapset.oc_id;
DBG_CALL(Dbg_cap_id(mf->mf_ofl->ofl_lml, mf->mf_lineno,
capstr->cs_str, tkv.tkv_str));
capstr->cs_str = tkv.tkv_str;
mf->mf_ofl->ofl_ocapset.oc_flags |= FLG_OCS_USRDEFID;
switch (tok = gettoken_optattr(mf, capstr->cs_str)) {
case TK_SEMICOLON:
return (TK_SEMICOLON);
case TK_LEFTBKT:
break;
default:
return (TK_ERROR);
}
break;
case TK_LEFTBKT:
break;
default:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPID),
MSG_ORIG(MSG_MAPKW_CAPABILITY),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_CAPABILITY),
attr_list, attr_list_bufsize, NULL) == TK_ERROR)
return (TK_ERROR);
return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_CAPABILITY)));
}
static void
gts_efunc_at_dv_allow(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
MSG_ORIG(MSG_MAPKW_ALLOW), ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_dv_allow(Mapfile *mf, Token eq_tok, void *uvalue)
{
ld_map_tkval_t tkv;
if (gettoken_str(mf, 0, &tkv, gts_efunc_at_dv_allow) == TK_ERROR)
return (TK_ERROR);
if (!ld_map_dv_entry(mf, uvalue, FALSE, tkv.tkv_str))
return (TK_ERROR);
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ALLOW)));
}
static void
gts_efunc_at_dv_require(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
MSG_ORIG(MSG_MAPKW_REQUIRE), ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_dv_require(Mapfile *mf, Token eq_tok, void *uvalue)
{
ld_map_tkval_t tkv;
if (gettoken_str(mf, 0, &tkv, gts_efunc_at_dv_require) == TK_ERROR)
return (TK_ERROR);
if (!ld_map_dv_entry(mf, uvalue, TRUE, tkv.tkv_str))
return (TK_ERROR);
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_REQUIRE)));
}
static void
gts_efunc_dir_depend_versions(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
dir_depend_versions(Mapfile *mf)
{
static attr_t attr_list[] = {
{ MSG_ORIG(MSG_MAPKW_ALLOW), at_dv_allow, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_REQUIRE), at_dv_require, ATTR_FMT_EQ },
{ 0 }
};
static size_t attr_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_ALLOW) +
KW_NAME_SIZE(MSG_MAPKW_REQUIRE);
ld_map_tkval_t tkv;
Sdf_desc *sdf;
if (gettoken_str(mf, 0, &tkv, gts_efunc_dir_depend_versions) ==
TK_ERROR)
return (TK_ERROR);
if ((sdf = ld_map_dv(mf, tkv.tkv_str)) == NULL)
return (TK_ERROR);
if (gettoken_leftbkt(mf, tkv.tkv_str) == TK_ERROR)
return (TK_ERROR);
if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS),
attr_list, attr_list_bufsize, sdf) == TK_ERROR)
return (TK_ERROR);
return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS)));
}
static Token
dir_hdr_noalloc(Mapfile *mf)
{
mf->mf_ofl->ofl_dtflags_1 |= DF_1_NOHDR;
DBG_CALL(Dbg_map_hdr_noalloc(mf->mf_ofl->ofl_lml, mf->mf_lineno));
return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_HDR_NOALLOC)));
}
static Token
dir_phdr_add_null(Mapfile *mf)
{
Sg_desc *sgp;
ld_map_tkval_t tkv;
if (gettoken_eq(mf, ATTR_FMT_EQ,
MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL)) == TK_ERROR)
return (TK_ERROR);
if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL), &tkv, 0) ==
TK_ERROR)
return (TK_ERROR);
while (tkv.tkv_int.tkvi_value-- > 0) {
if ((sgp = ld_map_seg_alloc(NULL, PT_NULL,
FLG_SG_P_TYPE | FLG_SG_EMPTY)) == NULL)
return (TK_ERROR);
if (ld_map_seg_insert(mf, DBG_STATE_NEW, sgp, 0) ==
SEG_INS_FAIL)
return (TK_ERROR);
}
return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL)));
}
static Token
at_seg_align(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue;
ld_map_tkval_t tkv;
if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_ALIGN), &tkv, 0) == TK_ERROR)
return (TK_ERROR);
sgp->sg_phdr.p_align = tkv.tkv_int.tkvi_value;
sgp->sg_flags |= FLG_SG_P_ALIGN;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ALIGN)));
}
static void
gts_efunc_at_seg_assign_file_basename(Mapfile *mf, Token tok,
ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_FILNAM),
MSG_ORIG(MSG_MAPKW_FILE_BASENAME),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_seg_assign_file_basename(Mapfile *mf, Token eq_tok, void *uvalue)
{
Ent_desc *enp = uvalue;
ld_map_tkval_t tkv;
if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_basename) ==
TK_ERROR)
return (TK_ERROR);
if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_BASENAME, tkv.tkv_str))
return (TK_ERROR);
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_BASENAME)));
}
static void
gts_efunc_at_seg_assign_file_objname(Mapfile *mf, Token tok,
ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
MSG_ORIG(MSG_MAPKW_FILE_OBJNAME),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_seg_assign_file_objname(Mapfile *mf, Token eq_tok, void *uvalue)
{
Ent_desc *enp = uvalue;
ld_map_tkval_t tkv;
if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_objname) ==
TK_ERROR)
return (TK_ERROR);
if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_OBJNAME, tkv.tkv_str))
return (TK_ERROR);
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_OBJNAME)));
}
static void
gts_efunc_at_seg_assign_file_path(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_FILPATH),
MSG_ORIG(MSG_MAPKW_FILE_PATH),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_seg_assign_file_path(Mapfile *mf, Token eq_tok, void *uvalue)
{
Ent_desc *enp = uvalue;
ld_map_tkval_t tkv;
if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_path) ==
TK_ERROR)
return (TK_ERROR);
if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_PATH, tkv.tkv_str))
return (TK_ERROR);
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_PATH)));
}
static Token
at_seg_assign_flags(Mapfile *mf, Token eq_tok, void *uvalue)
{
typedef struct {
const char *name;
Word value;
} secflag_t;
static secflag_t flag_list[] = {
{ MSG_ORIG(MSG_MAPKW_ALLOC), SHF_ALLOC },
{ MSG_ORIG(MSG_MAPKW_EXECUTE), SHF_EXECINSTR },
{ MSG_ORIG(MSG_MAPKW_WRITE), SHF_WRITE },
{ MSG_ORIG(MSG_MAPKW_AMD64_LARGE), SHF_AMD64_LARGE },
{ 0 },
};
static size_t flag_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_ALLOC) +
KW_NAME_SIZE(MSG_MAPKW_EXECUTE) +
KW_NAME_SIZE(MSG_MAPKW_WRITE) +
KW_NAME_SIZE(MSG_MAPKW_AMD64_LARGE);
Ent_desc *enp = uvalue;
int bcnt = 0, cnt = 0;
secflag_t *flag;
int done;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_BANG:
if (bcnt != 0) {
mf_fatal0(mf, MSG_INTL(MSG_MAP_SFLG_ONEBANG));
return (TK_ERROR);
}
bcnt++;
break;
case TK_STRING:
flag = ld_map_kwfind(tkv.tkv_str, flag_list,
SGSOFFSETOF(secflag_t, name), sizeof (flag[0]));
if (flag == NULL)
goto bad_flag;
cnt++;
enp->ec_attrmask |= flag->value;
if (bcnt == 0)
enp->ec_attrbits |= flag->value;
bcnt = 0;
break;
case TK_RIGHTBKT:
case TK_SEMICOLON:
done = 1;
break;
default:
bad_flag:
{
char buf[VLA_SIZE(flag_list_bufsize)];
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECFLAG),
ld_map_kwnames(flag_list,
SGSOFFSETOF(secflag_t, name),
sizeof (flag[0]), buf, flag_list_bufsize),
ld_map_tokenstr(tok, &tkv, &inv_buf));
}
return (TK_ERROR);
}
}
if (bcnt != 0) {
mf_fatal0(mf, MSG_INTL(MSG_MAP_SFLG_EXBANG));
return (TK_ERROR);
}
if (cnt == 0) {
mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
MSG_ORIG(MSG_MAPKW_FLAGS));
return (TK_ERROR);
}
return (tok);
}
static void
gts_efunc_at_seg_assign_is_name(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECNAM),
MSG_ORIG(MSG_MAPKW_IS_NAME), ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_seg_assign_is_name(Mapfile *mf, Token eq_tok, void *uvalue)
{
Ent_desc *enp = uvalue;
ld_map_tkval_t tkv;
if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_is_name) ==
TK_ERROR)
return (TK_ERROR);
enp->ec_is_name = tkv.tkv_str;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_IS_NAME)));
}
static void
gts_efunc_at_seg_assign_type(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SHTYPE),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_seg_assign_type(Mapfile *mf, Token eq_tok, void *uvalue)
{
Ent_desc *enp = uvalue;
ld_map_tkval_t tkv;
conv_strtol_uvalue_t conv_uvalue;
if (gettoken_str(mf, TK_F_KEYWORD, &tkv,
gts_efunc_at_seg_assign_type) == TK_ERROR)
return (TK_ERROR);
if (conv_iter_strtol_init(tkv.tkv_str, &conv_uvalue) != 0) {
conv_iter_ret_t status;
status = conv_iter_sec_type(CONV_OSABI_ALL, CONV_MACH_ALL,
CONV_FMT_ALT_CF, conv_iter_strtol, &conv_uvalue);
if (status != CONV_ITER_DONE)
(void) conv_iter_sec_type(CONV_OSABI_ALL,
CONV_MACH_ALL, CONV_FMT_ALT_NF, conv_iter_strtol,
&conv_uvalue);
if (!conv_uvalue.csl_found) {
gts_efunc_at_seg_assign_type(mf, TK_STRING, &tkv);
return (TK_ERROR);
}
}
enp->ec_type = conv_uvalue.csl_value;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_TYPE)));
}
static Token
at_seg_assign(Mapfile *mf, Token eq_tok, void *uvalue)
{
static attr_t attr_list[] = {
{ MSG_ORIG(MSG_MAPKW_FILE_BASENAME),
at_seg_assign_file_basename, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_FILE_OBJNAME),
at_seg_assign_file_objname, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_FILE_PATH),
at_seg_assign_file_path, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_FLAGS),
at_seg_assign_flags, ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_IS_NAME),
at_seg_assign_is_name, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_TYPE),
at_seg_assign_type, ATTR_FMT_EQ },
{ 0 }
};
static size_t attr_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_FILE_BASENAME) +
KW_NAME_SIZE(MSG_MAPKW_FILE_PATH) +
KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
KW_NAME_SIZE(MSG_MAPKW_FILE_OBJNAME) +
KW_NAME_SIZE(MSG_MAPKW_IS_NAME) +
KW_NAME_SIZE(MSG_MAPKW_TYPE);
Sg_desc *sgp = uvalue;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
const char *name = NULL;
Ent_desc *enp;
tok = ld_map_gettoken(mf, 0, &tkv);
switch (tok) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
name = tkv.tkv_str;
tok = ld_map_gettoken(mf, 0, &tkv);
break;
}
if ((enp = ld_map_seg_ent_add(mf, sgp, name)) == NULL)
return (TK_ERROR);
switch (tok) {
default:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMLBKT),
MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
case TK_ERROR:
return (TK_ERROR);
case TK_SEMICOLON:
case TK_RIGHTBKT:
enp->ec_flags |= FLG_EC_CATCHALL;
break;
case TK_LEFTBKT:
if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
attr_list, attr_list_bufsize, enp) == TK_ERROR)
return (TK_ERROR);
tok = gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION));
if (tok == TK_ERROR)
return (TK_ERROR);
break;
}
DBG_CALL(Dbg_map_ent(mf->mf_ofl->ofl_lml, enp, mf->mf_ofl,
mf->mf_lineno));
return (tok);
}
static Token
at_seg_disable(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue;
if (sgp->sg_flags & FLG_SG_NODISABLE) {
mf_fatal(mf, MSG_INTL(MSG_MAP_CNTDISSEG), sgp->sg_name);
return (TK_ERROR);
}
sgp->sg_flags |= FLG_SG_DISABLED;
return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_DISABLE)));
}
static Token
at_seg_flags(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue;
Token tok;
Xword flags;
tok = parse_segment_flags(mf, &flags);
if (tok == TK_ERROR)
return (TK_ERROR);
setflags_eq(&sgp->sg_phdr.p_flags, eq_tok, flags);
sgp->sg_flags |= FLG_SG_P_FLAGS;
return (tok);
}
static Token
at_seg_is_order(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
int done;
Aliste idx;
Ent_desc *enp, *enp2;
if (eq_tok == TK_EQUAL)
aplist_reset(sgp->sg_is_order);
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
enp = ld_ent_lookup(mf->mf_ofl, tkv.tkv_str, NULL);
if (enp == NULL) {
mf_fatal(mf, MSG_INTL(MSG_MAP_UNKENT),
tkv.tkv_str);
return (TK_ERROR);
}
for (APLIST_TRAVERSE(sgp->sg_is_order, idx, enp2))
if (enp == enp2) {
mf_fatal(mf,
MSG_INTL(MSG_MAP_DUP_IS_ORD),
tkv.tkv_str);
return (TK_ERROR);
}
if (aplist_append(&sgp->sg_is_order, enp,
AL_CNT_SG_IS_ORDER) == NULL)
return (TK_ERROR);
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_ECNAM),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
}
return (tok);
}
static Token
at_seg_max_size(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue;
ld_map_tkval_t tkv;
if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_MAX_SIZE), &tkv, 0) == TK_ERROR)
return (TK_ERROR);
sgp->sg_length = tkv.tkv_int.tkvi_value;
sgp->sg_flags |= FLG_SG_LENGTH;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_MAX_SIZE)));
}
static Token
at_seg_nohdr(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue;
sgp->sg_flags |= FLG_SG_NOHDR;
return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_NOHDR)));
}
static Token
at_seg_os_order(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
int done;
if (eq_tok == TK_EQUAL)
alist_reset(sgp->sg_os_order);
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
if (!ld_map_seg_os_order_add(mf, sgp, tkv.tkv_str))
return (TK_ERROR);
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECNAM),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
}
return (tok);
}
static Token
at_seg_paddr(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue, *sgp2;
Aliste idx;
ld_map_tkval_t tkv;
for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order, idx, sgp2))
if (sgp == sgp2) {
mf_fatal(mf,
MSG_INTL(MSG_MAP_CNTADDRORDER), sgp->sg_name);
return (TK_ERROR);
}
if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_PADDR), &tkv, 0) == TK_ERROR)
return (TK_ERROR);
sgp->sg_phdr.p_paddr = tkv.tkv_int.tkvi_value;
sgp->sg_flags |= FLG_SG_P_PADDR;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_PADDR)));
}
static Token
at_seg_round(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue;
ld_map_tkval_t tkv;
if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_ROUND), &tkv, 0) == TK_ERROR)
return (TK_ERROR);
sgp->sg_round = tkv.tkv_int.tkvi_value;
sgp->sg_flags |= FLG_SG_ROUND;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ROUND)));
}
static Token
at_seg_size_symbol(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
int done, cnt = 0;
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
if (!ld_map_seg_size_symbol(mf, sgp, eq_tok,
tkv.tkv_str))
return (TK_ERROR);
cnt++;
eq_tok = TK_PLUSEQ;
break;
case TK_SEMICOLON:
case TK_RIGHTBKT:
done = 1;
break;
default:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMNAM),
MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
}
if (cnt == 0) {
mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL));
return (TK_ERROR);
}
return (tok);
}
static Token
at_seg_vaddr(Mapfile *mf, Token eq_tok, void *uvalue)
{
Sg_desc *sgp = uvalue, *sgp2;
Aliste idx;
ld_map_tkval_t tkv;
for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order, idx, sgp2))
if (sgp == sgp2) {
mf_fatal(mf,
MSG_INTL(MSG_MAP_CNTADDRORDER), sgp->sg_name);
return (TK_ERROR);
}
if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_VADDR), &tkv, 0) == TK_ERROR)
return (TK_ERROR);
sgp->sg_phdr.p_vaddr = tkv.tkv_int.tkvi_value;
sgp->sg_flags |= FLG_SG_P_VADDR;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_VADDR)));
}
static Token
dir_segment_inner(Mapfile *mf, const char *dir_name, Word seg_type,
attr_t *attr_list, size_t attr_list_bufsize, gts_efunc_t gts_efunc)
{
Token tok;
ld_map_tkval_t tkv;
Sg_desc *sgp;
Boolean new_segment;
Xword ndx;
avl_index_t where;
if (gettoken_str(mf, 0, &tkv, gts_efunc) == TK_ERROR)
return (TK_ERROR);
sgp = ld_seg_lookup(mf->mf_ofl, tkv.tkv_str, &where);
new_segment = (sgp == NULL);
if (new_segment) {
if ((sgp = ld_map_seg_alloc(tkv.tkv_str, seg_type,
FLG_SG_P_TYPE)) == NULL)
return (TK_ERROR);
} else {
if (sgp->sg_phdr.p_type != seg_type) {
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXPSEGTYPE),
conv_phdr_type(ELFOSABI_SOLARIS, ld_targ.t_m.m_mach,
sgp->sg_phdr.p_type, CONV_FMT_ALT_CF, &inv_buf),
dir_name, tkv.tkv_str);
return (TK_ERROR);
}
sgp->sg_flags &= ~FLG_SG_DISABLED;
if (DBG_ENABLED) {
ndx = ld_map_seg_index(mf, sgp);
DBG_CALL(Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_BEFORE,
ndx, sgp, mf->mf_lineno));
}
}
switch (tok = gettoken_optattr(mf, dir_name)) {
default:
tok = TK_ERROR;
break;
case TK_SEMICOLON:
break;
case TK_LEFTBKT:
if (parse_attributes(mf, dir_name,
attr_list, attr_list_bufsize, sgp) == TK_ERROR)
return (TK_ERROR);
tok = gettoken_semicolon(mf, dir_name);
if (tok == TK_ERROR)
return (TK_ERROR);
break;
}
if (new_segment) {
if (ld_map_seg_insert(mf, DBG_STATE_NEW, sgp, where) ==
SEG_INS_FAIL)
return (TK_ERROR);
} else {
DBG_CALL(Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_AFTER,
ndx, sgp, mf->mf_lineno));
}
return (tok);
}
static void
gts_efunc_dir_load_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
dir_load_segment(Mapfile *mf)
{
static attr_t attr_list[] = {
{ MSG_ORIG(MSG_MAPKW_ALIGN), at_seg_align, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
at_seg_assign, ATTR_FMT_NAME },
{ MSG_ORIG(MSG_MAPKW_DISABLE), at_seg_disable, ATTR_FMT_NAME },
{ MSG_ORIG(MSG_MAPKW_FLAGS), at_seg_flags,
ATTR_FMT_EQ_ALL },
{ MSG_ORIG(MSG_MAPKW_IS_ORDER), at_seg_is_order,
ATTR_FMT_EQ_PEQ },
{ MSG_ORIG(MSG_MAPKW_MAX_SIZE), at_seg_max_size, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_NOHDR), at_seg_nohdr, ATTR_FMT_NAME },
{ MSG_ORIG(MSG_MAPKW_OS_ORDER), at_seg_os_order,
ATTR_FMT_EQ_PEQ },
{ MSG_ORIG(MSG_MAPKW_PADDR), at_seg_paddr, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_ROUND), at_seg_round, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL),
at_seg_size_symbol, ATTR_FMT_EQ_PEQ },
{ MSG_ORIG(MSG_MAPKW_VADDR), at_seg_vaddr, ATTR_FMT_EQ },
{ 0 }
};
static size_t attr_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_ALIGN) +
KW_NAME_SIZE(MSG_MAPKW_ASSIGN_SECTION) +
KW_NAME_SIZE(MSG_MAPKW_DISABLE) +
KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
KW_NAME_SIZE(MSG_MAPKW_IS_ORDER) +
KW_NAME_SIZE(MSG_MAPKW_MAX_SIZE) +
KW_NAME_SIZE(MSG_MAPKW_PADDR) +
KW_NAME_SIZE(MSG_MAPKW_ROUND) +
KW_NAME_SIZE(MSG_MAPKW_OS_ORDER) +
KW_NAME_SIZE(MSG_MAPKW_SIZE_SYMBOL) +
KW_NAME_SIZE(MSG_MAPKW_VADDR);
return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT),
PT_LOAD, attr_list, attr_list_bufsize, gts_efunc_dir_load_segment));
}
static attr_t segment_core_attr_list[] = {
{ MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION), at_seg_assign, ATTR_FMT_NAME },
{ MSG_ORIG(MSG_MAPKW_DISABLE), at_seg_disable, ATTR_FMT_NAME },
{ MSG_ORIG(MSG_MAPKW_IS_ORDER), at_seg_is_order, ATTR_FMT_EQ_PEQ },
{ MSG_ORIG(MSG_MAPKW_OS_ORDER), at_seg_os_order, ATTR_FMT_EQ_PEQ },
{ 0 }
};
static size_t segment_core_attr_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_ASSIGN_SECTION) +
KW_NAME_SIZE(MSG_MAPKW_DISABLE) +
KW_NAME_SIZE(MSG_MAPKW_IS_ORDER) +
KW_NAME_SIZE(MSG_MAPKW_OS_ORDER);
static void
gts_efunc_dir_note_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
dir_note_segment(Mapfile *mf)
{
return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT),
PT_NOTE, segment_core_attr_list, segment_core_attr_list_bufsize,
gts_efunc_dir_note_segment));
}
static void
gts_efunc_dir_null_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
MSG_ORIG(MSG_MAPKW_NULL_SEGMENT),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
dir_null_segment(Mapfile *mf)
{
return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_NULL_SEGMENT),
PT_NULL, segment_core_attr_list, segment_core_attr_list_bufsize,
gts_efunc_dir_null_segment));
}
static Token
dir_segment_order(Mapfile *mf)
{
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
Aliste idx;
Sg_desc *sgp, *sgp2;
int done;
tok = gettoken_eq(mf, ATTR_FMT_EQ_PEQ,
MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER));
if (tok == TK_ERROR)
return (TK_ERROR);
DBG_CALL(Dbg_map_seg_order(mf->mf_ofl, ELFOSABI_SOLARIS,
ld_targ.t_m.m_mach, DBG_STATE_MOD_BEFORE, mf->mf_lineno));
if (tok == TK_EQUAL)
aplist_reset(mf->mf_ofl->ofl_segs_order);
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
sgp = ld_seg_lookup(mf->mf_ofl, tkv.tkv_str, NULL);
if (sgp == NULL) {
mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSEG),
tkv.tkv_str);
return (TK_ERROR);
}
for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order,
idx, sgp2))
if (sgp == sgp2) {
mf_fatal(mf,
MSG_INTL(MSG_MAP_DUPORDSEG),
MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER),
tkv.tkv_str);
return (TK_ERROR);
}
if (sgp->sg_flags & (FLG_SG_P_PADDR | FLG_SG_P_VADDR)) {
mf_fatal(mf, MSG_INTL(MSG_MAP_CNTADDRORDER),
sgp->sg_name);
return (TK_ERROR);
}
if (aplist_append(&mf->mf_ofl->ofl_segs_order, sgp,
AL_CNT_SG_IS_ORDER) == NULL)
return (TK_ERROR);
break;
case TK_SEMICOLON:
done = 1;
break;
default:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
}
DBG_CALL(Dbg_map_seg_order(mf->mf_ofl, ELFOSABI_SOLARIS,
ld_targ.t_m.m_mach, DBG_STATE_MOD_AFTER, mf->mf_lineno));
return (tok);
}
static Token
dir_stack(Mapfile *mf)
{
static attr_t attr_list[] = {
{ MSG_ORIG(MSG_MAPKW_FLAGS), at_seg_flags, ATTR_FMT_EQ_ALL },
{ 0 }
};
static size_t attr_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_FLAGS);
Sg_desc *sgp;
Token tok;
if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_STACK)) == TK_ERROR)
return (TK_ERROR);
sgp = ld_map_seg_stack(mf);
if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_STACK),
attr_list, attr_list_bufsize, sgp) == TK_ERROR)
return (TK_ERROR);
tok = gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_STACK));
if (tok == TK_ERROR)
return (TK_ERROR);
if (DBG_ENABLED) {
Xword ndx = ld_map_seg_index(mf, sgp);
Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_AFTER, ndx, sgp,
mf->mf_lineno);
}
return (tok);
}
static void
gts_efunc_at_sym_aux(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
MSG_ORIG(MSG_MAPKW_AUX), ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_sym_aux(Mapfile *mf, Token eq_tok, void *uvalue)
{
symbol_state_t *ss = uvalue;
ld_map_tkval_t tkv;
if (gettoken_str(mf, 0, &tkv, gts_efunc_at_sym_aux) == TK_ERROR)
return (TK_ERROR);
ld_map_sym_filtee(mf, &ss->ss_mv, &ss->ss_ms, FLG_SY_AUXFLTR,
tkv.tkv_str);
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_AUX)));
}
static void
gts_efunc_at_sym_filter(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
MSG_ORIG(MSG_MAPKW_FILTER), ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_sym_filter(Mapfile *mf, Token eq_tok, void *uvalue)
{
symbol_state_t *ss = uvalue;
ld_map_tkval_t tkv;
if (gettoken_str(mf, 0, &tkv, gts_efunc_at_sym_filter) == TK_ERROR)
return (TK_ERROR);
ld_map_sym_filtee(mf, &ss->ss_mv, &ss->ss_ms, FLG_SY_STDFLTR,
tkv.tkv_str);
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILTER)));
}
static Token
at_sym_flags(Mapfile *mf, Token eq_tok, void *uvalue)
{
typedef struct {
const char *name;
sd_flag_t value;
} symflag_t;
static symflag_t symflag_list[] = {
{ MSG_ORIG(MSG_MAPKW_DIRECT), FLG_SY_DIR },
{ MSG_ORIG(MSG_MAPKW_DYNSORT), FLG_SY_DYNSORT },
{ MSG_ORIG(MSG_MAPKW_EXTERN), FLG_SY_EXTERN },
{ MSG_ORIG(MSG_MAPKW_INTERPOSE), FLG_SY_INTPOSE },
{ MSG_ORIG(MSG_MAPKW_NODIRECT), FLG_SY_NDIR },
{ MSG_ORIG(MSG_MAPKW_NODYNSORT), FLG_SY_NODYNSORT },
{ MSG_ORIG(MSG_MAPKW_PARENT), FLG_SY_PARENT },
{ 0 }
};
static size_t symflag_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_DIRECT) +
KW_NAME_SIZE(MSG_MAPKW_DYNSORT) +
KW_NAME_SIZE(MSG_MAPKW_EXTERN) +
KW_NAME_SIZE(MSG_MAPKW_INTERPOSE) +
KW_NAME_SIZE(MSG_MAPKW_NODIRECT) +
KW_NAME_SIZE(MSG_MAPKW_NODYNSORT) +
KW_NAME_SIZE(MSG_MAPKW_PARENT);
symbol_state_t *ss = uvalue;
int done;
symflag_t *symflag;
int cnt = 0;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
Ofl_desc *ofl = mf->mf_ofl;
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
symflag = ld_map_kwfind(tkv.tkv_str, symflag_list,
SGSOFFSETOF(symflag_t, name), sizeof (symflag[0]));
if (symflag == NULL)
goto bad_flag;
cnt++;
switch (symflag->value) {
case FLG_SY_DIR:
ss->ss_ms.ms_sdflags |= FLG_SY_DIR;
ofl->ofl_flags |= FLG_OF_SYMINFO;
break;
case FLG_SY_DYNSORT:
ss->ss_ms.ms_sdflags |= FLG_SY_DYNSORT;
ss->ss_ms.ms_sdflags &= ~FLG_SY_NODYNSORT;
break;
case FLG_SY_EXTERN:
ss->ss_ms.ms_sdflags |= FLG_SY_EXTERN;
ofl->ofl_flags |= FLG_OF_SYMINFO;
break;
case FLG_SY_INTPOSE:
if (!(ofl->ofl_flags & FLG_OF_EXEC)) {
mf_fatal0(mf,
MSG_INTL(MSG_MAP_NOINTPOSE));
ss->ss_mv.mv_errcnt++;
break;
}
ss->ss_ms.ms_sdflags |= FLG_SY_INTPOSE;
ofl->ofl_flags |= FLG_OF_SYMINFO;
ofl->ofl_dtflags_1 |= DF_1_SYMINTPOSE;
break;
case FLG_SY_NDIR:
ss->ss_ms.ms_sdflags |= FLG_SY_NDIR;
ofl->ofl_flags |= FLG_OF_SYMINFO;
ofl->ofl_flags1 |=
(FLG_OF1_NDIRECT | FLG_OF1_NGLBDIR);
break;
case FLG_SY_NODYNSORT:
ss->ss_ms.ms_sdflags &= ~FLG_SY_DYNSORT;
ss->ss_ms.ms_sdflags |= FLG_SY_NODYNSORT;
break;
case FLG_SY_PARENT:
ss->ss_ms.ms_sdflags |= FLG_SY_PARENT;
ofl->ofl_flags |= FLG_OF_SYMINFO;
break;
}
break;
case TK_RIGHTBKT:
case TK_SEMICOLON:
done = 1;
break;
default:
bad_flag:
{
char buf[VLA_SIZE(symflag_list_bufsize)];
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMFLAG),
ld_map_kwnames(symflag_list,
SGSOFFSETOF(symflag_t, name),
sizeof (symflag[0]), buf,
symflag_list_bufsize),
ld_map_tokenstr(tok, &tkv, &inv_buf));
}
return (TK_ERROR);
}
}
if (cnt == 0) {
mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
MSG_ORIG(MSG_MAPKW_FLAGS));
return (TK_ERROR);
}
return (tok);
}
static Token
at_sym_size(Mapfile *mf, Token eq_tok, void *uvalue)
{
symbol_state_t *ss = uvalue;
ld_map_tkval_t tkv;
if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_SIZE), &tkv,
TK_F_MULOK) == TK_ERROR)
return (TK_ERROR);
ss->ss_ms.ms_size = tkv.tkv_int.tkvi_value;
ss->ss_ms.ms_size_set = TRUE;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_SIZE)));
}
typedef struct {
const char *name;
Word ms_shndx;
uchar_t ms_type;
} at_sym_type_t;
static at_sym_type_t at_sym_type_list[] = {
{ MSG_ORIG(MSG_MAPKW_COMMON), SHN_COMMON, STT_OBJECT },
{ MSG_ORIG(MSG_MAPKW_DATA), SHN_ABS, STT_OBJECT },
{ MSG_ORIG(MSG_MAPKW_FUNCTION), SHN_ABS, STT_FUNC },
{ 0 }
};
static size_t at_sym_type_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_COMMON) +
KW_NAME_SIZE(MSG_MAPKW_DATA) +
KW_NAME_SIZE(MSG_MAPKW_FUNCTION);
static void
gts_efunc_at_sym_type(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
char buf[VLA_SIZE(at_sym_type_list_bufsize)];
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMTYPE),
ld_map_kwnames(at_sym_type_list, SGSOFFSETOF(at_sym_type_t, name),
sizeof (at_sym_type_list[0]), buf, at_sym_type_list_bufsize),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_sym_type(Mapfile *mf, Token eq_tok, void *uvalue)
{
symbol_state_t *ss = uvalue;
at_sym_type_t *type;
ld_map_tkval_t tkv;
if (gettoken_str(mf, TK_F_KEYWORD, &tkv, gts_efunc_at_sym_type) ==
TK_ERROR)
return (TK_ERROR);
type = ld_map_kwfind(tkv.tkv_str, at_sym_type_list,
SGSOFFSETOF(at_sym_type_t, name), sizeof (type[0]));
if (type == NULL) {
gts_efunc_at_sym_type(mf, TK_STRING, &tkv);
return (TK_ERROR);
}
ss->ss_ms.ms_shndx = type->ms_shndx;
ss->ss_ms.ms_sdflags |= FLG_SY_SPECSEC;
ss->ss_ms.ms_type = type->ms_type;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_TYPE)));
}
static Token
at_sym_value(Mapfile *mf, Token eq_tok, void *uvalue)
{
symbol_state_t *ss = uvalue;
ld_map_tkval_t tkv;
if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_VALUE), &tkv, 0) == TK_ERROR)
return (TK_ERROR);
ss->ss_ms.ms_value = tkv.tkv_int.tkvi_value;
ss->ss_ms.ms_value_set = TRUE;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_VALUE)));
}
typedef struct {
const char *name;
uchar_t ms_type;
} at_ass_type_t;
static at_ass_type_t at_ass_type_list[] = {
{ MSG_ORIG(MSG_MAPKW_DATA), STT_OBJECT },
{ MSG_ORIG(MSG_MAPKW_OBJECT), STT_OBJECT },
{ MSG_ORIG(MSG_MAPKW_FUNC), STT_FUNC },
{ MSG_ORIG(MSG_MAPKW_FUNCTION), STT_FUNC },
{ MSG_ORIG(MSG_MAPKW_SECTION), STT_SECTION },
{ MSG_ORIG(MSG_MAPKW_FILE), STT_FILE },
{ MSG_ORIG(MSG_MAPKW_COMMON), STT_COMMON },
{ MSG_ORIG(MSG_MAPKW_TLS), STT_TLS },
{ 0 }
};
static size_t at_ass_type_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_OBJECT) +
KW_NAME_SIZE(MSG_MAPKW_FUNC) +
KW_NAME_SIZE(MSG_MAPKW_FUNCTION) +
KW_NAME_SIZE(MSG_MAPKW_SECTION) +
KW_NAME_SIZE(MSG_MAPKW_FILE) +
KW_NAME_SIZE(MSG_MAPKW_COMMON) +
KW_NAME_SIZE(MSG_MAPKW_TLS);
static void
gts_efunc_at_ass_type(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
char buf[VLA_SIZE(at_ass_type_list_bufsize)];
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMTYPE),
ld_map_kwnames(at_ass_type_list, SGSOFFSETOF(at_ass_type_t, name),
sizeof (at_ass_type_list[0]), buf, at_ass_type_list_bufsize),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
typedef struct {
const char *name;
Boolean ms_bits;
} at_ass_shattr_t;
static at_ass_shattr_t at_ass_shattr_list[] = {
{ MSG_ORIG(MSG_MAPKW_BITS), TRUE },
{ MSG_ORIG(MSG_MAPKW_NOBITS), FALSE },
{ 0 }
};
static size_t at_ass_shattr_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_BITS) +
KW_NAME_SIZE(MSG_MAPKW_NOBITS);
static void
gts_efunc_at_ass_shattr(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
char buf[VLA_SIZE(at_ass_shattr_list_bufsize)];
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SHATTRTYPE),
ld_map_kwnames(at_ass_shattr_list,
SGSOFFSETOF(at_ass_shattr_t, name), sizeof (at_ass_shattr_list[0]),
buf, at_ass_shattr_list_bufsize),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_ass_shattr(Mapfile *mf, Token eq_tok, void *uvalue)
{
symbol_state_t *ss = uvalue;
at_ass_shattr_t *shattr;
ld_map_tkval_t tkv;
if (gettoken_str(mf, TK_F_KEYWORD, &tkv,
gts_efunc_at_ass_shattr) == TK_ERROR)
return (TK_ERROR);
shattr = ld_map_kwfind(tkv.tkv_str, at_ass_shattr_list,
SGSOFFSETOF(at_ass_shattr_t, name), sizeof (shattr[0]));
if (shattr == NULL) {
gts_efunc_at_ass_shattr(mf, TK_STRING, &tkv);
return (TK_ERROR);
}
ss->ss_ma.ass_bits = shattr->ms_bits;
ss->ss_ma.ass_enabled |= SYM_ASSERT_BITS;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_SHATTR)));
}
typedef struct {
const char *name;
uchar_t ms_bind;
} at_ass_bind_t;
static at_ass_bind_t at_ass_bind_list[] = {
{ MSG_ORIG(MSG_MAPKW_GLOBAL), STB_GLOBAL },
{ MSG_ORIG(MSG_MAPKW_LOCAL), STB_LOCAL },
{ MSG_ORIG(MSG_MAPKW_WEAK), STB_WEAK },
{ 0 }
};
static size_t at_ass_bind_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_GLOBAL) +
KW_NAME_SIZE(MSG_MAPKW_LOCAL) +
KW_NAME_SIZE(MSG_MAPKW_WEAK);
static void
gts_efunc_at_ass_bind(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
char buf[VLA_SIZE(at_ass_bind_list_bufsize)];
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_BINDTYPE),
ld_map_kwnames(at_ass_bind_list, SGSOFFSETOF(at_ass_bind_t, name),
sizeof (at_ass_bind_list[0]), buf, at_ass_bind_list_bufsize),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
at_ass_bind(Mapfile *mf, Token eq_tok, void *uvalue)
{
symbol_state_t *ss = uvalue;
at_ass_bind_t *bind;
ld_map_tkval_t tkv;
if (gettoken_str(mf, TK_F_KEYWORD, &tkv,
gts_efunc_at_ass_bind) == TK_ERROR)
return (TK_ERROR);
bind = ld_map_kwfind(tkv.tkv_str, at_ass_bind_list,
SGSOFFSETOF(at_ass_bind_t, name), sizeof (bind[0]));
if (bind == NULL) {
gts_efunc_at_ass_bind(mf, TK_STRING, &tkv);
return (TK_ERROR);
}
ss->ss_ma.ass_bind = bind->ms_bind;
ss->ss_ma.ass_enabled |= SYM_ASSERT_BIND;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_BIND)));
}
static Token
at_ass_size(Mapfile *mf, Token eq_tok, void *uvalue)
{
symbol_state_t *ss = uvalue;
ld_map_tkval_t tkv;
if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_SIZE), &tkv,
TK_F_MULOK) == TK_ERROR)
return (TK_ERROR);
ss->ss_ma.ass_size = tkv.tkv_int.tkvi_value;
ss->ss_ma.ass_enabled |= SYM_ASSERT_SIZE;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_SIZE)));
}
static Token
at_ass_alias(Mapfile *mf, Token eq_tok, void *uvalue)
{
symbol_state_t *ss = uvalue;
ld_map_tkval_t tkv;
if (ld_map_gettoken(mf, 0, &tkv) != TK_STRING) {
mf_fatal0(mf, MSG_INTL(MSG_MAP_BADALIAS));
return (TK_ERROR);
}
ss->ss_ma.ass_alias = tkv.tkv_str;
ss->ss_ma.ass_enabled |= SYM_ASSERT_ALIAS;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ALIAS)));
}
static Token
at_ass_type(Mapfile *mf, Token eq_tok, void *uvalue)
{
ld_map_tkval_t tkv;
at_ass_type_t *type;
symbol_state_t *ss = uvalue;
if (gettoken_str(mf, TK_F_KEYWORD, &tkv,
gts_efunc_at_ass_type) == TK_ERROR)
return (TK_ERROR);
type = ld_map_kwfind(tkv.tkv_str, at_ass_type_list,
SGSOFFSETOF(at_sym_type_t, name), sizeof (type[0]));
if (type == NULL) {
gts_efunc_at_ass_type(mf, TK_STRING, &tkv);
return (TK_ERROR);
}
ss->ss_ma.ass_type = type->ms_type;
ss->ss_ma.ass_enabled |= SYM_ASSERT_TYPE;
return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ASSERT)));
}
static Token
at_sym_assert(Mapfile *mf, Token eq_tok, void *uvalue)
{
static attr_t attr_list[] = {
{ MSG_ORIG(MSG_MAPKW_ALIAS), at_ass_alias, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_BIND), at_ass_bind, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_BINDING), at_ass_bind, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_SHATTR), at_ass_shattr, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_SIZE), at_ass_size, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_TYPE), at_ass_type, ATTR_FMT_EQ },
{ 0 }
};
static size_t attr_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_ALIAS) +
KW_NAME_SIZE(MSG_MAPKW_BIND) +
KW_NAME_SIZE(MSG_MAPKW_BINDING) +
KW_NAME_SIZE(MSG_MAPKW_SHATTR) +
KW_NAME_SIZE(MSG_MAPKW_SIZE) +
KW_NAME_SIZE(MSG_MAPKW_TYPE);
symbol_state_t *ss = uvalue;
int done = 0;
Token tok;
ld_map_tkval_t tkv;
Conv_inv_buf_t inv_buf;
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_LEFTBKT:
if (parse_attributes(mf, ss->ss_ms.ms_name,
attr_list, attr_list_bufsize, ss) == TK_ERROR)
return (TK_ERROR);
if ((ss->ss_ma.ass_enabled & SYM_ASSERT_ALIAS) &&
(ss->ss_ma.ass_enabled &
~(SYM_ASSERT_ALIAS|SYM_ASSERT_BIND))) {
mf_fatal(mf, MSG_INTL(MSG_MAP_ALIAS_COMBO),
ss->ss_ms.ms_name);
return (TK_ERROR);
}
tok = gettoken_term(mf, MSG_INTL(MSG_MAP_SYMATTR));
if (tok == TK_ERROR)
return (TK_ERROR);
if (tok == TK_SEMICOLON)
return (tok);
break;
default:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMDELIM),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
}
return (TK_ERROR);
}
static Token
parse_symbol_attributes(Mapfile *mf, const char *dir_name, symbol_state_t *ss)
{
static attr_t attr_list[] = {
{ MSG_ORIG(MSG_MAPKW_AUX), at_sym_aux, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_FILTER), at_sym_filter, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_FLAGS), at_sym_flags, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_SIZE), at_sym_size, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_TYPE), at_sym_type, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_VALUE), at_sym_value, ATTR_FMT_EQ },
{ MSG_ORIG(MSG_MAPKW_ASSERT), at_sym_assert, ATTR_FMT_EQ },
{ 0 }
};
static size_t attr_list_bufsize =
KW_NAME_SIZE(MSG_MAPKW_AUX) +
KW_NAME_SIZE(MSG_MAPKW_FILTER) +
KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
KW_NAME_SIZE(MSG_MAPKW_SIZE) +
KW_NAME_SIZE(MSG_MAPKW_TYPE) +
KW_NAME_SIZE(MSG_MAPKW_VALUE) +
KW_NAME_SIZE(MSG_MAPKW_ASSERT);
Token tok;
ld_map_tkval_t tkv, tkv_sym;
int done;
Conv_inv_buf_t inv_buf;
for (done = 0; done == 0; ) {
switch (tok = ld_map_gettoken(mf, 0, &tkv_sym)) {
case TK_ERROR:
return (TK_ERROR);
case TK_STRING:
(void) memset(&ss->ss_ms, 0, sizeof (ss->ss_ms));
(void) memset(&ss->ss_ma, 0, sizeof (ss->ss_ma));
ss->ss_ms.ms_name = tkv_sym.tkv_str;
ss->ss_ma.ass_file = mf->mf_name;
ss->ss_ma.ass_lineno = mf->mf_lineno;
ss->ss_mv.mv_vdp->vd_flags &= ~VER_FLG_WEAK;
switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
case TK_ERROR:
return (TK_ERROR);
case TK_COLON:
ld_map_sym_scope(mf, tkv_sym.tkv_str,
&ss->ss_mv);
break;
case TK_LEFTBKT:
if (parse_attributes(mf, tkv_sym.tkv_str,
attr_list, attr_list_bufsize, ss) ==
TK_ERROR)
return (TK_ERROR);
tok = gettoken_term(mf,
MSG_INTL(MSG_MAP_SYMATTR));
if (tok == TK_ERROR)
return (TK_ERROR);
if (tok == TK_RIGHTBKT)
done = 1;
case TK_SEMICOLON: {
ld_map_sym_t *ms = &ss->ss_ms;
if ((ss->ss_ma.ass_enabled != 0) &&
(((ms->ms_sdflags & FLG_SY_PARENT) != 0) ||
((ms->ms_sdflags & FLG_SY_EXTERN) != 0))) {
mf_fatal(mf,
MSG_INTL(MSG_MAP_EXTPAR_ASSERT),
ms->ms_name);
return (TK_ERROR);
}
if (!ld_map_sym_enter(mf, &ss->ss_mv,
&ss->ss_ms, &ss->ss_ma))
return (TK_ERROR);
break;
}
default:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMDELIM),
ld_map_tokenstr(tok, &tkv, &inv_buf));
return (TK_ERROR);
}
break;
case TK_RIGHTBKT:
done = 1;
break;
case TK_SEMICOLON:
break;
case TK_STAR:
ss->ss_mv.mv_vdp->vd_flags &= ~VER_FLG_WEAK;
ld_map_sym_autoreduce(mf, &ss->ss_mv);
switch (tok = gettoken_term(mf, dir_name)) {
case TK_ERROR:
return (TK_ERROR);
case TK_RIGHTBKT:
done = 1;
break;
}
break;
default:
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYM),
ld_map_tokenstr(tok, &tkv_sym, &inv_buf));
return (TK_ERROR);
}
}
if (ss->ss_mv.mv_errcnt)
return (TK_ERROR);
return (tok);
}
static Token
dir_symbol_scope(Mapfile *mf)
{
symbol_state_t ss;
if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE)) == TK_ERROR)
return (TK_ERROR);
if (!ld_map_sym_ver_init(mf, NULL, &ss.ss_mv))
return (TK_ERROR);
if (parse_symbol_attributes(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE),
&ss) == TK_ERROR)
return (TK_ERROR);
return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE)));
}
static void
gts_efunc_dir_symbol_version(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
{
Conv_inv_buf_t inv_buf;
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION),
ld_map_tokenstr(tok, tkv, &inv_buf));
}
static Token
dir_symbol_version(Mapfile *mf)
{
ld_map_tkval_t tkv;
symbol_state_t ss;
if (gettoken_str(mf, 0, &tkv, gts_efunc_dir_symbol_version) == TK_ERROR)
return (TK_ERROR);
if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION)) ==
TK_ERROR)
return (TK_ERROR);
if (!ld_map_sym_ver_init(mf, tkv.tkv_str, &ss.ss_mv))
return (TK_ERROR);
if (parse_symbol_attributes(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION),
&ss) == TK_ERROR)
return (TK_ERROR);
if (!ld_map_sym_ver_fini(mf, &ss.ss_mv))
return (TK_ERROR);
return (TK_SEMICOLON);
}
Boolean
ld_map_parse_v2(Mapfile *mf)
{
typedef struct {
const char *name;
dir_func_t func;
} tldir_t;
tldir_t dirlist[] = {
{ MSG_ORIG(MSG_MAPKW_CAPABILITY), dir_capability },
{ MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS), dir_depend_versions },
{ MSG_ORIG(MSG_MAPKW_HDR_NOALLOC), dir_hdr_noalloc },
{ MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT), dir_load_segment },
{ MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT), dir_note_segment },
{ MSG_ORIG(MSG_MAPKW_NULL_SEGMENT), dir_null_segment },
{ MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL), dir_phdr_add_null },
{ MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER), dir_segment_order },
{ MSG_ORIG(MSG_MAPKW_STACK), dir_stack },
{ MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE), dir_symbol_scope },
{ MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION), dir_symbol_version },
{ 0 }
};
static size_t dirlist_bufsize =
KW_NAME_SIZE(MSG_MAPKW_CAPABILITY) +
KW_NAME_SIZE(MSG_MAPKW_DEPEND_VERSIONS) +
KW_NAME_SIZE(MSG_MAPKW_HDR_NOALLOC) +
KW_NAME_SIZE(MSG_MAPKW_LOAD_SEGMENT) +
KW_NAME_SIZE(MSG_MAPKW_NOTE_SEGMENT) +
KW_NAME_SIZE(MSG_MAPKW_NULL_SEGMENT) +
KW_NAME_SIZE(MSG_MAPKW_PHDR_ADD_NULL) +
KW_NAME_SIZE(MSG_MAPKW_SEGMENT_ORDER) +
KW_NAME_SIZE(MSG_MAPKW_STACK) +
KW_NAME_SIZE(MSG_MAPKW_SYMBOL_SCOPE) +
KW_NAME_SIZE(MSG_MAPKW_SYMBOL_VERSION);
Token tok;
ld_map_tkval_t tkv;
tldir_t *tldir;
Conv_inv_buf_t inv_buf;
for (;;) {
tok = ld_map_gettoken(mf, TK_F_EOFOK | TK_F_KEYWORD, &tkv);
switch (tok) {
case TK_ERROR:
return (FALSE);
case TK_EOF:
return (TRUE);
case TK_SEMICOLON:
break;
case TK_STRING:
tldir = ld_map_kwfind(tkv.tkv_str, dirlist,
SGSOFFSETOF(tldir_t, name), sizeof (dirlist[0]));
if (tldir == NULL)
goto bad_dirtok;
if (tldir->func(mf) == TK_ERROR)
return (FALSE);
break;
default:
bad_dirtok:
{
char buf[VLA_SIZE(dirlist_bufsize)];
mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_DIR),
ld_map_kwnames(dirlist,
SGSOFFSETOF(tldir_t, name),
sizeof (dirlist[0]), buf, dirlist_bufsize),
ld_map_tokenstr(tok, &tkv, &inv_buf));
}
return (FALSE);
}
}
}