/* * 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. */ #include #include #include #include #include #include #include #include #include #include #if defined(DEBUG) #include #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 (0 == 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 */