diff options
Diffstat (limited to 'common.c')
| -rw-r--r-- | common.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/common.c b/common.c new file mode 100644 index 0000000..3ed85b0 --- /dev/null +++ b/common.c @@ -0,0 +1,143 @@ +#include <stdlib.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdio.h> + +#include "common.h" + +// The global trace flag +int g_trace = 0; +// The global disassembly flag +int g_disassemble = 0; +// The global indentation amount +int g_indent = 0; + +#define MORE(b) (((b) & 0x80) != 0) +#define ERROR (len != NULL ? *len = -(ptr - start) : 0), 0 + +#define BODY(type, mask, legal) \ + const uint8_t* start = ptr; \ + type result = 0, shift = 0; \ + while (ptr < limit) { \ + uint8_t b = *ptr; \ + ptr++; \ + result = result | (((type)b & 0x7F) << shift); \ + shift += 7; \ + if (shift > (8*sizeof(type))) { \ + if (MORE(b) != 0) return ERROR; /* overlong */ \ + uint8_t upper = b & mask; \ + if (upper != 0 && upper != legal) return ERROR; /* out of range */ \ + if (len != NULL) *len = (ptr - start); \ + return result; \ + } \ + if (MORE(b)) continue; \ + type rem = ((8*sizeof(type)) - shift); \ + if (len != NULL) *len = (ptr - start); \ + return ((0x7F & mask) == legal) ? (result << rem) >> rem : result; \ + } \ + return ERROR; + +int32_t decode_i32leb(const uint8_t* ptr, const uint8_t* limit, ssize_t *len) { + BODY(int32_t, 0xF8, 0x78); +} + +uint32_t decode_u32leb(const uint8_t* ptr, const uint8_t* limit, ssize_t *len) { + BODY(uint32_t, 0xF8, 0x08); +} + +int64_t decode_i64leb(const uint8_t* ptr, const uint8_t* limit, ssize_t *len) { + BODY(int64_t, 0xFF, 0x7F); +} + +uint64_t decode_u64leb(const uint8_t* ptr, const uint8_t* limit, ssize_t *len) { + BODY(int64_t, 0xFF, 0x01); +} + +uint32_t decode_u32(const uint8_t* ptr, const uint8_t* limit, ssize_t *len) { + ssize_t remain = limit - ptr; + if (remain < 4) { + if (remain > 0) *len = -remain; + else *len = remain; + return 0; + } + uint32_t b0 = ptr[0]; + uint32_t b1 = ptr[1]; + uint32_t b2 = ptr[2]; + uint32_t b3 = ptr[3]; + *len = 4; + return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; +} + +ssize_t load_file(const char* path, uint8_t** start, uint8_t** end) { + // Open the file for reading. + int fd = open(path, O_RDONLY); + if (fd < 0) return fd; + + // Query the size of the file in bytes. + struct stat statbuf; + int r = fstat(fd, &statbuf); + if (r < 0) { // stat call failed. + close(fd); + return r; + } + + // Reject overly large files. + off_t size = statbuf.st_size; + if (size > MAX_FILE_SIZE) { // too large. + close(fd); + return -1; + } + + // Allocate memory to store the bytes. + *start = (uint8_t*)malloc(size); + *end = *start + size; + off_t remain = size; + // Read the bytes from the file until done. + for (uint8_t* p = *start; remain > 0; ) { + r = read(fd, p, remain); + if (r < 0) { // reading failed. + close(fd); + return -2; + } + remain -= r; + p += r; + } + return (int)size; +} + +// Read an unsigned 32-bit LEB, advancing the buffer. +uint32_t read_u32leb(buffer_t* buf) { + ssize_t leblen = 0; + if (buf->ptr >= buf->end) return 0; + uint32_t val = decode_u32leb(buf->ptr, buf->end, &leblen); + if (leblen <= 0) buf->ptr = buf->end; // force failure + else buf->ptr += leblen; + return val; +} + +// Read a signed 32-bit LEB, advancing the buffer. +int32_t read_i32leb(buffer_t* buf) { + ssize_t leblen = 0; + if (buf->ptr >= buf->end) return 0; + int32_t val = decode_i32leb(buf->ptr, buf->end, &leblen); + if (leblen <= 0) buf->ptr = buf->end; // force failure + else buf->ptr += leblen; + return val; +} + +// Read an unsigned 8-bit byte, advancing the buffer. +uint32_t read_u8(buffer_t* buf) { + if (buf->ptr >= buf->end) return 0; + byte val = *buf->ptr; + buf->ptr++; + return val; +} + + +ssize_t unload_file(uint8_t** start, uint8_t** end) { + free(*start); + *start = NULL; + *end = NULL; + return 0; +} |
