I had a problem at work where two very small iterations of the debugger somehow triggered an "Out of memory" error. I think there was a little bit of memory corruption going on but that wasn't in the scope of what I was willing or able to tackle in that moment. So instead of solving the real problem, I learned how to load the debugger during runtime. I've no reason to think this method isn't applicable to removing the debugger either.

By the way, the punchline is that the module Enbugger is an implementation of the ideas in this post and with it you don't need to start perl with the -d flag or incur any debugging overhead. It does a bit more than it needs to but that's only because my understanding of how to do this evolved while I writing the module. Some future version (the current version is 0.03) will take this information into account. In fact, feel free to do this yourself if you wish. Email me at jjore at cpan.org to get PAUSE permissions if you're interested.

The only real trick appears to be to modify all "nextstate" opnodes to become "dbstate" opnodes. My first thought when approaching this problem was to hook the runops loop and change all OP_NEXTSTATE ops to OP_DBSTATE. This has two problems. Currently executing subroutines aren't affected because their runloop is already entered. I wasn't being discriminating about which nextstate ops to modify. I'd turned the debugger on itself. While this is interesting in theory, the debugger hasn't been tested while operating on itself and I'm not sure if this would break stuff.

Without debugging:

perl -MO=Terse -e 'print;exit' LISTOP (0x8133d68) leave [1] OP (0x8126628) enter COP (0x8133d28) nextstate LISTOP (0x8133e30) print OP (0x8133e68) pushmark UNOP (0x8133ce8) null [15] SVOP (0x8133f40) gvsv GV (0x811e120) *_ COP (0x8133d90) nextstate OP (0x8133c98) exit

With debugging:

perl -d -MO=Terse -e 'print;exit' Loading DB routines from perl5db.pl version 1.28 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. LISTOP (0x8133268) leave [1] OP (0x8126700) enter COP (0x81265f0) dbstate LISTOP (0x82db488) print OP (0x82db2d8) pushmark UNOP (0x82db468) null [15] SVOP (0x82db350) gvsv GV (0x811e120) *_ COP (0x81334b0) dbstate OP (0x8134a98) exit

In the above code, you can see an optree for the "main" part of a program including two "nextstate" operations. They occur roughly anywhere there could be a semi-colon in your perl program. If you compare to the debugged version, the same places that had nextstate operations now contain dbstate operations but were otherwise the same op class: COP.

op.c: Perl_newSTATEOP

if (PERLDB_LINE && CopLINE(PL_curcop) && PL_curstash != PL_debstash) { cop->op_type = OP_DBSTATE; cop->op_ppaddr = PL_ppaddr[ OP_DBSTATE ]; } else { cop->op_type = OP_NEXTSTATE; cop->op_ppaddr = PL_ppaddr[ OP_NEXTSTATE ]; }

The above snippet of C code show the only fundamental difference between DBSTATE and NEXTSTATE ops. The op_type field which is largely informational and then the function pointer from PL_ppaddr[...]. Switching between debugging and non-debugging is as simple as loading perl5db.pl and changing all the relevant opcodes. Simple thanks to B::Utils!

Enbugger.pm transforms all nextstate ops into breakpoints

B::Utils::walkallops_filtered( sub { local $@; return eval { return $_[0]->name eq 'nextstate' and $_[0]->stashpv ne 'DB'; }; }, \ &_enbug_cop, );

Enbugger.xs does an ickle bit of magic. The XS safety is lax here but I expect to get only B::COP objects. All B::* objects are just blessed scalars where the integer value is the pointer value. You can easily marshal them back into COP or SVs just by turning the ints into pointers.

void Enbugger_enbug_cop( o ) SV * o PROTOTYPE: $ PREINIT: COP* cop; CODE: cop = INT2PTR( COP*, SvIV( SvRV( o ) ) ); cop->op_type = OP_DBSTATE; cop->op_ppaddr = PL_ppaddr[ OP_DBSTATE ];

Removing the debugger at runtime is just the opposite operation to all the same COP nodes. Change all the nodes where ->name eq 'dbstate' and set cop->op_type = OP_NEXTSTATE; cop->op_ppaddr = PL_ppaddr[ OP_NEXTSTATE ].

Cake's done!

⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊


In reply to Enabling or disabliing the debugger at runtime by diotalevi

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.