Mercurial > hg > xemacs-beta
annotate src/dumper.c @ 4976:16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-02-04 Ben Wing <ben@xemacs.org>
* alloc.c (release_breathing_space):
* alloc.c (resize_string):
* alloc.c (sweep_lcrecords_1):
* alloc.c (SWEEP_FIXED_TYPE_BLOCK_1):
* alloc.c (ADDITIONAL_FREE_compiled_function):
* alloc.c (compact_string_chars):
* alloc.c (ADDITIONAL_FREE_string):
* alloc.c (sweep_strings):
* alloca.c (xemacs_c_alloca):
* alsaplay.c (alsa_play_sound_file):
* buffer.c (init_initial_directory):
* buffer.h:
* buffer.h (BUFFER_FREE):
* console-stream.c (stream_delete_console):
* console-tty.c (free_tty_console_struct):
* data.c (Fnumber_to_string):
* device-gtk.c (gtk_init_device):
* device-gtk.c (free_gtk_device_struct):
* device-gtk.c (gtk_delete_device):
* device-msw.c (mswindows_delete_device):
* device-msw.c (msprinter_delete_device):
* device-tty.c (free_tty_device_struct):
* device-tty.c (tty_delete_device):
* device-x.c (x_init_device):
* device-x.c (free_x_device_struct):
* device-x.c (x_delete_device):
* dialog-msw.c (handle_directory_dialog_box):
* dialog-x.c (dbox_descriptor_to_widget_value):
* dired-msw.c (Fmswindows_insert_directory):
* dired.c (free_user_cache):
* dired.c (user_name_completion_unwind):
* doc.c (unparesseuxify_doc_string):
* doc.c (Fsubstitute_command_keys):
* doprnt.c (emacs_doprnt_1):
* dumper.c (pdump_load_finish):
* dumper.c (pdump_file_free):
* dumper.c (pdump_file_unmap):
* dynarr.c:
* dynarr.c (Dynarr_free):
* editfns.c (uncache_home_directory):
* editfns.c (Fset_time_zone_rule):
* elhash.c:
* elhash.c (pdump_reorganize_hash_table):
* elhash.c (maphash_unwind):
* emacs.c (make_arg_list_1):
* emacs.c (free_argc_argv):
* emacs.c (sort_args):
* emacs.c (Frunning_temacs_p):
* emodules.c (attempt_module_delete):
* eval.c (free_pointer):
* event-Xt.c (unselect_filedesc):
* event-Xt.c (emacs_Xt_select_process):
* event-gtk.c (unselect_filedesc):
* event-gtk.c (dragndrop_data_received):
* event-msw.c (winsock_closer):
* event-msw.c (mswindows_dde_callback):
* event-msw.c (mswindows_wnd_proc):
* event-stream.c (finalize_command_builder):
* event-stream.c (free_command_builder):
* extents.c (free_gap_array):
* extents.c (free_extent_list):
* extents.c (free_soe):
* extents.c (extent_fragment_delete):
* extents.c (extent_priority_sort_function):
* file-coding.c (make_coding_system_1):
* file-coding.c (coding_finalizer):
* file-coding.c (set_coding_stream_coding_system):
* file-coding.c (chain_finalize_coding_stream_1):
* file-coding.c (chain_finalize):
* file-coding.c (free_detection_state):
* file-coding.c (coding_category_symbol_to_id):
* fileio.c:
* fileio.c (Ffile_name_directory):
* fileio.c (if):
* fileio.c (Ffile_symlink_p):
* filelock.c (FREE_LOCK_INFO):
* filelock.c (current_lock_owner):
* font-mgr.c (Ffc_name_unparse):
* font-mgr.c (Ffc_pattern_duplicate):
* frame-gtk.c (gtk_delete_frame):
* frame-msw.c (mswindows_delete_frame):
* frame-msw.c (msprinter_delete_frame):
* frame-x.c (x_cde_destroy_callback):
* frame-x.c (Fcde_start_drag_internal):
* frame-x.c (x_cde_transfer_callback):
* frame-x.c (x_delete_frame):
* frame.c (update_frame_title):
* frame.c (Fset_frame_pointer):
* gc.c (register_for_finalization):
* gccache-gtk.c (free_gc_cache):
* gccache-gtk.c (gc_cache_lookup):
* gccache-x.c (free_gc_cache):
* gccache-x.c (gc_cache_lookup):
* glyphs-eimage.c:
* glyphs-eimage.c (jpeg_instantiate_unwind):
* glyphs-eimage.c (gif_instantiate_unwind):
* glyphs-eimage.c (png_instantiate_unwind):
* glyphs-eimage.c (png_instantiate):
* glyphs-eimage.c (tiff_instantiate_unwind):
* glyphs-gtk.c (convert_EImage_to_GDKImage):
* glyphs-gtk.c (gtk_finalize_image_instance):
* glyphs-gtk.c (gtk_init_image_instance_from_eimage):
* glyphs-gtk.c (gtk_xpm_instantiate):
* glyphs-msw.c (convert_EImage_to_DIBitmap):
* glyphs-msw.c (mswindows_init_image_instance_from_eimage):
* glyphs-msw.c (mswindows_initialize_image_instance_mask):
* glyphs-msw.c (xpm_to_eimage):
* glyphs-msw.c (mswindows_xpm_instantiate):
* glyphs-msw.c (xbm_create_bitmap_from_data):
* glyphs-msw.c (mswindows_finalize_image_instance):
* glyphs-x.c (convert_EImage_to_XImage):
* glyphs-x.c (x_finalize_image_instance):
* glyphs-x.c (x_init_image_instance_from_eimage):
* glyphs-x.c (x_xpm_instantiate):
* gui-x.c (free_popup_widget_value_tree):
* hash.c (free_hash_table):
* hash.c (grow_hash_table):
* hash.c (pregrow_hash_table_if_necessary):
* imgproc.c (build_EImage_quantable):
* insdel.c (uninit_buffer_text):
* intl-win32.c (convert_multibyte_to_internal_malloc):
* intl.c:
* intl.c (Fset_current_locale):
* keymap.c:
* keymap.c (where_is_recursive_mapper):
* keymap.c (where_is_internal):
* lisp.h:
* lisp.h (xfree):
* lstream.c (Lstream_close):
* lstream.c (resizing_buffer_closer):
* mule-coding.c:
* mule-coding.c (iso2022_finalize_detection_state):
* nt.c:
* nt.c (mswindows_get_long_filename):
* nt.c (nt_get_resource):
* nt.c (init_mswindows_environment):
* nt.c (get_cached_volume_information):
* nt.c (mswindows_opendir):
* nt.c (mswindows_closedir):
* nt.c (mswindows_readdir):
* nt.c (mswindows_stat):
* nt.c (mswindows_getdcwd):
* nt.c (Fmswindows_long_file_name):
* ntplay.c (nt_play_sound_file):
* ntplay.c (play_sound_data_1):
* number-gmp.c (gmp_free):
* number-gmp.c (init_number_gmp):
* number-mp.c (bignum_to_string):
* number-mp.c (BIGNUM_TO_TYPE):
* number.c (bignum_print):
* number.c (bignum_convfree):
* number.c (ratio_print):
* number.c (bigfloat_print):
* number.c (bigfloat_finalize):
* objects-gtk.c (gtk_finalize_color_instance):
* objects-gtk.c (gtk_finalize_font_instance):
* objects-msw.c (mswindows_finalize_color_instance):
* objects-msw.c (mswindows_finalize_font_instance):
* objects-tty.c (tty_finalize_color_instance):
* objects-tty.c (tty_finalize_font_instance):
* objects-tty.c (tty_font_list):
* objects-x.c (x_finalize_color_instance):
* objects-x.c (x_finalize_font_instance):
* process.c:
* process.c (finalize_process):
* realpath.c:
* redisplay.c (add_propagation_runes):
* regex.c:
* regex.c (xfree):
* regex.c (REGEX_FREE_STACK):
* regex.c (FREE_STACK_RETURN):
* regex.c (regex_compile):
* regex.c (regexec):
* regex.c (regfree):
* scrollbar-gtk.c (gtk_free_scrollbar_instance):
* scrollbar-gtk.c (gtk_release_scrollbar_instance):
* scrollbar-msw.c (mswindows_free_scrollbar_instance):
* scrollbar-msw.c (unshow_that_mofo):
* scrollbar-x.c (x_free_scrollbar_instance):
* scrollbar-x.c (x_release_scrollbar_instance):
* select-gtk.c (emacs_gtk_selection_handle):
* select-msw.c (mswindows_own_selection):
* select-x.c:
* select-x.c (x_handle_selection_request):
* select-x.c (unexpect_property_change):
* select-x.c (x_handle_property_notify):
* select-x.c (receive_incremental_selection):
* select-x.c (x_get_window_property_as_lisp_data):
* select-x.c (Fx_get_cutbuffer_internal):
* specifier.c (finalize_specifier):
* syntax.c (uninit_buffer_syntax_cache):
* sysdep.c (qxe_allocating_getcwd):
* sysdep.c (qxe_lstat):
* sysdep.c (copy_in_passwd):
* sysdep.c (qxe_ctime):
* sysdep.c (closedir):
* sysdep.c (DIRSIZ):
* termcap.c (tgetent):
* termcap.c (tprint):
* tests.c (Ftest_data_format_conversion):
* text.c (new_dfc_convert_copy_data):
* text.h (eifree):
* text.h (eito_alloca):
* text.h (eito_external):
* toolbar-msw.c (mswindows_output_toolbar):
* ui-gtk.c (CONVERT_RETVAL):
* ui-gtk.c (__allocate_object_storage):
* unicode.c (free_from_unicode_table):
* unicode.c (free_to_unicode_table):
* unicode.c (free_charset_unicode_tables):
* win32.c (mswindows_read_link_1):
Rename: xfree(VAL, TYPE)->xfree(VAL)
Command used:
gr 'xfree *\((.*),.*\);' 'xfree (\1);' *.[ch]
Followed by grepping for 'xfree.*,' and fixing anything left.
Rationale: Having to specify the TYPE argument is annoying and
error-prone. It was originally put in to work around warnings
due to strict aliasing but years and years ago I rewrote it
in a way that doesn't use the TYPE argument at all and no one
has complained since then. (And anyway, XEmacs is far from
ever being in compliance with strict aliasing and would require
far-reaching changes to get that way.)
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Thu, 04 Feb 2010 07:28:14 -0600 |
parents | 19a72041c5ed |
children | c8f90d61dcf3 |
rev | line source |
---|---|
442 | 1 /* Portable data dumper for XEmacs. |
2551 | 2 Copyright (C) 1999-2000,2004 Olivier Galibert |
458 | 3 Copyright (C) 2001 Martin Buchholz |
2563 | 4 Copyright (C) 2001, 2002, 2003, 2004, 2005 Ben Wing. |
442 | 5 |
6 This file is part of XEmacs. | |
7 | |
8 XEmacs is free software; you can redistribute it and/or modify it | |
9 under the terms of the GNU General Public License as published by the | |
10 Free Software Foundation; either version 2, or (at your option) any | |
11 later version. | |
12 | |
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with XEmacs; see the file COPYING. If not, write to | |
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
21 Boston, MA 02111-1307, USA. */ | |
22 | |
23 /* Synched up with: Not in FSF. */ | |
24 | |
2367 | 25 /* This file has been Mule-ized, Ben Wing, 10-10-04. */ |
26 | |
27 /* #### Put in much more assertions. Whenever we store fixups in the | |
28 process or writing out data, make sure the fixups (offsets) point to the | |
29 beginning of an object, i.e. are registered. Same whenever we read in | |
30 -- verify offsets as registered, and when compute a fixup, verify the | |
31 pointer is pointing within the pdump area. registered and check within | |
32 pdump area. For specific types of pointers (e.g. to Lisp_Objects), | |
33 check if they're pointing to the right kinds of types. It should be | |
34 possible to check that a putative Lisp_Object is really a Lisp_Object | |
35 since it will follow a strict format in its header. */ | |
800 | 36 |
442 | 37 #include <config.h> |
38 #include "lisp.h" | |
39 | |
40 #include "specifier.h" | |
771 | 41 #include "file-coding.h" |
442 | 42 #include "elhash.h" |
1204 | 43 #include "lstream.h" |
442 | 44 #include "sysfile.h" |
45 #include "console-stream.h" | |
46 | |
47 #ifdef WIN32_NATIVE | |
771 | 48 #include "syswindows.h" |
442 | 49 #else |
50 #ifdef HAVE_MMAP | |
51 #include <sys/mman.h> | |
52 #endif | |
2720 | 53 #ifdef DUMP_IN_EXEC |
2015 | 54 #include "dump-data.h" |
442 | 55 #endif |
2720 | 56 #endif |
442 | 57 |
58 typedef struct | |
59 { | |
2367 | 60 const void *blockaddr; |
665 | 61 Bytecount size; |
1204 | 62 const struct memory_description *desc; |
63 } pdump_root_block; | |
452 | 64 |
65 typedef struct | |
66 { | |
1204 | 67 Dynarr_declare (pdump_root_block); |
68 } pdump_root_block_dynarr; | |
452 | 69 |
70 typedef struct | |
71 { | |
72 void **ptraddress; | |
1204 | 73 const struct sized_memory_description *desc; |
2367 | 74 } pdump_root_block_ptr; |
452 | 75 |
76 typedef struct | |
77 { | |
2367 | 78 Dynarr_declare (pdump_root_block_ptr); |
79 } pdump_root_block_ptr_dynarr; | |
452 | 80 |
458 | 81 typedef struct |
82 { | |
2551 | 83 const void *object; |
84 void *data; | |
85 Bytecount size; | |
86 EMACS_INT offset; | |
87 EMACS_INT dest_offset; | |
88 EMACS_INT save_offset; | |
89 const struct opaque_convert_functions *fcts; | |
90 } pdump_cv_data_info; | |
91 | |
92 typedef struct | |
93 { | |
94 Dynarr_declare (pdump_cv_data_info); | |
95 } pdump_cv_data_info_dynarr; | |
96 | |
97 typedef struct | |
98 { | |
99 EMACS_INT dest_offset; | |
100 EMACS_INT save_offset; | |
101 Bytecount size; | |
102 } pdump_cv_data_dump_info; | |
103 | |
104 typedef struct | |
105 { | |
106 const void *object; | |
107 void *data; | |
108 Bytecount size; | |
109 EMACS_INT index; | |
110 EMACS_INT save_offset; | |
111 const struct opaque_convert_functions *fcts; | |
112 } pdump_cv_ptr_info; | |
113 | |
114 typedef struct | |
115 { | |
116 Dynarr_declare (pdump_cv_ptr_info); | |
117 } pdump_cv_ptr_info_dynarr; | |
118 | |
119 typedef struct | |
120 { | |
121 EMACS_INT save_offset; | |
122 Bytecount size; | |
123 } pdump_cv_ptr_dump_info; | |
124 | |
125 typedef struct | |
126 { | |
127 EMACS_INT save_offset; | |
128 Bytecount size; | |
129 void *adr; | |
130 } pdump_cv_ptr_load_info; | |
131 | |
132 typedef struct | |
133 { | |
458 | 134 Lisp_Object *address; |
135 Lisp_Object value; | |
136 } pdump_static_Lisp_Object; | |
137 | |
138 typedef struct | |
139 { | |
2367 | 140 Rawbyte **address; /* Rawbyte * for ease of doing relocation */ |
141 Rawbyte * value; | |
458 | 142 } pdump_static_pointer; |
143 | |
1204 | 144 static pdump_root_block_dynarr *pdump_root_blocks; |
2367 | 145 static pdump_root_block_ptr_dynarr *pdump_root_block_ptrs; |
1204 | 146 static Lisp_Object_ptr_dynarr *pdump_root_lisp_objects; |
452 | 147 static Lisp_Object_ptr_dynarr *pdump_weak_object_chains; |
2551 | 148 static pdump_cv_data_info_dynarr *pdump_cv_data; |
149 static pdump_cv_ptr_info_dynarr *pdump_cv_ptr; | |
452 | 150 |
2367 | 151 /* Mark SIZE bytes at non-heap address BLOCKADDR for dumping, described |
152 by DESC. Called by outside callers during XEmacs initialization. */ | |
153 | |
452 | 154 void |
2367 | 155 dump_add_root_block (const void *blockaddr, Bytecount size, |
1204 | 156 const struct memory_description *desc) |
452 | 157 { |
1204 | 158 pdump_root_block info; |
2367 | 159 info.blockaddr = blockaddr; |
452 | 160 info.size = size; |
1204 | 161 info.desc = desc; |
162 if (pdump_root_blocks == NULL) | |
163 pdump_root_blocks = Dynarr_new (pdump_root_block); | |
164 Dynarr_add (pdump_root_blocks, info); | |
452 | 165 } |
166 | |
2367 | 167 /* Mark the block described by DESC and pointed to by the pointer at |
168 non-heap address PTRADDRESS for dumping. | |
169 All the objects reachable from this pointer will also be dumped. | |
170 Called by outside callers during XEmacs initialization. */ | |
452 | 171 void |
2367 | 172 dump_add_root_block_ptr (void *ptraddress, |
173 const struct sized_memory_description *desc) | |
452 | 174 { |
2367 | 175 pdump_root_block_ptr info; |
452 | 176 info.ptraddress = (void **) ptraddress; |
177 info.desc = desc; | |
2367 | 178 if (pdump_root_block_ptrs == NULL) |
179 pdump_root_block_ptrs = Dynarr_new (pdump_root_block_ptr); | |
180 Dynarr_add (pdump_root_block_ptrs, info); | |
452 | 181 } |
182 | |
183 /* Mark the Lisp_Object at non-heap address VARADDRESS for dumping. | |
2367 | 184 All the objects reachable from this var will also be dumped. |
185 Called by outside callers during XEmacs initialization. */ | |
452 | 186 void |
1204 | 187 dump_add_root_lisp_object (Lisp_Object *varaddress) |
452 | 188 { |
1204 | 189 if (pdump_root_lisp_objects == NULL) |
190 pdump_root_lisp_objects = Dynarr_new2 (Lisp_Object_ptr_dynarr, Lisp_Object *); | |
191 Dynarr_add (pdump_root_lisp_objects, varaddress); | |
452 | 192 } |
193 | |
2367 | 194 /* Mark the list pointed to by the Lisp_Object at VARADDRESS for dumping. |
195 Called by outside callers during XEmacs initialization. */ | |
452 | 196 void |
197 dump_add_weak_object_chain (Lisp_Object *varaddress) | |
198 { | |
199 if (pdump_weak_object_chains == NULL) | |
200 pdump_weak_object_chains = Dynarr_new2 (Lisp_Object_ptr_dynarr, Lisp_Object *); | |
201 Dynarr_add (pdump_weak_object_chains, varaddress); | |
202 } | |
203 | |
204 | |
458 | 205 inline static void |
665 | 206 pdump_align_stream (FILE *stream, Bytecount alignment) |
458 | 207 { |
208 long offset = ftell (stream); | |
209 long adjustment = ALIGN_SIZE (offset, alignment) - offset; | |
210 if (adjustment) | |
211 fseek (stream, adjustment, SEEK_CUR); | |
212 } | |
213 | |
214 #define PDUMP_ALIGN_OUTPUT(type) pdump_align_stream (pdump_out, ALIGNOF (type)) | |
215 | |
216 #define PDUMP_WRITE(type, object) \ | |
771 | 217 retry_fwrite (&object, sizeof (object), 1, pdump_out); |
458 | 218 |
219 #define PDUMP_WRITE_ALIGNED(type, object) do { \ | |
220 PDUMP_ALIGN_OUTPUT (type); \ | |
221 PDUMP_WRITE (type, object); \ | |
222 } while (0) | |
223 | |
224 #define PDUMP_READ(ptr, type) \ | |
2367 | 225 (((type *) (ptr = (Rawbyte *) (((type *) ptr) + 1)))[-1]) |
458 | 226 |
227 #define PDUMP_READ_ALIGNED(ptr, type) \ | |
2367 | 228 ((ptr = (Rawbyte *) ALIGN_PTR (ptr, type)), PDUMP_READ (ptr, type)) |
458 | 229 |
230 | |
231 | |
452 | 232 typedef struct |
233 { | |
1204 | 234 const struct memory_description *desc; |
442 | 235 int count; |
236 } pdump_reloc_table; | |
237 | |
2367 | 238 static Rawbyte *pdump_rt_list = 0; |
442 | 239 |
3263 | 240 #ifndef NEW_GC |
442 | 241 void |
242 pdump_objects_unmark (void) | |
243 { | |
244 int i; | |
2367 | 245 Rawbyte *p = pdump_rt_list; |
442 | 246 if (p) |
247 for (;;) | |
248 { | |
249 pdump_reloc_table *rt = (pdump_reloc_table *)p; | |
250 p += sizeof (pdump_reloc_table); | |
251 if (rt->desc) | |
252 { | |
253 for (i=0; i<rt->count; i++) | |
254 { | |
255 struct lrecord_header *lh = * (struct lrecord_header **) p; | |
256 if (! C_READONLY_RECORD_HEADER_P (lh)) | |
257 UNMARK_RECORD_HEADER (lh); | |
258 p += sizeof (EMACS_INT); | |
259 } | |
260 } else | |
261 break; | |
262 } | |
263 } | |
3263 | 264 #endif /* not NEW_GC */ |
265 | |
266 | |
267 #ifdef NEW_GC | |
2720 | 268 /* The structure of the dump file looks like this: |
269 0 - header | |
270 - dumped objects | |
271 stab_offset - mc allocation table (count, size, address) for individual | |
272 allocation and relocation at load time. | |
273 - nb_cv_data*struct(dest, adr) for in-object externally | |
274 represented data | |
275 - nb_cv_ptr*(adr) for pointed-to externally represented data | |
276 - relocation table | |
277 - nb_root_struct_ptrs*struct(void *, adr) | |
278 for global pointers to structures | |
279 - nb_root_blocks*struct(void *, size, info) for global | |
280 objects to restore | |
281 - root lisp object address/value couples with the count | |
282 preceding the list | |
283 */ | |
3263 | 284 #else /* not NEW_GC */ |
1204 | 285 /* The structure of the dump file looks like this: |
458 | 286 0 - header |
287 - dumped objects | |
2551 | 288 stab_offset - nb_cv_data*struct(dest, adr) for in-object externally |
289 represented data | |
290 - nb_cv_ptr*(adr) for pointed-to externally represented data | |
291 - nb_root_block_ptrs*struct(void *, adr) | |
2367 | 292 for global pointers to heap blocks |
1204 | 293 - nb_root_blocks*struct(void *, size, info) for global |
2367 | 294 data-segment blocks to restore |
458 | 295 - relocation table |
296 - root lisp object address/value couples with the count | |
297 preceding the list | |
442 | 298 */ |
3263 | 299 #endif /* not NEW_GC */ |
442 | 300 |
301 | |
452 | 302 #define PDUMP_SIGNATURE "XEmacsDP" |
303 #define PDUMP_SIGNATURE_LEN (sizeof (PDUMP_SIGNATURE) - 1) | |
442 | 304 |
305 typedef struct | |
306 { | |
452 | 307 char signature[PDUMP_SIGNATURE_LEN]; |
442 | 308 unsigned int id; |
309 EMACS_UINT stab_offset; | |
310 EMACS_UINT reloc_address; | |
2367 | 311 int nb_root_block_ptrs; |
1204 | 312 int nb_root_blocks; |
2551 | 313 int nb_cv_data; |
314 int nb_cv_ptr; | |
452 | 315 } pdump_header; |
442 | 316 |
2367 | 317 Rawbyte *pdump_start; |
318 Rawbyte *pdump_end; | |
665 | 319 static Bytecount pdump_length; |
442 | 320 |
2551 | 321 static pdump_cv_data_dump_info *pdump_loaded_cv_data; |
322 static pdump_cv_ptr_load_info *pdump_loaded_cv_ptr; | |
323 | |
442 | 324 #ifdef WIN32_NATIVE |
452 | 325 /* Handle for the dump file */ |
458 | 326 static HANDLE pdump_hFile = INVALID_HANDLE_VALUE; |
452 | 327 /* Handle for the file mapping object for the dump file */ |
458 | 328 static HANDLE pdump_hMap = INVALID_HANDLE_VALUE; |
442 | 329 #endif |
330 | |
458 | 331 static void (*pdump_free) (void); |
442 | 332 |
460 | 333 static unsigned char pdump_align_table[] = |
442 | 334 { |
460 | 335 64, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, |
336 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, | |
337 32, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, | |
338 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1 | |
442 | 339 }; |
340 | |
647 | 341 static inline int |
665 | 342 pdump_size_to_align (Bytecount size) |
442 | 343 { |
460 | 344 return pdump_align_table[size % countof (pdump_align_table)]; |
345 } | |
346 | |
2367 | 347 /************************************************************************/ |
348 /* Registering memory blocks */ | |
349 /************************************************************************/ | |
350 | |
351 /* "Registering" or recording a heap memory block (which will need to be | |
352 written out, reloaded and relocated, and to which there may be pointers | |
353 from other heap blocks or from the data segment) happens both in a list | |
354 and in a hash table. There is a single hash table covering all | |
355 registered blocks, but different lists for different kinds of blocks. | |
356 There is one list for "opaque data" (stuff identified as | |
357 XD_OPAQUE_DATA_PTR, XD_ASCII_STRING, XD_DOC_STRING), one list for each | |
358 type of Lisp object, and one list for each different memory descriptor. | |
359 This lets similar-sized and aligned objects be grouped together when | |
360 they are written out, to save space. | |
361 | |
362 pdump_block_list is a list keeping track of registered memory blocks. | |
363 pdump_block_list_elt is a single entry through the list, and the list is | |
364 threaded through the NEXT pointer. The information in this list | |
365 associated with a particular block of memory is | |
366 | |
367 -- address of the beginning | |
368 -- number of elements at that address | |
369 -- size of each element | |
370 -- offset to this block in the dumped data | |
371 | |
372 pdump_desc_list is a list keeping track of the various descriptions | |
373 that we've seen. The primary purpose of this is so that memory blocks | |
374 can be grouped depending on the particular memory description | |
375 appropriate for them. The format of the list is different from | |
376 pdump_block_list -- a single array is used. (#### Dynarr should have | |
377 been used!!!). The information in this list associated with a | |
378 description is | |
379 | |
380 -- pointer to the description | |
381 -- a pdump_block_list of blocks using that description | |
382 | |
383 Functions for working with lists of memory blocks: | |
384 | |
385 -- Add a memory block to a list using pdump_add_block() | |
386 | |
387 -- Get a memory block from a pointer to its beginning using | |
388 pdump_get_block(). This uses the hash table, which lists everything. | |
389 | |
390 -- Return the memory-block list (pdump_block_list) associated with a | |
391 descriptor, using pdump_get_block_list(). If no entry found in the | |
392 pdump_desc_list, add a new one. | |
393 | |
394 */ | |
395 | |
396 typedef struct pdump_block_list_elt | |
460 | 397 { |
2367 | 398 struct pdump_block_list_elt *next; |
442 | 399 const void *obj; |
665 | 400 Bytecount size; |
442 | 401 int count; |
402 EMACS_INT save_offset; | |
2367 | 403 } pdump_block_list_elt; |
442 | 404 |
405 typedef struct | |
406 { | |
2367 | 407 pdump_block_list_elt *first; |
442 | 408 int align; |
409 int count; | |
2367 | 410 } pdump_block_list; |
442 | 411 |
2367 | 412 typedef struct pdump_desc_list_elt |
442 | 413 { |
2367 | 414 pdump_block_list list; |
1204 | 415 const struct memory_description *desc; |
2367 | 416 } pdump_desc_list_elt; |
442 | 417 |
418 typedef struct | |
419 { | |
2367 | 420 pdump_desc_list_elt *list; |
442 | 421 int count; |
422 int size; | |
2367 | 423 } pdump_desc_list; |
442 | 424 |
2367 | 425 static pdump_block_list *pdump_object_table; |
426 static pdump_block_list pdump_opaque_data_list; | |
427 static pdump_desc_list pdump_desc_table; | |
442 | 428 |
460 | 429 static int *pdump_alert_undump_object; |
442 | 430 |
431 static unsigned long cur_offset; | |
665 | 432 static Bytecount max_size; |
442 | 433 static int pdump_fd; |
434 static void *pdump_buf; | |
458 | 435 static FILE *pdump_out; |
442 | 436 |
3263 | 437 #ifdef NEW_GC |
2775 | 438 /* PDUMP_HASHSIZE is a large prime. */ |
439 #define PDUMP_HASHSIZE 1000003 | |
440 /* Nothing special about PDUMP_HASH_MULTIPLIER: arbitrary odd integer | |
441 smaller than PDUMP_HASHSIZE. */ | |
442 #define PDUMP_HASH_MULTIPLIER 12347 | |
443 /* Nothing special about PDUMP_HASH_STEP: arbitrary integer for linear | |
444 probing. */ | |
445 #define PDUMP_HASH_STEP 574853 | |
3263 | 446 #else /* not NEW_GC */ |
442 | 447 #define PDUMP_HASHSIZE 200001 |
3263 | 448 #endif /* not NEW_GC */ |
442 | 449 |
2367 | 450 static pdump_block_list_elt **pdump_hash; |
442 | 451 |
3263 | 452 #ifndef NEW_GC |
442 | 453 /* Since most pointers are eight bytes aligned, the >>3 allows for a better hash */ |
3263 | 454 #endif /* not NEW_GC */ |
442 | 455 static int |
456 pdump_make_hash (const void *obj) | |
457 { | |
3263 | 458 #ifdef NEW_GC |
2775 | 459 return ((unsigned long)(obj) * PDUMP_HASH_MULTIPLIER) % PDUMP_HASHSIZE; |
3263 | 460 #else /* not NEW_GC */ |
442 | 461 return ((unsigned long)(obj)>>3) % PDUMP_HASHSIZE; |
3263 | 462 #endif /* not NEW_GC */ |
442 | 463 } |
464 | |
2367 | 465 /* Return the entry for an already-registered memory block at OBJ, |
466 or NULL if none. */ | |
467 | |
468 static pdump_block_list_elt * | |
469 pdump_get_block (const void *obj) | |
442 | 470 { |
471 int pos = pdump_make_hash (obj); | |
2367 | 472 pdump_block_list_elt *e; |
442 | 473 |
474 assert (obj != 0); | |
475 | |
476 while ((e = pdump_hash[pos]) != 0) | |
477 { | |
478 if (e->obj == obj) | |
479 return e; | |
480 | |
481 pos++; | |
482 if (pos == PDUMP_HASHSIZE) | |
483 pos = 0; | |
484 } | |
485 return 0; | |
486 } | |
487 | |
2367 | 488 /* Register a new memory block on Return the entry for an already-registered heap (?) memory block at OBJ, |
489 or NULL if none. */ | |
490 | |
442 | 491 static void |
2367 | 492 pdump_add_block (pdump_block_list *list, const void *obj, Bytecount size, |
458 | 493 int count) |
442 | 494 { |
2367 | 495 pdump_block_list_elt *e; |
442 | 496 int pos = pdump_make_hash (obj); |
497 | |
498 while ((e = pdump_hash[pos]) != 0) | |
499 { | |
500 if (e->obj == obj) | |
501 return; | |
502 | |
503 pos++; | |
504 if (pos == PDUMP_HASHSIZE) | |
505 pos = 0; | |
506 } | |
507 | |
2367 | 508 e = xnew (pdump_block_list_elt); |
442 | 509 |
510 e->next = list->first; | |
511 e->obj = obj; | |
512 e->size = size; | |
513 e->count = count; | |
514 list->first = e; | |
515 | |
516 list->count += count; | |
517 pdump_hash[pos] = e; | |
518 | |
460 | 519 { |
520 int align = pdump_size_to_align (size); | |
442 | 521 |
460 | 522 if (align < list->align) |
523 list->align = align; | |
524 } | |
442 | 525 } |
526 | |
3263 | 527 #ifdef NEW_GC |
2720 | 528 typedef struct mc_addr_elt |
529 { | |
530 const void *obj; | |
531 EMACS_INT addr; | |
532 } mc_addr_elt; | |
533 | |
534 static mc_addr_elt *pdump_mc_hash; | |
535 | |
536 /* Return the entry for an already-registered memory block at OBJ, | |
537 or NULL if none. */ | |
538 static EMACS_INT | |
539 pdump_get_mc_addr (const void *obj) | |
540 { | |
541 int pos = pdump_make_hash (obj); | |
542 mc_addr_elt *mc_addr; | |
543 | |
544 assert (obj != 0); | |
545 | |
2723 | 546 while (((mc_addr = &pdump_mc_hash[pos]) != 0) && (mc_addr->obj != 0)) |
2720 | 547 { |
548 if (mc_addr->obj == obj) | |
549 return mc_addr->addr; | |
550 | |
2775 | 551 pos += PDUMP_HASH_STEP; |
552 if (pos >= PDUMP_HASHSIZE) | |
553 pos -= PDUMP_HASHSIZE; | |
2720 | 554 } |
555 | |
556 /* If this code is reached, an heap address occurred which has not | |
557 been written to the lookup table before. | |
558 This is a bug! */ | |
559 ABORT(); | |
560 return 0; | |
561 } | |
562 | |
563 /* For indirect address lookups, needed for convertibles: Ptr points | |
564 to an address within an object. Indirect gives the offset by how | |
565 many bytes the address of the object has to be adjusted to do a | |
566 lookup in the mc_addr translation table and get the new location of | |
567 the data. */ | |
568 #define pdump_get_indirect_mc_addr(ptr, indirect) \ | |
569 pdump_get_mc_addr ((void *)((ptr) - indirect)) + indirect | |
570 | |
571 static void | |
572 pdump_put_mc_addr (const void *obj, EMACS_INT addr) | |
573 { | |
574 mc_addr_elt *mc_addr; | |
575 int pos = pdump_make_hash (obj); | |
576 | |
2723 | 577 while (((mc_addr = &pdump_mc_hash[pos]) != 0) && (mc_addr->obj != 0)) |
2720 | 578 { |
579 if (mc_addr->obj == obj) | |
580 return; | |
581 | |
2775 | 582 pos += PDUMP_HASH_STEP; |
583 if (pos >= PDUMP_HASHSIZE) | |
584 pos -= PDUMP_HASHSIZE; | |
2720 | 585 } |
586 | |
587 pdump_mc_hash[pos].obj = obj; | |
588 pdump_mc_hash[pos].addr = addr; | |
589 } | |
3263 | 590 #endif /* NEW_GC */ |
2720 | 591 |
2367 | 592 static pdump_block_list * |
593 pdump_get_block_list (const struct memory_description *desc) | |
442 | 594 { |
595 int i; | |
2367 | 596 for (i=0; i<pdump_desc_table.count; i++) |
597 if (pdump_desc_table.list[i].desc == desc) | |
598 return &pdump_desc_table.list[i].list; | |
442 | 599 |
2367 | 600 if (pdump_desc_table.size <= pdump_desc_table.count) |
442 | 601 { |
2367 | 602 if (pdump_desc_table.size == -1) |
603 pdump_desc_table.size = 10; | |
442 | 604 else |
2367 | 605 pdump_desc_table.size = pdump_desc_table.size * 2; |
606 pdump_desc_table.list = (pdump_desc_list_elt *) | |
607 xrealloc (pdump_desc_table.list, | |
608 pdump_desc_table.size * sizeof (pdump_desc_list_elt)); | |
442 | 609 } |
2367 | 610 pdump_desc_table.list[pdump_desc_table.count].list.first = 0; |
611 pdump_desc_table.list[pdump_desc_table.count].list.align = ALIGNOF (max_align_t); | |
612 pdump_desc_table.list[pdump_desc_table.count].list.count = 0; | |
613 pdump_desc_table.list[pdump_desc_table.count].desc = desc; | |
442 | 614 |
2367 | 615 return &pdump_desc_table.list[pdump_desc_table.count++].list; |
442 | 616 } |
617 | |
2551 | 618 static pdump_cv_ptr_info * |
619 pdump_find_in_cv_ptr_dynarr(const void *object) | |
620 { | |
621 int i; | |
622 for (i = 0; i < Dynarr_length (pdump_cv_ptr); i++) | |
623 if (Dynarr_at (pdump_cv_ptr, i).object == object) | |
624 return Dynarr_atp (pdump_cv_ptr, i); | |
625 return 0; | |
626 } | |
627 | |
2698 | 628 #define BACKTRACE_MAX 65536 |
629 | |
442 | 630 static struct |
631 { | |
632 struct lrecord_header *obj; | |
633 int position; | |
634 int offset; | |
2698 | 635 } backtrace[BACKTRACE_MAX]; |
442 | 636 |
1204 | 637 static int pdump_depth; |
442 | 638 |
1204 | 639 void |
452 | 640 pdump_backtrace (void) |
442 | 641 { |
642 int i; | |
643 stderr_out ("pdump backtrace :\n"); | |
1204 | 644 for (i = 0; i < pdump_depth; i++) |
442 | 645 { |
646 if (!backtrace[i].obj) | |
458 | 647 stderr_out (" - ind. (%d, %d)\n", |
648 backtrace[i].position, | |
649 backtrace[i].offset); | |
442 | 650 else |
651 { | |
652 stderr_out (" - %s (%d, %d)\n", | |
1204 | 653 LHEADER_IMPLEMENTATION (backtrace[i].obj)->name, |
654 backtrace[i].position, | |
655 backtrace[i].offset); | |
442 | 656 } |
657 } | |
658 } | |
659 | |
1204 | 660 static void |
1333 | 661 pdump_unsupported_dump_type (enum memory_description_type type, |
662 int do_backtrace) | |
663 { | |
664 stderr_out ("Unsupported dump type : %d\n", type); | |
665 #ifdef WIN32_NATIVE | |
666 stderr_out ("Are you compiling with SUPPORT_EDIT_AND_CONTINUE?\n"); | |
667 stderr_out ("See the PROBLEMS file.\n"); | |
668 #endif | |
669 if (do_backtrace) | |
670 pdump_backtrace (); | |
2500 | 671 ABORT (); |
1333 | 672 } |
673 | |
674 static void | |
1204 | 675 pdump_bump_depth (void) |
676 { | |
677 int me = pdump_depth++; | |
2698 | 678 if (me >= BACKTRACE_MAX) |
1204 | 679 { |
680 stderr_out ("Backtrace overflow, loop ?\n"); | |
2500 | 681 ABORT (); |
1204 | 682 } |
683 backtrace[me].obj = 0; | |
684 backtrace[me].position = 0; | |
685 backtrace[me].offset = 0; | |
686 } | |
687 | |
442 | 688 static void pdump_register_object (Lisp_Object obj); |
3092 | 689 #ifdef NEW_GC |
690 static void pdump_register_object_array (Lisp_Object data, | |
691 Bytecount size, | |
692 const struct memory_description *desc, | |
693 int count); | |
694 #endif /* NEW_GC */ | |
2367 | 695 static void pdump_register_block_contents (const void *data, |
696 Bytecount size, | |
697 const struct memory_description * | |
698 desc, | |
699 int count); | |
700 static void pdump_register_block (const void *data, | |
701 Bytecount size, | |
702 const struct memory_description *desc, | |
703 int count); | |
442 | 704 |
705 static void | |
1204 | 706 pdump_register_sub (const void *data, const struct memory_description *desc) |
442 | 707 { |
708 int pos; | |
1204 | 709 int me = pdump_depth - 1; |
442 | 710 |
711 for (pos = 0; desc[pos].type != XD_END; pos++) | |
712 { | |
1204 | 713 const struct memory_description *desc1 = &desc[pos]; |
714 EMACS_INT offset = lispdesc_indirect_count (desc1->offset, desc, | |
715 data); | |
2367 | 716 const void *rdata = (const Rawbyte *) data + offset; |
442 | 717 |
718 backtrace[me].position = pos; | |
1204 | 719 backtrace[me].offset = offset; |
720 | |
721 union_switcheroo: | |
442 | 722 |
1204 | 723 /* If the flag says don't dump, then don't dump. */ |
724 if ((desc1->flags) & XD_FLAG_NO_PDUMP) | |
725 continue; | |
726 | |
727 switch (desc1->type) | |
442 | 728 { |
665 | 729 case XD_BYTECOUNT: |
730 case XD_ELEMCOUNT: | |
731 case XD_HASHCODE: | |
442 | 732 case XD_INT: |
733 case XD_LONG: | |
734 case XD_INT_RESET: | |
735 case XD_LO_LINK: | |
736 break; | |
737 case XD_OPAQUE_DATA_PTR: | |
738 { | |
1204 | 739 EMACS_INT count = lispdesc_indirect_count (desc1->data1, desc, |
740 data); | |
442 | 741 |
2367 | 742 pdump_add_block (&pdump_opaque_data_list, |
458 | 743 *(void **)rdata, count, 1); |
442 | 744 break; |
745 } | |
2367 | 746 case XD_ASCII_STRING: |
442 | 747 { |
2367 | 748 const Ascbyte *str = * (const Ascbyte **) rdata; |
442 | 749 if (str) |
2367 | 750 pdump_add_block (&pdump_opaque_data_list, str, strlen (str) + 1, |
1204 | 751 1); |
442 | 752 break; |
753 } | |
754 case XD_DOC_STRING: | |
755 { | |
2367 | 756 const Ascbyte *str = * (const Ascbyte **) rdata; |
1204 | 757 if ((EMACS_INT) str > 0) |
2367 | 758 pdump_add_block (&pdump_opaque_data_list, str, strlen (str) + 1, |
1204 | 759 1); |
442 | 760 break; |
761 } | |
762 case XD_LISP_OBJECT: | |
763 { | |
1204 | 764 const Lisp_Object *pobj = (const Lisp_Object *) rdata; |
442 | 765 |
1204 | 766 assert (desc1->data1 == 0); |
442 | 767 |
2367 | 768 backtrace[me].offset = |
769 (const Rawbyte *) pobj - (const Rawbyte *) data; | |
442 | 770 pdump_register_object (*pobj); |
771 break; | |
772 } | |
773 case XD_LISP_OBJECT_ARRAY: | |
774 { | |
775 int i; | |
1204 | 776 EMACS_INT count = lispdesc_indirect_count (desc1->data1, desc, |
777 data); | |
442 | 778 |
779 for (i = 0; i < count; i++) | |
780 { | |
1204 | 781 const Lisp_Object *pobj = ((const Lisp_Object *) rdata) + i; |
442 | 782 Lisp_Object dobj = *pobj; |
783 | |
1204 | 784 backtrace[me].offset = |
2367 | 785 (const Rawbyte *) pobj - (const Rawbyte *) data; |
442 | 786 pdump_register_object (dobj); |
787 } | |
788 break; | |
789 } | |
3092 | 790 #ifdef NEW_GC |
791 case XD_LISP_OBJECT_BLOCK_PTR: | |
792 { | |
793 EMACS_INT count = lispdesc_indirect_count (desc1->data1, desc, | |
794 data); | |
795 const struct sized_memory_description *sdesc = | |
796 lispdesc_indirect_description (data, desc1->data2.descr); | |
797 const Lisp_Object *pobj = (const Lisp_Object *) rdata; | |
798 if (pobj) | |
799 pdump_register_object_array | |
800 (*pobj, sdesc->size, sdesc->description, count); | |
801 break; | |
802 } | |
803 #endif /* NEW_GC */ | |
2367 | 804 case XD_BLOCK_PTR: |
442 | 805 { |
1204 | 806 EMACS_INT count = lispdesc_indirect_count (desc1->data1, desc, |
807 data); | |
808 const struct sized_memory_description *sdesc = | |
2551 | 809 lispdesc_indirect_description (data, desc1->data2.descr); |
2367 | 810 const Rawbyte *dobj = *(const Rawbyte **)rdata; |
442 | 811 if (dobj) |
2367 | 812 pdump_register_block (dobj, sdesc->size, sdesc->description, |
813 count); | |
442 | 814 break; |
815 } | |
2367 | 816 case XD_BLOCK_ARRAY: |
771 | 817 { |
1204 | 818 EMACS_INT count = lispdesc_indirect_count (desc1->data1, desc, |
819 data); | |
820 const struct sized_memory_description *sdesc = | |
2551 | 821 lispdesc_indirect_description (data, desc1->data2.descr); |
771 | 822 |
2367 | 823 pdump_register_block_contents (rdata, sdesc->size, |
824 sdesc->description, count); | |
771 | 825 break; |
826 } | |
827 case XD_UNION: | |
1204 | 828 case XD_UNION_DYNAMIC_SIZE: |
829 desc1 = lispdesc_process_xd_union (desc1, desc, data); | |
830 if (desc1) | |
831 goto union_switcheroo; | |
832 break; | |
2551 | 833 case XD_OPAQUE_PTR_CONVERTIBLE: |
834 { | |
835 pdump_cv_ptr_info info; | |
836 info.object = *(void **)rdata; | |
837 info.fcts = desc1->data2.funcs; | |
838 if (!pdump_find_in_cv_ptr_dynarr (info.object)) | |
839 { | |
840 info.fcts->convert(info.object, &info.data, &info.size); | |
841 Dynarr_add (pdump_cv_ptr, info); | |
842 } | |
843 break; | |
844 } | |
845 case XD_OPAQUE_DATA_CONVERTIBLE: | |
846 { | |
847 pdump_cv_data_info info; | |
848 info.object = data; | |
849 info.offset = offset; | |
850 info.fcts = desc1->data2.funcs; | |
851 | |
852 info.fcts->convert(rdata, &info.data, &info.size); | |
853 Dynarr_add (pdump_cv_data, info); | |
854 break; | |
855 } | |
771 | 856 |
442 | 857 default: |
1333 | 858 pdump_unsupported_dump_type (desc1->type, 1); |
1204 | 859 } |
442 | 860 } |
861 } | |
862 | |
863 static void | |
864 pdump_register_object (Lisp_Object obj) | |
865 { | |
866 struct lrecord_header *objh; | |
458 | 867 const struct lrecord_implementation *imp; |
442 | 868 |
869 if (!POINTER_TYPE_P (XTYPE (obj))) | |
870 return; | |
871 | |
872 objh = XRECORD_LHEADER (obj); | |
873 if (!objh) | |
874 return; | |
875 | |
2367 | 876 if (pdump_get_block (objh)) |
442 | 877 return; |
878 | |
458 | 879 imp = LHEADER_IMPLEMENTATION (objh); |
880 | |
934 | 881 if (imp->description |
3263 | 882 #ifdef NEW_GC |
883 /* Objects with finalizers cannot be dumped with the new | |
884 allocator's asynchronous finalization strategy. */ | |
885 && !imp->finalizer | |
886 #endif /* not NEW_GC */ | |
1204 | 887 && RECORD_DUMPABLE (objh)) |
442 | 888 { |
1204 | 889 pdump_bump_depth (); |
890 backtrace[pdump_depth - 1].obj = objh; | |
2367 | 891 pdump_add_block (pdump_object_table + objh->type, |
1204 | 892 objh, detagged_lisp_object_size (objh), 1); |
893 pdump_register_sub (objh, imp->description); | |
894 --pdump_depth; | |
442 | 895 } |
896 else | |
897 { | |
898 pdump_alert_undump_object[objh->type]++; | |
458 | 899 stderr_out ("Undumpable object type : %s\n", imp->name); |
442 | 900 pdump_backtrace (); |
901 } | |
902 } | |
903 | |
3092 | 904 #ifdef NEW_GC |
905 static void | |
906 pdump_register_object_array (Lisp_Object obj, | |
907 Bytecount size, | |
908 const struct memory_description *desc, | |
909 int count) | |
910 { | |
911 struct lrecord_header *objh; | |
912 const struct lrecord_implementation *imp; | |
913 | |
914 if (!POINTER_TYPE_P (XTYPE (obj))) | |
915 return; | |
916 | |
917 objh = XRECORD_LHEADER (obj); | |
918 if (!objh) | |
919 return; | |
920 | |
921 if (pdump_get_block (objh)) | |
922 return; | |
923 | |
924 imp = LHEADER_IMPLEMENTATION (objh); | |
925 | |
926 if (imp->description | |
927 && RECORD_DUMPABLE (objh)) | |
928 { | |
929 pdump_bump_depth (); | |
930 backtrace[pdump_depth - 1].obj = objh; | |
931 pdump_add_block (pdump_object_table + objh->type, | |
932 objh, lispdesc_block_size_1 (objh, size, desc), count); | |
933 pdump_register_block_contents (objh, size, desc, count); | |
934 --pdump_depth; | |
935 } | |
936 else | |
937 { | |
938 pdump_alert_undump_object[objh->type]++; | |
939 stderr_out ("Undumpable object type : %s\n", imp->name); | |
940 pdump_backtrace (); | |
941 } | |
942 } | |
943 #endif /* NEW_GC */ | |
944 | |
2367 | 945 /* Register the referenced objects in the array of COUNT blocks located at |
946 DATA; each block is described by SIZE and DESC. "Block" here simply | |
947 means any block of memory. | |
771 | 948 |
949 This does not register the block of memory itself; it may, for | |
950 example, be an array of structures inlined in another memory block | |
2367 | 951 and thus should not be registered. See pdump_register_block(), |
771 | 952 which does register the memory block. */ |
953 | |
954 static void | |
2367 | 955 pdump_register_block_contents (const void *data, |
956 Bytecount size, | |
957 const struct memory_description *desc, | |
958 int count) | |
771 | 959 { |
960 int i; | |
961 Bytecount elsize; | |
962 | |
1204 | 963 pdump_bump_depth (); |
2367 | 964 elsize = lispdesc_block_size_1 (data, size, desc); |
771 | 965 for (i = 0; i < count; i++) |
966 { | |
2367 | 967 pdump_register_sub (((Rawbyte *) data) + elsize * i, desc); |
771 | 968 } |
1204 | 969 --pdump_depth; |
771 | 970 } |
971 | |
2367 | 972 /* Register the array of COUNT blocks located at DATA; each block is |
973 described by SDESC. "Block" here simply means any block of memory, | |
974 which is more accurate and less confusing than terms like `struct' and | |
975 `object'. A `block' need not actually be a C "struct". It could be a | |
976 single integer or Lisp_Object, for example, as long as the description | |
977 is accurate. | |
771 | 978 |
2367 | 979 This is like pdump_register_block_contents() but also registers |
771 | 980 the memory block itself. */ |
981 | |
442 | 982 static void |
2367 | 983 pdump_register_block (const void *data, |
984 Bytecount size, | |
985 const struct memory_description *desc, | |
986 int count) | |
442 | 987 { |
2367 | 988 if (data && !pdump_get_block (data)) |
442 | 989 { |
2367 | 990 pdump_add_block (pdump_get_block_list (desc), data, |
991 lispdesc_block_size_1 (data, size, desc), count); | |
992 pdump_register_block_contents (data, size, desc, count); | |
442 | 993 } |
994 } | |
995 | |
2551 | 996 |
1204 | 997 /* Store the already-calculated new pointer offsets for all pointers in the |
998 COUNT contiguous blocks of memory, each described by DESC and of size | |
999 SIZE, whose original is located at ORIG_DATA and the modifiable copy at | |
1000 DATA. We examine the description to figure out where the pointers are, | |
2367 | 1001 and then look up the replacement values using pdump_get_block(). |
771 | 1002 |
1204 | 1003 This is done just before writing the modified block of memory to the |
1004 dump file. The new pointer offsets have been carefully calculated so | |
1005 that the data being pointed gets written at that offset in the dump | |
1006 file. That way, the dump file is a correct memory image except perhaps | |
1007 for a constant that needs to be added to all pointers. (#### In fact, we | |
1008 SHOULD be starting up a dumped XEmacs, seeing where the dumped file gets | |
1009 loaded into memory, and then rewriting the dumped file after relocating | |
1010 all the pointers relative to this memory location. That way, if the | |
1011 file gets loaded again at the same location, which will be common, we | |
1012 don't have to do any relocating, which is both faster at startup and | |
771 | 1013 allows the read-only part of the dumped data to be shared read-only |
1014 between different invocations of XEmacs.) | |
1015 | |
1016 #### Do we distinguish between read-only and writable dumped data? | |
1017 Should we? It's tricky because the dumped data, once loaded again, | |
1204 | 1018 cannot really be free()d or garbage collected since it's all stored in |
1019 one contiguous block of data with no malloc() headers, and we don't keep | |
1020 track of the pointers used internally in malloc() and the Lisp allocator | |
1021 to track allocated blocks of memory. */ | |
771 | 1022 |
1023 static void | |
1024 pdump_store_new_pointer_offsets (int count, void *data, const void *orig_data, | |
1204 | 1025 const struct memory_description *desc, |
771 | 1026 int size) |
1027 { | |
1028 int pos, i; | |
1029 /* Process each block one by one */ | |
1030 for (i = 0; i < count; i++) | |
1031 { | |
1032 /* CUR points to the beginning of each block in the new data. */ | |
2367 | 1033 Rawbyte *cur = ((Rawbyte *)data) + i * size; |
771 | 1034 /* Scan each line of the description for relocatable pointers */ |
1035 for (pos = 0; desc[pos].type != XD_END; pos++) | |
1036 { | |
1037 /* RDATA points to the beginning of each element in the new data. */ | |
1204 | 1038 const struct memory_description *desc1 = &desc[pos]; |
1039 /* #### Change ORIG_DATA to DATA. See below. */ | |
1040 void *rdata = cur + lispdesc_indirect_count (desc1->offset, desc, | |
1041 orig_data); | |
1042 union_switcheroo: | |
1043 | |
1044 /* If the flag says don't dump, then don't dump. */ | |
1045 if ((desc1->flags) & XD_FLAG_NO_PDUMP) | |
1046 continue; | |
1047 | |
1048 switch (desc1->type) | |
771 | 1049 { |
1050 case XD_BYTECOUNT: | |
1051 case XD_ELEMCOUNT: | |
1052 case XD_HASHCODE: | |
1053 case XD_INT: | |
1054 case XD_LONG: | |
1055 break; | |
1056 case XD_INT_RESET: | |
1057 { | |
1204 | 1058 EMACS_INT val = lispdesc_indirect_count (desc1->data1, desc, |
1059 orig_data); | |
771 | 1060 * (int *) rdata = val; |
1061 break; | |
1062 } | |
3092 | 1063 #ifdef NEW_GC |
1064 case XD_LISP_OBJECT_BLOCK_PTR: | |
1065 #endif /* NEW_GC */ | |
771 | 1066 case XD_OPAQUE_DATA_PTR: |
2367 | 1067 case XD_ASCII_STRING: |
1068 case XD_BLOCK_PTR: | |
771 | 1069 { |
1070 void *ptr = * (void **) rdata; | |
1071 if (ptr) | |
2367 | 1072 * (EMACS_INT *) rdata = pdump_get_block (ptr)->save_offset; |
771 | 1073 break; |
1074 } | |
1075 case XD_LO_LINK: | |
1076 { | |
1077 /* As described in lrecord.h, this is a weak link. | |
1078 Thus, we need to link this object not (necessarily) | |
1079 to the object directly pointed to, but to the next | |
1080 referenced object in the chain. None of the | |
1081 intermediate objects will be written out, so we | |
1082 traverse down the chain of objects until we find a | |
1083 referenced one. (The Qnil or Qunbound that ends the | |
1084 chain will always be a referenced object.) */ | |
1085 Lisp_Object obj = * (Lisp_Object *) rdata; | |
2367 | 1086 pdump_block_list_elt *elt1; |
1204 | 1087 /* #### Figure out how to handle indirect offsets here. |
1088 #### In general, when computing indirect counts, do we | |
1089 really need to use the orig_data pointer? Why not just | |
1090 use the new stuff? | |
1091 | |
1092 No, we don't usually need orig_data. We only need it | |
1093 when fetching pointers out of the data, not integers. | |
1094 This currently occurs only with description maps. We | |
1095 should change the other places to DATA to emphasize | |
1096 this. */ | |
1097 assert (!XD_IS_INDIRECT (desc1->offset)); | |
771 | 1098 for (;;) |
1099 { | |
2367 | 1100 elt1 = pdump_get_block (XRECORD_LHEADER (obj)); |
771 | 1101 if (elt1) |
1102 break; | |
1204 | 1103 obj = * (Lisp_Object *) (desc1->offset + |
2367 | 1104 (Rawbyte *) |
1105 (XRECORD_LHEADER (obj))); | |
771 | 1106 } |
1107 * (EMACS_INT *) rdata = elt1->save_offset; | |
1108 break; | |
1109 } | |
1110 case XD_LISP_OBJECT: | |
1111 { | |
1112 Lisp_Object *pobj = (Lisp_Object *) rdata; | |
1113 | |
1204 | 1114 assert (desc1->data1 == 0); |
771 | 1115 |
1116 if (POINTER_TYPE_P (XTYPE (*pobj)) && XRECORD_LHEADER (*pobj)) | |
1117 * (EMACS_INT *) pobj = | |
2367 | 1118 pdump_get_block (XRECORD_LHEADER (*pobj))->save_offset; |
771 | 1119 break; |
1120 } | |
1121 case XD_LISP_OBJECT_ARRAY: | |
1122 { | |
1204 | 1123 EMACS_INT num = lispdesc_indirect_count (desc1->data1, desc, |
1124 orig_data); | |
771 | 1125 int j; |
1126 | |
1127 for (j = 0; j < num; j++) | |
1128 { | |
1129 Lisp_Object *pobj = ((Lisp_Object *) rdata) + j; | |
1130 if (POINTER_TYPE_P (XTYPE (*pobj)) && | |
1131 XRECORD_LHEADER (*pobj)) | |
1132 * (EMACS_INT *) pobj = | |
2367 | 1133 pdump_get_block (XRECORD_LHEADER (*pobj))->save_offset; |
771 | 1134 } |
1135 break; | |
1136 } | |
1137 case XD_DOC_STRING: | |
1138 { | |
1139 EMACS_INT str = *(EMACS_INT *)rdata; | |
1140 if (str > 0) | |
1141 * (EMACS_INT *) rdata = | |
2367 | 1142 pdump_get_block ((void *)str)->save_offset; |
771 | 1143 break; |
1144 } | |
2367 | 1145 case XD_BLOCK_ARRAY: |
771 | 1146 { |
1204 | 1147 EMACS_INT num = lispdesc_indirect_count (desc1->data1, desc, |
1148 orig_data); | |
1149 const struct sized_memory_description *sdesc = | |
2551 | 1150 lispdesc_indirect_description (orig_data, desc1->data2.descr); |
771 | 1151 |
1152 pdump_store_new_pointer_offsets | |
1153 (num, rdata, | |
2367 | 1154 ((Rawbyte *) rdata - (Rawbyte *) data) + |
1155 (Rawbyte *) orig_data, | |
1204 | 1156 sdesc->description, |
2367 | 1157 lispdesc_block_size |
1158 (((Rawbyte *) rdata - (Rawbyte *) data) + | |
1159 (Rawbyte *) orig_data, sdesc)); | |
771 | 1160 break; |
1161 } | |
1162 case XD_UNION: | |
1204 | 1163 case XD_UNION_DYNAMIC_SIZE: |
1164 desc1 = lispdesc_process_xd_union (desc1, desc, orig_data); | |
1165 if (desc1) | |
1166 goto union_switcheroo; | |
1167 break; | |
771 | 1168 |
2551 | 1169 case XD_OPAQUE_PTR_CONVERTIBLE: |
1170 *(EMACS_INT *)rdata = pdump_find_in_cv_ptr_dynarr (*(void **)rdata)->index; | |
1171 break; | |
1172 | |
1173 case XD_OPAQUE_DATA_CONVERTIBLE: | |
1174 /* in-object, nothing to do */ | |
1175 break; | |
1176 | |
771 | 1177 default: |
1333 | 1178 pdump_unsupported_dump_type (desc1->type, 0); |
771 | 1179 } |
1180 } | |
1181 } | |
1182 } | |
1183 | |
1184 /* Write out to global file descriptor PDUMP_OUT the element (one or | |
1185 more contiguous blocks of identical size/description) recorded in | |
1186 ELT and described by DESC. The element is first copied to a buffer | |
1187 and then all pointers (this includes Lisp_Objects other than | |
1188 integer/character) are relocated to the (pre-computed) offset in | |
1189 the dump file. */ | |
1190 | |
442 | 1191 static void |
2367 | 1192 pdump_dump_data (pdump_block_list_elt *elt, |
1204 | 1193 const struct memory_description *desc) |
442 | 1194 { |
665 | 1195 Bytecount size = elt->size; |
460 | 1196 int count = elt->count; |
442 | 1197 if (desc) |
1198 { | |
771 | 1199 /* Copy to temporary buffer */ |
460 | 1200 memcpy (pdump_buf, elt->obj, size*count); |
442 | 1201 |
771 | 1202 /* Store new offsets into all pointers in block */ |
1203 pdump_store_new_pointer_offsets (count, pdump_buf, elt->obj, desc, size); | |
1204 } | |
1205 retry_fwrite (desc ? pdump_buf : elt->obj, size, count, pdump_out); | |
1206 } | |
442 | 1207 |
3263 | 1208 #ifdef NEW_GC |
2720 | 1209 /* To be able to relocate during load time, more information about the |
1210 dumped objects are needed: The count (for array-like data | |
1211 structures), the size of the object, and the location in the dumped | |
1212 data. | |
1213 */ | |
1214 static void | |
1215 pdump_dump_mc_data (pdump_block_list_elt *elt, | |
1216 const struct memory_description *UNUSED(desc)) | |
1217 { | |
1218 EMACS_INT rdata = pdump_get_block (elt->obj)->save_offset; | |
1219 int j; | |
1220 PDUMP_WRITE_ALIGNED (int, elt->count); | |
1221 PDUMP_WRITE_ALIGNED (Bytecount, elt->size); | |
1222 for (j = 0; j < elt->count; j++) | |
1223 { | |
1224 PDUMP_WRITE_ALIGNED (EMACS_INT, rdata); | |
1225 rdata += elt->size; | |
1226 } | |
1227 } | |
1228 | |
1229 static void | |
1230 pdump_scan_lisp_objects_by_alignment (void (*f) | |
1231 (pdump_block_list_elt *, | |
1232 const struct memory_description *)) | |
1233 { | |
1234 int align; | |
1235 | |
1236 for (align = ALIGNOF (max_align_t); align; align>>=1) | |
1237 { | |
1238 int i; | |
1239 pdump_block_list_elt *elt; | |
1240 | |
1241 for (i=0; i<lrecord_type_count; i++) | |
1242 if (pdump_object_table[i].align == align) | |
1243 for (elt = pdump_object_table[i].first; elt; elt = elt->next) | |
1244 { | |
1245 f (elt, lrecord_implementations_table[i]->description); | |
1246 } | |
1247 } | |
1248 } | |
1249 | |
1250 static void | |
1251 pdump_scan_non_lisp_objects_by_alignment (void (*f) | |
1252 (pdump_block_list_elt *, | |
1253 const struct memory_description *)) | |
1254 { | |
1255 int align; | |
1256 | |
1257 for (align = ALIGNOF (max_align_t); align; align>>=1) | |
1258 { | |
1259 int i; | |
1260 pdump_block_list_elt *elt; | |
1261 | |
1262 for (i=0; i<pdump_desc_table.count; i++) | |
1263 { | |
1264 pdump_desc_list_elt list = pdump_desc_table.list[i]; | |
1265 if (list.list.align == align) | |
1266 for (elt = list.list.first; elt; elt = elt->next) | |
1267 f (elt, list.desc); | |
1268 } | |
1269 | |
1270 for (elt = pdump_opaque_data_list.first; elt; elt = elt->next) | |
1271 if (pdump_size_to_align (elt->size) == align) | |
1272 f (elt, 0); | |
1273 } | |
1274 } | |
1275 | |
1276 | |
1277 | |
1278 static void | |
1279 pdump_reloc_one_mc (void *data, const struct memory_description *desc) | |
1280 { | |
1281 int pos; | |
1282 | |
1283 for (pos = 0; desc[pos].type != XD_END; pos++) | |
1284 { | |
1285 const struct memory_description *desc1 = &desc[pos]; | |
1286 void *rdata = | |
1287 (Rawbyte *) data + lispdesc_indirect_count (desc1->offset, | |
1288 desc, data); | |
1289 | |
1290 union_switcheroo: | |
1291 | |
1292 /* If the flag says don't dump, then don't dump. */ | |
1293 if ((desc1->flags) & XD_FLAG_NO_PDUMP) | |
1294 continue; | |
1295 | |
1296 switch (desc1->type) | |
1297 { | |
1298 case XD_BYTECOUNT: | |
1299 case XD_ELEMCOUNT: | |
1300 case XD_HASHCODE: | |
1301 case XD_INT: | |
1302 case XD_LONG: | |
1303 case XD_INT_RESET: | |
1304 break; | |
3092 | 1305 case XD_LISP_OBJECT_BLOCK_PTR: |
2720 | 1306 case XD_OPAQUE_DATA_PTR: |
1307 case XD_ASCII_STRING: | |
1308 case XD_BLOCK_PTR: | |
1309 case XD_LO_LINK: | |
1310 { | |
1311 EMACS_INT ptr = *(EMACS_INT *) rdata; | |
1312 if (ptr) | |
1313 *(EMACS_INT *) rdata = pdump_get_mc_addr ((void *) ptr); | |
1314 break; | |
1315 } | |
1316 case XD_LISP_OBJECT: | |
1317 { | |
1318 Lisp_Object *pobj = (Lisp_Object *) rdata; | |
1319 | |
1320 assert (desc1->data1 == 0); | |
1321 | |
1322 if (POINTER_TYPE_P (XTYPE (*pobj)) | |
1323 && ! EQ (*pobj, Qnull_pointer)) | |
3092 | 1324 *pobj = wrap_pointer_1 ((Rawbyte *) pdump_get_mc_addr |
2720 | 1325 (XPNTR (*pobj))); |
1326 break; | |
1327 } | |
1328 case XD_LISP_OBJECT_ARRAY: | |
1329 { | |
1330 EMACS_INT num = lispdesc_indirect_count (desc1->data1, desc, | |
1331 data); | |
1332 int j; | |
1333 | |
1334 for (j=0; j<num; j++) | |
1335 { | |
1336 Lisp_Object *pobj = (Lisp_Object *) rdata + j; | |
1337 | |
1338 if (POINTER_TYPE_P (XTYPE (*pobj)) | |
1339 && ! EQ (*pobj, Qnull_pointer)) | |
3092 | 1340 *pobj = wrap_pointer_1 ((Rawbyte *) pdump_get_mc_addr |
2775 | 1341 (XPNTR (*pobj))); |
2720 | 1342 } |
1343 break; | |
1344 } | |
1345 case XD_DOC_STRING: | |
1346 { | |
1347 EMACS_INT str = *(EMACS_INT *) rdata; | |
1348 if (str > 0) | |
1349 *(EMACS_INT *) rdata = pdump_get_mc_addr ((void *) str); | |
1350 break; | |
1351 } | |
1352 case XD_BLOCK_ARRAY: | |
1353 { | |
1354 EMACS_INT num = lispdesc_indirect_count (desc1->data1, desc, | |
1355 data); | |
1356 int j; | |
1357 const struct sized_memory_description *sdesc = | |
1358 lispdesc_indirect_description (data, desc1->data2.descr); | |
1359 Bytecount size = lispdesc_block_size (rdata, sdesc); | |
1360 | |
1361 /* Note: We are recursing over data in the block itself */ | |
1362 for (j = 0; j < num; j++) | |
1363 pdump_reloc_one_mc ((Rawbyte *) rdata + j * size, | |
1364 sdesc->description); | |
1365 | |
1366 break; | |
1367 } | |
1368 case XD_UNION: | |
1369 case XD_UNION_DYNAMIC_SIZE: | |
1370 desc1 = lispdesc_process_xd_union (desc1, desc, data); | |
1371 if (desc1) | |
1372 goto union_switcheroo; | |
1373 break; | |
1374 | |
1375 case XD_OPAQUE_PTR_CONVERTIBLE: | |
1376 { | |
1377 pdump_cv_ptr_load_info *p = pdump_loaded_cv_ptr + *(EMACS_INT *)rdata; | |
1378 if (!p->adr) | |
1379 p->adr = desc1->data2.funcs->deconvert(0, | |
1380 pdump_start + p->save_offset, | |
1381 p->size); | |
1382 *(void **)rdata = p->adr; | |
1383 break; | |
1384 } | |
1385 | |
1386 case XD_OPAQUE_DATA_CONVERTIBLE: | |
1387 { | |
1388 EMACS_INT dest_offset = (EMACS_INT) rdata; | |
1389 EMACS_INT indirect = | |
1390 lispdesc_indirect_count (desc1->offset, desc, data); | |
1391 pdump_cv_data_dump_info *p; | |
1392 | |
1393 for(p = pdump_loaded_cv_data; | |
1394 pdump_get_indirect_mc_addr (p->dest_offset, indirect) | |
1395 != dest_offset; | |
1396 p++); | |
1397 | |
1398 desc1->data2.funcs->deconvert(rdata, pdump_start + p->save_offset, | |
1399 p->size); | |
1400 break; | |
1401 } | |
1402 | |
1403 default: | |
1404 pdump_unsupported_dump_type (desc1->type, 0); | |
1405 } | |
1406 } | |
1407 } | |
3263 | 1408 #else /* not NEW_GC */ |
771 | 1409 /* Relocate a single memory block at DATA, described by DESC, from its |
1204 | 1410 assumed load location to its actual one by adding DELTA to all pointers |
1411 in the block. Does not recursively relocate any other memory blocks | |
1412 pointed to. (We already have a list of all memory blocks in the dump | |
1413 file.) This is used once the dump data has been loaded back in, both | |
2367 | 1414 for blocks sitting in the dumped data (former heap blocks) and in global |
1415 data-sgment blocks whose contents have been restored from the dumped | |
1416 data. */ | |
442 | 1417 |
1418 static void | |
458 | 1419 pdump_reloc_one (void *data, EMACS_INT delta, |
1204 | 1420 const struct memory_description *desc) |
442 | 1421 { |
1422 int pos; | |
1423 | |
1424 for (pos = 0; desc[pos].type != XD_END; pos++) | |
1425 { | |
1204 | 1426 const struct memory_description *desc1 = &desc[pos]; |
2367 | 1427 void *rdata = |
1428 (Rawbyte *) data + lispdesc_indirect_count (desc1->offset, | |
1429 desc, data); | |
1204 | 1430 |
1431 union_switcheroo: | |
1432 | |
1433 /* If the flag says don't dump, then don't dump. */ | |
1434 if ((desc1->flags) & XD_FLAG_NO_PDUMP) | |
1435 continue; | |
1436 | |
1437 switch (desc1->type) | |
442 | 1438 { |
665 | 1439 case XD_BYTECOUNT: |
1440 case XD_ELEMCOUNT: | |
1441 case XD_HASHCODE: | |
442 | 1442 case XD_INT: |
1443 case XD_LONG: | |
1444 case XD_INT_RESET: | |
1445 break; | |
1446 case XD_OPAQUE_DATA_PTR: | |
2367 | 1447 case XD_ASCII_STRING: |
1448 case XD_BLOCK_PTR: | |
442 | 1449 case XD_LO_LINK: |
1450 { | |
1451 EMACS_INT ptr = *(EMACS_INT *)rdata; | |
1452 if (ptr) | |
1453 *(EMACS_INT *)rdata = ptr+delta; | |
1454 break; | |
1455 } | |
1456 case XD_LISP_OBJECT: | |
1457 { | |
1458 Lisp_Object *pobj = (Lisp_Object *) rdata; | |
1459 | |
1204 | 1460 assert (desc1->data1 == 0); |
442 | 1461 |
1462 if (POINTER_TYPE_P (XTYPE (*pobj)) | |
1463 && ! EQ (*pobj, Qnull_pointer)) | |
2367 | 1464 *pobj = wrap_pointer_1 ((Rawbyte *) XPNTR (*pobj) + delta); |
442 | 1465 |
1466 break; | |
1467 } | |
1468 case XD_LISP_OBJECT_ARRAY: | |
1469 { | |
1204 | 1470 EMACS_INT num = lispdesc_indirect_count (desc1->data1, desc, |
1471 data); | |
442 | 1472 int j; |
1473 | |
1474 for (j=0; j<num; j++) | |
1475 { | |
1476 Lisp_Object *pobj = (Lisp_Object *) rdata + j; | |
1477 | |
1478 if (POINTER_TYPE_P (XTYPE (*pobj)) | |
1479 && ! EQ (*pobj, Qnull_pointer)) | |
2367 | 1480 *pobj = wrap_pointer_1 ((Rawbyte *) XPNTR (*pobj) + |
1481 delta); | |
442 | 1482 } |
1483 break; | |
1484 } | |
1485 case XD_DOC_STRING: | |
1486 { | |
1487 EMACS_INT str = *(EMACS_INT *)rdata; | |
1488 if (str > 0) | |
1489 *(EMACS_INT *)rdata = str + delta; | |
1490 break; | |
1491 } | |
2367 | 1492 case XD_BLOCK_ARRAY: |
771 | 1493 { |
1204 | 1494 EMACS_INT num = lispdesc_indirect_count (desc1->data1, desc, |
1495 data); | |
771 | 1496 int j; |
1204 | 1497 const struct sized_memory_description *sdesc = |
2551 | 1498 lispdesc_indirect_description (data, desc1->data2.descr); |
2367 | 1499 Bytecount size = lispdesc_block_size (rdata, sdesc); |
771 | 1500 |
1501 /* Note: We are recursing over data in the block itself */ | |
1502 for (j = 0; j < num; j++) | |
2367 | 1503 pdump_reloc_one ((Rawbyte *) rdata + j * size, delta, |
771 | 1504 sdesc->description); |
1505 | |
1506 break; | |
1507 } | |
1204 | 1508 case XD_UNION: |
1509 case XD_UNION_DYNAMIC_SIZE: | |
1510 desc1 = lispdesc_process_xd_union (desc1, desc, data); | |
1511 if (desc1) | |
1512 goto union_switcheroo; | |
1513 break; | |
771 | 1514 |
2551 | 1515 case XD_OPAQUE_PTR_CONVERTIBLE: |
1516 { | |
1517 pdump_cv_ptr_load_info *p = pdump_loaded_cv_ptr + *(EMACS_INT *)rdata; | |
1518 if (!p->adr) | |
1519 p->adr = desc1->data2.funcs->deconvert(0, pdump_start + | |
1520 p->save_offset, p->size); | |
1521 *(void **)rdata = p->adr; | |
1522 break; | |
1523 } | |
1524 | |
1525 case XD_OPAQUE_DATA_CONVERTIBLE: | |
1526 { | |
1527 EMACS_INT dest_offset = (Rawbyte *)rdata - pdump_start; | |
1528 pdump_cv_data_dump_info *p; | |
1529 | |
1530 for(p = pdump_loaded_cv_data; p->dest_offset != dest_offset; p++); | |
1531 | |
1532 desc1->data2.funcs->deconvert(rdata, pdump_start + p->save_offset, | |
1533 p->size); | |
1534 break; | |
1535 } | |
1536 | |
442 | 1537 default: |
1333 | 1538 pdump_unsupported_dump_type (desc1->type, 0); |
1204 | 1539 } |
442 | 1540 } |
1541 } | |
3263 | 1542 #endif /* not NEW_GC */ |
442 | 1543 |
1544 static void | |
2367 | 1545 pdump_allocate_offset (pdump_block_list_elt *elt, |
2286 | 1546 const struct memory_description *UNUSED (desc)) |
442 | 1547 { |
665 | 1548 Bytecount size = elt->count * elt->size; |
460 | 1549 elt->save_offset = cur_offset; |
2367 | 1550 if (size > max_size) |
442 | 1551 max_size = size; |
1552 cur_offset += size; | |
1553 } | |
1554 | |
2551 | 1555 /* Write out to global file descriptor PDUMP_OUT the result of an |
1556 external element. It's just opaque data. */ | |
1557 | |
1558 static void | |
1559 pdump_dump_cv_data (pdump_cv_data_info *elt) | |
1560 { | |
1561 retry_fwrite (elt->data, elt->size, 1, pdump_out); | |
1562 } | |
1563 | |
1564 static void | |
1565 pdump_dump_cv_ptr (pdump_cv_ptr_info *elt) | |
1566 { | |
1567 retry_fwrite (elt->data, elt->size, 1, pdump_out); | |
1568 } | |
1569 | |
1570 static void | |
1571 pdump_allocate_offset_cv_data (pdump_cv_data_info *elt) | |
1572 { | |
1573 elt->save_offset = cur_offset; | |
1574 if (elt->size>max_size) | |
1575 max_size = elt->size; | |
1576 cur_offset += elt->size; | |
1577 } | |
1578 | |
1579 static void | |
1580 pdump_allocate_offset_cv_ptr (pdump_cv_ptr_info *elt) | |
1581 { | |
1582 elt->save_offset = cur_offset; | |
1583 if (elt->size>max_size) | |
1584 max_size = elt->size; | |
1585 cur_offset += elt->size; | |
1586 } | |
1587 | |
2367 | 1588 /* Traverse through all the heap blocks, once the "register" stage of |
1589 dumping has finished. To compress space as much as possible, we | |
1590 logically sort all blocks by alignment, hitting all blocks with | |
1591 alignment == the maximum (which may be 8 bytes, for doubles), then | |
1592 all blocks with the next lower alignment (4 bytes), etc. | |
1593 | |
1594 Within each alignment we hit | |
1595 | |
1596 -- first the Lisp objects, type-by-type | |
1597 | |
1598 -- then the heap memory blocks that are not Lisp objects, description-by- | |
1599 description -- i.e. all blocks with the same description will be | |
1600 placed together | |
1601 | |
1602 -- then the "opaque" data objects declared as XD_OPAQUE_DATA_PTR, | |
1603 XD_ASCII_STRING and XD_DOC_STRING. | |
1604 | |
1605 The idea is to have as little blank space as possible in the laid-out | |
1606 data. | |
1607 | |
1608 For each item that we have hit, we process it by calling F, the function | |
1609 passed it. In dumper.c, pdump_scan_by_alignment() is called twice with | |
1610 two different functions -- pdump_allocate_offset() in stage 2 to compute | |
1611 the offset to each block, and pdump_dump_data() in stage 3 to | |
1612 successively write each block to disk. | |
1613 | |
1614 It's extremely important that the SAME traversal order gets invoked | |
1615 in both stage 2 and 3. | |
1616 */ | |
1617 | |
442 | 1618 static void |
2367 | 1619 pdump_scan_by_alignment (void (*f)(pdump_block_list_elt *, |
2551 | 1620 const struct memory_description *), |
1621 void (*g)(pdump_cv_data_info *), | |
1622 void (*h)(pdump_cv_ptr_info *)) | |
442 | 1623 { |
460 | 1624 int align; |
1625 | |
1626 for (align = ALIGNOF (max_align_t); align; align>>=1) | |
442 | 1627 { |
460 | 1628 int i; |
2367 | 1629 pdump_block_list_elt *elt; |
460 | 1630 |
442 | 1631 for (i=0; i<lrecord_type_count; i++) |
1632 if (pdump_object_table[i].align == align) | |
460 | 1633 for (elt = pdump_object_table[i].first; elt; elt = elt->next) |
1634 f (elt, lrecord_implementations_table[i]->description); | |
442 | 1635 |
2367 | 1636 for (i=0; i<pdump_desc_table.count; i++) |
460 | 1637 { |
2367 | 1638 pdump_desc_list_elt list = pdump_desc_table.list[i]; |
460 | 1639 if (list.list.align == align) |
1640 for (elt = list.list.first; elt; elt = elt->next) | |
1204 | 1641 f (elt, list.desc); |
460 | 1642 } |
442 | 1643 |
460 | 1644 for (elt = pdump_opaque_data_list.first; elt; elt = elt->next) |
1645 if (pdump_size_to_align (elt->size) == align) | |
1646 f (elt, 0); | |
2551 | 1647 |
1648 for (i=0; i < Dynarr_length (pdump_cv_data); i++) | |
1649 if (pdump_size_to_align (Dynarr_atp (pdump_cv_data, i)->size) == align) | |
1650 g (Dynarr_atp (pdump_cv_data, i)); | |
1651 | |
1652 for (i=0; i < Dynarr_length (pdump_cv_ptr); i++) | |
1653 if (pdump_size_to_align (Dynarr_atp (pdump_cv_ptr, i)->size) == align) | |
1654 h (Dynarr_atp (pdump_cv_ptr, i)); | |
442 | 1655 } |
1656 } | |
1657 | |
2551 | 1658 static void |
1659 pdump_dump_cv_data_info (void) | |
1660 { | |
1661 int i; | |
1662 Elemcount count = Dynarr_length (pdump_cv_data); | |
1663 pdump_cv_data_dump_info *data = alloca_array (pdump_cv_data_dump_info, count); | |
1664 for (i = 0; i < count; i++) | |
1665 { | |
1666 data[i].dest_offset = Dynarr_at (pdump_cv_data, i).dest_offset; | |
1667 data[i].save_offset = Dynarr_at (pdump_cv_data, i).save_offset; | |
1668 data[i].size = Dynarr_at (pdump_cv_data, i).size; | |
1669 } | |
1670 | |
1671 PDUMP_ALIGN_OUTPUT (pdump_cv_data_dump_info); | |
1672 retry_fwrite (data, sizeof (pdump_cv_data_dump_info), count, pdump_out); | |
1673 } | |
1674 | |
442 | 1675 static void |
2551 | 1676 pdump_dump_cv_ptr_info (void) |
1677 { | |
1678 int i; | |
1679 Elemcount count = Dynarr_length (pdump_cv_ptr); | |
1680 pdump_cv_ptr_dump_info *data = alloca_array (pdump_cv_ptr_dump_info, count); | |
1681 for (i = 0; i < count; i++) | |
1682 { | |
1683 data[i].save_offset = Dynarr_at (pdump_cv_ptr, i).save_offset; | |
1684 data[i].size = Dynarr_at (pdump_cv_ptr, i).size; | |
1685 } | |
1686 | |
1687 PDUMP_ALIGN_OUTPUT (pdump_cv_ptr_dump_info); | |
1688 retry_fwrite (data, sizeof (pdump_cv_ptr_dump_info), count, pdump_out); | |
1689 } | |
1690 | |
3103 | 1691 /* Dump out the root block pointers, part of stage 3 (the "WRITE" stage) of |
1692 dumping. For each pointer we dump out a structure containing the | |
1693 location of the pointer and its value, replaced by the appropriate | |
1694 offset into the dumped data. */ | |
1695 | |
2551 | 1696 static void |
2367 | 1697 pdump_dump_root_block_ptrs (void) |
442 | 1698 { |
1699 int i; | |
2367 | 1700 Elemcount count = Dynarr_length (pdump_root_block_ptrs); |
458 | 1701 pdump_static_pointer *data = alloca_array (pdump_static_pointer, count); |
1702 for (i = 0; i < count; i++) | |
442 | 1703 { |
1333 | 1704 data[i].address = |
2367 | 1705 (Rawbyte **) Dynarr_atp (pdump_root_block_ptrs, i)->ptraddress; |
1333 | 1706 data[i].value = |
2367 | 1707 (Rawbyte *) pdump_get_block (* data[i].address)->save_offset; |
442 | 1708 } |
458 | 1709 PDUMP_ALIGN_OUTPUT (pdump_static_pointer); |
771 | 1710 retry_fwrite (data, sizeof (pdump_static_pointer), count, pdump_out); |
442 | 1711 } |
1712 | |
2367 | 1713 /* Dump out the root blocks, part of stage 3 (the "WRITE" stage) of |
1714 dumping. For each block we dump a structure containing info about the | |
1715 block (its location, size and description) and then the block itself, | |
1716 with its pointers replaced with offsets into the dump data. */ | |
1717 | |
442 | 1718 static void |
1204 | 1719 pdump_dump_root_blocks (void) |
442 | 1720 { |
1721 int i; | |
1204 | 1722 for (i = 0; i < Dynarr_length (pdump_root_blocks); i++) |
442 | 1723 { |
2367 | 1724 pdump_root_block info = Dynarr_at (pdump_root_blocks, i); |
1725 PDUMP_WRITE_ALIGNED (pdump_root_block, info); | |
1726 | |
1727 if (info.desc) | |
1728 { | |
1729 /* Copy to temporary buffer */ | |
1730 memcpy (pdump_buf, info.blockaddr, info.size); | |
1731 | |
1732 /* Store new offsets into all pointers in block */ | |
1733 pdump_store_new_pointer_offsets (1, pdump_buf, info.blockaddr, | |
1734 info.desc, info.size); | |
1735 } | |
1736 retry_fwrite (info.desc ? pdump_buf : info.blockaddr, | |
1737 info.size, 1, pdump_out); | |
442 | 1738 } |
1739 } | |
1740 | |
1741 static void | |
1742 pdump_dump_rtables (void) | |
1743 { | |
452 | 1744 int i; |
2367 | 1745 pdump_block_list_elt *elt; |
442 | 1746 pdump_reloc_table rt; |
1747 | |
1748 for (i=0; i<lrecord_type_count; i++) | |
1749 { | |
460 | 1750 elt = pdump_object_table[i].first; |
1751 if (!elt) | |
442 | 1752 continue; |
1753 rt.desc = lrecord_implementations_table[i]->description; | |
1754 rt.count = pdump_object_table[i].count; | |
458 | 1755 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt); |
460 | 1756 while (elt) |
442 | 1757 { |
2367 | 1758 EMACS_INT rdata = pdump_get_block (elt->obj)->save_offset; |
3092 | 1759 #ifdef NEW_GC |
1760 int j; | |
1761 for (j=0; j<elt->count; j++) | |
1762 { | |
1763 PDUMP_WRITE_ALIGNED (EMACS_INT, rdata); | |
1764 rdata += elt->size; | |
1765 } | |
1766 #else /* not NEW_GC */ | |
458 | 1767 PDUMP_WRITE_ALIGNED (EMACS_INT, rdata); |
3092 | 1768 #endif /* not NEW_GC */ |
460 | 1769 elt = elt->next; |
442 | 1770 } |
1771 } | |
1772 | |
1773 rt.desc = 0; | |
1774 rt.count = 0; | |
458 | 1775 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt); |
442 | 1776 |
2367 | 1777 for (i=0; i<pdump_desc_table.count; i++) |
442 | 1778 { |
2367 | 1779 elt = pdump_desc_table.list[i].list.first; |
1780 rt.desc = pdump_desc_table.list[i].desc; | |
1781 rt.count = pdump_desc_table.list[i].list.count; | |
458 | 1782 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt); |
460 | 1783 while (elt) |
442 | 1784 { |
2367 | 1785 EMACS_INT rdata = pdump_get_block (elt->obj)->save_offset; |
452 | 1786 int j; |
460 | 1787 for (j=0; j<elt->count; j++) |
442 | 1788 { |
458 | 1789 PDUMP_WRITE_ALIGNED (EMACS_INT, rdata); |
460 | 1790 rdata += elt->size; |
442 | 1791 } |
460 | 1792 elt = elt->next; |
442 | 1793 } |
1794 } | |
1795 rt.desc = 0; | |
1796 rt.count = 0; | |
458 | 1797 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt); |
442 | 1798 } |
1799 | |
1800 static void | |
1204 | 1801 pdump_dump_root_lisp_objects (void) |
442 | 1802 { |
1204 | 1803 Elemcount count = (Dynarr_length (pdump_root_lisp_objects) + |
647 | 1804 Dynarr_length (pdump_weak_object_chains)); |
665 | 1805 Elemcount i; |
442 | 1806 |
665 | 1807 PDUMP_WRITE_ALIGNED (Elemcount, count); |
458 | 1808 PDUMP_ALIGN_OUTPUT (pdump_static_Lisp_Object); |
442 | 1809 |
1204 | 1810 for (i = 0; i < Dynarr_length (pdump_root_lisp_objects); i++) |
442 | 1811 { |
458 | 1812 pdump_static_Lisp_Object obj; |
1204 | 1813 obj.address = Dynarr_at (pdump_root_lisp_objects, i); |
458 | 1814 obj.value = * obj.address; |
460 | 1815 |
458 | 1816 if (POINTER_TYPE_P (XTYPE (obj.value))) |
619 | 1817 obj.value = |
2367 | 1818 wrap_pointer_1 ((void *) pdump_get_block (XRECORD_LHEADER |
617 | 1819 (obj.value))->save_offset); |
460 | 1820 |
458 | 1821 PDUMP_WRITE (pdump_static_Lisp_Object, obj); |
442 | 1822 } |
1823 | |
2367 | 1824 for (i = 0; i < Dynarr_length (pdump_weak_object_chains); i++) |
442 | 1825 { |
2367 | 1826 pdump_block_list_elt *elt; |
458 | 1827 pdump_static_Lisp_Object obj; |
442 | 1828 |
458 | 1829 obj.address = Dynarr_at (pdump_weak_object_chains, i); |
1830 obj.value = * obj.address; | |
460 | 1831 |
442 | 1832 for (;;) |
1833 { | |
1204 | 1834 const struct memory_description *desc; |
442 | 1835 int pos; |
2367 | 1836 elt = pdump_get_block (XRECORD_LHEADER (obj.value)); |
460 | 1837 if (elt) |
442 | 1838 break; |
458 | 1839 desc = XRECORD_LHEADER_IMPLEMENTATION (obj.value)->description; |
442 | 1840 for (pos = 0; desc[pos].type != XD_LO_LINK; pos++) |
1841 assert (desc[pos].type != XD_END); | |
1842 | |
1204 | 1843 /* #### Figure out how to handle indirect offsets here. */ |
1844 assert (!XD_IS_INDIRECT (desc[pos].offset)); | |
1845 obj.value = | |
1846 * (Lisp_Object *) (desc[pos].offset + | |
2367 | 1847 (Rawbyte *) (XRECORD_LHEADER (obj.value))); |
442 | 1848 } |
619 | 1849 obj.value = wrap_pointer_1 ((void *) elt->save_offset); |
442 | 1850 |
458 | 1851 PDUMP_WRITE (pdump_static_Lisp_Object, obj); |
442 | 1852 } |
1853 } | |
1854 | |
2367 | 1855 |
1856 /*######################################################################## | |
1857 # Pdump # | |
1858 ######################################################################## | |
1859 | |
1860 [ben] | |
1861 | |
1862 DISCUSSION OF DUMPING: | |
1863 | |
1864 The idea of dumping is to record the state of XEmacs in a file, so that | |
1865 it can be reloaded later. This avoids having to reload all of the basic | |
1866 Lisp code each time XEmacs is run, which is a rather time-consuming | |
1867 process. (Less so on new machines, but still noticeable. As an example | |
1868 of a program with similar issues but which does not have a dumping | |
1869 process and as a result has a slow startup time, consider Adobe Photoshop | |
1870 5.0 or Adobe Photoshop Elements 2.0.) | |
1871 | |
1872 We don't actually record ALL the state of XEmacs (some of it, for example, | |
1873 is dependent on the run-time environment and needs to be initialized | |
1874 whenever XEmacs is run), but whatever state we don't record needs to be | |
1875 reinitialized every time XEmacs is run. | |
1876 | |
1877 The old way of dumping was to make a new executable file with the data | |
1878 segment expanded to contain the heap and written out from memory. This | |
1879 is what the unex* files do. Unfortunately this process is extremely | |
1880 system-specific and breaks easily with OS changes. | |
1881 | |
1882 Another simple, more portable trick, the "static heap" method, involves | |
1883 replacing the allocator with our own allocator which allocates all space | |
1884 out of a very large array declared in our data segment until we run out, | |
1885 then uses the underlying malloc() to start allocating on the heap. If we | |
1886 ensure that the large array is big enough to hold all data allocated | |
1887 during the dump stage, then all of the data we need to save is in the | |
1888 data segment, and it's easy to calculate the location and size of the | |
1889 data segment we want to save (we don't want to record and reinitialize | |
1890 the data segment of library functions) by using appropriately declared | |
1891 variables in the first and last file linked. This method is known as the | |
1892 "static heap" method, and is used by the non-pdump version of the dumper | |
1893 under Cygwin, and was also used under VMS and in Win-Emacs. | |
1894 | |
1895 The "static heap" method works well in practice. Nonetheless, a more | |
1896 complex method of dumping was written by Olivier Galibert, which requires | |
1897 that structural descriptions of all data allocated in the heap be provided | |
1898 and the roots of all pointers into the heap be noted through function calls | |
1899 to the pdump API. This way, all the heap data can be traversed and written | |
1900 out to a file, and then reloaded at run-time and the pointers relocated to | |
1901 point at the new location of the loaded data. This is the "pdump" method | |
1902 used in this file. | |
1903 | |
1904 There are two potential advantages of "pdump" over the "static heap": | |
1905 | |
1906 (1) It doesn't require any tricks to calculate the beginning and end of | |
1907 the data segment, or even that the XEmacs section of the data segment | |
1908 be contiguous. (It's not clear whether this is an issue in practice.) | |
1909 (2) Potentially, it could handle an OS that does not always load the | |
1910 static data segment at a predictable location. The "static heap" | |
1911 method by its nature needs the data segment to stay in the same place | |
1912 from invocation to invocation, since it simply dumps out memory and | |
1913 reloads it, without any pointer relocation. I say "potentially" | |
1914 because as it is currently written pdump does assume that the data | |
1915 segment is never relocated. However, changing pdump to remove this | |
1916 assumption is probably not difficult, as all the mechanism to handle | |
1917 pointer relocation is already present. | |
1918 | |
1919 | |
1920 DISCUSSION OF PDUMP WORKINGS: | |
1921 | |
1922 See man/internals/internals.texi for more information. | |
1923 | |
1924 NOTE that we have two kinds of memory to handle: memory on the heap | |
1925 (i.e. allocated through malloc()) or the like, and static memory in the | |
1926 data segment of the program, i.e. stuff declared as global or static. | |
1927 All heap memory needs to be written out to the dump file and reproduced | |
1928 (i.e. reloaded and any necessary relocations performed). Data-segment | |
1929 memory that is not statically initialized (i.e. through declarations in | |
1930 the C code) needs either to be written out and reloaded, or | |
1931 reinitialized. In addition, any pointers in data-segment memory to heap | |
1932 memory must be written out, reloaded and relocated. | |
1933 | |
1934 NOTE that we currently don't handle relocation of pointers into data- | |
1935 segment memory. (See overview discussion above.) These are treated in | |
1936 the descriptions as opaque data not needing relocation. If this becomes a | |
1937 problem, it can be fixed through new kinds of types in | |
1938 enum memory_description_type. | |
1939 | |
1940 Three basic steps to dumping out: | |
1941 | |
1942 (1) "REGISTER": | |
1943 Starting with all sources of relocatable memory (currently this means | |
1944 all data-segment pointers to heap memory -- see above about pointers | |
1945 to data-segment memory), recursively traverse the tree of pointers | |
1946 and "register" (make a note of) every memory block seen. | |
1947 | |
1948 (2) "LAYOUT": | |
1949 Go through all of the registered blocks and compute the location of | |
1950 each one in the dump data (i.e. the "offset" that will be added to | |
1951 the address corresponding to start of the loaded-in data to get the | |
1952 new pointer referring to this block). The blocks will be laid out | |
1953 sequentially according to the order we traverse them. Also note the | |
1954 maximum-sized block for use in step 3. | |
1955 | |
1956 (3) "WRITE": | |
1957 After writing some header stuff, go through all of the registered | |
1958 blocks and write out each one to the dump file. Note that we are | |
1959 simply writing out the blocks sequentially as we see them, and our | |
1960 traversal path is identical to that in step 2, so blocks will end up | |
1961 at the locations computed for them. In order to write out a block, | |
1962 first copy it to a temporary location (hence the maximum-block-size | |
1963 computation in the previous step), then for each relocatable pointer | |
1964 in the block, write in its place the offset to the heap block in the | |
1965 dump data. When the dump data is loaded, the address of the | |
1966 beginning of the dump data will be added to the offset in each | |
1967 pointer, and thence become accurate. | |
1968 | |
1969 --ben | |
1970 */ | |
1971 | |
442 | 1972 void |
1973 pdump (void) | |
1974 { | |
1975 int i; | |
1976 Lisp_Object t_console, t_device, t_frame; | |
1977 int none; | |
458 | 1978 pdump_header header; |
442 | 1979 |
1204 | 1980 in_pdump = 1; |
1981 | |
2367 | 1982 pdump_object_table = xnew_array (pdump_block_list, lrecord_type_count); |
460 | 1983 pdump_alert_undump_object = xnew_array (int, lrecord_type_count); |
1984 | |
1985 assert (ALIGNOF (max_align_t) <= pdump_align_table[0]); | |
1986 | |
1987 for (i = 0; i < countof (pdump_align_table); i++) | |
1988 if (pdump_align_table[i] > ALIGNOF (max_align_t)) | |
1989 pdump_align_table[i] = ALIGNOF (max_align_t); | |
1990 | |
446 | 1991 flush_all_buffer_local_cache (); |
1992 | |
442 | 1993 /* These appear in a DEFVAR_LISP, which does a staticpro() */ |
452 | 1994 t_console = Vterminal_console; Vterminal_console = Qnil; |
1995 t_frame = Vterminal_frame; Vterminal_frame = Qnil; | |
1996 t_device = Vterminal_device; Vterminal_device = Qnil; | |
442 | 1997 |
452 | 1998 dump_add_opaque (&lrecord_implementations_table, |
1204 | 1999 lrecord_type_count * |
2000 sizeof (lrecord_implementations_table[0])); | |
1676 | 2001 #ifdef USE_KKCC |
2002 dump_add_opaque (&lrecord_memory_descriptions, | |
2003 lrecord_type_count | |
2004 * sizeof (lrecord_memory_descriptions[0])); | |
2005 #else /* not USE_KKCC */ | |
452 | 2006 dump_add_opaque (&lrecord_markers, |
2007 lrecord_type_count * sizeof (lrecord_markers[0])); | |
1676 | 2008 #endif /* not USE_KKCC */ |
442 | 2009 |
2367 | 2010 pdump_hash = xnew_array_and_zero (pdump_block_list_elt *, PDUMP_HASHSIZE); |
442 | 2011 |
2367 | 2012 for (i = 0; i<lrecord_type_count; i++) |
442 | 2013 { |
2014 pdump_object_table[i].first = 0; | |
460 | 2015 pdump_object_table[i].align = ALIGNOF (max_align_t); |
442 | 2016 pdump_object_table[i].count = 0; |
2017 pdump_alert_undump_object[i] = 0; | |
2018 } | |
2367 | 2019 pdump_desc_table.count = 0; |
2020 pdump_desc_table.size = -1; | |
442 | 2021 |
2022 pdump_opaque_data_list.first = 0; | |
460 | 2023 pdump_opaque_data_list.align = ALIGNOF (max_align_t); |
442 | 2024 pdump_opaque_data_list.count = 0; |
1204 | 2025 pdump_depth = 0; |
442 | 2026 |
2551 | 2027 pdump_cv_data = Dynarr_new2 (pdump_cv_data_info_dynarr, pdump_cv_data_info); |
2028 pdump_cv_ptr = Dynarr_new2 (pdump_cv_ptr_info_dynarr, pdump_cv_ptr_info); | |
2029 | |
2367 | 2030 /* (I) The "register" stage: Note all heap memory blocks to be relocated |
2031 */ | |
2032 | |
2033 /* Try various roots of accessibility: */ | |
2034 | |
2035 /* (1) Lisp objects, both those declared using DEFVAR_LISP*() and those | |
2036 staticpro()d. */ | |
1204 | 2037 for (i = 0; i < Dynarr_length (pdump_root_lisp_objects); i++) |
2038 pdump_register_object (* Dynarr_at (pdump_root_lisp_objects, i)); | |
442 | 2039 |
2040 none = 1; | |
2367 | 2041 for (i = 0; i < lrecord_type_count; i++) |
442 | 2042 if (pdump_alert_undump_object[i]) |
2043 { | |
2044 if (none) | |
2367 | 2045 stderr_out ("Undumpable types list :\n"); |
442 | 2046 none = 0; |
2367 | 2047 stderr_out (" - %s (%d)\n", lrecord_implementations_table[i]->name, |
2048 pdump_alert_undump_object[i]); | |
442 | 2049 } |
2050 if (!none) | |
1204 | 2051 { |
2052 in_pdump = 0; | |
2053 return; | |
2054 } | |
442 | 2055 |
2367 | 2056 /* (2) Register out the data-segment pointer variables to heap blocks */ |
2057 for (i = 0; i < Dynarr_length (pdump_root_block_ptrs); i++) | |
452 | 2058 { |
2367 | 2059 pdump_root_block_ptr info = Dynarr_at (pdump_root_block_ptrs, i); |
2060 pdump_register_block (*(info.ptraddress), info.desc->size, | |
2061 info.desc->description, 1); | |
452 | 2062 } |
442 | 2063 |
2367 | 2064 /* (3) Register out the data-segment blocks, maybe with pointers to heap |
2065 blocks */ | |
2066 for (i = 0; i < Dynarr_length (pdump_root_blocks); i++) | |
2067 { | |
2068 pdump_root_block *info = Dynarr_atp (pdump_root_blocks, i); | |
2069 if (info->desc) | |
2070 { | |
2071 /* Size may have been given as 0 meaning "compute later". | |
2072 Compute now and update. If no DESC, size must always be | |
2073 correct as there is no other way of computing it. */ | |
2074 info->size = lispdesc_block_size_1 (info->blockaddr, info->size, | |
2075 info->desc); | |
2076 pdump_register_block_contents (info->blockaddr, info->size, | |
2077 info->desc, 1); | |
2078 } | |
2079 } | |
2080 | |
2081 /* (II) The "layout" stage: Compute the offsets and max-size */ | |
2082 | |
2083 /* (1) Determine header size */ | |
458 | 2084 memcpy (header.signature, PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN); |
2085 header.id = dump_id; | |
2086 header.reloc_address = 0; | |
2367 | 2087 header.nb_root_block_ptrs = Dynarr_length (pdump_root_block_ptrs); |
1204 | 2088 header.nb_root_blocks = Dynarr_length (pdump_root_blocks); |
2551 | 2089 header.nb_cv_data = Dynarr_length (pdump_cv_data); |
2090 header.nb_cv_ptr = Dynarr_length (pdump_cv_ptr); | |
442 | 2091 |
826 | 2092 cur_offset = MAX_ALIGN_SIZE (sizeof (header)); |
442 | 2093 max_size = 0; |
2094 | |
2367 | 2095 /* (2) Traverse all heap blocks and compute their offsets; keep track |
2096 of maximum block size seen */ | |
2551 | 2097 pdump_scan_by_alignment (pdump_allocate_offset, |
2098 pdump_allocate_offset_cv_data, | |
2099 pdump_allocate_offset_cv_ptr); | |
826 | 2100 cur_offset = MAX_ALIGN_SIZE (cur_offset); |
458 | 2101 header.stab_offset = cur_offset; |
442 | 2102 |
2367 | 2103 /* (3) Update maximum size based on root (data-segment) blocks */ |
2104 for (i = 0; i < Dynarr_length (pdump_root_blocks); i++) | |
2105 { | |
2106 pdump_root_block info = Dynarr_at (pdump_root_blocks, i); | |
2107 | |
2108 /* If no DESC, no relocation needed and we copy directly instead of | |
2109 into a temp buffer. */ | |
2110 if (info.desc) | |
2111 { | |
2112 if (info.size > max_size) | |
2113 max_size = info.size; | |
2114 } | |
2115 } | |
2116 | |
2117 /* (III) The "write "stage: Dump out the data, storing the offsets in | |
2118 place of pointers whenever we write out memory blocks */ | |
2119 | |
442 | 2120 pdump_buf = xmalloc (max_size); |
2367 | 2121 /* EMACS_PROGNAME is entirely ASCII so this should be Mule-safe */ |
442 | 2122 pdump_fd = open (EMACS_PROGNAME ".dmp", |
2123 O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY, 0666); | |
771 | 2124 if (pdump_fd < 0) |
2125 report_file_error ("Unable to open dump file", | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4388
diff
changeset
|
2126 build_ascstring (EMACS_PROGNAME ".dmp")); |
458 | 2127 pdump_out = fdopen (pdump_fd, "w"); |
771 | 2128 if (pdump_out < 0) |
2129 report_file_error ("Unable to open dump file for writing", | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4388
diff
changeset
|
2130 build_ascstring (EMACS_PROGNAME ".dmp")); |
442 | 2131 |
771 | 2132 retry_fwrite (&header, sizeof (header), 1, pdump_out); |
458 | 2133 PDUMP_ALIGN_OUTPUT (max_align_t); |
442 | 2134 |
2551 | 2135 for (i = 0; i < Dynarr_length (pdump_cv_data); i++) |
2136 { | |
2137 pdump_cv_data_info *elt = Dynarr_atp (pdump_cv_data, i); | |
2138 elt->dest_offset = | |
2139 pdump_get_block (elt->object)->save_offset + elt->offset; | |
2140 } | |
2141 | |
2142 for (i = 0; i < Dynarr_length (pdump_cv_ptr); i++) | |
2143 Dynarr_at (pdump_cv_ptr, i).index = i; | |
2144 | |
2145 pdump_scan_by_alignment (pdump_dump_data, pdump_dump_cv_data, pdump_dump_cv_ptr); | |
2146 | |
2147 for (i = 0; i < Dynarr_length (pdump_cv_data); i++) | |
2148 { | |
2149 pdump_cv_data_info *elt = Dynarr_atp (pdump_cv_data, i); | |
2150 if(elt->fcts->convert_free) | |
2151 elt->fcts->convert_free(elt->object, elt->data, elt->size); | |
2152 } | |
2153 | |
2154 for (i = 0; i < Dynarr_length (pdump_cv_ptr); i++) | |
2155 { | |
2156 pdump_cv_ptr_info *elt = Dynarr_atp (pdump_cv_ptr, i); | |
2157 if(elt->fcts->convert_free) | |
2158 elt->fcts->convert_free(elt->object, elt->data, elt->size); | |
2159 } | |
442 | 2160 |
458 | 2161 fseek (pdump_out, header.stab_offset, SEEK_SET); |
442 | 2162 |
3263 | 2163 #ifdef NEW_GC |
2720 | 2164 { |
2165 EMACS_INT zero = 0; | |
2166 pdump_scan_lisp_objects_by_alignment (pdump_dump_mc_data); | |
2167 PDUMP_WRITE_ALIGNED (EMACS_INT, zero); | |
2168 pdump_scan_non_lisp_objects_by_alignment (pdump_dump_mc_data); | |
2169 PDUMP_WRITE_ALIGNED (EMACS_INT, zero); | |
2170 } | |
3263 | 2171 #endif /* NEW_GC */ |
2551 | 2172 pdump_dump_cv_data_info (); |
2173 pdump_dump_cv_ptr_info (); | |
3263 | 2174 #ifdef NEW_GC |
2720 | 2175 pdump_dump_rtables (); |
3263 | 2176 #endif /* NEW_GC */ |
2367 | 2177 pdump_dump_root_block_ptrs (); |
1204 | 2178 pdump_dump_root_blocks (); |
3263 | 2179 #ifndef NEW_GC |
442 | 2180 pdump_dump_rtables (); |
3263 | 2181 #endif /* not NEW_GC */ |
1204 | 2182 pdump_dump_root_lisp_objects (); |
442 | 2183 |
771 | 2184 retry_fclose (pdump_out); |
3964 | 2185 /* pdump_fd is already closed by the preceding call to fclose. |
2186 retry_close (pdump_fd); */ | |
458 | 2187 |
442 | 2188 free (pdump_buf); |
2189 | |
2190 free (pdump_hash); | |
2191 | |
2192 Vterminal_console = t_console; | |
2193 Vterminal_frame = t_frame; | |
2194 Vterminal_device = t_device; | |
1204 | 2195 in_pdump = 0; |
442 | 2196 } |
2197 | |
452 | 2198 static int |
2199 pdump_load_check (void) | |
442 | 2200 { |
2367 | 2201 return (!memcmp (((pdump_header *) pdump_start)->signature, |
452 | 2202 PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN) |
2203 && ((pdump_header *)pdump_start)->id == dump_id); | |
442 | 2204 } |
2205 | |
458 | 2206 /*----------------------------------------------------------------------*/ |
2207 /* Reading the dump file */ | |
2208 /*----------------------------------------------------------------------*/ | |
452 | 2209 static int |
2210 pdump_load_finish (void) | |
442 | 2211 { |
2212 int i; | |
2367 | 2213 Rawbyte *p; |
442 | 2214 EMACS_INT delta; |
2215 EMACS_INT count; | |
1204 | 2216 pdump_header *header = (pdump_header *) pdump_start; |
442 | 2217 |
3092 | 2218 #ifdef NEW_GC |
2219 /* This is a DEFVAR_BOOL and gets dumped, but the actual value was | |
2220 already determined by vdb_install_signal_handler () in | |
2221 vdb-mprotect.c, which could be different from the value in the | |
2222 dump file. So store it here and restore it after loading the dump | |
2223 file. */ | |
2224 int allow_inc_gc = allow_incremental_gc; | |
2225 #endif /* NEW_GC */ | |
442 | 2226 pdump_end = pdump_start + pdump_length; |
2227 | |
1204 | 2228 delta = ((EMACS_INT) pdump_start) - header->reloc_address; |
458 | 2229 p = pdump_start + header->stab_offset; |
442 | 2230 |
3263 | 2231 #ifdef NEW_GC |
2720 | 2232 pdump_mc_hash = xnew_array_and_zero (mc_addr_elt, PDUMP_HASHSIZE); |
2233 | |
2234 /* Allocate space for each object individually. First the | |
2235 Lisp_Objects, then the blocks. */ | |
2236 count = 2; | |
2237 for (;;) | |
2238 { | |
2824 | 2239 EMACS_INT elt_count = PDUMP_READ_ALIGNED (p, EMACS_INT); |
2720 | 2240 if (elt_count) |
2241 { | |
2242 Rawbyte *mc_addr = 0; | |
2243 Bytecount size = PDUMP_READ_ALIGNED (p, Bytecount); | |
2244 for (i = 0; i < elt_count; i++) | |
2245 { | |
2246 EMACS_INT rdata = PDUMP_READ_ALIGNED (p, EMACS_INT); | |
2247 | |
2248 if (i == 0) | |
2249 { | |
2250 Bytecount real_size = size * elt_count; | |
2251 if (count == 2) | |
2775 | 2252 { |
3092 | 2253 if (elt_count <= 1) |
2254 mc_addr = (Rawbyte *) mc_alloc (real_size); | |
2255 else | |
2256 mc_addr = (Rawbyte *) mc_alloc_array (size, elt_count); | |
2994 | 2257 #ifdef ALLOC_TYPE_STATS |
2775 | 2258 inc_lrecord_stats (real_size, |
2259 (const struct lrecord_header *) | |
3092 | 2260 ((Rawbyte *) rdata + delta)); |
2994 | 2261 #endif /* ALLOC_TYPE_STATS */ |
2775 | 2262 } |
2720 | 2263 else |
2264 mc_addr = (Rawbyte *) xmalloc_and_zero (real_size); | |
2265 } | |
2266 else | |
2267 mc_addr += size; | |
2268 | |
2269 pdump_put_mc_addr ((void *) rdata, (EMACS_INT) mc_addr); | |
3092 | 2270 memcpy (mc_addr, (Rawbyte *) rdata + delta, size); |
2720 | 2271 } |
2272 } | |
2273 else if (!(--count)) | |
2274 break; | |
2275 } | |
3263 | 2276 #endif /* NEW_GC */ |
2720 | 2277 |
2551 | 2278 /* Get the cv_data array */ |
2553 | 2279 p = (Rawbyte *) ALIGN_PTR (p, pdump_cv_data_dump_info); |
2551 | 2280 pdump_loaded_cv_data = (pdump_cv_data_dump_info *)p; |
2281 p += header->nb_cv_data*sizeof(pdump_cv_data_dump_info); | |
2282 | |
2283 /* Build the cv_ptr array */ | |
2553 | 2284 p = (Rawbyte *) ALIGN_PTR (p, pdump_cv_ptr_dump_info); |
2551 | 2285 pdump_loaded_cv_ptr = |
2286 alloca_array (pdump_cv_ptr_load_info, header->nb_cv_ptr); | |
2287 for (i = 0; i < header->nb_cv_ptr; i++) | |
2288 { | |
2289 pdump_cv_ptr_dump_info info = PDUMP_READ (p, pdump_cv_ptr_dump_info); | |
2290 pdump_loaded_cv_ptr[i].save_offset = info.save_offset; | |
2291 pdump_loaded_cv_ptr[i].size = info.size; | |
2292 pdump_loaded_cv_ptr[i].adr = 0; | |
2293 } | |
2294 | |
3263 | 2295 #ifdef NEW_GC |
2720 | 2296 /* Relocate the heap objects */ |
2297 pdump_rt_list = p; | |
2298 count = 2; | |
2299 for (;;) | |
2300 { | |
2301 pdump_reloc_table rt = PDUMP_READ_ALIGNED (p, pdump_reloc_table); | |
2302 p = (Rawbyte *) ALIGN_PTR (p, Rawbyte *); | |
2303 if (rt.desc) | |
2304 { | |
3092 | 2305 Rawbyte **reloc = (Rawbyte **) p; |
2720 | 2306 for (i = 0; i < rt.count; i++) |
2307 { | |
3092 | 2308 reloc[i] = (Rawbyte *) pdump_get_mc_addr (reloc[i]); |
2720 | 2309 pdump_reloc_one_mc (reloc[i], rt.desc); |
2310 } | |
3092 | 2311 p += rt.count * sizeof (Rawbyte *); |
2720 | 2312 } |
2313 else if (!(--count)) | |
2314 break; | |
2315 } | |
3263 | 2316 #endif /* NEW_GC */ |
2720 | 2317 |
2367 | 2318 /* Put back the pdump_root_block_ptrs */ |
2319 p = (Rawbyte *) ALIGN_PTR (p, pdump_static_pointer); | |
2320 for (i = 0; i < header->nb_root_block_ptrs; i++) | |
442 | 2321 { |
458 | 2322 pdump_static_pointer ptr = PDUMP_READ (p, pdump_static_pointer); |
3263 | 2323 #ifdef NEW_GC |
2720 | 2324 (* ptr.address) = (Rawbyte *) pdump_get_mc_addr (ptr.value); |
3263 | 2325 #else /* not NEW_GC */ |
458 | 2326 (* ptr.address) = ptr.value + delta; |
3263 | 2327 #endif /* not NEW_GC */ |
442 | 2328 } |
2329 | |
1204 | 2330 /* Put back the pdump_root_blocks and relocate */ |
2331 for (i = 0; i < header->nb_root_blocks; i++) | |
442 | 2332 { |
1204 | 2333 pdump_root_block info = PDUMP_READ_ALIGNED (p, pdump_root_block); |
2367 | 2334 memcpy ((void *) info.blockaddr, p, info.size); |
1204 | 2335 if (info.desc) |
3263 | 2336 #ifdef NEW_GC |
2720 | 2337 pdump_reloc_one_mc ((void *) info.blockaddr, info.desc); |
3263 | 2338 #else /* not NEW_GC */ |
2367 | 2339 pdump_reloc_one ((void *) info.blockaddr, delta, info.desc); |
3263 | 2340 #endif /* not NEW_GC */ |
452 | 2341 p += info.size; |
442 | 2342 } |
2343 | |
3263 | 2344 #ifndef NEW_GC |
1204 | 2345 /* Relocate the heap objects */ |
442 | 2346 pdump_rt_list = p; |
2347 count = 2; | |
2348 for (;;) | |
2349 { | |
458 | 2350 pdump_reloc_table rt = PDUMP_READ_ALIGNED (p, pdump_reloc_table); |
2367 | 2351 p = (Rawbyte *) ALIGN_PTR (p, Rawbyte *); |
442 | 2352 if (rt.desc) |
2353 { | |
2367 | 2354 Rawbyte **reloc = (Rawbyte **) p; |
1204 | 2355 for (i = 0; i < rt.count; i++) |
442 | 2356 { |
458 | 2357 reloc[i] += delta; |
2358 pdump_reloc_one (reloc[i], delta, rt.desc); | |
442 | 2359 } |
2367 | 2360 p += rt.count * sizeof (Rawbyte *); |
1204 | 2361 } |
2362 else if (!(--count)) | |
2363 break; | |
442 | 2364 } |
3263 | 2365 #endif /* not NEW_GC */ |
442 | 2366 |
1204 | 2367 /* Put the pdump_root_lisp_objects variables in place */ |
665 | 2368 i = PDUMP_READ_ALIGNED (p, Elemcount); |
2367 | 2369 p = (Rawbyte *) ALIGN_PTR (p, pdump_static_Lisp_Object); |
458 | 2370 while (i--) |
442 | 2371 { |
458 | 2372 pdump_static_Lisp_Object obj = PDUMP_READ (p, pdump_static_Lisp_Object); |
442 | 2373 |
458 | 2374 if (POINTER_TYPE_P (XTYPE (obj.value))) |
3263 | 2375 #ifdef NEW_GC |
2720 | 2376 obj.value = wrap_pointer_1 ((Rawbyte *) pdump_get_mc_addr |
2377 (XPNTR (obj.value))); | |
3263 | 2378 #else /* not NEW_GC */ |
2720 | 2379 obj.value = wrap_pointer_1 ((Rawbyte *) XPNTR (obj.value) + delta); |
3263 | 2380 #endif /* not NEW_GC */ |
442 | 2381 |
458 | 2382 (* obj.address) = obj.value; |
442 | 2383 } |
2384 | |
2385 /* Final cleanups */ | |
2386 /* reorganize hash tables */ | |
2387 p = pdump_rt_list; | |
2388 for (;;) | |
2389 { | |
458 | 2390 pdump_reloc_table rt = PDUMP_READ_ALIGNED (p, pdump_reloc_table); |
2367 | 2391 p = (Rawbyte *) ALIGN_PTR (p, Lisp_Object); |
442 | 2392 if (!rt.desc) |
2393 break; | |
2394 if (rt.desc == hash_table_description) | |
2395 { | |
1204 | 2396 for (i = 0; i < rt.count; i++) |
442 | 2397 pdump_reorganize_hash_table (PDUMP_READ (p, Lisp_Object)); |
2398 break; | |
1204 | 2399 } |
2400 else | |
2401 p += sizeof (Lisp_Object) * rt.count; | |
442 | 2402 } |
2403 | |
3263 | 2404 #ifdef NEW_GC |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
2405 xfree (pdump_mc_hash); |
3263 | 2406 #endif /* NEW_GC */ |
2720 | 2407 |
3092 | 2408 #ifdef NEW_GC |
2409 allow_incremental_gc = allow_inc_gc; | |
2410 #endif /* NEW_GC */ | |
2411 | |
442 | 2412 return 1; |
2413 } | |
2414 | |
2415 #ifdef WIN32_NATIVE | |
2416 /* Free the mapped file if we decide we don't want it after all */ | |
452 | 2417 static void |
2418 pdump_file_unmap (void) | |
442 | 2419 { |
2420 UnmapViewOfFile (pdump_start); | |
2421 CloseHandle (pdump_hFile); | |
2422 CloseHandle (pdump_hMap); | |
2423 } | |
2424 | |
452 | 2425 static int |
2367 | 2426 pdump_file_get (const Wexttext *wpath) |
442 | 2427 { |
2367 | 2428 Extbyte *path; |
2429 if (XEUNICODE_P) | |
2430 path = (Extbyte *) wpath; | |
2431 else | |
2432 path = WEXTTEXT_TO_MULTIBYTE (wpath); | |
442 | 2433 |
2367 | 2434 pdump_hFile = |
2435 qxeCreateFile (path, | |
2436 GENERIC_READ + GENERIC_WRITE, /* Required for copy on | |
2437 write */ | |
2438 0, /* Not shared */ | |
2439 NULL, /* Not inheritable */ | |
2440 OPEN_EXISTING, | |
2441 FILE_ATTRIBUTE_NORMAL, | |
2442 NULL); /* No template file */ | |
442 | 2443 if (pdump_hFile == INVALID_HANDLE_VALUE) |
2444 return 0; | |
2445 | |
2446 pdump_length = GetFileSize (pdump_hFile, NULL); | |
2367 | 2447 pdump_hMap = |
2448 qxeCreateFileMapping (pdump_hFile, | |
2449 NULL, /* No security attributes */ | |
2450 PAGE_WRITECOPY, /* Copy on write */ | |
2451 0, /* Max size, high half */ | |
2452 0, /* Max size, low half */ | |
2453 NULL); /* Unnamed */ | |
442 | 2454 if (pdump_hMap == INVALID_HANDLE_VALUE) |
2455 return 0; | |
2456 | |
2367 | 2457 pdump_start = |
2458 (Rawbyte *) MapViewOfFile (pdump_hMap, | |
2459 FILE_MAP_COPY, /* Copy on write */ | |
2460 0, /* Start at zero */ | |
2461 0, | |
2462 0); /* Map all of it */ | |
442 | 2463 pdump_free = pdump_file_unmap; |
2464 return 1; | |
2465 } | |
2466 | |
2467 /* pdump_resource_free is called (via the pdump_free pointer) to release | |
2468 any resources allocated by pdump_resource_get. Since the Windows API | |
2469 specs specifically state that you don't need to (and shouldn't) free the | |
2470 resources allocated by FindResource, LoadResource, and LockResource this | |
2471 routine does nothing. */ | |
452 | 2472 static void |
2473 pdump_resource_free (void) | |
442 | 2474 { |
2475 } | |
2476 | |
452 | 2477 static int |
2478 pdump_resource_get (void) | |
442 | 2479 { |
452 | 2480 HRSRC hRes; /* Handle to dump resource */ |
2481 HRSRC hResLoad; /* Handle to loaded dump resource */ | |
442 | 2482 |
2483 /* See Q126630 which describes how Windows NT and 95 trap writes to | |
2484 resource sections and duplicate the page to allow the write to proceed. | |
2485 It also describes how to make the resource section read/write (and hence | |
2486 private to each process). Doing this avoids the exceptions and related | |
2487 overhead, but causes the resource section to be private to each process | |
2488 that is running XEmacs. Since the resource section contains little | |
2489 other than the dumped data, which should be private to each process, we | |
2490 make the whole resource section read/write so we don't have to copy it. */ | |
2491 | |
800 | 2492 hRes = FindResourceA (NULL, MAKEINTRESOURCE (101), "DUMP"); |
442 | 2493 if (hRes == NULL) |
2494 return 0; | |
2495 | |
2496 /* Found it, use the data in the resource */ | |
1204 | 2497 hResLoad = (HRSRC) LoadResource (NULL, hRes); |
442 | 2498 if (hResLoad == NULL) |
2499 return 0; | |
2500 | |
2367 | 2501 pdump_start = (Rawbyte *) LockResource (hResLoad); |
442 | 2502 if (pdump_start == NULL) |
2503 return 0; | |
2504 | |
2505 pdump_free = pdump_resource_free; | |
2506 pdump_length = SizeofResource (NULL, hRes); | |
665 | 2507 if (pdump_length <= (Bytecount) sizeof (pdump_header)) |
442 | 2508 { |
2509 pdump_start = 0; | |
2510 return 0; | |
2511 } | |
2512 | |
2513 return 1; | |
2514 } | |
2515 | |
2516 #else /* !WIN32_NATIVE */ | |
2517 | |
452 | 2518 static void |
2519 pdump_file_free (void) | |
442 | 2520 { |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
2521 xfree (pdump_start); |
442 | 2522 } |
2523 | |
2524 #ifdef HAVE_MMAP | |
452 | 2525 static void |
2526 pdump_file_unmap (void) | |
442 | 2527 { |
2528 munmap (pdump_start, pdump_length); | |
2529 } | |
2530 #endif | |
2531 | |
452 | 2532 static int |
2367 | 2533 pdump_file_get (const Wexttext *path) |
442 | 2534 { |
2367 | 2535 int fd = wext_retry_open (path, O_RDONLY | OPEN_BINARY); |
2536 if (fd < 0) | |
442 | 2537 return 0; |
2538 | |
2539 pdump_length = lseek (fd, 0, SEEK_END); | |
665 | 2540 if (pdump_length < (Bytecount) sizeof (pdump_header)) |
442 | 2541 { |
771 | 2542 retry_close (fd); |
442 | 2543 return 0; |
2544 } | |
2545 | |
2546 lseek (fd, 0, SEEK_SET); | |
2547 | |
2548 #ifdef HAVE_MMAP | |
456 | 2549 /* Unix 98 requires that sys/mman.h define MAP_FAILED, |
2550 but many earlier implementations don't. */ | |
2551 # ifndef MAP_FAILED | |
2552 # define MAP_FAILED ((void *) -1L) | |
2553 # endif | |
2367 | 2554 pdump_start = |
2555 (Rawbyte *) mmap (0, pdump_length, PROT_READ|PROT_WRITE, MAP_PRIVATE, | |
2556 fd, 0); | |
2557 if (pdump_start != (Rawbyte *) MAP_FAILED) | |
442 | 2558 { |
2559 pdump_free = pdump_file_unmap; | |
771 | 2560 retry_close (fd); |
442 | 2561 return 1; |
2562 } | |
456 | 2563 #endif /* HAVE_MMAP */ |
442 | 2564 |
2367 | 2565 pdump_start = xnew_array (Rawbyte, pdump_length); |
442 | 2566 pdump_free = pdump_file_free; |
771 | 2567 retry_read (fd, pdump_start, pdump_length); |
442 | 2568 |
771 | 2569 retry_close (fd); |
442 | 2570 return 1; |
2571 } | |
2015 | 2572 |
2720 | 2573 #ifdef DUMP_IN_EXEC |
2015 | 2574 static int |
2575 pdump_ram_try (void) | |
2576 { | |
2367 | 2577 pdump_start = dumped_data_get (); |
2578 pdump_length = dumped_data_size (); | |
2015 | 2579 |
2367 | 2580 return pdump_load_check (); |
2015 | 2581 } |
2720 | 2582 #endif |
2015 | 2583 |
442 | 2584 #endif /* !WIN32_NATIVE */ |
2585 | |
2586 | |
452 | 2587 static int |
2367 | 2588 pdump_file_try (Wexttext *exe_path) |
442 | 2589 { |
2367 | 2590 Wexttext *w = exe_path + wext_strlen (exe_path); |
442 | 2591 |
2563 | 2592 /* We look for various names, including those with the version and dump ID, |
2593 those with just the dump ID, and those without either. We first try | |
2594 adding directly to the executable name, then lopping off any extension | |
2595 (e.g. .exe) or version name in the executable (xemacs-21.5.18). */ | |
442 | 2596 do |
2597 { | |
2367 | 2598 wext_sprintf (w, WEXTSTRING ("-%s-%08x.dmp"), WEXTSTRING (EMACS_VERSION), |
2599 dump_id); | |
442 | 2600 if (pdump_file_get (exe_path)) |
2601 { | |
2602 if (pdump_load_check ()) | |
2603 return 1; | |
452 | 2604 pdump_free (); |
442 | 2605 } |
2606 | |
2367 | 2607 wext_sprintf (w, WEXTSTRING ("-%08x.dmp"), dump_id); |
442 | 2608 if (pdump_file_get (exe_path)) |
2609 { | |
2610 if (pdump_load_check ()) | |
2611 return 1; | |
452 | 2612 pdump_free (); |
442 | 2613 } |
2614 | |
2367 | 2615 wext_sprintf (w, WEXTSTRING (".dmp")); |
442 | 2616 if (pdump_file_get (exe_path)) |
2617 { | |
2618 if (pdump_load_check ()) | |
2619 return 1; | |
452 | 2620 pdump_free (); |
442 | 2621 } |
2622 | |
2623 do | |
2624 w--; | |
2367 | 2625 /* !!#### See comment below about how this is unsafe. */ |
2626 while (w > exe_path && !IS_DIRECTORY_SEP (*w) && (*w != '-') && | |
2627 (*w != '.')); | |
442 | 2628 } |
2367 | 2629 while (w > exe_path && !IS_DIRECTORY_SEP (*w)); |
442 | 2630 return 0; |
2631 } | |
2632 | |
4388
1a14c304cb8e
Don't use PATH_MAX_EXTERNAL, non-Win32.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4137
diff
changeset
|
2633 #define DUMP_SLACK 100 /* Enough to include dump ID, version name, .DMP */ |
1a14c304cb8e
Don't use PATH_MAX_EXTERNAL, non-Win32.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4137
diff
changeset
|
2634 |
452 | 2635 int |
2367 | 2636 pdump_load (const Wexttext *argv0) |
442 | 2637 { |
2638 #ifdef WIN32_NATIVE | |
2421 | 2639 Wexttext *exe_path = NULL; |
2640 int bufsize = 4096; | |
2641 int cchpathsize; | |
2642 | |
2643 /* Copied from mswindows_get_module_file_name (). Not clear if it's | |
2644 kosher to malloc() yet. */ | |
2645 while (1) | |
2646 { | |
2647 exe_path = alloca_array (Wexttext, bufsize); | |
2648 cchpathsize = qxeGetModuleFileName (NULL, (Extbyte *) exe_path, | |
2649 bufsize); | |
2650 if (!cchpathsize) | |
2651 goto fail; | |
2563 | 2652 if (cchpathsize + DUMP_SLACK <= bufsize) |
2421 | 2653 break; |
2654 bufsize *= 2; | |
2655 } | |
2656 | |
2367 | 2657 if (!XEUNICODE_P) |
2658 { | |
2659 Wexttext *wexe = MULTIBYTE_TO_WEXTTEXT ((Extbyte *) exe_path); | |
2660 wext_strcpy (exe_path, wexe); | |
2661 } | |
442 | 2662 #else /* !WIN32_NATIVE */ |
4388
1a14c304cb8e
Don't use PATH_MAX_EXTERNAL, non-Win32.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4137
diff
changeset
|
2663 Wexttext *exe_path; |
2367 | 2664 Wexttext *w; |
2665 const Wexttext *dir, *p; | |
442 | 2666 |
2720 | 2667 #ifdef DUMP_IN_EXEC |
2367 | 2668 if (pdump_ram_try ()) |
2669 { | |
2670 pdump_load_finish (); | |
2671 in_pdump = 0; | |
2672 return 1; | |
2673 } | |
2720 | 2674 #endif |
2015 | 2675 |
1204 | 2676 in_pdump = 1; |
442 | 2677 dir = argv0; |
2678 if (dir[0] == '-') | |
2679 { | |
2680 /* XEmacs as a login shell, oh goody! */ | |
2367 | 2681 dir = wext_getenv ("SHELL"); /* not egetenv -- not yet initialized and we |
2682 want external-format data */ | |
442 | 2683 } |
2684 | |
2367 | 2685 p = dir + wext_strlen (dir); |
2686 /* !!#### This is bad as it may fail with certain non-ASCII-compatible | |
2687 external formats such as JIS. Maybe we should be using the mb*() | |
2688 routines in libc? But can we reliably trust them on all Unix | |
2689 platforms? (We can't convert to internal since those conversion | |
2690 routines aren't yet initialized) */ | |
2691 while (p != dir && !IS_ANY_SEP (p[-1])) | |
2692 p--; | |
442 | 2693 |
2694 if (p != dir) | |
2695 { | |
2696 /* invocation-name includes a directory component -- presumably it | |
4137 | 2697 is relative to cwd, not $PATH. */ |
4388
1a14c304cb8e
Don't use PATH_MAX_EXTERNAL, non-Win32.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4137
diff
changeset
|
2698 exe_path = alloca_array (Wexttext, 1 + wext_strlen (dir) + DUMP_SLACK); |
2367 | 2699 wext_strcpy (exe_path, dir); |
442 | 2700 } |
2701 else | |
2702 { | |
2367 | 2703 const Wexttext *path = wext_getenv ("PATH"); /* not egetenv -- |
4388
1a14c304cb8e
Don't use PATH_MAX_EXTERNAL, non-Win32.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4137
diff
changeset
|
2704 not yet init. */ |
2367 | 2705 const Wexttext *name = p; |
4388
1a14c304cb8e
Don't use PATH_MAX_EXTERNAL, non-Win32.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4137
diff
changeset
|
2706 exe_path = alloca_array (Wexttext, |
1a14c304cb8e
Don't use PATH_MAX_EXTERNAL, non-Win32.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4137
diff
changeset
|
2707 1 + DUMP_SLACK + max (wext_strlen (name), |
1a14c304cb8e
Don't use PATH_MAX_EXTERNAL, non-Win32.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4137
diff
changeset
|
2708 wext_strlen (path))); |
442 | 2709 for (;;) |
2710 { | |
2711 p = path; | |
2712 while (*p && *p != SEPCHAR) | |
2713 p++; | |
2714 if (p == path) | |
2715 { | |
2716 exe_path[0] = '.'; | |
2717 w = exe_path + 1; | |
2718 } | |
2719 else | |
2720 { | |
2367 | 2721 memcpy (exe_path, path, (p - path) * sizeof (Wexttext)); |
442 | 2722 w = exe_path + (p - path); |
2723 } | |
2724 if (!IS_DIRECTORY_SEP (w[-1])) | |
2367 | 2725 *w++ = '/'; |
2726 wext_strcpy (w, name); | |
1466 | 2727 |
2728 { | |
2729 struct stat statbuf; | |
2367 | 2730 if (wext_access (exe_path, X_OK) == 0 |
2731 && wext_stat (exe_path, &statbuf) == 0 | |
1466 | 2732 && ! S_ISDIR (statbuf.st_mode)) |
2733 break; | |
2734 } | |
2735 | |
442 | 2736 if (!*p) |
2737 { | |
2738 /* Oh well, let's have some kind of default */ | |
2367 | 2739 wext_sprintf (exe_path, "./%s", name); |
442 | 2740 break; |
2741 } | |
2421 | 2742 path = p + 1; |
442 | 2743 } |
2744 } | |
2745 #endif /* WIN32_NATIVE */ | |
2746 | |
2747 if (pdump_file_try (exe_path)) | |
2748 { | |
2749 pdump_load_finish (); | |
1204 | 2750 in_pdump = 0; |
3263 | 2751 #ifdef NEW_GC |
2720 | 2752 pdump_free (); |
3263 | 2753 #endif /* NEW_GC */ |
442 | 2754 return 1; |
2755 } | |
2756 | |
2757 #ifdef WIN32_NATIVE | |
2758 if (pdump_resource_get ()) | |
2759 { | |
2760 if (pdump_load_check ()) | |
2761 { | |
2762 pdump_load_finish (); | |
1204 | 2763 in_pdump = 0; |
3263 | 2764 #ifdef NEW_GC |
2720 | 2765 pdump_free (); |
3263 | 2766 #endif /* NEW_GC */ |
442 | 2767 return 1; |
2768 } | |
2769 pdump_free (); | |
2770 } | |
2421 | 2771 |
2772 fail: | |
442 | 2773 #endif |
2774 | |
1204 | 2775 in_pdump = 0; |
442 | 2776 return 0; |
2777 } |