2 * This software is part of the SBCL system. See the README file for
5 * This software is derived from the CMU CL system, which was
6 * written at Carnegie Mellon University and released into the
7 * public domain. The software is in the public domain and is
8 * provided with absolutely no warranty. See the COPYING and CREDITS
9 * files for more information.
12 #ifndef LISP_FEATURE_WIN32
13 #include <sys/types.h>
31 #include "gc-internal.h"
34 #include "genesis/static-symbols.h"
35 #include "genesis/symbol.h"
37 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
38 #include "genesis/lutex.h"
41 /* write_runtime_options uses a simple serialization scheme that
42 * consists of one word of magic, one word indicating whether options
43 * are actually saved, and one word per struct field. */
45 write_runtime_options(FILE *file
, struct runtime_options
*options
)
47 size_t optarray
[RUNTIME_OPTIONS_WORDS
];
49 memset(&optarray
, 0, sizeof(optarray
));
50 optarray
[0] = RUNTIME_OPTIONS_MAGIC
;
52 if (options
!= NULL
) {
53 /* optarray[1] is a flag indicating that options are present */
55 optarray
[2] = options
->dynamic_space_size
;
56 optarray
[3] = options
->thread_control_stack_size
;
59 if (RUNTIME_OPTIONS_WORDS
!=
60 fwrite(optarray
, sizeof(size_t), RUNTIME_OPTIONS_WORDS
, file
)) {
61 perror("Error writing runtime options to file");
66 write_lispobj(lispobj obj
, FILE *file
)
68 if (1 != fwrite(&obj
, sizeof(lispobj
), 1, file
)) {
69 perror("Error writing to file");
74 write_bytes(FILE *file
, char *addr
, long bytes
, os_vm_offset_t file_offset
)
76 long count
, here
, data
;
78 bytes
= (bytes
+os_vm_page_size
-1)&~(os_vm_page_size
-1);
80 #ifdef LISP_FEATURE_WIN32
81 /* touch every single page in the space to force it to be mapped. */
82 for (count
= 0; count
< bytes
; count
+= 0x1000) {
83 volatile int temp
= addr
[count
];
89 fseek(file
, 0, SEEK_END
);
90 data
= (ftell(file
)+os_vm_page_size
-1)&~(os_vm_page_size
-1);
91 fseek(file
, data
, SEEK_SET
);
94 count
= fwrite(addr
, 1, bytes
, file
);
100 perror("error writing to save file");
105 fseek(file
, here
, SEEK_SET
);
106 return ((data
- file_offset
) / os_vm_page_size
) - 1;
109 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
110 /* saving lutexes in the core */
111 static void **lutex_addresses
;
112 static long n_lutexes
= 0;
113 static long max_lutexes
= 0;
116 default_scan_action(lispobj
*obj
)
118 return (sizetab
[widetag_of(*obj
)])(obj
);
122 lutex_scan_action(lispobj
*obj
)
124 /* note the address of the lutex */
125 if(n_lutexes
>= max_lutexes
) {
127 lutex_addresses
= realloc(lutex_addresses
, max_lutexes
* sizeof(void *));
128 gc_assert(lutex_addresses
);
131 lutex_addresses
[n_lutexes
++] = obj
;
133 return (*sizetab
[widetag_of(*obj
)])(obj
);
136 typedef long (*scan_table
[256])(lispobj
*obj
);
139 scan_objects(lispobj
*start
, long n_words
, scan_table table
)
141 lispobj
*end
= start
+ n_words
;
143 long n_words_scanned
;
144 for (object_ptr
= start
;
146 object_ptr
+= n_words_scanned
) {
147 lispobj obj
= *object_ptr
;
149 n_words_scanned
= (table
[widetag_of(obj
)])(object_ptr
);
154 scan_for_lutexes(lispobj
*addr
, long n_words
)
156 static int initialized
= 0;
157 static scan_table lutex_scan_table
;
162 /* allocate a little space to get started */
163 lutex_addresses
= malloc(16*sizeof(void *));
164 gc_assert(lutex_addresses
);
167 /* initialize the mapping table */
168 for(i
= 0; i
< ((sizeof lutex_scan_table
)/(sizeof lutex_scan_table
[0])); ++i
) {
169 lutex_scan_table
[i
] = default_scan_action
;
172 lutex_scan_table
[LUTEX_WIDETAG
] = lutex_scan_action
;
178 scan_objects(addr
, n_words
, lutex_scan_table
);
183 output_space(FILE *file
, int id
, lispobj
*addr
, lispobj
*end
, os_vm_offset_t file_offset
)
185 size_t words
, bytes
, data
;
186 static char *names
[] = {NULL
, "dynamic", "static", "read-only"};
188 write_lispobj(id
, file
);
190 write_lispobj(words
, file
);
192 bytes
= words
* sizeof(lispobj
);
194 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
195 printf("scanning space for lutexes...\n");
196 scan_for_lutexes((char *)addr
, words
);
199 printf("writing %lu bytes from the %s space at 0x%08lx\n",
200 (unsigned long)bytes
, names
[id
], (unsigned long)addr
);
202 data
= write_bytes(file
, (char *)addr
, bytes
, file_offset
);
204 write_lispobj(data
, file
);
205 write_lispobj((long)addr
/ os_vm_page_size
, file
);
206 write_lispobj((bytes
+ os_vm_page_size
- 1) / os_vm_page_size
, file
);
210 open_core_for_saving(char *filename
)
212 /* Open the output file. We don't actually need the file yet, but
213 * the fopen() might fail for some reason, and we want to detect
214 * that and back out before we do anything irreversible. */
216 return fopen(filename
, "wb");
220 save_to_filehandle(FILE *file
, char *filename
, lispobj init_function
,
221 boolean make_executable
,
222 boolean save_runtime_options
)
225 os_vm_offset_t core_start_pos
;
227 /* Smash the enclosing state. (Once we do this, there's no good
228 * way to go back, which is a sufficient reason that this ends up
229 * being SAVE-LISP-AND-DIE instead of SAVE-LISP-AND-GO-ON). */
230 printf("[undoing binding stack and other enclosing state... ");
232 for_each_thread(th
) { /* XXX really? */
233 unbind_to_here((lispobj
*)th
->binding_stack_start
,th
);
234 SetSymbolValue(CURRENT_CATCH_BLOCK
, 0,th
);
235 SetSymbolValue(CURRENT_UNWIND_PROTECT_BLOCK
, 0,th
);
240 /* (Now we can actually start copying ourselves into the output file.) */
242 printf("[saving current Lisp image into %s:\n", filename
);
245 core_start_pos
= ftell(file
);
246 write_lispobj(CORE_MAGIC
, file
);
248 write_lispobj(VERSION_CORE_ENTRY_TYPE_CODE
, file
);
249 write_lispobj(3, file
);
250 write_lispobj(SBCL_CORE_VERSION_INTEGER
, file
);
252 write_lispobj(BUILD_ID_CORE_ENTRY_TYPE_CODE
, file
);
253 write_lispobj(/* (We're writing the word count of the entry here, and the 2
254 * term is one word for the leading BUILD_ID_CORE_ENTRY_TYPE_CODE
255 * word and one word where we store the count itself.) */
256 2 + strlen((const char *)build_id
),
260 for (p
= (unsigned char *)build_id
; *p
; ++p
)
261 write_lispobj(*p
, file
);
264 write_lispobj(NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE
, file
);
265 write_lispobj(/* (word count = 3 spaces described by 5 words each, plus the
266 * entry type code, plus this count itself) */
269 READ_ONLY_CORE_SPACE_ID
,
270 (lispobj
*)READ_ONLY_SPACE_START
,
271 (lispobj
*)SymbolValue(READ_ONLY_SPACE_FREE_POINTER
,0),
274 STATIC_CORE_SPACE_ID
,
275 (lispobj
*)STATIC_SPACE_START
,
276 (lispobj
*)SymbolValue(STATIC_SPACE_FREE_POINTER
,0),
278 #ifdef LISP_FEATURE_GENCGC
279 /* Flush the current_region, updating the tables. */
280 gc_alloc_update_all_page_tables();
281 update_dynamic_space_free_pointer();
284 #ifdef LISP_FEATURE_GENCGC
286 DYNAMIC_CORE_SPACE_ID
,
287 (lispobj
*)DYNAMIC_SPACE_START
,
288 dynamic_space_free_pointer
,
292 DYNAMIC_CORE_SPACE_ID
,
293 (lispobj
*)current_dynamic_space
,
294 dynamic_space_free_pointer
,
299 DYNAMIC_CORE_SPACE_ID
,
300 (lispobj
*)DYNAMIC_SPACE_START
,
301 (lispobj
*)SymbolValue(ALLOCATION_POINTER
,0),
305 write_lispobj(INITIAL_FUN_CORE_ENTRY_TYPE_CODE
, file
);
306 write_lispobj(3, file
);
307 write_lispobj(init_function
, file
);
309 #ifdef LISP_FEATURE_GENCGC
311 size_t size
= (last_free_page
*sizeof(long)+os_vm_page_size
-1)
312 &~(os_vm_page_size
-1);
313 unsigned long *data
= calloc(size
, 1);
318 for (i
= 0; i
< last_free_page
; i
++) {
319 /* Thanks to alignment requirements, the two low bits
320 * are always zero, so we can use them to store the
321 * allocation type -- region is always closed, so only
322 * the two low bits of allocation flags matter. */
323 word
= page_table
[i
].region_start_offset
;
324 gc_assert((word
& 0x03) == 0);
325 data
[i
] = word
| (0x03 & page_table
[i
].allocated
);
327 write_lispobj(PAGE_TABLE_CORE_ENTRY_TYPE_CODE
, file
);
328 write_lispobj(4, file
);
329 write_lispobj(size
, file
);
330 offset
= write_bytes(file
, (char *)data
, size
, core_start_pos
);
331 write_lispobj(offset
, file
);
336 #if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_LUTEX)
339 printf("writing %ld lutexes to the core...\n", n_lutexes
);
340 write_lispobj(LUTEX_TABLE_CORE_ENTRY_TYPE_CODE
, file
);
341 /* word count of the entry */
342 write_lispobj(4, file
);
343 /* indicate how many lutexes we saved */
344 write_lispobj(n_lutexes
, file
);
345 /* save the lutexes */
346 offset
= write_bytes(file
, (char *) lutex_addresses
,
347 n_lutexes
* sizeof(*lutex_addresses
),
350 write_lispobj(offset
, file
);
354 write_lispobj(END_CORE_ENTRY_TYPE_CODE
, file
);
356 /* Write a trailing header, ignored when parsing the core normally.
357 * This is used to locate the start of the core when the runtime is
358 * prepended to it. */
359 fseek(file
, 0, SEEK_END
);
361 /* If NULL runtime options are passed to write_runtime_options,
362 * command-line processing is performed as normal in the SBCL
363 * executable. Otherwise, the saved runtime options are used and
364 * all command-line arguments are available to Lisp in
365 * SB-EXT:*POSIX-ARGV*. */
366 write_runtime_options(file
,
367 (save_runtime_options
? runtime_options
: NULL
));
369 if (1 != fwrite(&core_start_pos
, sizeof(os_vm_offset_t
), 1, file
)) {
370 perror("Error writing core starting position to file");
373 write_lispobj(CORE_MAGIC
, file
);
377 #ifndef LISP_FEATURE_WIN32
379 chmod (filename
, 0755);
386 /* Check if the build_id for the current runtime is present in a
389 check_runtime_build_id(void *buf
, size_t size
)
394 idlen
= strlen(build_id
) - 1;
395 while ((pos
= memchr(buf
, build_id
[0], size
)) != NULL
) {
396 size
-= (pos
+ 1) - (char *)buf
;
398 if (idlen
<= size
&& memcmp(buf
, build_id
+ 1, idlen
) == 0)
405 /* Slurp the executable portion of the runtime into a malloced buffer
406 * and return it. Places the size in bytes of the runtime into
407 * 'size_out'. Returns NULL if the runtime cannot be loaded from
410 load_runtime(char *runtime_path
, size_t *size_out
)
415 os_vm_offset_t core_offset
;
417 core_offset
= search_for_embedded_core (runtime_path
);
418 if ((input
= fopen(runtime_path
, "rb")) == NULL
) {
419 fprintf(stderr
, "Unable to open runtime: %s\n", runtime_path
);
423 fseek(input
, 0, SEEK_END
);
424 size
= (size_t) ftell(input
);
425 fseek(input
, 0, SEEK_SET
);
427 if (core_offset
!= -1 && size
> core_offset
)
430 buf
= successful_malloc(size
);
431 if ((count
= fread(buf
, 1, size
, input
)) != size
) {
432 fprintf(stderr
, "Premature EOF while reading runtime.\n");
436 if (!check_runtime_build_id(buf
, size
)) {
437 fprintf(stderr
, "Failed to locate current build_id in runtime: %s\n",
455 save_runtime_to_filehandle(FILE *output
, void *runtime
, size_t runtime_size
)
460 if (runtime_size
!= fwrite(runtime
, 1, runtime_size
, output
)) {
461 perror("Error saving runtime");
465 padding
= (os_vm_page_size
- (runtime_size
% os_vm_page_size
)) & ~os_vm_page_size
;
467 padbytes
= successful_malloc(padding
);
468 memset(padbytes
, 0, padding
);
469 if (padding
!= fwrite(padbytes
, 1, padding
, output
)) {
470 perror("Error saving runtime");
481 prepare_to_save(char *filename
, boolean prepend_runtime
, void **runtime_bytes
,
482 size_t *runtime_size
)
487 if (prepend_runtime
) {
488 runtime_path
= os_get_runtime_executable_path(0);
490 if (runtime_path
== NULL
&& saved_runtime_path
== NULL
) {
491 fprintf(stderr
, "Unable to get default runtime path.\n");
495 if (runtime_path
== NULL
)
496 *runtime_bytes
= load_runtime(saved_runtime_path
, runtime_size
);
498 *runtime_bytes
= load_runtime(runtime_path
, runtime_size
);
502 if (*runtime_bytes
== NULL
)
506 file
= open_core_for_saving(filename
);
508 free(*runtime_bytes
);
517 save(char *filename
, lispobj init_function
, boolean prepend_runtime
,
518 boolean save_runtime_options
)
521 void *runtime_bytes
= NULL
;
524 file
= prepare_to_save(filename
, prepend_runtime
, &runtime_bytes
, &runtime_size
);
529 save_runtime_to_filehandle(file
, runtime_bytes
, runtime_size
);
531 return save_to_filehandle(file
, filename
, init_function
, prepend_runtime
,
532 save_runtime_options
);