File Coverage

lib/Devel/MAT/Dumper.xs
Criterion Covered Total %
statement 291 431 67.5
branch 225 388 57.9
condition n/a
subroutine n/a
pod n/a
total 516 819 63.0


line stmt bran cond sub pod time code
1             /* You may distribute under the terms of either the GNU General Public License
2             * or the Artistic License (the same terms as Perl itself)
3             *
4             * (C) Paul Evans, 2013-2022 -- leonerd@leonerd.org.uk
5             */
6              
7             #include "EXTERN.h"
8             #include "perl.h"
9             #include "XSUB.h"
10              
11             #include
12             #include
13             #include
14             #include
15              
16             #define FORMAT_VERSION_MAJOR 0
17             #define FORMAT_VERSION_MINOR 4 /* Actually 5 if HAVE_FEATURE_CLASS */
18              
19             #ifndef SvOOK_offset
20             # define SvOOK_offset(sv, len) STMT_START { len = SvIVX(sv); } STMT_END
21             #endif
22              
23             #ifndef CxHASARGS
24             # define CxHASARGS(cx) ((cx)->blk_sub.hasargs)
25             #endif
26              
27             #ifndef OpSIBLING
28             # define OpSIBLING(o) ((o)->op_sibling)
29             #endif
30              
31             #ifndef HvNAMELEN
32             # define HvNAMELEN(hv) (strlen(HvNAME(hv)))
33             #endif
34              
35             /* This technically applies all the way back to 5.6 if we need it... */
36             #if (PERL_REVISION == 5) && (PERL_VERSION == 10) && (PERL_SUBVERSION == 0)
37             # define CxOLD_OP_TYPE(cx) ((cx)->blk_eval.old_op_type)
38             #endif
39              
40             #ifdef ObjectFIELDS
41             # define HAVE_FEATURE_CLASS
42             #endif
43              
44             static int max_string;
45              
46             #if NVSIZE == 8
47             # define PMAT_NVSIZE 8
48             #else
49             # define PMAT_NVSIZE 10
50             #endif
51              
52             #if (PERL_REVISION == 5) && (PERL_VERSION >= 26)
53             # define SAVEt_ARG0_MAX SAVEt_REGCONTEXT
54             # define SAVEt_ARG1_MAX SAVEt_FREEPADNAME
55             # define SAVEt_ARG2_MAX SAVEt_APTR
56             # define SAVEt_MAX SAVEt_DELETE
57             /* older perls already defined SAVEt_ARG_MAX */
58             #elif (PERL_REVISION == 5) && (PERL_VERSION >= 22)
59             # define SAVEt_MAX SAVEt_DELETE
60             #elif (PERL_REVISION == 5) && (PERL_VERSION >= 20)
61             # define SAVEt_MAX SAVEt_AELEM
62             #elif (PERL_REVISION == 5) && (PERL_VERSION >= 18)
63             # define SAVEt_MAX SAVEt_GVSLOT
64             #endif
65              
66             static SV *tmpsv; /* A temporary SV for internal purposes. Will not get dumped */
67              
68 0           static SV *make_tmp_iv(IV iv)
69             {
70 0 0         if(!tmpsv)
71 0           tmpsv = newSV(0);
72 0           sv_setiv(tmpsv, iv);
73 0           return tmpsv;
74             }
75              
76             static uint8_t sv_sizes[] = {
77             /* Header PTRs, STRs */
78             4 + PTRSIZE + UVSIZE, 1, 0, /* common SV */
79             UVSIZE, 8, 2, /* GLOB */
80             1 + 2*UVSIZE + PMAT_NVSIZE, 1, 1, /* SCALAR */
81             1, 2, 0, /* REF */
82             1 + UVSIZE, 0, 0, /* ARRAY + has body */
83             UVSIZE, 1, 0, /* HASH + has body */
84             UVSIZE + 0, 1 + 4, 0 + 1, /* STASH = extends HASH */
85             5 + UVSIZE + PTRSIZE, 5, 2, /* CODE + has body */
86             2*UVSIZE, 3, 0, /* IO */
87             1 + 2*UVSIZE, 1, 0, /* LVALUE */
88             0, 0, 0, /* REGEXP */
89             0, 0, 0, /* FORMAT */
90             0, 0, 0, /* INVLIST */
91             0, 0, 0, /* UNDEF */
92             0, 0, 0, /* YES */
93             0, 0, 0, /* NO */
94             #ifdef HAVE_FEATURE_CLASS
95             UVSIZE, 0, 0, /* OBJECT */
96             UVSIZE + 0, 1+4+1, 0+1, /* CLASS = extends STASH */
97             #endif
98             };
99              
100             static uint8_t svx_sizes[] = {
101             /* Header PTRs STRs */
102             2, 3, 0, /* magic */
103             0, 1, 0, /* saved SV */
104             0, 1, 0, /* saved AV */
105             0, 1, 0, /* saved HV */
106             UVSIZE, 1, 0, /* saved AELEM */
107             0, 2, 0, /* saved HELEM */
108             0, 1, 0, /* saved CV */
109             0, 1, 1, /* SV->SV annotation */
110             2*UVSIZE, 0, 1, /* SV leak report */
111             };
112              
113             static uint8_t ctx_sizes[] = {
114             /* Header PTRs STRs */
115             1 + UVSIZE, 0, 1, /* common CTX */
116             4, 2, 0, /* SUB */
117             0, 0, 0, /* TRY */
118             0, 1, 0, /* EVAL */
119             };
120              
121             // These do NOT agree with perl's SVt_* constants!
122             enum PMAT_SVt {
123             PMAT_SVtGLOB = 1,
124             PMAT_SVtSCALAR,
125             PMAT_SVtREF,
126             PMAT_SVtARRAY,
127             PMAT_SVtHASH,
128             PMAT_SVtSTASH,
129             PMAT_SVtCODE,
130             PMAT_SVtIO,
131             PMAT_SVtLVALUE,
132             PMAT_SVtREGEXP,
133             PMAT_SVtFORMAT,
134             PMAT_SVtINVLIST,
135             PMAT_SVtUNDEF,
136             PMAT_SVtYES,
137             PMAT_SVtNO,
138             PMAT_SVtOBJ,
139             PMAT_SVtCLASS,
140              
141             PMAT_SVtSTRUCT = 0x7F, /* fields as described by corresponding META_STRUCT */
142              
143             /* TODO: emit these in DMD_helper.h */
144             PMAT_SVxMAGIC = 0x80,
145             PMAT_SVxSAVED_SV,
146             PMAT_SVxSAVED_AV,
147             PMAT_SVxSAVED_HV,
148             PMAT_SVxSAVED_AELEM,
149             PMAT_SVxSAVED_HELEM,
150             PMAT_SVxSAVED_CV,
151             PMAT_SVxSVSVnote,
152             PMAT_SVxDEBUGREPORT,
153              
154             PMAT_SVtMETA_STRUCT = 0xF0,
155             };
156              
157             enum PMAT_CODEx {
158             PMAT_CODEx_CONSTSV = 1,
159             PMAT_CODEx_CONSTIX,
160             PMAT_CODEx_GVSV,
161             PMAT_CODEx_GVIX,
162             PMAT_CODEx_PADNAME,
163             /* PMAT_CODEx_PADSV was 6 */
164             PMAT_CODEx_PADNAMES = 7,
165             PMAT_CODEx_PAD,
166             PMAT_CODEx_PADNAME_FLAGS,
167             PMAT_CODEx_PADNAME_FIELD,
168             };
169              
170             enum PMAT_CLASSx {
171             PMAT_CLASSx_FIELD = 1,
172             };
173              
174             enum PMAT_CTXt {
175             PMAT_CTXtSUB = 1,
176             PMAT_CTXtTRY,
177             PMAT_CTXtEVAL,
178             };
179              
180             /* API v0.44 */
181             typedef struct {
182             FILE *fh;
183             int next_structid;
184             HV *structdefs;
185             } DMDContext;
186              
187             typedef int DMD_Helper(pTHX_ DMDContext *ctx, SV const *sv);
188             static HV *helper_per_package;
189              
190             typedef int DMD_MagicHelper(pTHX_ DMDContext *ctx, SV const *sv, MAGIC *mg);
191             static HV *helper_per_magic;
192              
193             /* Before API v0.44 */
194             typedef int DMD_LegacyHelper(pTHX_ SV const *sv);
195             static HV *legacy_helper_per_package;
196              
197             typedef int DMD_LegacyMagicHelper(pTHX_ SV const *sv, MAGIC *mg);
198             static HV *legacy_helper_per_magic;
199              
200             static void write_u8(FILE *fh, uint8_t v)
201             {
202 154301           fwrite(&v, 1, 1, fh);
203             }
204              
205             /* We just write multi-byte integers in native endian, because we've declared
206             * in the file flags what the platform byte direction is anyway
207             */
208             static void write_u32(FILE *fh, uint32_t v)
209             {
210 63638           fwrite(&v, 4, 1, fh);
211             }
212              
213             static void write_u64(FILE *fh, uint64_t v)
214             {
215 223317           fwrite(&v, 8, 1, fh);
216             }
217              
218             static void write_uint(FILE *fh, UV v)
219             {
220             #if UVSIZE == 8
221             write_u64(fh, v);
222             #elif UVSIZE == 4
223             write_u32(fh, v);
224             #else
225             # error "Expected UVSIZE to be either 4 or 8"
226             #endif
227             }
228              
229             static void write_ptr(FILE *fh, const void *ptr)
230             {
231 4590           fwrite(&ptr, sizeof ptr, 1, fh);
232             }
233              
234             static void write_svptr(FILE *fh, const SV *ptr)
235             {
236 276286           fwrite(&ptr, sizeof ptr, 1, fh);
237             }
238              
239             static void write_nv(FILE *fh, NV v)
240             {
241             #if NVSIZE == 8
242 22591           fwrite(&v, sizeof(NV), 1, fh);
243             #else
244             // long double is 10 bytes but sizeof() may be 16.
245             fwrite(&v, 10, 1, fh);
246             #endif
247             }
248              
249 56746           static void write_strn(FILE *fh, const char *s, size_t len)
250             {
251             write_uint(fh, len);
252 56746           fwrite(s, len, 1, fh);
253 56746           }
254              
255 34436           static void write_str(FILE *fh, const char *s)
256             {
257 34436 100         if(s)
258 21684           write_strn(fh, s, strlen(s));
259             else
260             write_uint(fh, -1);
261 34436           }
262              
263             #define PMOP_pmreplroot(o) o->op_pmreplrootu.op_pmreplroot
264              
265             #if (PERL_REVISION == 5) && (PERL_VERSION < 14)
266             # define OP_CLASS(o) (PL_opargs[o->op_type] & OA_CLASS_MASK)
267             #endif
268              
269             static void dump_optree(FILE *fh, const CV *cv, OP *o);
270 115473           static void dump_optree(FILE *fh, const CV *cv, OP *o)
271             {
272             OP *kid;
273              
274 115473           switch(o->op_type) {
275             case OP_CONST:
276             case OP_METHOD_NAMED:
277             #ifdef USE_ITHREADS
278             if(o->op_targ) {
279             write_u8(fh, PMAT_CODEx_CONSTIX);
280             write_uint(fh, o->op_targ);
281             }
282             #else
283             write_u8(fh, PMAT_CODEx_CONSTSV);
284 12320           write_svptr(fh, cSVOPx(o)->op_sv);
285             #endif
286             break;
287              
288             case OP_AELEMFAST:
289             case OP_GVSV:
290             case OP_GV:
291             #ifdef USE_ITHREADS
292             write_u8(fh, PMAT_CODEx_GVIX);
293             write_uint(fh, o->op_targ ? o->op_targ : cPADOPx(o)->op_padix);
294             #else
295             write_u8(fh, PMAT_CODEx_GVSV);
296 4898           write_svptr(fh, cSVOPx(o)->op_sv);
297             #endif
298             break;
299             }
300              
301 115473 100         if(o->op_flags & OPf_KIDS) {
302 166876 100         for (kid = ((UNOP*)o)->op_first; kid; kid = OpSIBLING(kid)) {
    100          
303 113407           dump_optree(fh, cv, kid);
304             }
305             }
306              
307 115473 50         if(OP_CLASS(o) == OA_PMOP &&
    100          
    100          
308             #if (PERL_REVISION == 5) && ((PERL_VERSION > 25) || ((PERL_VERSION == 25) && (PERL_SUBVERSION >= 6)))
309             /* The OP_PUSHRE behaviour was moved to OP_SPLIT in 5.25.6 */
310 583 100         o->op_type != OP_SPLIT &&
311             #else
312             o->op_type != OP_PUSHRE &&
313             #endif
314 583           (kid = PMOP_pmreplroot(cPMOPx(o))))
315 45           dump_optree(fh, cv, kid);
316 115473           }
317              
318 59046           static void write_common_sv(FILE *fh, const SV *sv, size_t size)
319             {
320             // Header
321             write_svptr(fh, sv);
322 59046           write_u32(fh, SvREFCNT(sv));
323 59046           write_uint(fh, sizeof(SV) + size);
324              
325             // PTRs
326 59046 100         write_svptr(fh, SvOBJECT(sv) ? (SV*)SvSTASH(sv) : NULL);
327 59046           }
328              
329 5773           static void write_private_gv(FILE *fh, const GV *gv)
330             {
331 11546 50         write_common_sv(fh, (const SV *)gv,
332 5773 50         sizeof(XPVGV) + (isGV_with_GP(gv) ? sizeof(struct gp) : 0));
333              
334 5773 50         if(isGV_with_GP(gv)) {
    50          
335             // Header
336 5773           write_uint(fh, GvLINE(gv));
337              
338             // PTRs
339 5773           write_svptr(fh, (SV*)GvSTASH(gv));
340 5773           write_svptr(fh, GvSV(gv));
341 5773           write_svptr(fh, (SV*)GvAV(gv));
342 5773           write_svptr(fh, (SV*)GvHV(gv));
343 5773           write_svptr(fh, (SV*)GvCV(gv));
344 5773           write_svptr(fh, (SV*)GvEGV(gv));
345 5773 50         write_svptr(fh, (SV*)GvIO(gv));
    50          
    50          
346 5773           write_svptr(fh, (SV*)GvFORM(gv));
347              
348             // STRs
349 5773           write_str(fh, GvNAME(gv));
350 5773 50         write_str(fh, GvFILE(gv));
351             }
352             else {
353             // Header
354             write_uint(fh, 0);
355              
356             // PTRs
357 0           write_svptr(fh, (SV*)GvSTASH(gv));
358             write_svptr(fh, NULL);
359             write_svptr(fh, NULL);
360             write_svptr(fh, NULL);
361             write_svptr(fh, NULL);
362             write_svptr(fh, NULL);
363             write_svptr(fh, NULL);
364             write_svptr(fh, NULL);
365              
366             // STRs
367             write_str(fh, NULL);
368             write_str(fh, NULL);
369             }
370 5773           }
371              
372 22591           static void write_private_sv(FILE *fh, const SV *sv)
373             {
374             size_t size = 0;
375 22591 100         switch(SvTYPE(sv)) {
376             case SVt_IV: break;
377             case SVt_NV: size += sizeof(NV); break;
378             case SVt_PV: size += sizeof(XPV) - STRUCT_OFFSET(XPV, xpv_cur); break;
379             case SVt_PVIV: size += sizeof(XPVIV) - STRUCT_OFFSET(XPV, xpv_cur); break;
380             case SVt_PVNV: size += sizeof(XPVNV) - STRUCT_OFFSET(XPV, xpv_cur); break;
381             case SVt_PVMG: size += sizeof(XPVMG); break;
382             }
383              
384 22591 100         if(SvPOK(sv))
385 17831           size += SvLEN(sv);
386 22591 50         if(SvOOK(sv)) {
387             STRLEN offset;
388 0 0         SvOOK_offset(sv, offset);
    0          
389 0           size += offset;
390             }
391              
392 22591           write_common_sv(fh, sv, size);
393              
394             // Header
395 22591 100         write_u8(fh, (SvIOK(sv) ? 0x01 : 0) |
    100          
    100          
    100          
396 22591           (SvUOK(sv) ? 0x02 : 0) |
397 22591           (SvNOK(sv) ? 0x04 : 0) |
398 22591           (SvPOK(sv) ? 0x08 : 0) |
399 22591           (SvUTF8(sv) ? 0x10 : 0));
400 22591 100         write_uint(fh, SvIOK(sv) ? SvUVX(sv) : 0);
401 22591 100         write_nv(fh, SvNOK(sv) ? SvNVX(sv) : 0.0);
402 22591 100         write_uint(fh, SvPOK(sv) ? SvCUR(sv) : 0);
403              
404             // PTRs
405             #if (PERL_REVISION == 5) && (PERL_VERSION <= 20)
406             write_svptr(fh, (SV *)SvOURSTASH(sv));
407             #else
408             write_svptr(fh, NULL);
409             #endif
410              
411             // STRs
412 22591 100         if(SvPOK(sv)) {
413 17831           STRLEN len = SvCUR(sv);
414 17831 50         if(max_string > -1 && len > max_string)
    100          
415             len = max_string;
416 17831           write_strn(fh, SvPVX((SV *)sv), len);
417             }
418             else
419             write_str(fh, NULL);
420 22591           }
421              
422 2296           static void write_private_rv(FILE *fh, const SV *rv)
423             {
424 2296           write_common_sv(fh, rv, 0);
425              
426             // Header
427 2296           write_u8(fh, (SvWEAKREF(rv) ? 0x01 : 0));
428              
429             // PTRs
430 2296           write_svptr(fh, SvRV((SV *)rv));
431             #if (PERL_REVISION == 5) && (PERL_VERSION <= 20)
432             write_svptr(fh, (SV *)SvOURSTASH(rv));
433             #else
434             write_svptr(fh, NULL);
435             #endif
436 2296           }
437              
438 5181           static void write_private_av(FILE *fh, const AV *av)
439             {
440             /* Perl doesn't bother to keep AvFILL(PL_curstack) updated for efficiency
441             * reasons, so if we're looking at PL_curstack we'll use a different method
442             * to calculate this
443             */
444 5181 100         int len = (av == PL_curstack) ? (PL_stack_sp - PL_stack_base + 1) :
445 5180           AvFILLp(av) + 1;
446              
447 5181           write_common_sv(fh, (const SV *)av,
448 5181           sizeof(XPVAV) + sizeof(SV *) * (AvMAX(av) + 1));
449              
450             // Header
451 5181           write_uint(fh, len);
452 5181           write_u8(fh, (!AvREAL(av) ? 0x01 : 0));
453              
454             // Body
455             int i;
456 40544 100         for(i = 0; i < len; i++)
457 35363           write_svptr(fh, AvARRAY(av)[i]);
458 5181           }
459              
460 1102           static int write_hv_header(FILE *fh, const HV *hv, size_t size)
461             {
462 1102           size += sizeof(XPVHV);
463             int nkeys = 0;
464              
465 1102 100         if(HvARRAY(hv)) {
466             int bucket;
467 30669 100         for(bucket = 0; bucket <= HvMAX(hv); bucket++) {
468             HE *he;
469 29740           size += sizeof(HE *);
470              
471 46971 100         for(he = HvARRAY(hv)[bucket]; he; he = he->hent_next) {
472 17231           size += sizeof(HE);
473 17231           nkeys++;
474              
475 17231 100         if(!HvSHAREKEYS(hv))
476 5758           size += sizeof(HEK) + he->hent_hek->hek_len + 2;
477             }
478             }
479             }
480              
481 1102           write_common_sv(fh, (const SV *)hv, size);
482              
483 1102           return nkeys;
484             }
485              
486 906           static void write_hv_body_elems(FILE *fh, const HV *hv)
487             {
488             // The shared string table (PL_strtab) has shared strings as keys but its
489             // values are not SV pointers; they are refcounts. Pretend these values are
490             // NULL.
491 906           bool is_strtab = (hv == PL_strtab);
492              
493             int bucket;
494 28534 100         for(bucket = 0; bucket <= HvMAX(hv); bucket++) {
495             HE *he;
496 44859 100         for(he = HvARRAY(hv)[bucket]; he; he = he->hent_next) {
497             STRLEN len;
498 17231 50         char *key = HePV(he, len);
    0          
499 17231           write_strn(fh, key, len);
500 17231 100         write_svptr(fh, is_strtab ? NULL : HeVAL(he));
501             }
502             }
503 906           }
504              
505 862           static void write_private_hv(FILE *fh, const HV *hv)
506             {
507 862           int nkeys = write_hv_header(fh, hv, 0);
508              
509             // Header
510 862           write_uint(fh, nkeys);
511              
512             // PTRs
513 862 100         if(SvOOK(hv) && HvAUX(hv))
    50          
514 68           write_svptr(fh, (SV*)HvAUX(hv)->xhv_backreferences);
515             else
516             write_svptr(fh, NULL);
517              
518             // Body
519 862 100         if(HvARRAY(hv) && nkeys)
    100          
520 666           write_hv_body_elems(fh, hv);
521 862           }
522              
523 240           static void write_stash_ptrs(FILE *fh, const HV *stash)
524             {
525 240           struct mro_meta *mro_meta = HvAUX(stash)->xhv_mro_meta;
526              
527 240 50         if(SvOOK(stash) && HvAUX(stash))
    50          
528 240           write_svptr(fh, (SV*)HvAUX(stash)->xhv_backreferences);
529             else
530             write_svptr(fh, NULL);
531 240 100         if(mro_meta) {
532             #if (PERL_REVISION == 5) && (PERL_VERSION >= 12)
533 175           write_svptr(fh, (SV*)mro_meta->mro_linear_all);
534 175           write_svptr(fh, mro_meta->mro_linear_current);
535             #else
536             write_svptr(fh, NULL);
537             write_svptr(fh, NULL);
538             #endif
539 175           write_svptr(fh, (SV*)mro_meta->mro_nextmethod);
540             #if (PERL_REVISION == 5) && ((PERL_VERSION > 10) || (PERL_VERSION == 10 && PERL_SUBVERSION > 0))
541 175           write_svptr(fh, (SV*)mro_meta->isa);
542             #else
543             write_svptr(fh, NULL);
544             #endif
545             }
546             else {
547             write_svptr(fh, NULL);
548             write_svptr(fh, NULL);
549             write_svptr(fh, NULL);
550             write_svptr(fh, NULL);
551             }
552 240           }
553              
554 240           static void write_private_stash(FILE *fh, const HV *stash)
555             {
556 240           struct mro_meta *mro_meta = HvAUX(stash)->xhv_mro_meta;
557              
558 240 100         int nkeys = write_hv_header(fh, stash,
559             sizeof(struct xpvhv_aux) + (mro_meta ? sizeof(struct mro_meta) : 0));
560              
561             // Header
562             // HASH
563 240           write_uint(fh, nkeys);
564              
565             // PTRs
566 240           write_stash_ptrs(fh, stash);
567              
568             // STRs
569 240 50         write_str(fh, HvNAME(stash));
    50          
    50          
    0          
    50          
    50          
570              
571             // Body
572 240 50         if(HvARRAY(stash))
573 240           write_hv_body_elems(fh, stash);
574 240           }
575              
576 4590           static void write_private_cv(FILE *fh, const CV *cv)
577             {
578 4590           bool is_xsub = CvISXSUB(cv);
579 4590 100         PADLIST *pl = (is_xsub ? NULL : CvPADLIST(cv));
580              
581             /* If the optree contains custom ops, the OP_CLASS() macro will allocate
582             * a mortal SV. We'll need to FREETMPS it to ensure we don't dump it
583             * accidentally
584             */
585 4590           SAVETMPS;
586              
587             // TODO: accurate size information on CVs
588 4590           write_common_sv(fh, (const SV *)cv, sizeof(XPVCV));
589              
590             // Header
591             int line = 0;
592             OP *start;
593 4590 100         if(!CvISXSUB(cv) && !CvCONST(cv) && (start = CvSTART(cv))) {
    100          
    100          
594 2125 100         if(start->op_type == OP_NEXTSTATE)
595 2018           line = CopLINE((COP*)start);
596             }
597 4590           write_uint(fh, line);
598 4590 100         write_u8(fh, (CvCLONE(cv) ? 0x01 : 0) |
    100          
    100          
    100          
    50          
599 4590           (CvCLONED(cv) ? 0x02 : 0) |
600             (is_xsub ? 0x04 : 0) |
601 4590           (CvWEAKOUTSIDE(cv) ? 0x08 : 0) |
602             #if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
603 4590           (CvCVGV_RC(cv) ? 0x10 : 0) |
604             #else
605             /* Prior to 5.14, CvANON() was used to indicate this */
606             (CvANON(cv) ? 0x10 : 0) |
607             #endif
608             #if (PERL_REVISION == 5) && (PERL_VERSION >= 22)
609 4590           (CvLEXICAL(cv) ? 0x20 : 0) |
610             #endif
611             0);
612 4590 100         if(!is_xsub && !CvCONST(cv))
    100          
613 2345           write_ptr(fh, CvROOT(cv));
614             else
615             write_ptr(fh, NULL);
616              
617 4590           write_u32(fh, CvDEPTH(cv));
618              
619             // PTRs
620 4590           write_svptr(fh, (SV*)CvSTASH(cv));
621             #if (PERL_REVISION == 5) && (PERL_VERSION >= 18)
622 4590 50         if(CvNAMED(cv))
623             write_svptr(fh, NULL);
624             else
625             #endif
626             write_svptr(fh, (SV*)CvGV(cv));
627 4590           write_svptr(fh, (SV*)CvOUTSIDE(cv));
628             #if (PERL_REVISION == 5) && (PERL_VERSION >= 20)
629             /* Padlists are no longer heap-allocated on 5.20+ */
630             write_svptr(fh, NULL);
631             #else
632             write_svptr(fh, (SV*)(pl));
633             #endif
634 4590 100         if(CvCONST(cv))
635 1590           write_svptr(fh, (SV*)CvXSUBANY(cv).any_ptr);
636             else
637             write_svptr(fh, NULL);
638              
639             // STRs
640 4590 100         if(CvFILE(cv))
641 4484           write_str(fh, CvFILE(cv));
642             else
643 106           write_str(fh, "");
644              
645             #if (PERL_REVISION == 5) && (PERL_VERSION >= 18)
646 4590 50         if(CvNAMED(cv))
647 0           write_str(fh, HEK_KEY(CvNAME_HEK((CV*)cv)));
648             else
649             #endif
650             write_str(fh, NULL);
651              
652             // Body
653 4590 100         if(cv == PL_main_cv && PL_main_root)
    50          
654             /* The PL_main_cv does not have a CvROOT(); instead that is found in
655             * PL_main_root
656             */
657 1           dump_optree(fh, cv, PL_main_root);
658 4589 100         else if(!is_xsub && !CvCONST(cv) && CvROOT(cv))
    100          
    100          
659 2020           dump_optree(fh, cv, CvROOT(cv));
660              
661             #if (PERL_REVISION == 5) && (PERL_VERSION >= 18)
662 4590 100         if(pl) {
663 2128           PADNAME **names = PadlistNAMESARRAY(pl);
664             PAD **pads = PadlistARRAY(pl);
665             int depth, i;
666              
667             write_u8(fh, PMAT_CODEx_PADNAMES);
668             # if (PERL_VERSION > 20)
669             write_svptr(fh, NULL);
670             {
671 2128           PADNAME **padnames = PadnamelistARRAY(PadlistNAMES(pl));
672 2128           int padix_max = PadnamelistMAX(PadlistNAMES(pl));
673              
674             int padix;
675 20684 100         for(padix = 1; padix <= padix_max; padix++) {
676 18556           PADNAME *pn = padnames[padix];
677 18556 100         if(!pn)
678 559           continue;
679              
680             write_u8(fh, PMAT_CODEx_PADNAME);
681             write_uint(fh, padix);
682 17997           write_str(fh, PadnamePV(pn));
683 17997           write_svptr(fh, (SV*)PadnameOURSTASH(pn));
684              
685 17997 100         if(PadnameFLAGS(pn)) {
686             uint8_t flags = 0;
687              
688 3429 100         if(PadnameOUTER(pn)) flags |= 0x01;
689 3429 100         if(PadnameIsSTATE(pn)) flags |= 0x02;
690 3429 100         if(PadnameLVALUE(pn)) flags |= 0x04;
691 3429 50         if(PadnameFLAGS(pn) & PADNAMEt_TYPED) flags |= 0x08;
692 3429 100         if(PadnameFLAGS(pn) & PADNAMEt_OUR) flags |= 0x10;
693              
694 3429 50         if(flags) {
695             write_u8(fh, PMAT_CODEx_PADNAME_FLAGS);
696             write_uint(fh, padix);
697             write_u8(fh, flags);
698             }
699              
700             #ifdef HAVE_FEATURE_CLASS
701             if(PadnameIsFIELD(pn)) {
702             write_u8(fh, PMAT_CODEx_PADNAME_FIELD);
703             write_uint(fh, padix);
704             write_uint(fh, PadnameFIELDINFO(pn)->fieldix);
705             write_svptr(fh, (SV *)PadnameFIELDINFO(pn)->fieldstash);
706             }
707             #endif
708             }
709             }
710             }
711             # else
712             write_svptr(fh, (SV*)PadlistNAMES(pl));
713             # endif
714              
715 4266 100         for(depth = 1; depth <= PadlistMAX(pl); depth++) {
716 2138           PAD *pad = pads[depth];
717              
718             write_u8(fh, PMAT_CODEx_PAD);
719             write_uint(fh, depth);
720             write_svptr(fh, (SV*)pad);
721             }
722             }
723             #endif
724              
725             write_u8(fh, 0);
726              
727 4590 50         FREETMPS;
728 4590           }
729              
730 15           static void write_private_io(FILE *fh, const IO *io)
731             {
732 15           write_common_sv(fh, (const SV *)io, sizeof(XPVIO));
733              
734 15           write_uint(fh, PerlIO_fileno(IoIFP(io)));
735 15           write_uint(fh, PerlIO_fileno(IoOFP(io)));
736              
737             // PTRs
738 15           write_svptr(fh, (SV*)IoTOP_GV(io));
739 15           write_svptr(fh, (SV*)IoFMT_GV(io));
740 15           write_svptr(fh, (SV*)IoBOTTOM_GV(io));
741 15           }
742              
743 0           static void write_private_lv(FILE *fh, const SV *sv)
744             {
745 0           write_common_sv(fh, sv, sizeof(XPVLV));
746              
747             // Header
748 0           write_u8(fh, LvTYPE(sv));
749 0           write_uint(fh, LvTARGOFF(sv));
750 0           write_uint(fh, LvTARGLEN(sv));
751              
752             // PTRs
753 0           write_svptr(fh, LvTARG(sv));
754 0           }
755              
756             #ifdef HAVE_FEATURE_CLASS
757             static void write_private_obj(FILE *fh, const SV *obj)
758             {
759             int nfields = ObjectMAXFIELD(obj) + 1;
760              
761             write_common_sv(fh, obj, sizeof(XPVOBJ));
762              
763             // Header
764             write_uint(fh, nfields);
765              
766             SV **fields = ObjectFIELDS(obj);
767             int i;
768             for(i = 0; i < nfields; i++)
769             write_svptr(fh, fields[i]);
770             }
771              
772             static void write_private_class(FILE *fh, const HV *cls)
773             {
774             struct mro_meta *mro_meta = HvAUX(cls)->xhv_mro_meta;
775              
776             int nkeys = write_hv_header(fh, cls,
777             sizeof(struct xpvhv_aux) + (mro_meta ? sizeof(struct mro_meta) : 0));
778              
779             // Header
780             // HASH
781             write_uint(fh, nkeys);
782              
783             // PTRs
784             write_stash_ptrs(fh, cls);
785             write_ptr(fh, HvAUX(cls)->xhv_class_adjust_blocks);
786              
787             // STRs
788             write_str(fh, HvNAME(cls));
789              
790             // Body
791             if(HvARRAY(cls))
792             write_hv_body_elems(fh, cls);
793              
794             {
795             PADNAMELIST *fields = HvAUX(cls)->xhv_class_fields;
796              
797             int nfields = PadnamelistMAX(fields)+1;
798             for(int i = 0; i < nfields; i++) {
799             PADNAME *pn = PadnamelistARRAY(fields)[i];
800              
801             write_u8(fh, PMAT_CLASSx_FIELD);
802             write_uint(fh, PadnameFIELDINFO(pn)->fieldix);
803             write_str(fh, PadnamePV(pn));
804             }
805             }
806              
807             write_u8(fh, 0);
808             }
809             #endif
810              
811 0           static void write_annotations_from_stack(FILE *fh, int n)
812             {
813 0           dSP;
814 0           SV **p = SP - n + 1;
815              
816 0 0         while(p <= SP) {
817 0 0         unsigned char type = SvIV(p[0]);
818 0 0         switch(type) {
819             case PMAT_SVxSVSVnote:
820             write_u8(fh, type);
821 0           write_svptr(fh, p[1]); /* target */
822 0           write_svptr(fh, p[2]); /* value */
823 0 0         write_strn(fh, SvPV_nolen(p[3]), SvCUR(p[3])); /* annotation */
824 0           p += 4;
825 0           break;
826             default:
827 0           fprintf(stderr, "ARG: Unsure how to handle PMAT_SVn annotation type %02x\n", type);
828 0           p = SP + 1;
829             }
830             }
831 0           }
832              
833             static void run_package_helpers(DMDContext *ctx, const SV *sv, HV *stash);
834 2819           static void run_package_helpers(DMDContext *ctx, const SV *sv, HV *stash)
835             {
836 2819           FILE *fh = ctx->fh;
837             SV **svp;
838              
839             DMD_Helper *helper = NULL;
840 2819 50         if((svp = hv_fetch(helper_per_package, HvNAME(stash), HvNAMELEN(stash), 0)))
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
841 0 0         helper = (DMD_Helper *)SvUV(*svp);
842              
843 2819 50         if(helper) {
844 0           ENTER;
845 0           SAVETMPS;
846              
847 0           int ret = (*helper)(aTHX_ ctx, sv);
848              
849 0 0         if(ret > 0)
850 0           write_annotations_from_stack(fh, ret);
851              
852 0 0         FREETMPS;
853 0           LEAVE;
854             }
855              
856             AV *isa_av;
857 2819 100         if((svp = hv_fetchs(stash, "ISA", 0)) &&
    50          
858 2109 50         SvTYPE(*svp) == SVt_PVGV &&
859 2109 50         (isa_av = GvAV((GV *)*svp)) &&
860 2109 50         AvFILL(isa_av) > -1) {
861             SSize_t i;
862 4666 50         for(i = 0; i <= AvFILL(isa_av); i++) {
    100          
863 2557           HV *superstash = gv_stashsv(AvARRAY(isa_av)[i], 0);
864 2557           run_package_helpers(ctx, sv, superstash);
865             }
866             }
867 2819           }
868              
869 59046           static void write_sv(DMDContext *ctx, const SV *sv)
870             {
871 59046           FILE *fh = ctx->fh;
872             unsigned char type = -1;
873 59046           switch(SvTYPE(sv)) {
874             case SVt_NULL:
875             type = PMAT_SVtUNDEF; break;
876             case SVt_IV:
877             case SVt_NV:
878             case SVt_PV:
879             case SVt_PVIV:
880             case SVt_PVNV:
881             case SVt_PVMG:
882 25441 100         type = SvROK(sv) ? PMAT_SVtREF : PMAT_SVtSCALAR; break;
883             #if (PERL_REVISION == 5) && (PERL_VERSION < 12)
884             case SVt_RV: type = PMAT_SVtREF; break;
885             #endif
886             #if (PERL_REVISION == 5) && (PERL_VERSION >= 19)
887 65           case SVt_INVLIST: type = PMAT_SVtINVLIST; break;
888             #endif
889             #if (PERL_REVISION == 5) && (PERL_VERSION >= 12)
890 611           case SVt_REGEXP: type = PMAT_SVtREGEXP; break;
891             #endif
892 5773           case SVt_PVGV: type = PMAT_SVtGLOB; break;
893 0           case SVt_PVLV: type = PMAT_SVtLVALUE; break;
894 5181           case SVt_PVAV: type = PMAT_SVtARRAY; break;
895             // HVs with names we call STASHes
896             case SVt_PVHV:
897             #ifdef HAVE_FEATURE_CLASS
898             if(HvNAME(sv) && HvSTASH_IS_CLASS(sv))
899             type = PMAT_SVtCLASS;
900             else
901             #endif
902 1102 100         if(HvNAME(sv))
    100          
    50          
    0          
    50          
    50          
    50          
903             type = PMAT_SVtSTASH;
904             else
905             type = PMAT_SVtHASH;
906             break;
907 4590           case SVt_PVCV: type = PMAT_SVtCODE; break;
908 0           case SVt_PVFM: type = PMAT_SVtFORMAT; break;
909 15           case SVt_PVIO: type = PMAT_SVtIO; break;
910             #ifdef HAVE_FEATURE_CLASS
911             case SVt_PVOBJ: type = PMAT_SVtOBJ; break;
912             #endif
913             default:
914 0           fprintf(stderr, "dumpsv %p has unknown SvTYPE %d\n", sv, SvTYPE(sv));
915             break;
916             }
917              
918 59046 100         if(type == PMAT_SVtSCALAR && !SvOK(sv))
    100          
    50          
    50          
919             type = PMAT_SVtUNDEF;
920             #if (PERL_REVISION == 5) && (PERL_VERSION >= 35)
921             if(type == PMAT_SVtSCALAR && SvIsBOOL(sv))
922             /* SvTRUE() et al. might mutate; but it's OK we know this is one of the bools */
923             type = (SvIVX(sv)) ? PMAT_SVtYES : PMAT_SVtNO;
924             #endif
925              
926             write_u8(fh, type);
927              
928 59046           switch(type) {
929 5773           case PMAT_SVtGLOB: write_private_gv (fh, (GV*)sv); break;
930 22591           case PMAT_SVtSCALAR: write_private_sv (fh, sv); break;
931 2296           case PMAT_SVtREF: write_private_rv (fh, sv); break;
932 5181           case PMAT_SVtARRAY: write_private_av (fh, (AV*)sv); break;
933 862           case PMAT_SVtHASH: write_private_hv (fh, (HV*)sv); break;
934 240           case PMAT_SVtSTASH: write_private_stash(fh, (HV*)sv); break;
935 4590           case PMAT_SVtCODE: write_private_cv (fh, (CV*)sv); break;
936 15           case PMAT_SVtIO: write_private_io (fh, (IO*)sv); break;
937 0           case PMAT_SVtLVALUE: write_private_lv (fh, sv); break;
938             #ifdef HAVE_FEATURE_CLASS
939             case PMAT_SVtOBJ: write_private_obj(fh, sv); break;
940             case PMAT_SVtCLASS: write_private_class(fh, (HV*)sv); break;
941             #endif
942              
943             #if (PERL_REVISION == 5) && (PERL_VERSION >= 12)
944 611           case PMAT_SVtREGEXP: write_common_sv(fh, sv, sizeof(regexp)); break;
945             #endif
946 0           case PMAT_SVtFORMAT: write_common_sv(fh, sv, sizeof(XPVFM)); break;
947 65           case PMAT_SVtINVLIST: write_common_sv(fh, sv, sizeof(XPV) + SvLEN(sv)); break;
948 16822           case PMAT_SVtUNDEF: write_common_sv(fh, sv, 0); break;
949 0           case PMAT_SVtYES: write_common_sv(fh, sv, 0); break;
950 0           case PMAT_SVtNO: write_common_sv(fh, sv, 0); break;
951             }
952              
953 59046 100         if(SvMAGICAL(sv)) {
954             MAGIC *mg;
955 9662 100         for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
956             write_u8(fh, PMAT_SVxMAGIC);
957             write_svptr(fh, sv);
958 4831           write_u8(fh, mg->mg_type);
959 4831           write_u8(fh, (mg->mg_flags & MGf_REFCOUNTED ? 0x01 : 0));
960 4831           write_svptr(fh, mg->mg_obj);
961 4831 100         if(mg->mg_len == HEf_SVKEY)
962 2           write_svptr(fh, (SV*)mg->mg_ptr);
963             else
964             write_svptr(fh, NULL);
965 4831           write_svptr(fh, (SV *)mg->mg_virtual); /* Not really an SV */
966              
967 4831 50         if(mg->mg_type == PERL_MAGIC_ext &&
    0          
968 0 0         mg->mg_ptr && mg->mg_len != HEf_SVKEY) {
969 0           SV *key = make_tmp_iv((IV)mg->mg_virtual);
970             HE *he;
971              
972             DMD_MagicHelper *helper = NULL;
973 0           he = hv_fetch_ent(helper_per_magic, key, 0, 0);
974 0 0         if(he)
975 0 0         helper = (DMD_MagicHelper *)SvUV(HeVAL(he));
976              
977 0 0         if(helper) {
978 0           ENTER;
979 0           SAVETMPS;
980              
981 0           int ret = (helper)(aTHX_ ctx, sv, mg);
982              
983 0 0         if(ret > 0)
984 0           write_annotations_from_stack(fh, ret);
985              
986 0 0         FREETMPS;
987 0           LEAVE;
988             }
989             }
990             }
991             }
992              
993 59046 100         if(SvOBJECT(sv)) {
994 262           run_package_helpers(ctx, sv, SvSTASH(sv));
995             }
996              
997             #ifdef DEBUG_LEAKING_SCALARS
998             {
999             write_u8(fh, PMAT_SVxDEBUGREPORT);
1000             write_svptr(fh, sv);
1001             write_uint(fh, sv->sv_debug_serial);
1002             write_uint(fh, sv->sv_debug_line);
1003             /* TODO: this is going to make the file a lot larger, due to nonshared
1004             * strings. Consider if there's a way we can share these somehow
1005             */
1006             write_str(fh, sv->sv_debug_file);
1007             }
1008             #endif
1009 59046           }
1010              
1011             typedef struct
1012             {
1013             const char *name;
1014             enum {
1015             DMD_FIELD_PTR,
1016             DMD_FIELD_BOOL,
1017             DMD_FIELD_U8,
1018             DMD_FIELD_U32,
1019             DMD_FIELD_UINT,
1020             } type;
1021             struct {
1022             void *ptr;
1023             bool b;
1024             long n;
1025             };
1026             } DMDNamedField;
1027              
1028             typedef struct
1029             {
1030             const char *name;
1031             const char *str;
1032             size_t len;
1033             } DMDNamedString;
1034              
1035 0           static void writestruct(pTHX_ DMDContext *ctx, const char *name, void *addr, size_t size,
1036             size_t nfields, const DMDNamedField fields[])
1037             {
1038 0           FILE *fh = ctx->fh;
1039              
1040 0 0         if(!ctx->structdefs)
1041 0           ctx->structdefs = newHV();
1042              
1043 0           SV *idsv = *hv_fetch(ctx->structdefs, name, strlen(name), 1);
1044 0 0         if(!SvOK(idsv)) {
    0          
    0          
1045 0           int structid = ctx->next_structid;
1046 0           ctx->next_structid++;
1047              
1048 0           sv_setiv(idsv, structid);
1049              
1050             write_u8(fh, PMAT_SVtMETA_STRUCT);
1051 0           write_uint(fh, structid);
1052             write_uint(fh, nfields);
1053 0           write_str(fh, name);
1054 0 0         for(size_t i = 0; i < nfields; i++) {
1055 0           write_str(fh, fields[i].name);
1056 0           write_u8(fh, fields[i].type);
1057             }
1058             }
1059              
1060             write_u8(fh, PMAT_SVtSTRUCT);
1061             /* Almost the same layout as write_common_sv() */
1062             // Header for common
1063             write_svptr(fh, addr);
1064             write_u32(fh, -1);
1065             write_uint(fh, size);
1066             // PTRs for common
1067 0 0         write_svptr(fh, NUM2PTR(SV *, SvIV(idsv))); /* abuse the stash pointer to store the descriptor ID */
1068              
1069             // Body
1070 0 0         for(size_t i = 0; i < nfields; i++)
1071 0           switch(fields[i].type) {
1072             case DMD_FIELD_PTR:
1073 0           write_ptr(fh, fields[i].ptr);
1074             break;
1075              
1076             case DMD_FIELD_BOOL:
1077 0           write_u8(fh, fields[i].b);
1078             break;
1079              
1080             case DMD_FIELD_U8:
1081 0           write_u8(fh, fields[i].n);
1082             break;
1083              
1084             case DMD_FIELD_U32:
1085 0           write_u32(fh, fields[i].n);
1086             break;
1087              
1088             case DMD_FIELD_UINT:
1089 0           write_uint(fh, fields[i].n);
1090             break;
1091             }
1092 0           }
1093              
1094             #if (PERL_REVISION == 5) && (PERL_VERSION < 14)
1095             /*
1096             * This won't be very good, but good enough for our needs
1097             */
1098             static I32 dopoptosub_at(const PERL_CONTEXT *cxstk, I32 startingblock)
1099             {
1100             dVAR;
1101             I32 i;
1102              
1103             for(i = startingblock; i >= 0; i--) {
1104             const PERL_CONTEXT * const cx = &cxstk[i];
1105             switch (CxTYPE(cx)) {
1106             case CXt_EVAL:
1107             case CXt_SUB:
1108             case CXt_FORMAT:
1109             return i;
1110             default:
1111             continue;
1112             }
1113             }
1114             return i;
1115             }
1116              
1117             static const PERL_CONTEXT *caller_cx(int count, void *ignore)
1118             {
1119             I32 cxix = dopoptosub_at(cxstack, cxstack_ix);
1120             const PERL_CONTEXT *ccstack = cxstack;
1121             const PERL_SI *top_si = PL_curstackinfo;
1122              
1123             while(1) {
1124             while(cxix < 0 && top_si->si_type != PERLSI_MAIN) {
1125             top_si = top_si->si_prev;
1126              
1127             ccstack = top_si->si_cxstack;
1128             cxix = dopoptosub_at(ccstack, top_si->si_cxix);
1129             }
1130              
1131             if(cxix < 0)
1132             return NULL;
1133              
1134             if (PL_DBsub && GvCV(PL_DBsub) && cxix >= 0 && ccstack[cxix].blk_sub.cv == GvCV(PL_DBsub))
1135             count++;
1136              
1137             if(!count--)
1138             break;
1139              
1140             cxix = dopoptosub_at(ccstack, cxix - 1);
1141             }
1142              
1143             const PERL_CONTEXT *cx = &ccstack[cxix];
1144              
1145             if(CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT) {
1146             const I32 dbcxix = dopoptosub_at(ccstack, cxix - 1);
1147             if (PL_DBsub && GvCV(PL_DBsub) && dbcxix >= 0 && ccstack[dbcxix].blk_sub.cv == GvCV(PL_DBsub))
1148             cx = &ccstack[dbcxix];
1149             }
1150              
1151             return cx;
1152             }
1153             #endif
1154              
1155 1           static void dumpfh(FILE *fh)
1156             {
1157 1 50         max_string = SvIV(get_sv("Devel::MAT::Dumper::MAX_STRING", GV_ADD));
1158              
1159             {
1160             HE *he;
1161              
1162 1 50         if(hv_iterinit(legacy_helper_per_package)) {
1163 0           warn("Legacy per-package helpers in %HELPER_PER_PACKAGE are no longer followed\n");
1164 0 0         while((he = hv_iternext(legacy_helper_per_package))) {
1165             STRLEN len;
1166 0 0         warn(" %s\n", HePV(he, len)); // package names won't contain embedded NULs
    0          
1167             }
1168             }
1169              
1170 1 50         if(hv_iterinit(legacy_helper_per_magic)) {
1171 0           warn("Legacy per-magic helpers in %HELPER_PER_MAGIC are no longer followed\n");
1172 0 0         while((he = hv_iternext(legacy_helper_per_magic))) {
1173             STRLEN len;
1174 0 0         warn(" %s\n", HePV(he, len)); // magic addresses are decimal integers
    0          
1175             }
1176             }
1177             }
1178              
1179 1           DMDContext ctx = {
1180             .fh = fh,
1181             .next_structid = 0,
1182             };
1183              
1184             // Header
1185 1           fwrite("PMAT", 4, 1, fh);
1186              
1187             int flags = 0;
1188             #if (BYTEORDER == 0x1234) || (BYTEORDER == 0x12345678)
1189             // little-endian
1190             #elif (BYTEORDER == 0x4321) || (BYTEORDER == 0x87654321)
1191             flags |= 0x01; // big-endian
1192             #else
1193             # error "Expected BYTEORDER to be big- or little-endian"
1194             #endif
1195              
1196             #if UVSIZE == 8
1197             flags |= 0x02; // 64-bit integers
1198             #elif UVSIZE == 4
1199             #else
1200             # error "Expected UVSIZE to be either 4 or 8"
1201             #endif
1202              
1203             #if PTRSIZE == 8
1204             flags |= 0x04; // 64-bit pointers
1205             #elif PTRSIZE == 4
1206             #else
1207             # error "Expected PTRSIZE to be either 4 or 8"
1208             #endif
1209              
1210             #if NVSIZE > 8
1211             flags |= 0x08; // long-double
1212             #endif
1213              
1214             #ifdef USE_ITHREADS
1215             flags |= 0x10; // ithreads
1216             #endif
1217              
1218             write_u8(fh, flags);
1219             write_u8(fh, 0);
1220             write_u8(fh, FORMAT_VERSION_MAJOR);
1221             #ifdef HAVE_FEATURE_CLASS
1222             write_u8(fh, 5);
1223             #else
1224             write_u8(fh, FORMAT_VERSION_MINOR);
1225             #endif
1226              
1227             write_u32(fh, PERL_REVISION<<24 | PERL_VERSION<<16 | PERL_SUBVERSION);
1228              
1229             write_u8(fh, sizeof(sv_sizes)/3);
1230 1           fwrite(sv_sizes, sizeof(sv_sizes), 1, fh);
1231              
1232             write_u8(fh, sizeof(svx_sizes)/3);
1233 1           fwrite(svx_sizes, sizeof(svx_sizes), 1, fh);
1234              
1235             write_u8(fh, sizeof(ctx_sizes)/3);
1236 1           fwrite(ctx_sizes, sizeof(ctx_sizes), 1, fh);
1237              
1238             // Roots
1239             write_svptr(fh, &PL_sv_undef);
1240             write_svptr(fh, &PL_sv_yes);
1241             write_svptr(fh, &PL_sv_no);
1242              
1243 1           struct root { char *name; SV *ptr; } roots[] = {
1244             { "main_cv", (SV*)PL_main_cv },
1245             { "defstash", (SV*)PL_defstash },
1246             { "mainstack", (SV*)PL_mainstack },
1247             { "beginav", (SV*)PL_beginav },
1248             { "checkav", (SV*)PL_checkav },
1249             { "unitcheckav", (SV*)PL_unitcheckav },
1250             { "initav", (SV*)PL_initav },
1251             { "endav", (SV*)PL_endav },
1252             { "strtab", (SV*)PL_strtab },
1253             { "envgv", (SV*)PL_envgv },
1254             { "incgv", (SV*)PL_incgv },
1255             { "statgv", (SV*)PL_statgv },
1256             { "statname", (SV*)PL_statname },
1257             { "tmpsv", (SV*)PL_Sv }, // renamed
1258             { "defgv", (SV*)PL_defgv },
1259             { "argvgv", (SV*)PL_argvgv },
1260             { "argvoutgv", (SV*)PL_argvoutgv },
1261             { "argvout_stack", (SV*)PL_argvout_stack },
1262             { "errgv", (SV*)PL_errgv },
1263             { "fdpid", (SV*)PL_fdpid },
1264             { "preambleav", (SV*)PL_preambleav },
1265             { "modglobalhv", (SV*)PL_modglobal },
1266             #ifdef USE_ITHREADS
1267             { "regex_padav", (SV*)PL_regex_padav },
1268             #endif
1269             { "sortstash", (SV*)PL_sortstash },
1270             { "firstgv", (SV*)PL_firstgv },
1271             { "secondgv", (SV*)PL_secondgv },
1272             { "debstash", (SV*)PL_debstash },
1273             { "stashcache", (SV*)PL_stashcache },
1274             { "isarev", (SV*)PL_isarev },
1275             #if (PERL_REVISION == 5) && ((PERL_VERSION > 10) || (PERL_VERSION == 10 && PERL_SUBVERSION > 0))
1276             { "registered_mros", (SV*)PL_registered_mros },
1277             #endif
1278             { "rs", (SV*)PL_rs },
1279             { "last_in_gv", (SV*)PL_last_in_gv },
1280             { "defoutgv", (SV*)PL_defoutgv },
1281             { "hintgv", (SV*)PL_hintgv },
1282             { "patchlevel", (SV*)PL_patchlevel },
1283             { "e_script", (SV*)PL_e_script },
1284             { "mess_sv", (SV*)PL_mess_sv },
1285             { "ors_sv", (SV*)PL_ors_sv },
1286             { "encoding", (SV*)PL_encoding },
1287             #if (PERL_REVISION == 5) && (PERL_VERSION >= 12)
1288             { "ofsgv", (SV*)PL_ofsgv },
1289             #endif
1290             #if (PERL_REVISION == 5) && (PERL_VERSION >= 14) && (PERL_VERSION <= 20)
1291             { "apiversion", (SV*)PL_apiversion },
1292             #endif
1293             #if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
1294             { "blockhooks", (SV*)PL_blockhooks },
1295             #endif
1296             #if (PERL_REVISION == 5) && (PERL_VERSION >= 16)
1297             { "custom_ops", (SV*)PL_custom_ops },
1298             { "custom_op_names", (SV*)PL_custom_op_names },
1299             { "custom_op_descs", (SV*)PL_custom_op_descs },
1300             #endif
1301              
1302             // Unicode etc...
1303             { "utf8_mark", (SV*)PL_utf8_mark },
1304             { "utf8_toupper", (SV*)PL_utf8_toupper },
1305             { "utf8_totitle", (SV*)PL_utf8_totitle },
1306             { "utf8_tolower", (SV*)PL_utf8_tolower },
1307             { "utf8_tofold", (SV*)PL_utf8_tofold },
1308             { "utf8_idstart", (SV*)PL_utf8_idstart },
1309             { "utf8_idcont", (SV*)PL_utf8_idcont },
1310             #if (PERL_REVISION == 5) && (PERL_VERSION >= 12) && (PERL_VERSION <= 20)
1311             { "utf8_X_extend", (SV*)PL_utf8_X_extend },
1312             #endif
1313             #if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
1314             { "utf8_xidstart", (SV*)PL_utf8_xidstart },
1315             { "utf8_xidcont", (SV*)PL_utf8_xidcont },
1316             { "utf8_foldclosures", (SV*)PL_utf8_foldclosures },
1317             #if (PERL_REVISION == 5) && ((PERL_VERSION < 29) || (PERL_VERSION == 29 && PERL_SUBVERSION < 7))
1318             { "utf8_foldable", (SV*)PL_utf8_foldable },
1319             #endif
1320             #endif
1321             #if (PERL_REVISION == 5) && (PERL_VERSION >= 16)
1322             { "Latin1", (SV*)PL_Latin1 },
1323             { "AboveLatin1", (SV*)PL_AboveLatin1 },
1324             { "utf8_perl_idstart", (SV*)PL_utf8_perl_idstart },
1325             #endif
1326             #if (PERL_REVISION == 5) && (PERL_VERSION >= 18)
1327             #if (PERL_REVISION == 5) && ((PERL_VERSION < 29) || (PERL_VERSION == 29 && PERL_SUBVERSION < 7))
1328             { "NonL1NonFinalFold", (SV*)PL_NonL1NonFinalFold },
1329             #endif
1330             { "HasMultiCharFold", (SV*)PL_HasMultiCharFold },
1331             # if (PERL_VERSION <= 20)
1332             { "utf8_X_regular_begin", (SV*)PL_utf8_X_regular_begin },
1333             # endif
1334             { "utf8_charname_begin", (SV*)PL_utf8_charname_begin },
1335             { "utf8_charname_continue", (SV*)PL_utf8_charname_continue },
1336             { "utf8_perl_idcont", (SV*)PL_utf8_perl_idcont },
1337             #endif
1338             #if (PERL_REVISION == 5) && ((PERL_VERSION > 19) || (PERL_VERSION == 19 && PERL_SUBVERSION >= 4))
1339             { "UpperLatin1", (SV*)PL_UpperLatin1 },
1340             #endif
1341             };
1342              
1343 1           AV *moreroots = get_av("Devel::MAT::Dumper::MORE_ROOTS", 0);
1344              
1345             int nroots = sizeof(roots) / sizeof(roots[0]);
1346 1 50         if(moreroots)
1347 0 0         nroots += (AvFILL(moreroots)+1) / 2;
1348              
1349 1           write_u32(fh, nroots);
1350              
1351             int i;
1352 64 100         for(i = 0; i < sizeof(roots) / sizeof(roots[0]); i++) {
1353 63           write_str(fh, roots[i].name);
1354 63           write_svptr(fh, roots[i].ptr);
1355             }
1356 1 50         if(moreroots) {
1357 0           SV **svp = AvARRAY(moreroots);
1358 0 0         int max = AvFILL(moreroots);
1359              
1360 0 0         for(i = 0; i < max; i += 2) {
1361 0 0         write_str(fh, SvPV_nolen(svp[i]));
1362 0           write_svptr(fh, svp[i+1]);
1363             }
1364             }
1365              
1366             // Stack
1367 1           write_uint(fh, PL_stack_sp - PL_stack_base + 1);
1368             SV **sp;
1369 3 100         for(sp = PL_stack_base; sp <= PL_stack_sp; sp++)
1370 2           write_svptr(fh, *sp);
1371              
1372             bool seen_defstash = false;
1373              
1374             // Heap
1375             SV *arena;
1376 351 100         for(arena = PL_sv_arenaroot; arena; arena = (SV *)SvANY(arena)) {
1377 350           const SV *arenaend = &arena[SvREFCNT(arena)];
1378              
1379             SV *sv;
1380 59500 100         for(sv = arena + 1; sv < arenaend; sv++) {
1381 59150 50         if(sv == tmpsv)
1382 0           continue;
1383              
1384 59150 100         switch(SvTYPE(sv)) {
1385             case 0xff:
1386 104           continue;
1387             }
1388              
1389 59046           write_sv(&ctx, sv);
1390              
1391 59046 100         if(sv == (const SV *)PL_defstash)
1392             seen_defstash = true;
1393             }
1394             }
1395              
1396             // and a few other things that don't actually appear in the arena
1397 1 50         if(!seen_defstash)
1398 0           write_sv(&ctx, (const SV *)PL_defstash);
1399              
1400             // Savestack
1401             #if (PERL_REVISION == 5) && (PERL_VERSION >= 18)
1402             /* The savestack only had a vaguely nicely predicable layout from perl 5.18 onwards
1403             * On earlier perls we'll just not bother. Sorry
1404             * No `local` detection for you
1405             */
1406              
1407 1           int saveix = PL_savestack_ix;
1408 4593 100         while(saveix) {
1409 4592           UV uv = PL_savestack[saveix-1].any_uv;
1410 4592           U8 type = (U8)uv & SAVE_MASK;
1411              
1412             /* TODO: this seems fragile - does core perl not export a nice way to
1413             * do it?
1414             */
1415             char count;
1416 4592 100         if(type <= SAVEt_ARG0_MAX)
1417             count = 0;
1418 4591 50         else if(type <= SAVEt_ARG1_MAX)
1419             count = 1;
1420 0 0         else if(type <= SAVEt_ARG2_MAX)
1421             count = 2;
1422 0 0         else if(type <= SAVEt_MAX)
1423             count = 3;
1424             else
1425             /* Unrecognised type; just abort here */
1426             break;
1427              
1428 4592           saveix -= (count + 1);
1429 4592 100         ANY *a0 = count > 0 ? &PL_savestack[saveix ] : NULL,
1430 4592 50         *a1 = count > 1 ? &PL_savestack[saveix+1] : NULL,
1431 4592 50         *a2 = count > 2 ? &PL_savestack[saveix+2] : NULL;
1432              
1433 4592           switch(type) {
1434             /* Most savestack entries aren't very interesting to Devel::MAT, but
1435             * there's a few we find useful. A lot of them don't add any linkages
1436             * between SVs, so we can ignore the majority of them
1437             */
1438             case SAVEt_CLEARSV:
1439             case SAVEt_CLEARPADRANGE:
1440              
1441             #if (PERL_REVISION == 5) && (PERL_VERSION >= 24)
1442             case SAVEt_TMPSFLOOR:
1443             #endif
1444             case SAVEt_BOOL:
1445             case SAVEt_COMPPAD:
1446             case SAVEt_FREEOP:
1447             case SAVEt_FREEPV:
1448             case SAVEt_FREESV:
1449             case SAVEt_I16:
1450             case SAVEt_I32_SMALL:
1451             case SAVEt_I8:
1452             case SAVEt_INT_SMALL:
1453             case SAVEt_MORTALIZESV:
1454             case SAVEt_OP:
1455             case SAVEt_PARSER:
1456             case SAVEt_SHARED_PVREF:
1457             case SAVEt_SPTR:
1458              
1459             case SAVEt_DESTRUCTOR:
1460             case SAVEt_DESTRUCTOR_X:
1461             case SAVEt_GP:
1462             case SAVEt_I32:
1463             case SAVEt_INT:
1464             case SAVEt_IV:
1465             case SAVEt_LONG:
1466             #if (PERL_REVISION == 5) && (PERL_VERSION >= 20)
1467             case SAVEt_STRLEN:
1468             #endif
1469             #if (PERL_REVISION == 5) && (PERL_VERSION >= 34)
1470             case SAVEt_STRLEN_SMALL:
1471             #endif
1472             case SAVEt_SAVESWITCHSTACK:
1473             case SAVEt_VPTR:
1474             case SAVEt_ADELETE:
1475              
1476             case SAVEt_DELETE:
1477             /* ignore */
1478             break;
1479              
1480             case SAVEt_AV:
1481             /* a local'ised @var */
1482             write_u8(fh, PMAT_SVxSAVED_AV);
1483 0           write_svptr(fh, a0->any_ptr); // GV
1484 0           write_svptr(fh, a1->any_ptr); // AV
1485             break;
1486              
1487             case SAVEt_HV:
1488             /* a local'ised %var */
1489             write_u8(fh, PMAT_SVxSAVED_HV);
1490 0           write_svptr(fh, a0->any_ptr); // GV
1491 0           write_svptr(fh, a1->any_ptr); // HV
1492             break;
1493              
1494             case SAVEt_SV:
1495             /* a local'ised $var */
1496             write_u8(fh, PMAT_SVxSAVED_SV);
1497 0           write_svptr(fh, a0->any_ptr); // GV
1498 0           write_svptr(fh, a1->any_ptr); // SV
1499             break;
1500              
1501             case SAVEt_HELEM:
1502             /* a local'ised $hash{key} */
1503             write_u8(fh, PMAT_SVxSAVED_HELEM);
1504 0           write_svptr(fh, a0->any_ptr); // HV
1505 0           write_svptr(fh, a1->any_ptr); // key SV
1506 0           write_svptr(fh, a2->any_ptr); // value SV
1507             break;
1508              
1509             case SAVEt_AELEM:
1510             /* a local'ised $array[idx] */
1511             write_u8(fh, PMAT_SVxSAVED_AELEM);
1512 0           write_svptr(fh, a0->any_ptr); // AV
1513 0           write_uint(fh, a1->any_iv); // index
1514 0           write_svptr(fh, a2->any_ptr); // value SV
1515             break;
1516              
1517             case SAVEt_GVSLOT:
1518             /* a local'ised glob slot
1519             * a0 points at the GV itself, a1 points at one of the slots within
1520             * the GP part
1521             * In practice this would only ever be the CODE slot, because other
1522             * slots have other localisation mechanisms
1523             */
1524 0 0         if(a1->any_ptr != (SV **) &(GvGP((GV *)a0->any_ptr)->gp_cv)) {
1525 0           fprintf(stderr, "TODO: SAVEt_GVSLOT of slot other than ->gp_cv\n");
1526             break;
1527             }
1528              
1529             write_u8(fh, PMAT_SVxSAVED_CV);
1530 0           write_svptr(fh, a0->any_ptr);
1531 0           write_svptr(fh, a2->any_ptr);
1532             break;
1533              
1534             case SAVEt_GENERIC_SVREF:
1535             /* Core perl uses this in a number of places, a few of which we can
1536             * identify
1537             */
1538 0 0         if(a0->any_ptr == &GvSV(PL_defgv)) {
1539             /* local $_ = ... */
1540             write_u8(fh, PMAT_SVxSAVED_SV);
1541 0           write_svptr(fh, (SV *)PL_defgv);
1542 0           write_svptr(fh, a1->any_ptr);
1543             }
1544             else
1545 0           fprintf(stderr, "TODO: SAVEt_GENERIC_SVREF *a0=%p a1=%p\n",
1546             *((void **)a0->any_ptr), a1->any_ptr);
1547             break;
1548              
1549             default:
1550 0           fprintf(stderr, "TODO: savestack type=%d\n", type);
1551             break;
1552             }
1553             }
1554             #endif
1555              
1556             write_u8(fh, 0);
1557              
1558             // Caller context
1559             int cxix;
1560 0           for(cxix = 0; ; cxix++) {
1561 1           const PERL_CONTEXT *cx = caller_cx(cxix, NULL);
1562 1 50         if(!cx)
1563             break;
1564              
1565 0           switch(CxTYPE(cx)) {
1566             case CXt_SUB: {
1567 0           COP *oldcop = cx->blk_oldcop;
1568              
1569             write_u8(fh, PMAT_CTXtSUB);
1570 0           write_u8(fh, cx->blk_gimme);
1571 0           write_uint(fh, CopLINE(oldcop));
1572 0 0         write_str(fh, CopFILE(oldcop));
1573              
1574 0           write_u32(fh, cx->blk_sub.olddepth);
1575 0           write_svptr(fh, (SV*)cx->blk_sub.cv);
1576             #if (PERL_REVISION == 5) && ((PERL_VERSION > 23) || (PERL_VERSION == 23 && PERL_SUBVERSION >= 8))
1577             write_svptr(fh, NULL);
1578             #else
1579             write_svptr(fh, CxHASARGS(cx) ? (SV*)cx->blk_sub.argarray : NULL);
1580             #endif
1581              
1582             break;
1583             }
1584             case CXt_EVAL: {
1585 0           COP *oldcop = cx->blk_oldcop;
1586              
1587              
1588 0 0         if(CxOLD_OP_TYPE(cx) == OP_ENTEREVAL) {
1589             /* eval() */
1590             write_u8(fh, PMAT_CTXtEVAL);
1591 0           write_u8(fh, cx->blk_gimme);
1592 0           write_uint(fh, CopLINE(oldcop));
1593 0 0         write_str(fh, CopFILE(oldcop));
1594 0           write_svptr(fh, cx->blk_eval.cur_text);
1595             }
1596 0 0         else if(cx->blk_eval.old_namesv)
1597             // require
1598             ;
1599             else {
1600             /* eval BLOCK == TRY */
1601             write_u8(fh, PMAT_CTXtTRY);
1602 0           write_u8(fh, cx->blk_gimme);
1603 0           write_uint(fh, CopLINE(oldcop));
1604 0 0         write_str(fh, CopFILE(oldcop));
1605             }
1606              
1607             break;
1608             }
1609             }
1610 0           }
1611              
1612             write_u8(fh, 0);
1613              
1614 1 50         if(ctx.structdefs)
1615             SvREFCNT_dec((SV *)ctx.structdefs);
1616 1           }
1617              
1618             MODULE = Devel::MAT::Dumper PACKAGE = Devel::MAT::Dumper
1619              
1620             void
1621             dump(char *file)
1622             CODE:
1623             {
1624 1           FILE *fh = fopen(file, "wb+");
1625 1 50         if(!fh)
1626 0           croak("Cannot open %s for writing - %s", file, strerror(errno));
1627              
1628 1           dumpfh(fh);
1629 1           fclose(fh);
1630             }
1631              
1632             void
1633             dumpfh(FILE *fh)
1634              
1635             BOOT:
1636             SV *sv, **svp;
1637              
1638 2 50         if((svp = hv_fetchs(PL_modglobal, "Devel::MAT::Dumper/%helper_per_package", 0)))
1639 0           sv = *svp;
1640             else
1641 2           hv_stores(PL_modglobal, "Devel::MAT::Dumper/%helper_per_package",
1642             sv = newRV_noinc((SV *)(newHV())));
1643 2           helper_per_package = (HV *)SvRV(sv);
1644              
1645 2 50         if((svp = hv_fetchs(PL_modglobal, "Devel::MAT::Dumper/%helper_per_magic", 0)))
1646 0           sv = *svp;
1647             else
1648 2           hv_stores(PL_modglobal, "Devel::MAT::Dumper/%helper_per_magic",
1649             sv = newRV_noinc((SV *)(newHV())));
1650 2           helper_per_magic = (HV *)SvRV(sv);
1651              
1652 2           legacy_helper_per_package = get_hv("Devel::MAT::Dumper::HELPER_PER_PACKAGE", GV_ADD);
1653 2           legacy_helper_per_magic = get_hv("Devel::MAT::Dumper::HELPER_PER_MAGIC", GV_ADD);
1654              
1655 2           sv_setiv(*hv_fetchs(PL_modglobal, "Devel::MAT::Dumper/writestruct()", 1), PTR2UV(&writestruct));