File Coverage

blib/lib/Devel/GDB/Reflect.pm
Criterion Covered Total %
statement 18 126 14.2
branch 0 50 0.0
condition 0 6 0.0
subroutine 6 16 37.5
pod 2 7 28.5
total 26 205 12.6


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Devel::GDB::Reflect - Reflection API for GDB/C++
4              
5             =head1 SYNOPSIS
6              
7             use Devel::GDB;
8             use Devel::GDB::Reflect;
9              
10             my $gdb = new Devel::GDB( -file => $foo );
11             my $reflector = new Devel::GDB::Reflect( $gdb );
12              
13             print $gdb->get( "b foo.c:123" );
14             $gdb->print( "myVariable" );
15              
16             =head1 DESCRIPTION
17              
18             Devel::GDB::Reflect provides a reflection API for GDB/C++, which can
19             be used to recursively print the contents of STL data structures
20             (C, C, C, etc.) within a GDB session. It is not
21             limited to STL, however; you can write your own delegates for printing
22             custom container types.
23              
24             The module implements the functionality used by the L script, which
25             serves as a wrapper around GDB. You should probably familiarize yourself with
26             the basic functionality of this script first, before diving into the gory
27             details presented here.
28              
29             =head2 Global Variables
30              
31             The following global variables control the behavior of the L method.
32              
33             =over
34              
35             =item $Devel::GDB::Reflect::INDENT
36              
37             The number of spaces to indent at each level of recursion. Defaults to 4.
38              
39             =item $Devel::GDB::Reflect::MAX_DEPTH
40              
41             The maximum recursion depth. Defaults to 5.
42              
43             =item $Devel::GDB::Reflect::MAX_WIDTH
44              
45             The maximum number of elements to show from a given container. Defaults to 10.
46              
47             =back
48              
49             =head2 Methods
50              
51             =cut
52              
53             package Devel::GDB::Reflect;
54              
55 1     1   34684 use warnings;
  1         2  
  1         37  
56 1     1   5 use strict;
  1         1  
  1         35  
57              
58 1     1   714 use Devel::GDB::Reflect::GDBGrammar;
  1         3  
  1         42  
59 1     1   2136 use Devel::GDB::Reflect::PrettyPrinter;
  1         3  
  1         31  
60 1     1   1158 use Data::Dumper;
  1         28636  
  1         647  
61 1     1   1898 use Devel::GDB;
  1         584842  
  1         1974  
