123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718 |
- /*
- * 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
- if(_rpn_expr_reset_map(expr) < 0)
- {
- snprintf(expr->err_reason, 128,
- "Unable to re-init code map : %s", strerror(errno));
- expr->state = RPN_ERROR;
- return -1;
- }
- 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_recompile(rpn_expr_t *expr, const char *code)
- {
- if(rpn_expr_reinit(expr) < 0)
- {
- return -1;
- }
- return rpn_expr_compile(expr, code);
- }
-
- int rpn_expr_tokens_updated(rpn_expr_t* expr)
- {
- if(rpn_expr_reinit(expr) < 0)
- {
- return -1;
- }
- if(_rpn_expr_compile_tokens(expr) < 0)
- {
- expr->state = RPN_ERROR;
- return -1;
- }
- if(expr->expr)
- {
- free(expr->expr);
- }
- expr->expr = rpn_tokenized_expr(&expr->toks, 0);
- expr->state = RPN_READY;
- 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, const 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 == EUCLEAN)
- {
- 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)
- {
- const int BUFF_ALLOC = 4096;
-
- 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 < BUFF_ALLOC / 4)
- {
- buff_sz += BUFF_ALLOC;
- 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;
- }
- }
- if(offset)
- {
- buff[offset-1] = '\0';
- }
- return buff;
- }
-
- size_t rpn_expr_serialize(rpn_expr_t* expr, void *buf, size_t buf_sz)
- {
- const size_t total_sz = sizeof(rpn_expr_serial_t) + \
- (sizeof(rpn_token_t)*expr->toks.tokens_sz) + \
- (sizeof(rpn_value_t)*expr->stack_sz);
-
- if(total_sz < buf_sz || !buf)
- {
- return total_sz;
- }
-
- bzero(buf, total_sz);
-
- rpn_expr_serial_t *ser = buf;
- rpn_token_t *tokens = (void*)buf + sizeof(*ser);
- rpn_value_t *stack = (void*)(tokens + expr->toks.tokens_sz);
-
- ser->token_sz = expr->toks.tokens_sz;
- ser->stack_sz = expr->stack_sz;
- ser->argc = expr->toks.argc;
- ser->state = expr->state;
- memcpy(ser->err_reason, expr->err_reason, sizeof(ser->err_reason));
- memcpy(stack, expr->stack, expr->stack_sz);
-
- for(size_t i=0; i < ser->token_sz; i++)
- {
- tokens[i].type = expr->toks.tokens[i].type;
- switch(expr->toks.tokens[i].type)
- {
- case RPN_arg:
- tokens[i].arg_n = expr->toks.tokens[i].arg_n;
- break;
- case RPN_val:
- tokens[i].value = expr->toks.tokens[i].value;
- break;
- case RPN_op:
- tokens[i].op_n = expr->toks.tokens[i].op_n;
- break;
- default:
- // SHOULD NEVER APPEND !
- errno = EINVAL;
- goto err;
- }
- }
-
- return total_sz;
-
- err:
- return 0;
- }
-
-
- int rpn_expr_deserialize(rpn_expr_t* expr, const void *buf, size_t buf_sz)
- {
- int err = EINVAL;
- const rpn_expr_serial_t *ser = buf;
-
- if(!expr)
- {
- errno = EINVAL;
- return -1;
- }
-
- if(buf_sz < sizeof(rpn_expr_serial_t))
- {
- snprintf(expr->err_reason, 128,
- "Given buffer is to small (%ld bytes) to deserialize", buf_sz);
- err = EINVAL;
- goto err;
- }
-
- const size_t total_sz = sizeof(rpn_expr_serial_t) + \
- (sizeof(rpn_token_t)*ser->token_sz) + \
- (sizeof(rpn_value_t)*ser->stack_sz);
- if(buf_sz < total_sz)
- {
- snprintf(expr->err_reason, 128,
- "Expected %ld bytes but %ld given",
- total_sz, buf_sz);
- err = EINVAL;
- goto err;
- }
-
- rpn_token_t *tokens = (void*)buf + sizeof(*ser);
- rpn_value_t *stack = (void*)(tokens + ser->token_sz);
-
- if(rpn_expr_init(expr, ser->stack_sz, ser->argc) < 0)
- {
- err = EINVAL;
- goto err;
- }
-
- expr->state = ser->state;
- memcpy(expr->err_reason, ser->err_reason, 128);
- memcpy(expr->stack, stack, sizeof(rpn_value_t)*ser->stack_sz);
-
- expr->args_count = expr->toks.argc = ser->argc;
-
- rpn_tokenized_t toks;
- toks.argc = ser->argc;
- toks.tokens_sz = ser->token_sz;
- toks.tokens = malloc(sizeof(rpn_token_t)*ser->token_sz);
- if(!toks.tokens)
- {
- err = errno;
- snprintf(expr->err_reason, 128,
- "Unable to allocate tokens : %s",
- strerror(errno));
- goto err_expr;
- }
-
-
- for(size_t i=0; i < ser->token_sz; i++)
- {
- toks.tokens[i].type = tokens[i].type;
- switch(tokens[i].type)
- {
- case RPN_val:
- toks.tokens[i].value = tokens[i].value;
- break;
- case RPN_arg:
- toks.tokens[i].arg_n = tokens[i].arg_n;
- break;
- case RPN_op:
- toks.tokens[i].op_n = tokens[i].op_n;
- toks.tokens[i].op = &(rpn_ops[tokens[i].op_n]);
- break;
- default:
- snprintf(expr->err_reason, 128,
- "Invalid token type encountered %d", tokens[i].type);
- err = EINVAL;
- goto err_expr;
- }
- }
-
- if(rpn_expr_untokenize(expr, &toks, 0) < 0)
- {
- err = EINVAL;
- goto err_expr;
- }
-
- expr->toks = toks;
-
- return 0;
-
- err_expr:
- rpn_expr_close(expr);
- err:
- expr->state = RPN_ERROR;
- errno = err;
- return -1;
- }
-
-
- 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 == EUCLEAN)
- {
- 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 == EUCLEAN)
- {
- 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;
- rpn_value_t 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:
- if(expr->args_count <= token->arg_n)
- {
- errno = EINVAL;
- return -1;
- }
- 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 = EUCLEAN;
- 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;
- }
-
- int _rpn_expr_reset_map(rpn_expr_t *expr)
- {
- if(!expr->code_map_sz)
- {
- return _rpn_expr_init_map(expr);
- }
- if(mprotect(expr->code_map, expr->code_map_sz,
- PROT_READ | PROT_WRITE))
- {
- return -1;
- }
- bzero(expr->code_map, expr->code_map_sz);
- return 0;
- }
|