/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <synch.h>
#if defined(DEBUG)
#include <stdarg.h>
#endif /* !DEBUG */
#include "iconv_tm.h"
#include "hash.h"
/*
* Debug
*/
#if defined(DEBUG)
static void trace_init(void);
static void trace_message(char *, ...);
static char trace_option[128];
#define TRACE(c) (*(trace_option + (c & 0x007f)))
#define TRACE_MESSAGE(c, args) ((TRACE(c))? trace_message args: (void)0)
#else /* !DEBUG */
#define trace_init()
#define TRACE()
#define TRACE_MESSAGE(c, args)
#endif /* !DEBUG */
/*
* ITM reference information
*/
typedef struct _itm_ref {
char *name; /* ITM file name */
itm_hdr_t *hdr; /* address of ITM */
size_t len; /* length of ITM */
} itm_ref_t;
/*
* struct _icv_state; to keep status
*/
typedef struct _icv_state {
struct _itm_ref *itm; /* reference to ITM */
itm_hdr_t *itm_hdr; /* address of ITM */
itm_tbl_hdr_t *direc; /* current direction */
itm_place_t default_action; /* default action */
itm_num_t *regs; /* register */
itm_num_t reg_num; /* number of register */
#if defined(OP_DEPTH_MAX)
int op_depth; /* depth of operation */
#endif /* OP_DEPTH_MAX */
} icv_state_t;
/*
* function prototype
*/
void * _icv_open(const char *);
void _icv_close(icv_state_t *);
size_t _icv_iconv(icv_state_t *, const unsigned char **,
size_t *, unsigned char **, size_t *);
static size_t map_i_f(itm_tbl_hdr_t *,
const unsigned char **, size_t *,
unsigned char **, size_t *, long);
static size_t map_l_f(itm_tbl_hdr_t *,
const unsigned char **, size_t *,
unsigned char **, size_t *, long);
static size_t map_h_l(itm_tbl_hdr_t *,
const unsigned char **, size_t *,
unsigned char **, size_t *, long);
static size_t map_d_e_l(itm_tbl_hdr_t *,
const unsigned char **, size_t *,
unsigned char **, size_t *, long);
static size_t eval_cond_tbl(icv_state_t *, itm_place_t,
const unsigned char **, size_t *,
size_t, itm_direc_t *);
static size_t eval_op_tbl(icv_state_t *, itm_place_t,
const unsigned char **, size_t *,
unsigned char **, size_t *);
static size_t eval_op(icv_state_t *, itm_place2_t,
const unsigned char **, size_t *,
unsigned char **, size_t *);
static itm_num_t eval_expr(icv_state_t *, itm_place_t,
size_t, const unsigned char *, size_t);
static void itm_ref_free(int, void *, void *, void *, size_t);
static itm_ref_t *itm_ref_inc(const char *);
static void itm_ref_dec(itm_ref_t *);
static void op_init_default(icv_state_t *);
static void op_reset_default(icv_state_t *);
static void regs_init(icv_state_t *);
/*
* macro definition
*/
#define ADDR(place) ((void *)(((char *)(ist->itm_hdr)) +\
((itm_place2_t)(place.itm_ptr))))
#define ADDR2(place2) ((void *)(((char *)(ist->itm_hdr)) +\
((itm_place2_t)(place2))))
#define DADDR(n) (((n)->size <= (sizeof ((n)->place.itm_64d))) ? \
((unsigned char *)(&((n)->place.itm_64d))) :\
((unsigned char *)(ADDR((n)->place))))
#define REG(n) (*(ist->regs + (n)))
#define DISCARD(c) (((*inbuf) = (void *)((*inbuf) + (c))),\
((*inbytesleft) -= (c)))
#define GET(c) ((c) = **inbuf, (*inbuf)++, (*inbytesleft)--)
#define PUT(c) (**outbuf = (c), (*outbuf)++, (*outbytesleft)--)
#define RETVALERR ((size_t)(-1))
#define RETVALDIR ((size_t)(-2))
#define RETVALBRK ((size_t)(-3))
#define RETVALRET ((size_t)(-4))
#define UPDATE_ARGS() (*inbuf = ip, \
*inbytesleft = ileft, \
*outbuf = op, \
*outbytesleft = oleft)
/*
* Open; called from iconv_open()
*/
void *
_icv_open(const char *itm)
{
icv_state_t *ist;
itm_hdr_t *hdr;
itm_ref_t *itm_ref;
int r;
/*
* for debug
*/
trace_init();
/*
* _icv_open() primaty task
*/
itm_ref = itm_ref_inc(itm);
if (NULL == itm_ref) {
return ((void *)(-1));
}
if (NULL == (ist = malloc(sizeof (icv_state_t)))) {
r = errno;
itm_ref_dec(itm_ref);
errno = r;
return (NULL);
}
ist->itm = itm_ref;
ist->itm_hdr = ist->itm->hdr;
ist->reg_num = ist->itm->hdr->reg_num;
hdr = ist->itm->hdr;
ist->direc = ADDR(hdr->direc_init_tbl);
ist->default_action.itm_64d = 0;
#if defined(OP_DEPTH_MAX)
ist->op_depth = 0;
#endif /* OP_DEPTH_MAX */
/*
* brief sanity check
*/
if (hdr->itm_size.itm_ptr <= hdr->direc_init_tbl.itm_ptr) {
_icv_close(ist);
errno = ELIBBAD;
return ((void *)(-1));
}
/* allocate register region */
if (hdr->reg_num <= 0) {
ist->regs = NULL;
} else {
ist->regs = malloc((sizeof (itm_num_t)) * hdr->reg_num);
if (NULL == ist->regs) {
r = errno;
_icv_close(ist);
errno = r;
return ((void *)(-1));
}
(void) memset(ist->regs, 0,
(sizeof (itm_num_t)) * hdr->reg_num);
}
/* evaluate init operation */
if (0 != ist->itm_hdr->op_init_tbl.itm_ptr) {
const unsigned char *ip = NULL;
size_t ileft = 0;
unsigned char *op = NULL;
size_t oleft = 0;
(void) eval_op_tbl(ist, ist->itm_hdr->op_init_tbl, &ip,
&ileft, &op, &oleft);
} else {
op_init_default(ist);
}
return (ist);
}
/*
* Close; called from iconv_close
*/
void
_icv_close(icv_state_t *ist)
{
if (NULL == ist) {
errno = EBADF;
return;
}
itm_ref_dec(ist->itm);
free(ist->regs);
free(ist);
}
/*
* Actual conversion; called from iconv()
*/
size_t
_icv_iconv(
icv_state_t *ist,
const unsigned char **inbuf,
size_t *inbytesleft,
unsigned char **outbuf,
size_t *outbytesleft)
{
size_t retval;
itm_hdr_t *hdr;
itm_type_t type;
const unsigned char *ip;
size_t ileft;
itm_place_t action;
if (NULL == ist) {
errno = EBADF;
TRACE_MESSAGE('e', ("_icv_iconv: error=%d\n", errno));
return ((size_t)(-1));
}
if (NULL == inbuf) {
ip = NULL;
inbuf = &ip;
}
if (NULL == inbytesleft) {
ileft = 0;
inbytesleft = &ileft;
}
hdr = ist->itm_hdr;
retval = 0;
TRACE_MESSAGE('i', ("_icv_iconv(inbuf=%p inbytesleft=%ld "
"outbuf=%p outbytesleft=%ld)\n", (NULL == inbuf) ? 0 : *inbuf,
(NULL == inbytesleft) ? 0 : *inbytesleft,
(NULL == outbuf) ? 0 : *outbuf,
(NULL == outbytesleft) ? 0 : *outbytesleft));
/*
* If (NULL == inbuf || NULL == *inbuf) then this conversion is
* placed into initial state.
*/
if ((NULL == inbuf) || (NULL == *inbuf)) {
if (0 != hdr->op_reset_tbl.itm_ptr) {
ist->direc = ADDR(hdr->direc_init_tbl);
retval = eval_op_tbl(ist, hdr->op_reset_tbl, inbuf,
inbytesleft, outbuf, outbytesleft);
if ((size_t)(-1) == retval) {
return (retval);
}
} else {
op_reset_default(ist);
}
return ((size_t)(0));
}
if (ITM_TBL_MAP_INDEX_FIXED_1_1 == ist->direc->type) {
itm_map_idx_fix_hdr_t *map_hdr;
char *map;
const unsigned char *ip;
size_t ileft;
unsigned char *op;
size_t oleft;
map_hdr = (itm_map_idx_fix_hdr_t *)(ist->direc + 1);
map = (char *)(map_hdr + 1);
if (1 == map_hdr->default_error) {
retval = map_i_f(ist->direc, inbuf, inbytesleft,
outbuf, outbytesleft, 0);
return (retval);
}
ip = *inbuf;
ileft = *inbytesleft;
op = *outbuf;
oleft = *outbytesleft;
while (1 <= ileft) {
if (oleft < 1) {
UPDATE_ARGS();
errno = E2BIG;
TRACE_MESSAGE('e', ("_icv_iconv: error=%d\n",
errno));
return ((size_t)-1);
}
*(op++) = *(map + *(ip++));
ileft--;
oleft--;
}
UPDATE_ARGS();
return (0);
} else if (ITM_TBL_MAP_INDEX_FIXED == ist->direc->type) {
retval = map_i_f(ist->direc, inbuf, inbytesleft,
outbuf, outbytesleft, 0);
return (retval);
} else if (ITM_TBL_MAP_HASH == ist->direc->type) {
retval = map_h_l(ist->direc, inbuf, inbytesleft,
outbuf, outbytesleft, 0);
return (retval);
} else if (ITM_TBL_MAP_DENSE_ENC == ist->direc->type) {
retval = map_d_e_l(ist->direc, inbuf, inbytesleft,
outbuf, outbytesleft, 0);
return (retval);
} else if (ITM_TBL_MAP_LOOKUP == ist->direc->type) {
retval = map_l_f(ist->direc, inbuf, inbytesleft,
outbuf, outbytesleft, 0);
return (retval);
}
#if defined(OP_DEPTH_MAX)
ist->op_depth = 0;
#endif /* OP_DEPTH_MAX */
/*
* Main loop; basically 1 loop per 1 output character
*/
retry_cond_eval:
while (0 < *inbytesleft) {
itm_tbl_hdr_t *direc_hdr;
itm_direc_t *direc;
long i;
direc_hdr = ist->direc;
direc = (itm_direc_t *)(ist->direc + 1);
for (i = 0; /* NULL */; i++, direc++) {
if (i >= direc_hdr->number) {
if (0 == ist->default_action.itm_ptr) {
errno = EILSEQ;
TRACE_MESSAGE('e',
("_icv_iconv:error=%d\n", errno));
return ((size_t)(-1));
}
action = ist->default_action;
type = ((itm_tbl_hdr_t *)(ADDR(action)))->type;
TRACE_MESSAGE('E',
("escape seq (default action=%6p, "
"type=%ld) executing\n",
action.itm_ptr, type));
} else if (0 != direc->condition.itm_ptr) {
retval = eval_cond_tbl(ist, direc->condition,
inbuf, inbytesleft, *outbytesleft, direc);
if ((size_t)(0) == retval) {
continue;
} else if ((size_t)(-1) == retval) {
return (retval);
} else if ((size_t)(2) == retval) {
goto retry_cond_eval;
}
action = direc->action;
type = ((itm_tbl_hdr_t *)(ADDR(action)))->type;
} else {
action = direc->action;
type = ((itm_tbl_hdr_t *)(ADDR(action)))->type;
}
TRACE_MESSAGE('a',
("inbytesleft=%ld; type=%ld:action=%p\n",
*inbytesleft, type, action.itm_ptr));
switch (ITM_TBL_MASK & type) {
case ITM_TBL_OP:
retval = eval_op_tbl(ist, action,
inbuf, inbytesleft, outbuf, outbytesleft);
if ((size_t)(-1) == retval) {
return (retval);
}
break;
case ITM_TBL_DIREC:
ist->direc = ADDR(action);
break;
case ITM_TBL_MAP:
switch (type) {
case ITM_TBL_MAP_INDEX_FIXED_1_1:
case ITM_TBL_MAP_INDEX_FIXED:
retval = map_i_f(ADDR(action),
inbuf, inbytesleft,
outbuf, outbytesleft, 1);
break;
case ITM_TBL_MAP_HASH:
retval = map_h_l(ADDR(action),
inbuf, inbytesleft,
outbuf, outbytesleft, 1);
break;
case ITM_TBL_MAP_DENSE_ENC:
retval = map_d_e_l(ADDR(action),
inbuf, inbytesleft,
outbuf, outbytesleft, 1);
break;
case ITM_TBL_MAP_LOOKUP:
retval = map_l_f(ADDR(action),
inbuf, inbytesleft,
outbuf, outbytesleft, 1);
break;
default:
errno = ELIBBAD;
TRACE_MESSAGE('e',
("_icv_iconv:error=%d\n", errno));
return ((size_t)(-1));
}
if ((size_t)(-1) == retval) {
return (retval);
}
break;
default: /* never */
errno = ELIBBAD;
TRACE_MESSAGE('e',
("_icv_iconv:error=%d\n", errno));
return ((size_t)(-1));
}
break;
}
}
return (retval);
}
/*
* map-indexed-fixed
*/
static size_t
map_i_f(
itm_tbl_hdr_t *tbl_hdr,
const unsigned char **inbuf,
size_t *inbytesleft,
unsigned char **outbuf,
size_t *outbytesleft,
long once)
{
itm_map_idx_fix_hdr_t *map_hdr;
long i;
unsigned char c;
unsigned long j;
const unsigned char *p;
TRACE_MESSAGE('i', ("map_i_f\n"));
map_hdr = (itm_map_idx_fix_hdr_t *)(tbl_hdr + 1);
do {
if (*inbytesleft < map_hdr->source_len) {
errno = EINVAL;
TRACE_MESSAGE('e', ("map_i_f:error=%d\n", errno));
return ((size_t)(-1));
}
j = 0;
for (i = 0; i < map_hdr->source_len; i++) {
GET(c);
j = ((j << 8) | c);
}
if (((j < map_hdr->start.itm_ptr) ||
(map_hdr->end.itm_ptr < j)) &&
(0 < map_hdr->default_error)) {
errno = EILSEQ;
(*inbuf) = (void*) ((*inbuf) - map_hdr->source_len);
(*inbytesleft) += map_hdr->source_len;
TRACE_MESSAGE('e', ("map_i_f:error=%d\n", errno));
return ((size_t)(-1));
}
if (*outbytesleft < map_hdr->result_len) {
errno = E2BIG;
(*inbuf) = (void *)((*inbuf) - map_hdr->source_len);
(*inbytesleft) += map_hdr->source_len;
TRACE_MESSAGE('e', ("map_i_f:error=%d\n", errno));
return ((size_t)(-1));
}
if ((j < map_hdr->start.itm_ptr) ||
(map_hdr->end.itm_ptr < j)) {
if (0 == map_hdr->default_error) {
p = (((unsigned char *)(map_hdr + 1)) +
(map_hdr->result_len * (tbl_hdr->number)));
for (i = 0; i < map_hdr->result_len; i++) {
PUT(*(p + i));
}
} else {
p = ((*inbuf) - map_hdr->source_len);
for (i = 0; i < map_hdr->source_len; i++) {
PUT(*(p + i));
}
}
} else {
char *map_error;
map_error = (((char *)(map_hdr + 1)) +
(map_hdr->result_len * (tbl_hdr->number)) +
(j - map_hdr->start.itm_ptr));
if (0 == map_hdr->default_error) {
map_error = (void *)
(map_error + map_hdr->result_len);
}
if (((1 == map_hdr->default_error) ||
(0 < map_hdr->error_num)) &&
(0 != *(map_error))) {
errno = EILSEQ;
(*inbuf) = (void *)
((*inbuf) - map_hdr->source_len);
(*inbytesleft) += map_hdr->source_len;
TRACE_MESSAGE('e',
("map_i_f:error=%d\n", errno));
return ((size_t)(-1));
}
p = (((unsigned char *)(map_hdr + 1)) +
(map_hdr->result_len *
(j - map_hdr->start.itm_ptr)));
for (i = 0; i < map_hdr->result_len; i++) {
PUT(*(p + i));
}
}
} while ((0 < *inbytesleft) && (0 == once));
return (size_t)(0);
}
/*
* map-lookup-fixed
*/
static size_t
map_l_f(
itm_tbl_hdr_t *tbl_hdr,
const unsigned char **inbuf,
size_t *inbytesleft,
unsigned char **outbuf,
size_t *outbytesleft,
long once)
{
itm_map_lookup_hdr_t *map_hdr;
long i;
unsigned char *map;
const unsigned char *p;
long high;
long mid;
long low;
long result;
itm_size_t pair_size;
TRACE_MESSAGE('i', ("map_l_f\n"));
map_hdr = (itm_map_lookup_hdr_t *)(tbl_hdr + 1);
map = (unsigned char *)(map_hdr + 1);
pair_size = map_hdr->source_len + 1 + map_hdr->result_len;
do {
if (*inbytesleft < map_hdr->source_len) {
errno = EINVAL;
TRACE_MESSAGE('e', ("map_l_f:error=%d\n", errno));
return ((size_t)(-1));
}
for (low = 0, high = tbl_hdr->number; low < high; ) {
mid = (low + high) / 2;
p = map + (pair_size * mid);
for (i = 0, result = 0; i < map_hdr->source_len;
i++, p++) {
if (*(unsigned char *)(*inbuf + i) < *p) {
result = -1;
break;
}
if (*p < *(unsigned char *)(*inbuf + i)) {
result = 1;
break;
}
}
if (result < 0) {
high = mid;
} else if (0 < result) {
low = mid + 1;
} else { /* 0 == result */
break;
}
}
if (0 != result) {
if (map_hdr->default_error < 0) {
p = *inbuf;
} else if (0 == map_hdr->default_error) {
p = map + (pair_size * tbl_hdr->number) +
map_hdr->source_len + 1;
} else if (0 < map_hdr->default_error) {
errno = EILSEQ;
TRACE_MESSAGE('e', ("map_l_f:error=%d\n",
errno));
return ((size_t)(-1));
}
} else {
if (0 != (*p)) {
errno = EILSEQ;
TRACE_MESSAGE('e', ("map_l_f:error=%d\n",
errno));
return ((size_t)(-1));
}
p++;
}
if (*outbytesleft < map_hdr->result_len) {
errno = E2BIG;
TRACE_MESSAGE('e', ("map_l_f:error=%d\n", errno));
return ((size_t)(-1));
}
DISCARD(map_hdr->source_len);
for (i = 0; i < map_hdr->result_len; i++) {
PUT(*(p + i));
}
} while ((0 < *inbytesleft) && (0 == once));
return ((size_t)(0));
}
/*
* map-hash-lookup
*/
static size_t
map_h_l(
itm_tbl_hdr_t *tbl_hdr,
const unsigned char **inbuf,
size_t *inbytesleft,
unsigned char **outbuf,
size_t *outbytesleft,
long once)
{
itm_map_hash_hdr_t *map_hdr;
long i;
unsigned char *map_error;
unsigned char *map_hash;
unsigned char *map_of;
const unsigned char *p;
const unsigned char *q;
long high;
long mid;
long low;
long result;
itm_size_t pair_size;
itm_size_t hash_value;
itm_size_t source_len;
itm_size_t result_len;
TRACE_MESSAGE('i', ("map_hash\n"));
map_hdr = (itm_map_hash_hdr_t *)(tbl_hdr + 1);
map_error = (unsigned char *)(map_hdr + 1);
map_hash = (map_error + map_hdr->hash_tbl_num);
map_of = map_hash + map_hdr->hash_tbl_size;
pair_size = map_hdr->source_len + 1 + map_hdr->result_len;
source_len = map_hdr->source_len;
result_len = map_hdr->result_len;
do {
if (*inbytesleft < source_len) {
errno = EINVAL;
TRACE_MESSAGE('e', ("map_h_l:error=%d\n", errno));
return ((size_t)(-1));
}
result = 1;
q = *inbuf;
hash_value = hash((const char *)(q), source_len,
map_hdr->hash_tbl_num);
p = map_hash + (pair_size * hash_value);
if (1 == *(map_error + hash_value)) {
for (i = 0, result = 0; i < source_len; i++) {
if (*(q + i) != *(p++)) {
result = -2;
break;
}
}
TRACE_MESSAGE('G',
("(h=%d): find pair without conflict\n",
hash_value));
} else if (0 == *(map_error + hash_value)) {
TRACE_MESSAGE('G', ("(h=%d): No Pair\n", hash_value));
result = -3;
} else /* if (0 < *(map_error + hash_value)) */ {
for (i = 0, result = 0; i < source_len; i++) {
if (*(q + i) != *(p++)) {
result = 1;
break;
}
}
if (0 < result) {
for (low = 0, high = map_hdr->hash_of_num;
low < high; /* NOP */) {
mid = (low + high) / 2;
p = map_of + (pair_size * mid);
for (i = 0, result = 0;
i < source_len;
i++, p++) {
if (*(q + i) < *p) {
result = -1;
break;
}
if (*p < *(q + i)) {
result = 1;
break;
}
}
if (result < 0) {
high = mid;
} else if (0 < result) {
low = mid + 1;
} else { /* 0 == result */
TRACE_MESSAGE('G', ("(h=%d): "
"find data on out of "
"hashtable with CONFLICT\n",
hash_value));
break;
}
}
}
}
if (0 != result) {
if (map_hdr->default_error < 0) {
p = q;
} else if (0 == map_hdr->default_error) {
p = map_of + map_hdr->hash_of_size;
} else if (0 < map_hdr->default_error) {
TRACE_MESSAGE('G', ("(h=%d): NO PAIR\n",
hash_value));
errno = EILSEQ;
TRACE_MESSAGE('e',
("map_h_l:error=%d\n", errno));
return ((size_t)(-1));
}
} else {
if (0 != (*p)) {
errno = EILSEQ;
TRACE_MESSAGE('G', (" : error pair\n"));
TRACE_MESSAGE('e', ("map_l_f:error\n", errno));
return ((size_t)(-1));
}
p++;
}
if (*outbytesleft < result_len) {
errno = E2BIG;
TRACE_MESSAGE('e', ("map_h_l:error=%d\n", errno));
return ((size_t)(-1));
}
DISCARD(source_len);
for (i = 0; i < result_len; i++) {
PUT(*(p + i));
}
} while ((0 < *inbytesleft) && (0 == once));
return ((size_t)(0));
}
/*
* map-dense_encoding-lookup
*/
static size_t
map_d_e_l(
itm_tbl_hdr_t *tbl_hdr,
const unsigned char **inbuf,
size_t *inbytesleft,
unsigned char **outbuf,
size_t *outbytesleft,
long once)
{
itm_map_dense_enc_hdr_t *map_hdr;
long i;
itm_num_t j;
const unsigned char *p;
unsigned char *map_ptr;
unsigned char *map_error;
unsigned char *byte_seq_min;
unsigned char *byte_seq_max;
TRACE_MESSAGE('i', ("map_d_e_l\n"));
map_hdr = (itm_map_dense_enc_hdr_t *)(tbl_hdr + 1);
map_ptr = ((unsigned char *)(map_hdr + 1) + map_hdr->source_len +
map_hdr->source_len);
map_error = (map_ptr + (tbl_hdr->number * map_hdr->result_len));
if (0 == map_hdr->default_error) {
map_error = (void *)(map_error + map_hdr->result_len);
}
byte_seq_min = (unsigned char *)(map_hdr + 1);
byte_seq_max = byte_seq_min + map_hdr->source_len;
do {
if (*inbytesleft < map_hdr->source_len) {
errno = EINVAL;
TRACE_MESSAGE('e', ("map_d_e_l:error=%d\n", errno));
return ((size_t)(-1));
}
j = hash_dense_encoding(*inbuf, map_hdr->source_len,
byte_seq_min, byte_seq_max);
if (((j < 0) || (tbl_hdr->number < j)) &&
(0 < map_hdr->default_error)) {
errno = EILSEQ;
TRACE_MESSAGE('e', ("map_d_e_l:error=%d\n", errno));
return ((size_t)(-1));
}
if (*outbytesleft < map_hdr->result_len) {
errno = E2BIG;
TRACE_MESSAGE('e', ("map_d_e_l:error=%d\n", errno));
return ((size_t)(-1));
}
if ((j < 0) || (tbl_hdr->number < j)) {
if (0 == map_hdr->default_error) {
p = (map_ptr + (tbl_hdr->number *
map_hdr->result_len));
for (i = 0; i < map_hdr->result_len; i++) {
PUT(*(p + i));
}
} else {
p = *inbuf;
for (i = 0; i < map_hdr->source_len; i++) {
PUT(*(p + i));
}
}
} else {
if ((1 == map_hdr->default_error) ||
(0 < map_hdr->error_num)) {
if (0 != *(map_error + j)) {
errno = EILSEQ;
TRACE_MESSAGE('e',
("map_d_e_l:error=%d\n", errno));
return ((size_t)(-1));
}
}
p = (map_ptr + (map_hdr->result_len * j));
for (i = 0; i < map_hdr->result_len; i++) {
PUT(*(p + i));
}
}
DISCARD(map_hdr->source_len);
} while ((0 < *inbytesleft) && (0 == once));
return ((size_t)(0));
}
/*
* Evaluate condition table
*
*/
static size_t
eval_cond_tbl(
icv_state_t *ist,
itm_place_t cond_place,
const unsigned char **inbuf,
size_t *inbytesleft,
size_t outbytesleft,
itm_direc_t *direc
)
{
itm_tbl_hdr_t *cond_hdr;
itm_cond_t *cond;
long i;
long j;
long k;
size_t retval;
itm_tbl_hdr_t *rth;
itm_range_hdr_t *rtsh;
unsigned char *p;
itm_tbl_hdr_t *eth;
itm_escapeseq_hdr_t *eh;
itm_data_t *d;
const unsigned char *ip;
size_t ileft;
retval = 0;
ip = *inbuf;
ileft = *inbytesleft;
cond_hdr = ADDR(cond_place);
cond = (itm_cond_t *)(cond_hdr + 1);
for (i = 0; i < cond_hdr->number; i++, cond++) {
switch (cond->type) {
case ITM_COND_BETWEEN:
rth = ADDR(cond->operand.place);
rtsh = (itm_range_hdr_t *)(rth + 1);
if (ileft < rtsh->len) {
errno = EINVAL;
TRACE_MESSAGE('e', ("eval_cond_tbl:error=%d\n",
errno));
retval = ((size_t)(-1));
goto eval_cond_return;
}
p = (unsigned char *)(rtsh + 1);
retval = 0;
for (j = 0; j < rth->number;
j++, p = (void *)(p + (2 * rtsh->len))) {
retval = 1;
for (k = 0; k < rtsh->len; k++) {
if ((*(ip + k) < *(p + k)) ||
(*(p + rtsh->len + k) <
*(ip + k))) {
retval = 0;
break;
}
}
if (1 == retval) {
break;
}
}
if (0 == retval) {
TRACE_MESSAGE('b',
("out of between (%p) len= rtsh=%ld\n",
*ip, rtsh->len));
goto eval_cond_return;
}
break; /* continue */
case ITM_COND_ESCAPESEQ:
/*
* if escape sequence occur,
* change ist->default_action and return 2.
* never return 1.
*/
retval = 0;
eth = ADDR(cond->operand.place);
eh = (itm_escapeseq_hdr_t *)(eth + 1);
if (NULL == ist->default_action.itm_ptr) {
ist->default_action = direc->action;
TRACE_MESSAGE('E',
("escape seq (default action=%6p, "
"type=%ld) set\n",
direc->action.itm_ptr, ((itm_tbl_hdr_t *)
(ADDR(direc->action)))->type));
}
retval = 0;
if (*inbytesleft < eh->len_min) {
break;
}
for (j = 0, d = (itm_data_t *)(eh + 1);
j < eth->number;
j++, d++) {
if (*inbytesleft < d->size) {
continue;
}
if (0 == memcmp(*inbuf, DADDR(d), d->size)) {
TRACE_MESSAGE('E',
("escape seq: discard=%ld chars\n",
d->size));
TRACE_MESSAGE('E',
("escape seq (default "
"action=%6p, type=%ld) set\n",
direc->action.itm_ptr,
((itm_tbl_hdr_t *)
(ADDR(direc->action)))->type));
ist->default_action = direc->action;
DISCARD(d->size);
retval = 2;
goto eval_cond_return;
}
}
if (0 == retval) {
goto eval_cond_return;
}
break; /* continue */
case ITM_COND_EXPR:
retval = eval_expr(ist, cond->operand.place,
*inbytesleft, ip, outbytesleft);
if (0 == retval) {
goto eval_cond_return;
} else {
retval = 1;
}
break; /* continue */
default:
TRACE_MESSAGE('e', ("eval_cond_tbl:illegal cond=%d\n",
cond->type));
retval = (size_t)-1;
goto eval_cond_return;
}
}
eval_cond_return:
return (retval);
}
/*
* Evaluate operation table
*
*/
static size_t
eval_op_tbl(
icv_state_t *ist,
itm_place_t op_tbl_place,
const unsigned char **inbuf,
size_t *inbytesleft,
unsigned char **outbuf,
size_t *outbytesleft)
{
itm_tbl_hdr_t *op_hdr;
itm_op_t *operation;
itm_place2_t op_place;
size_t retval;
long i;
retval = 0;
#if defined(OP_DEPTH_MAX)
if (OP_DEPTH_MAX <= ist->op_depth) {
errno = ELIBBAD;
TRACE_MESSAGE('e', ("eval_op_tbl:error=%d\n", errno));
return (RETVALERR);
}
ist->op_depth += 1;
#endif /* OP_DEPTH_MAX */
op_hdr = ADDR(op_tbl_place);
operation = (itm_op_t *)(op_hdr + 1);
op_place = op_tbl_place.itm_ptr + (sizeof (itm_tbl_hdr_t));
for (i = 0; i < op_hdr->number; i++, operation++,
op_place += (sizeof (itm_op_t))) {
TRACE_MESSAGE('O', ("eval_op_tbl: %ld %p\n", i, op_place));
retval = eval_op(ist, op_place, inbuf, inbytesleft,
outbuf, outbytesleft);
if (((long)(retval)) < 0) {
#if defined(OP_DEPTH_MAX)
ist->op_depth -= 1;
#endif /* OP_DEPTH_MAX */
switch (retval) {
case RETVALERR:
return (retval);
case RETVALRET:
if (0 == op_hdr->name.itm_ptr) {
return (RETVALRET);
} else {
return (0);
}
}
}
}
#if defined(OP_DEPTH_MAX)
ist->op_depth -= 1;
#endif /* OP_DEPTH_MAX */
return (retval);
}
/*
* Evaluate single operation
*
*/
static size_t
eval_op(
icv_state_t *ist,
itm_place2_t op_place,
const unsigned char **inbuf,
size_t *inbytesleft,
unsigned char **outbuf,
size_t *outbytesleft)
{
size_t retval;
itm_num_t num;
itm_op_t *operation;
itm_expr_t *expr;
itm_num_t c;
itm_num_t i;
itm_size_t z;
unsigned char *p;
itm_expr_t *expr0;
itm_tbl_hdr_t *h;
itm_type_t t;
#define EVAL_EXPR(n) \
(expr0 = ADDR(operation->data.operand[(n)]), \
(itm_num_t)((expr0->type == ITM_EXPR_INT) ? \
expr0->data.itm_exnum : \
((expr0->type == ITM_EXPR_REG) ? \
REG(expr0->data.itm_exnum) : \
((expr0->type == ITM_EXPR_IN_VECTOR_D) ? \
((expr0->data.itm_exnum < 0) ? \
(((-1) == expr0->data.itm_exnum) ? *inbytesleft : 0) : \
((expr0->data.itm_exnum < *inbytesleft) ? \
(*(uchar_t *)(*inbuf + expr0->data.itm_exnum)) : 0)): \
eval_expr(ist, operation->data.operand[(n)], \
*inbytesleft, *inbuf, *outbytesleft)))))
retval = 0;
operation = (itm_op_t *)ADDR2(op_place);
switch (operation->type) {
case ITM_OP_EXPR:
num = eval_expr(ist, operation->data.operand[0],
*inbytesleft, *inbuf, *outbytesleft);
TRACE_MESSAGE('o', ("ITM_OP_EXPR: %ld\n", retval));
break;
case ITM_OP_ERROR:
num = eval_expr(ist, operation->data.operand[0],
*inbytesleft, *inbuf, *outbytesleft);
errno = (int)num;
TRACE_MESSAGE('o', ("ITM_OP_ERROR: %ld\n", num));
retval = (size_t)(-1);
break;
case ITM_OP_ERROR_D:
errno = (int)operation->data.itm_opnum;
TRACE_MESSAGE('o', ("ITM_OP_ERROR_D: %d\n", errno));
retval = (size_t)(-1);
break;
case ITM_OP_OUT:
expr = ADDR(operation->data.operand[0]);
if ((*outbytesleft) == 0) {
errno = E2BIG;
TRACE_MESSAGE('e', ("eval_op:error=%d\n", errno));
return ((size_t)(-1));
}
c = eval_expr(ist, operation->data.operand[0],
*inbytesleft, *inbuf, *outbytesleft);
PUT((uchar_t)c);
retval = *inbytesleft;
TRACE_MESSAGE('o', ("ITM_OP_OUT: %ld %ld\n", c, *inbytesleft));
break;
case ITM_OP_OUT_D:
expr = ADDR(operation->data.operand[0]);
if ((*outbytesleft) == 0) {
errno = E2BIG;
TRACE_MESSAGE('e', ("eval_op:error=%d\n", errno));
return ((size_t)(-1));
}
PUT(0xff & (expr->data.itm_exnum));
break;
case ITM_OP_OUT_S:
expr = ADDR(operation->data.operand[0]);
if ((*outbytesleft) == 0) {
errno = E2BIG;
TRACE_MESSAGE('e', ("eval_op:error=%d\n", errno));
return ((size_t)(-1));
}
z = expr->data.value.size;
if (*outbytesleft < z) {
errno = E2BIG;
TRACE_MESSAGE('e', ("eval_op:error=%d\n", errno));
return ((size_t)(-1));
}
p = DADDR(&(expr->data.value));
for (; 0 < z; --z, p++) {
PUT(*p);
}
break;
case ITM_OP_OUT_R:
expr = ADDR(operation->data.operand[0]);
if ((*outbytesleft) == 0) {
errno = E2BIG;
TRACE_MESSAGE('e', ("eval_op:error=%d\n", errno));
return ((size_t)(-1));
}
c = REG(expr->data.itm_exnum);
PUT((uchar_t)c);
break;
case ITM_OP_OUT_INVD:
expr = ADDR(operation->data.operand[0]);
if ((*outbytesleft) == 0) {
errno = E2BIG;
TRACE_MESSAGE('e', ("eval_op:error=%d\n", errno));
return ((size_t)(-1));
}
z = (((0 <= expr->data.itm_exnum) &&
(expr->data.itm_exnum < *inbytesleft)) ?
(*((unsigned char *)(*inbuf + expr->data.itm_exnum))) :
(((-1) == expr->data.itm_exnum) ? *inbytesleft : 0));
PUT((uchar_t)z);
break;
case ITM_OP_DISCARD:
#if defined(EVAL_EXPR)
num = EVAL_EXPR(0);
#else /* !defined(EVAL_EXPR) */
num = eval_expr(ist, operation->data.operand[0],
*inbytesleft, *inbuf, *outbytesleft);
#endif /* defined(EVAL_EXPR) */
TRACE_MESSAGE('o', ("ITM_OP_DISCARD: %ld\n", num));
#if defined(DISCARD)
DISCARD((num <= *inbytesleft) ? ((ulong_t)num) : *inbytesleft);
#else /* defined(DISCARD) */
for (num = ((num <= *inbytesleft) ? num : *inbytesleft);
0 < num; --num) {
GET(c);
}
#endif /* defined(DISCARD) */
break;
case ITM_OP_DISCARD_D:
num = operation->data.itm_opnum;
TRACE_MESSAGE('o', ("ITM_OP_DISCARD_D: %ld\n", num));
#if defined(DISCARD)
DISCARD((num <= *inbytesleft) ? num : *inbytesleft);
#else /* defined(DISCARD) */
for (num = ((num <= *inbytesleft) ? num : *inbytesleft);
0 < num; --num) {
GET(c);
}
#endif /* defined(DISCARD) */
break;
case ITM_OP_IF:
c = eval_expr(ist, operation->data.operand[0],
*inbytesleft, *inbuf, *outbytesleft);
TRACE_MESSAGE('o', ("ITM_OP_IF: %ld\n", c));
if (c) {
retval = eval_op_tbl(ist, operation->data.operand[1],
inbuf, inbytesleft, outbuf, outbytesleft);
}
break;
case ITM_OP_IF_ELSE:
c = eval_expr(ist, operation->data.operand[0],
*inbytesleft, *inbuf, *outbytesleft);
TRACE_MESSAGE('o', ("ITM_OP_IF_ELSE: %ld\n", c));
if (c) {
retval = eval_op_tbl(ist, operation->data.operand[1],
inbuf, inbytesleft, outbuf, outbytesleft);
} else {
retval = eval_op_tbl(ist, operation->data.operand[2],
inbuf, inbytesleft, outbuf, outbytesleft);
}
break;
case ITM_OP_DIRECTION:
TRACE_MESSAGE('o', ("ITM_OP_DIRECTION: %p\n",
operation->data.operand[0].itm_ptr));
ist->direc = ADDR(operation->data.operand[0]);
return ((size_t)(-2));
case ITM_OP_MAP:
TRACE_MESSAGE('o', ("ITM_OP_MAP: %p\n",
operation->data.operand[0].itm_ptr));
i = 0;
if (0 != operation->data.operand[1].itm_ptr) {
#if defined(EVAL_EXPR)
i = EVAL_EXPR(1);
#else /* !defined(EVAL_EXPR) */
i = eval_expr(ist, operation->data.operand[1],
*inbytesleft, *inbuf, *outbytesleft);
#endif /* defined(EVAL_EXPR) */
(*inbytesleft) -= i;
(*inbuf) += i;
}
/*
* Based on what is the maptype, we call the corresponding
* mapping function.
*/
h = ADDR(operation->data.operand[0]);
t = h->type;
switch (t) {
case ITM_TBL_MAP_INDEX_FIXED:
case ITM_TBL_MAP_INDEX_FIXED_1_1:
retval = map_i_f(h, inbuf, inbytesleft,
outbuf, outbytesleft, 1);
break;
case ITM_TBL_MAP_HASH:
retval = map_h_l(h, inbuf, inbytesleft,
outbuf, outbytesleft, 1);
break;
case ITM_TBL_MAP_DENSE_ENC:
retval = map_d_e_l(h, inbuf, inbytesleft,
outbuf, outbytesleft, 1);
break;
case ITM_TBL_MAP_LOOKUP:
retval = map_l_f(h, inbuf, inbytesleft,
outbuf, outbytesleft, 1);
break;
default:
/*
* This should not be possible, but in case we
* have an incorrect maptype, don't fall back to
* map_i_f(). Instead, because it is an error, return
* an error. See CR 6622765.
*/
errno = EBADF;
TRACE_MESSAGE('e', ("eval_op:error=%d\n", errno));
retval = (size_t)-1;
break;
}
if ((size_t)(-1) == retval) {
(*outbytesleft) += i;
(*outbuf) -= i;
}
break;
case ITM_OP_OPERATION:
TRACE_MESSAGE('o', ("ITM_OP_OPERATION: %p\n",
operation->data.operand[0].itm_ptr));
retval = eval_op_tbl(ist, operation->data.operand[0],
inbuf, inbytesleft, outbuf, outbytesleft);
break;
case ITM_OP_INIT:
TRACE_MESSAGE('o', ("ITM_OP_INIT: %p\n",
ist->itm_hdr->op_init_tbl));
if (0 != ist->itm_hdr->op_init_tbl.itm_ptr) {
retval = eval_op_tbl(ist, ist->itm_hdr->op_init_tbl,
inbuf, inbytesleft, outbuf, outbytesleft);
} else {
op_init_default(ist);
retval = (size_t)-2;
}
break;
case ITM_OP_RESET:
TRACE_MESSAGE('o', ("ITM_OP_RESET: %p\n",
ist->itm_hdr->op_reset_tbl));
if (0 != ist->itm_hdr->op_reset_tbl.itm_ptr) {
retval = eval_op_tbl(ist, ist->itm_hdr->op_reset_tbl,
inbuf, inbytesleft, outbuf, outbytesleft);
} else {
op_reset_default(ist);
retval = (size_t)-2;
}
break;
case ITM_OP_BREAK:
TRACE_MESSAGE('o', ("ITM_OP_BREAK\n"));
return (RETVALBRK);
case ITM_OP_RETURN:
TRACE_MESSAGE('o', ("ITM_OP_RETURN\n"));
return (RETVALRET);
case ITM_OP_PRINTCHR:
c = eval_expr(ist, operation->data.operand[0], *inbytesleft,
*inbuf, *outbytesleft);
(void) fputc((uchar_t)c, stderr);
TRACE_MESSAGE('o', ("ITM_OP_PRINTCHR: %ld %ld\n",
c, *inbytesleft));
break;
case ITM_OP_PRINTHD:
c = eval_expr(ist, operation->data.operand[0], *inbytesleft,
*inbuf, *outbytesleft);
(void) fprintf(stderr, "%lx", c);
TRACE_MESSAGE('o', ("ITM_OP_PRINTHD: %ld %ld\n",
c, *inbytesleft));
break;
case ITM_OP_PRINTINT:
c = eval_expr(ist, operation->data.operand[0], *inbytesleft,
*inbuf, *outbytesleft);
(void) fprintf(stderr, "%ld", c);
TRACE_MESSAGE('o', ("ITM_OP_PRINTINT: %ld %ld\n",
c, *inbytesleft));
break;
default: /* never */
errno = ELIBBAD;
TRACE_MESSAGE('e', ("eval_op:error=%d\n", errno));
return (size_t)(-1);
}
return (retval);
#undef EVAL_EXPR
}
/*
* Evaluate expression
*/
static itm_num_t
eval_expr(
icv_state_t *ist,
itm_place_t expr_place,
size_t inbytesleft,
const unsigned char *inbuf,
size_t outbytesleft)
{
itm_expr_t *expr;
itm_expr_t *expr_op;
itm_num_t num;
unsigned char *p;
long i;
itm_expr_t *expr0;
itm_num_t num00;
itm_num_t num01;
#define EVAL_EXPR_E(n) (eval_expr(ist, expr->data.operand[(n)], \
inbytesleft, inbuf, outbytesleft))
#define EVAL_EXPR_D(n) ((itm_num_t)(expr->data.operand[(n)].itm_ptr))
#define EVAL_EXPR_R(n) (REG((itm_num_t)(expr->data.operand[(n)].itm_ptr)))
#define EVAL_EXPR_INVD(n) \
((num0 ## n) = ((itm_num_t)(expr->data.operand[(n)].itm_ptr)), \
((num0 ## n) < 0) ? \
(((-1) == (num0 ## n)) ? inbytesleft : 0) : \
(((num0 ## n) < inbytesleft) ? \
(*(unsigned char *)(inbuf + (num0 ## n))) : 0))
#define EVAL_EXPR(n) \
(expr0 = ADDR(expr->data.operand[(n)]), \
(itm_num_t)((expr0->type == ITM_EXPR_INT) ? \
expr0->data.itm_exnum : \
((expr0->type == ITM_EXPR_REG) ? \
REG(expr0->data.itm_exnum) : \
((expr0->type == ITM_EXPR_IN_VECTOR_D) ? \
((expr0->data.itm_exnum < 0) ? \
(((-1) == expr0->data.itm_exnum) ? inbytesleft : 0) : \
((expr0->data.itm_exnum < inbytesleft) ? \
(*(uchar_t *)(inbuf + expr0->data.itm_exnum)) : 0)) : \
eval_expr(ist, expr->data.operand[(n)], \
inbytesleft, inbuf, outbytesleft)))))
#define EVAL_OP_BIN_PROTO(op, name, name0, name1) \
case ITM_EXPR_##name##_##name0##_##name1: \
return (EVAL_EXPR_##name0(0) op EVAL_EXPR_##name1(1));
#define EVAL_OP_BIN1(op, name) \
EVAL_OP_BIN_PROTO(op, name, E, E) \
EVAL_OP_BIN_PROTO(op, name, E, D) \
EVAL_OP_BIN_PROTO(op, name, E, R) \
EVAL_OP_BIN_PROTO(op, name, E, INVD)
#define EVAL_OP_BIN2(op, name) \
EVAL_OP_BIN_PROTO(op, name, D, E) \
EVAL_OP_BIN_PROTO(op, name, D, D) \
EVAL_OP_BIN_PROTO(op, name, D, R) \
EVAL_OP_BIN_PROTO(op, name, D, INVD)
#define EVAL_OP_BIN3(op, name) \
EVAL_OP_BIN_PROTO(op, name, R, E) \
EVAL_OP_BIN_PROTO(op, name, R, D) \
EVAL_OP_BIN_PROTO(op, name, R, R) \
EVAL_OP_BIN_PROTO(op, name, R, INVD)
#define EVAL_OP_BIN4(op, name) \
EVAL_OP_BIN_PROTO(op, name, INVD, E) \
EVAL_OP_BIN_PROTO(op, name, INVD, D) \
EVAL_OP_BIN_PROTO(op, name, INVD, R) \
EVAL_OP_BIN_PROTO(op, name, INVD, INVD)
#define EVAL_OP_BIN_PROTECT_PROTO(op, name, name0, name1) \
case ITM_EXPR_##name##_##name0##_##name1: \
num = EVAL_EXPR_##name1(1); \
if (0 != num) { \
return (EVAL_EXPR_##name0(0) op num); \
} else { \
return (0); \
}
#define EVAL_OP_BIN_PROTECT1(op, name) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, E, E) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, E, D) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, E, R) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, E, INVD)
#define EVAL_OP_BIN_PROTECT2(op, name) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, D, E) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, D, D) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, D, R) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, D, INVD)
#define EVAL_OP_BIN_PROTECT3(op, name) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, R, E) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, R, D) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, R, R) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, R, INVD)
#define EVAL_OP_BIN_PROTECT4(op, name) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, INVD, E) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, INVD, D) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, INVD, R) \
EVAL_OP_BIN_PROTECT_PROTO(op, name, INVD, INVD)
expr = ADDR(expr_place);
switch (expr->type) {
case ITM_EXPR_NONE: /* not used */
return (0);
case ITM_EXPR_NOP: /* not used */
return (0);
case ITM_EXPR_NAME: /* not used */
return (0);
case ITM_EXPR_INT: /* integer */
return (expr->data.itm_exnum);
case ITM_EXPR_SEQ: /* byte sequence */
if ((sizeof (itm_place_t)) < expr->data.value.size) {
p = (unsigned char *)ADDR(expr->data.value.place);
} else {
p = (unsigned char *)&(expr->data.value.place);
}
for (i = 0, num = 0; i < expr->data.value.size; i++, p++) {
num = ((num << 8) | *p);
}
return (num);
case ITM_EXPR_REG: /* register */
return (REG(expr->data.itm_exnum));
case ITM_EXPR_IN_VECTOR: /* in[expr] */
num = EVAL_EXPR(0);
if ((0 <= num) && (num < inbytesleft)) {
return (*((unsigned char *)(inbuf + num)));
} else if ((-1) == num) {
return (inbytesleft);
} else {
return (0);
}
case ITM_EXPR_IN_VECTOR_D: /* in[DECIMAL] */
num = expr->data.itm_exnum;
if ((0 <= num) && (num < inbytesleft)) {
return (*((unsigned char *)(inbuf + num)));
} else if ((-1) == num) {
return (inbytesleft);
} else {
return (0);
}
case ITM_EXPR_OUT: /* out */
return (outbytesleft);
case ITM_EXPR_TRUE: /* true */
return (1);
case ITM_EXPR_FALSE: /* false */
return (0);
case ITM_EXPR_UMINUS: /* unary minus */
return ((-1) * EVAL_EXPR(0));
#define PLUS_FOR_CSTYLE_CLEAN +
#define MINUS_FOR_CSTYLE_CLEAN -
#define MUL_FOR_CSTYLE_CLEAN *
#define DIV_FOR_CSTYLE_CLEAN /
#define MOD_FOR_CSTYLE_CLEAN %
#define SHIFT_L_FOR_CSTYLE_CLEAN <<
#define SHIFT_R_FOR_CSTYLE_CLEAN >>
#define OR_FOR_CSTYLE_CLEAN |
#define XOR_FOR_CSTYLE_CLEAN ^
#define AND_FOR_CSTYLE_CLEAN &
#define EQ_FOR_CSTYLE_CLEAN ==
#define NE_FOR_CSTYLE_CLEAN !=
#define GT_FOR_CSTYLE_CLEAN >
#define GE_FOR_CSTYLE_CLEAN >=
#define LT_FOR_CSTYLE_CLEAN <
#define LE_FOR_CSTYLE_CLEAN <=
EVAL_OP_BIN1(PLUS_FOR_CSTYLE_CLEAN, PLUS) /* A + B */
EVAL_OP_BIN2(PLUS_FOR_CSTYLE_CLEAN, PLUS) /* A + B */
EVAL_OP_BIN3(PLUS_FOR_CSTYLE_CLEAN, PLUS) /* A + B */
EVAL_OP_BIN4(PLUS_FOR_CSTYLE_CLEAN, PLUS) /* A + B */
EVAL_OP_BIN1(MINUS_FOR_CSTYLE_CLEAN, MINUS) /* A - B */
EVAL_OP_BIN2(MINUS_FOR_CSTYLE_CLEAN, MINUS) /* A - B */
EVAL_OP_BIN3(MINUS_FOR_CSTYLE_CLEAN, MINUS) /* A - B */
EVAL_OP_BIN4(MINUS_FOR_CSTYLE_CLEAN, MINUS) /* A - B */
EVAL_OP_BIN1(MUL_FOR_CSTYLE_CLEAN, MUL) /* A * B */
EVAL_OP_BIN2(MUL_FOR_CSTYLE_CLEAN, MUL) /* A * B */
EVAL_OP_BIN3(MUL_FOR_CSTYLE_CLEAN, MUL) /* A * B */
EVAL_OP_BIN4(MUL_FOR_CSTYLE_CLEAN, MUL) /* A * B */
EVAL_OP_BIN_PROTECT1(DIV_FOR_CSTYLE_CLEAN, DIV) /* A / B */
EVAL_OP_BIN_PROTECT2(DIV_FOR_CSTYLE_CLEAN, DIV) /* A / B */
EVAL_OP_BIN_PROTECT3(DIV_FOR_CSTYLE_CLEAN, DIV) /* A / B */
EVAL_OP_BIN_PROTECT4(DIV_FOR_CSTYLE_CLEAN, DIV) /* A / B */
EVAL_OP_BIN_PROTECT1(MOD_FOR_CSTYLE_CLEAN, MOD) /* A % B */
EVAL_OP_BIN_PROTECT2(MOD_FOR_CSTYLE_CLEAN, MOD) /* A % B */
EVAL_OP_BIN_PROTECT3(MOD_FOR_CSTYLE_CLEAN, MOD) /* A % B */
EVAL_OP_BIN_PROTECT4(MOD_FOR_CSTYLE_CLEAN, MOD) /* A % B */
EVAL_OP_BIN1(SHIFT_L_FOR_CSTYLE_CLEAN, SHIFT_L) /* A << B */
EVAL_OP_BIN2(SHIFT_L_FOR_CSTYLE_CLEAN, SHIFT_L) /* A << B */
EVAL_OP_BIN3(SHIFT_L_FOR_CSTYLE_CLEAN, SHIFT_L) /* A << B */
EVAL_OP_BIN4(SHIFT_L_FOR_CSTYLE_CLEAN, SHIFT_L) /* A << B */
EVAL_OP_BIN1(SHIFT_R_FOR_CSTYLE_CLEAN, SHIFT_R) /* A >> B */
EVAL_OP_BIN2(SHIFT_R_FOR_CSTYLE_CLEAN, SHIFT_R) /* A >> B */
EVAL_OP_BIN3(SHIFT_R_FOR_CSTYLE_CLEAN, SHIFT_R) /* A >> B */
EVAL_OP_BIN4(SHIFT_R_FOR_CSTYLE_CLEAN, SHIFT_R) /* A >> B */
EVAL_OP_BIN1(OR_FOR_CSTYLE_CLEAN, OR) /* A | B */
EVAL_OP_BIN2(OR_FOR_CSTYLE_CLEAN, OR) /* A | B */
EVAL_OP_BIN3(OR_FOR_CSTYLE_CLEAN, OR) /* A | B */
EVAL_OP_BIN4(OR_FOR_CSTYLE_CLEAN, OR) /* A | B */
EVAL_OP_BIN1(XOR_FOR_CSTYLE_CLEAN, XOR) /* A ^ B */
EVAL_OP_BIN2(XOR_FOR_CSTYLE_CLEAN, XOR) /* A ^ B */
EVAL_OP_BIN3(XOR_FOR_CSTYLE_CLEAN, XOR) /* A ^ B */
EVAL_OP_BIN4(XOR_FOR_CSTYLE_CLEAN, XOR) /* A ^ B */
EVAL_OP_BIN1(AND_FOR_CSTYLE_CLEAN, AND) /* A & B */
EVAL_OP_BIN2(AND_FOR_CSTYLE_CLEAN, AND) /* A & B */
EVAL_OP_BIN3(AND_FOR_CSTYLE_CLEAN, AND) /* A & B */
EVAL_OP_BIN4(AND_FOR_CSTYLE_CLEAN, AND) /* A & B */
EVAL_OP_BIN1(EQ_FOR_CSTYLE_CLEAN, EQ) /* A == B */
EVAL_OP_BIN2(EQ_FOR_CSTYLE_CLEAN, EQ) /* A == B */
EVAL_OP_BIN3(EQ_FOR_CSTYLE_CLEAN, EQ) /* A == B */
EVAL_OP_BIN4(EQ_FOR_CSTYLE_CLEAN, EQ) /* A == B */
EVAL_OP_BIN1(NE_FOR_CSTYLE_CLEAN, NE) /* A != B */
EVAL_OP_BIN2(NE_FOR_CSTYLE_CLEAN, NE) /* A != B */
EVAL_OP_BIN3(NE_FOR_CSTYLE_CLEAN, NE) /* A != B */
EVAL_OP_BIN4(NE_FOR_CSTYLE_CLEAN, NE) /* A != B */
EVAL_OP_BIN1(GT_FOR_CSTYLE_CLEAN, GT) /* A > B */
EVAL_OP_BIN2(GT_FOR_CSTYLE_CLEAN, GT) /* A > B */
EVAL_OP_BIN3(GT_FOR_CSTYLE_CLEAN, GT) /* A > B */
EVAL_OP_BIN4(GT_FOR_CSTYLE_CLEAN, GT) /* A > B */
EVAL_OP_BIN1(GE_FOR_CSTYLE_CLEAN, GE) /* A >= B */
EVAL_OP_BIN2(GE_FOR_CSTYLE_CLEAN, GE) /* A >= B */
EVAL_OP_BIN3(GE_FOR_CSTYLE_CLEAN, GE) /* A >= B */
EVAL_OP_BIN4(GE_FOR_CSTYLE_CLEAN, GE) /* A >= B */
EVAL_OP_BIN1(LT_FOR_CSTYLE_CLEAN, LT) /* A < B */
EVAL_OP_BIN2(LT_FOR_CSTYLE_CLEAN, LT) /* A < B */
EVAL_OP_BIN3(LT_FOR_CSTYLE_CLEAN, LT) /* A < B */
EVAL_OP_BIN4(LT_FOR_CSTYLE_CLEAN, LT) /* A < B */
EVAL_OP_BIN1(LE_FOR_CSTYLE_CLEAN, LE) /* A <= B */
EVAL_OP_BIN2(LE_FOR_CSTYLE_CLEAN, LE) /* A <= B */
EVAL_OP_BIN3(LE_FOR_CSTYLE_CLEAN, LE) /* A <= B */
EVAL_OP_BIN4(LE_FOR_CSTYLE_CLEAN, LE) /* A <= B */
case ITM_EXPR_NOT: /* !A */
return (!(EVAL_EXPR(0)));
case ITM_EXPR_NEG: /* ~A */
return (~(EVAL_EXPR(0)));
case ITM_EXPR_LOR: /* A || B */
if (0 != (num = EVAL_EXPR(0)))
return (num);
if (0 != (num = EVAL_EXPR(1)))
return (num);
return (0);
case ITM_EXPR_LAND: /* A && B */
if (0 == EVAL_EXPR(0))
return (0);
if (0 == (num = EVAL_EXPR(1)))
return (0);
return (num);
case ITM_EXPR_ASSIGN: /* A = B */
num = EVAL_EXPR(1);
if (expr->data.operand[0].itm_ptr < ist->itm_hdr->reg_num) {
return (*(ist->regs + expr->data.operand[0].itm_ptr)
= num);
} else {
return (0);
}
case ITM_EXPR_IN_EQ: /* in == A */
expr_op = ADDR(expr->data.operand[0]);
switch (expr_op->type) {
case ITM_EXPR_SEQ:
if (inbytesleft < expr_op->data.value.size) {
return (0);
}
p = DADDR(&(expr_op->data.value));
for (i = 0; i < expr_op->data.value.size; i++, p++) {
if (*p != *(inbuf + i)) {
return (0);
}
}
return (1);
default:
num = EVAL_EXPR(0);
return (num == *((unsigned char *)inbuf));
}
default:
break;
}
return (0);
#undef EVAL_EXPR_E
#undef EVAL_EXPR_D
#undef EVAL_EXPR_R
#undef EVAL_EXPR_INVD
#undef EVAL_EXPR
}
/*
* maintain ITM reference information
*/
static void
itm_ref_free(int fd, void *ptr0, void *ptr1, void *ptr2, size_t len)
{
int r;
r = errno;
if (0 <= fd) {
(void) close(fd);
}
free(ptr0);
free(ptr1);
if (0 < len) {
(void) munmap(ptr2, len);
}
errno = r;
}
static itm_ref_t *
itm_ref_inc(const char *itm)
{
itm_ref_t *ref;
itm_hdr_t *hdr;
struct stat st;
int fd;
fd = open(itm, O_RDONLY, 0);
if (fd == -1) {
itm_ref_free(-1, NULL, NULL, NULL, 0);
return (NULL);
}
if (fstat(fd, &st) == -1) {
itm_ref_free(fd, NULL, NULL, NULL, 0);
return (NULL);
}
hdr = (void *) mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (MAP_FAILED == hdr) {
itm_ref_free(fd, NULL, NULL, NULL, 0);
return (NULL);
}
(void) close(fd);
ref = malloc(sizeof (itm_ref_t));
if (NULL == ref) {
itm_ref_free(-1, NULL, NULL, hdr, st.st_size);
return (NULL);
}
ref->name = malloc(strlen(itm) + 1);
if (NULL == ref->name) {
itm_ref_free(-1, ref, NULL, hdr, st.st_size);
return (NULL);
}
(void) strcpy(ref->name, itm);
ref->hdr = hdr;
ref->len = st.st_size;
if ((hdr->ident[0] != ITM_IDENT_0) ||
(hdr->ident[1] != ITM_IDENT_1) ||
(hdr->ident[2] != ITM_IDENT_2) ||
(hdr->ident[3] != ITM_IDENT_3) ||
(hdr->spec[0] != ITM_SPEC_0) ||
(hdr->spec[1] != ITM_SPEC_1) ||
(hdr->spec[2] != ITM_SPEC_2) ||
#if defined(_LITTLE_ENDIAN)
#if defined(_LP64)
((hdr->spec[3] != ITM_SPEC_3_32_LITTLE_ENDIAN) &&
(hdr->spec[3] != ITM_SPEC_3_64_LITTLE_ENDIAN)) ||
#else
(hdr->spec[3] != ITM_SPEC_3_32_LITTLE_ENDIAN) ||
#endif
#else
#if defined(_LP64)
((hdr->spec[3] != ITM_SPEC_3_32_BIG_ENDIAN) &&
(hdr->spec[3] != ITM_SPEC_3_64_BIG_ENDIAN)) ||
#else
(hdr->spec[3] != ITM_SPEC_3_32_BIG_ENDIAN) ||
#endif
#endif
(hdr->version[0] != ITM_VER_0) ||
(hdr->version[1] != ITM_VER_1) ||
(hdr->version[2] != ITM_VER_2) ||
(hdr->version[3] != ITM_VER_3) ||
(((size_t)(hdr->itm_size.itm_ptr)) != st.st_size)) {
itm_ref_free(-1, ref, ref->name, ref->hdr, ref->len);
errno = ELIBBAD;
TRACE_MESSAGE('e', ("itm_ref_inc:error=%d\n", errno));
return (NULL);
}
return (ref);
}
static void
itm_ref_dec(itm_ref_t *ref)
{
(void) munmap((char *)(ref->hdr), ref->len);
free(ref->name);
free(ref);
}
static void
op_init_default(icv_state_t *ist)
{
ist->direc = ADDR(ist->itm_hdr->direc_init_tbl);
regs_init(ist);
}
static void
op_reset_default(icv_state_t *ist)
{
ist->direc = ADDR(ist->itm_hdr->direc_init_tbl);
regs_init(ist);
}
static void
regs_init(icv_state_t *ist)
{
if (0 < ist->itm_hdr->reg_num) {
(void) memset(ist->regs, 0,
(sizeof (itm_num_t)) * ist->itm_hdr->reg_num);
}
}
#if defined(DEBUG)
static void
trace_init()
{
char *env_val;
char *p;
env_val = getenv("ITM_INT_TRACE");
if (NULL == env_val)
return;
for (p = env_val; *p; p++) {
trace_option[(*p) & 0x007f] = 1;
}
}
static void
trace_message(char *format, ...)
{
va_list ap;
va_start(ap, format);
(void) vfprintf(stderr, format, ap);
va_end(ap);
}
#endif /* DEBUG */