File Coverage

lib/Devel/Trepan/CmdProcessor/Location.pm
Criterion Covered Total %
statement 52 145 35.8
branch 1 70 1.4
condition 1 30 3.3
subroutine 16 25 64.0
pod 0 8 0.0
total 70 278 25.1


line stmt bran cond sub pod time code
1             # Copyright (C) 2011-2015 Rocky Bernstein <rocky@cpan.org>
2 12     12   17627 use strict;
  12         36  
  12         464  
3 12     12   77 use Exporter;
  12         32  
  12         471  
4 12     12   97 use warnings;
  12         33  
  12         331  
5 12     12   67 no warnings 'redefine'; no warnings 'once';
  12     12   28  
  12         418  
  12         123  
  12         29  
  12         311  
6 12     12   71 use rlib '../../..';
  12         27  
  12         73  
7             # require_relative '../app/default'
8              
9             package Devel::Trepan::CmdProcessor;
10              
11             # Because we use Exporter we want to silence:
12             # Use of inherited AUTOLOAD for non-method ... is deprecated
13             sub AUTOLOAD
14             {
15 0     0   0 my $name = our $AUTOLOAD;
16 0         0 $name =~ s/.*:://; # lose package name
17 0         0 my $target = "DynaLoader::$name";
18 0         0 goto &$target;
19             }
20              
21       0     sub DESTROY{}
22              
23 12     12   5361 use English qw( -no_match_vars );
  12         2830  
  12         73  
24 12     12   3029 use Cwd 'abs_path';
  12         31  
  12         534  
25              
26 12     12   77 use File::Basename;
  12         26  
  12         671  
27 12     12   85 use File::Spec;
  12         33  
  12         256  
28 12     12   445 use Devel::Trepan::DB::LineCache;
  12         29  
  12         7642  
