File Coverage

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