1 /* Portable data dumper for SXEmacs.
2 Copyright (C) 1999-2000 Olivier Galibert
3 Copyright (C) 2001 Martin Buchholz
5 This file is part of SXEmacs
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 /* Synched up with: Not in FSF. */
26 #include "specifier.h"
29 #include "ui/console-stream.h"
47 Dynarr_declare(pdump_opaque);
48 } pdump_opaque_dynarr;
52 const struct struct_description *desc;
53 } pdump_root_struct_ptr;
56 Dynarr_declare(pdump_root_struct_ptr);
57 } pdump_root_struct_ptr_dynarr;
62 } pdump_static_Lisp_Object;
65 char **address; /* char * for ease of doing relocation */
67 } pdump_static_pointer;
69 static pdump_opaque_dynarr *pdump_opaques;
70 static pdump_root_struct_ptr_dynarr *pdump_root_struct_ptrs;
71 static Lisp_Object_ptr_dynarr *pdump_root_objects;
72 static Lisp_Object_ptr_dynarr *pdump_weak_object_chains;
74 /* Mark SIZE bytes at non-heap address VARADDRESS for dumping as is,
75 without any bit-twiddling. */
76 void dump_add_opaque(void *varaddress, size_t size)
79 info.varaddress = varaddress;
81 if (pdump_opaques == NULL)
82 pdump_opaques = Dynarr_new(pdump_opaque);
83 Dynarr_add(pdump_opaques, info);
86 /* Mark the struct described by DESC and pointed to by the pointer at
87 non-heap address VARADDRESS for dumping.
88 All the objects reachable from this pointer will also be dumped. */
90 dump_add_root_struct_ptr(void *ptraddress,
91 const struct struct_description *desc)
93 pdump_root_struct_ptr info;
94 info.ptraddress = (void **)ptraddress;
96 if (pdump_root_struct_ptrs == NULL)
97 pdump_root_struct_ptrs = Dynarr_new(pdump_root_struct_ptr);
98 Dynarr_add(pdump_root_struct_ptrs, info);
101 /* Mark the Lisp_Object at non-heap address VARADDRESS for dumping.
102 All the objects reachable from this var will also be dumped. */
103 void dump_add_root_object(Lisp_Object * varaddress)
105 if (pdump_root_objects == NULL)
107 Dynarr_new2(Lisp_Object_ptr_dynarr, Lisp_Object *);
108 Dynarr_add(pdump_root_objects, varaddress);
111 /* Mark the list pointed to by the Lisp_Object at VARADDRESS for dumping. */
112 void dump_add_weak_object_chain(Lisp_Object * varaddress)
114 if (pdump_weak_object_chains == NULL)
115 pdump_weak_object_chains =
116 Dynarr_new2(Lisp_Object_ptr_dynarr, Lisp_Object *);
117 Dynarr_add(pdump_weak_object_chains, varaddress);
120 inline static void pdump_align_stream(FILE * stream, size_t alignment)
122 long offset = ftell(stream);
123 long adjustment = ALIGN_SIZE(offset, alignment) - offset;
125 fseek(stream, adjustment, SEEK_CUR);
128 #define PDUMP_ALIGN_OUTPUT(type) pdump_align_stream (pdump_out, ALIGNOF (type))
130 #define PDUMP_WRITE(type, object) \
131 fwrite (&object, sizeof (object), 1, pdump_out);
133 #define PDUMP_WRITE_ALIGNED(type, object) do { \
134 PDUMP_ALIGN_OUTPUT (type); \
135 PDUMP_WRITE (type, object); \
138 #define PDUMP_READ(ptr, type) \
139 (((type *) (ptr = (char*) (((type *) ptr) + 1)))[-1])
141 #define PDUMP_READ_ALIGNED(ptr, type) \
142 ((ptr = (char *) ALIGN_PTR (ptr, ALIGNOF (type))), PDUMP_READ (ptr, type))
145 const struct lrecord_description *desc;
149 static char *pdump_rt_list = 0;
151 void pdump_objects_unmark(void)
154 char *p = pdump_rt_list;
157 pdump_reloc_table *rt = (pdump_reloc_table *) p;
158 p += sizeof(pdump_reloc_table);
160 for (i = 0; i < rt->count; i++) {
161 struct lrecord_header *lh =
162 *(struct lrecord_header **)p;
163 if (!C_READONLY_RECORD_HEADER_P(lh))
164 UNMARK_RECORD_HEADER(lh);
165 p += sizeof(EMACS_INT);
172 /* The structure of the file
175 stab_offset - nb_root_struct_ptrs*pair(void *, adr)
176 for pointers to structures
177 - nb_opaques*pair(void *, size) for raw bits to restore
179 - root lisp object address/value couples with the count
183 #define PDUMP_SIGNATURE "SXEmacsDP"
184 #define PDUMP_SIGNATURE_LEN (sizeof (PDUMP_SIGNATURE) - 1)
187 char signature[PDUMP_SIGNATURE_LEN];
189 EMACS_UINT stab_offset;
190 EMACS_UINT reloc_address;
191 int nb_root_struct_ptrs;
197 static off_t pdump_length;
200 static void (*pdump_free) (void);
202 static unsigned char pdump_align_table[] = {
203 64, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
204 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
205 32, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
206 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1
209 static inline unsigned int pdump_size_to_align(size_t size)
211 return pdump_align_table[size % countof(pdump_align_table)];
214 typedef struct pdump_entry_list_elt {
215 struct pdump_entry_list_elt *next;
219 EMACS_INT save_offset;
220 } pdump_entry_list_elt;
223 pdump_entry_list_elt *first;
228 typedef struct pdump_struct_list_elt {
229 pdump_entry_list list;
230 const struct struct_description *sdesc;
231 } pdump_struct_list_elt;
234 pdump_struct_list_elt *list;
239 static pdump_entry_list *pdump_object_table;
240 static pdump_entry_list pdump_opaque_data_list;
241 static pdump_struct_list pdump_struct_table;
243 static int *pdump_alert_undump_object;
245 static unsigned long cur_offset;
246 static size_t max_size;
248 static void *pdump_buf;
249 static FILE *pdump_out;
251 #define PDUMP_HASHSIZE 200001
253 static pdump_entry_list_elt **pdump_hash;
255 /* Since most pointers are eight bytes aligned, the >>3 allows for a better hash */
256 static int pdump_make_hash(const void *obj)
258 return ((unsigned long)(obj) >> 3) % PDUMP_HASHSIZE;
261 static pdump_entry_list_elt *pdump_get_entry(const void *obj)
263 int pos = pdump_make_hash(obj);
264 pdump_entry_list_elt *e;
268 while ((e = pdump_hash[pos]) != 0) {
273 if (pos == PDUMP_HASHSIZE)
280 pdump_add_entry(pdump_entry_list *l, const void *obj, size_t size, int count)
282 pdump_entry_list_elt *e;
283 int pos = pdump_make_hash(obj);
285 while ((e = pdump_hash[pos]) != 0) {
290 if (pos == PDUMP_HASHSIZE) {
295 e = xnew(pdump_entry_list_elt);
307 int align = pdump_size_to_align(size);
309 if (align < l->align) {
316 static pdump_entry_list*
317 pdump_get_entry_list(const struct struct_description *sdesc)
320 for (i = 0; i < pdump_struct_table.count; i++)
321 if (pdump_struct_table.list[i].sdesc == sdesc)
322 return &pdump_struct_table.list[i].list;
324 if (pdump_struct_table.size <= pdump_struct_table.count) {
325 if (pdump_struct_table.size == -1)
326 pdump_struct_table.size = 10;
328 pdump_struct_table.size = pdump_struct_table.size * 2;
329 pdump_struct_table.list = (pdump_struct_list_elt *)
330 xrealloc(pdump_struct_table.list,
331 pdump_struct_table.size *
332 sizeof(pdump_struct_list_elt));
334 pdump_struct_table.list[pdump_struct_table.count].list.first = 0;
335 pdump_struct_table.list[pdump_struct_table.count].list.align =
336 ALIGNOF(max_align_t);
337 pdump_struct_table.list[pdump_struct_table.count].list.count = 0;
338 pdump_struct_table.list[pdump_struct_table.count].sdesc = sdesc;
340 return &pdump_struct_table.list[pdump_struct_table.count++].list;
344 struct lrecord_header *obj;
351 static void pdump_backtrace(void)
354 stderr_out("pdump backtrace :\n");
355 for (i = 0; i < depth; i++) {
356 if (!backtrace[i].obj)
357 stderr_out(" - ind. (%d, %d)\n",
358 backtrace[i].position, backtrace[i].offset);
360 stderr_out(" - %s (%d, %d)\n",
361 LHEADER_IMPLEMENTATION(backtrace[i].obj)->
362 name, backtrace[i].position,
363 backtrace[i].offset);
368 static void pdump_register_object(Lisp_Object obj);
369 static void pdump_register_struct(const void *data,
370 const struct struct_description *sdesc,
374 pdump_get_indirect_count(EMACS_INT code,
375 const struct lrecord_description *idesc,
378 EMACS_INT count = 0; /* initialize to shut up GCC */
381 int line = XD_INDIRECT_VAL(code);
382 int delta = XD_INDIRECT_DELTA(code);
384 irdata = ((const char *)idata) + idesc[line].offset;
385 switch (idesc[line].type) {
387 count = *(const size_t*)irdata;
390 count = *(const int*)irdata;
393 count = *(const long*)irdata;
396 count = *(const Bytecount*)irdata;
399 /* list the rest here */
400 case XD_LISP_OBJECT_ARRAY:
405 case XD_OPAQUE_DATA_PTR:
410 case XD_SPECIFIER_END:
414 ("Unsupported count type : %d (line = %d, code=%ld)\n",
415 idesc[line].type, line, (long)code);
424 pdump_register_sub(const void *data, const struct lrecord_description *desc,
430 for (pos = 0; desc[pos].type != XD_END; pos++) {
431 const void *rdata = (const char *)data + desc[pos].offset;
433 backtrace[me].position = pos;
434 backtrace[me].offset = desc[pos].offset;
436 switch (desc[pos].type) {
437 case XD_SPECIFIER_END:
440 ((const Lisp_Specifier *)data)->methods->
450 case XD_OPAQUE_DATA_PTR: {
451 EMACS_INT count = desc[pos].data1;
452 if (XD_IS_INDIRECT(count)) {
453 count = pdump_get_indirect_count(
456 pdump_add_entry(&pdump_opaque_data_list,
457 *(const void *const*)rdata, count, 1);
461 const char *str = *(const char *const*)rdata;
463 size_t str_sz = strlen(str);
464 pdump_add_entry(&pdump_opaque_data_list,
469 case XD_DOC_STRING: {
470 const char *str = *(const char *const*)rdata;
471 if ((EMACS_INT)str > 0) {
472 pdump_add_entry(&pdump_opaque_data_list,
473 str, strlen(str) + 1, 1);
477 case XD_LISP_OBJECT: {
478 const Lisp_Object *pobj = (const Lisp_Object*)rdata;
480 assert(desc[pos].data1 == 0);
482 backtrace[me].offset =
483 (const char *)pobj - (const char *)data;
484 pdump_register_object(*pobj);
487 case XD_LISP_OBJECT_ARRAY: {
489 EMACS_INT count = desc[pos].data1;
491 if (XD_IS_INDIRECT(count)) {
492 count = pdump_get_indirect_count(
495 for (i = 0; i < count; i++) {
496 const Lisp_Object *pobj =
497 ((const Lisp_Object*)rdata) + i;
498 Lisp_Object dobj = *pobj;
500 backtrace[me].offset =
503 pdump_register_object(dobj);
507 case XD_STRUCT_PTR: {
508 EMACS_INT count = desc[pos].data1;
509 const struct struct_description *sdesc =
511 const char *dobj = *(const char *const*)rdata;
514 if (XD_IS_INDIRECT(count)) {
515 count = pdump_get_indirect_count(
518 pdump_register_struct(dobj, sdesc, count);
526 stderr_out("Unsupported dump type : %d\n",
535 pdump_register_object(Lisp_Object obj)
537 struct lrecord_header *objh;
538 const struct lrecord_implementation *imp;
540 if (!POINTER_TYPE_P(XTYPE(obj))) {
544 objh = XRECORD_LHEADER(obj);
549 if (pdump_get_entry(objh)) {
553 imp = LHEADER_IMPLEMENTATION(objh);
555 if (imp->description) {
558 stderr_out("Backtrace overflow, loop ?\n");
561 backtrace[me].obj = objh;
562 backtrace[me].position = 0;
563 backtrace[me].offset = 0;
565 pdump_add_entry(pdump_object_table + objh->type,
569 imp->size_in_bytes_method(objh), 1);
570 pdump_register_sub(objh, imp->description, me);
573 pdump_alert_undump_object[objh->type]++;
574 stderr_out("Undumpable object type : %s\n", imp->name);
580 pdump_register_struct(const void *data,
581 const struct struct_description *sdesc, int count)
583 if (data && !pdump_get_entry(data)) {
587 stderr_out("Backtrace overflow, loop ?\n");
590 backtrace[me].obj = 0;
591 backtrace[me].position = 0;
592 backtrace[me].offset = 0;
594 pdump_add_entry(pdump_get_entry_list(sdesc),
595 data, sdesc->size, count);
596 for (i = 0; i < count; i++) {
598 ((const char*)data) + sdesc->size * i,
599 sdesc->description, me);
606 pdump_dump_data(pdump_entry_list_elt * elt,
607 const struct lrecord_description *desc)
609 size_t size = elt->size;
610 int count = elt->count;
613 memcpy(pdump_buf, elt->obj, size * count);
615 for (i = 0; i < count; i++) {
616 char *cur = ((char *)pdump_buf) + i * size;
618 for (pos = 0; desc[pos].type != XD_END; pos++) {
619 void *rdata = cur + desc[pos].offset;
620 switch (desc[pos].type) {
621 case XD_SPECIFIER_END:
622 desc = ((const Lisp_Specifier *)
624 methods->extra_description;
632 EMACS_INT val = desc[pos].data1;
633 if (XD_IS_INDIRECT(val))
634 val = pdump_get_indirect_count(
635 val, desc, elt->obj);
639 case XD_OPAQUE_DATA_PTR:
641 case XD_STRUCT_PTR: {
642 void *ptr = *(void**)rdata;
644 *(EMACS_INT*) rdata =
651 Lisp_Object obj = *(Lisp_Object*)rdata;
652 pdump_entry_list_elt *elt1;
655 elt1 = pdump_get_entry(
656 XRECORD_LHEADER(obj));
660 obj = *(Lisp_Object*)(
663 (XRECORD_LHEADER(obj)));
665 *(EMACS_INT *) rdata =
669 case XD_LISP_OBJECT: {
673 assert(desc[pos].data1 == 0);
675 if (POINTER_TYPE_P(XTYPE(*pobj))
676 && XRECORD_LHEADER(*pobj)) {
679 (XRECORD_LHEADER(*pobj))
684 case XD_LISP_OBJECT_ARRAY: {
685 EMACS_INT num = desc[pos].data1;
688 if (XD_IS_INDIRECT(num)) {
689 num = pdump_get_indirect_count(
690 num, desc, elt->obj);
692 for (j = 0; j < num; j++) {
694 ((Lisp_Object*)rdata) +
698 XRECORD_LHEADER(*pobj)) {
709 case XD_DOC_STRING: {
710 EMACS_INT str = *(EMACS_INT*)rdata;
724 ("Unsupported dump type : %d\n",
731 fwrite(desc ? pdump_buf : elt->obj, size, count, pdump_out);
735 pdump_reloc_one(void *data, EMACS_INT delta,
736 const struct lrecord_description *desc)
741 for (pos = 0; desc[pos].type != XD_END; pos++) {
742 void *rdata = (char *)data + desc[pos].offset;
743 switch (desc[pos].type) {
744 case XD_SPECIFIER_END:
746 desc = ((const Lisp_Specifier *)data)->methods->
755 case XD_OPAQUE_DATA_PTR:
759 EMACS_INT ptr = *(EMACS_INT *) rdata;
761 *(EMACS_INT *) rdata = ptr + delta;
765 case XD_LISP_OBJECT: {
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))
773 (char *)XPNTR(*pobj) + delta);
777 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++) {
784 Lisp_Object *pobj = (Lisp_Object*)rdata + j;
786 if (POINTER_TYPE_P(XTYPE(*pobj))
787 && !EQ(*pobj, Qnull_pointer)) {
789 (char *)XPNTR(*pobj) + delta);
794 case XD_DOC_STRING: {
795 EMACS_INT str = *(EMACS_INT *) rdata;
797 *(EMACS_INT *) rdata = str + delta;
805 stderr_out("Unsupported dump type : %d\n",
813 pdump_allocate_offset(pdump_entry_list_elt * elt,
814 const struct lrecord_description *desc)
816 size_t size = elt->count * elt->size;
817 elt->save_offset = cur_offset;
824 pdump_scan_by_alignment(void (*f) (pdump_entry_list_elt *,
825 const struct lrecord_description *))
829 for (align = ALIGNOF(max_align_t); align; align >>= 1) {
831 pdump_entry_list_elt *elt;
833 for (i = 0; i < lrecord_type_count; i++)
834 if (pdump_object_table[i].align == align)
835 for (elt = pdump_object_table[i].first; elt;
838 lrecord_implementations_table[i]->
841 for (i = 0; i < (size_t)pdump_struct_table.count; i++) {
842 pdump_struct_list_elt list = pdump_struct_table.list[i];
843 if (list.list.align == align)
844 for (elt = list.list.first; elt;
846 f(elt, list.sdesc->description);
849 for (elt = pdump_opaque_data_list.first; elt; elt = elt->next)
850 if (pdump_size_to_align(elt->size) ==
856 static void pdump_dump_root_struct_ptrs(void)
859 size_t count = Dynarr_length(pdump_root_struct_ptrs);
860 pdump_static_pointer *data = alloca_array(pdump_static_pointer, count);
861 for (i = 0; i < count; i++) {
863 (char **)Dynarr_atp(pdump_root_struct_ptrs, i)->ptraddress;
865 (char *)pdump_get_entry(*data[i].address)->save_offset;
867 PDUMP_ALIGN_OUTPUT(pdump_static_pointer);
868 fwrite(data, sizeof(pdump_static_pointer), count, pdump_out);
871 static void pdump_dump_opaques(void)
874 for (i = 0; i < Dynarr_length(pdump_opaques); i++) {
875 pdump_opaque *info = Dynarr_atp(pdump_opaques, i);
876 PDUMP_WRITE_ALIGNED(pdump_opaque, *info);
877 fwrite(info->varaddress, info->size, 1, pdump_out);
881 static void pdump_dump_rtables(void)
884 pdump_entry_list_elt *elt;
885 pdump_reloc_table rt;
887 for (i = 0; i < lrecord_type_count; i++) {
888 elt = pdump_object_table[i].first;
891 rt.desc = lrecord_implementations_table[i]->description;
892 rt.count = pdump_object_table[i].count;
893 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
896 pdump_get_entry(elt->obj)->save_offset;
897 PDUMP_WRITE_ALIGNED(EMACS_INT, rdata);
904 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
906 for (i = 0; i < (size_t)pdump_struct_table.count; i++) {
907 elt = pdump_struct_table.list[i].list.first;
908 rt.desc = pdump_struct_table.list[i].sdesc->description;
909 rt.count = pdump_struct_table.list[i].list.count;
910 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
913 pdump_get_entry(elt->obj)->save_offset;
915 for (j = 0; j < elt->count; j++) {
916 PDUMP_WRITE_ALIGNED(EMACS_INT, rdata);
924 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
927 static void pdump_dump_root_objects(void)
929 size_t count = (Dynarr_length(pdump_root_objects) +
930 Dynarr_length(pdump_weak_object_chains));
933 PDUMP_WRITE_ALIGNED(size_t, count);
934 PDUMP_ALIGN_OUTPUT(pdump_static_Lisp_Object);
936 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)))
944 pdump_get_entry(XRECORD_LHEADER
948 PDUMP_WRITE(pdump_static_Lisp_Object, obj);
951 for (i = 0; i < Dynarr_length(pdump_weak_object_chains); i++) {
952 pdump_entry_list_elt *elt;
953 pdump_static_Lisp_Object obj;
955 obj.address = Dynarr_at(pdump_weak_object_chains, i);
956 obj.value = *obj.address;
959 const struct lrecord_description *desc;
961 elt = pdump_get_entry(XRECORD_LHEADER(obj.value));
965 XRECORD_LHEADER_IMPLEMENTATION(obj.value)->
967 for (pos = 0; desc[pos].type != XD_LO_LINK; pos++)
968 assert(desc[pos].type != XD_END);
971 *(Lisp_Object *) (desc[pos].offset +
973 *)(XRECORD_LHEADER(obj.value)));
975 obj.value = wrap_object((void *)elt->save_offset);
977 PDUMP_WRITE(pdump_static_Lisp_Object, obj);
982 pdump(const char *dumpfile)
985 Lisp_Object t_console, t_device, t_frame;
989 pdump_object_table = xnew_array(pdump_entry_list, lrecord_type_count);
990 pdump_alert_undump_object = xnew_array(int, lrecord_type_count);
992 assert(ALIGNOF(max_align_t) <= pdump_align_table[0]);
994 for (i = 0; i < countof(pdump_align_table); i++)
995 if (pdump_align_table[i] > ALIGNOF(max_align_t))
996 pdump_align_table[i] = ALIGNOF(max_align_t);
998 flush_all_buffer_local_cache();
1000 /* These appear in a DEFVAR_LISP, which does a staticpro() */
1001 t_console = Vterminal_console;
1002 Vterminal_console = Qnil;
1003 t_frame = Vterminal_frame;
1004 Vterminal_frame = Qnil;
1005 t_device = Vterminal_device;
1006 Vterminal_device = Qnil;
1008 dump_add_opaque((void *)&lrecord_implementations_table,
1009 lrecord_type_count *
1010 sizeof(lrecord_implementations_table[0]));
1011 dump_add_opaque(&lrecord_markers,
1012 lrecord_type_count * sizeof(lrecord_markers[0]));
1014 pdump_hash = xnew_array_and_zero(pdump_entry_list_elt*, PDUMP_HASHSIZE);
1016 for (i = 0; i < lrecord_type_count; i++) {
1017 pdump_object_table[i].first = 0;
1018 pdump_object_table[i].align = ALIGNOF(max_align_t);
1019 pdump_object_table[i].count = 0;
1020 pdump_alert_undump_object[i] = 0;
1022 pdump_struct_table.count = 0;
1023 pdump_struct_table.size = -1;
1025 pdump_opaque_data_list.first = 0;
1026 pdump_opaque_data_list.align = ALIGNOF(max_align_t);
1027 pdump_opaque_data_list.count = 0;
1030 for (i = 0; i < (size_t)Dynarr_length(pdump_root_objects); i++) {
1031 pdump_register_object(*Dynarr_at(pdump_root_objects, i));
1035 for (i = 0; i < lrecord_type_count; i++)
1036 if (pdump_alert_undump_object[i]) {
1038 printf("Undumpable types list :\n");
1040 printf(" - %s (%d)\n",
1041 lrecord_implementations_table[i]->name,
1042 pdump_alert_undump_object[i]);
1048 for (i = 0; i < (size_t) Dynarr_length(pdump_root_struct_ptrs); i++) {
1049 pdump_root_struct_ptr info =
1050 Dynarr_at(pdump_root_struct_ptrs, i);
1051 pdump_register_struct(*(info.ptraddress), info.desc, 1);
1054 memcpy(header.signature, PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN);
1055 header.id = dump_id;
1056 header.reloc_address = 0;
1057 header.nb_root_struct_ptrs = Dynarr_length(pdump_root_struct_ptrs);
1058 header.nb_opaques = Dynarr_length(pdump_opaques);
1060 cur_offset = ALIGN_SIZE(sizeof(header), ALIGNOF(max_align_t));
1063 pdump_scan_by_alignment(pdump_allocate_offset);
1064 cur_offset = ALIGN_SIZE(cur_offset, ALIGNOF(max_align_t));
1065 header.stab_offset = cur_offset;
1067 pdump_buf = xmalloc_atomic(max_size);
1068 /* Avoid use of the `open' macro. We want the real function. */
1070 pdump_fd = open(dumpfile,
1071 O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY, 0666);
1072 if ( pdump_fd < 0 ) {
1073 stderr_out("Could not open dump file: %s", dumpfile);
1076 pdump_out = fdopen(pdump_fd, "w");
1077 if ( pdump_out < 0 ) {
1078 stderr_out("Could not fdopen dump file: %s %d", dumpfile, pdump_fd);
1082 fwrite(&header, sizeof(header), 1, pdump_out);
1083 PDUMP_ALIGN_OUTPUT(max_align_t);
1085 pdump_scan_by_alignment(pdump_dump_data);
1087 fseek(pdump_out, header.stab_offset, SEEK_SET);
1089 pdump_dump_root_struct_ptrs();
1090 pdump_dump_opaques();
1091 pdump_dump_rtables();
1092 pdump_dump_root_objects();
1101 Vterminal_console = t_console;
1102 Vterminal_frame = t_frame;
1103 Vterminal_device = t_device;
1106 static int pdump_load_check(void)
1108 return (!memcmp(((pdump_header*)pdump_start)->signature,
1109 PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN)
1110 && ((pdump_header *)pdump_start)->id == dump_id);
1113 /*----------------------------------------------------------------------*/
1114 /* Reading the dump file */
1115 /*----------------------------------------------------------------------*/
1117 pdump_load_finish(void)
1121 pdump_header *header = (pdump_header*)pdump_start;
1123 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
1124 int cache_GC_dont_gc = GC_dont_gc;
1129 pdump_end = pdump_start + pdump_length;
1131 delta = ((EMACS_INT)pdump_start) - header->reloc_address;
1132 p = pdump_start + header->stab_offset;
1134 /* Put back the pdump_root_struct_ptrs */
1135 p = (char*)ALIGN_PTR(p, ALIGNOF(pdump_static_pointer));
1136 for (int i = 0; i < header->nb_root_struct_ptrs; i++) {
1137 pdump_static_pointer ptr = PDUMP_READ(p, pdump_static_pointer);
1138 (*ptr.address) = ptr.value + delta;
1141 /* Put back the pdump_opaques */
1142 for (int i = 0; i < header->nb_opaques; i++) {
1143 pdump_opaque info = PDUMP_READ_ALIGNED(p, pdump_opaque);
1144 memcpy(info.varaddress, p, info.size);
1148 /* Do the relocations */
1150 for (EMACS_INT count = 2;;) {
1151 pdump_reloc_table rt = PDUMP_READ_ALIGNED(p, pdump_reloc_table);
1152 p = (char*)ALIGN_PTR(p, ALIGNOF(char*));
1154 char **reloc = (char**)p;
1155 for (int i = 0; i < rt.count; i++) {
1157 pdump_reloc_one(reloc[i], delta, rt.desc);
1159 p += rt.count * sizeof(char *);
1160 } else if (!(--count)) {
1165 /* Put the pdump_root_objects variables in place */
1166 p = (char*)ALIGN_PTR(p, ALIGNOF(pdump_static_Lisp_Object));
1168 for (int i = PDUMP_READ_ALIGNED(p, size_t); i--; ) {
1169 pdump_static_Lisp_Object obj =
1170 PDUMP_READ(p, pdump_static_Lisp_Object);
1172 if (POINTER_TYPE_P(XTYPE(obj.value))) {
1174 wrap_object((char*)XPNTR(obj.value) + delta);
1176 (*obj.address) = obj.value;
1179 /* Final cleanups */
1180 /* reorganize hash tables */
1183 pdump_reloc_table rt = PDUMP_READ_ALIGNED(p, pdump_reloc_table);
1184 p = (char*)ALIGN_PTR(p, ALIGNOF(Lisp_Object));
1189 if (rt.desc == hash_table_description) {
1190 for (int i = 0; i < rt.count; i++) {
1191 pdump_reorganize_hash_table(
1192 PDUMP_READ(p, Lisp_Object));
1196 p += sizeof(Lisp_Object) * rt.count;
1200 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
1201 GC_dont_gc = cache_GC_dont_gc;
1207 static void pdump_file_free(void)
1213 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1214 # if defined HAVE_MMAP
1215 static void pdump_file_unmap(void)
1217 munmap(pdump_start, pdump_length);
1219 # endif /* HAVE_MMAP */
1222 static int pdump_file_get(const char *path)
1224 int fd = open(path, O_RDONLY | OPEN_BINARY);
1226 if (UNLIKELY(fd < 0)) {
1230 pdump_length = lseek(fd, 0, SEEK_END);
1231 if (UNLIKELY(pdump_length < sizeof(pdump_header))) {
1236 lseek(fd, 0, SEEK_SET);
1238 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1239 # if defined HAVE_MMAP
1240 /* Unix 98 requires that sys/mman.h define MAP_FAILED,
1241 but many earlier implementations don't. */
1243 # define MAP_FAILED ((void*)-1L)
1244 # endif /* MAP_FAILED */
1245 pdump_start = (char*)mmap(0, pdump_length,
1246 PROT_READ | PROT_WRITE, MAP_PRIVATE,
1248 if (LIKELY(pdump_start != (char*)MAP_FAILED)) {
1249 pdump_free = pdump_file_unmap;
1253 # endif /* HAVE_MMAP */
1256 pdump_start = xnew_array(char, pdump_length);
1257 pdump_free = pdump_file_free;
1258 read(fd, pdump_start, pdump_length);
1264 static int pdump_file_try(char *exe_path, size_t size)
1266 char *w = exe_path + strlen(exe_path);
1268 size -= strlen(exe_path);
1272 #ifdef EMACS_PATCH_LEVEL
1273 sz = snprintf(w, size, "-%d.%d.%d-%08x.dmp",
1274 EMACS_MAJOR_VERSION, EMACS_MINOR_VERSION,
1275 EMACS_PATCH_LEVEL, dump_id);
1276 if (sz >=0 && sz < size && pdump_file_get(exe_path)) {
1277 if (pdump_load_check()) {
1282 #endif /* EMACS_PATCH_LEVEL */
1283 #ifdef EMACS_BETA_VERSION
1284 sz = snprintf(w, size, "-%d.%d.%d-%08x.dmp",
1285 EMACS_MAJOR_VERSION, EMACS_MINOR_VERSION,
1286 EMACS_BETA_VERSION, dump_id);
1287 if (sz >=0 && sz < size && pdump_file_get(exe_path)) {
1288 if (pdump_load_check()) {
1293 #endif /* EMACS_BETA_VERSION */
1295 sz = snprintf(w, size, "-%08x.dmp", dump_id);
1296 if (sz >=0 && sz < size && pdump_file_get(exe_path)) {
1297 if (pdump_load_check()) {
1303 sz = snprintf(w, size, ".dmp");
1304 if (sz >=0 && sz < size && pdump_file_get(exe_path)) {
1305 if (pdump_load_check()) {
1313 } while (w > exe_path && !IS_DIRECTORY_SEP(*w) && (*w != '-')
1315 } while (w > exe_path && !IS_DIRECTORY_SEP(*w));
1320 wipe_out_libtool_stuff(char *path)
1322 #define dotlibs ".libs/"
1323 #define ltdash "lt-"
1326 for (p = strchr(path, '.'); p; p = strchr(p+1, '.')) {
1328 strncmp(p, dotlibs, sizeof(dotlibs)-1);
1330 strncmp(p+sizeof(dotlibs)-1, ltdash, sizeof(ltdash)-1);
1331 if ((dotlibsp || ltdashp) == 0) {
1332 /* cut out the `.libs/lt-' portion */
1333 size_t offs = sizeof(dotlibs)-1+sizeof(ltdash)-1;
1334 size_t rest = strlen(p + offs);
1335 memmove(p, p + offs, rest);
1338 } else if (dotlibsp == 0) {
1339 /* cut out the `.libs/' portion */
1340 size_t offs = sizeof(dotlibs)-1;
1341 size_t rest = strlen(p + offs);
1342 memmove(p, p + offs, rest);
1351 int pdump_load(const char *argv0)
1353 char exe_path[PATH_MAX], real_exe_path[PATH_MAX];
1355 const char *dir, *p;
1358 if (dir[0] == '-') {
1359 /* SXEmacs as a login shell, oh goody! */
1360 dir = getenv("SHELL");
1361 assert(dir != NULL);
1364 p = dir + strlen(dir);
1365 while (p != dir && !IS_ANY_SEP(p[-1])) {
1370 /* invocation-name includes a directory component -- presumably it
1371 is relative to cwd, not $PATH */
1372 assert(strlen(dir) < sizeof(exe_path));
1373 strncpy(exe_path, dir, sizeof(exe_path)-1);
1374 exe_path[sizeof(exe_path)-1]='\0';
1376 const char *path = getenv("PATH");
1377 const char *name = p;
1379 assert(path != NULL);
1381 int remain = sizeof(exe_path)-1;
1382 exe_path[remain] = '\0';
1385 while (*p && *p != SEPCHAR) {
1393 size_t len = (p - path) <= remain
1396 memcpy(exe_path, path, len);
1400 if (!IS_DIRECTORY_SEP(w[-1]) && (remain > 0) ) {
1405 strncpy(w, name, remain);
1409 /* Check that exe_path is executable and not a
1411 #undef access /* avoid !@#$%^& encapsulated access */
1412 #undef stat /* avoid !@#$%^& encapsulated stat */
1414 struct stat statbuf;
1415 if (access(exe_path, X_OK) == 0
1416 && stat(exe_path, &statbuf) == 0
1417 && !S_ISDIR(statbuf.st_mode))
1422 /* Oh well, let's have some kind of default */
1423 int sz = snprintf(exe_path, sizeof(exe_path),
1425 assert(sz >= 0 && sz < sizeof(exe_path));
1433 /* do not use this one now as we follow libtool's concept of
1434 * convenience libraries and binaries */
1435 wipe_out_libtool_stuff(exe_path);
1438 /* Save exe_path because pdump_file_try() modifies it */
1439 assert(strlen(exe_path) < sizeof(real_exe_path));
1440 strcpy(real_exe_path, exe_path);
1441 if (pdump_file_try(exe_path,sizeof(exe_path))
1442 || (xrealpath(real_exe_path, real_exe_path)
1443 && pdump_file_try(real_exe_path,sizeof(real_exe_path)))) {
1444 pdump_load_finish();
1451 /* dumper.c ends here */