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);
608 pdump_dump_data(pdump_entry_list_elt * elt,
609 const struct lrecord_description *desc)
611 size_t size = elt->size;
612 int count = elt->count;
615 memcpy(pdump_buf, elt->obj, size * count);
617 for (i = 0; i < count; i++) {
618 char *cur = ((char *)pdump_buf) + i * size;
620 for (pos = 0; desc[pos].type != XD_END; pos++) {
621 void *rdata = cur + desc[pos].offset;
622 switch (desc[pos].type) {
623 case XD_SPECIFIER_END:
624 desc = ((const Lisp_Specifier *)
626 methods->extra_description;
634 EMACS_INT val = desc[pos].data1;
635 if (XD_IS_INDIRECT(val))
636 val = pdump_get_indirect_count(
637 val, desc, elt->obj);
641 case XD_OPAQUE_DATA_PTR:
643 case XD_STRUCT_PTR: {
644 void *ptr = *(void**)rdata;
646 *(EMACS_INT*) rdata =
653 Lisp_Object obj = *(Lisp_Object*)rdata;
654 pdump_entry_list_elt *elt1;
657 elt1 = pdump_get_entry(
658 XRECORD_LHEADER(obj));
662 obj = *(Lisp_Object*)(
665 (XRECORD_LHEADER(obj)));
667 *(EMACS_INT *) rdata =
671 case XD_LISP_OBJECT: {
675 assert(desc[pos].data1 == 0);
677 if (POINTER_TYPE_P(XTYPE(*pobj))
678 && XRECORD_LHEADER(*pobj)) {
681 (XRECORD_LHEADER(*pobj))
686 case XD_LISP_OBJECT_ARRAY: {
687 EMACS_INT num = desc[pos].data1;
690 if (XD_IS_INDIRECT(num)) {
691 num = pdump_get_indirect_count(
692 num, desc, elt->obj);
694 for (j = 0; j < num; j++) {
696 ((Lisp_Object*)rdata) +
700 XRECORD_LHEADER(*pobj)) {
711 case XD_DOC_STRING: {
712 EMACS_INT str = *(EMACS_INT*)rdata;
726 ("Unsupported dump type : %d\n",
733 fwrite(desc ? pdump_buf : elt->obj, size, count, pdump_out);
737 pdump_reloc_one(void *data, EMACS_INT delta,
738 const struct lrecord_description *desc)
743 for (pos = 0; desc[pos].type != XD_END; pos++) {
744 void *rdata = (char *)data + desc[pos].offset;
745 switch (desc[pos].type) {
746 case XD_SPECIFIER_END:
748 desc = ((const Lisp_Specifier *)data)->methods->
757 case XD_OPAQUE_DATA_PTR:
761 EMACS_INT ptr = *(EMACS_INT *) rdata;
763 *(EMACS_INT *) rdata = ptr + delta;
767 case XD_LISP_OBJECT: {
768 Lisp_Object *pobj = (Lisp_Object *) rdata;
770 assert(desc[pos].data1 == 0);
772 if (POINTER_TYPE_P(XTYPE(*pobj))
773 && !EQ(*pobj, Qnull_pointer))
775 (char *)XPNTR(*pobj) + delta);
779 case XD_LISP_OBJECT_ARRAY: {
780 EMACS_INT num = desc[pos].data1;
782 if (XD_IS_INDIRECT(num)) {
783 num = pdump_get_indirect_count(num, desc, data);
785 for (j = 0; j < num; j++) {
786 Lisp_Object *pobj = (Lisp_Object*)rdata + j;
788 if (POINTER_TYPE_P(XTYPE(*pobj))
789 && !EQ(*pobj, Qnull_pointer)) {
791 (char *)XPNTR(*pobj) + delta);
796 case XD_DOC_STRING: {
797 EMACS_INT str = *(EMACS_INT *) rdata;
799 *(EMACS_INT *) rdata = str + delta;
807 stderr_out("Unsupported dump type : %d\n",
815 pdump_allocate_offset(pdump_entry_list_elt * elt,
816 const struct lrecord_description *desc)
818 size_t size = elt->count * elt->size;
819 elt->save_offset = cur_offset;
826 pdump_scan_by_alignment(void (*f) (pdump_entry_list_elt *,
827 const struct lrecord_description *))
831 for (align = ALIGNOF(max_align_t); align; align >>= 1) {
833 pdump_entry_list_elt *elt;
835 for (i = 0; i < lrecord_type_count; i++)
836 if (pdump_object_table[i].align == align)
837 for (elt = pdump_object_table[i].first; elt;
840 lrecord_implementations_table[i]->
843 for (i = 0; i < (size_t)pdump_struct_table.count; i++) {
844 pdump_struct_list_elt list = pdump_struct_table.list[i];
845 if (list.list.align == align)
846 for (elt = list.list.first; elt;
848 f(elt, list.sdesc->description);
851 for (elt = pdump_opaque_data_list.first; elt; elt = elt->next)
852 if (pdump_size_to_align(elt->size) ==
858 static void pdump_dump_root_struct_ptrs(void)
861 size_t count = Dynarr_length(pdump_root_struct_ptrs);
862 pdump_static_pointer *data = alloca_array(pdump_static_pointer, count);
863 for (i = 0; i < count; i++) {
865 (char **)Dynarr_atp(pdump_root_struct_ptrs, i)->ptraddress;
867 (char *)pdump_get_entry(*data[i].address)->save_offset;
869 PDUMP_ALIGN_OUTPUT(pdump_static_pointer);
870 fwrite(data, sizeof(pdump_static_pointer), count, pdump_out);
873 static void pdump_dump_opaques(void)
876 for (i = 0; i < Dynarr_length(pdump_opaques); i++) {
877 pdump_opaque *info = Dynarr_atp(pdump_opaques, i);
878 PDUMP_WRITE_ALIGNED(pdump_opaque, *info);
879 fwrite(info->varaddress, info->size, 1, pdump_out);
883 static void pdump_dump_rtables(void)
886 pdump_entry_list_elt *elt;
887 pdump_reloc_table rt;
889 for (i = 0; i < lrecord_type_count; i++) {
890 elt = pdump_object_table[i].first;
893 rt.desc = lrecord_implementations_table[i]->description;
894 rt.count = pdump_object_table[i].count;
895 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
898 pdump_get_entry(elt->obj)->save_offset;
899 PDUMP_WRITE_ALIGNED(EMACS_INT, rdata);
906 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
908 for (i = 0; i < (size_t)pdump_struct_table.count; i++) {
909 elt = pdump_struct_table.list[i].list.first;
910 rt.desc = pdump_struct_table.list[i].sdesc->description;
911 rt.count = pdump_struct_table.list[i].list.count;
912 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
915 pdump_get_entry(elt->obj)->save_offset;
917 for (j = 0; j < elt->count; j++) {
918 PDUMP_WRITE_ALIGNED(EMACS_INT, rdata);
926 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
929 static void pdump_dump_root_objects(void)
931 size_t count = (Dynarr_length(pdump_root_objects) +
932 Dynarr_length(pdump_weak_object_chains));
935 PDUMP_WRITE_ALIGNED(size_t, count);
936 PDUMP_ALIGN_OUTPUT(pdump_static_Lisp_Object);
938 for (i = 0; i < Dynarr_length(pdump_root_objects); i++) {
939 pdump_static_Lisp_Object obj;
940 obj.address = Dynarr_at(pdump_root_objects, i);
941 obj.value = *obj.address;
943 if (POINTER_TYPE_P(XTYPE(obj.value)))
946 pdump_get_entry(XRECORD_LHEADER
950 PDUMP_WRITE(pdump_static_Lisp_Object, obj);
953 for (i = 0; i < Dynarr_length(pdump_weak_object_chains); i++) {
954 pdump_entry_list_elt *elt;
955 pdump_static_Lisp_Object obj;
957 obj.address = Dynarr_at(pdump_weak_object_chains, i);
958 obj.value = *obj.address;
961 const struct lrecord_description *desc;
963 elt = pdump_get_entry(XRECORD_LHEADER(obj.value));
967 XRECORD_LHEADER_IMPLEMENTATION(obj.value)->
969 for (pos = 0; desc[pos].type != XD_LO_LINK; pos++)
970 assert(desc[pos].type != XD_END);
973 *(Lisp_Object *) (desc[pos].offset +
975 *)(XRECORD_LHEADER(obj.value)));
977 obj.value = wrap_object((void *)elt->save_offset);
979 PDUMP_WRITE(pdump_static_Lisp_Object, obj);
984 pdump(const char *dumpfile)
987 Lisp_Object t_console, t_device, t_frame;
991 pdump_object_table = xnew_array(pdump_entry_list, lrecord_type_count);
992 pdump_alert_undump_object = xnew_array(int, lrecord_type_count);
994 assert(ALIGNOF(max_align_t) <= pdump_align_table[0]);
996 for (i = 0; i < countof(pdump_align_table); i++)
997 if (pdump_align_table[i] > ALIGNOF(max_align_t))
998 pdump_align_table[i] = ALIGNOF(max_align_t);
1000 flush_all_buffer_local_cache();
1002 /* These appear in a DEFVAR_LISP, which does a staticpro() */
1003 t_console = Vterminal_console;
1004 Vterminal_console = Qnil;
1005 t_frame = Vterminal_frame;
1006 Vterminal_frame = Qnil;
1007 t_device = Vterminal_device;
1008 Vterminal_device = Qnil;
1010 dump_add_opaque((void *)&lrecord_implementations_table,
1011 lrecord_type_count *
1012 sizeof(lrecord_implementations_table[0]));
1013 dump_add_opaque(&lrecord_markers,
1014 lrecord_type_count * sizeof(lrecord_markers[0]));
1016 pdump_hash = xnew_array_and_zero(pdump_entry_list_elt*, PDUMP_HASHSIZE);
1018 for (i = 0; i < lrecord_type_count; i++) {
1019 pdump_object_table[i].first = 0;
1020 pdump_object_table[i].align = ALIGNOF(max_align_t);
1021 pdump_object_table[i].count = 0;
1022 pdump_alert_undump_object[i] = 0;
1024 pdump_struct_table.count = 0;
1025 pdump_struct_table.size = -1;
1027 pdump_opaque_data_list.first = 0;
1028 pdump_opaque_data_list.align = ALIGNOF(max_align_t);
1029 pdump_opaque_data_list.count = 0;
1032 for (i = 0; i < (size_t)Dynarr_length(pdump_root_objects); i++) {
1033 pdump_register_object(*Dynarr_at(pdump_root_objects, i));
1037 for (i = 0; i < lrecord_type_count; i++)
1038 if (pdump_alert_undump_object[i]) {
1040 printf("Undumpable types list :\n");
1042 printf(" - %s (%d)\n",
1043 lrecord_implementations_table[i]->name,
1044 pdump_alert_undump_object[i]);
1050 for (i = 0; i < (size_t) Dynarr_length(pdump_root_struct_ptrs); i++) {
1051 pdump_root_struct_ptr info =
1052 Dynarr_at(pdump_root_struct_ptrs, i);
1053 pdump_register_struct(*(info.ptraddress), info.desc, 1);
1056 memcpy(header.signature, PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN);
1057 header.id = dump_id;
1058 header.reloc_address = 0;
1059 header.nb_root_struct_ptrs = Dynarr_length(pdump_root_struct_ptrs);
1060 header.nb_opaques = Dynarr_length(pdump_opaques);
1062 cur_offset = ALIGN_SIZE(sizeof(header), ALIGNOF(max_align_t));
1065 pdump_scan_by_alignment(pdump_allocate_offset);
1066 cur_offset = ALIGN_SIZE(cur_offset, ALIGNOF(max_align_t));
1067 header.stab_offset = cur_offset;
1069 pdump_buf = xmalloc_atomic(max_size);
1070 /* Avoid use of the `open' macro. We want the real function. */
1072 pdump_fd = open(dumpfile,
1073 O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY, 0666);
1074 if ( pdump_fd < 0 ) {
1075 stderr_out("Could not open dump file: %s", dumpfile);
1078 pdump_out = fdopen(pdump_fd, "w");
1079 if ( pdump_out < 0 ) {
1080 stderr_out("Could not fdopen dump file: %s %d",
1081 dumpfile, pdump_fd);
1085 fwrite(&header, sizeof(header), 1, pdump_out);
1086 PDUMP_ALIGN_OUTPUT(max_align_t);
1088 pdump_scan_by_alignment(pdump_dump_data);
1090 fseek(pdump_out, header.stab_offset, SEEK_SET);
1092 pdump_dump_root_struct_ptrs();
1093 pdump_dump_opaques();
1094 pdump_dump_rtables();
1095 pdump_dump_root_objects();
1104 Vterminal_console = t_console;
1105 Vterminal_frame = t_frame;
1106 Vterminal_device = t_device;
1111 static int pdump_load_check(void)
1113 return (!memcmp(((pdump_header*)pdump_start)->signature,
1114 PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN)
1115 && ((pdump_header *)pdump_start)->id == dump_id);
1118 /*----------------------------------------------------------------------*/
1119 /* Reading the dump file */
1120 /*----------------------------------------------------------------------*/
1122 pdump_load_finish(void)
1126 pdump_header *header = (pdump_header*)pdump_start;
1128 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
1129 int cache_GC_dont_gc = GC_dont_gc;
1134 pdump_end = pdump_start + pdump_length;
1136 delta = ((EMACS_INT)pdump_start) - header->reloc_address;
1137 p = pdump_start + header->stab_offset;
1139 /* Put back the pdump_root_struct_ptrs */
1140 p = (char*)ALIGN_PTR(p, ALIGNOF(pdump_static_pointer));
1141 for (int i = 0; i < header->nb_root_struct_ptrs; i++) {
1142 pdump_static_pointer ptr = PDUMP_READ(p, pdump_static_pointer);
1143 (*ptr.address) = ptr.value + delta;
1146 /* Put back the pdump_opaques */
1147 for (int i = 0; i < header->nb_opaques; i++) {
1148 pdump_opaque info = PDUMP_READ_ALIGNED(p, pdump_opaque);
1149 memcpy(info.varaddress, p, info.size);
1153 /* Do the relocations */
1155 for (EMACS_INT count = 2;;) {
1156 pdump_reloc_table rt = PDUMP_READ_ALIGNED(p, pdump_reloc_table);
1157 p = (char*)ALIGN_PTR(p, ALIGNOF(char*));
1159 char **reloc = (char**)p;
1160 for (int i = 0; i < rt.count; i++) {
1162 pdump_reloc_one(reloc[i], delta, rt.desc);
1164 p += rt.count * sizeof(char *);
1165 } else if (!(--count)) {
1170 /* Put the pdump_root_objects variables in place */
1171 p = (char*)ALIGN_PTR(p, ALIGNOF(pdump_static_Lisp_Object));
1173 for (int i = PDUMP_READ_ALIGNED(p, size_t); i--; ) {
1174 pdump_static_Lisp_Object obj =
1175 PDUMP_READ(p, pdump_static_Lisp_Object);
1177 if (POINTER_TYPE_P(XTYPE(obj.value))) {
1179 wrap_object((char*)XPNTR(obj.value) + delta);
1181 (*obj.address) = obj.value;
1184 /* Final cleanups */
1185 /* reorganize hash tables */
1188 pdump_reloc_table rt = PDUMP_READ_ALIGNED(p, pdump_reloc_table);
1189 p = (char*)ALIGN_PTR(p, ALIGNOF(Lisp_Object));
1194 if (rt.desc == hash_table_description) {
1195 for (int i = 0; i < rt.count; i++) {
1196 pdump_reorganize_hash_table(
1197 PDUMP_READ(p, Lisp_Object));
1201 p += sizeof(Lisp_Object) * rt.count;
1205 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
1206 GC_dont_gc = cache_GC_dont_gc;
1212 static void pdump_file_free(void)
1218 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1219 # if defined HAVE_MMAP
1220 static void pdump_file_unmap(void)
1222 munmap(pdump_start, pdump_length);
1224 # endif /* HAVE_MMAP */
1227 static int pdump_file_get(const char *path)
1229 int fd = open(path, O_RDONLY | OPEN_BINARY);
1231 if (UNLIKELY(fd < 0)) {
1235 pdump_length = lseek(fd, 0, SEEK_END);
1236 if (UNLIKELY(pdump_length < sizeof(pdump_header))) {
1241 lseek(fd, 0, SEEK_SET);
1243 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1244 # if defined HAVE_MMAP
1245 /* Unix 98 requires that sys/mman.h define MAP_FAILED,
1246 but many earlier implementations don't. */
1248 # define MAP_FAILED ((void*)-1L)
1249 # endif /* MAP_FAILED */
1250 pdump_start = (char*)mmap(0, pdump_length,
1251 PROT_READ | PROT_WRITE, MAP_PRIVATE,
1253 if (LIKELY(pdump_start != (char*)MAP_FAILED)) {
1254 pdump_free = pdump_file_unmap;
1258 # endif /* HAVE_MMAP */
1261 pdump_start = xnew_array(char, pdump_length);
1262 pdump_free = pdump_file_free;
1263 read(fd, pdump_start, pdump_length);
1269 static int pdump_file_try(char *exe_path, size_t size)
1271 char *w = exe_path + strlen(exe_path);
1273 size -= strlen(exe_path);
1277 #ifdef EMACS_PATCH_LEVEL
1278 sz = snprintf(w, size, "-%d.%d.%d-%08x.dmp",
1279 EMACS_MAJOR_VERSION, EMACS_MINOR_VERSION,
1280 EMACS_PATCH_LEVEL, dump_id);
1281 if (sz >=0 && sz < size && pdump_file_get(exe_path)) {
1282 if (pdump_load_check()) {
1287 #endif /* EMACS_PATCH_LEVEL */
1288 #ifdef EMACS_BETA_VERSION
1289 sz = snprintf(w, size, "-%d.%d.%d-%08x.dmp",
1290 EMACS_MAJOR_VERSION, EMACS_MINOR_VERSION,
1291 EMACS_BETA_VERSION, dump_id);
1292 if (sz >=0 && (size_t)sz < size && pdump_file_get(exe_path)) {
1293 if (pdump_load_check()) {
1298 #endif /* EMACS_BETA_VERSION */
1300 sz = snprintf(w, size, "-%08x.dmp", dump_id);
1301 if (sz >=0 && (size_t)sz < size && pdump_file_get(exe_path)) {
1302 if (pdump_load_check()) {
1308 sz = snprintf(w, size, ".dmp");
1309 if (sz >=0 && (size_t)sz < size && pdump_file_get(exe_path)) {
1310 if (pdump_load_check()) {
1318 } while (w > exe_path && !IS_DIRECTORY_SEP(*w) && (*w != '-')
1320 } while (w > exe_path && !IS_DIRECTORY_SEP(*w));
1325 wipe_out_libtool_stuff(char *path)
1327 #define dotlibs ".libs/"
1328 #define ltdash "lt-"
1331 for (p = strchr(path, '.'); p; p = strchr(p+1, '.')) {
1333 strncmp(p, dotlibs, sizeof(dotlibs)-1);
1335 strncmp(p+sizeof(dotlibs)-1, ltdash, sizeof(ltdash)-1);
1336 if ((dotlibsp || ltdashp) == 0) {
1337 /* cut out the `.libs/lt-' portion */
1338 size_t offs = sizeof(dotlibs)-1+sizeof(ltdash)-1;
1339 size_t rest = strlen(p + offs);
1340 memmove(p, p + offs, rest);
1343 } else if (dotlibsp == 0) {
1344 /* cut out the `.libs/' portion */
1345 size_t offs = sizeof(dotlibs)-1;
1346 size_t rest = strlen(p + offs);
1347 memmove(p, p + offs, rest);
1356 int pdump_load(const char *argv0)
1358 char exe_path[PATH_MAX], real_exe_path[PATH_MAX];
1360 const char *dir, *p;
1363 if (dir[0] == '-') {
1364 /* SXEmacs as a login shell, oh goody! */
1365 dir = getenv("SHELL");
1366 assert(dir != NULL);
1369 p = dir + strlen(dir);
1370 while (p != dir && !IS_ANY_SEP(p[-1])) {
1375 /* invocation-name includes a directory component -- presumably it
1376 is relative to cwd, not $PATH */
1377 assert(strlen(dir) < sizeof(exe_path));
1378 strncpy(exe_path, dir, sizeof(exe_path)-1);
1379 exe_path[sizeof(exe_path)-1]='\0';
1381 const char *path = getenv("PATH");
1382 const char *name = p;
1384 assert(path != NULL);
1386 int remain = sizeof(exe_path)-1;
1387 exe_path[remain] = '\0';
1390 while (*p && *p != SEPCHAR) {
1398 size_t len = (p - path) <= remain
1401 memcpy(exe_path, path, len);
1405 if (!IS_DIRECTORY_SEP(w[-1]) && (remain > 0) ) {
1410 strncpy(w, name, remain);
1414 /* Check that exe_path is executable and not a
1416 #undef access /* avoid !@#$%^& encapsulated access */
1417 #undef stat /* avoid !@#$%^& encapsulated stat */
1419 struct stat statbuf;
1420 if (access(exe_path, X_OK) == 0
1421 && stat(exe_path, &statbuf) == 0
1422 && !S_ISDIR(statbuf.st_mode))
1427 /* Oh well, let's have some kind of default */
1428 int sz = snprintf(exe_path, sizeof(exe_path),
1430 assert(sz >= 0 && (size_t)sz < sizeof(exe_path));
1438 /* do not use this one now as we follow libtool's concept of
1439 * convenience libraries and binaries */
1440 wipe_out_libtool_stuff(exe_path);
1443 /* Save exe_path because pdump_file_try() modifies it */
1444 assert(strlen(exe_path) < sizeof(real_exe_path));
1445 strcpy(real_exe_path, exe_path);
1446 if (pdump_file_try(exe_path,sizeof(exe_path))
1447 || (xrealpath(real_exe_path, real_exe_path)
1448 && pdump_file_try(real_exe_path,sizeof(real_exe_path)))) {
1449 pdump_load_finish();
1456 /* dumper.c ends here */