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"
38 write_lispobj(lispobj obj, FILE *file)
40 fwrite(&obj, sizeof(lispobj), 1, file);
44 write_bytes(FILE *file, char *addr, long bytes, os_vm_offset_t file_offset)
46 long count, here, data;
48 bytes = (bytes+os_vm_page_size-1)&~(os_vm_page_size-1);
50 #ifdef LISP_FEATURE_WIN32
51 /* touch every single page in the space to force it to be mapped. */
52 for (count = 0; count < bytes; count += 0x1000) {
53 volatile int temp = addr[count];
59 fseek(file, 0, SEEK_END);
60 data = (ftell(file)+os_vm_page_size-1)&~(os_vm_page_size-1);
61 fseek(file, data, SEEK_SET);
64 count = fwrite(addr, 1, bytes, file);
70 perror("error writing to save file");
75 fseek(file, here, SEEK_SET);
76 return ((data - file_offset) / os_vm_page_size) - 1;
80 output_space(FILE *file, int id, lispobj *addr, lispobj *end, os_vm_offset_t file_offset)
82 int words, bytes, data;
83 static char *names[] = {NULL, "dynamic", "static", "read-only"};
85 write_lispobj(id, file);
87 write_lispobj(words, file);
89 bytes = words * sizeof(lispobj);
91 printf("writing %d bytes from the %s space at 0x%08lx\n",
92 bytes, names[id], (unsigned long)addr);
94 data = write_bytes(file, (char *)addr, bytes, file_offset);
96 write_lispobj(data, file);
97 write_lispobj((long)addr / os_vm_page_size, file);
98 write_lispobj((bytes + os_vm_page_size - 1) / os_vm_page_size, file);
102 open_core_for_saving(char *filename)
104 /* Open the output file. We don't actually need the file yet, but
105 * the fopen() might fail for some reason, and we want to detect
106 * that and back out before we do anything irreversible. */
108 return fopen(filename, "wb");
112 save_to_filehandle(FILE *file, char *filename, lispobj init_function,
113 boolean make_executable)
116 os_vm_offset_t core_start_pos, core_end_pos, core_size;
118 /* Smash the enclosing state. (Once we do this, there's no good
119 * way to go back, which is a sufficient reason that this ends up
120 * being SAVE-LISP-AND-DIE instead of SAVE-LISP-AND-GO-ON). */
121 printf("[undoing binding stack and other enclosing state... ");
123 for_each_thread(th) { /* XXX really? */
124 unbind_to_here((lispobj *)th->binding_stack_start,th);
125 SetSymbolValue(CURRENT_CATCH_BLOCK, 0,th);
126 SetSymbolValue(CURRENT_UNWIND_PROTECT_BLOCK, 0,th);
131 /* (Now we can actually start copying ourselves into the output file.) */
133 printf("[saving current Lisp image into %s:\n", filename);
136 core_start_pos = ftell(file);
137 write_lispobj(CORE_MAGIC, file);
139 write_lispobj(VERSION_CORE_ENTRY_TYPE_CODE, file);
140 write_lispobj(3, file);
141 write_lispobj(SBCL_CORE_VERSION_INTEGER, file);
143 write_lispobj(BUILD_ID_CORE_ENTRY_TYPE_CODE, file);
144 write_lispobj(/* (We're writing the word count of the entry here, and the 2
145 * term is one word for the leading BUILD_ID_CORE_ENTRY_TYPE_CODE
146 * word and one word where we store the count itself.) */
147 2 + strlen((const char *)build_id),
151 for (p = build_id; *p; ++p)
152 write_lispobj(*p, file);
155 write_lispobj(NEW_DIRECTORY_CORE_ENTRY_TYPE_CODE, file);
156 write_lispobj(/* (word count = 3 spaces described by 5 words each, plus the
157 * entry type code, plus this count itself) */
160 READ_ONLY_CORE_SPACE_ID,
161 (lispobj *)READ_ONLY_SPACE_START,
162 (lispobj *)SymbolValue(READ_ONLY_SPACE_FREE_POINTER,0),
165 STATIC_CORE_SPACE_ID,
166 (lispobj *)STATIC_SPACE_START,
167 (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER,0),
169 #ifdef LISP_FEATURE_GENCGC
170 /* Flush the current_region, updating the tables. */
171 gc_alloc_update_all_page_tables();
172 update_dynamic_space_free_pointer();
175 #ifdef LISP_FEATURE_GENCGC
177 DYNAMIC_CORE_SPACE_ID,
178 (lispobj *)DYNAMIC_SPACE_START,
179 dynamic_space_free_pointer,
183 DYNAMIC_CORE_SPACE_ID,
184 (lispobj *)current_dynamic_space,
185 dynamic_space_free_pointer,
190 DYNAMIC_CORE_SPACE_ID,
191 (lispobj *)DYNAMIC_SPACE_START,
192 (lispobj *)SymbolValue(ALLOCATION_POINTER,0),
196 write_lispobj(INITIAL_FUN_CORE_ENTRY_TYPE_CODE, file);
197 write_lispobj(3, file);
198 write_lispobj(init_function, file);
200 #ifdef LISP_FEATURE_GENCGC
202 size_t size = (last_free_page*sizeof(long)+os_vm_page_size-1)
203 &~(os_vm_page_size-1);
204 long *data = calloc(size, 1);
208 for (i = 0; i < last_free_page; i++) {
209 data[i] = page_table[i].first_object_offset;
211 write_lispobj(PAGE_TABLE_CORE_ENTRY_TYPE_CODE, file);
212 write_lispobj(4, file);
213 write_lispobj(size, file);
214 offset = write_bytes(file, (char *) data, size, core_start_pos);
215 write_lispobj(offset, file);
220 write_lispobj(END_CORE_ENTRY_TYPE_CODE, file);
222 /* Write a trailing header, ignored when parsing the core normally.
223 * This is used to locate the start of the core when the runtime is
224 * prepended to it. */
225 fseek(file, 0, SEEK_END);
226 core_end_pos = ftell(file);
227 core_size = core_end_pos - core_start_pos;
229 fwrite(&core_size, sizeof(os_vm_offset_t), 1, file);
230 write_lispobj(CORE_MAGIC, file);
233 #ifndef LISP_FEATURE_WIN32
235 chmod (filename, 0755);
242 /* Slurp the executable portion of the runtime into a malloced buffer
243 * and return it. Places the size in bytes of the runtime into
244 * 'size_out'. Returns NULL if the runtime cannot be loaded from
247 load_runtime(char *runtime_path, size_t *size_out)
252 os_vm_offset_t core_offset;
254 core_offset = search_for_embedded_core (runtime_path);
255 if ((input = fopen(runtime_path, "rb")) == NULL) {
256 fprintf(stderr, "Unable to open runtime: %s\n", runtime_path);
260 fseek(input, 0, SEEK_END);
261 size = (size_t) ftell(input);
262 fseek(input, 0, SEEK_SET);
264 if (core_offset != -1 && size > core_offset)
267 buf = successful_malloc(size);
268 if ((count = fread(buf, 1, size, input)) != size) {
269 fprintf(stderr, "Premature EOF while reading runtime.\n");
286 save_runtime_to_filehandle(FILE *output, void *runtime, size_t runtime_size)
291 fwrite(runtime, 1, runtime_size, output);
293 padding = (os_vm_page_size - (runtime_size % os_vm_page_size)) & ~os_vm_page_size;
295 padbytes = successful_malloc(padding);
296 memset(padbytes, 0, padding);
297 fwrite(padbytes, 1, padding, output);
305 prepare_to_save(char *filename, boolean prepend_runtime, void **runtime_bytes,
306 size_t *runtime_size)
311 if (prepend_runtime) {
312 runtime_path = os_get_runtime_executable_path();
314 if (runtime_path == NULL) {
315 fprintf(stderr, "Unable to get default runtime path.\n");
319 *runtime_bytes = load_runtime(runtime_path, runtime_size);
322 if (*runtime_bytes == NULL)
326 file = open_core_for_saving(filename);
328 free(*runtime_bytes);
337 save(char *filename, lispobj init_function, boolean prepend_runtime)
340 void *runtime_bytes = NULL;
343 file = prepare_to_save(filename, prepend_runtime, &runtime_bytes, &runtime_size);
348 save_runtime_to_filehandle(file, runtime_bytes, runtime_size);
350 return save_to_filehandle(file, filename, init_function, prepend_runtime);