62              
63             our $VERSION = '0.2';
64             our $MAX_DEPTH = 5;
65             our $MAX_WIDTH = 10;
66             our $INDENT = 4;
67              
68             sub load_delegates()
69             {
70 0     0 0   my @insts = ();
71              
72 0           my $DELEGATE_NAMESPACE = __PACKAGE__ . "::DelegateProvider";
73 0           (my $DELEGATE_SUBDIR = $DELEGATE_NAMESPACE) =~ s!::!/!g;
74              
75 0           foreach my $root_dir (@INC)
76             {
77 0           my $dir = "$root_dir/$DELEGATE_SUBDIR";
78              
79 0 0         opendir(DIR, $dir) or next;
80 0 0         my @delegate_providers = grep { /\.pm$/ && -f "$dir/$_" } readdir(DIR);
  0            
81 0           closedir(DIR);
82              
83 0           foreach my $file (@delegate_providers)
84             {
85 0 0         die "Something wrong here: \$file = $file"
86             unless $file =~ /^(.+)\.pm$/;
87              
88 0           my $modname = "${DELEGATE_NAMESPACE}::$1";
89              
90 0           require "$dir/$file";
91             my $inst = eval "new $modname"
92 0 0         or do { warn "Can't instantiate $modname; skipping"; next };
  0            
  0            
93              
94 0           print STDERR " => $modname\n";
95              
96 0           push @insts, $inst;
97             }
98             }
99              
100 0           return \@insts;
101             }
102              
103             =head3 new
104              
105             Create a new Devel::GDB::Reflect instance. Takes a single parameter, an
106             instance of C.
107              
108             When the constructor is invoked, it searches C<@INC> for modules named
109             C, and recruits them as delegates. See
110             L.
111              
112             =cut
113              
114             sub new($$)
115             {
116 0     0 1   my $class = shift;
117 0           my ($gdb) = @_;
118              
119 0           return bless
120             {
121             parser => new Devel::GDB::Reflect::GDBGrammar(),
122             gdb => $gdb,
123             class_cache => {},
124             delegate_cache => {},
125             delegate_providers => load_delegates(),
126             };
127             }
128              
129             =head3 print
130              
131             C<< $reflector->print( "myVar" ); >>
132              
133             Given a variable or expression, recursively print the contents of the referenced
134             container. Specifically, this checks the type of the variable, iterates over
135             the L to determine the best one, then uses that delegate
136             to print out the contents of the container.
137              
138             The recursion is limited by C<$MAX_DEPTH>, and for each container, the number of
139             elements is limited by C<$MAX_WIDTH>.
140              
141             =cut
142              
143             sub print($$)
144             {
145 0     0 1   my $self = shift;
146 0           my ($var) = @_;
147              
148 0           $Devel::GDB::Reflect::PrettyPrinter::PAD = " " x $INDENT;
149 0           $self->_print_rec(0, new Devel::GDB::Reflect::PrettyPrinter(), $var);
150 0           print "\n";
151             }
152              
153             sub get_completions($$)
154             {
155 0     0 0   my $self = shift;
156 0           my ($line) = @_;
157              
158 0           my ($result, $error) = $self->{gdb}->get("complete $line");
159 0 0         die "Fatal Error: $error" if $error;
160              
161 0           return split "\n", $result;
162             }
163              
164             sub get_member($$$);
165             sub get_member($$$)
166             {
167 0     0 0   my $self = shift;
168 0           my ($type, $query) = @_;
169              
170 0 0         if(ref $type ne 'HASH')
171             {
172             # Someone passed in a variable, not a type
173 0           $type = $self->get_type($type);
174             }
175              
176 0           my $class_spec = $self->_get_class($type->{quotename});
177 0 0         return undef unless $class_spec->{members};
178              
179 0           foreach my $member (@{$class_spec->{members}})
  0            
180             {
181 0           foreach my $t ('variable', 'function')
182             {
183 0 0 0       return $member if (defined $member->{$t} and $member->{$t} eq $query);
184             }
185             }
186              
187 0 0         if(defined($class_spec->{parent}))
188             {
189 0           return $self->get_member($class_spec->{parent}, $query);
190             }
191              
192 0           return undef;
193             }
194              
195             sub eval($$)
196             {
197 0     0 0   my $self = shift;
198 0           my ($expr) = @_;
199              
200 0           my ($result, $error) = $self->{gdb}->get("output $expr");
201 0 0         die "Fatal Error: $error" if $error;
202              
203             # We're going to assume that it succeeded if $result either starts with an
204             # open brace (it's a struct or class of some sort), OR it's is not
205             # terminated with a newline (which is how error messages are shown).
206 0 0         return undef if($result =~ /^[^{].*\n/); return $result; }
  0            
207              
208             sub _print_rec($$$;$)
209             {
210 0     0     my $self = shift;
211 0           my ($depth, $pp, $var, $type) = @_;
212              
213 0           my $pp_fh = $pp->{fh};
214              
215             #
216             # Control for excessive recursion
217             #
218 0 0         if($depth >= $MAX_DEPTH)
219             {
220 0           print $pp_fh "{ ... }";
221 0           return;
222             }
223              
224             #
225             # Get the type of $var, unless we're told what it is
226             #
227              
228 0 0         unless(defined $type)
229             {
230 0 0         $type = $self->get_type($var) or return;
231             }
232              
233             #
234             # Find candidate delegates for this type, unless we already have one cached
235             #
236              
237 0 0         unless(defined $self->{delegate_cache}->{$type->{quotename}})
238             {
239 0           my @delegates = ();
240              
241 0           foreach my $inst (@{$self->{delegate_providers}})
  0            
242             {
243 0           push @delegates, $inst->get_delegates($type, $var, $self);
244             }
245              
246 0 0         if(!@delegates)
247             {
248 0           print $pp_fh "[No delegate found!]";
249 0           return;
250             }
251              
252             #
253             # Take the highest-priority one
254             #
255              
256 0           my $delegate = (sort { $b->{priority} <=> $a->{priority} } @delegates)[0];
  0            
257 0           $self->{delegate_cache}->{$type->{quotename}} = $delegate;
258             }
259              
260 0 0         my $delegate = $self->{delegate_cache}->{$type->{quotename}}
261             or die "Something wrong here";
262              
263             #
264             # Now use $delegate to either dump the object as-is, or iterate
265             #
266              
267 0           my $pp_child = new Devel::GDB::Reflect::PrettyPrinter( $pp,
268             $delegate->{print_open_brace},
269             $delegate->{print_separator},
270             $delegate->{print_close_brace} );
271              
272 0     0     my $callback = sub { $self->_print_rec($depth+1, $pp_child, @_) };
  0            
273 0           my $printer = $delegate->{factory}->($var);
274              
275 0 0         if($delegate->{can_iterate})
276             {
277 0   0       for(my $i=0 ; $i<$MAX_WIDTH && $printer->has_next() ; $i++)
278             {
279 0           $printer->print_next($callback, $pp_child->{fh});
280             }
281              
282 0           my $pp_child_fh = $pp_child->{fh};
283 0 0         print $pp_child_fh "..." if($printer->has_next());
284             }
285             else
286             {
287 0           $printer->print($callback, $pp_child->{fh});
288             }
289              
290 0           $pp_child->finish($delegate->{print_newline});
291             }
292              
293             sub _get_class($$)
294             {
295 0     0     my $self = shift;
296 0           my ($typename) = @_;
297              
298 0 0         unless(defined $self->{class_cache}->{$typename})
299             {
300 0           my ($result, $error) = $self->{gdb}->get("ptype $typename");
301 0 0         die "Fatal Error: $error" if $error;
302              
303 0           my $class_spec = $self->{parser}->parse($result);
304 0 0         unless(defined $class_spec)
305             {
306 0           $DB::single = 2;
307 0           print STDERR "Failed parsing type '$typename'!\n";
308 0           return undef;
309             }
310              
311 0           $self->{class_cache}->{$typename} = $class_spec;
312             }
313              
314 0           return $self->{class_cache}->{$typename};
315             }
316              
317             ##
318             ## It would be better to use "whatis" here, rather than "ptype", but GDB
319             ## is stupid. There, I said it. :-)
320             ##
321             ## If $var is of type std::string, "whatis $var" gives "type = string",
322             ## while "ptype $var" gives the full type specification.
323             ##
324             sub get_type($$)
325             {
326 0     0 0   my $self = shift;
327 0           my ($var) = @_;
328              
329 0           my ($result, $error) = $self->{gdb}->get("ptype $var");
330 0 0         die "Fatal Error: $error" if $error;
331              
332 0 0         if($result !~ /^type =/)
333             {
334 0           print STDERR $result;
335 0           return undef;
336             }
337              
338             # Strip off the class definition, if any. This is ugly, but it avoids
339             # expensively parsing the entire class...
340 0           $result =~ s/ : .*//s;
341 0           $result =~ s/{.*//s;
342              
343 0           my $type = $self->{parser}->parse($result);
344              
345 0 0         unless(defined $type)
346             {
347 0           print STDERR "Failed parsing type!\n Result was: $result\n";
348 0           return undef;
349             }
350              
351 0           return $type;
352             }
353              
354             1;
355              
356             =head2 Delegates
357              
358             Although this module is designed primarily for printing the contents of STL
359             containers, it is fully extensible to support custom data types. The
360             L method works by iterating over a set of I to determine
361             how to print out a given variable.
362              
363             A I is a hash consisting of:
364              
365             =over
366              
367             =item priority
368              
369             A numeric value used to disambiguate which delegate to use when there is more
370             than one to choose from. For example, the fallback delegate
371             (C) can print any data type, but has
372             very low priority (-1000) to prevent it from being invoked unless no other
373             delegate is available.
374              
375             =item can_iterate
376              
377             A boolean value, B<1> if the delegate is used to print a container that should
378             be iterated (such as a vector), or B<0> if it is used to print a single value
379             (such as a string). If C is true, then the delegate's factory must
380             provide C and C; otherwise, it must provide C.
381              
382             =item print_open_brace, print_close_brace
383              
384             The string to print before and after the contents of the variable; defaults to
385             C<"["> and C<"]"> respectively.
386              
387             =item print_separator
388              
389             The string to print between elements within the variable; defaults to C<",">.
390             Only makes sense with C is true.
391              
392             =item print_newline
393              
394             A boolean indicating whether or not to print a newline after printing the
395             contents of the container. Typically this should be B<1> (true) except for
396             simple types.
397              
398             =item factory
399              
400             A C taking a single parameter, C<$var> (a C++ expression) and returning an
401             object. This object is expected to contain either C (if C
402             is false) or C and C:
403              
404             =over
405              
406             =item print
407              
408             Takes two parameters: C<$callback> and C<$fh>. Either prints the contents of
409             C<$var> directly to the file handle C<$fh>, or invokes C<$callback> to print
410             C<$var> recursively.
411              
412             =item has_next
413              
414             Like Java's C, this function is called to determine whether or
415             not there are any items remaining to print out.
416              
417             =item print_next
418              
419             Prints out the current element and advances the iterator (similarly again to
420             Java's C).
421              
422             Like C, this function takes two parameters, C<$callback> and C<$fh>,
423             and either prints directly to C<$fh> or invokes C<$callback> recursively.
424              
425             =back
426              
427             =back
428              
429             =head3 Delegate Providers
430              
431             A I is an object containing a method called C.
432             This module searches for delegate providers by looking in C<@INC> for modules by
433             the name of C.
434              
435             The C method takes three parameters C<($type, $var, $reflector)>:
436             a I, a C++ expression, and an instance of C. The
437             C<$type> is a hash, containing:
438              
439             =over
440              
441             =item *
442              
443             C: the full name of the type, including its namespace and template
444             specialization, e.g. C<<< class std::vector > * >>>.
445             This type should B be passed to GDB; use C instead.
446              
447             =item *
448              
449             C: the type name without the template or namespace, e.g. C.
450              
451             =item *
452              
453             C: the full name, properly quoted to pass to GDB, e.g.
454             C<<< class 'std::vector >' * >>>.
455              
456             =item *
457              
458             C