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