allow loading images from offsets

This commit is contained in:
Alex Shinn 2016-03-13 09:08:41 +09:00
parent 524179388d
commit eed963381c
3 changed files with 27 additions and 22 deletions

View file

@ -574,21 +574,27 @@ char* sexp_load_image_err() {
return gc_heap_err_str; return gc_heap_err_str;
} }
sexp sexp_load_image (const char* filename, sexp_uint_t heap_free_size, sexp_uint_t heap_max_size) { sexp sexp_load_image (const char* filename, off_t offset, sexp_uint_t heap_free_size, sexp_uint_t heap_max_size) {
sexp res = NULL; struct load_image_state state;
sexp ctx = NULL; struct sexp_image_header_t header;
FILE *fp;
int i;
sexp res = NULL, ctx = NULL, base, *ctx_globals, *ctx_types;
gc_heap_err_str[0] = 0; gc_heap_err_str[0] = 0;
struct load_image_state state;
memset(&state, 0, sizeof(struct load_image_state)); memset(&state, 0, sizeof(struct load_image_state));
FILE *fp = fopen(filename, "rb"); fp = fopen(filename, "rb");
if (!fp) { if (!fp) {
snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't open image file for reading: %s\n", filename); snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't open image file for reading: %s\n", filename);
goto done; goto done;
} }
if (offset > 0 && fseek(fp, offset, SEEK_SET) < 0) {
snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't seek to image offset: %s -> %lld: %s\n", filename, offset, strerror(errno));
goto done;
}
struct sexp_image_header_t header;
if (!load_image_header(fp, &header)) { goto done; } if (!load_image_header(fp, &header)) { goto done; }
state.heap = sexp_gc_packed_heap_make(header.size, heap_free_size); state.heap = sexp_gc_packed_heap_make(header.size, heap_free_size);
@ -596,7 +602,7 @@ sexp sexp_load_image (const char* filename, sexp_uint_t heap_free_size, sexp_uin
snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't malloc heap\n"); snprintf(gc_heap_err_str, ERR_STR_SIZE, "couldn't malloc heap\n");
goto done; goto done;
} }
sexp base = sexp_heap_first_block(state.heap); base = sexp_heap_first_block(state.heap);
if (fread(base, 1, header.size, fp) != header.size) { if (fread(base, 1, header.size, fp) != header.size) {
snprintf(gc_heap_err_str, ERR_STR_SIZE, "error reading image\n"); snprintf(gc_heap_err_str, ERR_STR_SIZE, "error reading image\n");
@ -614,24 +620,23 @@ sexp sexp_load_image (const char* filename, sexp_uint_t heap_free_size, sexp_uin
copy of the type array pointers with correct offsets is applied is created outside copy of the type array pointers with correct offsets is applied is created outside
of the new heap to be used with the pointer adjustment process. of the new heap to be used with the pointer adjustment process.
*/ */
sexp* ctx_globals = sexp_vector_data((sexp)((unsigned char*)sexp_context_globals(ctx) + state.offset)); ctx_globals = sexp_vector_data((sexp)((unsigned char*)sexp_context_globals(ctx) + state.offset));
sexp* ctx_types = sexp_vector_data((sexp)((unsigned char*)(ctx_globals[SEXP_G_TYPES]) + state.offset)); ctx_types = sexp_vector_data((sexp)((unsigned char*)(ctx_globals[SEXP_G_TYPES]) + state.offset));
state.types_cnt = sexp_unbox_fixnum(ctx_globals[SEXP_G_NUM_TYPES]); state.types_cnt = sexp_unbox_fixnum(ctx_globals[SEXP_G_NUM_TYPES]);
state.types = malloc(sizeof(sexp) * state.types_cnt); state.types = malloc(sizeof(sexp) * state.types_cnt);
if (!state.types) goto done; if (!state.types) goto done;
int i;
for (i = 0; i < state.types_cnt; i++) { for (i = 0; i < state.types_cnt; i++) {
state.types[i] = (sexp)((unsigned char *)ctx_types[i] + state.offset); state.types[i] = (sexp)((unsigned char *)ctx_types[i] + state.offset);
} }
if (sexp_gc_heap_walk(ctx, sexp_context_heap(ctx), state.types, state.types_cnt, if (sexp_gc_heap_walk(ctx, sexp_context_heap(ctx), state.types, state.types_cnt,
&state, NULL, NULL, load_image_callback_p1) != SEXP_TRUE) { &state, NULL, NULL, load_image_callback_p1) != SEXP_TRUE)
goto done; } goto done;
/* Second pass to fix code references */ /* Second pass to fix code references */
if (sexp_gc_heap_walk(ctx, sexp_context_heap(ctx), state.types, state.types_cnt, if (sexp_gc_heap_walk(ctx, sexp_context_heap(ctx), state.types, state.types_cnt,
&state, NULL, NULL, load_image_callback_p2) != SEXP_TRUE) { &state, NULL, NULL, load_image_callback_p2) != SEXP_TRUE)
goto done; } goto done;
if (heap_max_size > SEXP_INITIAL_HEAP_SIZE) { if (heap_max_size > SEXP_INITIAL_HEAP_SIZE) {
sexp_context_heap(ctx)->max_size = heap_max_size; sexp_context_heap(ctx)->max_size = heap_max_size;

View file

@ -82,7 +82,7 @@ SEXP_API sexp sexp_save_image (sexp ctx, const char* filename);
to provide a description of the error encountered. An sexp exception cannot be to provide a description of the error encountered. An sexp exception cannot be
returned because there is not a valid context in which to put the exception. returned because there is not a valid context in which to put the exception.
*/ */
SEXP_API sexp sexp_load_image (const char* filename, sexp_uint_t heap_free_size, sexp_uint_t heap_max_size); SEXP_API sexp sexp_load_image (const char* filename, off_t offset, sexp_uint_t heap_free_size, sexp_uint_t heap_max_size);
/* In the case that sexp_load_image() returns NULL, this function will return /* In the case that sexp_load_image() returns NULL, this function will return

2
main.c
View file

@ -409,7 +409,7 @@ sexp run_main (int argc, char **argv) {
fprintf(stderr, "-:i <file>: image files must be loaded first\n"); fprintf(stderr, "-:i <file>: image files must be loaded first\n");
exit_failure(); exit_failure();
} }
ctx = sexp_load_image(arg, heap_size, heap_max_size); ctx = sexp_load_image(arg, 0, heap_size, heap_max_size);
if (!ctx || !sexp_contextp(ctx)) { if (!ctx || !sexp_contextp(ctx)) {
fprintf(stderr, "-:i <file>: couldn't open file for reading: %s\n", arg); fprintf(stderr, "-:i <file>: couldn't open file for reading: %s\n", arg);
fprintf(stderr, " %s\n", sexp_load_image_err()); fprintf(stderr, " %s\n", sexp_load_image_err());