File Coverage

lib/Devel/MAT/Dumper.xs
Criterion Covered Total %
statement 267 407 65.6
branch 213 378 56.3
condition n/a
subroutine n/a
pod n/a
total 480 785 61.1


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