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"
54 Dynarr_declare (pdump_opaque);
55 } pdump_opaque_dynarr;
60 const struct struct_description *desc;
61 } pdump_root_struct_ptr;
65 Dynarr_declare (pdump_root_struct_ptr);
66 } pdump_root_struct_ptr_dynarr;
72 } pdump_static_Lisp_Object;
76 char **address; /* char * for ease of doing relocation */
78 } pdump_static_pointer;
80 static pdump_opaque_dynarr *pdump_opaques;
81 static pdump_root_struct_ptr_dynarr *pdump_root_struct_ptrs;
82 static Lisp_Object_ptr_dynarr *pdump_root_objects;
83 static Lisp_Object_ptr_dynarr *pdump_weak_object_chains;
85 /* Mark SIZE bytes at non-heap address VARADDRESS for dumping as is,
86 without any bit-twiddling. */
88 dump_add_opaque (void *varaddress, size_t size)
91 info.varaddress = varaddress;
93 if (pdump_opaques == NULL)
94 pdump_opaques = Dynarr_new (pdump_opaque);
95 Dynarr_add (pdump_opaques, info);
98 /* Mark the struct described by DESC and pointed to by the pointer at
99 non-heap address VARADDRESS for dumping.
100 All the objects reachable from this pointer will also be dumped. */
102 dump_add_root_struct_ptr (void *ptraddress, const struct struct_description *desc)
104 pdump_root_struct_ptr info;
105 info.ptraddress = (void **) ptraddress;
107 if (pdump_root_struct_ptrs == NULL)
108 pdump_root_struct_ptrs = Dynarr_new (pdump_root_struct_ptr);
109 Dynarr_add (pdump_root_struct_ptrs, info);
112 /* Mark the Lisp_Object at non-heap address VARADDRESS for dumping.
113 All the objects reachable from this var will also be dumped. */
115 dump_add_root_object (Lisp_Object *varaddress)
117 if (pdump_root_objects == NULL)
118 pdump_root_objects = Dynarr_new2 (Lisp_Object_ptr_dynarr, Lisp_Object *);
119 Dynarr_add (pdump_root_objects, varaddress);
122 /* Mark the list pointed to by the Lisp_Object at VARADDRESS for dumping. */
124 dump_add_weak_object_chain (Lisp_Object *varaddress)
126 if (pdump_weak_object_chains == NULL)
127 pdump_weak_object_chains = Dynarr_new2 (Lisp_Object_ptr_dynarr, Lisp_Object *);
128 Dynarr_add (pdump_weak_object_chains, varaddress);
133 pdump_align_stream (FILE *stream, size_t alignment)
135 long offset = ftell (stream);
136 long adjustment = ALIGN_SIZE (offset, alignment) - offset;
138 fseek (stream, adjustment, SEEK_CUR);
141 #define PDUMP_ALIGN_OUTPUT(type) pdump_align_stream (pdump_out, ALIGNOF (type))
143 #define PDUMP_WRITE(type, object) \
144 fwrite (&object, sizeof (object), 1, pdump_out);
146 #define PDUMP_WRITE_ALIGNED(type, object) do { \
147 PDUMP_ALIGN_OUTPUT (type); \
148 PDUMP_WRITE (type, object); \
151 #define PDUMP_READ(ptr, type) \
152 (((type *) (ptr = (char*) (((type *) ptr) + 1)))[-1])
154 #define PDUMP_READ_ALIGNED(ptr, type) \
155 ((ptr = (char *) ALIGN_PTR (ptr, ALIGNOF (type))), PDUMP_READ (ptr, type))
161 const struct lrecord_description *desc;
165 static char *pdump_rt_list = 0;
168 pdump_objects_unmark (void)
171 char *p = pdump_rt_list;
175 pdump_reloc_table *rt = (pdump_reloc_table *)p;
176 p += sizeof (pdump_reloc_table);
179 for (i=0; i<rt->count; i++)
181 struct lrecord_header *lh = * (struct lrecord_header **) p;
182 if (! C_READONLY_RECORD_HEADER_P (lh))
183 UNMARK_RECORD_HEADER (lh);
184 p += sizeof (EMACS_INT);
192 /* The structure of the file
195 stab_offset - nb_root_struct_ptrs*pair(void *, adr)
196 for pointers to structures
197 - nb_opaques*pair(void *, size) for raw bits to restore
199 - root lisp object address/value couples with the count
204 #define PDUMP_SIGNATURE "XEmacsDP"
205 #define PDUMP_SIGNATURE_LEN (sizeof (PDUMP_SIGNATURE) - 1)
209 char signature[PDUMP_SIGNATURE_LEN];
211 EMACS_UINT stab_offset;
212 EMACS_UINT reloc_address;
213 int nb_root_struct_ptrs;
219 static size_t pdump_length;
222 /* Handle for the dump file */
223 static HANDLE pdump_hFile = INVALID_HANDLE_VALUE;
224 /* Handle for the file mapping object for the dump file */
225 static HANDLE pdump_hMap = INVALID_HANDLE_VALUE;
228 static void (*pdump_free) (void);
230 static unsigned char pdump_align_table[] =
232 64, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
233 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
234 32, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
235 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1
238 static inline unsigned int
239 pdump_size_to_align (size_t size)
241 return pdump_align_table[size % countof (pdump_align_table)];
244 typedef struct pdump_entry_list_elt
246 struct pdump_entry_list_elt *next;
250 EMACS_INT save_offset;
251 } pdump_entry_list_elt;
255 pdump_entry_list_elt *first;
260 typedef struct pdump_struct_list_elt
262 pdump_entry_list list;
263 const struct struct_description *sdesc;
264 } pdump_struct_list_elt;
268 pdump_struct_list_elt *list;
273 static pdump_entry_list *pdump_object_table;
274 static pdump_entry_list pdump_opaque_data_list;
275 static pdump_struct_list pdump_struct_table;
277 static int *pdump_alert_undump_object;
279 static unsigned long cur_offset;
280 static size_t max_size;
282 static void *pdump_buf;
283 static FILE *pdump_out;
286 #define PDUMP_HASHSIZE 20000001
288 #define PDUMP_HASHSIZE 200001
291 static pdump_entry_list_elt **pdump_hash;
293 /* Since most pointers are eight bytes aligned, the >>3 allows for a better hash */
295 pdump_make_hash (const void *obj)
297 return ((unsigned long)(obj)>>3) % PDUMP_HASHSIZE;
300 static pdump_entry_list_elt *
301 pdump_get_entry (const void *obj)
303 int pos = pdump_make_hash (obj);
304 pdump_entry_list_elt *e;
308 while ((e = pdump_hash[pos]) != 0)
314 if (pos == PDUMP_HASHSIZE)
321 pdump_add_entry (pdump_entry_list *list, const void *obj, size_t size,
324 pdump_entry_list_elt *e;
325 int pos = pdump_make_hash (obj);
327 while ((e = pdump_hash[pos]) != 0)
333 if (pos == PDUMP_HASHSIZE)
337 e = xnew (pdump_entry_list_elt);
339 e->next = list->first;
345 list->count += count;
349 int align = pdump_size_to_align (size);
351 if (align < list->align)
356 static pdump_entry_list *
357 pdump_get_entry_list (const struct struct_description *sdesc)
360 for (i=0; i<pdump_struct_table.count; i++)
361 if (pdump_struct_table.list[i].sdesc == sdesc)
362 return &pdump_struct_table.list[i].list;
364 if (pdump_struct_table.size <= pdump_struct_table.count)
366 if (pdump_struct_table.size == -1)
367 pdump_struct_table.size = 10;
369 pdump_struct_table.size = pdump_struct_table.size * 2;
370 pdump_struct_table.list = (pdump_struct_list_elt *)
371 xrealloc (pdump_struct_table.list,
372 pdump_struct_table.size * sizeof (pdump_struct_list_elt));
374 pdump_struct_table.list[pdump_struct_table.count].list.first = 0;
375 pdump_struct_table.list[pdump_struct_table.count].list.align = ALIGNOF (max_align_t);
376 pdump_struct_table.list[pdump_struct_table.count].list.count = 0;
377 pdump_struct_table.list[pdump_struct_table.count].sdesc = sdesc;
379 return &pdump_struct_table.list[pdump_struct_table.count++].list;
384 struct lrecord_header *obj;
392 pdump_backtrace (void)
395 stderr_out ("pdump backtrace :\n");
396 for (i=0;i<depth;i++)
398 if (!backtrace[i].obj)
399 stderr_out (" - ind. (%d, %d)\n",
400 backtrace[i].position,
401 backtrace[i].offset);
404 stderr_out (" - %s (%d, %d)\n",
405 LHEADER_IMPLEMENTATION (backtrace[i].obj)->name,
406 backtrace[i].position,
407 backtrace[i].offset);
412 static void pdump_register_object (Lisp_Object obj);
413 static void pdump_register_struct (const void *data,
414 const struct struct_description *sdesc,
418 pdump_get_indirect_count (EMACS_INT code,
419 const struct lrecord_description *idesc,
422 EMACS_INT count = 0; /* initialize to shut up GCC */
425 int line = XD_INDIRECT_VAL (code);
426 int delta = XD_INDIRECT_DELTA (code);
428 irdata = ((char *)idata) + idesc[line].offset;
429 switch (idesc[line].type)
432 count = *(size_t *)irdata;
435 count = *(int *)irdata;
438 count = *(long *)irdata;
441 count = *(Bytecount *)irdata;
444 stderr_out ("Unsupported count type : %d (line = %d, code=%ld)\n",
445 idesc[line].type, line, (long)code);
454 pdump_register_sub (const void *data, const struct lrecord_description *desc, int me)
459 for (pos = 0; desc[pos].type != XD_END; pos++)
461 const void *rdata = (const char *)data + desc[pos].offset;
463 backtrace[me].position = pos;
464 backtrace[me].offset = desc[pos].offset;
466 switch (desc[pos].type)
468 case XD_SPECIFIER_END:
470 desc = ((const Lisp_Specifier *)data)->methods->extra_description;
479 case XD_OPAQUE_DATA_PTR:
481 EMACS_INT count = desc[pos].data1;
482 if (XD_IS_INDIRECT (count))
483 count = pdump_get_indirect_count (count, desc, data);
485 pdump_add_entry (&pdump_opaque_data_list,
486 *(void **)rdata, count, 1);
491 const char *str = *(const char **)rdata;
493 pdump_add_entry (&pdump_opaque_data_list, str, strlen (str)+1, 1);
498 const char *str = *(const char **)rdata;
499 if ((EMACS_INT)str > 0)
500 pdump_add_entry (&pdump_opaque_data_list, str, strlen (str)+1, 1);
505 const Lisp_Object *pobj = (const Lisp_Object *)rdata;
507 assert (desc[pos].data1 == 0);
509 backtrace[me].offset = (const char *)pobj - (const char *)data;
510 pdump_register_object (*pobj);
513 case XD_LISP_OBJECT_ARRAY:
516 EMACS_INT count = desc[pos].data1;
517 if (XD_IS_INDIRECT (count))
518 count = pdump_get_indirect_count (count, desc, data);
520 for (i = 0; i < count; i++)
522 const Lisp_Object *pobj = ((const Lisp_Object *)rdata) + i;
523 Lisp_Object dobj = *pobj;
525 backtrace[me].offset = (const char *)pobj - (const char *)data;
526 pdump_register_object (dobj);
532 EMACS_INT count = desc[pos].data1;
533 const struct struct_description *sdesc = desc[pos].data2;
534 const char *dobj = *(const char **)rdata;
537 if (XD_IS_INDIRECT (count))
538 count = pdump_get_indirect_count (count, desc, data);
540 pdump_register_struct (dobj, sdesc, count);
545 stderr_out ("Unsupported dump type : %d\n", desc[pos].type);
553 pdump_register_object (Lisp_Object obj)
555 struct lrecord_header *objh;
556 const struct lrecord_implementation *imp;
558 if (!POINTER_TYPE_P (XTYPE (obj)))
561 objh = XRECORD_LHEADER (obj);
565 if (pdump_get_entry (objh))
568 imp = LHEADER_IMPLEMENTATION (objh);
570 if (imp->description)
575 stderr_out ("Backtrace overflow, loop ?\n");
578 backtrace[me].obj = objh;
579 backtrace[me].position = 0;
580 backtrace[me].offset = 0;
582 pdump_add_entry (pdump_object_table + objh->type,
586 imp->size_in_bytes_method (objh),
588 pdump_register_sub (objh, imp->description, me);
593 pdump_alert_undump_object[objh->type]++;
594 stderr_out ("Undumpable object type : %s\n", imp->name);
600 pdump_register_struct (const void *data,
601 const struct struct_description *sdesc,
604 if (data && !pdump_get_entry (data))
610 stderr_out ("Backtrace overflow, loop ?\n");
613 backtrace[me].obj = 0;
614 backtrace[me].position = 0;
615 backtrace[me].offset = 0;
617 pdump_add_entry (pdump_get_entry_list (sdesc),
618 data, sdesc->size, count);
619 for (i=0; i<count; i++)
621 pdump_register_sub (((char *)data) + sdesc->size*i,
630 pdump_dump_data (pdump_entry_list_elt *elt,
631 const struct lrecord_description *desc)
633 size_t size = elt->size;
634 int count = elt->count;
638 memcpy (pdump_buf, elt->obj, size*count);
640 for (i=0; i<count; i++)
642 char *cur = ((char *)pdump_buf) + i*size;
644 for (pos = 0; desc[pos].type != XD_END; pos++)
646 void *rdata = cur + desc[pos].offset;
647 switch (desc[pos].type)
649 case XD_SPECIFIER_END:
650 desc = ((const Lisp_Specifier *)(elt->obj))->methods->extra_description;
659 EMACS_INT val = desc[pos].data1;
660 if (XD_IS_INDIRECT (val))
661 val = pdump_get_indirect_count (val, desc, elt->obj);
665 case XD_OPAQUE_DATA_PTR:
669 void *ptr = *(void **)rdata;
671 *(EMACS_INT *)rdata = pdump_get_entry (ptr)->save_offset;
676 Lisp_Object obj = *(Lisp_Object *)rdata;
677 pdump_entry_list_elt *elt1;
680 elt1 = pdump_get_entry (XRECORD_LHEADER (obj));
683 obj = *(Lisp_Object *)(desc[pos].offset + (char *)(XRECORD_LHEADER (obj)));
685 *(EMACS_INT *)rdata = elt1->save_offset;
690 Lisp_Object *pobj = (Lisp_Object *) rdata;
692 assert (desc[pos].data1 == 0);
694 if (POINTER_TYPE_P (XTYPE (*pobj)) && XRECORD_LHEADER (*pobj))
696 pdump_get_entry (XRECORD_LHEADER (*pobj))->save_offset;
699 case XD_LISP_OBJECT_ARRAY:
701 EMACS_INT num = desc[pos].data1;
703 if (XD_IS_INDIRECT (num))
704 num = pdump_get_indirect_count (num, desc, elt->obj);
706 for (j=0; j<num; j++)
708 Lisp_Object *pobj = ((Lisp_Object *)rdata) + j;
709 if (POINTER_TYPE_P (XTYPE (*pobj)) && XRECORD_LHEADER (*pobj))
711 pdump_get_entry (XRECORD_LHEADER (*pobj))->save_offset;
717 EMACS_INT str = *(EMACS_INT *)rdata;
719 *(EMACS_INT *)rdata = pdump_get_entry ((void *)str)->save_offset;
723 stderr_out ("Unsupported dump type : %d\n", desc[pos].type);
729 fwrite (desc ? pdump_buf : elt->obj, size, count, pdump_out);
733 pdump_reloc_one (void *data, EMACS_INT delta,
734 const struct lrecord_description *desc)
739 for (pos = 0; desc[pos].type != XD_END; pos++)
741 void *rdata = (char *)data + desc[pos].offset;
742 switch (desc[pos].type)
744 case XD_SPECIFIER_END:
746 desc = ((const Lisp_Specifier *)data)->methods->extra_description;
754 case XD_OPAQUE_DATA_PTR:
759 EMACS_INT ptr = *(EMACS_INT *)rdata;
761 *(EMACS_INT *)rdata = ptr+delta;
766 Lisp_Object *pobj = (Lisp_Object *) rdata;
768 assert (desc[pos].data1 == 0);
770 if (POINTER_TYPE_P (XTYPE (*pobj))
771 && ! EQ (*pobj, Qnull_pointer))
772 XSETOBJ (*pobj, (char *) XPNTR (*pobj) + delta);
776 case XD_LISP_OBJECT_ARRAY:
778 EMACS_INT num = desc[pos].data1;
780 if (XD_IS_INDIRECT (num))
781 num = pdump_get_indirect_count (num, desc, data);
783 for (j=0; j<num; j++)
785 Lisp_Object *pobj = (Lisp_Object *) rdata + j;
787 if (POINTER_TYPE_P (XTYPE (*pobj))
788 && ! EQ (*pobj, Qnull_pointer))
789 XSETOBJ (*pobj, (char *) XPNTR (*pobj) + delta);
795 EMACS_INT str = *(EMACS_INT *)rdata;
797 *(EMACS_INT *)rdata = str + delta;
801 stderr_out ("Unsupported dump type : %d\n", desc[pos].type);
808 pdump_allocate_offset (pdump_entry_list_elt *elt,
809 const struct lrecord_description *desc)
811 size_t size = elt->count * elt->size;
812 elt->save_offset = cur_offset;
819 pdump_scan_by_alignment (void (*f)(pdump_entry_list_elt *,
820 const struct lrecord_description *))
824 for (align = ALIGNOF (max_align_t); align; align>>=1)
827 pdump_entry_list_elt *elt;
829 for (i=0; i<lrecord_type_count; i++)
830 if (pdump_object_table[i].align == align)
831 for (elt = pdump_object_table[i].first; elt; elt = elt->next)
832 f (elt, lrecord_implementations_table[i]->description);
834 for (i=0; i<pdump_struct_table.count; i++)
836 pdump_struct_list_elt list = pdump_struct_table.list[i];
837 if (list.list.align == align)
838 for (elt = list.list.first; elt; elt = elt->next)
839 f (elt, list.sdesc->description);
842 for (elt = pdump_opaque_data_list.first; elt; elt = elt->next)
843 if (pdump_size_to_align (elt->size) == align)
849 pdump_dump_root_struct_ptrs (void)
852 size_t count = Dynarr_length (pdump_root_struct_ptrs);
853 pdump_static_pointer *data = alloca_array (pdump_static_pointer, count);
854 for (i = 0; i < count; i++)
856 data[i].address = (char **) Dynarr_atp (pdump_root_struct_ptrs, i)->ptraddress;
857 data[i].value = (char *) pdump_get_entry (* data[i].address)->save_offset;
859 PDUMP_ALIGN_OUTPUT (pdump_static_pointer);
860 fwrite (data, sizeof (pdump_static_pointer), count, pdump_out);
864 pdump_dump_opaques (void)
867 for (i = 0; i < Dynarr_length (pdump_opaques); i++)
869 pdump_opaque *info = Dynarr_atp (pdump_opaques, i);
870 PDUMP_WRITE_ALIGNED (pdump_opaque, *info);
871 fwrite (info->varaddress, info->size, 1, pdump_out);
876 pdump_dump_rtables (void)
879 pdump_entry_list_elt *elt;
880 pdump_reloc_table rt;
882 for (i=0; i<lrecord_type_count; i++)
884 elt = pdump_object_table[i].first;
887 rt.desc = lrecord_implementations_table[i]->description;
888 rt.count = pdump_object_table[i].count;
889 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt);
892 EMACS_INT rdata = pdump_get_entry (elt->obj)->save_offset;
893 PDUMP_WRITE_ALIGNED (EMACS_INT, rdata);
900 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt);
902 for (i=0; i<pdump_struct_table.count; i++)
904 elt = pdump_struct_table.list[i].list.first;
905 rt.desc = pdump_struct_table.list[i].sdesc->description;
906 rt.count = pdump_struct_table.list[i].list.count;
907 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt);
910 EMACS_INT rdata = pdump_get_entry (elt->obj)->save_offset;
912 for (j=0; j<elt->count; j++)
914 PDUMP_WRITE_ALIGNED (EMACS_INT, rdata);
922 PDUMP_WRITE_ALIGNED (pdump_reloc_table, rt);
926 pdump_dump_root_objects (void)
928 size_t count = (Dynarr_length (pdump_root_objects) +
929 Dynarr_length (pdump_weak_object_chains));
932 PDUMP_WRITE_ALIGNED (size_t, count);
933 PDUMP_ALIGN_OUTPUT (pdump_static_Lisp_Object);
935 for (i=0; i<Dynarr_length (pdump_root_objects); i++)
937 pdump_static_Lisp_Object obj;
938 obj.address = Dynarr_at (pdump_root_objects, i);
939 obj.value = * obj.address;
941 if (POINTER_TYPE_P (XTYPE (obj.value)))
942 obj.value = wrap_object ((void *) pdump_get_entry (XRECORD_LHEADER (obj.value))->save_offset);
944 PDUMP_WRITE (pdump_static_Lisp_Object, obj);
947 for (i=0; i<Dynarr_length (pdump_weak_object_chains); i++)
949 pdump_entry_list_elt *elt;
950 pdump_static_Lisp_Object obj;
952 obj.address = Dynarr_at (pdump_weak_object_chains, i);
953 obj.value = * obj.address;
957 const struct lrecord_description *desc;
959 elt = pdump_get_entry (XRECORD_LHEADER (obj.value));
962 desc = XRECORD_LHEADER_IMPLEMENTATION (obj.value)->description;
963 for (pos = 0; desc[pos].type != XD_LO_LINK; pos++)
964 assert (desc[pos].type != XD_END);
966 obj.value = *(Lisp_Object *)(desc[pos].offset + (char *)(XRECORD_LHEADER (obj.value)));
968 obj.value = wrap_object ((void *) elt->save_offset);
970 PDUMP_WRITE (pdump_static_Lisp_Object, obj);
978 Lisp_Object t_console, t_device, t_frame;
982 pdump_object_table = xnew_array (pdump_entry_list, lrecord_type_count);
983 pdump_alert_undump_object = xnew_array (int, lrecord_type_count);
985 assert (ALIGNOF (max_align_t) <= pdump_align_table[0]);
987 for (i = 0; i < countof (pdump_align_table); i++)
988 if (pdump_align_table[i] > ALIGNOF (max_align_t))
989 pdump_align_table[i] = ALIGNOF (max_align_t);
991 flush_all_buffer_local_cache ();
993 /* These appear in a DEFVAR_LISP, which does a staticpro() */
994 t_console = Vterminal_console; Vterminal_console = Qnil;
995 t_frame = Vterminal_frame; Vterminal_frame = Qnil;
996 t_device = Vterminal_device; Vterminal_device = Qnil;
998 dump_add_opaque ((void *) &lrecord_implementations_table,
999 lrecord_type_count * sizeof (lrecord_implementations_table[0]));
1000 dump_add_opaque (&lrecord_markers,
1001 lrecord_type_count * sizeof (lrecord_markers[0]));
1003 pdump_hash = xnew_array_and_zero (pdump_entry_list_elt *, PDUMP_HASHSIZE);
1005 for (i=0; i<lrecord_type_count; i++)
1007 pdump_object_table[i].first = 0;
1008 pdump_object_table[i].align = ALIGNOF (max_align_t);
1009 pdump_object_table[i].count = 0;
1010 pdump_alert_undump_object[i] = 0;
1012 pdump_struct_table.count = 0;
1013 pdump_struct_table.size = -1;
1015 pdump_opaque_data_list.first = 0;
1016 pdump_opaque_data_list.align = ALIGNOF (max_align_t);
1017 pdump_opaque_data_list.count = 0;
1020 for (i=0; i<Dynarr_length (pdump_root_objects); i++)
1021 pdump_register_object (* Dynarr_at (pdump_root_objects, i));
1024 for (i=0; i<lrecord_type_count; i++)
1025 if (pdump_alert_undump_object[i])
1028 printf ("Undumpable types list :\n");
1030 printf (" - %s (%d)\n", lrecord_implementations_table[i]->name, pdump_alert_undump_object[i]);
1035 for (i=0; i<(size_t)Dynarr_length (pdump_root_struct_ptrs); i++)
1037 pdump_root_struct_ptr info = Dynarr_at (pdump_root_struct_ptrs, i);
1038 pdump_register_struct (*(info.ptraddress), info.desc, 1);
1041 memcpy (header.signature, PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN);
1042 header.id = dump_id;
1043 header.reloc_address = 0;
1044 header.nb_root_struct_ptrs = Dynarr_length (pdump_root_struct_ptrs);
1045 header.nb_opaques = Dynarr_length (pdump_opaques);
1047 cur_offset = ALIGN_SIZE (sizeof (header), ALIGNOF (max_align_t));
1050 pdump_scan_by_alignment (pdump_allocate_offset);
1051 cur_offset = ALIGN_SIZE (cur_offset, ALIGNOF (max_align_t));
1052 header.stab_offset = cur_offset;
1054 pdump_buf = xmalloc (max_size);
1055 /* Avoid use of the `open' macro. We want the real function. */
1057 pdump_fd = open (EMACS_PROGNAME ".dmp",
1058 O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY, 0666);
1059 pdump_out = fdopen (pdump_fd, "w");
1061 fwrite (&header, sizeof (header), 1, pdump_out);
1062 PDUMP_ALIGN_OUTPUT (max_align_t);
1064 pdump_scan_by_alignment (pdump_dump_data);
1066 fseek (pdump_out, header.stab_offset, SEEK_SET);
1068 pdump_dump_root_struct_ptrs ();
1069 pdump_dump_opaques ();
1070 pdump_dump_rtables ();
1071 pdump_dump_root_objects ();
1080 Vterminal_console = t_console;
1081 Vterminal_frame = t_frame;
1082 Vterminal_device = t_device;
1086 pdump_load_check (void)
1088 return (!memcmp (((pdump_header *)pdump_start)->signature,
1089 PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN)
1090 && ((pdump_header *)pdump_start)->id == dump_id);
1093 /*----------------------------------------------------------------------*/
1094 /* Reading the dump file */
1095 /*----------------------------------------------------------------------*/
1097 pdump_load_finish (void)
1103 pdump_header *header = (pdump_header *)pdump_start;
1105 pdump_end = pdump_start + pdump_length;
1107 delta = ((EMACS_INT)pdump_start) - header->reloc_address;
1108 p = pdump_start + header->stab_offset;
1110 /* Put back the pdump_root_struct_ptrs */
1111 p = (char *) ALIGN_PTR (p, ALIGNOF (pdump_static_pointer));
1112 for (i=0; i<header->nb_root_struct_ptrs; i++)
1114 pdump_static_pointer ptr = PDUMP_READ (p, pdump_static_pointer);
1115 (* ptr.address) = ptr.value + delta;
1118 /* Put back the pdump_opaques */
1119 for (i=0; i<header->nb_opaques; i++)
1121 pdump_opaque info = PDUMP_READ_ALIGNED (p, pdump_opaque);
1122 memcpy (info.varaddress, p, info.size);
1126 /* Do the relocations */
1131 pdump_reloc_table rt = PDUMP_READ_ALIGNED (p, pdump_reloc_table);
1132 p = (char *) ALIGN_PTR (p, ALIGNOF (char *));
1135 char **reloc = (char **)p;
1136 for (i=0; i < rt.count; i++)
1139 pdump_reloc_one (reloc[i], delta, rt.desc);
1141 p += rt.count * sizeof (char *);
1147 /* Put the pdump_root_objects variables in place */
1148 i = PDUMP_READ_ALIGNED (p, size_t);
1149 p = (char *) ALIGN_PTR (p, ALIGNOF (pdump_static_Lisp_Object));
1152 pdump_static_Lisp_Object obj = PDUMP_READ (p, pdump_static_Lisp_Object);
1154 if (POINTER_TYPE_P (XTYPE (obj.value)))
1155 obj.value = wrap_object ((char *) XPNTR (obj.value) + delta);
1157 (* obj.address) = obj.value;
1160 /* Final cleanups */
1161 /* reorganize hash tables */
1165 pdump_reloc_table rt = PDUMP_READ_ALIGNED (p, pdump_reloc_table);
1166 p = (char *) ALIGN_PTR (p, ALIGNOF (Lisp_Object));
1169 if (rt.desc == hash_table_description)
1171 for (i=0; i < rt.count; i++)
1172 pdump_reorganize_hash_table (PDUMP_READ (p, Lisp_Object));
1175 p += sizeof (Lisp_Object) * rt.count;
1182 /* Free the mapped file if we decide we don't want it after all */
1184 pdump_file_unmap (void)
1186 UnmapViewOfFile (pdump_start);
1187 CloseHandle (pdump_hFile);
1188 CloseHandle (pdump_hMap);
1192 pdump_file_get (const char *path)
1195 pdump_hFile = CreateFile (path,
1196 GENERIC_READ + GENERIC_WRITE, /* Required for copy on write */
1198 NULL, /* Not inheritable */
1200 FILE_ATTRIBUTE_NORMAL,
1201 NULL); /* No template file */
1202 if (pdump_hFile == INVALID_HANDLE_VALUE)
1205 pdump_length = GetFileSize (pdump_hFile, NULL);
1206 pdump_hMap = CreateFileMapping (pdump_hFile,
1207 NULL, /* No security attributes */
1208 PAGE_WRITECOPY, /* Copy on write */
1209 0, /* Max size, high half */
1210 0, /* Max size, low half */
1211 NULL); /* Unnamed */
1212 if (pdump_hMap == INVALID_HANDLE_VALUE)
1215 pdump_start = MapViewOfFile (pdump_hMap,
1216 FILE_MAP_COPY, /* Copy on write */
1217 0, /* Start at zero */
1219 0); /* Map all of it */
1220 pdump_free = pdump_file_unmap;
1224 /* pdump_resource_free is called (via the pdump_free pointer) to release
1225 any resources allocated by pdump_resource_get. Since the Windows API
1226 specs specifically state that you don't need to (and shouldn't) free the
1227 resources allocated by FindResource, LoadResource, and LockResource this
1228 routine does nothing. */
1230 pdump_resource_free (void)
1235 pdump_resource_get (void)
1237 HRSRC hRes; /* Handle to dump resource */
1238 HRSRC hResLoad; /* Handle to loaded dump resource */
1240 /* See Q126630 which describes how Windows NT and 95 trap writes to
1241 resource sections and duplicate the page to allow the write to proceed.
1242 It also describes how to make the resource section read/write (and hence
1243 private to each process). Doing this avoids the exceptions and related
1244 overhead, but causes the resource section to be private to each process
1245 that is running XEmacs. Since the resource section contains little
1246 other than the dumped data, which should be private to each process, we
1247 make the whole resource section read/write so we don't have to copy it. */
1249 hRes = FindResource (NULL, MAKEINTRESOURCE(101), "DUMP");
1253 /* Found it, use the data in the resource */
1254 hResLoad = LoadResource (NULL, hRes);
1255 if (hResLoad == NULL)
1258 pdump_start = LockResource (hResLoad);
1259 if (pdump_start == NULL)
1262 pdump_free = pdump_resource_free;
1263 pdump_length = SizeofResource (NULL, hRes);
1264 if (pdump_length <= sizeof (pdump_header))
1273 #else /* !WIN32_NATIVE */
1276 pdump_file_free (void)
1278 xfree (pdump_start);
1283 pdump_file_unmap (void)
1285 munmap (pdump_start, pdump_length);
1290 pdump_file_get (const char *path)
1292 int fd = open (path, O_RDONLY | OPEN_BINARY);
1296 pdump_length = lseek (fd, 0, SEEK_END);
1297 if (pdump_length < sizeof (pdump_header))
1303 lseek (fd, 0, SEEK_SET);
1306 /* Unix 98 requires that sys/mman.h define MAP_FAILED,
1307 but many earlier implementations don't. */
1309 # define MAP_FAILED ((void *) -1L)
1311 pdump_start = (char *) mmap (0, pdump_length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
1312 if (pdump_start != (char *) MAP_FAILED)
1314 pdump_free = pdump_file_unmap;
1318 #endif /* HAVE_MMAP */
1320 pdump_start = xnew_array (char, pdump_length);
1321 pdump_free = pdump_file_free;
1322 read (fd, pdump_start, pdump_length);
1327 #endif /* !WIN32_NATIVE */
1331 pdump_file_try (char *exe_path)
1333 char *w = exe_path + strlen (exe_path);
1337 sprintf (w, "-%s-%08x.dmp", EMACS_VERSION, dump_id);
1338 if (pdump_file_get (exe_path))
1340 if (pdump_load_check ())
1345 sprintf (w, "-%08x.dmp", dump_id);
1346 if (pdump_file_get (exe_path))
1348 if (pdump_load_check ())
1353 sprintf (w, ".dmp");
1354 if (pdump_file_get (exe_path))
1356 if (pdump_load_check ())
1363 while (w>exe_path && !IS_DIRECTORY_SEP (*w) && (*w != '-') && (*w != '.'));
1365 while (w>exe_path && !IS_DIRECTORY_SEP (*w));
1370 pdump_load (const char *argv0)
1372 char exe_path[PATH_MAX], real_exe_path[PATH_MAX];
1374 GetModuleFileName (NULL, exe_path, PATH_MAX);
1375 /* #### urk, needed for xrealpath() below */
1376 Vdirectory_sep_char = make_char ('\\');
1377 #else /* !WIN32_NATIVE */
1379 const char *dir, *p;
1384 /* XEmacs as a login shell, oh goody! */
1385 dir = getenv ("SHELL");
1388 p = dir + strlen (dir);
1389 while (p != dir && !IS_ANY_SEP (p[-1])) p--;
1393 /* invocation-name includes a directory component -- presumably it
1394 is relative to cwd, not $PATH */
1395 strcpy (exe_path, dir);
1399 const char *path = getenv ("PATH");
1400 const char *name = p;
1404 while (*p && *p != SEPCHAR)
1413 memcpy (exe_path, path, p - path);
1414 w = exe_path + (p - path);
1416 if (!IS_DIRECTORY_SEP (w[-1]))
1422 /* Check that exe_path is executable and not a directory */
1423 #undef access /* avoid !@#$%^& encapsulated access */
1424 #undef stat /* avoid !@#$%^& encapsulated stat */
1426 struct stat statbuf;
1427 if (access (exe_path, X_OK) == 0
1428 && stat (exe_path, &statbuf) == 0
1429 && ! S_ISDIR (statbuf.st_mode))
1435 /* Oh well, let's have some kind of default */
1436 sprintf (exe_path, "./%s", name);
1442 #endif /* WIN32_NATIVE */
1444 /* Save exe_path because pdump_file_try() modifies it */
1445 strcpy(real_exe_path, exe_path);
1446 if (pdump_file_try (exe_path)
1447 || (xrealpath(real_exe_path, real_exe_path)
1448 && pdump_file_try (real_exe_path)))
1450 pdump_load_finish ();
1455 if (pdump_resource_get ())
1457 if (pdump_load_check ())
1459 pdump_load_finish ();