Generalize immobile space addresses
[sbcl.git] / src / runtime / coreparse.c
blob0f5ed517a1fcfbae4d8c094b60286653cca59b32
1 /*
2 * A saved SBCL system is a .core file; the code here helps us accept
3 * such a file as input.
4 */
6 /*
7 * This software is part of the SBCL system. See the README file for
8 * more information.
10 * This software is derived from the CMU CL system, which was
11 * written at Carnegie Mellon University and released into the
12 * public domain. The software is in the public domain and is
13 * provided with absolutely no warranty. See the COPYING and CREDITS
14 * files for more information.
17 #include "sbcl.h"
19 #ifndef LISP_FEATURE_WIN32
20 #ifdef LISP_FEATURE_LINUX
21 /* For madvise */
22 #define _BSD_SOURCE
23 #include <sys/mman.h>
24 #undef _BSD_SOURCE
25 #else
26 #include <sys/mman.h>
27 #endif
28 #endif
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/file.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <unistd.h>
39 #include "os.h"
40 #include "runtime.h"
41 #include "globals.h"
42 #include "core.h"
43 #include "arch.h"
44 #include "interr.h"
45 #include "thread.h"
47 #include "validate.h"
48 #include "gc-internal.h"
49 #include "runtime-options.h"
50 #include "pseudo-atomic.h"
52 #include <errno.h>
54 #ifdef LISP_FEATURE_SB_CORE_COMPRESSION
55 # include <zlib.h>
56 #endif
58 unsigned char build_id[] =
59 // The suffix added to build-id indicates which flavor of C compiler was used.
60 // This enforces that when you put :MSAN in your Lisp features, you don't
61 // omit "-fsanitize=memory -DMEMORY_SANITIZE" from CFLAGS and LINKFLAGS.
62 // (Some Lisp features affect C flags, but not this one.)
63 // It is important for out-of-tree builds: once they work, you can produce
64 // two trees of artifacts from identical sources *including* the build-id.inc
65 // (but not including "local-target-features.lisp-expr"), and end up with two
66 // Lisp cores and two C runtimes. The extra suffix avoids accidental mismatch.
67 #include "../../output/build-id.inc"
68 #ifdef MEMORY_SANITIZER
69 "-msan"
70 #endif
73 int
74 open_binary(char *filename, int mode)
76 #ifdef LISP_FEATURE_WIN32
77 mode |= O_BINARY;
78 #endif
80 return open(filename, mode);
84 static struct runtime_options *
85 read_runtime_options(int fd)
87 os_vm_size_t optarray[RUNTIME_OPTIONS_WORDS];
88 struct runtime_options *options = NULL;
90 if (read(fd, optarray, RUNTIME_OPTIONS_WORDS * sizeof(os_vm_size_t)) !=
91 RUNTIME_OPTIONS_WORDS * sizeof(size_t)) {
92 return NULL;
95 if ((RUNTIME_OPTIONS_MAGIC != optarray[0]) || (0 == optarray[1])) {
96 return NULL;
99 options = successful_malloc(sizeof(struct runtime_options));
101 options->dynamic_space_size = optarray[2];
102 options->thread_control_stack_size = optarray[3];
104 return options;
107 void
108 maybe_initialize_runtime_options(int fd)
110 struct runtime_options *new_runtime_options;
111 off_t end_offset = sizeof(lispobj) +
112 sizeof(os_vm_offset_t) +
113 (RUNTIME_OPTIONS_WORDS * sizeof(size_t));
115 lseek(fd, -end_offset, SEEK_END);
117 if ((new_runtime_options = read_runtime_options(fd))) {
118 runtime_options = new_runtime_options;
122 /* Search 'filename' for an embedded core. An SBCL core has, at the
123 * end of the file, a trailer containing optional saved runtime
124 * options, the start of the core (an os_vm_offset_t), and a final
125 * signature word (the lispobj CORE_MAGIC). If this trailer is found
126 * at the end of the file, the start of the core can be determined
127 * from the core size.
129 * If an embedded core is present, this returns the offset into the
130 * file to load the core from, or -1 if no core is present. */
131 os_vm_offset_t
132 search_for_embedded_core(char *filename)
134 lispobj header;
135 os_vm_offset_t lispobj_size = sizeof(lispobj);
136 os_vm_offset_t trailer_size = lispobj_size + sizeof(os_vm_offset_t);
137 os_vm_offset_t core_start, pos;
138 int fd = -1;
140 if ((fd = open_binary(filename, O_RDONLY)) < 0)
141 goto lose;
143 if (read(fd, &header, (size_t)lispobj_size) < lispobj_size)
144 goto lose;
145 if (header == CORE_MAGIC) {
146 /* This file is a real core, not an embedded core. Return 0 to
147 * indicate where the core starts, and do not look for runtime
148 * options in this case. */
149 return 0;
152 if (lseek(fd, -lispobj_size, SEEK_END) < 0)
153 goto lose;
154 if (read(fd, &header, (size_t)lispobj_size) < lispobj_size)
155 goto lose;
157 if (header == CORE_MAGIC) {
158 if (lseek(fd, -trailer_size, SEEK_END) < 0)
159 goto lose;
160 if (read(fd, &core_start, sizeof(os_vm_offset_t)) < 0)
161 goto lose;
163 if (lseek(fd, core_start, SEEK_SET) < 0)
164 goto lose;
165 pos = lseek(fd, 0, SEEK_CUR);
167 if (read(fd, &header, (size_t)lispobj_size) < lispobj_size)
168 goto lose;
170 if (header != CORE_MAGIC)
171 goto lose;
173 maybe_initialize_runtime_options(fd);
175 close(fd);
176 return pos;
179 lose:
180 if (fd != -1)
181 close(fd);
183 return -1;
186 #ifndef LISP_FEATURE_HPUX
187 #define load_core_bytes(fd, where, addr, len) os_map(fd, where, addr, len)
188 #else
189 #define load_core_bytes(fd, where, addr, len) copy_core_bytes(fd, where, addr, len)
190 /* If more platforms don't support overlapping mmap rename this
191 * def to something like ifdef nommapoverlap */
192 /* currently hpux only */
193 static void copy_core_bytes(int fd, os_vm_offset_t offset,
194 os_vm_address_t addr, int len)
196 unsigned char buf[4096];
197 int c,x;
198 int old_fd = lseek(fd, 0, SEEK_CUR);
200 if(len & (4096-1)){
201 fprintf(stderr, "cant copy a slice of core because slice-length is not of page size(4096)\n");
202 exit(-1);
204 if(old_fd < 0){
205 fprintf(stderr, "cant perform lseek() on corefile\n");
207 lseek(fd, offset, SEEK_SET);
208 if(fd < 0){
209 fprintf(stderr, "cant perform lseek(%u,%lu,SEEK_SET) on corefile\n", fd, offset);
211 for(x = 0; x < len; x += 4096){
212 c = read(fd, buf, 4096);
213 if(c != 4096){
214 fprintf(stderr, "cant read memory area from corefile at position %lu, got %d\n", offset + x, c);
215 exit(-1);
217 memcpy(addr+x, buf, 4096);
219 os_flush_icache(addr, len);
221 #endif
223 #ifndef LISP_FEATURE_SB_CORE_COMPRESSION
224 # define inflate_core_bytes(fd,offset,addr,len) \
225 lose("This runtime was not built with zlib-compressed core support... aborting\n")
226 #else
227 # define ZLIB_BUFFER_SIZE (1u<<16)
228 static void inflate_core_bytes(int fd, os_vm_offset_t offset,
229 os_vm_address_t addr, int len)
231 z_stream stream;
232 unsigned char* buf = successful_malloc(ZLIB_BUFFER_SIZE);
233 int ret;
235 # ifdef LISP_FEATURE_WIN32
236 /* Ensure the memory is committed so zlib doesn't segfault trying to
237 inflate. */
238 os_validate_recommit(addr, len);
239 # endif
241 if (-1 == lseek(fd, offset, SEEK_SET)) {
242 lose("Unable to lseek() on corefile\n");
245 stream.zalloc = NULL;
246 stream.zfree = NULL;
247 stream.opaque = NULL;
248 stream.avail_in = 0;
249 stream.next_in = buf;
251 ret = inflateInit(&stream);
252 if (ret != Z_OK)
253 lose("zlib error %i\n", ret);
255 stream.next_out = (void*)addr;
256 stream.avail_out = len;
257 do {
258 ssize_t count = read(fd, buf, ZLIB_BUFFER_SIZE);
259 if (count < 0)
260 lose("unable to read core file (errno = %i)\n", errno);
261 stream.next_in = buf;
262 stream.avail_in = count;
263 if (count == 0) break;
264 ret = inflate(&stream, Z_NO_FLUSH);
265 switch (ret) {
266 case Z_STREAM_END:
267 break;
268 case Z_OK:
269 if (stream.avail_out == 0)
270 lose("Runaway gzipped core directory... aborting\n");
271 if (stream.avail_in > 0)
272 lose("zlib inflate returned without fully"
273 "using up input buffer... aborting\n");
274 break;
275 default:
276 lose("zlib inflate error: %i\n", ret);
277 break;
279 } while (ret != Z_STREAM_END);
281 if (stream.avail_out > 0) {
282 if (stream.avail_out >= os_vm_page_size)
283 fprintf(stderr, "Warning: gzipped core directory significantly"
284 "shorter than expected (%lu bytes)", (unsigned long)stream.avail_out);
285 /* Is this needed? */
286 memset(stream.next_out, 0, stream.avail_out);
289 inflateEnd(&stream);
290 free(buf);
292 # undef ZLIB_BUFFER_SIZE
293 #endif
295 struct heap_adjust {
296 /* range[0] is immobile space, range [1] is dynamic space */
297 struct range {
298 lispobj start, end;
299 sword_t delta;
300 } range[2];
303 #ifndef LISP_FEATURE_RELOCATABLE_HEAP
304 #define adjust_word(ignore,thing) thing
305 #define relocate_heap(ignore)
306 #else
307 #include "genesis/gc-tables.h"
308 #include "genesis/hash-table.h"
309 #include "genesis/layout.h"
310 #include "genesis/vector.h"
312 static inline sword_t calc_adjustment(struct heap_adjust* adj, lispobj x)
314 #ifdef LISP_FEATURE_IMMOBILE_SPACE
315 if (adj->range[0].start <= x && x < adj->range[0].end)
316 return adj->range[0].delta;
317 #endif
318 if (adj->range[1].start <= x && x < adj->range[1].end)
319 return adj->range[1].delta;
320 return 0;
323 // Return the adjusted value of 'word' without testing whether it looks
324 // like a pointer. But do test whether it points to a relocatable space.
325 static inline lispobj adjust_word(struct heap_adjust* adj, lispobj word) {
326 return word + calc_adjustment(adj, word);
329 // Adjust the words in range [where,where+n_words)
330 // skipping any words that have non-pointer nature.
331 static void adjust_pointers(lispobj *where, sword_t n_words, struct heap_adjust* adj)
333 long i;
334 for (i=0;i<n_words;++i) {
335 lispobj word = where[i];
336 sword_t adjustment;
337 if (is_lisp_pointer(word) && (adjustment = calc_adjustment(adj, word)) != 0) {
338 where[i] += adjustment;
343 #include "var-io.h"
344 #include "unaligned.h"
345 static void __attribute__((unused))
346 adjust_code_refs(struct heap_adjust* adj, lispobj fixups, struct code* code)
348 struct varint_unpacker unpacker;
349 varint_unpacker_init(&unpacker, fixups);
350 char* instructions = (char*)((lispobj*)code + code_header_words(code->header));
351 int prev_loc = 0, loc;
352 while (varint_unpack(&unpacker, &loc) && loc != 0) {
353 // For extra compactness, each loc is relative to the prior,
354 // so that the magnitudes are smaller.
355 loc += prev_loc;
356 prev_loc = loc;
357 int* fixup_where = (int*)(instructions + loc);
358 lispobj ptr = UNALIGNED_LOAD32(fixup_where);
359 UNALIGNED_STORE32(fixup_where, ptr + calc_adjustment(adj, ptr));
363 #if defined(LISP_FEATURE_COMPACT_INSTANCE_HEADER) && defined(LISP_FEATURE_64_BIT)
364 #define FIX_FUN_HEADER_LAYOUT(fun) \
365 set_function_layout(fun, adjust_word(adj, function_layout(fun)))
366 #else
367 #define FIX_FUN_HEADER_LAYOUT(f) {}
368 #endif
370 static void relocate_space(uword_t start, lispobj* end, struct heap_adjust* adj)
372 lispobj *where = (lispobj*)start;
373 lispobj header_word;
374 int widetag;
375 long nwords;
376 lispobj layout, adjusted_layout, bitmap;
377 struct code* code;
378 sword_t delta;
380 for ( ; where < end ; where += nwords ) {
381 header_word = *where;
382 if (is_cons_half(header_word)) {
383 adjust_pointers(where, 2, adj);
384 nwords = 2;
385 continue;
387 widetag = widetag_of(header_word);
388 nwords = sizetab[widetag](where);
389 switch (widetag) {
390 case FUNCALLABLE_INSTANCE_WIDETAG:
391 // Special note on the word at where[1] in funcallable instances:
392 // - If no immobile code, then the word points to read-only space,
393 /// hence needs no adjustment.
394 // - Otherwise, the word might point to a relocated range,
395 // either the instance itself, or a trampoline in immobile space.
396 where[1] = adjust_word(adj, where[1]);
397 case INSTANCE_WIDETAG:
398 layout = (widetag == FUNCALLABLE_INSTANCE_WIDETAG) ?
399 funinstance_layout(where) : instance_layout(where);
400 adjusted_layout = adjust_word(adj, layout);
401 // Do not alter the layout as stored in the instance if non-compact
402 // header. instance_scan() will do it if necessary.
403 #ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER
404 if (adjusted_layout != layout)
405 instance_layout(where) = adjusted_layout;
406 #endif
407 bitmap = LAYOUT(adjusted_layout)->bitmap;
408 gc_assert(fixnump(bitmap)
409 || widetag_of(*native_pointer(bitmap))==BIGNUM_WIDETAG);
410 // If the post-adjustment address of 'layout' is higher than 'where',
411 // then the layout's pointer slots need adjusting.
412 // This is true regardless of whether the core was mapped at a higher
413 // or lower address than desired.
414 if (is_lisp_pointer(bitmap) && adjusted_layout > (lispobj)where) {
415 // Do not write back the adjusted bitmap pointer. Each heap word
416 // must be touched at most once. When the layout itself gets scanned,
417 // the bitmap slot will be rewritten if needed.
418 bitmap = adjust_word(adj, bitmap);
421 instance_scan((void(*)(lispobj*,sword_t,uword_t))adjust_pointers,
422 where+1, nwords-1, bitmap, (uintptr_t)adj);
423 continue;
424 case FDEFN_WIDETAG:
425 adjust_pointers(where+1, 2, adj);
426 // 'raw_addr' doesn't satisfy is_lisp_pointer() for x86,
427 // so adjust_pointers() would ignore it. Therefore we need to
428 // forcibly adjust it.
429 #ifndef LISP_FEATURE_IMMOBILE_CODE
430 where[3] = adjust_word(adj, where[3]);
431 #elif defined(LISP_FEATURE_X86_64)
432 // static space to immobile space JMP needs adjustment
433 if (STATIC_SPACE_START <= (uintptr_t)where && (uintptr_t)where < STATIC_SPACE_END) {
434 delta = calc_adjustment(adj, fdefn_callee_lispobj((struct fdefn*)where));
435 if (delta != 0)
436 *(int*)(1+(char*)(where+3)) += delta;
438 #endif
439 continue;
440 case CODE_HEADER_WIDETAG:
441 // Fixup the constant pool. The word at where+1 is a fixnum.
442 adjust_pointers(where+2, code_header_words(header_word)-2, adj);
443 // Fixup all embedded simple-funs
444 code = (struct code*)where;
445 for_each_simple_fun(i, f, code, 1, {
446 FIX_FUN_HEADER_LAYOUT((lispobj*)f);
447 f->self = adjust_word(adj, f->self);
448 adjust_pointers(SIMPLE_FUN_SCAV_START(f), SIMPLE_FUN_SCAV_NWORDS(f), adj);
450 // Compute the address where the code "was" as the first argument
451 // by negating the adjustment for 'where'.
452 // Can't call calc_adjustment to get the negative of the adjustment!
453 gencgc_apply_code_fixups((struct code*)((char*)where - adj->range[1].delta),
454 code);
455 #ifdef LISP_FEATURE_IMMOBILE_SPACE
456 // Now that the packed integer comprising the list of fixup locations
457 // has been fixed-up (if necessary), apply them to the code.
458 if (code->fixups != 0)
459 adjust_code_refs(adj, code->fixups, code);
460 #endif
461 continue;
462 case CLOSURE_WIDETAG:
463 FIX_FUN_HEADER_LAYOUT(where);
464 #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)
465 // For x86[-64], the closure fun appears to be a fixnum,
466 // and might need adjustment unless pointing to immobile code.
467 // Then fall into the general case; where[1] won't get re-adjusted
468 // because it doesn't satisfy is_lisp_pointer().
469 where[1] = adjust_word(adj, where[1]);
470 #endif
471 break;
472 // Vectors require extra care because of EQ-based hashing.
473 case SIMPLE_VECTOR_WIDETAG:
474 if (is_vector_subtype(*where, VectorValidHashing)) {
475 struct vector* v = (struct vector*)where;
476 gc_assert(v->length > 0 &&
477 !(v->length & make_fixnum(1)) && // length must be even
478 lowtag_of(v->data[0]) == INSTANCE_POINTER_LOWTAG);
479 lispobj* data = (lispobj*)v->data;
480 adjust_pointers(&data[0], 1, adj); // adjust the hash-table structure
481 boolean needs_rehash = 0;
482 int i;
483 // Adjust the elements, checking for need to rehash.
484 // v->data[1] is the unbound marker (a non-pointer)
485 for (i = fixnum_value(v->length)-1 ; i>=2 ; --i) {
486 lispobj ptr = data[i];
487 if (is_lisp_pointer(ptr) && (delta = calc_adjustment(adj, ptr)) != 0) {
488 data[i] += delta;
489 needs_rehash = 1;
492 if (needs_rehash)
493 data[1] = make_fixnum(1);
494 continue;
496 // All the array header widetags.
497 case SIMPLE_ARRAY_WIDETAG:
498 #ifdef COMPLEX_CHARACTER_STRING_WIDETAG
499 case COMPLEX_CHARACTER_STRING_WIDETAG:
500 #endif
501 case COMPLEX_BASE_STRING_WIDETAG:
502 case COMPLEX_VECTOR_NIL_WIDETAG:
503 case COMPLEX_BIT_VECTOR_WIDETAG:
504 case COMPLEX_VECTOR_WIDETAG:
505 case COMPLEX_ARRAY_WIDETAG:
506 // And the rest of the purely descriptor objects.
507 case SYMBOL_WIDETAG:
508 case VALUE_CELL_WIDETAG:
509 case WEAK_POINTER_WIDETAG:
510 case RATIO_WIDETAG:
511 case COMPLEX_WIDETAG:
512 break;
514 // Other
515 case SAP_WIDETAG:
516 if ((delta = calc_adjustment(adj, where[1])) != 0) {
517 fprintf(stderr,
518 "WARNING: SAP at %p -> %p in relocatable core\n",
519 where, (void*)where[1]);
520 where[1] += delta;
522 continue;
523 case BIGNUM_WIDETAG:
524 #ifndef LISP_FEATURE_64_BIT
525 case SINGLE_FLOAT_WIDETAG:
526 #endif
527 case DOUBLE_FLOAT_WIDETAG:
528 case COMPLEX_SINGLE_FLOAT_WIDETAG:
529 case COMPLEX_DOUBLE_FLOAT_WIDETAG:
530 #ifdef SIMD_PACK_WIDETAG
531 case SIMD_PACK_WIDETAG:
532 #endif
533 continue;
534 default:
535 if (other_immediate_lowtag_p(widetag)
536 && specialized_vector_widetag_p(widetag))
537 continue;
538 else
539 lose("Unrecognized heap object: @%p: %lx\n", where, header_word);
541 adjust_pointers(where+1, nwords-1, adj);
545 #define SHOW_SPACE_RELOCATION 0
546 void relocate_heap(struct heap_adjust* adj)
548 if (SHOW_SPACE_RELOCATION) {
549 #ifdef LISP_FEATURE_IMMOBILE_SPACE
550 fprintf(stderr, "Relocating immobile space from [%p:%p] to [%p:%p]\n",
551 (char*)adj->range[0].start,
552 (char*)adj->range[0].end,
553 (char*)FIXEDOBJ_SPACE_START,
554 (char*)FIXEDOBJ_SPACE_START+(adj->range[0].end-adj->range[0].start));
555 #endif
556 fprintf(stderr, "Relocating dynamic space from [%p:%p] to [%p:%p]\n",
557 (char*)adj->range[1].start,
558 (char*)adj->range[1].end,
559 (char*)DYNAMIC_SPACE_START,
560 (char*)DYNAMIC_SPACE_START+(adj->range[1].end-adj->range[1].start));
562 relocate_space(STATIC_SPACE_START, static_space_free_pointer, adj);
563 #ifdef LISP_FEATURE_IMMOBILE_SPACE
564 relocate_space(FIXEDOBJ_SPACE_START, fixedobj_free_pointer, adj);
565 relocate_space(VARYOBJ_SPACE_START, varyobj_free_pointer, adj);
566 SYMBOL(FUNCTION_LAYOUT)->value = \
567 adjust_word(adj, SYMBOL(FUNCTION_LAYOUT)->value >> 32) << 32;
568 #endif
569 relocate_space(DYNAMIC_SPACE_START, (lispobj*)get_alloc_pointer(), adj);
570 lispobj asmroutines = SYMBOL(ASSEMBLER_ROUTINES)->value;
571 if (lowtag_of(asmroutines) == INSTANCE_POINTER_LOWTAG) {
572 /* Adjust the values in SB-FASL::*ASSEMBLER-ROUTINES*.
573 * No need to frob the 'needs_rehash_p' slot on account of this */
574 struct hash_table *ht = (struct hash_table*)native_pointer(asmroutines);
575 struct vector *table = (struct vector*)native_pointer(ht->table);
576 int i;
577 for (i=fixnum_value(table->length)-1; i>=3; i -= 2) {
578 if (fixnump(table->data[i]))
579 table->data[i] = make_fixnum(adjust_word(adj, fixnum_value(table->data[i])));
583 #endif
585 int merge_core_pages = -1;
587 static void
588 process_directory(int count, struct ndir_entry *entry,
589 int fd, os_vm_offset_t file_offset,
590 struct heap_adjust* adj)
592 extern void immobile_space_coreparse(uword_t,uword_t);
594 struct {
595 uword_t len; // length in bytes, as an integral multiple of os_vm_page_size
596 uword_t base;
597 lispobj** pfree_pointer; // pointer to x_free_pointer
598 } spaces[MAX_CORE_SPACE_ID+1] = {
599 {0, 0, 0}, // blank for space ID 0
600 #ifdef LISP_FEATURE_GENCGC
601 {0, DYNAMIC_SPACE_START, 0},
602 #else
603 {0, 0, 0},
604 #endif
605 // This order is determined by constants in compiler/generic/genesis
606 {0, STATIC_SPACE_START, &static_space_free_pointer},
607 {0, READ_ONLY_SPACE_START, &read_only_space_free_pointer},
608 #ifdef LISP_FEATURE_IMMOBILE_SPACE
609 {0, FIXEDOBJ_SPACE_START, &fixedobj_free_pointer},
610 {0, VARYOBJ_SPACE_START, &varyobj_free_pointer}
611 #endif
614 for ( ; --count>= 0; ++entry) {
615 sword_t id = entry->identifier;
616 uword_t addr = (1024 * entry->address); // multiplier as per core.h
617 int compressed = id & DEFLATED_CORE_SPACE_ID_FLAG;
618 id -= compressed;
619 if (id < 1 || id > MAX_CORE_SPACE_ID)
620 lose("unknown space ID %ld addr %p\n", id, addr);
622 #ifndef LISP_FEATURE_RELOCATABLE_HEAP
623 int enforce_address = 1;
624 #elif defined(LISP_FEATURE_IMMOBILE_SPACE)
625 // Enforce address of readonly, static, immobile varyobj
626 int enforce_address = id != DYNAMIC_CORE_SPACE_ID
627 && id != IMMOBILE_FIXEDOBJ_CORE_SPACE_ID;
628 #else
629 // Enforce address of readonly and static spaces.
630 int enforce_address = id != DYNAMIC_CORE_SPACE_ID;
631 #endif
632 if (enforce_address) {
633 int fail;
634 #ifdef LISP_FEATURE_CHENEYGC
635 if (id == DYNAMIC_CORE_SPACE_ID) {
636 if ((fail = (addr != DYNAMIC_0_SPACE_START) &&
637 (addr != DYNAMIC_1_SPACE_START)) != 0)
638 fprintf(stderr, "in core: %p; in runtime: %p or %p\n",
639 (void*)addr,
640 (void*)DYNAMIC_0_SPACE_START,
641 (void*)DYNAMIC_1_SPACE_START);
642 } else
643 #endif
644 if ((fail = (addr != spaces[id].base)) != 0)
645 fprintf(stderr, "in core: %p; in runtime: %p\n",
646 (void*)addr, (void*)spaces[id].base);
647 char *names[] = {
648 "DYNAMIC", "STATIC", "READ_ONLY", "IMMOBILE", "IMMOBILE"
650 if (fail)
651 lose("core/runtime address mismatch: %s_SPACE_START", names[id-1]);
653 spaces[id].base = addr;
654 uword_t len = os_vm_page_size * entry->page_count;
655 spaces[id].len = len;
656 if (id == DYNAMIC_CORE_SPACE_ID && len > dynamic_space_size) {
657 lose("dynamic space too small for core: %luKiB required, %luKiB available.\n",
658 (unsigned long)len >> 10,
659 (unsigned long)dynamic_space_size >> 10);
661 if (len != 0) {
662 uword_t __attribute__((unused)) aligned_start;
663 #ifdef LISP_FEATURE_RELOCATABLE_HEAP
664 // Try to map at address requested by the core file.
665 if (id == DYNAMIC_CORE_SPACE_ID) {
666 addr = (uword_t)os_validate(MOVABLE, (os_vm_address_t)addr,
667 dynamic_space_size);
668 aligned_start = ALIGN_UP(addr, GENCGC_CARD_BYTES);
669 /* Misalignment can happen only if card size exceeds OS page.
670 * Drop one card to avoid overrunning the allocated space */
671 if (aligned_start > addr) // not card-aligned
672 dynamic_space_size -= GENCGC_CARD_BYTES;
673 DYNAMIC_SPACE_START = addr = aligned_start;
674 # ifndef LISP_FEATURE_IMMOBILE_SPACE
676 # else
677 if (DYNAMIC_SPACE_START < FIXEDOBJ_SPACE_START)
678 lose("Won't map dynamic space below immobile space");
679 /* Assume presence of linkage-table space for this platform.
680 * An unusable gap may exist between the linkage table and immobile space
681 * but it's not important whether it does or doesn't. So we don't bother
682 * unmapping the alleged gap */
683 } else if (id == IMMOBILE_FIXEDOBJ_CORE_SPACE_ID) {
684 addr = (uword_t)os_validate(MOVABLE_LOW, (os_vm_address_t)addr,
685 IMMOBILE_SPACE_TOTAL_SIZE);
686 FIXEDOBJ_SPACE_START = addr;
687 if (FIXEDOBJ_SPACE_START + IMMOBILE_SPACE_TOTAL_SIZE > 0x80000000)
688 lose("Won't map immobile space above 2GB");
689 // varyobj subspace must be enforced to reside at a known offset
690 // from fixedobj subspace.
691 spaces[IMMOBILE_VARYOBJ_CORE_SPACE_ID].base =
692 spaces[id].base + FIXEDOBJ_SPACE_SIZE;
693 VARYOBJ_SPACE_START = addr + FIXEDOBJ_SPACE_SIZE;
694 } else if (id == IMMOBILE_VARYOBJ_CORE_SPACE_ID) {
695 /* Ignore what the core file said */
696 addr = VARYOBJ_SPACE_START;
698 # endif
700 #endif /* LISP_FEATURE_RELOCATABLE_HEAP */
702 sword_t offset = os_vm_page_size * (1 + entry->data_page);
703 if (compressed)
704 inflate_core_bytes(fd, offset + file_offset, (os_vm_address_t)addr, len);
705 else
706 load_core_bytes(fd, offset + file_offset, (os_vm_address_t)addr, len);
709 #ifdef MADV_MERGEABLE
710 if ((merge_core_pages == 1)
711 || ((merge_core_pages == -1) && compressed)) {
712 madvise((void *)addr, len, MADV_MERGEABLE);
714 #endif
716 lispobj *free_pointer = (lispobj *) addr + entry->nwords;
717 switch (id) {
718 default:
719 *spaces[id].pfree_pointer = free_pointer;
720 break;
721 case DYNAMIC_CORE_SPACE_ID:
722 #ifdef LISP_FEATURE_CHENEYGC
723 /* 'addr' is the actual address if relocatable.
724 * For cheneygc, this will be whatever the GC was using
725 * at the time the core was saved.
726 * For gencgc this is #defined as DYNAMIC_SPACE_START */
727 current_dynamic_space = (lispobj *)addr;
728 #endif
729 set_alloc_pointer((lispobj)free_pointer);
731 anon_dynamic_space_start = (os_vm_address_t)(addr + len);
732 /* This assertion safeguards the test in zero_pages_with_mmap()
733 * which trusts that if addr > anon_dynamic_space_start
734 * then addr did not come from any file mapping. */
735 gc_assert((lispobj)anon_dynamic_space_start > STATIC_SPACE_END);
739 #ifdef LISP_FEATURE_RELOCATABLE_HEAP
740 #ifdef LISP_FEATURE_IMMOBILE_SPACE
741 if (FIXEDOBJ_SPACE_START != spaces[IMMOBILE_FIXEDOBJ_CORE_SPACE_ID].base) {
742 adj->range[0].start = spaces[IMMOBILE_FIXEDOBJ_CORE_SPACE_ID].base;
743 adj->range[0].end = adj->range[0].start + FIXEDOBJ_SPACE_SIZE
744 + spaces[IMMOBILE_VARYOBJ_CORE_SPACE_ID].len;
745 adj->range[0].delta = FIXEDOBJ_SPACE_START - adj->range[0].start;
747 #endif
748 if (DYNAMIC_SPACE_START != spaces[DYNAMIC_CORE_SPACE_ID].base) {
749 adj->range[1].start = spaces[DYNAMIC_CORE_SPACE_ID].base;
750 adj->range[1].end = adj->range[1].start + spaces[DYNAMIC_CORE_SPACE_ID].len;
751 adj->range[1].delta = DYNAMIC_SPACE_START - adj->range[1].start;
753 if (adj->range[0].delta | adj->range[1].delta)
754 relocate_heap(adj);
755 #endif
757 #ifdef LISP_FEATURE_IMMOBILE_SPACE
758 /* Now determine page characteristics (such as object spacing)
759 * after relocation, because we need to know which objects are layouts
760 * based on knowing layout-of-layout. The test for that is dependent
761 * on what it's address should be, not what it was in the file */
762 immobile_space_coreparse(spaces[IMMOBILE_FIXEDOBJ_CORE_SPACE_ID].len,
763 spaces[IMMOBILE_VARYOBJ_CORE_SPACE_ID].len);
764 #endif
765 #ifdef LISP_FEATURE_X86_64
766 tune_asm_routines_for_microarch(); // before WPing immobile space
767 #endif
770 lispobj
771 load_core_file(char *file, os_vm_offset_t file_offset)
773 void *header;
774 core_entry_elt_t val, *ptr;
775 os_vm_size_t len, remaining_len;
776 int fd = open_binary(file, O_RDONLY);
777 ssize_t count;
778 lispobj initial_function = NIL;
779 struct heap_adjust adj;
780 memset(&adj, 0, sizeof adj);
782 FSHOW((stderr, "/entering load_core_file(%s)\n", file));
783 if (fd < 0) {
784 fprintf(stderr, "could not open file \"%s\"\n", file);
785 perror("open");
786 exit(1);
789 lseek(fd, file_offset, SEEK_SET);
790 header = calloc(os_vm_page_size, 1);
792 count = read(fd, header, os_vm_page_size);
793 if (count < (ssize_t) os_vm_page_size) {
794 lose("premature end of core file\n");
796 SHOW("successfully read first page of core");
798 ptr = header;
799 val = *ptr++;
801 if (val != CORE_MAGIC) {
802 lose("invalid magic number in core: 0x%lx should have been 0x%x.\n",
803 val,
804 CORE_MAGIC);
806 SHOW("found CORE_MAGIC");
808 #define WORD_FMTX OS_VM_SIZE_FMTX
809 for ( ; ; ptr += remaining_len) {
810 val = *ptr++;
811 len = *ptr++;
812 remaining_len = len - 2; /* (-2 to cancel the two ++ operations) */
813 FSHOW((stderr, "/val=0x%"WORD_FMTX", remaining_len=0x%"WORD_FMTX"\n",
814 val, remaining_len));
816 switch (val) {
818 case END_CORE_ENTRY_TYPE_CODE:
819 free(header);
820 close(fd);
821 return initial_function;
823 case BUILD_ID_CORE_ENTRY_TYPE_CODE:
824 SHOW("BUILD_ID_CORE_ENTRY_TYPE_CODE case");
826 os_vm_size_t stringlen = *ptr++;
827 --remaining_len;
828 gc_assert(remaining_len * sizeof (core_entry_elt_t) >= stringlen);
829 if (sizeof build_id == stringlen+1 && !memcmp(ptr, build_id, stringlen))
830 break;
831 /* .core files are not binary-compatible between
832 * builds because we can't easily detect whether the
833 * sources were patched between the time the
834 * dumping-the-.core runtime was built and the time
835 * that the loading-the-.core runtime was built.
837 * (We could easily detect whether version.lisp-expr
838 * was changed, but people experimenting with patches
839 * don't necessarily update version.lisp-expr.) */
840 fprintf(stderr,
841 "core was built for runtime \"%.*s\" but this is \"%s\"\n",
842 (int)stringlen, (char*)ptr, build_id);
843 lose("can't load .core for different runtime, sorry\n");
846 case NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE:
847 SHOW("NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE case");
848 process_directory(remaining_len / NDIR_ENTRY_LENGTH,
849 (struct ndir_entry*)ptr, fd, file_offset,
850 &adj);
851 break;
853 case INITIAL_FUN_CORE_ENTRY_TYPE_CODE:
854 SHOW("INITIAL_FUN_CORE_ENTRY_TYPE_CODE case");
855 initial_function = adjust_word(&adj, (lispobj)*ptr);
856 break;
858 #ifdef LISP_FEATURE_GENCGC
859 case PAGE_TABLE_CORE_ENTRY_TYPE_CODE:
861 extern void gc_allocate_ptes();
862 extern boolean gc_load_corefile_ptes(char data[], ssize_t,
863 page_index_t, page_index_t*);
864 // Allocation of PTEs is delayed 'til now so that calloc() doesn't
865 // consume addresses that would have been taken by a mapped space.
866 gc_allocate_ptes();
867 os_vm_size_t remaining = *ptr;
868 os_vm_size_t fdoffset = (*(ptr+1) + 1) * (os_vm_page_size);
869 page_index_t page = 0, npages;
870 ssize_t bytes_read;
871 char data[8192];
872 // A corefile_pte is 10 bytes for x86-64
873 // Process an integral number of ptes on each read.
874 os_vm_size_t chunksize = sizeof (struct corefile_pte)
875 * (sizeof data / sizeof (struct corefile_pte));
876 lseek(fd, fdoffset + file_offset, SEEK_SET);
877 bytes_read = read(fd, &npages, sizeof npages);
878 gc_assert(bytes_read == sizeof npages);
879 remaining -= sizeof npages;
880 while ((bytes_read = read(fd, data,
881 remaining < chunksize ? remaining : chunksize)) > 0
882 && gc_load_corefile_ptes(data, bytes_read, npages, &page))
883 remaining -= bytes_read;
885 gencgc_partial_pickup = 1;
886 break;
888 #endif
889 default:
890 lose("unknown core file entry: 0x%"WORD_FMTX"\n", val);
895 #include "genesis/hash-table.h"
896 #include "genesis/vector.h"
897 os_vm_address_t get_asm_routine_by_name(const char* name)
899 lispobj routines = SYMBOL(ASSEMBLER_ROUTINES)->value;
900 if (lowtag_of(routines) == INSTANCE_POINTER_LOWTAG) {
901 struct hash_table* ht = (struct hash_table*)native_pointer(routines);
902 struct vector* table = VECTOR(ht->table);
903 lispobj sym;
904 int i;
905 for (i=2 ; i < fixnum_value(table->length) ; i += 2) {
906 sym = table->data[i];
907 if (lowtag_of(sym) == OTHER_POINTER_LOWTAG
908 && widetag_of(SYMBOL(sym)->header) == SYMBOL_WIDETAG
909 && !strcmp(name, (char*)(VECTOR(SYMBOL(sym)->name)->data)))
910 return (os_vm_address_t)fixnum_value(table->data[i+1]);
912 // Something is wrong if we have a hashtable but find nothing.
913 fprintf(stderr, "WARNING: get_asm_routine_by_name(%s) failed\n",
914 name);
916 return NULL;
919 void asm_routine_poke(const char* routine, int offset, char byte)
921 char *address = (char *)get_asm_routine_by_name(routine);
922 if (address)
923 address[offset] = byte;