void test_integration(void) { function_t *f = function_create("2**x - log(x)"); ASSERT_EQ(integrate_simpson(f, 0.5, 2.3), 4.60212); function_destroy(f); f = function_create("1/x - sin(x)**3"); ASSERT_EQ(integrate_simpson(f, 2.45, 8.145), 1.54018); function_destroy(f); }
void test_arclength(void) { function_t *f = function_create("2**x - log(x)"); ASSERT_EQ(arc_length(f, 0.5, 2.3), 3.0663188081); function_destroy(f); f = function_create("1/x + sin(x)**0.3"); ASSERT_EQ(arc_length(f, 0.5, 2.3), 2.4417982309); function_destroy(f); f = function_create("3.5*x**4 - 30.3*x**3 + 7.2*x**2 - 3.4*x + 32.0"); ASSERT_EQ(arc_length(f, -5, 7), 8109.52041086); function_destroy(f); f = function_create("3.5*x**4 - 7.2*x**2 - 3.4*x - 32.0"); ASSERT_EQ(arc_length(f, -1.5, 0.73), 14.196939434); function_destroy(f); }
void test_derivates(void) { function_t *f = function_create("x**2"); ASSERT_EQ(derivate_1(f, 0.2), 0.4); ASSERT_EQ(derivate_1(f, 0.0), 0.0); ASSERT_EQ(derivate_2(f, 0.0), 2.0); function_destroy(f); f = function_create("cos(x) - x**3"); ASSERT_EQ(derivate_1(f, 5.0), -75.0-sinl(5.0)); ASSERT_EQ(derivate_1(f, 0.0), 0.0); ASSERT_EQ(derivate_2(f, 0.0), -1.0); ASSERT_EQ(derivate_2(f, 3.75), -21.6794); ASSERT_EQ(derivate(f, 3, -34.2), -6.34995); ASSERT_EQ(derivate(f, 3, -3.2), -5.94163); function_destroy(f); f = function_create("2**x - log(x)"); ASSERT_EQ(derivate_1(f, 1.5), 1.29385); ASSERT_EQ(derivate_1(f, 3.2), 6.05724); ASSERT_EQ(derivate_2(f, 3.2), 4.51282); ASSERT_EQ(derivate_2(f, 5.0), 15.41446); function_destroy(f); }
int rdis_user_function (struct _rdis * rdis, uint64_t address) { // get a tree of all functions reachable at this address struct _map * functions = loader_function_address(rdis->loader, rdis->memory, address); // add in this address as a new function as well struct _function * function = function_create(address); map_insert(functions, function->address, function); object_delete(function); // for each newly reachable function struct _map_it * mit; for (mit = map_iterator(functions); mit != NULL; mit = map_it_next(mit)) { struct _function * function = map_it_data(mit); uint64_t fitaddress = function->address; // if we already have this function, skip it if (map_fetch(rdis->functions, function->address) != NULL) continue; // add this function to the rdis->function_tree map_insert(rdis->functions, function->address, function); // add label struct _label * label = loader_label_address(rdis->loader, rdis->memory, fitaddress); map_insert(rdis->labels, fitaddress, label); object_delete(label); // if this function is already in our graph, all we need to do is make // sure its a separate node and then remove function predecessors struct _graph_node * node = graph_fetch_node_max(rdis->graph, fitaddress); if (node != NULL) { // already a node, remove function predecessors if (node->index == address) { remove_function_predecessors(rdis->graph, rdis->functions); continue; } // search for instruction with given address struct _list * ins_list = node->data; struct _list_it * it; for (it = list_iterator(ins_list); it != NULL; it = it->next) { struct _ins * ins = it->data; // found instruction if (ins->address == fitaddress) { // create a new instruction list. // add remaining instructions to new list while removing them from // the current list struct _list * new_ins_list = list_create(); while (1) { list_append(new_ins_list, it->data); it = list_remove(ins_list, it); if (it == NULL) break; } // create a new graph node for this new function graph_add_node(rdis->graph, fitaddress, new_ins_list); // all graph successors from old node are added to new node struct _queue * queue = queue_create(); struct _list * successors = graph_node_successors(node); struct _list_it * sit; for (sit = list_iterator(successors); sit != NULL; sit = sit->next) { struct _graph_edge * edge = sit->data; graph_add_edge(rdis->graph, fitaddress, edge->tail, edge->data); queue_push(queue, edge); } object_delete(successors); // and removed from old node while (queue->size > 0) { struct _graph_edge * edge = queue_peek(queue); graph_remove_edge(rdis->graph, edge->head, edge->tail); queue_pop(queue); } object_delete(queue); // that was easy break; } } if (it != NULL) continue; } // we need to create a new graph for this node struct _graph * graph = loader_graph_address(rdis->loader, rdis->memory, fitaddress); graph_merge(rdis->graph, graph); object_delete(graph); } object_delete(functions); rdis_callback(rdis, RDIS_CALLBACK_ALL); return 0; }
void x8664_functions_r (struct _map * functions, struct _tree * disassembled, uint64_t address, struct _map * memory) { ud_t ud_obj; int continue_disassembling = 1; struct _buffer * buffer = map_fetch_max(memory, address); if (buffer == NULL) return; uint64_t base_address = map_fetch_max_key(memory, address); if (base_address + buffer->size < address) return; uint64_t offset = address - base_address; ud_init (&ud_obj); ud_set_mode (&ud_obj, 64); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, &(buffer->bytes[offset]), buffer->size - offset); while (continue_disassembling == 1) { size_t bytes_disassembled = ud_disassemble(&ud_obj); if (bytes_disassembled == 0) { break; } if ( (ud_obj.mnemonic == UD_Icall) && (ud_obj.operand[0].type == UD_OP_JIMM)) { uint64_t target_addr = address + ud_insn_len(&ud_obj) + udis86_sign_extend_lval(&(ud_obj.operand[0])); if (map_fetch(functions, target_addr) == NULL) { struct _function * function = function_create(target_addr); map_insert(functions, target_addr, function); object_delete(function); } } struct _index * index = index_create(address); if (tree_fetch(disassembled, index) != NULL) { object_delete(index); return; } tree_insert(disassembled, index); object_delete(index); // these mnemonics cause us to continue disassembly somewhere else struct ud_operand * operand; switch (ud_obj.mnemonic) { case UD_Ijo : case UD_Ijno : case UD_Ijb : case UD_Ijae : case UD_Ijz : case UD_Ijnz : case UD_Ijbe : case UD_Ija : case UD_Ijs : case UD_Ijns : case UD_Ijp : case UD_Ijnp : case UD_Ijl : case UD_Ijge : case UD_Ijle : case UD_Ijg : case UD_Ijmp : case UD_Iloop : case UD_Icall : operand = &(ud_obj.operand[0]); if (operand->type == UD_OP_JIMM) { x8664_functions_r(functions, disassembled, address + ud_insn_len(&ud_obj) + udis86_sign_extend_lval(operand), memory); } break; default : break; } // these mnemonics cause disassembly to stop switch (ud_obj.mnemonic) { case UD_Iret : case UD_Ihlt : case UD_Ijmp : continue_disassembling = 0; break; default : break; } address += bytes_disassembled; } }
struct _map * elf32_functions (struct _elf32 * elf32, struct _map * memory) { struct _list * entries = list_create(); // add the entry point struct _function * function = function_create(elf32_entry(elf32)); list_append(entries, function); object_delete(function); // check for __libc_start_main loader uint64_t target_offset = elf32_entry(elf32) - elf32_base_address(elf32) + 0x17; if (target_offset + 0x10 < elf32->data_size) { uint8_t * data = &(elf32->data[target_offset]); size_t size = elf32->data_size - target_offset; ud_t ud_obj; ud_init (&ud_obj); ud_set_mode (&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_input_buffer(&ud_obj, data, size); ud_disassemble(&ud_obj); if (ud_obj.mnemonic == UD_Ipush) { printf("found __libc_start_main loader, main at %llx\n", (unsigned long long) udis86_sign_extend_lval(&(ud_obj.operand[0]))); // add main to function tree struct _function * function; function = function_create(udis86_sign_extend_lval(&(ud_obj.operand[0]))); list_append(entries, function); object_delete(function); } else printf("disassembled: %s\n disassembled at %llx\n", ud_insn_asm(&ud_obj), (unsigned long long) target_offset); } struct _map * functions = elf32_functions_wqueue(elf32, memory, entries); // these are the reachable functions struct _map_it * mit; for (mit = map_iterator(functions); mit != NULL; mit = map_it_next(mit)) { struct _function * function = map_it_data(mit); function->flags |= FUNCTION_REACHABLE; } // reset entries object_delete(entries); entries = list_create(); // symbols are easy int sec_i; for (sec_i = 0; sec_i < elf32->ehdr->e_shnum; sec_i++) { Elf32_Shdr * shdr = elf32_shdr(elf32, sec_i); if (shdr == NULL) break; if ((shdr->sh_type != SHT_SYMTAB) && (shdr->sh_type != SHT_DYNSYM)) continue; int sym_i; for (sym_i = 0; sym_i < shdr->sh_size / shdr->sh_entsize; sym_i++) { Elf32_Sym * sym = elf32_section_element(elf32, sec_i, sym_i); if (sym == NULL) break; if (ELF32_ST_TYPE(sym->st_info) != STT_FUNC) continue; if (sym->st_value == 0) continue; struct _function * function = function_create(sym->st_value); list_append(entries, function); object_delete(function); } } struct _map * sym_functions = elf32_functions_wqueue(elf32, memory, entries); for (mit = map_iterator(sym_functions); mit != NULL; mit = map_it_next(mit)) { struct _function * function = map_it_data(mit); if (map_fetch(functions, function->address) == NULL) map_insert(functions, function->address, function); } object_delete(sym_functions); object_delete(entries); return functions; }
int main(int argc, char *argv[]) { int ret; char *x0 = NULL, *x1 = NULL; char *epsilon = EPSILON, *func = NULL; char *max_iter = MAXITER, *method = "secant"; long double r; /* parse command line */ while ((ret = getopt(argc, argv, "vm:e:i:a:b:")) != -1) { switch (ret) { case 'e': epsilon = optarg; /* optarg is just a pointer to argv */ break; case 'i': max_iter = optarg; break; case 'a': x0 = optarg; break; case 'b': x1 = optarg; break; case 'm': method = optarg; break; case 'v': root_search_verbose = 1; break; default: return 1; } } if (optind >= argc || !x0) { fprintf(stderr, "usage: %s [-v] [-e <epsilon>] [-i <max-iter>] [-m <method>]" "-a <x0> [-b <x1>] <function eg: cos(x)-x^3>\n", argv[0]); return 1; } else { func = argv[optind]; } function_t *f = function_create(func); interval_t *i = interval_create(atof(x0), x1 ? atof(x1) : (atof(x0) + 1.0)); stop_cond_t *s = stop_cond_create(atof(epsilon), atoi(max_iter)); if (!strcmp(method, "secant")) ret = root_secant(f, i, s, &r); else if (!strcmp(method, "bisection")) ret = root_bisection(f, i, s, &r); else if (!strcmp(method, "regulafalsi")) ret = root_regulafalsi(f, i, s, &r); else if (!strcmp(method, "newton")) ret = root_newton(f, atof(x0), s, &r); else { fprintf(stderr, "Method not recognized: %s\n", method); return 1; } if (ret) { fprintf(stderr, "%s method failed (ret: %d)\n", method, ret); } else { printf("%.15Lg\n", r); } function_destroy(f); interval_destroy(i); stop_cond_destroy(s); return ret; }
/* write callback */ static ssize_t kplugs_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) { kplugs_command_t *cmd = NULL; context_t *file_cont = NULL; context_t *cont = NULL; bytecode_t *code = NULL; function_t *func = NULL; exception_t excep; stack_t stack; word iter, arg; word args; byte little_endian; byte func_name[MAX_FUNC_NAME + 1]; int err = 0; #ifdef __LITTLE_ENDIAN little_endian = 1; #else little_endian = 0; #endif /* get the user's command */ cmd = (kplugs_command_t *)buf; file_cont = (context_t *)filp->private_data; if (count < sizeof(byte) * 3) { /* three bytes of header */ return create_error(file_cont, -ERROR_PARAM); } if (cmd->word_size != sizeof(word) || cmd->l_endian != little_endian) { return create_error(file_cont, -ERROR_ARCH); } if (cmd->version_major != VERSION_MAJOR || cmd->version_minor != VERSION_MINOR) { return create_error(file_cont, -ERROR_VERSION); } if (count != sizeof(kplugs_command_t)) { return create_error(file_cont, -ERROR_PARAM); } cont = cmd->is_global ? GLOBAL_CONTEXT : file_cont; switch (cmd->type) { case KPLUGS_LOAD: /* load a new function */ if (cmd->len2 != 0 || cmd->ptr2 != NULL) { return create_error(file_cont, -ERROR_PARAM); } code = memory_alloc(cmd->len1); if (NULL == code) { ERROR(create_error(file_cont, -ERROR_MEM)); } err = memory_copy_from_outside(code, cmd->uptr1, cmd->len1); if (err < 0) { err = create_error(file_cont, err); goto clean; } /* create the function */ err = function_create(code, cmd->len1, &func); if (err < 0) { err = create_error(file_cont, err); goto clean; } err = context_add_function(cont, func); if (err < 0) { err = create_error(file_cont, err); goto clean; } /* return the function's address */ context_create_reply(file_cont, (word)&func->func_code, NULL); return count; case KPLUGS_UNLOAD: /* unload a function with a name */ if (NULL != cmd->uptr2) { return create_error(file_cont, -ERROR_PARAM); } case KPLUGS_EXECUTE: /* execute (and unload) a function with a name */ if (cmd->len1 > MAX_FUNC_NAME || (cmd->len2 % sizeof(word)) != 0) { return create_error(file_cont, -ERROR_PARAM); } err = memory_copy_from_outside(func_name, cmd->uptr1, cmd->len1); if (err < 0) { return create_error(file_cont, err); } func_name[cmd->len1] = '\0'; /* find the function */ if (cmd->type == KPLUGS_UNLOAD) { func = context_find_function(cont, func_name); if (NULL == func) { return create_error(file_cont, -ERROR_UFUNC); } /* delete the function */ context_free_function(func); err = (int)count; goto clean; } if (!cmd->is_global) { func = context_find_function(file_cont, func_name); } if (NULL == func) { func = context_find_function(GLOBAL_CONTEXT, func_name); if (NULL == func) { return create_error(file_cont, -ERROR_UFUNC); } } goto execute_func; case KPLUGS_UNLOAD_ANONYMOUS: /* unload an anonymous function */ if (NULL != cmd->uptr2 || cmd->len1 || cmd->len2) { return create_error(file_cont, -ERROR_PARAM); } func = context_find_anonymous(cont, cmd->ptr1); if (NULL == func) { return create_error(file_cont, -ERROR_UFUNC); } /* delete the function */ context_free_function(func); err = (int)count; goto clean; break; case KPLUGS_EXECUTE_ANONYMOUS: /* execute (and unload) an anonymous function */ if (cmd->len1 || (cmd->len2 % sizeof(word)) != 0) { return create_error(file_cont, -ERROR_PARAM); } /* find the function */ if (!cmd->is_global) { func = context_find_anonymous(file_cont, cmd->ptr1); } if (NULL == func) { func = context_find_anonymous(GLOBAL_CONTEXT, cmd->ptr1); if (NULL == func) { return create_error(file_cont, -ERROR_UFUNC); } } execute_func: /* do the execution of a function: */ args = cmd->len2 / sizeof(word); if (args > func->num_maxargs || args < func->num_minargs) { ERROR_CLEAN(create_error(file_cont, -ERROR_ARGS)); } err = stack_alloc(&stack, sizeof(word), CALL_STACK_SIZE); if (err < 0) { err = create_error(file_cont, err); goto clean; } /* push the arguments to a stack */ for (iter = 0; iter < args; ++iter) { err = memory_copy_from_outside(&arg, cmd->ptr2 + (iter * sizeof(word)), sizeof(arg)); if (err < 0) { stack_free(&stack); err = create_error(file_cont, err); goto clean; } if (NULL == stack_push(&stack, &arg)) { stack_free(&stack); ERROR_CLEAN(create_error(file_cont, -ERROR_MEM)); } } /* execute the function and create an answer */ arg = vm_run_function(func, &stack, &excep); stack_free(&stack); if (excep.had_exception) { err = -EINVAL; /* it dosen't really matter which error. the value of the error will be taken from the answer */ arg = excep.value; } else { err = (int)count; } context_create_reply(file_cont, arg, &excep); goto clean; case KPLUGS_GET_LAST_EXCEPTION: if (NULL != cmd->uptr2 || cmd->len1 < sizeof(exception_t) || cmd->len2) { ERROR(create_error(file_cont, -ERROR_PARAM)); } err = context_get_last_exception(file_cont, (exception_t *)cmd->ptr1); if (err < 0) { return create_error(file_cont, err); } return count; default: return create_error(file_cont, -ERROR_PARAM); } clean: if (NULL != func) { function_put(func); } else if (NULL != code) { memory_free(code); } return err; }