/usr/share/perl5/Net/SIP/Debug.pm is in libnet-sip-perl 0.66-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | package Net::SIP::Debug;
use strict;
use warnings;
use Carp;
use Data::Dumper;
use Time::HiRes 'gettimeofday';
use Scalar::Util 'looks_like_number';
use base 'Exporter';
our @EXPORT = qw( DEBUG DEBUG_DUMP LEAK_TRACK );
our @EXPORT_OK = qw( debug stacktrace );
our $level = 0; # needed global for source filter
my %level4package; # package specific level
my $debug_prefix = 'DEBUG:'; # default prefix
my $debug_sub; # alternative sub to STDERR output
##############################################################
# set level, scope etc from use. Usually used at the
# start, e.g. perl -MNet::SIP::Debug=level program
# Args: @args
# @args: something for sub level, rest to Exporter
# Returns: NONE
##############################################################
sub import {
my $class = shift;
my (@export,@level);
for (@_) {
if ( ref eq 'CODE' ) {
# set debug sub
$debug_sub = $_;
} elsif ( m{[=\*]} || m{^\d} || m{::} ) {
push @level,$_
} else {
push @export,$_
}
}
$class->level(@level) if @level;
$class->export_to_level(1,@export) if @export;
$class->export_to_level(1) if ! @export && ! @level;
}
##############################################################
# set/get debug level
# Args: ($class,@spec)
# @spec: number|package|package=number for setting
# global|package specific debug level. If package
# is postfixed with '*' the level will be used for
# subpackages too.
# Returns: NONE|level
# level: if not @spec level for the current package
# (first outside Net::SIP::Debug in caller stack) will
# be returned
##############################################################
sub level {
shift; # class
if ( @_ ) {
my @level = @_ >1 ? split( m{[^\w:=\*]+}, $_[0] ): @_;
foreach (@level) {
if ( m{^\d+$} ) {
$level = $_;
} elsif ( m{^([\w:]+)(\*)?(?:=(\d+))?$} ) {
# package || package=level
my $l = defined($3) ? $3: $level || 1;
my $name = $1;
my $below = $2;
my @names = ( $name );
push @names, "Net::".$name if $name =m{^SIP\b};
push @names, "Net::SIP::".$name if $name !~m{^Net::SIP\b};
foreach (@names) {
$level4package{$_} = $l;
$level4package{$_.'::'} = $l if $below;
}
}
}
} else {
# check
if ( %level4package ) {
# check if there is a specific level for this package
my $pkg;
for( my $i=1;1;$i++ ) {
# find first frame outside of this package
($pkg) = caller($i);
last if !$pkg or $pkg ne __PACKAGE__;
}
return $level if !$pkg;
# find exakt match
my $l = $level4package{$pkg};
return $l if defined($l);
# find match for upper packages, e.g. if there is an entry for
# 'Net::SIP::' it matches everything below Net::SIP
while ( $pkg =~s{::\w+(::)?$}{::} ) {
return $l if defined( $l = $level4package{$pkg} );
}
}
}
return $level
}
################################################################
# set prefix
# default prefix is 'DEBUG:' but in forking apps it might
# be useful to change it to "DEBUG($$):" or similar
# Args: $class,$prefix
# Returns: NONE
################################################################
sub set_prefix {
(undef,$debug_prefix) = @_
}
################################################################
# write debug output if debugging enabled for caller
# Args: ?$level, ( $message | $fmt,@arg )
# $level: if first arg is number it's interpreted as debug level
# $message: single message
# $fmt: format for sprintf
# @arg: arguments for sprintf after format
# Returns: NONE
################################################################
sub DEBUG { goto &debug }
sub debug {
my $level = __PACKAGE__->level || return;
my $prefix = $debug_prefix;
if (@_>1 and looks_like_number($_[0])) {
my $when = shift;
return if $when>$level;
$prefix .= "<$when>";
}
my ($msg,@arg) = @_;
return if !defined($msg);
if ( 1 || $msg !~ m{^\w+:} ) {
# Message hat keinen eigenen "Prefix:", also mit Funktion[Zeile] prefixen
my ($sub) = (caller(1))[3];
my $line = (caller(0))[2];
$sub =~s{^main::}{} if $sub;
$sub ||= 'Main';
$msg = "$sub\[$line]: ".$msg;
}
if ( @arg ) {
# $msg als format-string für sprintf ansehen
no warnings 'uninitialized';
$msg = sprintf($msg,@arg);
}
# if $debug_sub use this
return $debug_sub->($msg) if $debug_sub;
# alle Zeilen mit DEBUG: prefixen
$prefix = sprintf "%.4f %s",scalar(gettimeofday()),$prefix;
$msg = $prefix." ".$msg;
$msg =~s{\n}{\n$prefix\t}g;
return $msg if defined wantarray; # don't print
$msg =~s{[^[:space:][:print:]]}{_}g;
print STDERR $msg,"\n";
}
################################################################
# Dumps structure if debugging enabled
# Args: ?$level,@data
# $level: if first arg is number it's interpreted as debug level
# @data: what to be dumped, if @data>1 will dump \@data, else $data[0]
# Returns: NONE
################################################################
sub DEBUG_DUMP {
my $level = __PACKAGE__->level || return;
my $when;
if (@_>1 and looks_like_number($_[0])) {
$when = shift;
return if $when>$level;
}
@_ = Dumper( @_>1 ? \@_:$_[0] );
unshift @_,$when if defined $when;
goto &debug;
}
################################################################
# return stacktrace
# Args: $message | $fmt,@arg
# Returns: $stacktrace
# $stacktrace: stracktrace including debug info from args
################################################################
sub stacktrace {
return Carp::longmess( debug(@_) );
}
################################################################
# helps to track leaks, e.g. where refcounts will never go to
# zero because of circular references...
# will build proxy object around reference and will inform when
# LEAK_TRACK is called or when object gets destroyed. If Devel::Peek
# is available it will Devel::Peek::Dump the object on each
# LEAK_TRACK (better would be to just show the refcount of the
# reference inside the object, but Devel::Peek dumps to STDERR
# and I didn't found any other package to provide the necessary
# functionality)
# Args: $ref
# Returns: $ref
# $ref: reblessed original reference if not reblessed yet
################################################################
sub LEAK_TRACK {
my $class = ref($_[0]);
my $leak_pkg = '__LEAK_TRACK__';
my ($file,$line) = (caller(0))[1,2];
my $count = Devel::Peek::SvREFCNT($_[0]);
if ( $class =~m{^$leak_pkg} ) {
# only print info
warn "$_[0] +++ refcount($count) tracking from $file:$line\n";
Devel::Peek::Dump($_[0],1);
return $_[0];
}
unless ( $class eq 'HASH' || $class eq 'ARRAY' || $class eq 'SCALAR' ) {
# need to create wrapper package ?
$leak_pkg .= '::'.$class;
if ( ! UNIVERSAL::can( $leak_pkg, 'DESTROY' )) {
eval <<EOL;
package $leak_pkg;
our \@ISA = qw( $class );
sub DESTROY {
warn "\$_[0] --- destroy\n";
\$_[0]->SUPER::DESTROY;
}
EOL
die $@ if $@;
}
}
bless $_[0], $leak_pkg;
warn "$_[0] +++ refcount($count) starting tracking called from $file:$line\n";
Devel::Peek::Dump($_[0],1);
return $_[0];
}
{
package __LEAK_TRACK__;
sub DESTROY {
my ($file,$line) = (caller(0))[1,2];
warn "$_[0] --- destroy in $file:$line\n";
}
}
eval 'require Devel::Peek';
if ( $@ ) {
# cannot be loaded
*{ 'Devel::Peek::Dump' } = sub {};
*{ 'Devel::Peek::SvREFCNT' } = sub { 'unknown' };
}
=for experimental_use_only
# works, but startup of programs using this is noticably slower, therefore
# not enabled by default
use Filter::Simple;
FILTER_ONLY( code => sub {
# replace DEBUG(...) with
# - if Debug::level around it (faster, because expressions inside debug
# get only evaluated if debugging is active)
# - no warnings for expressions, because in often debug messages
# are quick and dirty
# FIXME: do it for DEBUG_DUMP too
# cannot use Text::Balanced etc because placeholder might contain ')' which
# should not be matched
my $code = '';
{
local $_ = $_; # copy
while (1) {
$code .=
s{\ADEBUG\s*\(}{}s ? '' :
s{\A(.*?[^\w:])DEBUG\s*\(}{}s ? $1 :
last;
my $level = 1;
my $inside = '';
while ( s{\A((?:$Filter::Simple::placeholder|.)*?)([()])}{}s ) {
$inside .= $1;
$level += ( $2 eq '(' ) ? +1:-1;
last if !$level;
$inside .= $2;
}
$level && die "unbalanced brackets in DEBUG(..)";
$code .= "if (\$Debug::level) { no warnings; Debug::debug($inside) }";
}
$code .= $_; # rest
}
$_ = $code;
});
=cut
1;
|