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"
38 #include <sxe-paths.h>
50 Dynarr_declare(pdump_opaque);
51 } pdump_opaque_dynarr;
55 const struct struct_description *desc;
56 } pdump_root_struct_ptr;
59 Dynarr_declare(pdump_root_struct_ptr);
60 } pdump_root_struct_ptr_dynarr;
65 } pdump_static_Lisp_Object;
68 char **address; /* char * for ease of doing relocation */
70 } pdump_static_pointer;
72 static pdump_opaque_dynarr *pdump_opaques;
73 static pdump_root_struct_ptr_dynarr *pdump_root_struct_ptrs;
74 static Lisp_Object_ptr_dynarr *pdump_root_objects;
75 static Lisp_Object_ptr_dynarr *pdump_weak_object_chains;
77 /* Mark SIZE bytes at non-heap address VARADDRESS for dumping as is,
78 without any bit-twiddling. */
79 void dump_add_opaque(void *varaddress, size_t size)
82 info.varaddress = varaddress;
84 if (pdump_opaques == NULL)
85 pdump_opaques = Dynarr_new(pdump_opaque);
86 Dynarr_add(pdump_opaques, info);
89 /* Mark the struct described by DESC and pointed to by the pointer at
90 non-heap address VARADDRESS for dumping.
91 All the objects reachable from this pointer will also be dumped. */
93 dump_add_root_struct_ptr(void *ptraddress,
94 const struct struct_description *desc)
96 pdump_root_struct_ptr info;
97 info.ptraddress = (void **)ptraddress;
99 if (pdump_root_struct_ptrs == NULL)
100 pdump_root_struct_ptrs = Dynarr_new(pdump_root_struct_ptr);
101 Dynarr_add(pdump_root_struct_ptrs, info);
104 /* Mark the Lisp_Object at non-heap address VARADDRESS for dumping.
105 All the objects reachable from this var will also be dumped. */
106 void dump_add_root_object(Lisp_Object * varaddress)
108 if (pdump_root_objects == NULL)
110 Dynarr_new2(Lisp_Object_ptr_dynarr, Lisp_Object *);
111 Dynarr_add(pdump_root_objects, varaddress);
114 /* Mark the list pointed to by the Lisp_Object at VARADDRESS for dumping. */
115 void dump_add_weak_object_chain(Lisp_Object * varaddress)
117 if (pdump_weak_object_chains == NULL)
118 pdump_weak_object_chains =
119 Dynarr_new2(Lisp_Object_ptr_dynarr, Lisp_Object *);
120 Dynarr_add(pdump_weak_object_chains, varaddress);
123 inline static void pdump_align_stream(FILE * stream, size_t alignment)
125 long offset = ftell(stream);
126 long adjustment = ALIGN_SIZE(offset, alignment) - offset;
128 fseek(stream, adjustment, SEEK_CUR);
131 #define PDUMP_ALIGN_OUTPUT(type) pdump_align_stream (pdump_out, ALIGNOF (type))
133 #define PDUMP_WRITE(type, object) \
134 fwrite (&object, sizeof (object), 1, pdump_out);
136 #define PDUMP_WRITE_ALIGNED(type, object) do { \
137 PDUMP_ALIGN_OUTPUT (type); \
138 PDUMP_WRITE (type, object); \
141 #define PDUMP_READ(ptr, type) \
142 (((type *) (ptr = (char*) (((type *) ptr) + 1)))[-1])
144 #define PDUMP_READ_ALIGNED(ptr, type) \
145 ((ptr = (char *) ALIGN_PTR (ptr, ALIGNOF (type))), PDUMP_READ (ptr, type))
148 const struct lrecord_description *desc;
152 static char *pdump_rt_list = 0;
154 void pdump_objects_unmark(void)
157 char *p = pdump_rt_list;
160 pdump_reloc_table *rt = (pdump_reloc_table *) p;
161 p += sizeof(pdump_reloc_table);
163 for (i = 0; i < rt->count; i++) {
164 struct lrecord_header *lh =
165 *(struct lrecord_header **)p;
166 if (!C_READONLY_RECORD_HEADER_P(lh))
167 UNMARK_RECORD_HEADER(lh);
168 p += sizeof(EMACS_INT);
175 /* The structure of the file
178 stab_offset - nb_root_struct_ptrs*pair(void *, adr)
179 for pointers to structures
180 - nb_opaques*pair(void *, size) for raw bits to restore
182 - root lisp object address/value couples with the count
186 #define PDUMP_SIGNATURE "SXEmacsDP"
187 #define PDUMP_SIGNATURE_LEN (sizeof (PDUMP_SIGNATURE) - 1)
190 char signature[PDUMP_SIGNATURE_LEN];
192 EMACS_UINT stab_offset;
193 EMACS_UINT reloc_address;
194 int nb_root_struct_ptrs;
200 static off_t pdump_length;
203 static void (*pdump_free) (void);
205 static unsigned char pdump_align_table[] = {
206 64, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
207 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
208 32, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1,
209 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1
212 static inline unsigned int pdump_size_to_align(size_t size)
214 return pdump_align_table[size % countof(pdump_align_table)];
217 typedef struct pdump_entry_list_elt {
218 struct pdump_entry_list_elt *next;
222 EMACS_INT save_offset;
223 } pdump_entry_list_elt;
226 pdump_entry_list_elt *first;
231 typedef struct pdump_struct_list_elt {
232 pdump_entry_list list;
233 const struct struct_description *sdesc;
234 } pdump_struct_list_elt;
237 pdump_struct_list_elt *list;
242 static pdump_entry_list *pdump_object_table;
243 static pdump_entry_list pdump_opaque_data_list;
244 static pdump_struct_list pdump_struct_table;
246 static int *pdump_alert_undump_object;
248 static unsigned long cur_offset;
249 static size_t max_size;
251 static void *pdump_buf;
252 static FILE *pdump_out;
254 #define PDUMP_HASHSIZE 200001
256 static pdump_entry_list_elt **pdump_hash;
258 /* Since most pointers are eight bytes aligned, the >>3 allows for a better hash */
259 static int pdump_make_hash(const void *obj)
261 return ((unsigned long)(obj) >> 3) % PDUMP_HASHSIZE;
264 static pdump_entry_list_elt *pdump_get_entry(const void *obj)
266 int pos = pdump_make_hash(obj);
267 pdump_entry_list_elt *e;
271 while ((e = pdump_hash[pos]) != 0) {
276 if (pos == PDUMP_HASHSIZE)
283 pdump_add_entry(pdump_entry_list *l, const void *obj, size_t size, int count)
285 pdump_entry_list_elt *e;
286 int pos = pdump_make_hash(obj);
288 while ((e = pdump_hash[pos]) != 0) {
293 if (pos == PDUMP_HASHSIZE) {
298 e = xnew(pdump_entry_list_elt);
310 int align = pdump_size_to_align(size);
312 if (align < l->align) {
319 static pdump_entry_list*
320 pdump_get_entry_list(const struct struct_description *sdesc)
323 for (i = 0; i < pdump_struct_table.count; i++)
324 if (pdump_struct_table.list[i].sdesc == sdesc)
325 return &pdump_struct_table.list[i].list;
327 if (pdump_struct_table.size <= pdump_struct_table.count) {
328 if (pdump_struct_table.size == -1)
329 pdump_struct_table.size = 10;
331 pdump_struct_table.size = pdump_struct_table.size * 2;
332 pdump_struct_table.list = (pdump_struct_list_elt *)
333 xrealloc(pdump_struct_table.list,
334 pdump_struct_table.size *
335 sizeof(pdump_struct_list_elt));
337 pdump_struct_table.list[pdump_struct_table.count].list.first = 0;
338 pdump_struct_table.list[pdump_struct_table.count].list.align =
339 ALIGNOF(max_align_t);
340 pdump_struct_table.list[pdump_struct_table.count].list.count = 0;
341 pdump_struct_table.list[pdump_struct_table.count].sdesc = sdesc;
343 return &pdump_struct_table.list[pdump_struct_table.count++].list;
347 struct lrecord_header *obj;
354 static void pdump_backtrace(void)
357 stderr_out("pdump backtrace :\n");
358 for (i = 0; i < depth; i++) {
359 if (!backtrace[i].obj)
360 stderr_out(" - ind. (%d, %d)\n",
361 backtrace[i].position, backtrace[i].offset);
363 stderr_out(" - %s (%d, %d)\n",
364 LHEADER_IMPLEMENTATION(backtrace[i].obj)->
365 name, backtrace[i].position,
366 backtrace[i].offset);
371 static void pdump_register_object(Lisp_Object obj);
372 static void pdump_register_struct(const void *data,
373 const struct struct_description *sdesc,
377 pdump_get_indirect_count(EMACS_INT code,
378 const struct lrecord_description *idesc,
381 EMACS_INT count = 0; /* initialize to shut up GCC */
384 int line = XD_INDIRECT_VAL(code);
385 int delta = XD_INDIRECT_DELTA(code);
387 irdata = ((const char *)idata) + idesc[line].offset;
388 switch (idesc[line].type) {
390 count = *(const size_t*)irdata;
393 count = *(const int*)irdata;
396 count = *(const long*)irdata;
399 count = *(const Bytecount*)irdata;
402 /* list the rest here */
403 case XD_LISP_OBJECT_ARRAY:
408 case XD_OPAQUE_DATA_PTR:
413 case XD_SPECIFIER_END:
417 ("Unsupported count type : %d (line = %d, code=%ld)\n",
418 idesc[line].type, line, (long)code);
427 pdump_register_sub(const void *data, const struct lrecord_description *desc,
433 for (pos = 0; desc[pos].type != XD_END; pos++) {
434 const void *rdata = (const char *)data + desc[pos].offset;
436 backtrace[me].position = pos;
437 backtrace[me].offset = desc[pos].offset;
439 switch (desc[pos].type) {
440 case XD_SPECIFIER_END:
443 ((const Lisp_Specifier *)data)->methods->
453 case XD_OPAQUE_DATA_PTR: {
454 EMACS_INT count = desc[pos].data1;
455 if (XD_IS_INDIRECT(count)) {
456 count = pdump_get_indirect_count(
459 pdump_add_entry(&pdump_opaque_data_list,
460 *(const void *const*)rdata, count, 1);
464 const char *str = *(const char *const*)rdata;
466 size_t str_sz = strlen(str);
467 pdump_add_entry(&pdump_opaque_data_list,
472 case XD_DOC_STRING: {
473 const char *str = *(const char *const*)rdata;
474 if ((EMACS_INT)str > 0) {
475 pdump_add_entry(&pdump_opaque_data_list,
476 str, strlen(str) + 1, 1);
480 case XD_LISP_OBJECT: {
481 const Lisp_Object *pobj = (const Lisp_Object*)rdata;
483 assert(desc[pos].data1 == 0);
485 backtrace[me].offset =
486 (const char *)pobj - (const char *)data;
487 pdump_register_object(*pobj);
490 case XD_LISP_OBJECT_ARRAY: {
492 EMACS_INT count = desc[pos].data1;
494 if (XD_IS_INDIRECT(count)) {
495 count = pdump_get_indirect_count(
498 for (i = 0; i < count; i++) {
499 const Lisp_Object *pobj =
500 ((const Lisp_Object*)rdata) + i;
501 Lisp_Object dobj = *pobj;
503 backtrace[me].offset =
506 pdump_register_object(dobj);
510 case XD_STRUCT_PTR: {
511 EMACS_INT count = desc[pos].data1;
512 const struct struct_description *sdesc =
514 const char *dobj = *(const char *const*)rdata;
517 if (XD_IS_INDIRECT(count)) {
518 count = pdump_get_indirect_count(
521 pdump_register_struct(dobj, sdesc, count);
529 stderr_out("Unsupported dump type : %d\n",
538 pdump_register_object(Lisp_Object obj)
540 struct lrecord_header *objh;
541 const struct lrecord_implementation *imp;
543 if (!POINTER_TYPE_P(XTYPE(obj))) {
547 objh = XRECORD_LHEADER(obj);
552 if (pdump_get_entry(objh)) {
556 imp = LHEADER_IMPLEMENTATION(objh);
558 if (imp->description) {
561 stderr_out("Backtrace overflow, loop ?\n");
565 backtrace[me].obj = objh;
566 backtrace[me].position = 0;
567 backtrace[me].offset = 0;
569 pdump_add_entry(pdump_object_table + objh->type,
573 imp->size_in_bytes_method(objh), 1);
574 pdump_register_sub(objh, imp->description, me);
577 pdump_alert_undump_object[objh->type]++;
578 stderr_out("Undumpable object type : %s\n", imp->name);
584 pdump_register_struct(const void *data,
585 const struct struct_description *sdesc, int count)
587 if (data && !pdump_get_entry(data)) {
591 stderr_out("Backtrace overflow, loop ?\n");
594 backtrace[me].obj = 0;
595 backtrace[me].position = 0;
596 backtrace[me].offset = 0;
598 pdump_add_entry(pdump_get_entry_list(sdesc),
599 data, sdesc->size, count);
600 for (i = 0; i < count; i++) {
602 ((const char*)data) + sdesc->size * i,
603 sdesc->description, me);
611 pdump_dump_data(pdump_entry_list_elt * elt,
612 const struct lrecord_description *desc)
614 size_t size = elt->size;
615 int count = elt->count;
618 memcpy(pdump_buf, elt->obj, size * count);
620 for (i = 0; i < count; i++) {
621 char *cur = ((char *)pdump_buf) + i * size;
623 for (pos = 0; desc[pos].type != XD_END; pos++) {
624 void *rdata = cur + desc[pos].offset;
625 switch (desc[pos].type) {
626 case XD_SPECIFIER_END:
627 desc = ((const Lisp_Specifier *)
629 methods->extra_description;
637 EMACS_INT val = desc[pos].data1;
638 if (XD_IS_INDIRECT(val))
639 val = pdump_get_indirect_count(
640 val, desc, elt->obj);
644 case XD_OPAQUE_DATA_PTR:
646 case XD_STRUCT_PTR: {
647 void *ptr = *(void**)rdata;
649 *(EMACS_INT*) rdata =
656 Lisp_Object obj = *(Lisp_Object*)rdata;
657 pdump_entry_list_elt *elt1;
660 elt1 = pdump_get_entry(
661 XRECORD_LHEADER(obj));
665 obj = *(Lisp_Object*)(
668 (XRECORD_LHEADER(obj)));
670 *(EMACS_INT *) rdata =
674 case XD_LISP_OBJECT: {
678 assert(desc[pos].data1 == 0);
680 if (POINTER_TYPE_P(XTYPE(*pobj))
681 && XRECORD_LHEADER(*pobj)) {
684 (XRECORD_LHEADER(*pobj))
689 case XD_LISP_OBJECT_ARRAY: {
690 EMACS_INT num = desc[pos].data1;
693 if (XD_IS_INDIRECT(num)) {
694 num = pdump_get_indirect_count(
695 num, desc, elt->obj);
697 for (j = 0; j < num; j++) {
699 ((Lisp_Object*)rdata) +
703 XRECORD_LHEADER(*pobj)) {
714 case XD_DOC_STRING: {
715 EMACS_INT str = *(EMACS_INT*)rdata;
729 ("Unsupported dump type : %d\n",
736 fwrite(desc ? pdump_buf : elt->obj, size, count, pdump_out);
740 pdump_reloc_one(void *data, EMACS_INT delta,
741 const struct lrecord_description *desc)
746 for (pos = 0; desc[pos].type != XD_END; pos++) {
747 void *rdata = (char *)data + desc[pos].offset;
748 switch (desc[pos].type) {
749 case XD_SPECIFIER_END:
751 desc = ((const Lisp_Specifier *)data)->methods->
760 case XD_OPAQUE_DATA_PTR:
764 EMACS_INT ptr = *(EMACS_INT *) rdata;
766 *(EMACS_INT *) rdata = ptr + delta;
770 case XD_LISP_OBJECT: {
771 Lisp_Object *pobj = (Lisp_Object *) rdata;
773 assert(desc[pos].data1 == 0);
775 if (POINTER_TYPE_P(XTYPE(*pobj))
776 && !EQ(*pobj, Qnull_pointer))
778 (char *)XPNTR(*pobj) + delta);
782 case XD_LISP_OBJECT_ARRAY: {
783 EMACS_INT num = desc[pos].data1;
785 if (XD_IS_INDIRECT(num)) {
786 num = pdump_get_indirect_count(num, desc, data);
788 for (j = 0; j < num; j++) {
789 Lisp_Object *pobj = (Lisp_Object*)rdata + j;
791 if (POINTER_TYPE_P(XTYPE(*pobj))
792 && !EQ(*pobj, Qnull_pointer)) {
794 (char *)XPNTR(*pobj) + delta);
799 case XD_DOC_STRING: {
800 EMACS_INT str = *(EMACS_INT *) rdata;
802 *(EMACS_INT *) rdata = str + delta;
810 stderr_out("Unsupported dump type : %d\n",
818 pdump_allocate_offset(pdump_entry_list_elt * elt,
819 const struct lrecord_description *desc)
821 size_t size = elt->count * elt->size;
822 elt->save_offset = cur_offset;
829 pdump_scan_by_alignment(void (*f) (pdump_entry_list_elt *,
830 const struct lrecord_description *))
834 for (align = ALIGNOF(max_align_t); align; align >>= 1) {
836 pdump_entry_list_elt *elt;
838 for (i = 0; i < lrecord_type_count; i++)
839 if (pdump_object_table[i].align == align)
840 for (elt = pdump_object_table[i].first; elt;
843 lrecord_implementations_table[i]->
846 for (i = 0; i < (size_t)pdump_struct_table.count; i++) {
847 pdump_struct_list_elt list = pdump_struct_table.list[i];
848 if (list.list.align == align)
849 for (elt = list.list.first; elt;
851 f(elt, list.sdesc->description);
854 for (elt = pdump_opaque_data_list.first; elt; elt = elt->next)
855 if (pdump_size_to_align(elt->size) ==
861 static void pdump_dump_root_struct_ptrs(void)
864 size_t count = Dynarr_length(pdump_root_struct_ptrs);
865 pdump_static_pointer *data = alloca_array(pdump_static_pointer, count);
866 for (i = 0; i < count; i++) {
868 (char **)Dynarr_atp(pdump_root_struct_ptrs, i)->ptraddress;
870 (char *)pdump_get_entry(*data[i].address)->save_offset;
872 PDUMP_ALIGN_OUTPUT(pdump_static_pointer);
873 fwrite(data, sizeof(pdump_static_pointer), count, pdump_out);
876 static void pdump_dump_opaques(void)
879 for (i = 0; i < Dynarr_length(pdump_opaques); i++) {
880 pdump_opaque *info = Dynarr_atp(pdump_opaques, i);
881 PDUMP_WRITE_ALIGNED(pdump_opaque, *info);
882 fwrite(info->varaddress, info->size, 1, pdump_out);
886 static void pdump_dump_rtables(void)
889 pdump_entry_list_elt *elt;
890 pdump_reloc_table rt;
892 for (i = 0; i < lrecord_type_count; i++) {
893 elt = pdump_object_table[i].first;
896 rt.desc = lrecord_implementations_table[i]->description;
897 rt.count = pdump_object_table[i].count;
898 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
901 pdump_get_entry(elt->obj)->save_offset;
902 PDUMP_WRITE_ALIGNED(EMACS_INT, rdata);
909 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
911 for (i = 0; i < (size_t)pdump_struct_table.count; i++) {
912 elt = pdump_struct_table.list[i].list.first;
913 rt.desc = pdump_struct_table.list[i].sdesc->description;
914 rt.count = pdump_struct_table.list[i].list.count;
915 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
918 pdump_get_entry(elt->obj)->save_offset;
920 for (j = 0; j < elt->count; j++) {
921 PDUMP_WRITE_ALIGNED(EMACS_INT, rdata);
929 PDUMP_WRITE_ALIGNED(pdump_reloc_table, rt);
932 static void pdump_dump_root_objects(void)
934 size_t count = (Dynarr_length(pdump_root_objects) +
935 Dynarr_length(pdump_weak_object_chains));
938 PDUMP_WRITE_ALIGNED(size_t, count);
939 PDUMP_ALIGN_OUTPUT(pdump_static_Lisp_Object);
941 for (i = 0; i < Dynarr_length(pdump_root_objects); i++) {
942 pdump_static_Lisp_Object obj;
943 obj.address = Dynarr_at(pdump_root_objects, i);
944 obj.value = *obj.address;
946 if (POINTER_TYPE_P(XTYPE(obj.value)))
949 pdump_get_entry(XRECORD_LHEADER
953 PDUMP_WRITE(pdump_static_Lisp_Object, obj);
956 for (i = 0; i < Dynarr_length(pdump_weak_object_chains); i++) {
957 pdump_entry_list_elt *elt;
958 pdump_static_Lisp_Object obj;
960 obj.address = Dynarr_at(pdump_weak_object_chains, i);
961 obj.value = *obj.address;
964 const struct lrecord_description *desc;
966 elt = pdump_get_entry(XRECORD_LHEADER(obj.value));
970 XRECORD_LHEADER_IMPLEMENTATION(obj.value)->
972 for (pos = 0; desc[pos].type != XD_LO_LINK; pos++)
973 assert(desc[pos].type != XD_END);
976 *(Lisp_Object *) (desc[pos].offset +
978 *)(XRECORD_LHEADER(obj.value)));
980 obj.value = wrap_object((void *)elt->save_offset);
982 PDUMP_WRITE(pdump_static_Lisp_Object, obj);
987 pdump(const char *dumpfile)
990 Lisp_Object t_console, t_device, t_frame;
994 pdump_object_table = xnew_array(pdump_entry_list, lrecord_type_count);
995 pdump_alert_undump_object = xnew_array(int, lrecord_type_count);
997 assert(ALIGNOF(max_align_t) <= pdump_align_table[0]);
999 for (i = 0; i < countof(pdump_align_table); i++)
1000 if (pdump_align_table[i] > ALIGNOF(max_align_t))
1001 pdump_align_table[i] = ALIGNOF(max_align_t);
1003 flush_all_buffer_local_cache();
1005 /* These appear in a DEFVAR_LISP, which does a staticpro() */
1006 t_console = Vterminal_console;
1007 Vterminal_console = Qnil;
1008 t_frame = Vterminal_frame;
1009 Vterminal_frame = Qnil;
1010 t_device = Vterminal_device;
1011 Vterminal_device = Qnil;
1013 dump_add_opaque((void *)&lrecord_implementations_table,
1014 lrecord_type_count *
1015 sizeof(lrecord_implementations_table[0]));
1016 dump_add_opaque(&lrecord_markers,
1017 lrecord_type_count * sizeof(lrecord_markers[0]));
1019 pdump_hash = xnew_array_and_zero(pdump_entry_list_elt*, PDUMP_HASHSIZE);
1021 for (i = 0; i < lrecord_type_count; i++) {
1022 pdump_object_table[i].first = 0;
1023 pdump_object_table[i].align = ALIGNOF(max_align_t);
1024 pdump_object_table[i].count = 0;
1025 pdump_alert_undump_object[i] = 0;
1027 pdump_struct_table.count = 0;
1028 pdump_struct_table.size = -1;
1030 pdump_opaque_data_list.first = 0;
1031 pdump_opaque_data_list.align = ALIGNOF(max_align_t);
1032 pdump_opaque_data_list.count = 0;
1035 for (i = 0; i < (size_t)Dynarr_length(pdump_root_objects); i++) {
1036 pdump_register_object(*Dynarr_at(pdump_root_objects, i));
1040 for (i = 0; i < lrecord_type_count; i++)
1041 if (pdump_alert_undump_object[i]) {
1043 printf("Undumpable types list :\n");
1045 printf(" - %s (%d)\n",
1046 lrecord_implementations_table[i]->name,
1047 pdump_alert_undump_object[i]);
1053 for (i = 0; i < (size_t) Dynarr_length(pdump_root_struct_ptrs); i++) {
1054 pdump_root_struct_ptr info =
1055 Dynarr_at(pdump_root_struct_ptrs, i);
1056 pdump_register_struct(*(info.ptraddress), info.desc, 1);
1059 memcpy(header.signature, PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN);
1060 header.id = dump_id;
1061 header.reloc_address = 0;
1062 header.nb_root_struct_ptrs = Dynarr_length(pdump_root_struct_ptrs);
1063 header.nb_opaques = Dynarr_length(pdump_opaques);
1065 cur_offset = ALIGN_SIZE(sizeof(header), ALIGNOF(max_align_t));
1068 pdump_scan_by_alignment(pdump_allocate_offset);
1069 cur_offset = ALIGN_SIZE(cur_offset, ALIGNOF(max_align_t));
1070 header.stab_offset = cur_offset;
1072 pdump_buf = xmalloc_atomic(max_size);
1073 /* Avoid use of the `open' macro. We want the real function. */
1075 pdump_fd = open(dumpfile,
1076 O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY, 0666);
1077 if ( pdump_fd < 0 ) {
1078 stderr_out("Could not open dump file: %s", dumpfile);
1081 pdump_out = fdopen(pdump_fd, "w");
1082 if ( pdump_out < 0 ) {
1083 stderr_out("Could not fdopen dump file: %s %d",
1084 dumpfile, pdump_fd);
1088 fwrite(&header, sizeof(header), 1, pdump_out);
1089 PDUMP_ALIGN_OUTPUT(max_align_t);
1091 pdump_scan_by_alignment(pdump_dump_data);
1093 fseek(pdump_out, header.stab_offset, SEEK_SET);
1095 pdump_dump_root_struct_ptrs();
1096 pdump_dump_opaques();
1097 pdump_dump_rtables();
1098 pdump_dump_root_objects();
1107 Vterminal_console = t_console;
1108 Vterminal_frame = t_frame;
1109 Vterminal_device = t_device;
1114 static int pdump_load_check(void)
1116 return (!memcmp(((pdump_header*)pdump_start)->signature,
1117 PDUMP_SIGNATURE, PDUMP_SIGNATURE_LEN)
1118 && ((pdump_header *)pdump_start)->id == dump_id);
1121 /*----------------------------------------------------------------------*/
1122 /* Reading the dump file */
1123 /*----------------------------------------------------------------------*/
1125 pdump_load_finish(void)
1129 pdump_header *header = (pdump_header*)pdump_start;
1131 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
1132 int cache_GC_dont_gc = GC_dont_gc;
1137 pdump_end = pdump_start + pdump_length;
1139 delta = ((EMACS_INT)pdump_start) - header->reloc_address;
1140 p = pdump_start + header->stab_offset;
1142 /* Put back the pdump_root_struct_ptrs */
1143 p = (char*)ALIGN_PTR(p, ALIGNOF(pdump_static_pointer));
1144 for (int i = 0; i < header->nb_root_struct_ptrs; i++) {
1145 pdump_static_pointer ptr = PDUMP_READ(p, pdump_static_pointer);
1146 (*ptr.address) = ptr.value + delta;
1149 /* Put back the pdump_opaques */
1150 for (int i = 0; i < header->nb_opaques; i++) {
1151 pdump_opaque info = PDUMP_READ_ALIGNED(p, pdump_opaque);
1152 memcpy(info.varaddress, p, info.size);
1156 /* Do the relocations */
1158 for (EMACS_INT count = 2;;) {
1159 pdump_reloc_table rt = PDUMP_READ_ALIGNED(p, pdump_reloc_table);
1160 p = (char*)ALIGN_PTR(p, ALIGNOF(char*));
1162 char **reloc = (char**)p;
1163 for (int i = 0; i < rt.count; i++) {
1165 pdump_reloc_one(reloc[i], delta, rt.desc);
1167 p += rt.count * sizeof(char *);
1168 } else if (!(--count)) {
1173 /* Put the pdump_root_objects variables in place */
1174 p = (char*)ALIGN_PTR(p, ALIGNOF(pdump_static_Lisp_Object));
1176 for (int i = PDUMP_READ_ALIGNED(p, size_t); i--; ) {
1177 pdump_static_Lisp_Object obj =
1178 PDUMP_READ(p, pdump_static_Lisp_Object);
1180 if (POINTER_TYPE_P(XTYPE(obj.value))) {
1182 wrap_object((char*)XPNTR(obj.value) + delta);
1184 (*obj.address) = obj.value;
1187 /* Final cleanups */
1188 /* reorganize hash tables */
1191 pdump_reloc_table rt = PDUMP_READ_ALIGNED(p, pdump_reloc_table);
1192 p = (char*)ALIGN_PTR(p, ALIGNOF(Lisp_Object));
1197 if (rt.desc == hash_table_description) {
1198 for (int i = 0; i < rt.count; i++) {
1199 pdump_reorganize_hash_table(
1200 PDUMP_READ(p, Lisp_Object));
1204 p += sizeof(Lisp_Object) * rt.count;
1208 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
1209 GC_dont_gc = cache_GC_dont_gc;
1215 static void pdump_file_free(void)
1221 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1222 # if defined HAVE_MMAP
1223 static void pdump_file_unmap(void)
1225 munmap(pdump_start, pdump_length);
1227 # endif /* HAVE_MMAP */
1230 static int pdump_file_get(const char *path)
1232 int fd = open(path, O_RDONLY | OPEN_BINARY);
1234 if (UNLIKELY(fd < 0)) {
1238 pdump_length = lseek(fd, 0, SEEK_END);
1239 if (UNLIKELY(pdump_length < sizeof(pdump_header))) {
1244 lseek(fd, 0, SEEK_SET);
1246 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1247 # if defined HAVE_MMAP
1248 /* Unix 98 requires that sys/mman.h define MAP_FAILED,
1249 but many earlier implementations don't. */
1251 # define MAP_FAILED ((void*)-1L)
1252 # endif /* MAP_FAILED */
1253 pdump_start = (char*)mmap(0, pdump_length,
1254 PROT_READ | PROT_WRITE, MAP_PRIVATE,
1256 if (LIKELY(pdump_start != (char*)MAP_FAILED)) {
1257 pdump_free = pdump_file_unmap;
1261 # endif /* HAVE_MMAP */
1264 pdump_start = xnew_array(char, pdump_length);
1265 pdump_free = pdump_file_free;
1266 read(fd, pdump_start, pdump_length);
1273 pdump_file_try(char *exe_path, size_t size)
1275 static const char pdump_ext[] = ".dmp";
1276 size_t exe_path_len = strlen(exe_path);
1277 char *w = exe_path + exe_path_len;
1279 if (exe_path_len + sizeof(pdump_ext) <= size) {
1280 /* just hammer the pdump extension onto w */
1281 memcpy(w, pdump_ext, sizeof(pdump_ext));
1283 if (pdump_file_get(exe_path)) {
1285 if (pdump_load_check()) {
1296 wipe_out_libtool_stuff(char *path)
1298 #define dotlibs ".libs/"
1299 #define ltdash "lt-"
1302 for (p = strchr(path, '.'); p; p = strchr(p+1, '.')) {
1304 strncmp(p, dotlibs, sizeof(dotlibs)-1);
1306 strncmp(p+sizeof(dotlibs)-1, ltdash, sizeof(ltdash)-1);
1307 if ((dotlibsp || ltdashp) == 0) {
1308 /* cut out the `.libs/lt-' portion */
1309 size_t offs = sizeof(dotlibs)-1+sizeof(ltdash)-1;
1310 size_t rest = strlen(p + offs);
1311 memmove(p, p + offs, rest);
1314 } else if (dotlibsp == 0) {
1315 /* cut out the `.libs/' portion */
1316 size_t offs = sizeof(dotlibs)-1;
1317 size_t rest = strlen(p + offs);
1318 memmove(p, p + offs, rest);
1327 int pdump_load(const char *argv0)
1329 char exe_path[PATH_MAX], real_exe_path[PATH_MAX];
1330 char libarchdir_path[PATH_MAX] = PATH_EXEC "/sxemacs";
1332 const char *dir, *p;
1335 if (dir[0] == '-') {
1336 /* SXEmacs as a login shell, oh goody! */
1337 dir = getenv("SHELL");
1338 assert(dir != NULL);
1341 p = dir + strlen(dir);
1342 while (p != dir && !IS_ANY_SEP(p[-1])) {
1347 /* invocation-name includes a directory component -- presumably it
1348 is relative to cwd, not $PATH */
1349 assert(strlen(dir) < sizeof(exe_path));
1350 xstrncpy(exe_path, dir, sizeof(exe_path));
1351 exe_path[sizeof(exe_path)-1]='\0';
1353 const char *path = getenv("PATH");
1354 const char *name = p;
1356 assert(path != NULL);
1358 int remain = sizeof(exe_path)-1;
1359 exe_path[remain] = '\0';
1362 while (*p && *p != SEPCHAR) {
1370 size_t len = (p - path) <= remain
1373 memcpy(exe_path, path, len);
1377 if (!IS_DIRECTORY_SEP(w[-1]) && (remain > 0) ) {
1382 xstrncpy(w, name, remain);
1385 /* Check that exe_path is executable and not a
1387 #undef access /* avoid !@#$%^& encapsulated access */
1388 #undef stat /* avoid !@#$%^& encapsulated stat */
1390 struct stat statbuf;
1391 if (access(exe_path, X_OK) == 0
1392 && stat(exe_path, &statbuf) == 0
1393 && !S_ISDIR(statbuf.st_mode))
1398 /* Oh well, let's have some kind of default */
1399 int sz = snprintf(exe_path, sizeof(exe_path),
1401 assert(sz >= 0 && (size_t)sz < sizeof(exe_path));
1409 /* do not use this one now as we follow libtool's concept of
1410 * convenience libraries and binaries */
1411 wipe_out_libtool_stuff(exe_path);
1414 /* Save exe_path because pdump_file_try() modifies it */
1415 assert(strlen(exe_path) < sizeof(real_exe_path));
1416 xstrncpy(real_exe_path, exe_path, sizeof(real_exe_path));
1417 if (pdump_file_try(exe_path,sizeof(exe_path))
1418 || (xrealpath(real_exe_path, real_exe_path)
1419 && pdump_file_try(real_exe_path,sizeof(real_exe_path)))
1420 || pdump_file_try(libarchdir_path,sizeof(libarchdir_path)) ) {
1421 pdump_load_finish();
1428 /* dumper.c ends here */