about summary refs log tree commit diff stats
path: root/src/miasm/jitter/vm_mngr.c
diff options
context:
space:
mode:
authorTheofilos Augoustis <theofilos.augoustis@gmail.com>2025-10-14 09:09:29 +0000
committerTheofilos Augoustis <theofilos.augoustis@gmail.com>2025-10-14 09:09:29 +0000
commit579cf1d03fb932083e6317967d1613d5c2587fb6 (patch)
tree629f039935382a2a7391bce9253f6c9968159049 /src/miasm/jitter/vm_mngr.c
parent51c15d3ea2e16d4fc5f0f01a3b9befc66b1f982e (diff)
downloadfocaccia-miasm-ta/nix.tar.gz
focaccia-miasm-ta/nix.zip
Convert to src-layout ta/nix
Diffstat (limited to 'src/miasm/jitter/vm_mngr.c')
-rw-r--r--src/miasm/jitter/vm_mngr.c1032
1 files changed, 1032 insertions, 0 deletions
diff --git a/src/miasm/jitter/vm_mngr.c b/src/miasm/jitter/vm_mngr.c
new file mode 100644
index 00000000..9fe8ab65
--- /dev/null
+++ b/src/miasm/jitter/vm_mngr.c
@@ -0,0 +1,1032 @@
+/*
+** Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
+**
+** This program 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 2 of the License, or
+** (at your option) any later version.
+**
+** This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "vm_mngr.h"
+
+#include <inttypes.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "queue.h"
+
+
+
+/****************memory manager**************/
+
+
+
+
+#define MIN(a,b)  (((a)<(b))?(a):(b))
+#define MAX(a,b)  (((a)>(b))?(a):(b))
+
+// #define DEBUG_MIASM_AUTOMOD_CODE
+#define MEMORY_ACCESS_LIST_INITIAL_COUNT 100
+
+/*
+  To avoid alloc/free for each instruction access, the buffer is allocated here,
+  and is increased depending of program needs.
+ */
+void memory_access_list_init(struct memory_access_list * access)
+{
+	access->array = malloc(MEMORY_ACCESS_LIST_INITIAL_COUNT * sizeof(struct memory_access));
+	if (access->array == NULL) {
+		fprintf(stderr, "cannot realloc struct memory_access access->array\n");
+		exit(EXIT_FAILURE);
+	}
+	access->allocated = MEMORY_ACCESS_LIST_INITIAL_COUNT;
+	access->num = 0;
+}
+
+void memory_access_list_reset(struct memory_access_list * access)
+{
+	access->num = 0;
+}
+
+void memory_access_list_add(struct memory_access_list * access, uint64_t start, uint64_t stop)
+{
+	if (access->num >= access->allocated) {
+		if (access->allocated == 0)
+			access->allocated = 1;
+		else {
+			if (access->allocated >= SIZE_MAX / 2) {
+				fprintf(stderr, "Cannot alloc more pages\n");
+				exit(EXIT_FAILURE);
+			}
+			access->allocated *= 2;
+		}
+		access->array = realloc(access->array, access->allocated * sizeof(struct memory_access));
+		if (access->array == NULL) {
+			fprintf(stderr, "cannot realloc struct memory_access access->array\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+	access->array[access->num].start = start;
+	access->array[access->num].stop = stop;
+	access->num += 1;
+}
+
+
+
+uint16_t set_endian16(vm_mngr_t* vm_mngr, uint16_t val)
+{
+	if (vm_mngr->sex == __BYTE_ORDER)
+		return val;
+	else
+		return Endian16_Swap(val);
+}
+
+uint32_t set_endian32(vm_mngr_t* vm_mngr, uint32_t val)
+{
+	if (vm_mngr->sex == __BYTE_ORDER)
+		return val;
+	else
+		return Endian32_Swap(val);
+}
+
+uint64_t set_endian64(vm_mngr_t* vm_mngr, uint64_t val)
+{
+	if (vm_mngr->sex == __BYTE_ORDER)
+		return val;
+	else
+		return Endian64_Swap(val);
+}
+
+void print_val(uint64_t base, uint64_t addr)
+{
+	uint64_t *ptr = (uint64_t *) (intptr_t) addr;
+	fprintf(stderr, "addr 0x%"PRIX64" val 0x%"PRIX64"\n", addr-base, *ptr);
+}
+
+int midpoint(int imin, int imax)
+{
+	return (imin + imax) / 2;
+}
+
+
+int find_page_node(struct memory_page_node * array, uint64_t key, int imin, int imax)
+{
+	// continue searching while [imin,imax] is not empty
+	while (imin <= imax) {
+		// calculate the midpoint for roughly equal partition
+		int imid = midpoint(imin, imax);
+		if(array[imid].ad <= key && key < array[imid].ad + array[imid].size)
+			// key found at index imid
+			return imid;
+		// determine which subarray to search
+		else if (array[imid].ad < key)
+			// change min index to search upper subarray
+			imin = imid + 1;
+		else
+			// change max index to search lower subarray
+			imax = imid - 1;
+	}
+	// key was not found
+	return -1;
+}
+
+struct memory_page_node * get_memory_page_from_address(vm_mngr_t* vm_mngr, uint64_t ad, int raise_exception)
+{
+	struct memory_page_node * mpn;
+	int i;
+
+	i = find_page_node(vm_mngr->memory_pages_array,
+			   ad,
+			   0,
+			   vm_mngr->memory_pages_number - 1);
+	if (i >= 0) {
+		mpn = &vm_mngr->memory_pages_array[i];
+		if ((mpn->ad <= ad) && (ad < mpn->ad + mpn->size))
+			return mpn;
+	}
+	if (raise_exception) {
+		fprintf(stderr, "WARNING: address 0x%"PRIX64" is not mapped in virtual memory:\n", ad);
+		vm_mngr->exception_flags |= EXCEPT_ACCESS_VIOL;
+	}
+	return NULL;
+}
+
+static uint64_t memory_page_read(vm_mngr_t* vm_mngr, unsigned int my_size, uint64_t ad)
+{
+	struct memory_page_node * mpn;
+	unsigned char * addr;
+	uint64_t ret = 0;
+	struct memory_breakpoint_info * b;
+
+
+	mpn = get_memory_page_from_address(vm_mngr, ad, 1);
+	if (!mpn)
+		return 0;
+
+	if ((mpn->access & PAGE_READ) == 0){
+		fprintf(stderr, "access to non readable page!! %"PRIX64"\n", ad);
+		vm_mngr->exception_flags |= EXCEPT_ACCESS_VIOL;
+		return 0;
+	}
+
+	/* check read breakpoint */
+	LIST_FOREACH(b, &vm_mngr->memory_breakpoint_pool, next){
+		if ((b->access & BREAKPOINT_READ) == 0)
+			continue;
+		if ((b->ad <= ad) && (ad < b->ad + b->size))
+			vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY;
+	}
+
+
+	addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad];
+
+	/* read fits in a page */
+	if (ad - mpn->ad + my_size/8 <= mpn->size){
+		switch(my_size){
+		case 8:
+			ret = *((unsigned char*)addr)&0xFF;
+			break;
+		case 16:
+			ret = *((unsigned short*)addr)&0xFFFF;
+			ret = set_endian16(vm_mngr, (uint16_t)ret);
+			break;
+		case 32:
+			ret = *((unsigned int*)addr)&0xFFFFFFFF;
+			ret = set_endian32(vm_mngr, (uint32_t)ret);
+			break;
+		case 64:
+			ret = *((uint64_t*)addr)&0xFFFFFFFFFFFFFFFFULL;
+			ret = set_endian64(vm_mngr, ret);
+			break;
+		default:
+			fprintf(stderr, "Bad memory access size %d\n", my_size);
+			exit(EXIT_FAILURE);
+			break;
+		}
+	}
+	/* read is multiple page wide */
+	else{
+		unsigned int new_size = my_size;
+		int index = 0;
+		while (new_size){
+			mpn = get_memory_page_from_address(vm_mngr, ad, 1);
+			if (!mpn)
+				return 0;
+			addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad];
+			ret |= ((uint64_t)(*((unsigned char*)addr)&0xFF))<<(index);
+			index +=8;
+			new_size -= 8;
+			ad ++;
+		}
+		switch(my_size){
+		case 8:
+			break;
+		case 16:
+			ret = set_endian16(vm_mngr, (uint16_t)ret);
+			break;
+		case 32:
+			ret = set_endian32(vm_mngr, (uint32_t)ret);
+			break;
+		case 64:
+			ret = set_endian64(vm_mngr, ret);
+			break;
+		default:
+			fprintf(stderr, "Bad memory access size %d\n", my_size);
+			exit(EXIT_FAILURE);
+			break;
+		}
+	}
+	return ret;
+}
+
+static void memory_page_write(vm_mngr_t* vm_mngr, unsigned int my_size,
+			      uint64_t ad, uint64_t src)
+{
+	struct memory_page_node * mpn;
+	unsigned char * addr;
+	struct memory_breakpoint_info * b;
+
+	mpn = get_memory_page_from_address(vm_mngr, ad, 1);
+	if (!mpn)
+		return;
+
+	if ((mpn->access & PAGE_WRITE) == 0){
+		fprintf(stderr, "access to non writable page!! %"PRIX64"\n", ad);
+		vm_mngr->exception_flags |= EXCEPT_ACCESS_VIOL;
+		return ;
+	}
+
+	/* check read breakpoint*/
+	LIST_FOREACH(b, &vm_mngr->memory_breakpoint_pool, next){
+		if ((b->access & BREAKPOINT_WRITE) == 0)
+			continue;
+		if ((b->ad <= ad) && (ad < b->ad + b->size))
+			vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY;
+	}
+
+	addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad];
+
+	/* write fits in a page */
+	if (ad - mpn->ad + my_size/8 <= mpn->size){
+		switch(my_size){
+		case 8:
+			*((unsigned char*)addr) = src&0xFF;
+			break;
+		case 16:
+			src = set_endian16(vm_mngr, (uint16_t)src);
+			*((unsigned short*)addr) = src&0xFFFF;
+			break;
+		case 32:
+			src = set_endian32(vm_mngr, (uint32_t)src);
+			*((unsigned int*)addr) = src&0xFFFFFFFF;
+			break;
+		case 64:
+			src = set_endian64(vm_mngr, src);
+			*((uint64_t*)addr) = src&0xFFFFFFFFFFFFFFFFULL;
+			break;
+		default:
+			fprintf(stderr, "Bad memory access size %d\n", my_size);
+			exit(EXIT_FAILURE);
+			break;
+		}
+	}
+	/* write is multiple page wide */
+	else{
+		switch(my_size){
+
+		case 8:
+			break;
+		case 16:
+			src = set_endian16(vm_mngr, (uint16_t)src);
+			break;
+		case 32:
+			src = set_endian32(vm_mngr, (uint32_t)src);
+			break;
+		case 64:
+			src = set_endian64(vm_mngr, src);
+			break;
+		default:
+			fprintf(stderr, "Bad memory access size %d\n", my_size);
+			exit(EXIT_FAILURE);
+			break;
+		}
+		while (my_size){
+			mpn = get_memory_page_from_address(vm_mngr, ad, 1);
+			if (!mpn)
+				return;
+
+			addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad];
+			*((unsigned char*)addr) = src&0xFF;
+			my_size -= 8;
+			src >>=8;
+			ad ++;
+		}
+	}
+}
+
+// ##################
+
+void dump_code_bloc(vm_mngr_t* vm_mngr)
+{
+	struct code_bloc_node * cbp;
+	LIST_FOREACH(cbp, &vm_mngr->code_bloc_pool, next){
+		fprintf(stderr, "%"PRIX64"%"PRIX64"\n", cbp->ad_start,  cbp->ad_stop);
+	}
+
+}
+
+void add_range_to_list(struct memory_access_list * access, uint64_t addr1, uint64_t addr2)
+{
+	if (access->num > 0) {
+		/* Check match on upper bound */
+		 if (access->array[access->num-1].stop == addr1) {
+			 access->array[access->num-1].stop = addr2;
+			 return;
+		 }
+
+		/* Check match on lower bound */
+		 if (access->array[0].start == addr2) {
+			 access->array[0].start = addr1;
+			 return;
+		 }
+	}
+
+	/* No merge, add to the list */
+	memory_access_list_add(access, addr1, addr2);
+}
+
+
+void add_mem_read(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size)
+{
+	add_range_to_list(&(vm_mngr->memory_r), addr, addr + size);
+}
+
+void add_mem_write(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size)
+{
+	add_range_to_list(&(vm_mngr->memory_w), addr, addr + size);
+}
+
+void check_invalid_code_blocs(vm_mngr_t* vm_mngr)
+{
+	size_t i;
+	struct code_bloc_node * cbp;
+	for (i=0;i<vm_mngr->memory_w.num; i++) {
+		if (vm_mngr->exception_flags & EXCEPT_CODE_AUTOMOD)
+			break;
+		if (vm_mngr->memory_w.array[i].stop <= vm_mngr->code_bloc_pool_ad_min ||
+		    vm_mngr->memory_w.array[i].start >=vm_mngr->code_bloc_pool_ad_max)
+			continue;
+
+		LIST_FOREACH(cbp, &vm_mngr->code_bloc_pool, next){
+			if ((cbp->ad_start < vm_mngr->memory_w.array[i].stop) &&
+			    (vm_mngr->memory_w.array[i].start < cbp->ad_stop)){
+#ifdef DEBUG_MIASM_AUTOMOD_CODE
+				fprintf(stderr, "**********************************\n");
+				fprintf(stderr, "self modifying code %"PRIX64" %"PRIX64"\n",
+					vm_mngr->memory_w.array[i].start,
+					vm_mngr->memory_w.array[i].stop);
+				fprintf(stderr, "**********************************\n");
+#endif
+				vm_mngr->exception_flags |= EXCEPT_CODE_AUTOMOD;
+				break;
+			}
+		}
+	}
+}
+
+
+void check_memory_breakpoint(vm_mngr_t* vm_mngr)
+{
+	size_t i;
+	struct memory_breakpoint_info * memory_bp;
+
+	/* Check memory breakpoints */
+	LIST_FOREACH(memory_bp, &vm_mngr->memory_breakpoint_pool, next) {
+		if (vm_mngr->exception_flags & EXCEPT_BREAKPOINT_MEMORY)
+			break;
+		if (memory_bp->access & BREAKPOINT_READ) {
+			for (i=0;i<vm_mngr->memory_r.num; i++) {
+				if ((memory_bp->ad < vm_mngr->memory_r.array[i].stop) &&
+				    (vm_mngr->memory_r.array[i].start < memory_bp->ad + memory_bp->size)) {
+					vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY;
+					break;
+				}
+			}
+		}
+		if (memory_bp->access & BREAKPOINT_WRITE) {
+			for (i=0;i<vm_mngr->memory_w.num; i++) {
+				if ((memory_bp->ad < vm_mngr->memory_w.array[i].stop) &&
+				    (vm_mngr->memory_w.array[i].start < memory_bp->ad + memory_bp->size)) {
+					vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY;
+					break;
+				}
+			}
+		}
+	}
+}
+
+
+PyObject* get_memory_pylist(vm_mngr_t* vm_mngr, struct memory_access_list* memory_list)
+{
+	size_t i;
+	PyObject *pylist;
+	PyObject *range;
+
+	pylist = PyList_New(memory_list->num);
+	for (i=0;i<memory_list->num;i++) {
+		range = PyTuple_New(2);
+		PyTuple_SetItem(range, 0, PyLong_FromUnsignedLongLong((uint64_t)memory_list->array[i].start));
+		PyTuple_SetItem(range, 1, PyLong_FromUnsignedLongLong((uint64_t)memory_list->array[i].stop));
+		PyList_SetItem(pylist, i, range);
+	}
+	return pylist;
+
+}
+
+PyObject* get_memory_read(vm_mngr_t* vm_mngr)
+{
+	return get_memory_pylist(vm_mngr, &vm_mngr->memory_r);
+}
+
+PyObject* get_memory_write(vm_mngr_t* vm_mngr)
+{
+	return get_memory_pylist(vm_mngr, &vm_mngr->memory_w);
+}
+
+void vm_MEM_WRITE_08(vm_mngr_t* vm_mngr, uint64_t addr, unsigned char src)
+{
+	add_mem_write(vm_mngr, addr, 1);
+	memory_page_write(vm_mngr, 8, addr, src);
+}
+
+void vm_MEM_WRITE_16(vm_mngr_t* vm_mngr, uint64_t addr, unsigned short src)
+{
+	add_mem_write(vm_mngr, addr, 2);
+	memory_page_write(vm_mngr, 16, addr, src);
+}
+void vm_MEM_WRITE_32(vm_mngr_t* vm_mngr, uint64_t addr, unsigned int src)
+{
+	add_mem_write(vm_mngr, addr, 4);
+	memory_page_write(vm_mngr, 32, addr, src);
+}
+void vm_MEM_WRITE_64(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t src)
+{
+	add_mem_write(vm_mngr, addr, 8);
+	memory_page_write(vm_mngr, 64, addr, src);
+}
+
+unsigned char vm_MEM_LOOKUP_08(vm_mngr_t* vm_mngr, uint64_t addr)
+{
+	unsigned char ret;
+	add_mem_read(vm_mngr, addr, 1);
+	ret = (unsigned char)memory_page_read(vm_mngr, 8, addr);
+	return ret;
+}
+unsigned short vm_MEM_LOOKUP_16(vm_mngr_t* vm_mngr, uint64_t addr)
+{
+	unsigned short ret;
+	add_mem_read(vm_mngr, addr, 2);
+	ret = (unsigned short)memory_page_read(vm_mngr, 16, addr);
+	return ret;
+}
+unsigned int vm_MEM_LOOKUP_32(vm_mngr_t* vm_mngr, uint64_t addr)
+{
+	unsigned int ret;
+	add_mem_read(vm_mngr, addr, 4);
+	ret = (unsigned int)memory_page_read(vm_mngr, 32, addr);
+	return ret;
+}
+uint64_t vm_MEM_LOOKUP_64(vm_mngr_t* vm_mngr, uint64_t addr)
+{
+	uint64_t ret;
+	add_mem_read(vm_mngr, addr, 8);
+	ret = memory_page_read(vm_mngr, 64, addr);
+	return ret;
+}
+
+
+int vm_read_mem(vm_mngr_t* vm_mngr, uint64_t addr, char** buffer_ptr, size_t size)
+{
+       char* buffer;
+       size_t len;
+       uint64_t addr_diff;
+       size_t addr_diff_st;
+       struct memory_page_node * mpn;
+
+       buffer = malloc(size);
+       *buffer_ptr = buffer;
+       if (!buffer){
+	      fprintf(stderr, "Error: cannot alloc read\n");
+	      exit(EXIT_FAILURE);
+       }
+
+       /* read is multiple page wide */
+       while (size){
+	      mpn = get_memory_page_from_address(vm_mngr, addr, 1);
+	      if (!mpn){
+		      free(*buffer_ptr);
+		      PyErr_SetString(PyExc_RuntimeError, "Error: cannot find address");
+		      return -1;
+	      }
+
+	      addr_diff = addr - mpn->ad;
+	      if (addr_diff > SIZE_MAX) {
+		      fprintf(stderr, "Size too big\n");
+		      exit(EXIT_FAILURE);
+	      }
+	      addr_diff_st = (size_t) addr_diff;
+	      len = MIN(size, mpn->size - addr_diff_st);
+	      memcpy(buffer, (char*)mpn->ad_hp + (addr_diff_st), len);
+	      buffer += len;
+	      addr += len;
+	      size -= len;
+       }
+
+       return 0;
+}
+
+
+/*
+   Try to read @size bytes from vm mmemory
+   Return the number of bytes consecutively read
+*/
+uint64_t vm_read_mem_ret_buf(vm_mngr_t* vm_mngr, uint64_t addr, size_t size, char *buffer)
+{
+	size_t len;
+	uint64_t addr_diff;
+	uint64_t size_out;
+	size_t addr_diff_st;
+
+	struct memory_page_node * mpn;
+
+	size_out = 0;
+	/* read is multiple page wide */
+	while (size){
+		mpn = get_memory_page_from_address(vm_mngr, addr, 0);
+		if (!mpn){
+			return size_out;
+		}
+
+		addr_diff = addr - mpn->ad;
+		if (addr_diff > SIZE_MAX) {
+			fprintf(stderr, "Size too big\n");
+			exit(EXIT_FAILURE);
+		}
+		addr_diff_st = (size_t) addr_diff;
+		len = MIN(size, mpn->size - addr_diff_st);
+		memcpy(buffer, (char*)mpn->ad_hp + (addr_diff_st), len);
+		buffer += len;
+		size_out += len;
+		addr += len;
+		size -= len;
+	}
+
+	return size_out;
+}
+
+
+int vm_write_mem(vm_mngr_t* vm_mngr, uint64_t addr, char *buffer, size_t size)
+{
+       size_t len;
+       uint64_t addr_diff;
+       size_t addr_diff_st;
+       struct memory_page_node * mpn;
+
+       if (size > SIZE_MAX) {
+	       fprintf(stderr, "Write size wider than supported system\n");
+	       exit(EXIT_FAILURE);
+       }
+
+       /* write is multiple page wide */
+       while (size){
+	      mpn = get_memory_page_from_address(vm_mngr, addr, 1);
+	      if (!mpn){
+		      PyErr_SetString(PyExc_RuntimeError, "Error: cannot find address");
+		      return -1;
+	      }
+
+	      addr_diff = addr - mpn->ad;
+	      if (addr_diff > SIZE_MAX) {
+		      fprintf(stderr, "Size too big\n");
+		      exit(EXIT_FAILURE);
+	      }
+	      addr_diff_st = (size_t) addr_diff;
+	      len = MIN(size, mpn->size - addr_diff_st);
+	      memcpy((char*)mpn->ad_hp + addr_diff_st, buffer, len);
+	      buffer += len;
+	      addr += len;
+	      size -= len;
+       }
+
+       return 0;
+}
+
+
+
+int is_mapped(vm_mngr_t* vm_mngr, uint64_t addr, size_t size)
+{
+       size_t len;
+       uint64_t addr_diff;
+       size_t addr_diff_st;
+       struct memory_page_node * mpn;
+
+       if (size > SIZE_MAX) {
+	       fprintf(stderr, "Test size wider than supported system\n");
+	       exit(EXIT_FAILURE);
+       }
+
+       /* test multiple page wide */
+       while (size){
+	      mpn = get_memory_page_from_address(vm_mngr, addr, 0);
+	      if (!mpn)
+		      return 0;
+
+	      addr_diff = addr - mpn->ad;
+	      if (addr_diff > SIZE_MAX) {
+		      fprintf(stderr, "Size too big\n");
+		      exit(EXIT_FAILURE);
+	      }
+	      addr_diff_st = (size_t) addr_diff;
+	      len = MIN(size, mpn->size - addr_diff_st);
+	      addr += len;
+	      size -= len;
+       }
+
+       return 1;
+}
+
+struct memory_page_node * create_memory_page_node(uint64_t ad, size_t size, unsigned int access, const char *name)
+{
+	struct memory_page_node * mpn;
+	void* ad_hp;
+
+	mpn = malloc(sizeof(*mpn));
+	if (!mpn){
+		fprintf(stderr, "Error: cannot alloc mpn\n");
+		return NULL;
+	}
+	ad_hp = malloc(size);
+	if (!ad_hp){
+		free(mpn);
+		fprintf(stderr, "Error: cannot alloc %zu\n", size);
+		return NULL;
+	}
+	mpn->name = malloc(strlen(name) + 1);
+	if (!mpn->name){
+		free(mpn);
+		free(ad_hp);
+		fprintf(stderr, "Error: cannot alloc\n");
+		return NULL;
+	}
+
+	mpn->ad = ad;
+	mpn->size = size;
+	mpn->access = access;
+	mpn->ad_hp = ad_hp;
+	strcpy(mpn->name, name);
+
+	return mpn;
+}
+
+
+struct code_bloc_node * create_code_bloc_node(uint64_t ad_start, uint64_t ad_stop)
+{
+	struct code_bloc_node * cbp;
+
+	cbp = malloc(sizeof(*cbp));
+	if (!cbp){
+		fprintf(stderr, "Error: cannot alloc cbp\n");
+		exit(EXIT_FAILURE);
+	}
+
+	cbp->ad_start = ad_start;
+	cbp->ad_stop = ad_stop;
+
+	return cbp;
+}
+
+
+void add_code_bloc(vm_mngr_t* vm_mngr, struct code_bloc_node* cbp)
+{
+	LIST_INSERT_HEAD(&vm_mngr->code_bloc_pool, cbp, next);
+	if (vm_mngr->code_bloc_pool_ad_min> cbp->ad_start)
+		vm_mngr->code_bloc_pool_ad_min = cbp->ad_start;
+	if (vm_mngr->code_bloc_pool_ad_max< cbp->ad_stop)
+		vm_mngr->code_bloc_pool_ad_max = cbp->ad_stop;
+}
+
+void dump_code_bloc_pool(vm_mngr_t* vm_mngr)
+{
+	struct code_bloc_node * cbp;
+
+	LIST_FOREACH(cbp, &vm_mngr->code_bloc_pool, next){
+		printf("ad start %"PRIX64" ad_stop %"PRIX64"\n",
+		       cbp->ad_start,
+		       cbp->ad_stop);
+	}
+}
+
+
+void init_memory_page_pool(vm_mngr_t* vm_mngr)
+{
+
+	vm_mngr->memory_pages_number = 0;
+	vm_mngr->memory_pages_array = NULL;
+}
+
+void init_code_bloc_pool(vm_mngr_t* vm_mngr)
+{
+	LIST_INIT(&vm_mngr->code_bloc_pool);
+	vm_mngr->code_bloc_pool_ad_min = 0xffffffffffffffffULL;
+	vm_mngr->code_bloc_pool_ad_max = 0;
+
+	memory_access_list_init(&(vm_mngr->memory_r));
+	memory_access_list_init(&(vm_mngr->memory_w));
+
+
+}
+
+void init_memory_breakpoint(vm_mngr_t* vm_mngr)
+{
+	LIST_INIT(&vm_mngr->memory_breakpoint_pool);
+}
+
+
+void reset_memory_page_pool(vm_mngr_t* vm_mngr)
+{
+	struct memory_page_node * mpn;
+	int i;
+	for (i=0;i<vm_mngr->memory_pages_number; i++) {
+		mpn = &vm_mngr->memory_pages_array[i];
+		free(mpn->ad_hp);
+		free(mpn->name);
+	}
+	free(vm_mngr->memory_pages_array);
+	vm_mngr->memory_pages_array = NULL;
+	vm_mngr->memory_pages_number = 0;
+}
+
+
+void reset_code_bloc_pool(vm_mngr_t* vm_mngr)
+{
+	struct code_bloc_node * cbp;
+
+
+	while (!LIST_EMPTY(&vm_mngr->code_bloc_pool)) {
+		cbp = LIST_FIRST(&vm_mngr->code_bloc_pool);
+		LIST_REMOVE(cbp, next);
+		free(cbp);
+	}
+	vm_mngr->code_bloc_pool_ad_min = 0xffffffffffffffffULL;
+	vm_mngr->code_bloc_pool_ad_max = 0;
+}
+
+void reset_memory_access(vm_mngr_t* vm_mngr)
+{
+	memory_access_list_reset(&(vm_mngr->memory_r));
+	memory_access_list_reset(&(vm_mngr->memory_w));
+}
+
+void reset_memory_breakpoint(vm_mngr_t* vm_mngr)
+{
+	struct memory_breakpoint_info * mpn;
+
+	while (!LIST_EMPTY(&vm_mngr->memory_breakpoint_pool)) {
+		mpn = LIST_FIRST(&vm_mngr->memory_breakpoint_pool);
+		LIST_REMOVE(mpn, next);
+		free(mpn);
+	}
+
+}
+
+
+
+/* We don't use dichotomy here for the insertion */
+int is_mpn_in_tab(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a)
+{
+	struct memory_page_node * mpn;
+	int i;
+
+	for (i=0;i<vm_mngr->memory_pages_number; i++) {
+		mpn = &vm_mngr->memory_pages_array[i];
+		if (mpn->ad >= mpn_a->ad + mpn_a->size)
+			continue;
+		if (mpn->ad + mpn->size  <= mpn_a->ad)
+			continue;
+		fprintf(stderr,
+			"Error: attempt to add page (0x%"PRIX64" 0x%"PRIX64") "
+			"overlapping page (0x%"PRIX64" 0x%"PRIX64")\n",
+			mpn_a->ad, mpn_a->ad + mpn_a->size,
+			mpn->ad, mpn->ad + mpn->size);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+
+/* We don't use dichotomy here for the insertion */
+void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a)
+{
+	struct memory_page_node * mpn;
+	int i;
+
+	for (i=0; i < vm_mngr->memory_pages_number; i++) {
+		mpn = &vm_mngr->memory_pages_array[i];
+		if (mpn->ad < mpn_a->ad)
+			continue;
+		break;
+	}
+	vm_mngr->memory_pages_array = realloc(vm_mngr->memory_pages_array,
+					      sizeof(struct memory_page_node) *
+					      (vm_mngr->memory_pages_number+1));
+	if (vm_mngr->memory_pages_array == NULL) {
+		fprintf(stderr, "cannot realloc struct memory_page_node vm_mngr->memory_pages_array\n");
+		exit(EXIT_FAILURE);
+	}
+
+
+	memmove(&vm_mngr->memory_pages_array[i+1],
+		&vm_mngr->memory_pages_array[i],
+		sizeof(struct memory_page_node) * (vm_mngr->memory_pages_number - i)
+		);
+
+	vm_mngr->memory_pages_array[i] = *mpn_a;
+	vm_mngr->memory_pages_number ++;
+}
+
+void remove_memory_page(vm_mngr_t* vm_mngr, uint64_t ad)
+{
+  struct memory_page_node * mpn;
+  int i;
+
+  i = find_page_node(vm_mngr->memory_pages_array,
+		     ad,
+		     0,
+		     vm_mngr->memory_pages_number - 1);
+  if (i < 0) {
+    return;
+  }
+
+  mpn = &vm_mngr->memory_pages_array[i];
+  free(mpn->name);
+  free(mpn->ad_hp);
+  memmove(&vm_mngr->memory_pages_array[i],
+  	      &vm_mngr->memory_pages_array[i+1],
+  	      sizeof(struct memory_page_node) * (vm_mngr->memory_pages_number - i - 1)
+  	      );
+  vm_mngr->memory_pages_number --;
+  vm_mngr->memory_pages_array = realloc(vm_mngr->memory_pages_array,
+					sizeof(struct memory_page_node) *
+					(vm_mngr->memory_pages_number));
+}
+
+/* Return a char* representing the repr of vm_mngr_t object */
+char* dump(vm_mngr_t* vm_mngr)
+{
+	char buf[0x100];
+	int length;
+	char *buf_final;
+	int i;
+	char buf_addr[0x20];
+	char buf_size[0x20];
+	struct memory_page_node * mpn;
+	/*             0x1234567812345678 0x1234567812345678        */
+	char* intro = "Addr               Size               Access Comment\n";
+	size_t total_len = strlen(intro) + 1;
+
+	buf_final = malloc(total_len);
+	if (buf_final == NULL) {
+		fprintf(stderr, "Error: cannot alloc char* buf_final\n");
+		exit(EXIT_FAILURE);
+	}
+	strcpy(buf_final, intro);
+	for (i=0; i< vm_mngr->memory_pages_number; i++) {
+		mpn = &vm_mngr->memory_pages_array[i];
+		snprintf(buf_addr, sizeof(buf_addr),
+			 "0x%"PRIX64, (uint64_t)mpn->ad);
+		snprintf(buf_size, sizeof(buf_size),
+			 "0x%"PRIX64, (uint64_t)mpn->size);
+
+		length = snprintf(buf, sizeof(buf) - 1,
+				  "%-18s %-18s %c%c%c    %s",
+				  buf_addr,
+				  buf_size,
+				  mpn->access & PAGE_READ? 'R':'_',
+				  mpn->access & PAGE_WRITE? 'W':'_',
+				  mpn->access & PAGE_EXEC? 'X':'_',
+				  mpn->name
+				  );
+		strcat(buf, "\n");
+		total_len += length + 1 + 1;
+		buf_final = realloc(buf_final, total_len);
+		if (buf_final == NULL) {
+			fprintf(stderr, "cannot realloc char* buf_final\n");
+			exit(EXIT_FAILURE);
+		}
+		strcat(buf_final, buf);
+	}
+
+	return buf_final;
+}
+
+void dump_memory_breakpoint_pool(vm_mngr_t* vm_mngr)
+{
+	struct memory_breakpoint_info * mpn;
+
+	LIST_FOREACH(mpn, &vm_mngr->memory_breakpoint_pool, next){
+		printf("ad %"PRIX64" size %"PRIX64" access %"PRIX64"\n",
+		       mpn->ad,
+		       mpn->size,
+		       mpn->access
+		       );
+	}
+}
+
+
+void add_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, uint64_t size, unsigned int access)
+{
+	struct memory_breakpoint_info * mpn_a;
+	mpn_a = malloc(sizeof(*mpn_a));
+	if (!mpn_a) {
+		fprintf(stderr, "Error: cannot alloc\n");
+		exit(EXIT_FAILURE);
+	}
+	mpn_a->ad = ad;
+	mpn_a->size = size;
+	mpn_a->access = access;
+
+	LIST_INSERT_HEAD(&vm_mngr->memory_breakpoint_pool, mpn_a, next);
+
+}
+
+void remove_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, unsigned int access)
+{
+	struct memory_breakpoint_info * mpn;
+
+	LIST_FOREACH(mpn, &vm_mngr->memory_breakpoint_pool, next){
+		if (mpn->ad == ad && mpn->access == access)
+			LIST_REMOVE(mpn, next);
+	}
+
+}
+
+
+/********************************************/
+
+void hexdump(char* m, unsigned int l)
+{
+  unsigned int i, j, last;
+  last = 0;
+  for (i=0;i<l;i++){
+      if (!(i%0x10) && i){
+      last = i;
+      printf("    ");
+      for (j=-0x10;j<0;j++){
+	      if (isprint(m[i+j])){
+		      printf("%c", m[i+j]);
+	      }
+	      else{
+		      printf(".");
+	      }
+      }
+      printf("\n");
+      }
+      printf("%.2X ", m[i]&0xFF);
+  }
+  l-=last;
+  if (l){
+    for (j=i;j<last+0x10;j++)
+      printf("   ");
+    printf("    ");
+    for (j = 0;l;j++){
+      if (isprint(m[last+j])){
+	      printf("%c", m[last+j]);
+      }
+      else{
+	      printf(".");
+      }
+      l--;
+    }
+  }
+  printf("\n");
+
+}
+
+
+// Return vm_mngr's exception flag value
+_MIASM_EXPORT uint64_t get_exception_flag(vm_mngr_t* vm_mngr)
+{
+	return vm_mngr->exception_flags;
+}