I am trying to implement a linked list that would store a memory address when encountering call/return assembly instructions. This works recursively by parsing each line of the assembly and only breaking out of the function when encountering either a call or return instruction. So far this works for call instructions, meaning that the return address is saved a node in a linked list, but when trying to retrieve this value during a return instruction the data has gone missing (meaning that the linked list is now empty). Here is what I am working with:
struct ret_addr {
int address;
struct ret_addr *nxt;
};
struct ret_addr *ret_data(cs_insn *insn, struct ret_addr **head) {
struct ret_addr *r = malloc(sizeof(*r));
r->address = insn->address + insn->size;
r->nxt = (*head);
(*head) = r;
return r;
}
struct bb_data *disassemble_function_cfg(int startAddr, unsigned char *bytes, int end_section) {
csh handle;
cs_insn *insn;
cs_detail *detail;
cs_x86 *x86;
size_t count;
int stop_disasm = 0;
struct bb_data *edges = NULL;
struct ret_addr *ret_edge = NULL;
count = cs_disasm(handle, bytes, end_section, startAddr, 1, &insn);
detail = insn->detail;
for(int n = 0; n < detail->groups_count; n++) {
//break when encountering a call instruction
if(detail->groups[n] == X86_GRP_CALL) {
stop_disasm = 1;
vector_new(edges);
edges = call_insn(handle, x86, insn, vector_back(edges));
ret_edge = ret_data(insn, &ret_edge);
}
//break when encountering a return instruction
else if(detail->groups[n] == X86_GRP_RET) {
stop_disasm = 1;
vector_new(edges);
edges = ret_insn(insn, edges, &ret_edge);
}
}
if(!stop_disasm) {
disassemble_function_cfg(insn->address + insn->size, bytes + insn->size, end_section);
}
else {
return edges;
}
}
You don't preserve your list between recursive calls. What you might want to do:
struct bb_data *disassemble_function_cfg(struct ret_addr **ret_edge, int startAddr, unsigned char *bytes, int end_section)
{
...
if(*ret_edge == NULL) *ret_edge = ret_data(insn, ret_edge);
...
}
Related
I am trying to create a linked list that stores return instructions while parsing an assembly code file. As an explanation for the code, when encountering a call instruction the address of the next instruction is to be saved. When encountering a return instruction, the linked list is supposed to be traversed until it reaches a point when the next node is NULL. For some reason the code is not saving the return addresses. Might it have something to do with the recursion?
//function to create a node in linked list
struct ret_addr *return_address(cs_insn *insn, struct ret_addr *r) {
struct ret_addr *ret = malloc(sizeof(*ret));
ret->address = insn->address + insn->size;
ret->nxt_ret_addr = r;
return ret;
}
//retrieve the data from the last node of the linked list
int return_val(struct ret_addr *r) {
if(r == NULL)
return 0;
while(r->nxt_ret_addr != NULL) {
r = r->nxt_ret_addr;
return r->address;
}
}
//parse assembly code
struct bb_data *disassemble_function_cfg(int startAddr, unsigned char *bytes, int end_section) {
csh handle;
cs_insn *insn;
cs_detail *detail;
size_t count;
int stop_disasm = 0;
struct ret_addr *r_data = malloc(sizeof(*r_data));
count = cs_disasm(handle, bytes, end_section, startAddr, 1, &insn);
detail = insn->detail;
for(int n = 0; n < detail->groups_count; n++) {
if(detail->groups[n] == X86_GRP_CALL) {
stop_disasm = 1;
r_data = return_address(insn, r_data);
}
else if(detail->groups[n] == X86_GRP_RET) {
stop_disasm = 1;
start_edge = return_val(r_data);
}
if(!stop_disasm)
disassemble_function_cfg(insn->address + insn->size, bytes + insn->size, end_section);
else
return edges;
}
During an inital call instruction the return value is saved (checked by printing it out), but when reaching a return instruction the linked list is suddenly empty. My idea is that this is caused by the constant calls to malloc, but am unsure if that is a correct assumption.
The problem is in the return_val function : it does not modify the r_datavalue from the caller function disassemble_function_cfg.
There's also one little thing I assumed : since it is a call/return implementation, the linked list should behave as LIFO (last in first out). The return_address function fills the linked list by inserting in the head, so the return_val function should remove address from the head first : there's no need to read the list until reaching NULL.
Try this code :
//retrieve the data from the last node of the linked list
int return_val(struct ret_addr **r) {
int ret_val;
if (*r == NULL)
return 0;
ret_val = (*r)->address;
*r = (*r)->nxt_ret_addr;
return ret_val;
}
In the caller function :
else if(detail->groups[n] == X86_GRP_RET) {
stop_disasm = 1;
start_edge = return_val(&r_data); // address of r_data, so it can be modified
}
I am coding a data structure involving a set of two linked lists, stacked on top of each other. When trying to initialize the set in my test harness, I get a segmentation error. I've commented out all value setters to test to see if I could figure out the error myself, but I could not.
Prototype for init method:
Test Harness:
int
main( )
{
list the_list;
int used = 0;
int values[MAX_VALUES];
char input[LINE_LEN];
char command;
int argument;
int num_found;
bool result;
set_t lower;
set_t upper;
the_list->lower = lower;
the_list->upper = upper;
input[0] = '\0';
input[LINE_LEN-1] = '\0';
fgets( input, LINE_LEN, stdin );
while (*input != 'q') {
num_found = sscanf( input, "%c %d", &command, &argument );
if (num_found > 0) {
switch (command) {
case 'i':
printf ("Request to initialize the set\n");
if (num_found == 1) {
result = set_init( &the_list );
} else {
result = set_init( NULL );
}
printf ("Returned as %d\n", result);
break;
34,0-1 8%
Init method:
bool
set_init( list *the_list )
{
bool initialized = false;
if (the_list !=NULL ) {
/* We have space to initialize. */
the_list->lower->set_size = 0;
/* the_list->lower->head = NULL;
the_list->lower->tail = NULL;
the_list->lower->set_level = 1;
the_list->lower->ready = true;
the_list->upper->set_size = 0;
the_list->upper->head = NULL;
the_list->upper->tail = NULL;
the_list->upper->set_level = 2;
the_list->upper->ready = true;*/
initialized = true;
}
return initialized;
}
Also my struct definitions for my set, linked list, and node structs:
typedef struct _set_node_t {
test_type_t *data;
struct _set_node_t *next;
struct _set_node_t *below;
} set_node_t;
/* the set itself keeps track of the head and the tail of the linked list */
typedef struct {
int set_size;
bool ready;
set_node_t *head;
set_node_t *tail;
int set_level;
} set_t;
typedef struct {
set_t *lower;
set_t *upper;
}list;
The only thing that could be crashing here is this line:
the_list->lower->set_size = 0;
Either the_list or the_list->lower must be uninitialized or NULL or be pointing to invalid or inaccessible memory.
Edit: Yeah this line will crash because you don't initialize the_list.lower:
result = set_init( &the_list );
And this line will crash because you're passing NULL:
result = set_init( NULL );
I'm currently dealing with a generic Tree with this structure:
typedef struct NODE {
//node's keys
unsigned short *transboard;
int depth;
unsigned int i;
unsigned int j;
int player;
int value;
struct NODE *leftchild; //points to the first child from the left
struct NODE *rightbrothers; //linked list of brothers from the current node
}NODE;
static NODE *GameTree = NULL;
While the function that allocates the different nodes is (don't bother too much at the keys' values, basically allocates the children-nodes. If there aren't any the new child goes to leftchild, otherwise it goes at the end of the list "node->leftchild->rightbrothers"):
static int AllocateChildren(NODE **T, int depth, unsigned int i, unsigned int j, int player, unsigned short *transboard) {
NODE *tmp = NULL;
if ((*T)->leftchild == NULL) {
if( (tmp = (NODE*)malloc(sizeof(NODE)) )== NULL) return 0;
else {
tmp->i = i;
tmp->j = j;
tmp->depth = depth;
(player == MAX ) ? (tmp->value = 2 ): (tmp->value = -2);
tmp->player = player;
tmp->transboard = transboard;
tmp->leftchild = NULL;
tmp->rightbrothers = NULL;
(*T)->leftchild = tmp;
}
}
else {
NODE *scorri = (*T)->leftchild;
while (scorri->rightbrothers != NULL)
scorri = scorri->rightbrothers;
if( ( tmp = (NODE*)malloc(sizeof(NODE)) )== NULL) return 0;
else {
tmp->i = i;
tmp->j = j;
tmp->depth = depth;
(player == MAX) ? (tmp->value = 2) : (tmp->value = -2);
tmp->player = player;
tmp->transboard = transboard;
tmp->leftchild = NULL;
tmp->rightbrothers = NULL;
}
scorri->rightbrothers = tmp;
}
return 1;
}
I need to come up with a function, possibly recursive, that deallocates the whole tree, so far I've come up with this:
void DeleteTree(NODE **T) {
if((*T) != NULL) {
NODE *tmp;
for(tmp = (*T)->children; tmp->brother != NULL; tmp = tmp->brother) {
DeleteTree(&tmp);
}
free(*T);
}
}
But it doesn't seem working, it doesn't even deallocate a single node of memory.
Any ideas of where I am being wrong or how can it be implemented?
P.s. I've gotten the idea of the recursive function from this pseudocode from my teacher. However I'm not sure I've translated it correctly in C with my kind of Tree.
Pseudocode:
1: function DeleteTree(T)
2: if T != NULL then
3: for c ∈ Children(T) do
4: DeleteTree(c)
5: end for
6: Delete(T)
7: end if
8: end function
One thing I like doing if I'm allocating lots of tree nodes, that are going to go away at the same time, is to allocate them in 'batches'. I malloc then as an array of nodes and dole them out from a special nodealloc function after saving a pointer to the array (in a function like below). To drop the tree I just make sure I'm not keeping any references and then call the free routine (also like below).
This can also reduce the amount of RAM you allocate if you're lucky (or very smart) with your initial malloc or can trust realloc not to move the block when you shrink it.
struct freecell { struct freecell * next; void * memp; } * saved_pointers = 0;
static void
save_ptr_for_free(void * memp)
{
struct freecell * n = malloc(sizeof*n);
if (!n) {perror("malloc"); return; }
n->next = saved_pointers;
n->memp = memp;
saved_pointers = n;
}
static void
free_saved_memory(void)
{
while(saved_pointers) {
struct freecell * n = saved_pointers;
saved_pointers = saved_pointers->next;
free(n->memp);
free(n);
}
}
I've just realized my BIG mistake in the code and I'll just answer myself since no one had found the answer.
The error lies in this piece of code:
for(tmp = (*T)->children; tmp->brother != NULL; tmp = tmp->brother) {
DeleteTree(&tmp);
}
First of all Ami Tavory was right about the for condition, i need to continue as long as tmp != NULL
Basically it won't just work because after the DeleteTree(&tmp), I can no longer access the memory in tmp because it's obviously deleted, so after the first cycle of for ends I can't do tmp = tmp->rightbrother to move on the next node to delete because tmp->rightbrother no longer exists as I just deleted it.
In order to fix it I just needed to save the tmp->brother somewhere else:
void DeleteTree(NODE **T) {
if((*T) != NULL) {
NODE *tmp, *deletenode, *nextbrother;
for(tmp = (*T)->children; tmp != NULL; tmp = nextbrother) {
nextbrother = tmp->rightbrother;
DeleteTree(&tmp);
}
canc = (*T);
free(*T);
(*T) = NULL;
}
}
Just for the sake of completeness I want to add my version of DeleteTree
void DeleteTree(NODE *T) {
if(T != NULL) {
DeleteTree(T->rightbrothers);
DeleteTree(T->leftchild);
free(T);
}
}
I think it is much less obscure and much easier to read. Basically it solves the issue in DeleteTree but through eliminating the loop.
Since we free the nodes recursively we might as well do the whole process recursively.
I have implemented several functions for the Stack ADT. I am trying to find the max and min values in O(1) time and I have augmented my stack structure to serve this purpose. This is my code:
void mms_push(MMStack mms, int i) {
struct llnode *new = malloc(sizeof(struct llnode));
new->item = i;
if(mms->len!=0)
{
new->next = mms->topnode;
mms->topnode = new;
}
else
{
new->next = NULL;
mms->topnode = new;
}
if (mms->len == 0)
{
mms->topnode->minc = i;
mms->topnode->maxc = i;}
else
{
if(mms->topnode->maxc < i)
{
mms->topnode->maxc = i;
}
if(i<mms->topnode->minc)
{
mms->topnode->minc = i;
}
mms->len++;}
int mms_pop(MMStack mms) {
assert(mms);
int ret = mms->topnode->item;
struct llnode *backup = mms->topnode;
mms->topnode = mms->topnode->next;
mms->len--;
free(backup);
return ret;
}
My structures used are as below:
struct llnode
{
int item;
struct llnode *next;
int minc;
int maxc;
};
struct mmstack
{
int len ;
struct llnode *topnode;
};
typedef struct mmstack *MMStack;
I am not getting the correct value of max and min values. How do I correct the code so that I get the right value of max and min element in the stack?
Thanks in advance!
Take a look at this code:
if (mms->len == 0)
{
mms->topnode->minc = i;
mms->topnode->maxc = i;
}
else
{
if(mms->topnode->maxc < i)
{
mms->topnode->maxc = i;
}
if(i<mms->topnode->minc)
{
mms->topnode->minc = i;
}
}
Notice that in the else branch, you're reading the values of mms->topnode->minc and mms->topnode->maxc before you've initialized them. I think you meant to look at the values of mms->topnode->minc/maxc before you reassigned mms->topnode. To fix this, try doing something like this:
else
{
mms->topnode->maxc = mms->topnode->next->maxc;
mms->topnode->minc = mms->topnode->next->minc;
if(mms->topnode->maxc < i)
{
mms->topnode->maxc = i;
}
if(i<mms->topnode->minc)
{
mms->topnode->minc = i;
}
}
These extra two lines initialize the min and max values to the old max values before comparing against i, which should ensure that they get a value.
Hope this helps!
You're doing things a bit backwards — comparing i to the values in the new, uninitialised node after you have inserted it in the stack.
It's easier to first prepare the new node completely, and then link it into the stack.
Assuming that an empty stack has a NULL topnode:
void mms_push(MMStack mms, int i) {
struct llnode *new = malloc(sizeof(struct llnode));
new->item = i;
new->next = mms->topnode;
if (!mms->topnode)
{
new->minc = i;
new->maxc = i;
}
else
{
new->minc = min(mms->topnode->minc, i);
new->maxc = max(mms->topnode->maxc, i);
}
mms->topnode = new;
mms->len++;
}
I'm not sure if min and max are C99, but they're trivial to define.
I'm trying to implement sequence_insert_at using the add_to_front function here
Everything before
typedef struct sequence *Sequence;
is pasted from another c file.
void sequence_insert_at(Sequence s, int pos, int item)
{
struct node* temp = s->lst;
for(; pos > 0; --pos)
{
temp = temp->rest;
}
add_to_front(&temp, item);
++s->length;
if(!temp->rest)
{
s->end = temp;
}
//s->lst = temp;
}
I don't know why I keep getting a runtime error. if I clone s->lst and traverse the clone, I'm not modifying the pointer to the node in s, but if I change temp, s->lst should have the reflected changes since the nodes are all linked still. Any ideas as to how to fix this? I tried creating another node that is one before the temp after traversal, and then setting it->rest = temp, but that failed as well.
following mistakes a could spot but only so far to get the main function run
new_sequence does not initialize anything in Sequence it creates. lst is not initialized when you access it in sequence_insert_at
struct node* temp = s->lst;
here how it should look like
Sequence new_sequence()
{
Sequence s = malloc(sizeof(struct sequence));
if(!s)
{
printf("Out of memory. Can't allocate s\n");
exit(EXIT_FAILURE);
}
s->lst = malloc(sizeof(struct node));
if(! s->lst) {
printf("Out of memory. Can't allocate lst\n");
}
s->lst->rest = NULL;
s->length = 0;
return s;
}
also s->lst->rest has to be set to NULL, this is what tells that the list has no more elements an not end witch turns obsolete.
struct sequence
{
struct node* lst;
int length;
};
You should be passing the sequence itself to your functions not a pointer to some internal data in the sequence.
add_to_front(&temp, item);
Your sequence_insert_at function should be the one that can handle any position not add_to_front() so it is easier to call with the position 0 from add_to_front() and your having the the hole work done in one function, not a half here and a half there.
void sequence_insert_at(Sequence s, int pos, int item)
{
if(s && pos <= s->length) {
print_sequence(s);
struct node *newnode = malloc(sizeof(struct node));
if (newnode == NULL) {
printf("ERROR! add_to_front ran out of memory!\n");
exit(EXIT_FAILURE);
}
newnode->first = item;
struct node* temp = s->lst;
struct node* prv = NULL;
for(int i = 0; i < pos; i++) {
printf("skip %d\n", temp->first);
prv = temp;
temp = temp->rest;
}
newnode->rest = temp;
if(pos == 0) {
printf("insert as first\n");
s->lst = newnode;
} else {
printf("insert before %d\n", temp->first);
prv->rest = newnode;
}
++s->length;
}
}
and in add_to_front only one statement is needed
void add_to_front(Sequence s, int item) {
sequence_insert_at(s, 0, item);
}
as for inserting at the back of the list
void add_to_back(Sequence s, int item) {
sequence_insert_at(s, s->length, item);
}
A small test with the main function
void print_sequence(Sequence s)
{
struct node* temp = s->lst;
for(int i = 0; i < s->length; temp = temp->rest) {
printf("%d ", temp->first);
i++;
}
printf("\n");
}
int main()
{
Sequence derp = new_sequence();
sequence_insert_at(derp, 0, 14);
add_to_front(derp, 16);
sequence_insert_at(derp, 0, 17);
sequence_insert_at(derp, 2, 15);
add_to_back(derp, 13);
print_sequence(derp);
delete_sequence(derp);
return 0;
}
output is:
17 16 15 14 13
You'll have to go trough the other functions and fix them.
Finally i should note that variable names you have choosen are little bit confusing if not misleading, i would name them this way
typedef struct node {
int data; /* the data that a node holds */
struct node* next; /* the pointer to the next node */
} Node_t;
typedef struct sequence {
struct node* head; /* head or first element of the sequence/list */
int length; /* length is ok but size is better */
} Sequence_t;