Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

443 lines
12 KiB

  1. require 5.002; # For (defined ref)
  2. package dumpvar;
  3. # Needed for PrettyPrinter only:
  4. # require 5.001; # Well, it coredumps anyway undef DB in 5.000 (not now)
  5. # translate control chars to ^X - Randal Schwartz
  6. # Modifications to print types by Peter Gordon v1.0
  7. # Ilya Zakharevich -- patches after 5.001 (and some before ;-)
  8. # Won't dump symbol tables and contents of debugged files by default
  9. $winsize = 80 unless defined $winsize;
  10. # Defaults
  11. # $globPrint = 1;
  12. $printUndef = 1 unless defined $printUndef;
  13. $tick = "auto" unless defined $tick;
  14. $unctrl = 'quote' unless defined $unctrl;
  15. $subdump = 1;
  16. $dumpReused = 0 unless defined $dumpReused;
  17. $bareStringify = 1 unless defined $bareStringify;
  18. sub main::dumpValue {
  19. local %address;
  20. local $^W=0;
  21. (print "undef\n"), return unless defined $_[0];
  22. (print &stringify($_[0]), "\n"), return unless ref $_[0];
  23. dumpvar::unwrap($_[0],0);
  24. }
  25. # This one is good for variable names:
  26. sub unctrl {
  27. local($_) = @_;
  28. local($v) ;
  29. return \$_ if ref \$_ eq "GLOB";
  30. s/([\001-\037\177])/'^'.pack('c',ord($1)^64)/eg;
  31. $_;
  32. }
  33. sub stringify {
  34. local($_,$noticks) = @_;
  35. local($v) ;
  36. my $tick = $tick;
  37. return 'undef' unless defined $_ or not $printUndef;
  38. return $_ . "" if ref \$_ eq 'GLOB';
  39. $_ = &{'overload::StrVal'}($_)
  40. if $bareStringify and ref $_
  41. and %overload:: and defined &{'overload::StrVal'};
  42. if ($tick eq 'auto') {
  43. if (/[\000-\011\013-\037\177]/) {
  44. $tick = '"';
  45. }else {
  46. $tick = "'";
  47. }
  48. }
  49. if ($tick eq "'") {
  50. s/([\'\\])/\\$1/g;
  51. } elsif ($unctrl eq 'unctrl') {
  52. s/([\"\\])/\\$1/g ;
  53. s/([\000-\037\177])/'^'.pack('c',ord($1)^64)/eg;
  54. s/([\200-\377])/'\\0x'.sprintf('%2X',ord($1))/eg
  55. if $quoteHighBit;
  56. } elsif ($unctrl eq 'quote') {
  57. s/([\"\\\$\@])/\\$1/g if $tick eq '"';
  58. s/\033/\\e/g;
  59. s/([\000-\037\177])/'\\c'.chr(ord($1)^64)/eg;
  60. }
  61. s/([\200-\377])/'\\'.sprintf('%3o',ord($1))/eg if $quoteHighBit;
  62. ($noticks || /^\d+(\.\d*)?\Z/)
  63. ? $_
  64. : $tick . $_ . $tick;
  65. }
  66. sub ShortArray {
  67. my $tArrayDepth = $#{$_[0]} ;
  68. $tArrayDepth = $#{$_[0]} < $arrayDepth-1 ? $#{$_[0]} : $arrayDepth-1
  69. unless $arrayDepth eq '' ;
  70. my $shortmore = "";
  71. $shortmore = " ..." if $tArrayDepth < $#{$_[0]} ;
  72. if (!grep(ref $_, @{$_[0]})) {
  73. $short = "0..$#{$_[0]} '" .
  74. join("' '", @{$_[0]}[0..$tArrayDepth]) . "'$shortmore";
  75. return $short if length $short <= $compactDump;
  76. }
  77. undef;
  78. }
  79. sub DumpElem {
  80. my $short = &stringify($_[0], ref $_[0]);
  81. if ($veryCompact && ref $_[0]
  82. && (ref $_[0] eq 'ARRAY' and !grep(ref $_, @{$_[0]}) )) {
  83. my $end = "0..$#{$v} '" .
  84. join("' '", @{$_[0]}[0..$tArrayDepth]) . "'$shortmore";
  85. } elsif ($veryCompact && ref $_[0]
  86. && (ref $_[0] eq 'HASH') and !grep(ref $_, values %{$_[0]})) {
  87. my $end = 1;
  88. $short = $sp . "0..$#{$v} '" .
  89. join("' '", @{$v}[0..$tArrayDepth]) . "'$shortmore";
  90. } else {
  91. print "$short\n";
  92. unwrap($_[0],$_[1]);
  93. }
  94. }
  95. sub unwrap {
  96. return if $DB::signal;
  97. local($v) = shift ;
  98. local($s) = shift ; # extra no of spaces
  99. local(%v,@v,$sp,$value,$key,@sortKeys,$more,$shortmore,$short) ;
  100. local($tHashDepth,$tArrayDepth) ;
  101. $sp = " " x $s ;
  102. $s += 3 ;
  103. # Check for reused addresses
  104. if (ref $v) {
  105. my $val = $v;
  106. $val = &{'overload::StrVal'}($v)
  107. if %overload:: and defined &{'overload::StrVal'};
  108. ($address) = $val =~ /(0x[0-9a-f]+)\)$/ ;
  109. if (!$dumpReused && defined $address) {
  110. $address{$address}++ ;
  111. if ( $address{$address} > 1 ) {
  112. print "${sp}-> REUSED_ADDRESS\n" ;
  113. return ;
  114. }
  115. }
  116. } elsif (ref \$v eq 'GLOB') {
  117. $address = "$v" . ""; # To avoid a bug with globs
  118. $address{$address}++ ;
  119. if ( $address{$address} > 1 ) {
  120. print "${sp}*DUMPED_GLOB*\n" ;
  121. return ;
  122. }
  123. }
  124. if (ref $v eq 'Regexp') {
  125. my $re = "$v";
  126. $re =~ s,/,\\/,g;
  127. print "$sp-> qr/$re/\n";
  128. return;
  129. }
  130. if ( UNIVERSAL::isa($v, 'HASH') ) {
  131. @sortKeys = sort keys(%$v) ;
  132. undef $more ;
  133. $tHashDepth = $#sortKeys ;
  134. $tHashDepth = $#sortKeys < $hashDepth-1 ? $#sortKeys : $hashDepth-1
  135. unless $hashDepth eq '' ;
  136. $more = "....\n" if $tHashDepth < $#sortKeys ;
  137. $shortmore = "";
  138. $shortmore = ", ..." if $tHashDepth < $#sortKeys ;
  139. $#sortKeys = $tHashDepth ;
  140. if ($compactDump && !grep(ref $_, values %{$v})) {
  141. #$short = $sp .
  142. # (join ', ',
  143. # Next row core dumps during require from DB on 5.000, even with map {"_"}
  144. # map {&stringify($_) . " => " . &stringify($v->{$_})}
  145. # @sortKeys) . "'$shortmore";
  146. $short = $sp;
  147. my @keys;
  148. for (@sortKeys) {
  149. push @keys, &stringify($_) . " => " . &stringify($v->{$_});
  150. }
  151. $short .= join ', ', @keys;
  152. $short .= $shortmore;
  153. (print "$short\n"), return if length $short <= $compactDump;
  154. }
  155. for $key (@sortKeys) {
  156. return if $DB::signal;
  157. $value = $ {$v}{$key} ;
  158. print "$sp", &stringify($key), " => ";
  159. DumpElem $value, $s;
  160. }
  161. print "$sp empty hash\n" unless @sortKeys;
  162. print "$sp$more" if defined $more ;
  163. } elsif ( UNIVERSAL::isa($v, 'ARRAY') ) {
  164. $tArrayDepth = $#{$v} ;
  165. undef $more ;
  166. $tArrayDepth = $#{$v} < $arrayDepth-1 ? $#{$v} : $arrayDepth-1
  167. unless $arrayDepth eq '' ;
  168. $more = "....\n" if $tArrayDepth < $#{$v} ;
  169. $shortmore = "";
  170. $shortmore = " ..." if $tArrayDepth < $#{$v} ;
  171. if ($compactDump && !grep(ref $_, @{$v})) {
  172. if ($#$v >= 0) {
  173. $short = $sp . "0..$#{$v} " .
  174. join(" ",
  175. map {exists $v->[$_] ? stringify $v->[$_] : "empty"} ($[..$tArrayDepth)
  176. ) . "$shortmore";
  177. } else {
  178. $short = $sp . "empty array";
  179. }
  180. (print "$short\n"), return if length $short <= $compactDump;
  181. }
  182. #if ($compactDump && $short = ShortArray($v)) {
  183. # print "$short\n";
  184. # return;
  185. #}
  186. for $num ($[ .. $tArrayDepth) {
  187. return if $DB::signal;
  188. print "$sp$num ";
  189. if (exists $v->[$num]) {
  190. DumpElem $v->[$num], $s;
  191. } else {
  192. print "empty slot\n";
  193. }
  194. }
  195. print "$sp empty array\n" unless @$v;
  196. print "$sp$more" if defined $more ;
  197. } elsif ( UNIVERSAL::isa($v, 'SCALAR') or ref $v eq 'REF' ) {
  198. print "$sp-> ";
  199. DumpElem $$v, $s;
  200. } elsif ( UNIVERSAL::isa($v, 'CODE') ) {
  201. print "$sp-> ";
  202. dumpsub (0, $v);
  203. } elsif ( UNIVERSAL::isa($v, 'GLOB') ) {
  204. print "$sp-> ",&stringify($$v,1),"\n";
  205. if ($globPrint) {
  206. $s += 3;
  207. dumpglob($s, "{$$v}", $$v, 1);
  208. } elsif (defined ($fileno = fileno($v))) {
  209. print( (' ' x ($s+3)) . "FileHandle({$$v}) => fileno($fileno)\n" );
  210. }
  211. } elsif (ref \$v eq 'GLOB') {
  212. if ($globPrint) {
  213. dumpglob($s, "{$v}", $v, 1) if $globPrint;
  214. } elsif (defined ($fileno = fileno(\$v))) {
  215. print( (' ' x $s) . "FileHandle({$v}) => fileno($fileno)\n" );
  216. }
  217. }
  218. }
  219. sub matchvar {
  220. $_[0] eq $_[1] or
  221. ($_[1] =~ /^([!~])(.)([\x00-\xff]*)/) and
  222. ($1 eq '!') ^ (eval {($_[2] . "::" . $_[0]) =~ /$2$3/});
  223. }
  224. sub compactDump {
  225. $compactDump = shift if @_;
  226. $compactDump = 6*80-1 if $compactDump and $compactDump < 2;
  227. $compactDump;
  228. }
  229. sub veryCompact {
  230. $veryCompact = shift if @_;
  231. compactDump(1) if !$compactDump and $veryCompact;
  232. $veryCompact;
  233. }
  234. sub unctrlSet {
  235. if (@_) {
  236. my $in = shift;
  237. if ($in eq 'unctrl' or $in eq 'quote') {
  238. $unctrl = $in;
  239. } else {
  240. print "Unknown value for `unctrl'.\n";
  241. }
  242. }
  243. $unctrl;
  244. }
  245. sub quote {
  246. if (@_ and $_[0] eq '"') {
  247. $tick = '"';
  248. $unctrl = 'quote';
  249. } elsif (@_ and $_[0] eq 'auto') {
  250. $tick = 'auto';
  251. $unctrl = 'quote';
  252. } elsif (@_) { # Need to set
  253. $tick = "'";
  254. $unctrl = 'unctrl';
  255. }
  256. $tick;
  257. }
  258. sub dumpglob {
  259. return if $DB::signal;
  260. my ($off,$key, $val, $all) = @_;
  261. local(*entry) = $val;
  262. my $fileno;
  263. if (($key !~ /^_</ or $dumpDBFiles) and defined $entry) {
  264. print( (' ' x $off) . "\$", &unctrl($key), " = " );
  265. DumpElem $entry, 3+$off;
  266. }
  267. if (($key !~ /^_</ or $dumpDBFiles) and @entry) {
  268. print( (' ' x $off) . "\@$key = (\n" );
  269. unwrap(\@entry,3+$off) ;
  270. print( (' ' x $off) . ")\n" );
  271. }
  272. if ($key ne "main::" && $key ne "DB::" && %entry
  273. && ($dumpPackages or $key !~ /::$/)
  274. && ($key !~ /^_</ or $dumpDBFiles)
  275. && !($package eq "dumpvar" and $key eq "stab")) {
  276. print( (' ' x $off) . "\%$key = (\n" );
  277. unwrap(\%entry,3+$off) ;
  278. print( (' ' x $off) . ")\n" );
  279. }
  280. if (defined ($fileno = fileno(*entry))) {
  281. print( (' ' x $off) . "FileHandle($key) => fileno($fileno)\n" );
  282. }
  283. if ($all) {
  284. if (defined &entry) {
  285. dumpsub($off, $key);
  286. }
  287. }
  288. }
  289. sub CvGV_name_or_bust {
  290. my $in = shift;
  291. return if $skipCvGV; # Backdoor to avoid problems if XS broken...
  292. $in = \&$in; # Hard reference...
  293. eval {require Devel::Peek; 1} or return;
  294. my $gv = Devel::Peek::CvGV($in) or return;
  295. *$gv{PACKAGE} . '::' . *$gv{NAME};
  296. }
  297. sub dumpsub {
  298. my ($off,$sub) = @_;
  299. my $ini = $sub;
  300. my $s;
  301. $sub = $1 if $sub =~ /^\{\*(.*)\}$/;
  302. my $subref = defined $1 ? \&$sub : \&$ini;
  303. my $place = $DB::sub{$sub} || (($s = $subs{"$subref"}) && $DB::sub{$s})
  304. || (($s = CvGV_name_or_bust($subref)) && $DB::sub{$s})
  305. || ($subdump && ($s = findsubs("$subref")) && $DB::sub{$s});
  306. $place = '???' unless defined $place;
  307. $s = $sub unless defined $s;
  308. print( (' ' x $off) . "&$s in $place\n" );
  309. }
  310. sub findsubs {
  311. return undef unless %DB::sub;
  312. my ($addr, $name, $loc);
  313. while (($name, $loc) = each %DB::sub) {
  314. $addr = \&$name;
  315. $subs{"$addr"} = $name;
  316. }
  317. $subdump = 0;
  318. $subs{ shift() };
  319. }
  320. sub main::dumpvar {
  321. my ($package,@vars) = @_;
  322. local(%address,$key,$val,$^W);
  323. $package .= "::" unless $package =~ /::$/;
  324. *stab = *{"main::"};
  325. while ($package =~ /(\w+?::)/g){
  326. *stab = $ {stab}{$1};
  327. }
  328. local $TotalStrings = 0;
  329. local $Strings = 0;
  330. local $CompleteTotal = 0;
  331. while (($key,$val) = each(%stab)) {
  332. return if $DB::signal;
  333. next if @vars && !grep( matchvar($key, $_), @vars );
  334. if ($usageOnly) {
  335. globUsage(\$val, $key)
  336. if ($package ne 'dumpvar' or $key ne 'stab')
  337. and ref(\$val) eq 'GLOB';
  338. } else {
  339. dumpglob(0,$key, $val);
  340. }
  341. }
  342. if ($usageOnly) {
  343. print "String space: $TotalStrings bytes in $Strings strings.\n";
  344. $CompleteTotal += $TotalStrings;
  345. print "Grand total = $CompleteTotal bytes (1 level deep) + overhead.\n";
  346. }
  347. }
  348. sub scalarUsage {
  349. my $size = length($_[0]);
  350. $TotalStrings += $size;
  351. $Strings++;
  352. $size;
  353. }
  354. sub arrayUsage { # array ref, name
  355. my $size = 0;
  356. map {$size += scalarUsage($_)} @{$_[0]};
  357. my $len = @{$_[0]};
  358. print "\@$_[1] = $len item", ($len > 1 ? "s" : ""),
  359. " (data: $size bytes)\n"
  360. if defined $_[1];
  361. $CompleteTotal += $size;
  362. $size;
  363. }
  364. sub hashUsage { # hash ref, name
  365. my @keys = keys %{$_[0]};
  366. my @values = values %{$_[0]};
  367. my $keys = arrayUsage \@keys;
  368. my $values = arrayUsage \@values;
  369. my $len = @keys;
  370. my $total = $keys + $values;
  371. print "\%$_[1] = $len item", ($len > 1 ? "s" : ""),
  372. " (keys: $keys; values: $values; total: $total bytes)\n"
  373. if defined $_[1];
  374. $total;
  375. }
  376. sub globUsage { # glob ref, name
  377. local *name = *{$_[0]};
  378. $total = 0;
  379. $total += scalarUsage $name if defined $name;
  380. $total += arrayUsage \@name, $_[1] if @name;
  381. $total += hashUsage \%name, $_[1] if %name and $_[1] ne "main::"
  382. and $_[1] ne "DB::"; #and !($package eq "dumpvar" and $key eq "stab"));
  383. $total;
  384. }
  385. sub packageUsage {
  386. my ($package,@vars) = @_;
  387. $package .= "::" unless $package =~ /::$/;
  388. local *stab = *{"main::"};
  389. while ($package =~ /(\w+?::)/g){
  390. *stab = $ {stab}{$1};
  391. }
  392. local $TotalStrings = 0;
  393. local $CompleteTotal = 0;
  394. my ($key,$val);
  395. while (($key,$val) = each(%stab)) {
  396. next if @vars && !grep($key eq $_,@vars);
  397. globUsage \$val, $key unless $package eq 'dumpvar' and $key eq 'stab';
  398. }
  399. print "String space: $TotalStrings.\n";
  400. $CompleteTotal += $TotalStrings;
  401. print "\nGrand total = $CompleteTotal bytes\n";
  402. }
  403. 1;