/* -*- indent-tabs-mode: nil -*- */ /* a stripped-down version of relocate.c from sb-heapdump: */ /* Copyright (c) 2006 David Lichteblau * partly derived from SBCL source code (gc-common.c/gencgc.c) * * Tested on x86, x86-64, and PPC. */ /* * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include "genesis/config.h" #include "validate.h" #include "gc.h" #include "gc-internal.h" #ifdef LISP_FEATURE_GENCGC #include "gencgc-internal.h" #else #include "cheneygc-internal.h" #endif #include "runtime.h" #include "interr.h" #include "genesis/fdefn.h" #include "genesis/closure.h" #include "genesis/instance.h" #include "genesis/layout.h" #include "genesis/code.h" #include "genesis/simple-fun.h" #include "genesis/vector.h" /* * our stuff */ #define ALIGN(len) CEILING(len, 2) #define RELOCATE_BOXED 0 #define RELOCATE_IMMEDIATE 0 #ifndef LISP_FEATURE_GENCGC #define PAGE_BYTES 0x1000 #endif struct relocator { long *start; long *end; long displacement; void *baseptr; }; typedef long (*relocfn)(long *, struct relocator *); static relocfn reloctab[256]; static int reloctab_initialized = 0; static void relocate_init(); void relocate(long *, long nwords, long *old_start, long displacement); static void sub_relocate(long *ptr, long nwords, struct relocator *ctx); /* * relocation */ static void * natify(lispobj thing, struct relocator *ctx) { /* Same as `native_pointer' if tempspace == newspace. Else, * turn the result into a tempspace pointer. * This is for relocate_dumpfile. */ void *old_start = (void *) ctx->start; void *new_start = old_start + ctx->displacement; void *ptr = native_pointer((long) thing); long offset = ptr - new_start; return (void *) ctx->baseptr + offset; } #ifdef LISP_FEATURE_X86 static void * oldify(void *ptr, struct relocator *ctx) { return (void *) ctx->start + (ptr - (void *) ctx->baseptr); } #endif void relocate(long *ptr, long nwords, long *old_start, long displacement) { struct relocator ctx; if (!reloctab_initialized) { relocate_init(); reloctab_initialized = 1; } ctx.baseptr = ptr; ctx.start = old_start; ctx.end = old_start + nwords; ctx.displacement = displacement; sub_relocate(ptr, nwords, &ctx); } void relocation_fixup(long *fixup_ptr, long n_fixup_words, long *old_start, long n_old_words, long displacement) { struct relocator ctx; if (!reloctab_initialized) { relocate_init(); reloctab_initialized = 1; } ctx.baseptr = (void *) old_start + displacement; ctx.start = old_start; ctx.end = old_start + n_old_words; ctx.displacement = displacement; sub_relocate(fixup_ptr, n_fixup_words, &ctx); } static void sub_relocate(long *ptr, long nwords, struct relocator *ctx) { long *p; long *q = ptr + nwords; long nrelocated; for (p = ptr; p < q; p += nrelocated) { long word = *p; if (is_lisp_pointer(word)) { long *address = (long *) native_pointer(word); if (ctx->start <= address && address < ctx->end) *p += ctx->displacement; nrelocated = 1; } else { relocfn fn = reloctab[widetag_of(word)]; if (fn) nrelocated = fn(p, ctx); else nrelocated = 1; } } } static long relocate_lose(long *ptr, struct relocator *ctx) { lose("no relocation function for header 0x%08x at 0x%08x\n", *ptr, ptr); return 0; } static long relocate_unboxed(long *ptr, struct relocator *ctx) { return ALIGN(HeaderValue(*ptr) + 1); } static long relocate_raw_vector(long *ptr, struct relocator *ctx) { return sizetab[widetag_of(*ptr)]((void *) ptr); } static long relocate_simple_vector(long *ptr, struct relocator *ctx) { if (HeaderValue(*ptr) == subtype_VectorValidHashing) *ptr = (subtype_VectorMustRehash<fun + FUN_RAW_ADDR_OFFSET; sub_relocate(ptr + 1, 2, ctx); if (fdefn->raw_addr == nontramp_raw_addr) fdefn->raw_addr = (char *)(fdefn->fun + FUN_RAW_ADDR_OFFSET); return sizeof(struct fdefn) / sizeof(lispobj); } #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) static long relocate_closure_header(long *ptr, struct relocator *ctx) { struct closure *closure = (struct closure *) ptr; long fun = (long) closure->fun - FUN_RAW_ADDR_OFFSET; sub_relocate(&fun, 1, ctx); closure->fun = fun + FUN_RAW_ADDR_OFFSET; return 2; } #endif static long relocate_instance(long *ptr, struct relocator *ctx) { lispobj nuntagged; struct instance *instance = (struct instance *) ptr; long ntotal = HeaderValue(*ptr); sub_relocate((long *) &instance->slots[0], 1, ctx); if (fixnump(instance->slots[0])) /* If the layout is a fixup, the dumper stores `nuntagged' * here for us to find. */ nuntagged = instance->slots[0]; else { struct layout *layout = natify(instance->slots[0], ctx); nuntagged = layout->n_untagged_slots; } sub_relocate(ptr + 2, ntotal - fixnum_value(nuntagged) - 1, ctx); return ntotal + 1; } static long relocate_code_header(long *ptr, struct relocator *ctx) { long header = *ptr; struct code *code = (struct code *) ptr; long n_header_words = HeaderValue(header); long n_code_words = fixnum_value(code->code_size); long n_words = ALIGN(n_header_words + n_code_words); lispobj ep; sub_relocate(ptr + 1, n_header_words - 1, ctx); ep = code->entry_points; while (ep != NIL) { struct simple_fun *fun = natify(ep, ctx); #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) fun->self = (long) ep + FUN_RAW_ADDR_OFFSET; #else fun->self = ep; #endif sub_relocate((void *) &fun->next, 1, ctx); sub_relocate((void *) &fun->name, 1, ctx); sub_relocate((void *) &fun->arglist, 1, ctx); sub_relocate((void *) &fun->type, 1, ctx); ep = fun->next; } #ifdef LISP_FEATURE_X86 if (is_lisp_pointer(code->constants[0])) { long word_displacement = ctx->displacement / N_WORD_BYTES; char *code_start = ((char *) code) + n_header_words * N_WORD_BYTES; long *old_start = oldify(ptr, ctx); long *old_end = old_start + n_words; struct vector *fixups = natify(code->constants[0], ctx); long n = fixnum_value(fixups->length); long i; for (i = 0; i < n; i++) { unsigned long offset = fixups->data[i]; long **place = (long **) (code_start + offset); long *old_value = *place; if (old_start <= old_value && old_value < old_end) *place = old_value + word_displacement; else *place = old_value - word_displacement; } } #endif return n_words; } void relocate_init() { int i; for (i = 0; i < ((sizeof reloctab)/(sizeof reloctab[0])); i++) reloctab[i] = relocate_lose; for (i = 0; i < (1<<(N_WIDETAG_BITS-N_LOWTAG_BITS)); i++) { reloctab[EVEN_FIXNUM_LOWTAG|(i<