29              
30             our $EVENT2ICON = {
31             'brkpt' => 'xx',
32             'call' => '->',
33             'debugger-call' => ':o',
34             'end' => '-|',
35             'interrupt' => 'oo',
36             'line' => '--',
37             'post-mortem' => 'XX',
38             'return' => '<-',
39             'signal' => '!!',
40             'tbrkpt' => 'x1',
41             'terminated' => ':x',
42             'trace' => '==',
43             'unknown' => '?!',
44             'watch' => 'wa'
45             };
46              
47             sub canonic_file($$;$)
48             {
49 0     0 0 0 my ($self, $filename, $resolve) = @_;
50 0 0       0 return undef unless defined $filename;
51 0 0       0 $resolve = 1 unless defined $resolve;
52              
53             # For now we want resolved filenames
54 0 0       0 if ($self->{settings}{basename}) {
    0          
55 0         0 my $is_eval = filename_is_eval($filename);
56 0 0 0     0 return $is_eval ? $filename : (basename($filename) || $filename);
57             } elsif ($resolve) {
58 0         0 my $mapped_filename = map_file($filename);
59 0 0       0 $filename = $mapped_filename if defined($mapped_filename);
60 0         0 my $is_eval = filename_is_eval($filename);
61 0 0 0     0 return $is_eval ? $filename : (abs_path($filename) || $filename);
62             } else {
63 0         0 return $filename;
64             }
65             }
66              
67             sub min($$) {
68 0     0 0 0 my ($a, $b) = @_;
69 0 0       0 return $a < $b ? $a : $b;
70             }
71              
72             # Return the text to the current source line. We use trace line
73             # information to try to retrieve all of the current source line up
74             # to some limit of lines. The lines returned may be colorized.
75             # Devel::Trepan::DB:LineCache::getline actually does the retrieval.
76             sub current_source_text(;$)
77             {
78 1     1 0 12 my ($self, $opts) = @_;
79 1 50       4 $opts = {maxlines => 5} unless defined $opts;
80 1         3 my $filename = $self->{frame}{file};
81 1         3 my $line_number = $self->{frame}{line};
82 1   50     7 my $text = (getline($filename, $line_number, $opts)) || '';
83 1         3 chomp($text);
84 1         4 return $text;
85             }
86              
87             sub resolve_file_with_dir($$)
88             {
89 0     0 0   my ($self, $path_suffix) = @_;
90 0           my @dirs = @$self->{settings}{directory};
91 0           for my $dir (split(/:/, @dirs)) {
92 0 0         if ('$cwd' eq $dir) {
    0          
93 0           $dir = `pwd`;
94             } elsif ('$cdir' eq $dir) {
95 0           $dir = $DB::OS_STARTUP_DIR;
96             }
97 0 0 0       next unless $dir && !-d ($dir);
98 0           my $try_file = File::Spec->catfile($dir, $path_suffix);
99 0 0         return $try_file if -f $try_file;
100             }
101 0           return undef;
102             }
103              
104             sub text_at($;$)
105             {
106 0     0 0   my ($self, $opts) = @_;
107             $opts = {
108             reload_on_change => $self->{settings}{reload},
109             output => $self->{settings}{highlight},
110 0 0         } unless defined $opts;
111              
112 0           my $line_no = $self->line();
113 0           my $text;
114 0           my $filename = $self->filename();
115 0 0         if (filename_is_eval($filename)) {
116 0 0         if ($DB::filename eq $filename) {
117             {
118             # Some lines in @DB::line might not be defined.
119             # So we have to turn off strict here.
120 12     12   102 no warnings;
  12         30  
  12         725  
  0            
121 0           my $string = join("\n", @DB::dbline);
122 12     12   80 use warnings;
  12         38  
  12         6042  
123 0           $filename = map_script($filename, $string);
124 0           $text = getline($filename, $line_no, $opts);
125             }
126             }
127             } else {
128 0           $text = line_at($filename, $line_no, $opts);
129 0           my ($map_file, $map_line) =
130             map_file_line($filename, $line_no);
131             }
132 0           $text;
133             }
134              
135             sub format_location($;$$$)
136             {
137 0     0 0   my ($self, $event, $frame, $frame_index) = @_;
138 0 0         $event = $self->{event} unless defined $event;
139 0 0         $frame = $self->{frame} unless defined $frame;
140 0 0         $frame_index = $self->{frame_index} unless defined $frame_index;
141 0           my $text = undef;
142 0           my $ev = ' ';
143 0 0 0       if (defined($self->{event}) && 0 == $frame_index) {
144 0           $ev = $EVENT2ICON->{$self->{event}};
145             }
146              
147 0           $self->{line_no} = $self->{frame}{line};
148              
149 0           my $loc = $self->source_location_info;
150 0 0 0       my $suffix = ($event eq 'return' && defined($DB::_[0])) ? " $DB::_[0]" : '';
151 0   0       my $pkg = $self->{frame}{pkg} || '??' ;
152 0           "${ev} ${pkg}::(${loc})$suffix";
153             }
154              
155             sub print_location($;$)
156             {
157 0     0 0   my ($self,$opts) = @_;
158             $opts = {
159             output => $self->{settings}{highlight},
160             max_continue => $self->{settings}{lines},
161 0 0         } unless defined $opts;
162 0           my $loc = $self->format_location;
163 0           $self->msg(${loc});
164              
165 0           my $text = $self->current_source_text($opts);
166 0 0         if ($text) {
167 0           $self->msg($text, {unlimited => 1});
168             }
169             }
170              
171             sub source_location_info($)
172             {
173 0     0 0   my $self = shift;
174             # if (@frame.eval?)
175 0           my $canonic_filename;
176             # 'eval ' + safe_repr(@frame.eval_string.gsub("\n", ';').inspect, 20)
177             # else
178 0           my $filename = $self->{frame}{file};
179 0   0       my $line_number = $self->line() || 0;
180              
181 0           my $op_addr_str = '';
182 0           $self->{op_addr} = undef;
183 0 0         if ($self->{settings}{displayop}) {
184 0           my $frame_index = $self->{frame_index};
185 0 0 0       if ($DB::OP_addr && $frame_index == 0) {
186 0           $self->{op_addr} = $DB::OP_addr;
187             } else {
188 0           my $skip = DB::caller_levels_skip();
189 0           my $addr = Devel::Callsite::callsite($frame_index + $skip);
190 0 0 0       $self->{op_addr} = $addr if defined $addr and $addr > 0;
191             }
192             $op_addr_str = sprintf(" \@0x%x", $self->{op_addr}) if $self->{op_addr}
193 0 0         }
194 0 0         if (filename_is_eval($filename)) {
195             ### FIXME: put this all into DB::LineCache
196 0 0         if ($DB::filename eq $filename) {
197             # Some lines in @DB::line might not be defined.
198             # So we have to turn off strict here.
199 0 0         if ($filename ne '-e') {
200 0           my $string = undef;
201 0 0         if (@DB::dbline) {
  0 0          
202 12     12   86 no warnings;
  12         32  
  12         456  
203 0           $string = join('', @DB::dbline);
204 12     12   67 use warnings;
  12         37  
  12         4779  
205             } elsif ($filename =~/^sub (\S+)/) {
206 0           my $func = $1;
207 0 0         if (%SelfLoader::Cache) {
208 0           $string = $SelfLoader::Cache{$func};
209 0           $string =~ s/^\n#line 1.+\n//;
210             }
211             }
212 0 0         unless (defined($string)) {
213 0           return "${filename}:${line_number}$op_addr_str";
214             }
215 0           my $try_filename = map_script($filename, $string);
216 0 0         $filename = $try_filename if defined($try_filename);
217             }
218 0           return $self->filename() .
219             " remapped $filename:$line_number$op_addr_str";
220             }
221             }
222 0   0       $canonic_filename = $self->canonic_file($self->filename(), 0)
223             || $filename;
224 0           return "${canonic_filename}:${line_number}$op_addr_str";
225             }
226              
227             unless (caller()) {
228             # Demo it.
229             require Devel::Trepan::CmdProcessor;
230             my $proc = Devel::Trepan::CmdProcessor->new;
231             eval <<'EOE';
232             sub create_frame() {
233             my ($pkg, $file, $line, $fn) = caller(0);
234             return [
235             {
236             file => $file,
237             fn => $fn,
238             line => $line,
239             pkg => $pkg,
240             }];
241             }
242             EOE
243             my $frame_ary = create_frame();
244             $proc->frame_setup($frame_ary);
245             $proc->{event} = 'return';
246             print $proc->format_location, "\n";
247             print $proc->current_source_text({output=>'plain'}), "\n";
248             print $proc->current_source_text({output=>'term'}), "\n";
249             # See if cached line is the same
250             print $proc->current_source_text({output=>'term'}), "\n";
251             # Try unhighlighted line.
252             print $proc->current_source_text, "\n";
253              
254             # Now try an eval
255             $DB::filename = '';
256             $frame_ary = eval "create_frame()";
257             $proc->frame_setup($frame_ary);
258             $proc->{event} = 'line';
259             print $proc->format_location, "\n";
260             print $proc->current_source_text({output=>'plain'}), "\n";
261             }
262              
263             1;