ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-GDB/GDB.pm
Revision: 1.1
Committed: Sun Dec 23 03:25:39 2012 UTC (11 years, 5 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     AnyEvent::GDB - asynchronous GDB machine interface interface
4    
5     =head1 SYNOPSIS
6    
7     use AnyEvent::GDB;
8    
9     =head1 DESCRIPTION
10    
11     This module is an L<AnyEvent> user, you need to make sure that you use and
12     run a supported event loop.
13    
14     =cut
15    
16     package AnyEvent::GDB;
17    
18     use common::sense;
19    
20     use Fcntl ();
21     use Scalar::Util ();
22    
23     use AnyEvent ();
24     use AnyEvent::Util ();
25    
26     our $VERSION = '0.0';
27    
28     =head2 METHODS
29    
30     =over 4
31    
32     =item $gdb = new AnyEvent::GDB
33    
34     =over 4
35    
36     =item exec => $path (default: "gdb")
37    
38     The path of the GDB executable.
39    
40     =item args => [$string...] (default: ["-n"])
41    
42     An optional array of parameters to pass to GDB. This should not be
43     used to load a program executable, use the C<file_exec_and_symbols>,
44     C<target_attach> or similar MI commands instead.
45    
46     =item on_error => $callback->($dbh, $filename, $line, $fatal)#d#
47    
48     =back
49    
50     =cut
51    
52     sub new {
53     my ($class, %arg) = @_;
54    
55     my $self = bless {
56     %arg,
57     }, $class;
58    
59     my $exe = delete $self->{exec} // "gdb";
60     my $arg = delete $self->{args} // [qw(-n)];
61    
62     ($self->{fh}, my $fh2) = AnyEvent::Util::portable_socketpair;
63    
64     $self->{pid} = fork;
65    
66     open my $stdin , "<&STDIN" ;
67     open my $stdout, ">&STDOUT";
68    
69     unless ($self->{pid}) {
70     if (defined $self->{pid}) {
71     open STDIN , "<&", $fh2;
72     open STDOUT, ">&", $fh2;
73     fcntl $stdin , Fcntl::F_SETFD, 0;
74     fcntl $stdout, Fcntl::F_SETFD, 0;
75     exec $exe, qw(--interpreter=mi2 -q), @$arg;
76     kill 9, 0; # don't want to load the POSIX module just for this
77     } else {
78     $self->fatal ("cannot fork: $!");
79     }
80     }
81    
82     AnyEvent::Util::fh_nonblocking $self->{fh}, 1;
83    
84     {
85     Scalar::Util::weaken (my $self = $self);
86     $self->{rw} = AE::io $self->{fh}, 0, sub {
87     my $len = sysread $self->{fh}, $self->{rbuf}, 256, length $self->{rbuf};
88    
89     defined $len || $self->fatal ("unexpected EOF from GDB");
90    
91     $self->feed ("$1")
92     while $self->{rbuf} =~ s/^([^\r\n]*)\r?\n//;
93     };
94    
95     $self->{wcb} = sub {
96     my $len = syswrite $self->{fh}, $self->{wbuf};
97     substr $self->{wbuf}, 0, $len, "";
98     delete $self->{ww} unless length $self->{wbuf};
99     };
100     }
101    
102     $self->cmd_raw ((sprintf "run <&%d >&%d", fileno $stdin, fileno $stdout), sub { });
103    
104     $self
105     }
106    
107     #sub DESTROY {
108     #)}
109    
110     sub send {
111     my ($self, $data) = @_;
112    
113     print "s<$data>\n";#d#
114    
115     $self->{wbuf} .= $data;
116     $self->{ww} ||= AE::io $self->{fh}, 1, $self->{wcb};
117     }
118    
119     our %C_ESCAPE = (
120     "\\" => "\\",
121     '"' => '"',
122     "'" => "'",
123     "?" => "?",
124    
125     a => "\x07",
126     b => "\x08",
127     t => "\x09",
128     n => "\x0a",
129     v => "\x0b",
130     f => "\x0c",
131     r => "\x0d",
132     );
133    
134     sub _parse_c_string {
135     my $r = "";
136    
137     # syntax is not documented, so we do full C99, except unicode
138    
139     while () {
140     if (/\G([^"\\\n]+)/gc) {
141     $r .= $1;
142     } elsif (/\G\\([abtnvfr\\"'?])/gc) {
143     $r .= $C_ESCAPE{$1};
144     } elsif (/\G\\([0-8]{1,3})/gc) {
145     $r .= chr oct $1;
146     } elsif (/\G\\x([0-9a-fA-F]+)/gc) {
147     $r .= chr hex $1;
148     } elsif (/\G"/gc) {
149     last;
150     } else {
151     die "invalid string syntax\n";
152     }
153     }
154    
155     $r
156     }
157    
158     sub _parse_value {
159     if (/\G"/gc) { # c-string
160     &_parse_c_string
161    
162     } elsif (/\G\{/gc) { # tuple
163     my $r = &_parse_results;
164    
165     /\G\}/gc
166     or die "tuple does not end with '}'\n";
167    
168     $r
169    
170     } elsif (/\G\[/gc) { # list
171     my @r;
172    
173     until (/\G\]/gc) {
174     # if GDB outputs "result" in lists, let me know and uncomment the following lines
175     # # list might also contain key value pairs, but apparently
176     # # those are supposed to be ordered, so we use an array in perl.
177     # push @r, $1
178     # if /\G([^=,\[\]\{\}]+)=/gc;
179    
180     push @r, &_parse_value;
181    
182     /\G,/gc
183     or last;
184     }
185    
186     /\G\]/gc
187     or die "list does not end with ']'\n";
188    
189     \@r
190    
191     } else {
192     die "value expected\n";
193     }
194     }
195    
196     sub _parse_results {
197     my %r;
198    
199     # syntax for string is undocumented
200     while (/\G([^=,\[\]\{\}]+)=/gc) {
201     my $k = $1;
202    
203     $r{$k} = &_parse_value;
204    
205     /\G,/gc
206     or last;
207     }
208    
209     \%r
210     }
211    
212     my %type_map = qw(
213     * exec_async
214     + status_async
215     = notify_async
216     );
217    
218     sub feed {
219     my ($self, $line) = @_;
220     use Data::Dump; #d#
221    
222     warn "parse<$line>\n";#d#
223    
224     for ($line) {
225     if (/^\(gdb\)\s*$/gc) { # docs say "(gdb)", but reality says "(gdb) "
226     # nop
227     } else {
228     /^([0-9]*)/gc; # [token], actually ([0-9]+)?
229     my $token = $1;
230    
231     eval {
232     if (/\G\^(done|running|connected|error|exit)/gc) { # result
233     my $class = $1 eq "running" ? "done" : $1;
234     # documented for error is an incompatible format, but in reality it is sane
235    
236     my $results = /\G,/gc ? &_parse_results : {};
237    
238     if (my $cb = delete $self->{cb}{$token}) {
239     # unfortunately, gdb sometimes outputs multiple result records for one command
240     $cb->($class, $results, delete $self->{console_stream});
241     }
242    
243     } elsif (/\G([*+=])([^,]+)/gc) { # *exec-async, +status-async, =notify-async
244     my ($type, $class) = ($type_map{$1}, $2);
245    
246     my $results = /\G,/gc ? &_parse_results : {};
247    
248     $self->event ($type => $results);
249    
250     } elsif (/\G~"/gc) {
251     push @{ $self->{console_stream} }, &_parse_c_string;
252     } elsif (/\G&"/gc) {
253     $self->event (log_stream => &_parse_c_string);
254     } elsif (/\G\@"/gc) {
255     $self->event (target_stream => &_parse_c_string);
256     }
257     };
258    
259     /\G(.{0,16})/gcs;
260     $@ = "extra data\n" if !$@ and length $1;
261    
262     if ($@) {
263     chop $@;
264     die "parse error: $@, at ...$1\n";
265     }
266     }
267     }
268     }
269    
270     sub _q($) {
271     return $_[0]
272     if $_[0] =~ /^[A-Za-z0-9_]+$/; # we are a lot more strict than the spec
273    
274     local $_ = shift;
275     utf8::encode $_; # just in case
276     s/([^\x20-\x21\x23-\x5b\x5d-\x7e])/sprintf "\\x%02x", ord $1/ge;
277     "\"$_\""
278     }
279    
280     =item $gdb->cmd_raw ($command, $cb->($class, $results, $console))
281    
282     Execute a raw command: C<$command> is sent unchanged to GDB. See C<cmd_>
283     for a description of the callback arguments.
284    
285     Example: execute a CLI command and print its output.
286    
287     $gdb->cmd_raw ("info sh", sub {
288     print "$_[3]\n";
289     });
290    
291     =cut
292    
293     sub cmd_raw {
294     my ($self, $cmd, $cb) = @_;
295    
296     my $token = ++$self->{token};
297     $self->send ("$token$cmd\n");
298     $self->{cb}{$token} = $cb;
299     }
300    
301     =item $gdb->cmd ($command => [$option...], $parameter..., $cb->($class, $results, $console))
302    
303     Execute a MI command and invoke the callback with the results.
304    
305     C<$command> is a MI command name, with C<-> replaced by C<_> and without
306     the intiial C<->, i.e. the GDB MI command C<-file-exec-and-symbols>
307     becomes C<file_exec_and_symbols>.
308    
309     The second argument is an optional array reference with options (i.e. it
310     can simply be missing). Each C<$option> is either an option name (similar
311     rules as with command names, i.e. no initial C<-->) or an array reference
312     with the first element being the option name, and the remaining elements
313     being parameters: [$option, $parameter...].
314    
315     The remaining arguments, excluding the last one, are simply the parameters
316     passed to GDB.
317    
318     All options and parameters will be properly quoted.
319    
320     When the command is done, the callback C<$cb> will be invoked with
321     C<$class> being one of C<done>, C<connected>, C<error> or C<exit>
322     (note: not C<running>), C<$results> being a has reference with all the
323     C<variable=value> pairs from the result list.
324    
325     C<$console> is an array reference with all the GDB console messages
326     written while command executes (for MI commands, this should always be
327     C<undef> and can be ignored).
328    
329     Example: #todo#
330    
331     =cut
332    
333     sub cmd {
334     my $cb = pop;
335     my ($self, $cmd, @arg) = @_;
336    
337     $cmd = "-$cmd ";
338     $cmd =~ s/_/-/g;
339    
340     my $opt = ref $arg[0] ? shift @arg : [];
341    
342     for (@$opt) {
343     $cmd .= "-";
344     $cmd .= (_q $_) . " "
345     for (ref) ? @$_ : $_;
346     }
347    
348     # the mi syntax is inconsistent, providing "--" in case
349     # parameters start with "-", but not allowing "-" as first
350     # char of a parameter. in fact, "--" is flagged as unknown
351     # option.
352     if (@arg) {
353     # $cmd .= "-- ";
354    
355     $cmd .= (_q $_) . " "
356     for @arg;
357     }
358    
359     # remove trailing " "
360     substr $cmd, -1, 1, "";
361    
362     $self->cmd_raw ($cmd, $cb);
363     }
364    
365     =item ($class, $results, $console) = $gdb->cmd_sync ($command => [$option...], $parameter...])
366    
367     Like C<cmd>, but blocks execution until the command has been executed, and returns the results.
368    
369     This is purely a convenience method for small scripts: since it blocks
370     execution using a condvar, it is not suitable to be used inside callbacks
371     or modules, unless L<Coro> is used.
372    
373     =cut
374    
375     sub cmd_sync {
376     push @_, my $cv = AE::cv;
377     &cmd;
378     $cv->recv
379     }
380    
381     sub event {
382     my ($self, $event, @args) = @_;
383    
384     use Data::Dump;
385     ddx [$event, @args];
386    
387     }
388    
389     =back
390    
391     =head1 SEE ALSO
392    
393     L<AnyEvent>, L<http://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html#GDB_002fMI>.
394    
395     =head1 AUTHOR
396    
397     Marc Lehmann <schmorp@schmorp.de>
398     http://home.schmorp.de/
399    
400     =cut
401    
402     1