1 /* Portable data dumper for XEmacs.
2 Copyright (C) 1999-2000 Olivier Galibert
3 Copyright (C) 2001 Martin Buchholz
5 This file is part of XEmacs.
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 /* Synched up with: Not in FSF. */
27 #include "specifier.h"
30 #include "console-stream.h"
53 Dynarr_declare (pdump_opaque);
54 } pdump_opaque_dynarr;
59 const struct struct_description *desc;
60 } pdump_root_struct_ptr;
64 Dynarr_declare (pdump_root_struct_ptr);
65 } pdump_root_struct_ptr_dynarr;
71 } pdump_static_Lisp_Object;
75 char **address; /* char * for ease of doing relocation */
77 } pdump_static_pointer;
79 static pdump_opaque_dynarr *pdump_opaques;
80 static pdump_root_struct_ptr_dynarr *pdump_root_struct_ptrs;
81 static Lisp_Object_ptr_dynarr *pdump_root_objects;
82 static Lisp_Object_ptr_dynarr *pdump_weak_object_chains;
84 /* Mark SIZE bytes at non-heap address VARADDRESS for dumping as is,
85 without any bit-twiddling. */
87 dump_add_opaque (void *varaddress, size_t size)
90 info.varaddress = varaddress;
92 if (pdump_opaques == NULL)
93 pdump_opaques = Dynarr_new (pdump_opaque);
94 Dynarr_add (pdump_opaques, info);
97 /* Mark the struct described by DESC and pointed to by the pointer at
98 non-heap address VARADDRESS for dumping.
99 All the objects reachable from this pointer will also be dumped. */
101 dump_add_root_struct_ptr (void *ptraddress, const struct struct_description *desc)
103 pdump_root_struct_ptr info;
104 info.ptraddress = (void **) ptraddress;
106 if (pdump_root_struct_ptrs == NULL)
107 pdump_root_struct_ptrs = Dynarr_new (pdump_root_struct_ptr);
108 Dynarr_add (pdump_root_struct_ptrs, info);
111 /* Mark the Lisp_Object at non-heap address VARADDRESS for dumping.
112 All the objects reachable from this var will also be dumped. */
114 dump_add_root_object (Lisp_Object *varaddress)
116 if (pdump_root_objects == NULL)
117 pdump_root_objects = Dynarr_new2 (Lisp_Object_ptr_dynarr, Lisp_Object *);
118 Dynarr_add (pdump_root_objects, varaddress);
121 /* Mark the list pointed to by the Lisp_Object at VARADDRESS for dumping. */
123 dump_add_weak_object_chain (Lisp_Object *varaddress)
125 if (pdump_weak_object_chains == NULL)
126 pdump_weak_object_chains = Dynarr_new2 (Lisp_Object_ptr_dynarr, Lisp_Object *);
127 Dynarr_add (pdump_weak_object_chains, varaddress);
132 pdump_align_stream (FILE *stream, size_t alignment)
134 long offset = ftell (stream);
135 long adjustment = ALIGN_SIZE (offset, alignment) - offset;
137 fseek (stream, adjustment, SEEK_CUR);
140 #define PDUMP_ALIGN_OUTPUT(type) pdump_align_stream (pdump_out, ALIGNOF (type))
142 #define PDUMP_WRITE(type, object) \
143 fwrite (&object, sizeof (object), 1, pdump_out);
145 #define PDUMP_WRITE_ALIGNED(type, object) do { \
146 PDUMP_ALIGN_OUTPUT (type); \
147 PDUMP_WRITE (type, object); \
150 #define PDUMP_READ(ptr, type) \
151 (((type *) (ptr = (char*) (((type *) ptr) + 1)))[-1])
153 #define PDUMP_READ_ALIGNED(ptr, type) \
154 ((ptr = (char *) ALIGN_PTR (ptr, ALIGNOF (type))), PDUMP_READ (ptr, type))
160 const struct lrecord_description *desc;
164 static char *pdump_rt_list = 0;
167 pdump_objects_unmark (void)
170 char *p = pdump_rt_list;
174 pdump_reloc_table *rt = (pdump_reloc_table *)p;
175 p += sizeof (pdump_reloc_table);
178 for (i=0; i<rt->count; i++)
180 struct lrecord_header *lh = * (struct lrecord_header **) p;
181 if (! C_READONLY_RECORD_HEADER_P (lh))
182 UNMARK_RECORD_HEADER (lh);
183 p += sizeof (EMACS_INT);
191 /* The structure of the file
194 stab_offset - nb_root_struct_ptrs*pair(void *, adr)
195 for pointers to structures
196 - nb_opaques*pair(void *, size) for raw bits to restore
198 - root lisp object address/value couples with the count
203 #define PDUMP_SIGNATURE "XEmacsDP"
204 #define PDUMP_SIGNATURE_LEN (sizeof (PDUMP_SIGNATURE) - 1)
208 char signature[PDUMP_SIGNATURE_LEN];
210 EMACS_UINT stab_offset;
211 EMACS_UINT reloc_address;
212 int nb_root_struct_ptrs;
218 static size_t pdump_length;
221 /* Handle for the dump file */
222 static HANDLE pdump_hFile = INVALID_HANDLE_VALUE;
223 /* Handle for the file mapping object for the dump file */
224 static HANDLE pdump_hMap = INVALID_HANDLE_VALUE;
227 static void (*pdump_free) (void);
229 static unsigned char pdump_align_table[] =
231 64, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
232 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
233 32, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
234 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1
237 static inline unsigned int
238 pdump_size_to_align (size_t size)
240 return pdump_align_table[size % countof (pdump_align_table)];
243 typedef struct pdump_entry_list_elt
245 struct pdump_entry_list_elt *next;
249 EMACS_INT save_offset;
250 } pdump_entry_list_elt;
254 pdump_entry_list_elt *first;
259 typedef struct pdump_struct_list_elt
261 pdump_entry_list list;
262 const struct struct_description *sdesc;
263 } pdump_struct_list_elt;
267 pdump_struct_list_elt *list;
272 static pdump_entry_list *pdump_object_table;
273 static pdump_entry_list pdump_opaque_data_list;
274 static pdump_struct_list pdump_struct_table;
276 static int *pdump_alert_undump_object;
278 static unsigned long cur_offset;
279 static size_t max_size;
281 static void *pdump_buf;
282 static FILE *pdump_out;
285 #define PDUMP_HASHSIZE 20000001
287 #define PDUMP_HASHSIZE 200001
290 static pdump_entry_list_elt **pdump_hash;
292 /* Since most pointers are eight bytes aligned, the >>3 allows for a better hash */
294 pdump_make_hash (const void *obj)
296 return ((unsigned long)(obj)>>3) % PDUMP_HASHSIZE;
299 static pdump_entry_list_elt *
300 pdump_get_entry (const void *obj)
302 int pos = pdump_make_hash (obj);
303 pdump_entry_list_elt *e;
307 while ((e = pdump_hash[pos]) != 0)
313 if (pos == PDUMP_HASHSIZE)
320 pdump_add_entry (pdump_entry_list *list, const void *obj, size_t size,
323 pdump_entry_list_elt *e;
324 int pos = pdump_make_hash (obj);
326 while ((e = pdump_hash[pos]) != 0)
332 if (pos == PDUMP_HASHSIZE)
336 e = xnew (pdump_entry_list_elt);
338 e->next = list->first;
344 list->count += count;
348 int align = pdump_size_to_align (size);
350 if (align < list->align)
355 static pdump_entry_list *
356 pdump_get_entry_list (const struct struct_description *sdesc)
359 for (i=0; i<pdump_struct_table.count; i++)
360 if (pdump_struct_table.list[i].sdesc == sdesc)
361 return &pdump_struct_table.list[i].list;
363 if (pdump_struct_table.size <= pdump_struct_table.count)
365 if (pdump_struct_table.size == -1)
366 pdump_struct_table.size = 10;
368 pdump_struct_table.size = pdump_struct_table.size * 2;
369 pdump_struct_table.list = (pdump_struct_list_elt *)
370 xrealloc (pdump_struct_table.list,
371 pdump_struct_table.size * sizeof (pdump_struct_list_elt));
373 pdump_struct_table.list[pdump_struct_table.count].list.first = 0;
374 pdump_struct_table.list[pdump_struct_table.count].list.align = ALIGNOF (max_align_t);
375 pdump_struct_table.list[pdump_struct_table.count].list.count = 0;
376 pdump_struct_table.list[pdump_struct_table.count].sdesc = sdesc;
378 return &pdump_struct_table.list[pdump_struct_table.count++].list;
383 struct lrecord_header *obj;
391 pdump_backtrace (void)
394 stderr_out ("pdump backtrace :\n");
395 for (i=0;i<depth;i++)
397 if (!backtrace[i].obj)
398 stderr_out (" - ind. (%d, %d)\n",
399 backtrace[i].position,
400 backtrace[i].offset);
403 stderr_out (" - %s (%d, %d)\n",
404 LHEADER_IMPLEMENTATION (backtrace[i].obj)->name,
405 backtrace[i].position,
406 backtrace[i].offset);
411 static void pdump_register_object (Lisp_Object obj);
412 static void pdump_register_struct (const void *data,
413 const struct struct_description *sdesc,
417 pdump_get_indirect_count (EMACS_INT code,
418 const struct lrecord_description *idesc,
424 int line = XD_INDIRECT_VAL (code);
425 int delta = XD_INDIRECT_DELTA (code);
427 irdata = ((char *)idata) + idesc[line].offset;
428 switch (idesc[line].type)
431 count = *(size_t *)irdata;
434 count = *(int *)irdata;
437 count = *(long *)irdata;
440 count = *(Bytecount *)irdata;
443 stderr_out ("Unsupported count type : %d (line = %d, code=%ld)\n",
444 idesc[line].type, line, (long)code);
453 pdump_register_sub (const void *data, const struct lrecord_description *desc, int me)
458 for (pos = 0; desc[pos].type != XD_END; pos++)
460 const void *rdata = (const char *)data + desc[pos].offset;
462 backtrace[me].position = pos;
463 backtrace[me].offset = desc[pos].offset;
465 switch (desc[pos].type)
467 case XD_SPECIFIER_END:
469 desc = ((const Lisp_Specifier *)data)->methods->extra_description;
478 case XD_OPAQUE_DATA_PTR:
480 EMACS_INT count = desc[pos].data1;
481 if (XD_IS_INDIRECT (count))
482 count = pdump_get_indirect_count (count, desc, data);
484 pdump_add_entry (&pdump_opaque_data_list,
485 *(void **)rdata, count, 1);
490 const char *str = *(const char **)rdata;
492 pdump_add_entry (&pdump_opaque_data_list, str, strlen (str)+1, 1);
497 const char *str = *(const char **)rdata;
498 if ((EMACS_INT)str > 0)
499 pdump_add_entry (&pdump_opaque_data_list, str, strlen (str)+1, 1);
504 const Lisp_Object *pobj = (const Lisp_Object *)rdata;
506 assert (desc[pos].data1 == 0);
508 backtrace[me].offset = (const char *)pobj - (const char *)data;
509 pdump_register_object (*pobj);
512 case XD_LISP_OBJECT_ARRAY:
515 EMACS_INT count = desc[pos].data1;
516 if (XD_IS_INDIRECT (count))
517 count = pdump_get_indirect_count (count, desc, data);
519 for (i = 0; i < count; i++)
521 const Lisp_Object *pobj = ((const Lisp_Object *)rdata) + i;
522 Lisp_Object dobj = *pobj;
524 backtrace[me].offset = (const char *)pobj - (const char *)data;
525 pdump_register_object (dobj);
531 EMACS_INT count = desc[pos].data1;
532 const struct struct_description *sdesc = desc[pos].data2;
533 const char *dobj = *(const char **)rdata;
536 if (XD_IS_INDIRECT (count))
537 count = pdump_get_indirect_count (count, desc, data);
539 pdump_register_struct (dobj, sdesc, count);
544 stderr_out ("Unsupported dump type : %d\n", desc[pos].type);
552 pdump_register_object (Lisp_Object obj)
554 struct lrecord_header *objh;
555 const struct lrecord_implementation *imp;
557 if (!POINTER_TYPE_P (XTYPE (obj)))
560 objh = XRECORD_LHEADER (obj);
564 if (pdump_get_entry (objh))
567 imp = LHEADER_IMPLEMENTATION (objh);
569 if (imp->description)
574 stderr_out ("Backtrace overflow, loop ?\n");
577 backtrace[me].obj = objh;
578 backtrace[me].position = 0;
579 backtrace[me].offset = 0;
581 pdump_add_entry (pdump_object_table + objh->type,
585 imp->size_in_bytes_method (objh),
587 pdump_register_sub (objh, imp->description, me);
592 pdump_alert_undump_object[objh->type]++;
593 stderr_out ("Undumpable object type : %s\n", imp->name);
599 pdump_register_struct (const void *data,
600 const struct struct_description *sdesc,
603 if (data && !pdump_get_entry (data))
609 stderr_out ("Backtrace overflow, loop ?\n");
612 backtrace[me].obj = 0;
613 backtrace[me].position = 0;
614 backtrace[me].offset = 0;
616 pdump_add_entry (pdump_get_entry_list (sdesc),
617 data, sdesc->size, count);
618 for (i=0; i<count; i++)
620 pdump_register_sub (((char *)data) + sdesc->size*i,
629 pdump_dump_data (pdump_entry_list_elt *elt,
630 const struct lrecord_description *desc)
632 size_t size = elt->size;
633 int count = elt->count;
637 memcpy (pdump_buf, elt->obj, size*count);
639 for (i=0; i<count; i++)
641 char *cur = ((char *)pdump_buf) + i*size;
643 for (pos = 0; desc[pos].type != XD_END; pos++)
645 void *rdata = cur + desc[pos].offset;
646 switch (desc[pos].type)
648 case XD_SPECIFIER_END:
649 desc = ((const Lisp_Specifier *)(elt->obj))->methods->extra_description;
658 EMACS_INT val = desc[pos].data1;
659 if (XD_IS_INDIRECT (val))
660 val = pdump_get_indirect_count (val, desc, elt->obj);
664 case XD_OPAQUE_DATA_PTR:
668 void *ptr = *(void **)rdata;
670 *(EMACS_INT *)rdata = pdump_get_entry (ptr)->save_offset;
675 Lisp_Object obj = *(Lisp_Object *)rdata;
676 pdump_entry_list_elt *elt1;
679 elt1 = pdump_get_entry (XRECORD_LHEADER (obj));
682 obj = *(Lisp_Object *)(desc[pos].offset + (char *)(XRECORD_LHEADER (obj)));
684 *(EMACS_INT *)rdata = elt1->save_offset;
689 Lisp_Object *pobj = (Lisp_Object *) rdata;
691 assert (desc[pos].data1 == 0);
693 if (POINTER_TYPE_P (XTYPE (*pobj)) && XRECORD_LHEADER (*pobj))
695 pdump_get_entry (XRECORD_LHEADER (*pobj))->save_offset;
698 case XD_LISP_OBJECT_ARRAY:
700 EMACS_INT num = desc[pos].data1;
702 if (XD_IS_INDIRECT (num))
703 num = pdump_get_indirect_count (num, desc, elt->obj);
705 for (j=0; j<num; j++)
707 Lisp_Object *pobj = ((Lisp_Object *)rdata) + j;
708 if (POINTER_TYPE_P (XTYPE (*pobj)) && XRECORD_LHEADER (*pobj))
710 pdump_get_entry (XRECORD_LHEADER (*pobj))->save_offset;
716 EMACS_INT str = *(EMACS_INT *)rdata;
718 *(EMACS_INT *)rdata = pdump_get_entry ((void *)str)->save_offset;
722 stderr_out ("Unsupported dump type : %d\n", desc[pos].type);
728 fwrite (desc ? pdump_buf : elt->obj, size, count, pdump_out);
732 pdump_reloc_one (void *data, EMACS_INT delta,
733 const struct lrecord_description *desc)
738 for (pos = 0; desc[pos].type != XD_END; pos++)
740 void *rdata = (char *)data + desc[pos].offset;
741 switch (desc[pos].type)
743 case XD_SPECIFIER_END:
745 desc = ((const Lisp_Specifier *)data)->methods->extra_description;
753 case XD_OPAQUE_DATA_PTR:
758 EMACS_INT ptr = *(EMACS_INT *)rdata;
760 *(EMACS_INT *)rdata = ptr+delta;
765 Lisp_Object *pobj = (Lisp_Object *) rdata;
767 assert (desc[pos].data1 == 0);
769 if (POINTER_TYPE_P (XTYPE (*pobj))
770 && ! EQ (*pobj, Qnull_pointer))
771 XSETOBJ (*pobj, (char *) XPNTR (*pobj) + delta);
775 case XD_LISP_OBJECT_ARRAY:
777 EMACS_INT num = desc[pos].data1;
779 if (XD_IS_INDIRECT (num))
780 num = pdump_get_indirect_count (num, desc, data);
782 for (j=0; j<num; j++)
784 Lisp_Object *pobj = (Lisp_Object *) rdata + j;
786 if (POINTER_TYPE_P (XTYPE (*pobj))
787 && ! EQ (*pobj, Qnull_pointer))
788 XSETOBJ (*pobj, (char *) XPNTR (*pobj) + delta);
794 EMACS_INT str = *(EMACS_INT *)rdata;
796 *(EMACS_INT *)rdata = str + delta;
800 stderr_out ("Unsupported dump type : %d\n", desc[pos].type);
807 pdump_allocate_offset (pdump_entry_list_elt *elt,
808 const struct lrecord_description *desc)
810 size_t size = elt->count * elt->size;
811 elt->save_offset = cur_offset;
818 pdump_scan_by_alignment (void (*f)(pdump_entry_list_elt *,
819 const struct lrecord_description *))
823 for (align = ALIGNOF (max_align_t); align; align>>=1)
826 pdump_entry_list_elt *elt;
828 for (i=0; i<lrecord_type_count; i++)
829 if (pdump_object_table[i].align == align)
830 for (elt = pdump_object_table[i].first; elt; elt = elt->next)
831 f (elt, lrecord_implementations_table[i]->description);
833 for (i=0; i<pdump_struct_table.count; i++)
835 pdump_struct_list_elt list = pdump_struct_table.list[i];
836 if (list.list.align == align)
837 for (elt = list.list.first; elt; elt = elt->next)
838 f (elt, list.sdesc->description);
841 for (elt = pdump_opaque_data_list.first; elt; elt = elt->next)
842 if (pdump_size_to_align (elt->size) == align)
848 pdump_dump_root_struct_ptrs (void)
851 size_t count = Dynarr_length (pdump_root_struct_ptrs);
852 pdump_static_pointer *data = alloca_array (pdump_static_pointer, count);
853 for (i = 0; i < count; i++)
855 data[i].address = (char **) Dynarr_atp (pdump_root_struct_ptrs, i)->ptraddress;
856 data[i].value = (char *) pdump_get_entry (* data[i].address)->save_offset;
858 PDUMP_ALIGN_OUTPUT (pdump_static_pointer);
859 fwrite (data, sizeof (pdump_static_pointer), count, pdump_out);
863 pdump_dump_opaques (void)
866 for (i = 0; i < Dynarr_length (pdump_opaques); i++)
868 pdump_opaque *info = Dynarr_atp (pdump_opaques, i);
869 PDUMP_WRITE_ALIGNED (pdump_opaque, *info);
870 fwrite (info->varaddress, info->size, 1, pdump_out);
875 pdump_dump_rtables (void)
878 pdump_entry_list_elt *elt;
879 pdump_reloc_table rt;
881 for (i=0; i<lrecord_type_count; i++)
883 elt = pdump_object_table[i].first;
886 rt.desc = lrecord_implementations_table[i]->description;
887 rt.count = pdump_object_table[i].count;
888 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt);
891 EMACS_INT rdata = pdump_get_entry (elt->obj)->save_offset;
892 PDUMP_WRITE_ALIGNED (EMACS_INT, rdata);
899 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt);
901 for (i=0; i<pdump_struct_table.count; i++)
903 elt = pdump_struct_table.list[i].list.first;
904 rt.desc = pdump_struct_table.list[i].sdesc->description;
905 rt.count = pdump_struct_table.list[i].list.count;
906 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt);
909 EMACS_INT rdata = pdump_get_entry (elt->obj)->save_offset;
911 for (j=0; j<elt->count; j++)
913 PDUMP_WRITE_ALIGNED (EMACS_INT, rdata);
921 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt);
925 pdump_dump_root_objects (void)
927 size_t count = (Dynarr_length (pdump_root_objects) +
928 Dynarr_length (pdump_weak_object_chains));
931 PDUMP_WRITE_ALIGNED (size_t, count);
932 PDUMP_ALIGN_OUTPUT (pdump_static_Lisp_Object);
934 for (i=0; i<Dynarr_length (pdump_root_objects); i++)
936 pdump_static_Lisp_Object obj;
937 obj.address = Dynarr_at (pdump_root_objects, i);
938 obj.value = * obj.address;
940 if (POINTER_TYPE_P (XTYPE (obj.value)))
941 obj.value = wrap_object ((void *) pdump_get_entry (XRECORD_LHEADER (obj.value))->save_offset);
943 PDUMP_WRITE (pdump_static_Lisp_Object, obj);
946 for (i=0; i<Dynarr_length (pdump_weak_object_chains); i++)
948 pdump_entry_list_elt *elt;
949 pdump_static_Lisp_Object obj;
951 obj.address = Dynarr_at (pdump_weak_object_chains, i);
952 obj.value = * obj.address;
956 const struct lrecord_description *desc;
958 elt = pdump_get_entry (XRECORD_LHEADER (obj.value));
961 desc = XRECORD_LHEADER_IMPLEMENTATION (obj.value)->description;
962 for (pos = 0; desc[pos].type != XD_LO_LINK; pos++)
963 assert (desc[pos].type != XD_END);
965 obj.value = *(Lisp_Object *)(desc[pos].offset + (char *)(XRECORD_LHEADER (obj.value)));
967 obj.value = wrap_object ((void *) elt->save_offset);
969 PDUMP_WRITE (pdump_static_Lisp_Object, obj);
977 Lisp_Object t_console, t_device, t_frame;
981 pdump_object_table = xnew_array (pdump_entry_list, lrecord_type_count);
982 pdump_alert_undump_object = xnew_array (int, lrecord_type_count);
984 assert (ALIGNOF (max_align_t) <= pdump_align_table[0]);
986 for (i = 0; i < countof (pdump_align_table); i++)
987 if (pdump_align_table[i] > ALIGNOF (max_align_t))
988 pdump_align_table[i] = ALIGNOF (max_align_t);
990 flush_all_buffer_local_cache ();
992 /* These appear in a DEFVAR_LISP, which does a staticpro() */
993 t_console = Vterminal_console; Vterminal_console = Qnil;
994 t_frame = Vterminal_frame; Vterminal_frame = Qnil;
995 t_device = Vterminal_device; Vterminal_device = Qnil;
997 dump_add_opaque (&lrecord_implementations_table,
998 lrecord_type_count * sizeof (lrecord_implementations_table[0]));
999 dump_add_opaque (&lrecord_markers,
1000 lrecord_type_count * sizeof (lrecord_markers[0]));
1002 pdump_hash = xnew_array_and_zero (pdump_entry_list_elt *, PDUMP_HASHSIZE);
1004 for (i=0; i<lrecord_type_count; i++)
1006 pdump_object_table[i].first = 0;
1007 pdump_object_table[i].align = ALIGNOF (max_align_t);
1008 pdump_object_table[i].count = 0;
1009 pdump_alert_undump_object[i] = 0;
1011 pdump_struct_table.count = 0;
1012 pdump_struct_table.size = -1;
1014 pdump_opaque_data_list.first = 0;
1015 pdump_opaque_data_list.align = ALIGNOF (max_align_t);
1016 pdump_opaque_data_list.count = 0;
1019 for (i=0; i<Dynarr_length (pdump_root_objects); i++)
1020 pdump_register_object (* Dynarr_at (pdump_root_objects, i));
1023 for (i=0; i<lrecord_type_count; i++)
1024 if (pdump_alert_undump_object[i])
1027 printf ("Undumpable types list :\n");
1029 printf (" - %s (%d)\n", lrecord_implementations_table[i]->name, pdump_alert_undump_object[i]);
1034 for (i=0; i<Dynarr_length (pdump_root_struct_ptrs); i++)
1036 pdump_root_struct_ptr info = Dynarr_at (pdump_root_struct_ptrs, i);
1037 pdump_register_struct (*(info.ptraddress), info.desc, 1);
1040 memcpy (header.signature, PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN);
1041 header.id = dump_id;
1042 header.reloc_address = 0;
1043 header.nb_root_struct_ptrs = Dynarr_length (pdump_root_struct_ptrs);
1044 header.nb_opaques = Dynarr_length (pdump_opaques);
1046 cur_offset = ALIGN_SIZE (sizeof (header), ALIGNOF (max_align_t));
1049 pdump_scan_by_alignment (pdump_allocate_offset);
1050 cur_offset = ALIGN_SIZE (cur_offset, ALIGNOF (max_align_t));
1051 header.stab_offset = cur_offset;
1053 pdump_buf = xmalloc (max_size);
1054 /* Avoid use of the `open' macro. We want the real function. */
1056 pdump_fd = open (EMACS_PROGNAME ".dmp",
1057 O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY, 0666);
1058 pdump_out = fdopen (pdump_fd, "w");
1060 fwrite (&header, sizeof (header), 1, pdump_out);
1061 PDUMP_ALIGN_OUTPUT (max_align_t);
1063 pdump_scan_by_alignment (pdump_dump_data);
1065 fseek (pdump_out, header.stab_offset, SEEK_SET);
1067 pdump_dump_root_struct_ptrs ();
1068 pdump_dump_opaques ();
1069 pdump_dump_rtables ();
1070 pdump_dump_root_objects ();
1079 Vterminal_console = t_console;
1080 Vterminal_frame = t_frame;
1081 Vterminal_device = t_device;
1085 pdump_load_check (void)
1087 return (!memcmp (((pdump_header *)pdump_start)->signature,
1088 PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN)
1089 && ((pdump_header *)pdump_start)->id == dump_id);
1092 /*----------------------------------------------------------------------*/
1093 /* Reading the dump file */
1094 /*----------------------------------------------------------------------*/
1096 pdump_load_finish (void)
1102 pdump_header *header = (pdump_header *)pdump_start;
1104 pdump_end = pdump_start + pdump_length;
1106 delta = ((EMACS_INT)pdump_start) - header->reloc_address;
1107 p = pdump_start + header->stab_offset;
1109 /* Put back the pdump_root_struct_ptrs */
1110 p = (char *) ALIGN_PTR (p, ALIGNOF (pdump_static_pointer));
1111 for (i=0; i<header->nb_root_struct_ptrs; i++)
1113 pdump_static_pointer ptr = PDUMP_READ (p, pdump_static_pointer);
1114 (* ptr.address) = ptr.value + delta;
1117 /* Put back the pdump_opaques */
1118 for (i=0; i<header->nb_opaques; i++)
1120 pdump_opaque info = PDUMP_READ_ALIGNED (p, pdump_opaque);
1121 memcpy (info.varaddress, p, info.size);
1125 /* Do the relocations */
1130 pdump_reloc_table rt = PDUMP_READ_ALIGNED (p, pdump_reloc_table);
1131 p = (char *) ALIGN_PTR (p, ALIGNOF (char *));
1134 char **reloc = (char **)p;
1135 for (i=0; i < rt.count; i++)
1138 pdump_reloc_one (reloc[i], delta, rt.desc);
1140 p += rt.count * sizeof (char *);
1146 /* Put the pdump_root_objects variables in place */
1147 i = PDUMP_READ_ALIGNED (p, size_t);
1148 p = (char *) ALIGN_PTR (p, ALIGNOF (pdump_static_Lisp_Object));
1151 pdump_static_Lisp_Object obj = PDUMP_READ (p, pdump_static_Lisp_Object);
1153 if (POINTER_TYPE_P (XTYPE (obj.value)))
1154 obj.value = wrap_object ((char *) XPNTR (obj.value) + delta);
1156 (* obj.address) = obj.value;
1159 /* Final cleanups */
1160 /* reorganize hash tables */
1164 pdump_reloc_table rt = PDUMP_READ_ALIGNED (p, pdump_reloc_table);
1165 p = (char *) ALIGN_PTR (p, ALIGNOF (Lisp_Object));
1168 if (rt.desc == hash_table_description)
1170 for (i=0; i < rt.count; i++)
1171 pdump_reorganize_hash_table (PDUMP_READ (p, Lisp_Object));
1174 p += sizeof (Lisp_Object) * rt.count;
1181 /* Free the mapped file if we decide we don't want it after all */
1183 pdump_file_unmap (void)
1185 UnmapViewOfFile (pdump_start);
1186 CloseHandle (pdump_hFile);
1187 CloseHandle (pdump_hMap);
1191 pdump_file_get (const char *path)
1194 pdump_hFile = CreateFile (path,
1195 GENERIC_READ + GENERIC_WRITE, /* Required for copy on write */
1197 NULL, /* Not inheritable */
1199 FILE_ATTRIBUTE_NORMAL,
1200 NULL); /* No template file */
1201 if (pdump_hFile == INVALID_HANDLE_VALUE)
1204 pdump_length = GetFileSize (pdump_hFile, NULL);
1205 pdump_hMap = CreateFileMapping (pdump_hFile,
1206 NULL, /* No security attributes */
1207 PAGE_WRITECOPY, /* Copy on write */
1208 0, /* Max size, high half */
1209 0, /* Max size, low half */
1210 NULL); /* Unnamed */
1211 if (pdump_hMap == INVALID_HANDLE_VALUE)
1214 pdump_start = MapViewOfFile (pdump_hMap,
1215 FILE_MAP_COPY, /* Copy on write */
1216 0, /* Start at zero */
1218 0); /* Map all of it */
1219 pdump_free = pdump_file_unmap;
1223 /* pdump_resource_free is called (via the pdump_free pointer) to release
1224 any resources allocated by pdump_resource_get. Since the Windows API
1225 specs specifically state that you don't need to (and shouldn't) free the
1226 resources allocated by FindResource, LoadResource, and LockResource this
1227 routine does nothing. */
1229 pdump_resource_free (void)
1234 pdump_resource_get (void)
1236 HRSRC hRes; /* Handle to dump resource */
1237 HRSRC hResLoad; /* Handle to loaded dump resource */
1239 /* See Q126630 which describes how Windows NT and 95 trap writes to
1240 resource sections and duplicate the page to allow the write to proceed.
1241 It also describes how to make the resource section read/write (and hence
1242 private to each process). Doing this avoids the exceptions and related
1243 overhead, but causes the resource section to be private to each process
1244 that is running XEmacs. Since the resource section contains little
1245 other than the dumped data, which should be private to each process, we
1246 make the whole resource section read/write so we don't have to copy it. */
1248 hRes = FindResource (NULL, MAKEINTRESOURCE(101), "DUMP");
1252 /* Found it, use the data in the resource */
1253 hResLoad = LoadResource (NULL, hRes);
1254 if (hResLoad == NULL)
1257 pdump_start = LockResource (hResLoad);
1258 if (pdump_start == NULL)
1261 pdump_free = pdump_resource_free;
1262 pdump_length = SizeofResource (NULL, hRes);
1263 if (pdump_length <= sizeof (pdump_header))
1272 #else /* !WIN32_NATIVE */
1275 pdump_file_free (void)
1277 xfree (pdump_start);
1282 pdump_file_unmap (void)
1284 munmap (pdump_start, pdump_length);
1289 pdump_file_get (const char *path)
1291 int fd = open (path, O_RDONLY | OPEN_BINARY);
1295 pdump_length = lseek (fd, 0, SEEK_END);
1296 if (pdump_length < sizeof (pdump_header))
1302 lseek (fd, 0, SEEK_SET);
1305 /* Unix 98 requires that sys/mman.h define MAP_FAILED,
1306 but many earlier implementations don't. */
1308 # define MAP_FAILED ((void *) -1L)
1310 pdump_start = (char *) mmap (0, pdump_length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
1311 if (pdump_start != (char *) MAP_FAILED)
1313 pdump_free = pdump_file_unmap;
1317 #endif /* HAVE_MMAP */
1319 pdump_start = xnew_array (char, pdump_length);
1320 pdump_free = pdump_file_free;
1321 read (fd, pdump_start, pdump_length);
1326 #endif /* !WIN32_NATIVE */
1330 pdump_file_try (char *exe_path)
1332 char *w = exe_path + strlen (exe_path);
1336 sprintf (w, "-%s-%08x.dmp", EMACS_VERSION, dump_id);
1337 if (pdump_file_get (exe_path))
1339 if (pdump_load_check ())
1344 sprintf (w, "-%08x.dmp", dump_id);
1345 if (pdump_file_get (exe_path))
1347 if (pdump_load_check ())
1352 sprintf (w, ".dmp");
1353 if (pdump_file_get (exe_path))
1355 if (pdump_load_check ())
1362 while (w>exe_path && !IS_DIRECTORY_SEP (*w) && (*w != '-') && (*w != '.'));
1364 while (w>exe_path && !IS_DIRECTORY_SEP (*w));
1369 pdump_load (const char *argv0)
1371 char exe_path[PATH_MAX];
1373 GetModuleFileName (NULL, exe_path, PATH_MAX);
1374 #else /* !WIN32_NATIVE */
1376 const char *dir, *p;
1381 /* XEmacs as a login shell, oh goody! */
1382 dir = getenv ("SHELL");
1385 p = dir + strlen (dir);
1386 while (p != dir && !IS_ANY_SEP (p[-1])) p--;
1390 /* invocation-name includes a directory component -- presumably it
1391 is relative to cwd, not $PATH */
1392 strcpy (exe_path, dir);
1396 const char *path = getenv ("PATH");
1397 const char *name = p;
1401 while (*p && *p != SEPCHAR)
1410 memcpy (exe_path, path, p - path);
1411 w = exe_path + (p - path);
1413 if (!IS_DIRECTORY_SEP (w[-1]))
1419 /* ### #$%$#^$^@%$^#%@$ ! */
1424 if (!access (exe_path, X_OK))
1428 /* Oh well, let's have some kind of default */
1429 sprintf (exe_path, "./%s", name);
1435 #endif /* WIN32_NATIVE */
1437 if (pdump_file_try (exe_path))
1439 pdump_load_finish ();
1444 if (pdump_resource_get ())
1446 if (pdump_load_check ())
1448 pdump_load_finish ();