struct _graph * elf32_graph_functions (struct _elf32 * elf32, struct _map * memory, struct _map * functions) { struct _graph * graph; struct _wqueue * wqueue; // disassemble from entry point graph = x86_graph(elf32_entry(elf32), memory); struct _map_it * it; wqueue = wqueue_create(); for (it = map_iterator(functions); it != NULL; it = map_it_next(it)) { struct _function * function = map_it_data(it); struct _x86_wqueue * x86w; x86w = x86_wqueue_create(function->address, memory); wqueue_push(wqueue, WQUEUE_CALLBACK(x86_graph_wqueue), x86w); object_delete(x86w); } wqueue_wait(wqueue); while (wqueue_peek(wqueue) != NULL) { graph_merge(graph, wqueue_peek(wqueue)); wqueue_pop(wqueue); } object_delete(wqueue); remove_function_predecessors(graph, functions); graph_reduce(graph); return graph; }
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; }