Untangle spaghetti in process_directory()
[sbcl.git] / src / runtime / coreparse.c
blobc4bde90e14da235fcbc58865bcb6140f1ab5f136
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"
51 #include <errno.h>
53 #ifdef LISP_FEATURE_SB_CORE_COMPRESSION
54 # include <zlib.h>
55 #endif
57 unsigned char build_id[] =
58 #include "../../output/build-id.tmp"
61 int
62 open_binary(char *filename, int mode)
64 #ifdef LISP_FEATURE_WIN32
65 mode |= O_BINARY;
66 #endif
68 return open(filename, mode);
72 static struct runtime_options *
73 read_runtime_options(int fd)
75 os_vm_size_t optarray[RUNTIME_OPTIONS_WORDS];
76 struct runtime_options *options = NULL;
78 if (read(fd, optarray, RUNTIME_OPTIONS_WORDS * sizeof(os_vm_size_t)) !=
79 RUNTIME_OPTIONS_WORDS * sizeof(size_t)) {
80 return NULL;
83 if ((RUNTIME_OPTIONS_MAGIC != optarray[0]) || (0 == optarray[1])) {
84 return NULL;
87 options = successful_malloc(sizeof(struct runtime_options));
89 options->dynamic_space_size = optarray[2];
90 options->thread_control_stack_size = optarray[3];
92 return options;
95 void
96 maybe_initialize_runtime_options(int fd)
98 struct runtime_options *new_runtime_options;
99 off_t end_offset = sizeof(lispobj) +
100 sizeof(os_vm_offset_t) +
101 (RUNTIME_OPTIONS_WORDS * sizeof(size_t));
103 lseek(fd, -end_offset, SEEK_END);
105 if ((new_runtime_options = read_runtime_options(fd))) {
106 runtime_options = new_runtime_options;
110 /* Search 'filename' for an embedded core. An SBCL core has, at the
111 * end of the file, a trailer containing optional saved runtime
112 * options, the start of the core (an os_vm_offset_t), and a final
113 * signature word (the lispobj CORE_MAGIC). If this trailer is found
114 * at the end of the file, the start of the core can be determined
115 * from the core size.
117 * If an embedded core is present, this returns the offset into the
118 * file to load the core from, or -1 if no core is present. */
119 os_vm_offset_t
120 search_for_embedded_core(char *filename)
122 lispobj header;
123 os_vm_offset_t lispobj_size = sizeof(lispobj);
124 os_vm_offset_t trailer_size = lispobj_size + sizeof(os_vm_offset_t);
125 os_vm_offset_t core_start, pos;
126 int fd = -1;
128 if ((fd = open_binary(filename, O_RDONLY)) < 0)
129 goto lose;
131 if (read(fd, &header, (size_t)lispobj_size) < lispobj_size)
132 goto lose;
133 if (header == CORE_MAGIC) {
134 /* This file is a real core, not an embedded core. Return 0 to
135 * indicate where the core starts, and do not look for runtime
136 * options in this case. */
137 return 0;
140 if (lseek(fd, -lispobj_size, SEEK_END) < 0)
141 goto lose;
142 if (read(fd, &header, (size_t)lispobj_size) < lispobj_size)
143 goto lose;
145 if (header == CORE_MAGIC) {
146 if (lseek(fd, -trailer_size, SEEK_END) < 0)
147 goto lose;
148 if (read(fd, &core_start, sizeof(os_vm_offset_t)) < 0)
149 goto lose;
151 if (lseek(fd, core_start, SEEK_SET) < 0)
152 goto lose;
153 pos = lseek(fd, 0, SEEK_CUR);
155 if (read(fd, &header, (size_t)lispobj_size) < lispobj_size)
156 goto lose;
158 if (header != CORE_MAGIC)
159 goto lose;
161 maybe_initialize_runtime_options(fd);
163 close(fd);
164 return pos;
167 lose:
168 if (fd != -1)
169 close(fd);
171 return -1;
174 #ifndef LISP_FEATURE_HPUX
175 #define load_core_bytes(fd, where, addr, len) os_map(fd, where, addr, len)
176 #else
177 #define load_core_bytes(fd, where, addr, len) copy_core_bytes(fd, where, addr, len)
178 /* If more platforms don't support overlapping mmap rename this
179 * def to something like ifdef nommapoverlap */
180 /* currently hpux only */
181 static void copy_core_bytes(int fd, os_vm_offset_t offset,
182 os_vm_address_t addr, int len)
184 unsigned char buf[4096];
185 int c,x;
186 int old_fd = lseek(fd, 0, SEEK_CUR);
188 if(len & (4096-1)){
189 fprintf(stderr, "cant copy a slice of core because slice-length is not of page size(4096)\n");
190 exit(-1);
192 if(old_fd < 0){
193 fprintf(stderr, "cant perform lseek() on corefile\n");
195 lseek(fd, offset, SEEK_SET);
196 if(fd < 0){
197 fprintf(stderr, "cant perform lseek(%u,%lu,SEEK_SET) on corefile\n", fd, offset);
199 for(x = 0; x < len; x += 4096){
200 c = read(fd, buf, 4096);
201 if(c != 4096){
202 fprintf(stderr, "cant read memory area from corefile at position %lu, got %d\n", offset + x, c);
203 exit(-1);
205 memcpy(addr+x, buf, 4096);
207 os_flush_icache(addr, len);
209 #endif
211 #ifndef LISP_FEATURE_SB_CORE_COMPRESSION
212 # define inflate_core_bytes(fd,offset,addr,len) \
213 lose("This runtime was not built with zlib-compressed core support... aborting\n")
214 #else
215 # define ZLIB_BUFFER_SIZE (1u<<16)
216 static void inflate_core_bytes(int fd, os_vm_offset_t offset,
217 os_vm_address_t addr, int len)
219 z_stream stream;
220 unsigned char* buf = successful_malloc(ZLIB_BUFFER_SIZE);
221 int ret;
223 # ifdef LISP_FEATURE_WIN32
224 /* Ensure the memory is committed so zlib doesn't segfault trying to
225 inflate. */
226 os_validate_recommit(addr, len);
227 # endif
229 if (-1 == lseek(fd, offset, SEEK_SET)) {
230 lose("Unable to lseek() on corefile\n");
233 stream.zalloc = NULL;
234 stream.zfree = NULL;
235 stream.opaque = NULL;
236 stream.avail_in = 0;
237 stream.next_in = buf;
239 ret = inflateInit(&stream);
240 if (ret != Z_OK)
241 lose("zlib error %i\n", ret);
243 stream.next_out = (void*)addr;
244 stream.avail_out = len;
245 do {
246 ssize_t count = read(fd, buf, ZLIB_BUFFER_SIZE);
247 if (count < 0)
248 lose("unable to read core file (errno = %i)\n", errno);
249 stream.next_in = buf;
250 stream.avail_in = count;
251 if (count == 0) break;
252 ret = inflate(&stream, Z_NO_FLUSH);
253 switch (ret) {
254 case Z_STREAM_END:
255 break;
256 case Z_OK:
257 if (stream.avail_out == 0)
258 lose("Runaway gzipped core directory... aborting\n");
259 if (stream.avail_in > 0)
260 lose("zlib inflate returned without fully"
261 "using up input buffer... aborting\n");
262 break;
263 default:
264 lose("zlib inflate error: %i\n", ret);
265 break;
267 } while (ret != Z_STREAM_END);
269 if (stream.avail_out > 0) {
270 if (stream.avail_out >= os_vm_page_size)
271 fprintf(stderr, "Warning: gzipped core directory significantly"
272 "shorter than expected (%lu bytes)", (unsigned long)stream.avail_out);
273 /* Is this needed? */
274 memset(stream.next_out, 0, stream.avail_out);
277 inflateEnd(&stream);
278 free(buf);
280 # undef ZLIB_BUFFER_SIZE
281 #endif
283 #ifndef LISP_FEATURE_RELOCATABLE_HEAP
284 #define adjust_word(x) x
285 #else
286 #include "genesis/gc-tables.h"
287 #include "genesis/hash-table.h"
288 #include "genesis/layout.h"
289 #include "genesis/vector.h"
290 static lispobj expected_range_start, expected_range_end;
291 static sword_t heap_adjustment;
293 /* Define this in CFLAGS as 1 to deliberately mess up the mapped address */
294 #ifndef MOCK_MMAP_FAILURE
295 #define MOCK_MMAP_FAILURE 0
296 #endif
298 #if !MOCK_MMAP_FAILURE
299 #define maybe_fuzz_address(x) x
300 #else
301 /// "Pseudo-randomly" alter requested address for testing purposes so that
302 /// we can test interesting scenarios such as:
303 /// - partially overlapping ranges for the desired and actual space
304 /// - aligned to OS page but misaligned for GC card
305 #define maybe_fuzz_address(x) fuzz_address(x)
306 #include <time.h>
307 #include <stdio.h>
308 #include <stdlib.h>
309 uword_t fuzz_address(uword_t addr)
311 char * pathname;
312 FILE * f;
313 char line[100];
314 int line_number, i;
316 if ((pathname = getenv("SBCL_FAKE_MMAP_INSTRUCTION_FILE")) == NULL) {
317 fprintf(stderr, "WARNING: image built with MOCK_MMAP_FAILURE\n");
318 fprintf(stderr, " but no mock configuration data found.\n");
319 exit(1);
321 if ((f = fopen(pathname, "r+")) == NULL) {
322 // If the file can't be found, don't silently ignore it,
323 // because if the relocator "worked" you don't want to get all happy
324 // that it worked only to find that it didn't actually perform relocation.
325 fprintf(stderr, "Could not read 'fakemap' file\n");
326 exit(1);
328 ignore_value(fgets(line, sizeof line, f));
329 line_number = atoi(line);
330 uword_t result = 0;
331 for (i = 0 ; i <= line_number ; ++i) {
332 boolean ok;
333 ok = fgets(line, sizeof line, f) != NULL && line[0] != '\n';
334 if (i == line_number - 1)
335 result = strtol(line, 0, 16);
336 if (!ok) {
337 // fprintf(stderr, "*** Rewinding fake mmap instructions\n");
338 line_number = 0;
339 break;
342 rewind(f);
343 fprintf(f, "%02d", 1+line_number);
344 fclose(f);
345 fprintf(stderr, "//dynamic space @ %p\n", (void*)result);
346 return result;
348 #endif
350 static inline boolean needs_adjusting(lispobj x)
352 return (expected_range_start <= x && x < expected_range_end);
355 // Return the adjusted value of 'word' without testing whether it looks
356 // like a pointer. But do test whether it points to the dynamic space.
357 static inline lispobj adjust_word(lispobj word)
359 return (needs_adjusting(word) ? heap_adjustment : 0) + word;
362 // Adjust the words in range [where,where+n_words)
363 // skipping any words that have non-pointer nature.
364 static void adjust_pointers(lispobj *where, long n_words)
366 long i;
367 for (i=0;i<n_words;++i) {
368 lispobj word = where[i], adjusted;
369 if (is_lisp_pointer(word) && (adjusted = adjust_word(word)) != word) {
370 where[i] = adjusted;
375 static void fixup_space(lispobj* where, uword_t len)
377 lispobj *end = (lispobj*)((char*)where + len);
378 lispobj header_word;
379 int widetag;
380 long nwords;
381 lispobj layout, layout_slots_adjustp, bitmap;
382 struct code* code;
384 for ( ; where < end ; where += nwords ) {
385 header_word = *where;
386 if (is_cons_half(header_word)) {
387 adjust_pointers(where, 2);
388 nwords = 2;
389 continue;
391 widetag = widetag_of(header_word);
392 nwords = sizetab[widetag](where);
393 switch (widetag) {
394 case INSTANCE_WIDETAG:
395 case FUNCALLABLE_INSTANCE_WIDETAG:
396 // Special note on the word at where[1] in funcallable instances:
397 // - If the instance lives in immobile space and has a self-contained
398 // trampoline, that word does not need adjustment.
399 // - If the instance does not have a self-contained trampoline,
400 // then the word points to read-only space hence needs no adjustment.
401 layout = (widetag == FUNCALLABLE_INSTANCE_WIDETAG) ?
402 fin_layout(where) : instance_layout(where);
403 // Possibly adjust, but do not alter the in-memory value of, this layout.
404 // instance_scan_interleaved() on this instance will actually adjust
405 // the layout slot if needed.
406 bitmap = LAYOUT(adjust_word(layout))->bitmap;
408 // If the layout of this instance resides at a higher address
409 // than the instance itself, then the layout's pointer slots were
410 // not fixed up yet. This is true regardless of whether the core
411 // was mapped at a higher or lower address than desired.
412 // i.e. If we haven't yet scanned the layout in this fixup pass, and if
413 // it resides in the expected dynamic space range, then it needs adjusting.
414 layout_slots_adjustp = layout > (lispobj)where && needs_adjusting(layout);
416 // If the layout has not itself been adjusted, then its bitmap,
417 // if not a fixnum, needs (nondestructive) adjustment.
418 if (!fixnump(bitmap) && layout_slots_adjustp)
419 bitmap = adjust_word(bitmap);
421 instance_scan(adjust_pointers, where+1, nwords-1, bitmap);
422 continue;
423 case FDEFN_WIDETAG:
424 adjust_pointers(where+1, 2);
425 // 'raw_addr' doesn't satisfy is_lisp_pointer() for x86,
426 // so adjust_pointers() would ignore it. Force adjustment if
427 // it points to dynamic space. For x86-64 with IMMOBILE_CODE,
428 // the fdefn can only point to immobile space,
429 // and it does so via a JMP instruction, so we must ignore it,
430 // lest it accidentally be adjusted (if somehow the next 8 bytes
431 // when interpreted as a word seemed to point to dynamic space
432 // though in fact it's an opcode followed by a 4 byte displacement).
433 // For all others, just adjust it here for uniformity.
434 #ifndef LISP_FEATURE_IMMOBILE_CODE
435 where[3] = adjust_word(where[3]);
436 #endif
437 continue;
438 case CODE_HEADER_WIDETAG:
439 // Fixup the constant pool. The word at where+1 is a fixnum.
440 adjust_pointers(where+2, code_header_words(header_word)-2);
441 // Fixup all embedded simple-funs
442 code = (struct code*)where;
443 for_each_simple_fun(i, f, code, 1, {
444 f->self = adjust_word(f->self);
445 adjust_pointers(SIMPLE_FUN_SCAV_START(f), SIMPLE_FUN_SCAV_NWORDS(f));
447 // Compute the address where the code "was" as the first argument
448 gencgc_apply_code_fixups((struct code*)((char*)where - heap_adjustment),
449 code);
450 #ifdef LISP_FEATURE_IMMOBILE_SPACE
451 // Now that the packed integer comprising the list of fixup locations
452 // has been fixed-up (if necessary), apply them to the code.
453 if (code->fixups != 0)
454 fixup_immobile_refs(adjust_word, code->fixups, code);
455 #endif
456 continue;
457 case CLOSURE_WIDETAG:
458 #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)
459 // For x86[-64], the closure fun appears to be a fixnum,
460 // and might need adjustment unless pointing to immobile code.
461 // Then fall into the general case; where[1] won't get re-adjusted
462 // because it doesn't satisfy is_lisp_pointer().
463 where[1] = adjust_word(where[1]);
464 #endif
465 break;
466 // Vectors require extra care because of EQ-based hashing.
467 case SIMPLE_VECTOR_WIDETAG:
468 if ((HeaderValue(*where) & 0xFF) == subtype_VectorValidHashing) {
469 struct vector* v = (struct vector*)where;
470 gc_assert(v->length > 0 &&
471 !(fixnum_value(v->length) & 1) && // length must be even
472 lowtag_of(v->data[0]) == INSTANCE_POINTER_LOWTAG);
473 lispobj* data = v->data;
474 adjust_pointers(&data[0], 1); // adjust the hash-table structure
475 boolean needs_rehash = 0;
476 int i;
477 // Adjust the elements, checking for need to rehash.
478 // v->data[1] is the unbound marker (a non-pointer)
479 for (i = fixnum_value(v->length)-1 ; i>=2 ; --i) {
480 lispobj ptr = data[i];
481 if (is_lisp_pointer(ptr) && needs_adjusting(ptr)) {
482 data[i] += heap_adjustment;
483 needs_rehash = 1;
486 if (needs_rehash) {
487 struct hash_table *ht = (struct hash_table*)native_pointer(v->data[0]);
488 ht->needs_rehash_p = T;
490 continue;
492 // All the array header widetags.
493 case SIMPLE_ARRAY_WIDETAG:
494 #ifdef COMPLEX_CHARACTER_STRING_WIDETAG
495 case COMPLEX_CHARACTER_STRING_WIDETAG:
496 #endif
497 case COMPLEX_BASE_STRING_WIDETAG:
498 case COMPLEX_VECTOR_NIL_WIDETAG:
499 case COMPLEX_BIT_VECTOR_WIDETAG:
500 case COMPLEX_VECTOR_WIDETAG:
501 case COMPLEX_ARRAY_WIDETAG:
502 // And the rest of the purely descriptor objects.
503 case SYMBOL_WIDETAG:
504 case VALUE_CELL_WIDETAG:
505 case WEAK_POINTER_WIDETAG:
506 case RATIO_WIDETAG:
507 case COMPLEX_WIDETAG:
508 break;
510 // Other
511 case SAP_WIDETAG:
512 if (needs_adjusting(where[1])) {
513 fprintf(stderr,
514 "WARNING: SAP at %p -> %p in relocatable core\n",
515 where, (void*)where[1]);
516 where[1] += heap_adjustment;
518 continue;
519 case BIGNUM_WIDETAG:
520 #ifndef LISP_FEATURE_64_BIT
521 case SINGLE_FLOAT_WIDETAG:
522 #endif
523 case DOUBLE_FLOAT_WIDETAG:
524 case COMPLEX_SINGLE_FLOAT_WIDETAG:
525 case COMPLEX_DOUBLE_FLOAT_WIDETAG:
526 #ifdef SIMD_PACK_WIDETAG
527 case SIMD_PACK_WIDETAG:
528 #endif
529 continue;
530 default:
531 if (other_immediate_lowtag_p(widetag)
532 && specialized_vector_widetag_p(widetag))
533 continue;
534 else
535 lose("Unrecognized heap object: @%p: %lx\n", where, header_word);
537 adjust_pointers(where+1, nwords-1);
541 void relocate_heap(lispobj* want, lispobj* got, uword_t len)
543 expected_range_start = (lispobj)want;
544 expected_range_end = (lispobj)want + len;
545 heap_adjustment = (lispobj)got - (lispobj)want;
546 #if MOCK_MMAP_FAILURE
547 fprintf(stderr, "Relocating heap from [%p:%p] to [%p:%p]\n",
548 want, (char*)want+len, got, (char*)got+len);
549 #endif
551 fixup_space((lispobj*)STATIC_SPACE_START, STATIC_SPACE_SIZE);
552 #ifdef LISP_FEATURE_IMMOBILE_SPACE
553 fixup_space((lispobj*)IMMOBILE_SPACE_START, IMMOBILE_SPACE_SIZE);
554 #endif
555 fixup_space((lispobj*)got, len); // the dynamic space itself
557 #endif
559 int merge_core_pages = -1;
561 os_vm_address_t anon_dynamic_space_start;
563 static void
564 process_directory(int fd, lispobj *ptr, int count, os_vm_offset_t file_offset)
566 extern void immobile_space_coreparse(uword_t,uword_t);
567 extern void write_protect_immobile_space();
568 struct ndir_entry *entry;
570 struct {
571 uword_t len;
572 uword_t base;
573 } spaces[MAX_CORE_SPACE_ID+1] = {
574 {0, 0}, // blank for space ID 0
575 #ifdef LISP_FEATURE_GENCGC
576 {0, DYNAMIC_SPACE_START},
577 #else
578 {0, 0},
579 #endif
580 // This order is determined by constants in compiler/generic/genesis
581 {0, STATIC_SPACE_START},
582 {0, READ_ONLY_SPACE_START},
583 #ifdef LISP_FEATURE_IMMOBILE_SPACE
584 {0, IMMOBILE_SPACE_START},
585 {0, IMMOBILE_VARYOBJ_SUBSPACE_START}
586 #endif
589 for (entry = (struct ndir_entry *) ptr; --count>= 0; ++entry) {
590 sword_t id = entry->identifier;
591 uword_t addr = (os_vm_page_size * entry->address);
592 int compressed = id & DEFLATED_CORE_SPACE_ID_FLAG;
593 id -= compressed;
594 if (id < 1 || id > MAX_CORE_SPACE_ID)
595 lose("unknown space ID %ld addr %p\n", id, addr);
597 #ifndef LISP_FEATURE_RELOCATABLE_HEAP
598 int enforce_address = 1;
599 #else
600 // Only enforce other spaces' addresses
601 int enforce_address = id != DYNAMIC_CORE_SPACE_ID;
602 #endif
603 if (enforce_address) {
604 int fail;
605 #ifdef LISP_FEATURE_CHENEYGC
606 if (id == DYNAMIC_CORE_SPACE_ID) {
607 if ((fail = (addr != DYNAMIC_0_SPACE_START) &&
608 (addr != DYNAMIC_1_SPACE_START)) != 0)
609 fprintf(stderr, "in core: %p; in runtime: %p or %p\n",
610 (void*)addr,
611 (void*)DYNAMIC_0_SPACE_START,
612 (void*)DYNAMIC_1_SPACE_START);
613 } else
614 #endif
615 if ((fail = (addr != spaces[id].base)) != 0)
616 fprintf(stderr, "in core: %p; in runtime: %p\n",
617 (void*)addr, (void*)spaces[id].base);
618 char *names[MAX_CORE_SPACE_ID] = {
619 "DYNAMIC", "STATIC", "READ_ONLY", "IMMOBILE", "IMMOBILE"
621 if (fail)
622 lose("core/runtime address mismatch: %s_SPACE_START", names[id-1]);
624 spaces[id].base = (uword_t)addr;
625 uword_t len = os_vm_page_size * entry->page_count;
626 spaces[id].len = len;
627 if (id == DYNAMIC_CORE_SPACE_ID && len > dynamic_space_size) {
628 lose("dynamic space too small for core: %luKiB required, %luKiB available.\n",
629 (unsigned long)len >> 10,
630 (unsigned long)dynamic_space_size >> 10);
632 if (len != 0) {
633 uword_t __attribute__((unused)) aligned_start;
634 #ifdef LISP_FEATURE_RELOCATABLE_HEAP
635 // Try to map at address requested by the core file.
636 if (id == DYNAMIC_CORE_SPACE_ID) {
637 addr = (uword_t)os_validate(MOVABLE,
638 (os_vm_address_t)maybe_fuzz_address(addr),
639 dynamic_space_size);
640 aligned_start = CEILING(addr, GENCGC_CARD_BYTES);
641 /* Misalignment can happen only if card size exceeds OS page.
642 * Drop one card to avoid overrunning the allocated space */
643 if (aligned_start > addr) // not card-aligned
644 dynamic_space_size -= GENCGC_CARD_BYTES;
645 DYNAMIC_SPACE_START = addr = aligned_start;
647 #endif /* LISP_FEATURE_RELOCATABLE_HEAP */
649 sword_t offset = os_vm_page_size * (1 + entry->data_page);
650 if (compressed)
651 inflate_core_bytes(fd, offset + file_offset, (os_vm_address_t)addr, len);
652 else
653 load_core_bytes(fd, offset + file_offset, (os_vm_address_t)addr, len);
656 #ifdef MADV_MERGEABLE
657 if ((merge_core_pages == 1)
658 || ((merge_core_pages == -1) && compressed)) {
659 madvise(addr, len, MADV_MERGEABLE);
661 #endif
663 if (id == DYNAMIC_CORE_SPACE_ID) {
664 /* 'addr' is the actual address if relocatable.
665 * For cheneygc, this will be whatever the GC was using
666 * at the time the core was saved.
667 * For gencgc we don't look at current_dynamic_space */
668 current_dynamic_space = (lispobj *)addr;
670 lispobj *free_pointer = (lispobj *) addr + entry->nwords;
671 /* FIXME: why not use set_alloc_pointer() ? */
672 #if defined(ALLOCATION_POINTER)
673 SetSymbolValue(ALLOCATION_POINTER, (lispobj)free_pointer,0);
674 #else
675 dynamic_space_free_pointer = free_pointer;
676 #endif
677 anon_dynamic_space_start = (os_vm_address_t)(addr + len);
678 /* This assertion safeguards the test in zero_pages_with_mmap()
679 * which trusts that if addr > anon_dynamic_space_start
680 * then addr did not come from any file mapping. */
681 gc_assert((lispobj)anon_dynamic_space_start > STATIC_SPACE_END);
685 #ifdef LISP_FEATURE_GENCGC
686 immobile_space_coreparse(spaces[IMMOBILE_FIXEDOBJ_CORE_SPACE_ID].len,
687 spaces[IMMOBILE_VARYOBJ_CORE_SPACE_ID].len);
688 #endif
689 #ifdef LISP_FEATURE_RELOCATABLE_HEAP
690 if (DYNAMIC_SPACE_START != spaces[DYNAMIC_CORE_SPACE_ID].base)
691 relocate_heap((lispobj*)spaces[DYNAMIC_CORE_SPACE_ID].base,
692 (lispobj*)DYNAMIC_SPACE_START,
693 spaces[DYNAMIC_CORE_SPACE_ID].len);
694 #endif
695 #ifdef LISP_FEATURE_X86_64
696 tune_asm_routines_for_microarch(); // before WPing immobile space
697 #endif
698 #ifdef LISP_FEATURE_IMMOBILE_SPACE
699 /* Delayed until after dynamic space has been mapped so that writes
700 * to immobile space due to core relocation don't fault. */
701 write_protect_immobile_space();
702 #endif
705 lispobj
706 load_core_file(char *file, os_vm_offset_t file_offset)
708 void *header;
709 #ifndef LISP_FEATURE_ALPHA
710 word_t val, *ptr;
711 #else
712 u32 val, *ptr;
713 #endif
714 os_vm_size_t len, remaining_len;
715 int fd = open_binary(file, O_RDONLY);
716 ssize_t count;
717 lispobj initial_function = NIL;
719 FSHOW((stderr, "/entering load_core_file(%s)\n", file));
720 if (fd < 0) {
721 fprintf(stderr, "could not open file \"%s\"\n", file);
722 perror("open");
723 exit(1);
726 lseek(fd, file_offset, SEEK_SET);
727 header = calloc(os_vm_page_size, 1);
729 count = read(fd, header, os_vm_page_size);
730 if (count < (ssize_t) os_vm_page_size) {
731 lose("premature end of core file\n");
733 SHOW("successfully read first page of core");
735 ptr = header;
736 val = *ptr++;
738 if (val != CORE_MAGIC) {
739 lose("invalid magic number in core: 0x%lx should have been 0x%x.\n",
740 val,
741 CORE_MAGIC);
743 SHOW("found CORE_MAGIC");
745 while (val != END_CORE_ENTRY_TYPE_CODE) {
746 val = *ptr++;
747 len = *ptr++;
748 remaining_len = len - 2; /* (-2 to cancel the two ++ operations) */
749 FSHOW((stderr, "/val=0x%"WORD_FMTX", remaining_len=0x%"WORD_FMTX"\n",
750 val, remaining_len));
752 switch (val) {
754 case END_CORE_ENTRY_TYPE_CODE:
755 SHOW("END_CORE_ENTRY_TYPE_CODE case");
756 break;
758 case BUILD_ID_CORE_ENTRY_TYPE_CODE:
759 SHOW("BUILD_ID_CORE_ENTRY_TYPE_CODE case");
761 os_vm_size_t i;
763 FSHOW((stderr, "build_id[]=\"%s\"\n", build_id));
764 FSHOW((stderr, "remaining_len = %d\n", remaining_len));
765 if (remaining_len != strlen((const char *)build_id))
766 goto losing_build_id;
767 for (i = 0; i < remaining_len; ++i) {
768 FSHOW((stderr, "ptr[%d] = char = %d, expected=%d\n",
769 i, ptr[i], build_id[i]));
770 if (ptr[i] != build_id[i])
771 goto losing_build_id;
773 break;
774 losing_build_id:
775 /* .core files are not binary-compatible between
776 * builds because we can't easily detect whether the
777 * sources were patched between the time the
778 * dumping-the-.core runtime was built and the time
779 * that the loading-the-.core runtime was built.
781 * (We could easily detect whether version.lisp-expr
782 * was changed, but people experimenting with patches
783 * don't necessarily update version.lisp-expr.) */
785 fprintf(stderr, "core was built for runtime '");
786 for (i = 0; i < remaining_len; ++i) putc(ptr[i], stderr);
787 fprintf(stderr, "' but this is '%s'\n", build_id);
788 lose("can't load .core for different runtime, sorry\n");
791 case NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE:
792 SHOW("NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE case");
793 process_directory(fd,
794 ptr,
795 #ifndef LISP_FEATURE_ALPHA
796 remaining_len / (sizeof(struct ndir_entry) /
797 sizeof(lispobj)),
798 #else
799 remaining_len / (sizeof(struct ndir_entry) /
800 sizeof(u32)),
801 #endif
802 file_offset);
803 break;
805 case INITIAL_FUN_CORE_ENTRY_TYPE_CODE:
806 SHOW("INITIAL_FUN_CORE_ENTRY_TYPE_CODE case");
807 initial_function = adjust_word((lispobj)*ptr);
808 break;
810 #ifdef LISP_FEATURE_GENCGC
811 case PAGE_TABLE_CORE_ENTRY_TYPE_CODE:
813 extern void gc_allocate_ptes();
814 // Allocation of PTEs is delayed 'til now so that calloc() doesn't
815 // consume addresses that would have been taken by a mapped space.
816 gc_allocate_ptes();
817 os_vm_size_t remaining = *ptr;
818 os_vm_size_t fdoffset = (*(ptr+1) + 1) * (os_vm_page_size);
819 page_index_t page = 0, npages;
820 ssize_t bytes_read;
821 char data[8192];
822 // A corefile_pte is 10 bytes for x86-64
823 // Process an integral number of ptes on each read.
824 os_vm_size_t chunksize = sizeof (struct corefile_pte)
825 * (sizeof data / sizeof (struct corefile_pte));
826 lseek(fd, fdoffset + file_offset, SEEK_SET);
827 bytes_read = read(fd, &npages, sizeof npages);
828 gc_assert(bytes_read == sizeof npages);
829 remaining -= sizeof npages;
830 while ((bytes_read = read(fd, data,
831 remaining < chunksize ? remaining : chunksize)) > 0) {
833 int i = 0;
834 remaining -= bytes_read;
835 while (bytes_read) {
836 bytes_read -= sizeof(struct corefile_pte);
837 /* Ignore all zeroes. The size of the page table
838 * core entry was rounded up to os_vm_page_size
839 * during the save, and might now have more
840 * elements than the page table.
842 * The low bits of each word are allocation flags.
844 struct corefile_pte pte;
845 memcpy(&pte, data+i*sizeof (struct corefile_pte), sizeof pte);
846 set_page_bytes_used(page, pte.bytes_used);
847 set_page_scan_start_offset(page, pte.sso & ~0x03);
848 page_table[page].allocated = pte.sso & 0x03;
849 if (++page == npages) // break out of both loops
850 goto done;
851 i++;
854 done:
856 gencgc_partial_pickup = 1;
857 break;
859 #endif
860 default:
861 lose("unknown core file entry: 0x%"WORD_FMTX"\n", val);
864 ptr += remaining_len;
865 FSHOW((stderr, "/new ptr=0x%"WORD_FMTX"\n", ptr));
867 SHOW("about to free(header)");
868 free(header);
869 close(fd);
870 SHOW("returning from load_core_file(..)");
871 return initial_function;
874 #include "genesis/hash-table.h"
875 #include "genesis/vector.h"
876 os_vm_address_t get_asm_routine_by_name(const char* name)
878 lispobj routines = SYMBOL(ASSEMBLER_ROUTINES)->value;
879 if (lowtag_of(routines) == INSTANCE_POINTER_LOWTAG) {
880 struct hash_table* ht = (struct hash_table*)native_pointer(routines);
881 struct vector* table = VECTOR(ht->table);
882 lispobj sym;
883 int i;
884 for (i=2 ; i < fixnum_value(table->length) ; i += 2) {
885 sym = table->data[i];
886 if (lowtag_of(sym) == OTHER_POINTER_LOWTAG
887 && widetag_of(SYMBOL(sym)->header) == SYMBOL_WIDETAG
888 && !strcmp(name, (char*)(VECTOR(SYMBOL(sym)->name)->data)))
889 return (os_vm_address_t)fixnum_value(table->data[i+1]);
891 // Something is wrong if we have a hashtable but find nothing.
892 fprintf(stderr, "WARNING: get_asm_routine_by_name(%s) failed\n",
893 name);
895 return NULL;
898 void asm_routine_poke(const char* routine, int offset, char byte)
900 char *address = (char *)get_asm_routine_by_name(routine);
901 if (address)
902 address[offset] = byte;