f6fb4bd2e285891e83914d8c62ac8ae58a669d8f
[projects/cmucl/cmucl.git] / src / lisp / save.c
1 /*
2
3  $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/save.c,v 1.29 2010/09/24 04:08:39 rtoy Rel $
4
5  This code was written as part of the CMU Common Lisp project at
6  Carnegie Mellon University, and has been placed in the public domain.
7
8 */
9
10
11 #include <stdio.h>
12 #include <signal.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "lisp.h"
17 #include "os.h"
18 #include "internals.h"
19 #include "core.h"
20 #include "globals.h"
21 #include "save.h"
22 #include "lispregs.h"
23 #include "validate.h"
24 #include "dynbind.h"
25
26 #ifdef GENCGC
27 #include "gencgc.h"
28 #endif
29
30 #ifdef FEATURE_EXECUTABLE
31 #include "elf.h"
32 #if !(defined(DARWIN) && defined(__ppc__))
33 #include <libgen.h>
34 #endif
35 #endif
36
37 extern int version;
38
39 static long
40 write_bytes(FILE * file, char *addr, long bytes)
41 {
42     long count, here, data;
43
44     bytes = (bytes + CORE_PAGESIZE - 1) & ~(CORE_PAGESIZE - 1);
45
46     fflush(file);
47     here = ftell(file);
48     fseek(file, 0, 2);
49     data = (ftell(file) + CORE_PAGESIZE - 1) & ~(CORE_PAGESIZE - 1);
50     fseek(file, data, 0);
51
52     while (bytes > 0) {
53         count = fwrite(addr, 1, bytes, file);
54         if (count > 0) {
55             bytes -= count;
56             addr += count;
57         } else {
58             perror("Error writing to save file");
59             bytes = 0;
60         }
61     }
62     fflush(file);
63     fseek(file, here, 0);
64     return data / CORE_PAGESIZE - 1;
65 }
66
67 static void
68 output_space(FILE * file, int id, lispobj * addr, lispobj * end)
69 {
70     int words, bytes, data;
71     static char *names[] = { NULL, "Dynamic", "Static", "Read-Only" };
72
73     putw(id, file);
74     words = end - addr;
75     putw(words, file);
76
77     bytes = words * sizeof(lispobj);
78
79     printf("Writing %d bytes from the %s space at 0x%08lX.\n",
80            bytes, names[id], (unsigned long) addr);
81
82     data = write_bytes(file, (char *) addr, bytes);
83
84     putw(data, file);
85     putw((long) addr / CORE_PAGESIZE, file);
86     putw((bytes + CORE_PAGESIZE - 1) / CORE_PAGESIZE, file);
87 }
88
89 #ifdef DEBUG_BAD_HEAP
90 static void
91 dump_region(struct alloc_region *alloc_region)
92 {
93     fprintf(stderr, "free_pointer = %p\n", alloc_region->free_pointer);
94     fprintf(stderr, "end_addr     = %p\n", alloc_region->end_addr);
95     fprintf(stderr, "first_page   = %d\n", alloc_region->first_page);
96     fprintf(stderr, "last_page    = %d\n", alloc_region->last_page);
97     fprintf(stderr, "start_addr   = %p\n", alloc_region->start_addr);
98
99     fprintf(stderr, " page_table[%d]\n", alloc_region->first_page);
100     fprintf(stderr, "   flags     = %x\n", page_table[alloc_region->first_page].flags);
101     fprintf(stderr, "   offset    = %x\n", page_table[alloc_region->first_page].first_object_offset);
102     fprintf(stderr, "   used      = %x\n", page_table[alloc_region->first_page].bytes_used);
103 }
104 #endif
105
106 boolean
107 save(char *filename, lispobj init_function, int sse2_mode)
108 {
109     FILE *file;
110
111 #if defined WANT_CGC
112     volatile lispobj *func_ptr = &init_function;
113     char sbuf[128];
114
115     strcpy(sbuf, filename);
116     filename = sbuf;
117     /* Get rid of remnant stuff. This is a MUST so that
118      * the memory manager can get started correctly when
119      * we restart after this save. Purify is going to
120      * maybe move the args so we need to consider them volatile,
121      * especially if the gcc optimizer is working!!
122      */
123     purify(NIL, NIL);
124
125     init_function = *func_ptr;
126     /* Set dynamic space pointer to base value so we don't write out
127      * MBs of just cleared heap.
128      */
129     if (SymbolValue(X86_CGC_ACTIVE_P) != NIL)
130         SetSymbolValue(ALLOCATION_POINTER, DYNAMIC_0_SPACE_START);
131 #endif
132     /* Open the file: */
133     remove(filename);
134     file = fopen(filename, "w");
135     if (file == NULL) {
136         perror(filename);
137         return TRUE;
138     }
139     printf("[Undoing binding stack... ");
140     fflush(stdout);
141     unbind_to_here((lispobj *) BINDING_STACK_START);
142     SetSymbolValue(CURRENT_CATCH_BLOCK, 0);
143     SetSymbolValue(CURRENT_UNWIND_PROTECT_BLOCK, 0);
144     SetSymbolValue(EVAL_STACK_TOP, 0);
145     printf("done]\n");
146 #if defined WANT_CGC && defined X86_CGC_ACTIVE_P
147     SetSymbolValue(X86_CGC_ACTIVE_P, T);
148 #endif
149     printf("[Saving current lisp image into %s:\n", filename);
150
151     putw(CORE_MAGIC, file);
152
153     putw(CORE_VERSION, file);
154 #if defined(i386) && defined(FEATURE_SSE2)
155     putw(4, file);
156 #else
157     putw(3, file);
158 #endif
159     putw(version, file);
160
161 #if defined(i386) && defined(FEATURE_SSE2)
162     if (sse2_mode) {
163         putw(SSE2, file);
164     } else {
165         putw(X87, file);
166     }
167 #endif
168     
169     putw(CORE_NDIRECTORY, file);
170     putw((5 * 3) + 2, file);
171
172     output_space(file, READ_ONLY_SPACE_ID, read_only_space,
173                  (lispobj *) SymbolValue(READ_ONLY_SPACE_FREE_POINTER));
174     output_space(file, STATIC_SPACE_ID, static_space,
175                  (lispobj *) SymbolValue(STATIC_SPACE_FREE_POINTER));
176 #ifdef GENCGC
177     /* Flush the current_region updating the tables. */
178 #ifdef DEBUG_BAD_HEAP
179     fprintf(stderr, "before ALLOC_POINTER = %p\n", (lispobj *) SymbolValue(ALLOCATION_POINTER));
180     dump_region(&boxed_region);
181 #endif
182     gc_alloc_update_page_tables(0, &boxed_region);
183     gc_alloc_update_page_tables(1, &unboxed_region);
184 #ifdef DEBUG_BAD_HEAP
185     fprintf(stderr, "boxed_region after update\n");
186     dump_region(&boxed_region);
187
188     print_ptr((lispobj*) 0x2805a184);
189 #endif
190     
191 #ifdef DEBUG_BAD_HEAP
192     /*
193      * For some reason x86 has a heap corruption problem.  I (rtoy)
194      * have not been able to figure out how that occurs, but what is
195      * happening is that when a core is loaded, there is some static
196      * object pointing to an object that is on a free page.  In normal
197      * usage, at startup there should be 4 objects in static space
198      * pointing to a free page, because these are newly allocated
199      * objects created by the C runtime.  However, there is an
200      * additional object.
201      *
202      * I do not know what this object should be or how it got there,
203      * but it will often cause CMUCL to fail to save a new core file.
204      *
205      * Disabling this call to update_dynamic_space_free_pointer is a
206      * work around.  What is happening is that u_d_s_f_p is resetting
207      * ALLOCATION_POINTER, but that weird object is in the current
208      * region, but after resetting the pointer, that object isn't
209      * saved to the core file.  By not resetting the pointer, the
210      * object (or at least enough of it) gets saved in the core file
211      * that we don't have problems when reloading.
212      *
213      * Note that on sparc and ppc, u_d_s_f_p doesn't actually do
214      * anything because the call to reset ALLOCATION_POINTER is a nop
215      * on sparc and ppc.  And sparc and ppc dont' have the heap
216      * corruption issue.  That's not conclusive evidence, though.
217      *
218      * This needs more work and investigation.
219      */
220     update_dynamic_space_free_pointer();
221 #endif
222
223 #ifdef DEBUG_BAD_HEAP    
224     fprintf(stderr, "after ALLOC_POINTER = %p\n", (lispobj *) SymbolValue(ALLOCATION_POINTER));
225 #endif    
226 #endif
227
228 #ifdef reg_ALLOC
229     output_space(file, DYNAMIC_SPACE_ID, current_dynamic_space,
230                  current_dynamic_space_free_pointer);
231 #else
232     output_space(file, DYNAMIC_SPACE_ID, current_dynamic_space,
233                  (lispobj *) SymbolValue(ALLOCATION_POINTER));
234 #endif
235
236     putw(CORE_INITIAL_FUNCTION, file);
237     putw(3, file);
238     putw(init_function, file);
239
240     putw(CORE_END, file);
241     fclose(file);
242
243     printf("done.]\n");
244
245     exit(0);
246 }
247
248
249 #ifdef FEATURE_EXECUTABLE
250 boolean
251 save_executable(char *filename, lispobj init_function)
252 {
253     char *dir_name;
254
255 #if defined WANT_CGC
256     volatile lispobj *func_ptr = &init_function;
257     char sbuf[128];
258
259     strcpy(sbuf, filename);
260     filename = sbuf;
261     /* Get rid of remnant stuff. This is a MUST so that
262      * the memory manager can get started correctly when
263      * we restart after this save. Purify is going to
264      * maybe move the args so we need to consider them volatile,
265      * especially if the gcc optimizer is working!!
266      */
267     purify(NIL, NIL);
268
269     init_function = *func_ptr;
270     /* Set dynamic space pointer to base value so we don't write out
271      * MBs of just cleared heap.
272      */
273     if(SymbolValue(X86_CGC_ACTIVE_P) != NIL)
274         SetSymbolValue(ALLOCATION_POINTER, DYNAMIC_0_SPACE_START);
275 #endif
276     dir_name = dirname(strdup(filename));
277
278     printf("[Undoing binding stack... ");
279     fflush(stdout);
280     unbind_to_here((lispobj *)BINDING_STACK_START);
281     SetSymbolValue(CURRENT_CATCH_BLOCK, 0);
282     SetSymbolValue(CURRENT_UNWIND_PROTECT_BLOCK, 0);
283     SetSymbolValue(EVAL_STACK_TOP, 0);
284     printf("done]\n");
285 #if defined WANT_CGC && defined X86_CGC_ACTIVE_P
286     SetSymbolValue(X86_CGC_ACTIVE_P, T);
287 #endif
288     printf("[Saving current lisp image as executable into \"%s\":\n", filename);
289
290     printf("\t[Writing core objects\n");
291     fflush(stdout);
292     write_space_object(dir_name, READ_ONLY_SPACE_ID, (os_vm_address_t)read_only_space,
293                        (os_vm_address_t)SymbolValue(READ_ONLY_SPACE_FREE_POINTER));
294     write_space_object(dir_name, STATIC_SPACE_ID, (os_vm_address_t)static_space,
295                        (os_vm_address_t)SymbolValue(STATIC_SPACE_FREE_POINTER));
296 #ifdef GENCGC
297     /* Flush the current_region updating the tables. */
298 #ifdef DEBUG_BAD_HEAP
299     fprintf(stderr, "before ALLOC_POINTER = %p\n", (lispobj *) SymbolValue(ALLOCATION_POINTER));
300     dump_region(&boxed_region);
301 #endif
302     gc_alloc_update_page_tables(0,&boxed_region);
303     gc_alloc_update_page_tables(1,&unboxed_region);
304 #ifdef DEBUG_BAD_HEAP
305     fprintf(stderr, "boxed_region after update\n");
306     dump_region(&boxed_region);
307
308     print_ptr((lispobj*) 0x2805a184);
309 #endif
310 #ifdef DEBUG_BAD_HEAP
311     /*
312      * For some reason x86 has a heap corruption problem.  I (rtoy)
313      * have not been able to figure out how that occurs, but what is
314      * happening is that when a core is loaded, there is some static
315      * object pointing to an object that is on a free page.  In normal
316      * usage, at startup there should be 4 objects in static space
317      * pointing to a free page, because these are newly allocated
318      * objects created by the C runtime.  However, there is an
319      * additional object.
320      *
321      * I do not know what this object should be or how it got there,
322      * but it will often cause CMUCL to fail to save a new core file.
323      *
324      * Disabling this call to update_dynamic_space_free_pointer is a
325      * work around.  What is happening is that u_d_s_f_p is resetting
326      * ALLOCATION_POINTER, but that weird object is in the current
327      * region, but after resetting the pointer, that object isn't
328      * saved to the core file.  By not resetting the pointer, the
329      * object (or at least enough of it) gets saved in the core file
330      * that we don't have problems when reloading.
331      *
332      * Note that on sparc and ppc, u_d_s_f_p doesn't actually do
333      * anything because the call to reset ALLOCATION_POINTER is a nop
334      * on sparc and ppc.  And sparc and ppc dont' have the heap
335      * corruption issue.  That's not conclusive evidence, though.
336      *
337      * This needs more work and investigation.
338      */
339     update_dynamic_space_free_pointer();
340 #endif
341
342 #ifdef DEBUG_BAD_HEAP    
343     fprintf(stderr, "after ALLOC_POINTER = %p\n", (lispobj *) SymbolValue(ALLOCATION_POINTER));
344 #endif    
345 #endif
346
347 #ifdef reg_ALLOC
348     write_space_object(dir_name, DYNAMIC_SPACE_ID, (os_vm_address_t)current_dynamic_space,
349                        (os_vm_address_t)current_dynamic_space_free_pointer);
350 #else
351     write_space_object(dir_name, DYNAMIC_SPACE_ID, (os_vm_address_t)current_dynamic_space,
352                        (os_vm_address_t)SymbolValue(ALLOCATION_POINTER));
353 #endif
354
355     printf("\tdone]\n");
356     fflush(stdout);
357     
358     printf("Linking executable...\n");
359     fflush(stdout);
360     obj_run_linker(init_function, filename);
361     printf("done.\n");
362     exit(0);
363 }
364 #endif