123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- /*
- * Copyright (C) 2020 Weber Yann
- *
- * This file is part of pyrpn.
- *
- * pyrpn is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * any later version.
- *
- * pyrpn is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with pyrpn. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "rpn_jit.h"
-
- int rpn_expr_init(rpn_expr_t* expr, const unsigned char stack_sz,
- const size_t args_count)
- {
- #ifdef DEBUG
- if(!expr)
- {
- dprintf(2, "Error, NULL ptr given as expression to rpn_expr_init");
- errno = EINVAL;
- return -1;
- }
- #endif
- bzero(expr, sizeof(rpn_expr_t));
-
- expr->stack_sz = stack_sz;
- expr->args_count = args_count;
-
- expr->state = RPN_SOURCE;
- memset(expr->err_reason, (int)'\0', 128);
-
- expr->stack = malloc(sizeof(unsigned long) * stack_sz);
- if(!expr->stack)
- {
- snprintf(expr->err_reason, 128,
- "Unable to malloc stack : %s", strerror(errno));
- expr->state = RPN_ERROR;
- return -1;
- }
- bzero(expr->stack, sizeof(unsigned long) * stack_sz);
-
- if(_rpn_expr_init_map(expr) < 0)
- {
- snprintf(expr->err_reason, 128,
- "Unable to init code map : %s", strerror(errno));
- free(expr->expr);
- expr->state = RPN_ERROR;
- return -1;
- }
- return 0;
- }
-
- int rpn_expr_reinit(rpn_expr_t* expr)
- {
- #ifdef DEBUG
- if(!expr)
- {
- dprintf(2, "Error, NULL ptr given as expression to rpn_expr_compile");
- errno = EINVAL;
- return -1;
- }
- #endif
- bzero(expr->code_map, expr->code_map_sz);
- bzero(expr->stack, sizeof(unsigned long) * expr->stack_sz);
- if(_rpn_expr_init_map(expr) < 0)
- {
- snprintf(expr->err_reason, 128,
- "Unable to re-init code map : %s", strerror(errno));
- free(expr->expr);
- expr->state = RPN_ERROR;
- return -1;
- }
- return 0;
- }
-
- int rpn_expr_compile(rpn_expr_t *expr, const char *code)
- {
- #ifdef DEBUG
- if(!expr)
- {
- dprintf(2, "Error, NULL ptr given as expression to rpn_expr_compile");
- errno = EINVAL;
- return -1;
- }
- #endif
- expr->expr = strdup(code);
- if(!expr->expr)
- {
- snprintf(expr->err_reason, 128,
- "Unable to strdup expression : %s", strerror(errno));
- expr->state = RPN_ERROR;
- return -1;
- }
- return _rpn_expr_compile_expr(expr);
- }
-
- int rpn_expr_untokenize(rpn_expr_t *expr, rpn_tokenized_t *tokens, char long_op)
- {
- int err;
- size_t i;
-
-
- errno = 0;
- #ifdef DEBUG
- if(!expr)
- {
- dprintf(2, "Error, NULL ptr given as expression to rpn_expr_untokenize");
- err = EINVAL;
- goto ret_err;
- }
- if(tokens->argc != expr->args_count)
- {
- /* even if it should work with tokens->argc < expr->args_count */
- snprintf(expr->err_reason, 128,
- "Expression argc differ from tokenized version");
- err = EINVAL;
- goto ret_err;
- }
- #endif
- if(!(expr->expr = rpn_tokenized_expr(tokens, long_op)))
- {
- err = errno;
- snprintf(expr->err_reason, 128,
- "Error reading tokenized expression : %s",
- strerror(err));
- goto ret_err;
- }
-
- for(i=0; i<tokens->tokens_sz; i++)
- {
- if(_rpn_expr_token_copy(expr, &(tokens->tokens[i])) < 0)
- {
- err = errno;
- if(errno == EINVAL)
- {
- dprintf(2,
- "Fatal error, unknown token type : %d.\nMemory corruption ?\n",
- tokens->tokens[i].type);
- exit(1);
- }
- snprintf(expr->err_reason, 128,
- "Untokenize error : %s",
- strerror(err));
- goto ret_err;
- }
- }
-
- if(_rpn_expr_end_map(expr))
- {
- snprintf(expr->err_reason, 128,
- "Error ending code map : %s",
- strerror(errno));
- expr->state = RPN_ERROR;
- return -1;
- }
-
- expr->state = RPN_READY;
- return 0;
-
- ret_err:
- expr->state = RPN_ERROR;
- errno = err;
- return -1;
- }
-
- char* rpn_random(size_t op_sz, size_t args_count)
- {
- double step;
- size_t i, buff_sz, offset, rnd;
- char *buff, *cur;
- unsigned char op_n;
- unsigned long int seed, rnd_val;
- int nchr, err;
-
- buff_sz = offset = 0;
- buff = NULL;
- step = 1.0 / (rpn_op_sz() + (args_count>0?2:1)); // + args and values
-
- if(getrandom(&seed, sizeof(long int), 0) < 0)
- {
- err=errno;
- perror("Fails to get a random number from kernel");
- errno=err;
- return NULL;
- }
- srand48(seed);
-
- for(i=0; i<op_sz; i++)
- {
- if(buff_sz - offset < 21)
- {
- buff_sz += 40;
- cur = realloc(buff, sizeof(char) * buff_sz);
- if(!cur)
- {
- err=errno;
- perror("Error allocating random expression");
- errno=err;
- return NULL;
- }
- buff=cur;
- }
- cur = buff + offset;
- *cur = '\0';
- op_n = drand48() / step;
- if(op_n < rpn_op_sz())
- {
- cur[0] = rpn_ops[op_n].chr;
- cur[1] = ' ';
- cur[2] = '\0';
- offset += 2;
- }
- else if(op_n == rpn_op_sz())
- {
-
- if(getrandom(&rnd_val, sizeof(long int), 0) < 0)
- {
- err=errno;
- perror("Fails to get a random number for value");
- errno=err;
- return NULL;
- }
- // values
- if((nchr = sprintf(cur, "0x%lX ", rnd_val)) < 0)
- {
- err=errno;
- perror("Error while sprintf arguments in random generator");
- errno=err;
- return NULL;
- }
- offset += nchr;
- }
- else
- {
- rnd = drand48() / (1.0 / args_count);
- // arguments
- if((nchr = sprintf(cur, "A%ld ", rnd)) < 0)
- {
- err=errno;
- perror("Error while sprintf arguments in random generator");
- errno=err;
- return NULL;
- }
- offset += nchr;
- }
- }
- buff[offset] = '\0';
- return buff;
- }
-
- int _rpn_expr_compile_expr(rpn_expr_t* expr)
- {
- rpn_tokenizer_t tokenizer;
- rpn_token_t *token;
-
-
- if(expr->state == RPN_ERROR)
- {
- goto err;
- }
-
- if(rpn_tokenizer_start(&tokenizer, &(expr->toks), expr->expr,
- expr->args_count) < 0)
- {
- snprintf(expr->err_reason, 128,
- "Error starting tokenizer : %s",
- tokenizer.err_reason);
- goto err;
- }
-
- while((token = rpn_tok(&tokenizer)))
- {
- if(_rpn_expr_token_copy(expr, token) < 0)
- {
- if(errno == EINVAL)
- {
- dprintf(2,
- "Fatal error, unknown token type : %d chr %ld.\nMemory corruption ?\n",
- token->type, tokenizer.chr_no);
- exit(1);
- }
- snprintf(expr->err_reason, 128,
- "Compilation error on chr %ld, unable to copy code part : %s",
- tokenizer.chr_no, strerror(errno));
- goto err;
- }
- }
- if(rpn_tokenizer_error(&tokenizer))
- {
- snprintf(expr->err_reason, 128,
- "Compilation error, chr %ld : %s",
- tokenizer.chr_no, tokenizer.err_reason);
- goto err;
- }
-
- if(_rpn_expr_end_map(expr))
- {
- snprintf(expr->err_reason, 128,
- "Error ending code map : %s",
- strerror(errno));
- expr->state = RPN_ERROR;
- return -1;
- }
-
- expr->state = RPN_READY;
- return 0;
- err:
- expr->state = RPN_ERROR;
- return -1;
- }
-
- int _rpn_expr_compile_tokens(rpn_expr_t* expr)
- {
- size_t i;
- rpn_token_t *token;
- for(i=0; i<expr->toks.tokens_sz; i++)
- {
- token = &(expr->toks.tokens[i]);
- if(_rpn_expr_token_copy(expr, token) < 0)
- {
- if(errno == EINVAL)
- {
- dprintf(2,
- "Fatal error, unknown token type : %d\nMemory corruption ?\n",
- token->type);
- exit(1);
- }
- snprintf(expr->err_reason, 128,
- "Compilation error, unable to copy code part : %s",
- strerror(errno));
- expr->state = RPN_ERROR;
- return -1;
- }
-
- }
-
- if(_rpn_expr_end_map(expr))
- {
- snprintf(expr->err_reason, 128,
- "Error ending code map : %s",
- strerror(errno));
- expr->state = RPN_ERROR;
- return -1;
- }
-
- expr->state = RPN_READY;
- return 0;
- }
-
- unsigned long rpn_expr_eval(rpn_expr_t *expr, unsigned long *args)
- {
- rpn_run_f expr_run;
- unsigned long int res;
- if(expr->state == RPN_ERROR)
- {
- return 0;
- }
- expr_run = expr->code_map;
- res = expr_run(expr->stack_sz, args, expr->stack);
- return res;
- }
-
- void rpn_expr_close(rpn_expr_t* expr)
- {
- if(expr->expr)
- {
- free(expr->expr);
- expr->expr = NULL;
- }
- if(expr->stack)
- {
- free(expr->stack);
- expr->stack = NULL;
- }
- if(expr->code_map)
- {
- if(munmap(expr->code_map, expr->code_map_sz))
- {
- perror("Unable to unmap code_map");
- }
- expr->code_map = NULL;
- }
- }
-
- void rpn_expr_reset_stack(rpn_expr_t *expr)
- {
- bzero(expr->stack, sizeof(unsigned long) * expr->stack_sz);
- }
-
- int _rpn_expr_token_copy(rpn_expr_t *expr, rpn_token_t *token)
- {
- unsigned long int *value;
- rpn_op_t local_op;
- value = NULL;
- switch(token->type)
- {
- case RPN_op:
- local_op = *(token->op);
- value = NULL;
- break;
- case RPN_arg:
- local_op.fun = &rpn_arg;
- local_op.fun_sz = &(CODE_SZ(rpn_arg));
- value = &(token->arg_n);
- break;
- case RPN_val:
- local_op.fun = &rpn_value;
- local_op.fun_sz = &(CODE_SZ(rpn_value));
- value = &(token->value);
- break;
- default:
- errno = EINVAL;
- return -1;
- }
- if(_rpn_code_part_cpy(expr, local_op.fun, *(local_op.fun_sz),
- value))
- {
- return -1;
- }
- return 0;
- }
-
- int _rpn_code_part_cpy(rpn_expr_t *expr, const void *code_part,
- unsigned long code_part_sz, const unsigned long *value)
- {
- size_t old_sz, code_sz;
- void *new_ptr;
- //printf("DEBUG _copy : %p %ld %p:%ld\n", code_part, code_part_sz, value, value?*value:0);
- code_sz = expr->code_map_ptr - expr->code_map;
- if(!expr->code_map_sz)
- {
- errno = EINVAL;
- return -1;
- }
- if(code_sz + code_part_sz >= expr->code_map_sz)
- {
- old_sz = expr->code_map_sz;
- expr->code_map_sz = (((code_sz + code_part_sz)>>9)+1)<<9;
- new_ptr = mremap(expr->code_map, old_sz, expr->code_map_sz,
- MREMAP_MAYMOVE);
- if(new_ptr == (void*)-1)
- {
- expr->code_map_sz = 0;
- return -1;
- }
- expr->code_map = new_ptr;
- expr->code_map_ptr = expr->code_map + code_sz;
- }
- memcpy(expr->code_map_ptr, code_part, code_part_sz);
-
- if(value)
- {
- // set 1st instruction argument
- *(unsigned long*)(expr->code_map_ptr + 2) = *value;
- }
-
- expr->code_map_ptr += code_part_sz;
- return 0;
- }
-
- int _rpn_expr_init_map(rpn_expr_t* expr)
- {
- if(!expr->code_map_sz)
- {
- expr->code_map_sz = RPN_MAP_CHUNK;
- expr->code_map = mmap(NULL, expr->code_map_sz, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if(!expr->code_map)
- {
- return -1;
- }
- }
- expr->code_map_ptr = expr->code_map;
- if(CODE_PART_CPY(expr, rpn_exec))
- {
- return -1;
- }
- return 0;
- }
-
- int _rpn_expr_end_map(rpn_expr_t *expr)
- {
- if(CODE_PART_CPY(expr, rpn_exec_ret))
- {
- return -1;
- }
- if(mprotect(expr->code_map, expr->code_map_ptr - expr->code_map,
- PROT_EXEC))
- {
- return -1;
- }
- return 0;
- }
|