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