File Coverage

lib/Devel/MAT/Dumper.xs
Criterion Covered Total %
statement 344 562 61.2
branch 208 334 62.2
condition n/a
subroutine n/a
pod n/a
total 552 896 61.6


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