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");
562 backtrace[me].obj = objh;
563 backtrace[me].position = 0;
564 backtrace[me].offset = 0;
566 pdump_add_entry(pdump_object_table + objh->type,
570 imp->size_in_bytes_method(objh), 1);
571 pdump_register_sub(objh, imp->description, me);
574 pdump_alert_undump_object[objh->type]++;
575 stderr_out("Undumpable object type : %s\n", imp->name);
581 pdump_register_struct(const void *data,
582 const struct struct_description *sdesc, int count)
584 if (data && !pdump_get_entry(data)) {
588 stderr_out("Backtrace overflow, loop ?\n");
591 backtrace[me].obj = 0;
592 backtrace[me].position = 0;
593 backtrace[me].offset = 0;
595 pdump_add_entry(pdump_get_entry_list(sdesc),
596 data, sdesc->size, count);
597 for (i = 0; i < count; i++) {
599 ((const char*)data) + sdesc->size * i,
600 sdesc->description, me);
607 pdump_dump_data(pdump_entry_list_elt * elt,
608 const struct lrecord_description *desc)
610 size_t size = elt->size;
611 int count = elt->count;
614 memcpy(pdump_buf, elt->obj, size * count);
616 for (i = 0; i < count; i++) {
617 char *cur = ((char *)pdump_buf) + i * size;
619 for (pos = 0; desc[pos].type != XD_END; pos++) {
620 void *rdata = cur + desc[pos].offset;
621 switch (desc[pos].type) {
622 case XD_SPECIFIER_END:
623 desc = ((const Lisp_Specifier *)
625 methods->extra_description;
633 EMACS_INT val = desc[pos].data1;
634 if (XD_IS_INDIRECT(val))
635 val = pdump_get_indirect_count(
636 val, desc, elt->obj);
640 case XD_OPAQUE_DATA_PTR:
642 case XD_STRUCT_PTR: {
643 void *ptr = *(void**)rdata;
645 *(EMACS_INT*) rdata =
652 Lisp_Object obj = *(Lisp_Object*)rdata;
653 pdump_entry_list_elt *elt1;
656 elt1 = pdump_get_entry(
657 XRECORD_LHEADER(obj));
661 obj = *(Lisp_Object*)(
664 (XRECORD_LHEADER(obj)));
666 *(EMACS_INT *) rdata =
670 case XD_LISP_OBJECT: {
674 assert(desc[pos].data1 == 0);
676 if (POINTER_TYPE_P(XTYPE(*pobj))
677 && XRECORD_LHEADER(*pobj)) {
680 (XRECORD_LHEADER(*pobj))
685 case XD_LISP_OBJECT_ARRAY: {
686 EMACS_INT num = desc[pos].data1;
689 if (XD_IS_INDIRECT(num)) {
690 num = pdump_get_indirect_count(
691 num, desc, elt->obj);
693 for (j = 0; j < num; j++) {
695 ((Lisp_Object*)rdata) +
699 XRECORD_LHEADER(*pobj)) {
710 case XD_DOC_STRING: {
711 EMACS_INT str = *(EMACS_INT*)rdata;
725 ("Unsupported dump type : %d\n",
732 fwrite(desc ? pdump_buf : elt->obj, size, count, pdump_out);
736 pdump_reloc_one(void *data, EMACS_INT delta,
737 const struct lrecord_description *desc)
742 for (pos = 0; desc[pos].type != XD_END; pos++) {
743 void *rdata = (char *)data + desc[pos].offset;
744 switch (desc[pos].type) {
745 case XD_SPECIFIER_END:
747 desc = ((const Lisp_Specifier *)data)->methods->
756 case XD_OPAQUE_DATA_PTR:
760 EMACS_INT ptr = *(EMACS_INT *) rdata;
762 *(EMACS_INT *) rdata = ptr + delta;
766 case XD_LISP_OBJECT: {
767 Lisp_Object *pobj = (Lisp_Object *) rdata;
769 assert(desc[pos].data1 == 0);
771 if (POINTER_TYPE_P(XTYPE(*pobj))
772 && !EQ(*pobj, Qnull_pointer))
774 (char *)XPNTR(*pobj) + delta);
778 case XD_LISP_OBJECT_ARRAY: {
779 EMACS_INT num = desc[pos].data1;
781 if (XD_IS_INDIRECT(num)) {
782 num = pdump_get_indirect_count(num, desc, data);
784 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)) {
790 (char *)XPNTR(*pobj) + delta);
795 case XD_DOC_STRING: {
796 EMACS_INT str = *(EMACS_INT *) rdata;
798 *(EMACS_INT *) rdata = str + delta;
806 stderr_out("Unsupported dump type : %d\n",
814 pdump_allocate_offset(pdump_entry_list_elt * elt,
815 const struct lrecord_description *desc)
817 size_t size = elt->count * elt->size;
818 elt->save_offset = cur_offset;
825 pdump_scan_by_alignment(void (*f) (pdump_entry_list_elt *,
826 const struct lrecord_description *))
830 for (align = ALIGNOF(max_align_t); align; align >>= 1) {
832 pdump_entry_list_elt *elt;
834 for (i = 0; i < lrecord_type_count; i++)
835 if (pdump_object_table[i].align == align)
836 for (elt = pdump_object_table[i].first; elt;
839 lrecord_implementations_table[i]->
842 for (i = 0; i < (size_t)pdump_struct_table.count; i++) {
843 pdump_struct_list_elt list = pdump_struct_table.list[i];
844 if (list.list.align == align)
845 for (elt = list.list.first; elt;
847 f(elt, list.sdesc->description);
850 for (elt = pdump_opaque_data_list.first; elt; elt = elt->next)
851 if (pdump_size_to_align(elt->size) ==
857 static void pdump_dump_root_struct_ptrs(void)
860 size_t count = Dynarr_length(pdump_root_struct_ptrs);
861 pdump_static_pointer *data = alloca_array(pdump_static_pointer, count);
862 for (i = 0; i < count; i++) {
864 (char **)Dynarr_atp(pdump_root_struct_ptrs, i)->ptraddress;
866 (char *)pdump_get_entry(*data[i].address)->save_offset;
868 PDUMP_ALIGN_OUTPUT(pdump_static_pointer);
869 fwrite(data, sizeof(pdump_static_pointer), count, pdump_out);
872 static void pdump_dump_opaques(void)
875 for (i = 0; i < Dynarr_length(pdump_opaques); i++) {
876 pdump_opaque *info = Dynarr_atp(pdump_opaques, i);
877 PDUMP_WRITE_ALIGNED(pdump_opaque, *info);
878 fwrite(info->varaddress, info->size, 1, pdump_out);
882 static void pdump_dump_rtables(void)
885 pdump_entry_list_elt *elt;
886 pdump_reloc_table rt;
888 for (i = 0; i < lrecord_type_count; i++) {
889 elt = pdump_object_table[i].first;
892 rt.desc = lrecord_implementations_table[i]->description;
893 rt.count = pdump_object_table[i].count;
894 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
897 pdump_get_entry(elt->obj)->save_offset;
898 PDUMP_WRITE_ALIGNED(EMACS_INT, rdata);
905 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
907 for (i = 0; i < (size_t)pdump_struct_table.count; i++) {
908 elt = pdump_struct_table.list[i].list.first;
909 rt.desc = pdump_struct_table.list[i].sdesc->description;
910 rt.count = pdump_struct_table.list[i].list.count;
911 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
914 pdump_get_entry(elt->obj)->save_offset;
916 for (j = 0; j < elt->count; j++) {
917 PDUMP_WRITE_ALIGNED(EMACS_INT, rdata);
925 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
928 static void pdump_dump_root_objects(void)
930 size_t count = (Dynarr_length(pdump_root_objects) +
931 Dynarr_length(pdump_weak_object_chains));
934 PDUMP_WRITE_ALIGNED(size_t, count);
935 PDUMP_ALIGN_OUTPUT(pdump_static_Lisp_Object);
937 for (i = 0; i < Dynarr_length(pdump_root_objects); i++) {
938 pdump_static_Lisp_Object obj;
939 obj.address = Dynarr_at(pdump_root_objects, i);
940 obj.value = *obj.address;
942 if (POINTER_TYPE_P(XTYPE(obj.value)))
945 pdump_get_entry(XRECORD_LHEADER
949 PDUMP_WRITE(pdump_static_Lisp_Object, obj);
952 for (i = 0; i < Dynarr_length(pdump_weak_object_chains); i++) {
953 pdump_entry_list_elt *elt;
954 pdump_static_Lisp_Object obj;
956 obj.address = Dynarr_at(pdump_weak_object_chains, i);
957 obj.value = *obj.address;
960 const struct lrecord_description *desc;
962 elt = pdump_get_entry(XRECORD_LHEADER(obj.value));
966 XRECORD_LHEADER_IMPLEMENTATION(obj.value)->
968 for (pos = 0; desc[pos].type != XD_LO_LINK; pos++)
969 assert(desc[pos].type != XD_END);
972 *(Lisp_Object *) (desc[pos].offset +
974 *)(XRECORD_LHEADER(obj.value)));
976 obj.value = wrap_object((void *)elt->save_offset);
978 PDUMP_WRITE(pdump_static_Lisp_Object, obj);
983 pdump(const char *dumpfile)
986 Lisp_Object t_console, t_device, t_frame;
990 pdump_object_table = xnew_array(pdump_entry_list, lrecord_type_count);
991 pdump_alert_undump_object = xnew_array(int, lrecord_type_count);
993 assert(ALIGNOF(max_align_t) <= pdump_align_table[0]);
995 for (i = 0; i < countof(pdump_align_table); i++)
996 if (pdump_align_table[i] > ALIGNOF(max_align_t))
997 pdump_align_table[i] = ALIGNOF(max_align_t);
999 flush_all_buffer_local_cache();
1001 /* These appear in a DEFVAR_LISP, which does a staticpro() */
1002 t_console = Vterminal_console;
1003 Vterminal_console = Qnil;
1004 t_frame = Vterminal_frame;
1005 Vterminal_frame = Qnil;
1006 t_device = Vterminal_device;
1007 Vterminal_device = Qnil;
1009 dump_add_opaque((void *)&lrecord_implementations_table,
1010 lrecord_type_count *
1011 sizeof(lrecord_implementations_table[0]));
1012 dump_add_opaque(&lrecord_markers,
1013 lrecord_type_count * sizeof(lrecord_markers[0]));
1015 pdump_hash = xnew_array_and_zero(pdump_entry_list_elt*, PDUMP_HASHSIZE);
1017 for (i = 0; i < lrecord_type_count; i++) {
1018 pdump_object_table[i].first = 0;
1019 pdump_object_table[i].align = ALIGNOF(max_align_t);
1020 pdump_object_table[i].count = 0;
1021 pdump_alert_undump_object[i] = 0;
1023 pdump_struct_table.count = 0;
1024 pdump_struct_table.size = -1;
1026 pdump_opaque_data_list.first = 0;
1027 pdump_opaque_data_list.align = ALIGNOF(max_align_t);
1028 pdump_opaque_data_list.count = 0;
1031 for (i = 0; i < (size_t)Dynarr_length(pdump_root_objects); i++) {
1032 pdump_register_object(*Dynarr_at(pdump_root_objects, i));
1036 for (i = 0; i < lrecord_type_count; i++)
1037 if (pdump_alert_undump_object[i]) {
1039 printf("Undumpable types list :\n");
1041 printf(" - %s (%d)\n",
1042 lrecord_implementations_table[i]->name,
1043 pdump_alert_undump_object[i]);
1049 for (i = 0; i < (size_t) Dynarr_length(pdump_root_struct_ptrs); i++) {
1050 pdump_root_struct_ptr info =
1051 Dynarr_at(pdump_root_struct_ptrs, i);
1052 pdump_register_struct(*(info.ptraddress), info.desc, 1);
1055 memcpy(header.signature, PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN);
1056 header.id = dump_id;
1057 header.reloc_address = 0;
1058 header.nb_root_struct_ptrs = Dynarr_length(pdump_root_struct_ptrs);
1059 header.nb_opaques = Dynarr_length(pdump_opaques);
1061 cur_offset = ALIGN_SIZE(sizeof(header), ALIGNOF(max_align_t));
1064 pdump_scan_by_alignment(pdump_allocate_offset);
1065 cur_offset = ALIGN_SIZE(cur_offset, ALIGNOF(max_align_t));
1066 header.stab_offset = cur_offset;
1068 pdump_buf = xmalloc_atomic(max_size);
1069 /* Avoid use of the `open' macro. We want the real function. */
1071 pdump_fd = open(dumpfile,
1072 O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY, 0666);
1073 if ( pdump_fd < 0 ) {
1074 stderr_out("Could not open dump file: %s", dumpfile);
1077 pdump_out = fdopen(pdump_fd, "w");
1078 if ( pdump_out < 0 ) {
1079 stderr_out("Could not fdopen dump file: %s %d",
1080 dumpfile, pdump_fd);
1084 fwrite(&header, sizeof(header), 1, pdump_out);
1085 PDUMP_ALIGN_OUTPUT(max_align_t);
1087 pdump_scan_by_alignment(pdump_dump_data);
1089 fseek(pdump_out, header.stab_offset, SEEK_SET);
1091 pdump_dump_root_struct_ptrs();
1092 pdump_dump_opaques();
1093 pdump_dump_rtables();
1094 pdump_dump_root_objects();
1103 Vterminal_console = t_console;
1104 Vterminal_frame = t_frame;
1105 Vterminal_device = t_device;
1110 static int pdump_load_check(void)
1112 return (!memcmp(((pdump_header*)pdump_start)->signature,
1113 PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN)
1114 && ((pdump_header *)pdump_start)->id == dump_id);
1117 /*----------------------------------------------------------------------*/
1118 /* Reading the dump file */
1119 /*----------------------------------------------------------------------*/
1121 pdump_load_finish(void)
1125 pdump_header *header = (pdump_header*)pdump_start;
1127 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
1128 int cache_GC_dont_gc = GC_dont_gc;
1133 pdump_end = pdump_start + pdump_length;
1135 delta = ((EMACS_INT)pdump_start) - header->reloc_address;
1136 p = pdump_start + header->stab_offset;
1138 /* Put back the pdump_root_struct_ptrs */
1139 p = (char*)ALIGN_PTR(p, ALIGNOF(pdump_static_pointer));
1140 for (int i = 0; i < header->nb_root_struct_ptrs; i++) {
1141 pdump_static_pointer ptr = PDUMP_READ(p, pdump_static_pointer);
1142 (*ptr.address) = ptr.value + delta;
1145 /* Put back the pdump_opaques */
1146 for (int i = 0; i < header->nb_opaques; i++) {
1147 pdump_opaque info = PDUMP_READ_ALIGNED(p, pdump_opaque);
1148 memcpy(info.varaddress, p, info.size);
1152 /* Do the relocations */
1154 for (EMACS_INT count = 2;;) {
1155 pdump_reloc_table rt = PDUMP_READ_ALIGNED(p, pdump_reloc_table);
1156 p = (char*)ALIGN_PTR(p, ALIGNOF(char*));
1158 char **reloc = (char**)p;
1159 for (int i = 0; i < rt.count; i++) {
1161 pdump_reloc_one(reloc[i], delta, rt.desc);
1163 p += rt.count * sizeof(char *);
1164 } else if (!(--count)) {
1169 /* Put the pdump_root_objects variables in place */
1170 p = (char*)ALIGN_PTR(p, ALIGNOF(pdump_static_Lisp_Object));
1172 for (int i = PDUMP_READ_ALIGNED(p, size_t); i--; ) {
1173 pdump_static_Lisp_Object obj =
1174 PDUMP_READ(p, pdump_static_Lisp_Object);
1176 if (POINTER_TYPE_P(XTYPE(obj.value))) {
1178 wrap_object((char*)XPNTR(obj.value) + delta);
1180 (*obj.address) = obj.value;
1183 /* Final cleanups */
1184 /* reorganize hash tables */
1187 pdump_reloc_table rt = PDUMP_READ_ALIGNED(p, pdump_reloc_table);
1188 p = (char*)ALIGN_PTR(p, ALIGNOF(Lisp_Object));
1193 if (rt.desc == hash_table_description) {
1194 for (int i = 0; i < rt.count; i++) {
1195 pdump_reorganize_hash_table(
1196 PDUMP_READ(p, Lisp_Object));
1200 p += sizeof(Lisp_Object) * rt.count;
1204 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
1205 GC_dont_gc = cache_GC_dont_gc;
1211 static void pdump_file_free(void)
1217 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1218 # if defined HAVE_MMAP
1219 static void pdump_file_unmap(void)
1221 munmap(pdump_start, pdump_length);
1223 # endif /* HAVE_MMAP */
1226 static int pdump_file_get(const char *path)
1228 int fd = open(path, O_RDONLY | OPEN_BINARY);
1230 if (UNLIKELY(fd < 0)) {
1234 pdump_length = lseek(fd, 0, SEEK_END);
1235 if (UNLIKELY(pdump_length < sizeof(pdump_header))) {
1240 lseek(fd, 0, SEEK_SET);
1242 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1243 # if defined HAVE_MMAP
1244 /* Unix 98 requires that sys/mman.h define MAP_FAILED,
1245 but many earlier implementations don't. */
1247 # define MAP_FAILED ((void*)-1L)
1248 # endif /* MAP_FAILED */
1249 pdump_start = (char*)mmap(0, pdump_length,
1250 PROT_READ | PROT_WRITE, MAP_PRIVATE,
1252 if (LIKELY(pdump_start != (char*)MAP_FAILED)) {
1253 pdump_free = pdump_file_unmap;
1257 # endif /* HAVE_MMAP */
1260 pdump_start = xnew_array(char, pdump_length);
1261 pdump_free = pdump_file_free;
1262 read(fd, pdump_start, pdump_length);
1268 static int pdump_file_try(char *exe_path, size_t size)
1270 char *w = exe_path + strlen(exe_path);
1272 size -= strlen(exe_path);
1276 #ifdef EMACS_PATCH_LEVEL
1277 sz = snprintf(w, size, "-%d.%d.%d-%08x.dmp",
1278 EMACS_MAJOR_VERSION, EMACS_MINOR_VERSION,
1279 EMACS_PATCH_LEVEL, dump_id);
1280 if (sz >=0 && sz < size && pdump_file_get(exe_path)) {
1281 if (pdump_load_check()) {
1286 #endif /* EMACS_PATCH_LEVEL */
1287 #ifdef EMACS_BETA_VERSION
1288 sz = snprintf(w, size, "-%d.%d.%d-%08x.dmp",
1289 EMACS_MAJOR_VERSION, EMACS_MINOR_VERSION,
1290 EMACS_BETA_VERSION, dump_id);
1291 if (sz >=0 && (size_t)sz < size && pdump_file_get(exe_path)) {
1292 if (pdump_load_check()) {
1297 #endif /* EMACS_BETA_VERSION */
1299 sz = snprintf(w, size, "-%08x.dmp", dump_id);
1300 if (sz >=0 && (size_t)sz < size && pdump_file_get(exe_path)) {
1301 if (pdump_load_check()) {
1307 sz = snprintf(w, size, ".dmp");
1308 if (sz >=0 && (size_t)sz < size && pdump_file_get(exe_path)) {
1309 if (pdump_load_check()) {
1317 } while (w > exe_path && !IS_DIRECTORY_SEP(*w) && (*w != '-')
1319 } while (w > exe_path && !IS_DIRECTORY_SEP(*w));
1324 wipe_out_libtool_stuff(char *path)
1326 #define dotlibs ".libs/"
1327 #define ltdash "lt-"
1330 for (p = strchr(path, '.'); p; p = strchr(p+1, '.')) {
1332 strncmp(p, dotlibs, sizeof(dotlibs)-1);
1334 strncmp(p+sizeof(dotlibs)-1, ltdash, sizeof(ltdash)-1);
1335 if ((dotlibsp || ltdashp) == 0) {
1336 /* cut out the `.libs/lt-' portion */
1337 size_t offs = sizeof(dotlibs)-1+sizeof(ltdash)-1;
1338 size_t rest = strlen(p + offs);
1339 memmove(p, p + offs, rest);
1342 } else if (dotlibsp == 0) {
1343 /* cut out the `.libs/' portion */
1344 size_t offs = sizeof(dotlibs)-1;
1345 size_t rest = strlen(p + offs);
1346 memmove(p, p + offs, rest);
1355 int pdump_load(const char *argv0)
1357 char exe_path[PATH_MAX], real_exe_path[PATH_MAX];
1359 const char *dir, *p;
1362 if (dir[0] == '-') {
1363 /* SXEmacs as a login shell, oh goody! */
1364 dir = getenv("SHELL");
1365 assert(dir != NULL);
1368 p = dir + strlen(dir);
1369 while (p != dir && !IS_ANY_SEP(p[-1])) {
1374 /* invocation-name includes a directory component -- presumably it
1375 is relative to cwd, not $PATH */
1376 assert(strlen(dir) < sizeof(exe_path));
1377 strncpy(exe_path, dir, sizeof(exe_path)-1);
1378 exe_path[sizeof(exe_path)-1]='\0';
1380 const char *path = getenv("PATH");
1381 const char *name = p;
1383 assert(path != NULL);
1385 int remain = sizeof(exe_path)-1;
1386 exe_path[remain] = '\0';
1389 while (*p && *p != SEPCHAR) {
1397 size_t len = (p - path) <= remain
1400 memcpy(exe_path, path, len);
1404 if (!IS_DIRECTORY_SEP(w[-1]) && (remain > 0) ) {
1409 strncpy(w, name, remain);
1413 /* Check that exe_path is executable and not a
1415 #undef access /* avoid !@#$%^& encapsulated access */
1416 #undef stat /* avoid !@#$%^& encapsulated stat */
1418 struct stat statbuf;
1419 if (access(exe_path, X_OK) == 0
1420 && stat(exe_path, &statbuf) == 0
1421 && !S_ISDIR(statbuf.st_mode))
1426 /* Oh well, let's have some kind of default */
1427 int sz = snprintf(exe_path, sizeof(exe_path),
1429 assert(sz >= 0 && (size_t)sz < sizeof(exe_path));
1437 /* do not use this one now as we follow libtool's concept of
1438 * convenience libraries and binaries */
1439 wipe_out_libtool_stuff(exe_path);
1442 /* Save exe_path because pdump_file_try() modifies it */
1443 assert(strlen(exe_path) < sizeof(real_exe_path));
1444 strcpy(real_exe_path, exe_path);
1445 if (pdump_file_try(exe_path,sizeof(exe_path))
1446 || (xrealpath(real_exe_path, real_exe_path)
1447 && pdump_file_try(real_exe_path,sizeof(real_exe_path)))) {
1448 pdump_load_finish();
1455 /* dumper.c ends here */