From bd49f02dee1a12a683c0a900a29ed24a0fcbfb47 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Thu, 19 Mar 2026 15:59:27 +0100 Subject: [PATCH] command parser updated --- setup.py | 3 +- src/coparun/coparun.c | 18 +- src/coparun/coparun_module.c | 6 +- src/coparun/mem_man.c | 43 ++++- src/coparun/mem_man.h | 6 + src/coparun/runmem.c | 331 +++++++++++++++++++---------------- src/coparun/runmem.h | 7 + 7 files changed, 255 insertions(+), 159 deletions(-) diff --git a/setup.py b/setup.py index 529ed6c..0bd1286 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,8 @@ ext = Extension( "src/coparun/coparun_module.c", "src/coparun/runmem.c", "src/coparun/mem_man.c" - ] + ], + #define_macros=[("ENABLE_BASIC_LOGGING", None)] ) setup( diff --git a/src/coparun/coparun.c b/src/coparun/coparun.c index 10dfada..f9effe4 100644 --- a/src/coparun/coparun.c +++ b/src/coparun/coparun.c @@ -64,10 +64,22 @@ int main(int argc, char *argv[]) { targ.data_memory = NULL; targ.entr_point = NULL; targ.data_offs = 0; + targ.rx_state = RX_STATE_IDLE; + targ.state_flag = 0; - int ret = parse_commands(&targ, file_buff); + int ret = parse_commands(&targ, file_buff, (uint32_t)sz); - if (ret == 2) { + /*int offs = 0; + for (int i = 0; i < sz + 1; i++) { + if (i - offs < 0) { + printf("Error: parse_commands returned invalid offset i=%i offs=%i\n", i, offs); + return EXIT_FAILURE; + } + offs += parse_commands(&targ, file_buff + offs, i - offs); + printf("> i=%i offs=%i\n", i, offs); + }*/ + + if (targ.state_flag == STATE_FLAG_DUMP_CODE) { /* Dump code for debugging */ if (argc != 3) { fprintf(stderr, "Usage: %s \n", argv[0]); @@ -80,5 +92,5 @@ int main(int argc, char *argv[]) { free_memory(&targ); - return ret < 0; + return targ.state_flag < 0; } diff --git a/src/coparun/coparun_module.c b/src/coparun/coparun_module.c index 1e50f29..de1eb7f 100644 --- a/src/coparun/coparun_module.c +++ b/src/coparun/coparun_module.c @@ -14,7 +14,6 @@ static PyObject* coparun(PyObject* self, PyObject* args) { PyObject *handle_obj; const char *buf; Py_ssize_t buf_len; - int result; // Expect: handle, bytes if (!PyArg_ParseTuple(args, "Oy#", &handle_obj, &buf, &buf_len)) { @@ -30,10 +29,10 @@ static PyObject* coparun(PyObject* self, PyObject* args) { /* If parse_commands may run for a long time, release the GIL. */ Py_BEGIN_ALLOW_THREADS - result = parse_commands(context, (uint8_t*)buf); + parse_commands(context, (uint8_t*)buf, (uint32_t)buf_len); Py_END_ALLOW_THREADS - return PyLong_FromLong(result); + return PyLong_FromLong(context->state_flag); } static PyObject* read_data_mem(PyObject* self, PyObject* args) { @@ -74,6 +73,7 @@ static PyObject* read_data_mem(PyObject* self, PyObject* args) { } static PyObject* create_target(PyObject* self, PyObject* args) { + // Allocate a new runmem_t struct, zero-initialized runmem_t *context = (runmem_t*)calloc(1, sizeof(runmem_t)); if (!context) { return PyErr_NoMemory(); diff --git a/src/coparun/mem_man.c b/src/coparun/mem_man.c index 8e89978..5fab4b3 100644 --- a/src/coparun/mem_man.c +++ b/src/coparun/mem_man.c @@ -6,12 +6,46 @@ * handles memory management accordingly. */ -#include #include -#include -#ifdef _WIN32 + +#if defined DATA_MEMORY_ADDR || defined EXECUTABLE_MEMORY_ADDR +/* Bare metal implementations */ +#if not defined(EXECUTABLE_MEMORY_ADDR) || not defined(DATA_MEMORY_ADDR) + #error "For bare metal, you must define DATA_MEMORY_ADDR and DATA_EXECUTABLE_MEMORY_ADDR." +#endif + +uint8_t *allocate_executable_memory(uint32_t num_bytes) { + return (uint8_t*)EXECUTABLE_MEMORY_ADDR; +} + +uint8_t *allocate_data_memory(uint32_t num_bytes) { + return (uint8_t*)DATA_MEMORY_ADDR; +} + +int mark_mem_executable(uint8_t *memory, uint32_t memory_len) { + /* No-op for bare metal */ + return 1; +} + +void deallocate_memory(uint8_t *memory, uint32_t memory_len) { + /* No-op for bare metal */ +} + +void memcpy(void *dest, const void *src, size_t n) { + uint8_t *d = (uint8_t*)dest; + const uint8_t *s = (const uint8_t*)src; + for (size_t i = 0; i < n; i++) { + d[i] = s[i]; + } + return 0; +} + + +#elif defined _WIN32 #include +#include +#include /* Windows implementations */ @@ -62,6 +96,9 @@ void deallocate_memory(uint8_t *memory, uint32_t memory_len) { #else #include +#include +#include +#include /* POSIX implementations */ diff --git a/src/coparun/mem_man.h b/src/coparun/mem_man.h index 03fc662..4767f33 100644 --- a/src/coparun/mem_man.h +++ b/src/coparun/mem_man.h @@ -7,4 +7,10 @@ uint8_t *allocate_buffer_memory(uint32_t num_bytes); int mark_mem_executable(uint8_t *memory, uint32_t memory_len); void deallocate_memory(uint8_t *memory, uint32_t memory_len); +#ifdef DATA_MEMORY_ADDR +void memcpy(void *dest, const void *src, size_t n); +#else +#include +#endif + #endif /* MEM_MAN_H */ diff --git a/src/coparun/runmem.c b/src/coparun/runmem.c index d0bded9..77509dc 100644 --- a/src/coparun/runmem.c +++ b/src/coparun/runmem.c @@ -5,10 +5,6 @@ * and jumps to the entry point of the copapy program */ -#include -#include -#include -#include #include "runmem.h" #include "mem_man.h" @@ -60,7 +56,7 @@ void patch_arm32_abs(uint8_t *patch_addr, uint32_t imm16) void patch_arm_thm_abs(uint8_t *patch_addr, uint32_t imm16) { // Thumb MOVW (T3) / MOVT (T1) encoding - + uint16_t *instr16 = (uint16_t *)patch_addr; uint16_t first_half = instr16[0]; uint16_t second_half = instr16[1]; @@ -144,176 +140,213 @@ int floor_div(int a, int b) { return a / b - ((a % b != 0) && ((a < 0) != (b < 0))); } -int parse_commands(runmem_t *context, uint8_t *bytes) { +int parse_commands(runmem_t *context, uint8_t *bytes, uint32_t lengths) { int32_t value; uint32_t command; uint32_t patch_mask; int32_t patch_scale; uint32_t offs; uint32_t size; - int end_flag = 0; uint32_t rel_entr_point = 0; + uint32_t header_size; + uint8_t *byte_offset = bytes; - while(!end_flag) { - command = *(uint32_t*)bytes; - bytes += 4; - switch(command) { - case ALLOCATE_DATA: - size = *(uint32_t*)bytes; bytes += 4; - context->data_memory = allocate_data_memory(size); - context->data_memory_len = size; - LOG("ALLOCATE_DATA size=%i mem_addr=%p\n", size, (void*)context->data_memory); - if (!update_data_offs(context)) end_flag = -4; - break; + while(bytes < byte_offset + lengths) { + //LOG("# LOOP START: context->rx_state=%i byte_index=%i lengths=%i\n", context->rx_state, bytes - byte_offset, lengths); + if (context->rx_state == RX_STATE_IDLE) { + uint32_t remaining_bytes = (uint32_t)(byte_offset + lengths - bytes); + if (remaining_bytes < 4) { + return bytes - byte_offset; // Return the number of bytes processed + } + command = *(uint32_t*)bytes; + header_size = (command >> 16) & 0xFFFF; + if (remaining_bytes < 4 + header_size) { + return bytes - byte_offset; // Return the number of bytes processed + } + //LOG("+ Switch to RX_STATE_HEADER; context->rx_state=%i byte_index=%i lengths=%i\n", context->rx_state, bytes - byte_offset, lengths); + context->rx_state = RX_STATE_HEADER; + } else if (context->rx_state == RX_STATE_DATA) { + uint32_t chunk_size = context->data_size; + if (lengths - (bytes - byte_offset) < chunk_size) { + chunk_size = lengths - (bytes - byte_offset); + } + //LOG(" -> COPY_DATA chunk_size=%i remaining_data_size=%i\n", chunk_size, context->data_size); + memcpy(context->data_dest, context->data_src, chunk_size); + context->data_dest += chunk_size; + context->data_src += chunk_size; + context->data_size -= chunk_size; + bytes += chunk_size; + if (context->data_size == 0) { + //LOG(" -> COPY_DATA completed\n"); + context->rx_state = RX_STATE_IDLE; + } + } else if (context->rx_state == RX_STATE_HEADER) { + bytes += 4; + context->rx_state = RX_STATE_IDLE; + switch(command) { + case ALLOCATE_DATA: + size = *(uint32_t*)bytes; bytes += 4; + context->data_memory = allocate_data_memory(size); + context->data_memory_len = size; + LOG("ALLOCATE_DATA size=%i mem_addr=%p\n", size, (void*)context->data_memory); + if (!update_data_offs(context)) context->state_flag = STATE_FLAG_MEM_DIST; + break; - case COPY_DATA: - offs = *(uint32_t*)bytes; bytes += 4; - size = *(uint32_t*)bytes; bytes += 4; - LOG("COPY_DATA offs=%i size=%i\n", offs, size); - memcpy(context->data_memory + offs, bytes, size); bytes += size; - break; + case COPY_DATA: + offs = *(uint32_t*)bytes; bytes += 4; + size = *(uint32_t*)bytes; bytes += 4; + LOG("COPY_DATA offs=%i size=%i\n", offs, size); + context->data_src = bytes; + context->data_dest = context->data_memory + offs; + context->data_size = size; + context->rx_state = RX_STATE_DATA; + break; - case ALLOCATE_CODE: - size = *(uint32_t*)bytes; bytes += 4; - context->executable_memory = allocate_executable_memory(size); - context->executable_memory_len = size; - LOG("ALLOCATE_CODE size=%i mem_addr=%p\n", size, (void*)context->executable_memory); - if (!update_data_offs(context)) end_flag = -4; - break; + case ALLOCATE_CODE: + size = *(uint32_t*)bytes; bytes += 4; + context->executable_memory = allocate_executable_memory(size); + context->executable_memory_len = size; + LOG("ALLOCATE_CODE size=%i mem_addr=%p\n", size, (void*)context->executable_memory); + if (!update_data_offs(context)) context->state_flag = STATE_FLAG_MEM_DIST; + break; - case COPY_CODE: - offs = *(uint32_t*)bytes; bytes += 4; - size = *(uint32_t*)bytes; bytes += 4; - LOG("COPY_CODE offs=%i size=%i\n", offs, size); - memcpy(context->executable_memory + offs, bytes, size); bytes += size; - break; + case COPY_CODE: + offs = *(uint32_t*)bytes; bytes += 4; + size = *(uint32_t*)bytes; bytes += 4; + LOG("COPY_CODE offs=%i size=%i\n", offs, size); + context->data_src = bytes; + context->data_dest = context->executable_memory + offs; + context->data_size = size; + context->rx_state = RX_STATE_DATA; + break; - case PATCH_FUNC: - offs = *(uint32_t*)bytes; bytes += 4; - patch_mask = *(uint32_t*)bytes; bytes += 4; - patch_scale = *(int32_t*)bytes; bytes += 4; - value = *(int32_t*)bytes; bytes += 4; - LOG("PATCH_FUNC patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", - offs, patch_mask, patch_scale, value); - patch(context->executable_memory + offs, patch_mask, value / patch_scale); - break; + case PATCH_FUNC: + offs = *(uint32_t*)bytes; bytes += 4; + patch_mask = *(uint32_t*)bytes; bytes += 4; + patch_scale = *(int32_t*)bytes; bytes += 4; + value = *(int32_t*)bytes; bytes += 4; + LOG("PATCH_FUNC patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", + offs, patch_mask, patch_scale, value); + patch(context->executable_memory + offs, patch_mask, value / patch_scale); + break; - case PATCH_OBJECT: - offs = *(uint32_t*)bytes; bytes += 4; - patch_mask = *(uint32_t*)bytes; bytes += 4; - patch_scale = *(int32_t*)bytes; bytes += 4; - value = *(int32_t*)bytes; bytes += 4; - LOG("PATCH_OBJECT patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", - offs, patch_mask, patch_scale, value); - patch(context->executable_memory + offs, patch_mask, value / patch_scale + context->data_offs / patch_scale); - break; + case PATCH_OBJECT: + offs = *(uint32_t*)bytes; bytes += 4; + patch_mask = *(uint32_t*)bytes; bytes += 4; + patch_scale = *(int32_t*)bytes; bytes += 4; + value = *(int32_t*)bytes; bytes += 4; + LOG("PATCH_OBJECT patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", + offs, patch_mask, patch_scale, value); + patch(context->executable_memory + offs, patch_mask, value / patch_scale + context->data_offs / patch_scale); + break; - case PATCH_OBJECT_ABS: - offs = *(uint32_t*)bytes; bytes += 4; - patch_mask = *(uint32_t*)bytes; bytes += 4; - patch_scale = *(int32_t*)bytes; bytes += 4; - value = *(int32_t*)bytes; bytes += 4; - LOG("PATCH_OBJECT_ABS patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", - offs, patch_mask, patch_scale, value); - patch(context->executable_memory + offs, patch_mask, value / patch_scale); - break; + case PATCH_OBJECT_ABS: + offs = *(uint32_t*)bytes; bytes += 4; + patch_mask = *(uint32_t*)bytes; bytes += 4; + patch_scale = *(int32_t*)bytes; bytes += 4; + value = *(int32_t*)bytes; bytes += 4; + LOG("PATCH_OBJECT_ABS patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", + offs, patch_mask, patch_scale, value); + patch(context->executable_memory + offs, patch_mask, value / patch_scale); + break; - case PATCH_OBJECT_REL: - offs = *(uint32_t*)bytes; bytes += 4; - bytes += 4; - patch_scale = *(int32_t*)bytes; bytes += 4; - value = *(int32_t*)bytes; bytes += 4; - LOG("PATCH_OBJECT_REL patch_offs=%i patch_addr=%p scale=%i value=%i\n", - offs, (void*)(context->data_memory + value), patch_scale, value); - *(void **)(context->executable_memory + offs) = context->data_memory + value; - break; + case PATCH_OBJECT_REL: + offs = *(uint32_t*)bytes; bytes += 4; + bytes += 4; + patch_scale = *(int32_t*)bytes; bytes += 4; + value = *(int32_t*)bytes; bytes += 4; + LOG("PATCH_OBJECT_REL patch_offs=%i patch_addr=%p scale=%i value=%i\n", + offs, (void*)(context->data_memory + value), patch_scale, value); + *(void **)(context->executable_memory + offs) = context->data_memory + value; + break; - case PATCH_OBJECT_HI21: - offs = *(uint32_t*)bytes; bytes += 4; - bytes += 4; - patch_scale = *(int32_t*)bytes; bytes += 4; - value = *(int32_t*)bytes; bytes += 4; - LOG("PATCH_OBJECT_HI21 patch_offs=%i scale=%i value=%i res_value=%i\n", - offs, patch_scale, value, floor_div(context->data_offs + value, patch_scale) - (int32_t)offs / patch_scale); - patch_hi21(context->executable_memory + offs, floor_div(context->data_offs + value, patch_scale) - (int32_t)offs / patch_scale); - break; + case PATCH_OBJECT_HI21: + offs = *(uint32_t*)bytes; bytes += 4; + bytes += 4; + patch_scale = *(int32_t*)bytes; bytes += 4; + value = *(int32_t*)bytes; bytes += 4; + LOG("PATCH_OBJECT_HI21 patch_offs=%i scale=%i value=%i res_value=%i\n", + offs, patch_scale, value, floor_div(context->data_offs + value, patch_scale) - (int32_t)offs / patch_scale); + patch_hi21(context->executable_memory + offs, floor_div(context->data_offs + value, patch_scale) - (int32_t)offs / patch_scale); + break; - case PATCH_OBJECT_ARM32_ABS: - offs = *(uint32_t*)bytes; bytes += 4; - patch_mask = *(uint32_t*)bytes; bytes += 4; - patch_scale = *(int32_t*)bytes; bytes += 4; - value = *(int32_t*)bytes; bytes += 4; - LOG("PATCH_OBJECT_ARM32_ABS patch_offs=%i patch_mask=%#08x scale=%i value=%i imm16=%#04x\n", - offs, patch_mask, patch_scale, value, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); - patch_arm32_abs(context->executable_memory + offs, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); - break; + case PATCH_OBJECT_ARM32_ABS: + offs = *(uint32_t*)bytes; bytes += 4; + patch_mask = *(uint32_t*)bytes; bytes += 4; + patch_scale = *(int32_t*)bytes; bytes += 4; + value = *(int32_t*)bytes; bytes += 4; + LOG("PATCH_OBJECT_ARM32_ABS patch_offs=%i patch_mask=%#08x scale=%i value=%i imm16=%#04x\n", + offs, patch_mask, patch_scale, value, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); + patch_arm32_abs(context->executable_memory + offs, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); + break; - case PATCH_FUNC_ARM32_THM: - offs = *(uint32_t*)bytes; bytes += 4; - patch_mask = *(uint32_t*)bytes; bytes += 4; - patch_scale = *(int32_t*)bytes; bytes += 4; - value = *(int32_t*)bytes; bytes += 4; - LOG("PATCH_FUNC_ARM32_THM patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", - offs, patch_mask, patch_scale, value); - patch_arm_thm_jump24(context->executable_memory + offs, value); - break; + case PATCH_FUNC_ARM32_THM: + offs = *(uint32_t*)bytes; bytes += 4; + patch_mask = *(uint32_t*)bytes; bytes += 4; + patch_scale = *(int32_t*)bytes; bytes += 4; + value = *(int32_t*)bytes; bytes += 4; + LOG("PATCH_FUNC_ARM32_THM patch_offs=%i patch_mask=%#08x scale=%i value=%i\n", + offs, patch_mask, patch_scale, value); + patch_arm_thm_jump24(context->executable_memory + offs, value); + break; - case PATCH_OBJECT_ARM32_ABS_THM: - offs = *(uint32_t*)bytes; bytes += 4; - patch_mask = *(uint32_t*)bytes; bytes += 4; - patch_scale = *(int32_t*)bytes; bytes += 4; - value = *(int32_t*)bytes; bytes += 4; - LOG("PATCH_OBJECT_ARM32_ABS_THM patch_offs=%i patch_mask=%#08x scale=%i value=%i imm16=%#04x\n", - offs, patch_mask, patch_scale, value, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); - patch_arm_thm_abs(context->executable_memory + offs, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); - break; + case PATCH_OBJECT_ARM32_ABS_THM: + offs = *(uint32_t*)bytes; bytes += 4; + patch_mask = *(uint32_t*)bytes; bytes += 4; + patch_scale = *(int32_t*)bytes; bytes += 4; + value = *(int32_t*)bytes; bytes += 4; + LOG("PATCH_OBJECT_ARM32_ABS_THM patch_offs=%i patch_mask=%#08x scale=%i value=%i imm16=%#04x\n", + offs, patch_mask, patch_scale, value, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); + patch_arm_thm_abs(context->executable_memory + offs, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); + break; - case ENTRY_POINT: - rel_entr_point = *(uint32_t*)bytes; bytes += 4; - context->entr_point = (entry_point_t)(context->executable_memory + rel_entr_point); - LOG("ENTRY_POINT rel_entr_point=%i\n", rel_entr_point); - mark_mem_executable(context->executable_memory, context->executable_memory_len); - break; + case ENTRY_POINT: + rel_entr_point = *(uint32_t*)bytes; bytes += 4; + context->entr_point = (entry_point_t)(context->executable_memory + rel_entr_point); + LOG("ENTRY_POINT rel_entr_point=%i\n", rel_entr_point); + mark_mem_executable(context->executable_memory, context->executable_memory_len); + break; - case RUN_PROG: - LOG("RUN_PROG\n"); - { - int ret = context->entr_point(); - (void)ret; - BLOG("Return value: %i\n", ret); - } - break; + case RUN_PROG: + LOG("RUN_PROG\n"); + { + int ret = context->entr_point(); + (void)ret; + BLOG("Return value: %i\n", ret); + } + break; - case READ_DATA: - offs = *(uint32_t*)bytes; bytes += 4; - size = *(uint32_t*)bytes; bytes += 4; - BLOG("READ_DATA offs=%i size=%i data=", offs, size); - for (uint32_t i = 0; i < size; i++) { - printf("%02X ", context->data_memory[offs + i]); - } - printf("\n"); - break; + case READ_DATA: + offs = *(uint32_t*)bytes; bytes += 4; + size = *(uint32_t*)bytes; bytes += 4; + BLOG("READ_DATA offs=%i size=%i data=", offs, size); + for (uint32_t i = 0; i < size; i++) { + PRINTF("%02X ", context->data_memory[offs + i]); + } + PRINTF("\n"); + break; - case FREE_MEMORY: - LOG("FREE_MENORY\n"); - free_memory(context); - break; + case FREE_MEMORY: + LOG("FREE_MENORY\n"); + free_memory(context); + break; - case DUMP_CODE: - LOG("DUMP_CODE\n"); - end_flag = 2; - break; + case DUMP_CODE: + LOG("DUMP_CODE\n"); + context->state_flag = STATE_FLAG_DUMP_CODE; + break; - case END_COM: - LOG("END_COM\n"); - end_flag = 1; - break; + case END_COM: + LOG("END_COM\n"); + context->state_flag = STATE_FLAG_END_COM; + break; - default: - LOG("Unknown command\n"); - end_flag = -1; - break; + default: + LOG("Unknown command\n"); + context->state_flag = STATE_FLAG_UNKNOWN_COMMAND; + break; + } } } - return end_flag; + return bytes - byte_offset; } diff --git a/src/coparun/runmem.h b/src/coparun/runmem.h index 897a306..cd74053 100644 --- a/src/coparun/runmem.h +++ b/src/coparun/runmem.h @@ -10,6 +10,13 @@ #include +#ifdef DATA_MEMORY_ADDR + #define PRINTF(...) +#else + #include + #define PRINTF(...) printf(__VA_ARGS__) +#endif + #ifdef ENABLE_LOGGING #define LOG(...) printf(__VA_ARGS__) #define BLOG(...) printf(__VA_ARGS__)