note
ambrus
<P>
If I understand you correctly, you want to trap each
entry and exit to the subroutines of a certain package.
<P>
As [theorbtwo] has noted, you can trap
each and every subroutine call that happens in perl
with &DB::sub, and then you check for the called package.
A small example is (for perl 5.8.2)
<code>
BEGIN {
sub DB::sub {
my ($r, @r, $s);
$s = $DB::sub;
$s=~/^T::/ or goto &$s;
warn "entering $s\n";
if (wantarray)
{ @r = &$s; }
elsif (defined wantarray)
{ $r = &$s; }
else
{ &$s; }
warn "exitting $s\n";
wantarray ? @r : $r;
}
$^P |= 1;
}
{
package T;
$r = "r";
sub f { $_[0].$r.n(); }
sub n { @l = l(); 2, chr(@l); }
sub l { -5..4; }
}
sub g { T::f($_[0]."a"); };
print g("b");
</code>
(Thanks to [wog] for bringing $^P in my attention in [id://376696].)
<P>
The above aspect, however, has some problems.
It might be slow as it has to catch all subroutine calls, not only those in a certain package,
it does not work for anonymous subs,
and it might be difficult to make it work if you use the perl debugger or use DB::sub for any other purpose.
<P>
As a different approach, you could replace
each subroutine in the package with a different subroutine.
This, however, has the backdraw that the subroutines you want to trap have to be defined by the time you install the trapping code, as a special case you can not trap AUTOLOADED subs this way. An example is:
<code>
{
for $n (keys %T::) { if (defined &{$T::{$n}}) {
my $s = $n; my $f = \&{$T::{$n}};
$T::{$n} = sub {
my ($r, @r);
warn "entering $s\n";
if (wantarray)
{ @r = &$f; }
elsif (defined wantarray)
{ $r = &$f; }
else
{ &$f; }
warn "exitting $s\n";
wantarray ? @r : $r;
}
} }
}
{
package T;
$r = "r";
sub f { print $_[0].$r.n(); }
sub n { @l = l(); 2, chr(@l); }
sub l { -5..4; }
}
sub g { T::f($_[0]."a"); }; g("b");
</code>
<P>
(Pity overloading "&{}" can not catch named subroutine calls,
as that would have been a very elegant solution.)
<P>
Update: Note that these codes get much shorter if you only want to trace subroutine entry, not exit, as you don't have to mess with the contexts. You might only want to trace calls that come from a different package. That should be possible with <code>caller</code>.
378941
378941