line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Devel::hdb::Client; |
2
|
|
|
|
|
|
|
|
3
|
37
|
|
|
37
|
|
1554684
|
use strict; |
|
37
|
|
|
|
|
413
|
|
|
37
|
|
|
|
|
1068
|
|
4
|
37
|
|
|
37
|
|
204
|
use warnings; |
|
37
|
|
|
|
|
69
|
|
|
37
|
|
|
|
|
1285
|
|
5
|
|
|
|
|
|
|
|
6
|
37
|
|
|
37
|
|
22657
|
use LWP::UserAgent; |
|
37
|
|
|
|
|
1600166
|
|
|
37
|
|
|
|
|
1311
|
|
7
|
37
|
|
|
37
|
|
21827
|
use JSON; |
|
37
|
|
|
|
|
343512
|
|
|
37
|
|
|
|
|
218
|
|
8
|
37
|
|
|
37
|
|
5176
|
use Carp; |
|
37
|
|
|
|
|
87
|
|
|
37
|
|
|
|
|
2149
|
|
9
|
37
|
|
|
37
|
|
20076
|
use Data::Dumper; |
|
37
|
|
|
|
|
218862
|
|
|
37
|
|
|
|
|
2245
|
|
10
|
37
|
|
|
37
|
|
313
|
use URI::Escape qw(); |
|
37
|
|
|
|
|
80
|
|
|
37
|
|
|
|
|
849
|
|
11
|
37
|
|
|
37
|
|
16355
|
use Data::Transform::ExplicitMetadata '0.02'; |
|
37
|
|
|
|
|
196921
|
|
|
37
|
|
|
|
|
4794
|
|
12
|
37
|
|
|
37
|
|
366
|
use Scalar::Util qw(reftype); |
|
37
|
|
|
|
|
73
|
|
|
37
|
|
|
|
|
1720
|
|
13
|
|
|
|
|
|
|
|
14
|
37
|
|
|
37
|
|
16431
|
use Devel::hdb::Utils; |
|
37
|
|
|
|
|
96
|
|
|
37
|
|
|
|
|
2705
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $VERSION = '0.24'; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use Exception::Class ( |
19
|
37
|
|
|
|
|
426
|
'Devel::hdb::Client::Exception', |
20
|
|
|
|
|
|
|
'Devel::hdb::Client::RequiredParameterMissing' => { |
21
|
|
|
|
|
|
|
isa => 'Devel::hdb::Client::Exception', |
22
|
|
|
|
|
|
|
description => 'Required parameter missing', |
23
|
|
|
|
|
|
|
fields => ['params'], |
24
|
|
|
|
|
|
|
}, |
25
|
|
|
|
|
|
|
'Devel::hdb::Client::Exception::HTTP' => { |
26
|
|
|
|
|
|
|
isa => 'Devel::hdb::Client::Exception', |
27
|
|
|
|
|
|
|
fields => [qw( http_code http_message http_content )], |
28
|
|
|
|
|
|
|
}, |
29
|
|
|
|
|
|
|
'Devel::hdb::Client::Exception::Eval' => { |
30
|
|
|
|
|
|
|
isa => 'Devel::hdb::Client::Exception', |
31
|
|
|
|
|
|
|
}, |
32
|
|
|
|
|
|
|
'Devel::hdb::Client::Exception::Error' => { |
33
|
|
|
|
|
|
|
isa => 'Devel::hdb::Client::Exception', |
34
|
|
|
|
|
|
|
}, |
35
|
37
|
|
|
37
|
|
17065
|
); |
|
37
|
|
|
|
|
307387
|
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
my $JSON ||= JSON->new->utf8->allow_nonref(); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub new { |
40
|
38
|
|
|
38
|
1
|
725635
|
my $class = shift; |
41
|
38
|
|
|
|
|
1073
|
my %params = @_; |
42
|
|
|
|
|
|
|
|
43
|
38
|
|
|
|
|
458
|
my %self; |
44
|
38
|
|
|
|
|
765
|
$self{base_url} = delete $params{url}; |
45
|
38
|
50
|
|
|
|
775
|
unless ($self{base_url}) { |
46
|
0
|
|
|
|
|
0
|
Devel::hdb::Client::RequiredParameterMissing->throw(params => ['url']); |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
38
|
|
|
|
|
378
|
$self{debug} = delete $params{debug}; |
50
|
38
|
|
|
|
|
1026
|
$self{base_url} =~ s{/$}{}; |
51
|
|
|
|
|
|
|
|
52
|
38
|
|
|
|
|
1848
|
$self{http_client} = LWP::UserAgent->new(); |
53
|
38
|
|
|
|
|
142657
|
$self{http_client}->agent("Devel::hdb::Client/$VERSION"); |
54
|
|
|
|
|
|
|
|
55
|
38
|
|
|
|
|
2958
|
return bless \%self, $class; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub stack { |
59
|
41
|
|
|
41
|
1
|
24847
|
my($self, %params) = @_; |
60
|
|
|
|
|
|
|
|
61
|
41
|
|
|
|
|
213
|
my $url = 'stack'; |
62
|
41
|
100
|
|
|
|
254
|
if ($params{exclude_sub_params}) { |
63
|
1
|
|
|
|
|
47
|
$url .= '?exclude_sub_params=1'; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
41
|
|
|
|
|
482
|
my $response = $self->_GET($url); |
67
|
41
|
|
|
|
|
201
|
_assert_success($response, q(Can't get stack position)); |
68
|
41
|
|
|
|
|
915
|
my $stack = $JSON->decode($response->content); |
69
|
41
|
|
|
|
|
3379
|
foreach my $frame ( @$stack ) { |
70
|
62
|
|
|
|
|
496
|
$frame->{args} = _decode_stack_frame_args($frame->{args}); |
71
|
|
|
|
|
|
|
} |
72
|
41
|
|
|
|
|
572
|
return $stack; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub stack_depth { |
76
|
1
|
|
|
1
|
0
|
3101
|
my $self = shift; |
77
|
|
|
|
|
|
|
|
78
|
1
|
|
|
|
|
18
|
my $response = $self->_HEAD('stack'); |
79
|
1
|
|
|
|
|
5
|
_assert_success($response, q(Can't get stack depth)); |
80
|
1
|
|
|
|
|
13
|
return $response->header('X-Stack-Depth'); |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub stack_frame { |
85
|
12
|
|
|
12
|
1
|
70999
|
my($self, $level, %params) = @_; |
86
|
|
|
|
|
|
|
|
87
|
12
|
|
|
|
|
51
|
my $url = join('/', 'stack', $level); |
88
|
12
|
100
|
|
|
|
46
|
if ($params{exclude_sub_params}) { |
89
|
6
|
|
|
|
|
18
|
$url .= '?exclude_sub_params=1'; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
12
|
|
|
|
|
55
|
my $response = $self->_GET($url); |
93
|
12
|
|
|
|
|
50
|
_assert_success($response, q(Can't get stack frame)); |
94
|
12
|
|
|
|
|
159
|
my $frame = $JSON->decode($response->content); |
95
|
12
|
|
|
|
|
494
|
$frame->{args} = _decode_stack_frame_args($frame->{args}); |
96
|
|
|
|
|
|
|
|
97
|
12
|
|
|
|
|
153
|
return $frame; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub _decode_stack_frame_args { |
101
|
74
|
|
|
74
|
|
193
|
my $args = shift; |
102
|
74
|
100
|
|
|
|
306
|
return unless $args; |
103
|
62
|
|
|
|
|
150
|
[ map { Data::Transform::ExplicitMetadata::decode($_) } @{$args} ]; |
|
13
|
|
|
|
|
118
|
|
|
62
|
|
|
|
|
251
|
|
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub stack_frame_signature { |
107
|
12
|
|
|
12
|
1
|
57637
|
my($self, $level) = @_; |
108
|
|
|
|
|
|
|
|
109
|
12
|
|
|
|
|
62
|
my $response = $self->_HEAD(join('/', 'stack', $level)); |
110
|
12
|
|
|
|
|
44
|
_assert_success($response, q(Can't get stack frame)); |
111
|
|
|
|
|
|
|
|
112
|
12
|
|
|
|
|
150
|
return ( $response->header('X-Stack-Serial'), |
113
|
|
|
|
|
|
|
$response->header('X-Stack-Line') ); |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
|
117
|
3
|
|
|
3
|
|
50243
|
sub _gui_url { 'debugger-gui' } |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub gui { |
120
|
1
|
|
|
1
|
1
|
2442
|
my $self = shift; |
121
|
|
|
|
|
|
|
|
122
|
1
|
|
|
|
|
12
|
my $response = $self->_GET( _gui_url ); |
123
|
1
|
|
|
|
|
6
|
_assert_success($response, q(Can't get debugger gui')); |
124
|
1
|
|
|
|
|
24
|
return $response->content; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub _deserialize_status { |
128
|
71
|
|
|
71
|
|
2504
|
my $status = shift; |
129
|
71
|
100
|
100
|
|
|
488
|
if ($status->{events} |
130
|
|
|
|
|
|
|
and |
131
|
16
|
|
|
|
|
133
|
my @watchpoint_events = grep { $_->{type} eq 'watchpoint' } @{$status->{events}} |
|
16
|
|
|
|
|
73
|
|
132
|
|
|
|
|
|
|
) { |
133
|
4
|
|
|
|
|
11
|
foreach my $event ( @watchpoint_events ) { |
134
|
4
|
|
|
|
|
28
|
$event->{$_} = Data::Transform::ExplicitMetadata::decode($event->{$_}) foreach (qw(old new)); |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
} |
137
|
71
|
|
|
|
|
1427
|
return $status; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub _encode_url { |
141
|
72
|
|
|
72
|
|
290
|
my $base = shift; |
142
|
72
|
|
|
|
|
195
|
my @params; |
143
|
72
|
|
|
|
|
354
|
for(my $i = 0; $i < @_; $i += 2) { |
144
|
8
|
50
|
|
|
|
33
|
if (defined $_[$i + 1]) { |
145
|
8
|
|
|
|
|
49
|
push @params, join('=', @_[$i, $i+1]) |
146
|
|
|
|
|
|
|
} else { |
147
|
0
|
|
|
|
|
0
|
push @params, $_[$i]; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
} |
150
|
72
|
|
|
|
|
355
|
return join('', $base, '?', join('&', @params)); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub _validate_params { |
154
|
72
|
|
|
72
|
|
196
|
my $params = shift; |
155
|
72
|
|
|
|
|
278
|
my %allowed = map { $_ => 1 } @_; |
|
184
|
|
|
|
|
875
|
|
156
|
72
|
|
|
|
|
487
|
for (my $i = 0; $i < @$params; $i += 2) { |
157
|
8
|
50
|
|
|
|
49
|
unless (exists $allowed{ $params->[$i] }) { |
158
|
0
|
|
|
|
|
0
|
Carp::croak('Unrecognized param ' . $params->[$i]); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
} |
161
|
72
|
|
|
|
|
299
|
return 1; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub stepin { |
165
|
11
|
|
|
11
|
1
|
11950
|
my $self = shift; |
166
|
|
|
|
|
|
|
|
167
|
11
|
|
|
|
|
103
|
_validate_params(\@_, qw(next_statement next_fragment)); |
168
|
11
|
|
|
|
|
73
|
my $url = _encode_url('stepin', @_); |
169
|
11
|
|
|
|
|
50
|
my $response = $self->_POST($url); |
170
|
11
|
|
|
|
|
35
|
_assert_success($response, q(Can't stepin)); |
171
|
11
|
|
|
|
|
122
|
return _deserialize_status $JSON->decode($response->content); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub stepover { |
175
|
14
|
|
|
14
|
1
|
17471
|
my $self = shift; |
176
|
|
|
|
|
|
|
|
177
|
14
|
|
|
|
|
85
|
_validate_params(\@_, qw(next_statement next_fragment)); |
178
|
14
|
|
|
|
|
96
|
my $url = _encode_url('stepover', @_); |
179
|
14
|
|
|
|
|
285
|
my $response = $self->_POST($url); |
180
|
14
|
|
|
|
|
56
|
_assert_success($response, q(Can't stepover)); |
181
|
14
|
|
|
|
|
183
|
return _deserialize_status $JSON->decode($response->content); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub stepout { |
185
|
4
|
|
|
4
|
1
|
3500
|
my $self = shift; |
186
|
|
|
|
|
|
|
|
187
|
4
|
|
|
|
|
31
|
_validate_params(\@_, qw(next_statement next_fragment)); |
188
|
4
|
|
|
|
|
11
|
my $url = _encode_url('stepout', @_); |
189
|
4
|
|
|
|
|
35
|
my $response = $self->_POST($url); |
190
|
4
|
|
|
|
|
18
|
_assert_success($response, q(Can't stepover)); |
191
|
4
|
|
|
|
|
51
|
return _deserialize_status $JSON->decode($response->content); |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub continue { |
195
|
40
|
|
|
40
|
1
|
52111
|
my $self = shift; |
196
|
|
|
|
|
|
|
|
197
|
40
|
|
|
|
|
331
|
_validate_params(\@_, qw(nostop next_statement next_fragment)); |
198
|
40
|
|
|
|
|
129
|
my %params = @_; |
199
|
40
|
|
|
|
|
270
|
my $url = _encode_url('continue', %params); |
200
|
|
|
|
|
|
|
|
201
|
40
|
|
|
|
|
272
|
my $response = $self->_POST($url); |
202
|
40
|
|
|
|
|
181
|
_assert_success($response, q(Can't continue')); |
203
|
|
|
|
|
|
|
return $params{nostop} |
204
|
40
|
100
|
|
|
|
809
|
? 1 |
205
|
|
|
|
|
|
|
: _deserialize_status $JSON->decode($response->content); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub status { |
209
|
3
|
|
|
3
|
1
|
1443
|
my $self = shift; |
210
|
|
|
|
|
|
|
|
211
|
3
|
|
|
|
|
56
|
_validate_params(\@_, qw(next_statement next_fragment)); |
212
|
3
|
|
|
|
|
12
|
my $url = _encode_url('status', @_); |
213
|
3
|
|
|
|
|
30
|
my $response = $self->_GET($url); |
214
|
3
|
|
|
|
|
14
|
_assert_success($response, q(Can't get status)); |
215
|
3
|
|
|
|
|
56
|
return _deserialize_status $JSON->decode($response->content); |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub overview { |
219
|
1
|
|
|
1
|
0
|
18
|
my $self = shift; |
220
|
|
|
|
|
|
|
|
221
|
1
|
|
|
|
|
16
|
my $response = $self->_GET(''); |
222
|
1
|
|
|
|
|
7
|
_assert_success($response, q(Can't get status)); |
223
|
1
|
|
|
|
|
38
|
return $JSON->decode($response->content); |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub _create_breakpoint_action_sub { |
227
|
74
|
|
|
74
|
|
205
|
my($type, $required_params, $default_params) = @_; |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# create_breakpoint() and create_action() |
230
|
|
|
|
|
|
|
return sub { |
231
|
19
|
|
|
19
|
|
31742
|
my $self = shift; |
232
|
19
|
|
|
|
|
168
|
my %params = @_; |
233
|
|
|
|
|
|
|
|
234
|
19
|
|
|
|
|
108
|
_verify_required_params_exist(\%params, $required_params); |
235
|
19
|
|
|
|
|
189
|
_fill_in_default_params(\%params, $default_params); |
236
|
|
|
|
|
|
|
|
237
|
19
|
|
|
|
|
104
|
my $response = $self->_POST("${type}s", \%params); |
238
|
19
|
|
|
|
|
99
|
_assert_success($response, "Can't create $type"); |
239
|
|
|
|
|
|
|
|
240
|
15
|
|
|
|
|
181
|
my $bp = $JSON->decode($response->content); |
241
|
15
|
|
|
|
|
446
|
return $bp->{href}; |
242
|
74
|
|
|
|
|
507
|
}; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
my $create_breakpoint = "create_breakpoint"; |
246
|
|
|
|
|
|
|
my $create_action = "create_action"; |
247
|
|
|
|
|
|
|
{ |
248
|
37
|
|
|
37
|
|
114461
|
no strict 'refs'; |
|
37
|
|
|
|
|
100
|
|
|
37
|
|
|
|
|
18287
|
|
249
|
|
|
|
|
|
|
*$create_breakpoint = _create_breakpoint_action_sub( |
250
|
|
|
|
|
|
|
'breakpoint', |
251
|
|
|
|
|
|
|
[qw( filename line )], |
252
|
|
|
|
|
|
|
{ code => 1, inactive => 0 } ); |
253
|
|
|
|
|
|
|
*$create_action = _create_breakpoint_action_sub( |
254
|
|
|
|
|
|
|
'action', |
255
|
|
|
|
|
|
|
[qw( filename line code )], |
256
|
|
|
|
|
|
|
{ inactive => 0 } ); |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
foreach my $type ( qw(breakpoint action) ) { |
260
|
|
|
|
|
|
|
# change_breakpoint() and change_action() |
261
|
|
|
|
|
|
|
my $change_subname = "change_$type"; |
262
|
|
|
|
|
|
|
my $change = sub { |
263
|
8
|
|
|
8
|
|
15117
|
my($self, $bp, %params) = @_; |
264
|
|
|
|
|
|
|
|
265
|
8
|
|
|
|
|
35
|
my $response = $self->_POST($bp, \%params); |
266
|
8
|
|
|
|
|
60
|
_assert_success($response, "Can't $change_subname"); |
267
|
6
|
|
|
|
|
69
|
return $JSON->decode($response->content); |
268
|
|
|
|
|
|
|
}; |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# delete_breakpoint() and delete_action() |
271
|
|
|
|
|
|
|
my $delete_subname = "delete_$type"; |
272
|
|
|
|
|
|
|
my $delete = sub { |
273
|
4
|
|
|
4
|
|
8385
|
my($self, $href) = @_; |
274
|
|
|
|
|
|
|
|
275
|
4
|
|
|
|
|
21
|
my $response = $self->_DELETE($href); |
276
|
4
|
|
|
|
|
23
|
_assert_success($response, "Can't $delete_subname"); |
277
|
3
|
|
|
|
|
48
|
return 1; |
278
|
|
|
|
|
|
|
}; |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# get_breakpoint() and get_action() |
281
|
|
|
|
|
|
|
my $get_one_subname = "get_$type"; |
282
|
|
|
|
|
|
|
my $get_one = sub { |
283
|
2
|
|
|
2
|
|
7766
|
my($self, $href) = @_; |
284
|
|
|
|
|
|
|
|
285
|
2
|
|
|
|
|
8
|
my $response = $self->_GET($href); |
286
|
2
|
|
|
|
|
11
|
_assert_success($response, "Can't $get_one_subname"); |
287
|
|
|
|
|
|
|
|
288
|
1
|
|
|
|
|
12
|
my $bp = $JSON->decode($response->content); |
289
|
1
|
|
|
|
|
31
|
return $bp; |
290
|
|
|
|
|
|
|
}; |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
my $get_multiple_subname = "get_${type}s"; |
293
|
|
|
|
|
|
|
my $get_multiple = do { |
294
|
|
|
|
|
|
|
my @recognized_params = qw(filename line code inactive); |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# get_breakpoints() and get_actions() |
297
|
|
|
|
|
|
|
sub { |
298
|
9
|
|
|
9
|
|
7121
|
my $self = shift; |
299
|
9
|
|
|
|
|
37
|
my %filters = @_; |
300
|
|
|
|
|
|
|
|
301
|
9
|
|
|
|
|
51
|
_verify_recognized_params(\%filters, \@recognized_params); |
302
|
|
|
|
|
|
|
|
303
|
9
|
|
|
|
|
29
|
my $url = "${type}s"; |
304
|
9
|
|
|
|
|
42
|
my $query_string = _encode_query_string_for_hash(%filters); |
305
|
9
|
100
|
|
|
|
36
|
$url .= '?' . $query_string if length($query_string); |
306
|
9
|
|
|
|
|
59
|
my $response = $self->_GET($url); |
307
|
9
|
|
|
|
|
40
|
_assert_success($response, "Can't $get_multiple_subname"); |
308
|
|
|
|
|
|
|
|
309
|
9
|
|
|
|
|
99
|
return $JSON->decode($response->content); |
310
|
|
|
|
|
|
|
}; |
311
|
|
|
|
|
|
|
}; |
312
|
|
|
|
|
|
|
|
313
|
37
|
|
|
37
|
|
299
|
no strict 'refs'; |
|
37
|
|
|
|
|
81
|
|
|
37
|
|
|
|
|
16770
|
|
314
|
|
|
|
|
|
|
*$change_subname = $change; |
315
|
|
|
|
|
|
|
*$delete_subname = $delete; |
316
|
|
|
|
|
|
|
*$get_one_subname = $get_one; |
317
|
|
|
|
|
|
|
*$get_multiple_subname = $get_multiple; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
sub loaded_files { |
321
|
4
|
|
|
4
|
1
|
4322
|
my $self = shift; |
322
|
|
|
|
|
|
|
|
323
|
4
|
|
|
|
|
20
|
my $response = $self->_GET('source'); |
324
|
4
|
|
|
|
|
37
|
_assert_success($response, q(Can't get loaded files)); |
325
|
|
|
|
|
|
|
|
326
|
4
|
|
|
|
|
55
|
return $JSON->decode($response->content); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub file_source_and_breakable { |
330
|
4
|
|
|
4
|
1
|
3879
|
my($self, $filename) = @_; |
331
|
|
|
|
|
|
|
|
332
|
4
|
|
|
|
|
18
|
my $escaped_filename = URI::Escape::uri_escape($filename); |
333
|
4
|
|
|
|
|
135
|
my $response = $self->_GET(join('/', 'source', $escaped_filename)); |
334
|
4
|
|
|
|
|
20
|
_assert_success($response, "Can't get source for $filename"); |
335
|
|
|
|
|
|
|
|
336
|
2
|
|
|
|
|
24
|
return $JSON->decode($response->content); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub eval { |
340
|
22
|
|
|
22
|
1
|
39160
|
my($self, $eval_string) = @_; |
341
|
|
|
|
|
|
|
|
342
|
22
|
|
|
|
|
199
|
my $string_was_fixed_up = $eval_string ne Devel::hdb::Utils::_fixup_expr_for_eval($eval_string); |
343
|
|
|
|
|
|
|
|
344
|
22
|
|
|
|
|
134
|
my %params = ( 'wantarray' => wantarray, code => $eval_string ); |
345
|
22
|
|
|
|
|
110
|
my $response = $self->_POST('eval', \%params); |
346
|
|
|
|
|
|
|
|
347
|
22
|
|
|
|
|
115
|
my $result = Data::Transform::ExplicitMetadata::decode($JSON->decode($response->content)); |
348
|
|
|
|
|
|
|
|
349
|
22
|
100
|
|
|
|
2247
|
if ($response->code == 409) { |
350
|
1
|
|
|
|
|
63
|
Devel::hdb::Client::Exception::Eval->throw( |
351
|
|
|
|
|
|
|
error => $result |
352
|
|
|
|
|
|
|
); |
353
|
|
|
|
|
|
|
} |
354
|
21
|
|
|
|
|
354
|
_assert_success($response, q(eval failed)); |
355
|
|
|
|
|
|
|
|
356
|
21
|
|
|
|
|
261
|
return _return_eval_data($result, $string_was_fixed_up); |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub _return_eval_data { |
360
|
21
|
|
|
21
|
|
64
|
my($result, $string_was_fixed_up) = @_; |
361
|
|
|
|
|
|
|
|
362
|
21
|
|
|
|
|
81
|
my $reftype = reftype($result); |
363
|
|
|
|
|
|
|
|
364
|
21
|
50
|
66
|
|
|
105
|
if (wantarray and $reftype and $reftype ne 'ARRAY') { |
|
|
|
66
|
|
|
|
|
365
|
0
|
|
|
|
|
0
|
Devel::hdb::Exception::Error->throw( |
366
|
|
|
|
|
|
|
error => "Expected ARRAY ref but got $reftype" |
367
|
|
|
|
|
|
|
); |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
21
|
|
|
|
|
69
|
return _return_unfixed_value_from_eval($string_was_fixed_up, $result); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
sub _return_unfixed_value_from_eval { |
374
|
21
|
|
|
21
|
|
49
|
my $was_fixed_up = shift; |
375
|
21
|
|
|
|
|
37
|
my $val = shift; |
376
|
|
|
|
|
|
|
|
377
|
37
|
|
|
37
|
|
300
|
no warnings 'uninitialized'; |
|
37
|
|
|
|
|
89
|
|
|
37
|
|
|
|
|
67087
|
|
378
|
|
|
|
|
|
|
|
379
|
21
|
100
|
|
|
|
72
|
if ($was_fixed_up) { |
380
|
2
|
100
|
66
|
|
|
24
|
if (wantarray and reftype($val->[0]) eq 'HASH') { |
|
|
50
|
|
|
|
|
|
381
|
1
|
|
|
|
|
3
|
return %{ $val->[0] }; |
|
1
|
|
|
|
|
16
|
|
382
|
|
|
|
|
|
|
} elsif (reftype($val) eq 'GLOB') { |
383
|
1
|
|
|
|
|
15
|
return *$val; |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
19
|
100
|
|
|
|
65
|
if (wantarray) { |
388
|
3
|
|
|
|
|
35
|
return @$val; |
389
|
|
|
|
|
|
|
} else { |
390
|
16
|
|
|
|
|
198
|
return $val; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub list_vars_at_level { |
395
|
0
|
|
|
0
|
0
|
0
|
my($self, $level) = @_; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub get_var_at_level { |
400
|
32
|
|
|
32
|
1
|
22781
|
my($self, $varname, $level) = @_; |
401
|
|
|
|
|
|
|
|
402
|
32
|
|
|
|
|
128
|
my $string_was_fixed_up = $varname ne Devel::hdb::Utils::_fixup_expr_for_eval($varname); |
403
|
|
|
|
|
|
|
|
404
|
32
|
|
|
|
|
96
|
my $escaped_varname = URI::Escape::uri_escape($varname); |
405
|
32
|
|
|
|
|
940
|
my $response = $self->_GET(join('/', 'getvar', $level, $escaped_varname)); |
406
|
32
|
|
|
|
|
139
|
_assert_success($response, "Can't get $varname at level $level"); |
407
|
|
|
|
|
|
|
|
408
|
32
|
|
|
|
|
330
|
return Data::Transform::ExplicitMetadata::decode($JSON->decode($response->content)); |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub load_config { |
412
|
1
|
|
|
1
|
1
|
3462
|
my($self, $filename) = @_; |
413
|
|
|
|
|
|
|
|
414
|
1
|
|
|
|
|
12
|
my $escaped_filename = URI::Escape::uri_escape($filename); |
415
|
1
|
|
|
|
|
72
|
my $response = $self->_POST(join('/', 'loadconfig', $escaped_filename)); |
416
|
1
|
|
|
|
|
8
|
_assert_success($response, "Loading config from $filename failed: " . $response->content); |
417
|
|
|
|
|
|
|
|
418
|
1
|
|
|
|
|
17
|
return 1; |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub save_config { |
422
|
1
|
|
|
1
|
1
|
1181
|
my($self, $filename) = @_; |
423
|
|
|
|
|
|
|
|
424
|
1
|
|
|
|
|
5
|
my $escaped_filename = URI::Escape::uri_escape($filename); |
425
|
1
|
|
|
|
|
70
|
my $response = $self->_POST(join('/', 'saveconfig', $escaped_filename)); |
426
|
1
|
|
|
|
|
7
|
_assert_success($response, "Save config to $filename failed: " . $response->content); |
427
|
|
|
|
|
|
|
|
428
|
1
|
|
|
|
|
20
|
return 1; |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
sub exit { |
432
|
1
|
|
|
1
|
1
|
433
|
my $self = shift; |
433
|
|
|
|
|
|
|
|
434
|
1
|
|
|
|
|
8
|
my $response = $self->_POST('exit'); |
435
|
1
|
|
|
|
|
5
|
_assert_success($response, q(Can't exit)); |
436
|
|
|
|
|
|
|
|
437
|
1
|
|
|
|
|
24
|
return 1; |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
sub package_info { |
441
|
8
|
|
|
8
|
1
|
9728
|
my($self, $package) = @_; |
442
|
|
|
|
|
|
|
|
443
|
8
|
|
|
|
|
35
|
my $escaped_pkg = URI::Escape::uri_escape($package); |
444
|
8
|
|
|
|
|
223
|
my $response = $self->_GET(join('/', 'packageinfo', $escaped_pkg)); |
445
|
8
|
|
|
|
|
36
|
_assert_success($response, "Cannot get info for package $package"); |
446
|
|
|
|
|
|
|
|
447
|
7
|
|
|
|
|
74
|
return $JSON->decode($response->content); |
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
sub sub_info { |
451
|
10
|
|
|
10
|
1
|
20576
|
my($self, $subname) = @_; |
452
|
|
|
|
|
|
|
|
453
|
10
|
|
|
|
|
35
|
my $escaped_subname = URI::Escape::uri_escape($subname); |
454
|
10
|
|
|
|
|
294
|
my $response = $self->_GET(join('/', 'subinfo', $escaped_subname)); |
455
|
10
|
|
|
|
|
42
|
_assert_success($response, "Cannot get info for subroutine $subname"); |
456
|
|
|
|
|
|
|
|
457
|
9
|
|
|
|
|
97
|
return $JSON->decode($response->content); |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
sub add_watchpoint { |
461
|
1
|
|
|
1
|
1
|
1556
|
my($self, $expr) = @_; |
462
|
|
|
|
|
|
|
|
463
|
1
|
|
|
|
|
7
|
my $escaped_expr = URI::Escape::uri_escape($expr); |
464
|
1
|
|
|
|
|
67
|
my $response = $self->_PUT(join('/', 'watchpoints', $escaped_expr)); |
465
|
1
|
|
|
|
|
5
|
_assert_success($response, "Cannot add watchpoint for $expr"); |
466
|
|
|
|
|
|
|
|
467
|
1
|
|
|
|
|
16
|
return 1; |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
sub delete_watchpoint { |
471
|
0
|
|
|
0
|
1
|
0
|
my($self, $expr) = @_; |
472
|
|
|
|
|
|
|
|
473
|
0
|
|
|
|
|
0
|
my $escaped_expr = URI::Escape::uri_escape($expr); |
474
|
0
|
|
|
|
|
0
|
my $response = $self->_DELETE(join('/', 'watchpoints', $escaped_expr)); |
475
|
0
|
|
|
|
|
0
|
_assert_success($response, "Cannot delete watchpoint for $expr"); |
476
|
|
|
|
|
|
|
|
477
|
0
|
|
|
|
|
0
|
return 1; |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
sub get_watchpoints { |
481
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
482
|
|
|
|
|
|
|
|
483
|
0
|
|
|
|
|
0
|
my $response = $self->_GET('watchpoints'); |
484
|
0
|
|
|
|
|
0
|
_assert_success($response, 'Cannot get watchpoints'); |
485
|
|
|
|
|
|
|
|
486
|
0
|
|
|
|
|
0
|
return $JSON->decode($response->content); |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
sub print_optree { |
490
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
491
|
0
|
|
|
|
|
0
|
my $response = $self->_GET('print_optree'); |
492
|
0
|
|
|
|
|
0
|
_assert_success($response, 'Cannot print_optree'); |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
sub _encode_query_string_for_hash { |
496
|
9
|
|
|
9
|
|
16
|
my @params; |
497
|
9
|
|
|
|
|
33
|
for(my $i = 0; $i < @_; $i += 2) { |
498
|
|
|
|
|
|
|
push @params, |
499
|
8
|
|
|
|
|
87
|
join('=', map { URI::Escape::uri_escape($_) } @_[$i, $i+1]); |
|
16
|
|
|
|
|
160
|
|
500
|
|
|
|
|
|
|
} |
501
|
9
|
|
|
|
|
172
|
return join('&', @params); |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
sub _verify_required_params_exist { |
505
|
19
|
|
|
19
|
|
50
|
my($param_hash, $required_list) = @_; |
506
|
19
|
|
|
|
|
81
|
foreach my $required ( @$required_list ) { |
507
|
45
|
50
|
|
|
|
146
|
unless (exists $param_hash->{$required}) { |
508
|
0
|
|
|
|
|
0
|
my $sub_name = (caller())[3]; |
509
|
0
|
|
|
|
|
0
|
Carp::croak("$required is a required param of $sub_name"); |
510
|
|
|
|
|
|
|
} |
511
|
|
|
|
|
|
|
} |
512
|
19
|
|
|
|
|
37
|
return 1; |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
sub _verify_recognized_params { |
516
|
9
|
|
|
9
|
|
21
|
my($param_hash, $recognized_list) = @_; |
517
|
|
|
|
|
|
|
|
518
|
9
|
|
|
|
|
59
|
my %recognized = map { $_ => 1 } @$recognized_list; |
|
36
|
|
|
|
|
133
|
|
519
|
|
|
|
|
|
|
|
520
|
9
|
|
|
|
|
56
|
foreach my $key ( keys %$param_hash ) { |
521
|
8
|
50
|
|
|
|
28
|
Carp::croak("Unrecognized param $key") unless exists $recognized{$key}; |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
sub _fill_in_default_params { |
526
|
19
|
|
|
19
|
|
54
|
my($params_hash, $defaults) = @_; |
527
|
|
|
|
|
|
|
|
528
|
19
|
|
|
|
|
120
|
foreach my $param_name (keys %$defaults) { |
529
|
|
|
|
|
|
|
$params_hash->{$param_name} = $defaults->{$param_name} |
530
|
31
|
100
|
|
|
|
114
|
unless (exists $params_hash->{$param_name}); |
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
270
|
|
|
270
|
|
1240
|
sub _base_url { shift->{base_url} } |
535
|
268
|
|
|
268
|
|
1513
|
sub _http_client { shift->{http_client} } |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
sub _combined_url { |
538
|
270
|
|
|
270
|
|
504
|
my $self = shift; |
539
|
270
|
|
|
|
|
858
|
return join('/', $self->_base_url, @_); |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
sub _http_request { |
543
|
268
|
|
|
268
|
|
587
|
my $self = shift; |
544
|
268
|
|
|
|
|
737
|
my $method = shift; |
545
|
268
|
|
|
|
|
659
|
my $url_ext = shift; |
546
|
268
|
|
|
|
|
532
|
my $body = shift; |
547
|
|
|
|
|
|
|
|
548
|
268
|
|
|
|
|
795
|
my $url = $self->_combined_url($url_ext); |
549
|
268
|
|
|
|
|
1254
|
$self->_dmsg("\nSending $method => $url"); |
550
|
|
|
|
|
|
|
|
551
|
268
|
|
|
|
|
2262
|
my $request = HTTP::Request->new($method => $url); |
552
|
|
|
|
|
|
|
|
553
|
268
|
100
|
|
|
|
323104
|
if (defined $body) { |
554
|
49
|
|
|
|
|
290
|
$request->content_type('application/json'); |
555
|
49
|
|
|
|
|
1855
|
$request->content($JSON->encode($body)); |
556
|
|
|
|
|
|
|
} else { |
557
|
219
|
|
|
|
|
1431
|
$request->content_type('text/html'); |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
268
|
|
|
|
|
9951
|
$self->_dmsg("Request: ",Data::Dumper::Dumper($request)); |
561
|
268
|
|
|
|
|
1039
|
my $response = $self->_http_client->request($request); |
562
|
268
|
|
|
|
|
12787047
|
$self->_dmsg('Response ', Data::Dumper::Dumper($response)); |
563
|
268
|
|
|
|
|
1449
|
return $response; |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
sub _dmsg { |
567
|
804
|
|
|
804
|
|
71428
|
my $self = shift; |
568
|
804
|
50
|
|
|
|
2334
|
return unless $self->debug; |
569
|
0
|
|
|
|
|
0
|
print STDERR @_,"\n"; |
570
|
|
|
|
|
|
|
} |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
sub _GET { |
573
|
129
|
|
|
129
|
|
364
|
my $self = shift; |
574
|
129
|
|
|
|
|
584
|
$self->_http_request('GET', @_); |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
sub _POST { |
578
|
121
|
|
|
121
|
|
267
|
my $self = shift; |
579
|
121
|
|
|
|
|
450
|
$self->_http_request('POST', @_); |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
sub _PUT { |
583
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
584
|
1
|
|
|
|
|
5
|
$self->_http_request('PUT', @_); |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
sub _HEAD { |
588
|
13
|
|
|
13
|
|
63
|
my $self = shift; |
589
|
13
|
|
|
|
|
51
|
$self->_http_request('HEAD', @_); |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
sub _DELETE { |
593
|
4
|
|
|
4
|
|
10
|
my $self = shift; |
594
|
4
|
|
|
|
|
15
|
$self->_http_request('DELETE', @_); |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub _assert_success { |
598
|
265
|
|
|
265
|
|
548
|
my $response = shift; |
599
|
265
|
|
|
|
|
674
|
my $error = shift; |
600
|
265
|
100
|
|
|
|
1154
|
unless ($response->is_success) { |
601
|
12
|
|
|
|
|
159
|
Devel::hdb::Client::Exception::HTTP->throw( |
602
|
|
|
|
|
|
|
error => $error . ': ' . $response->message, |
603
|
|
|
|
|
|
|
http_code => $response->code, |
604
|
|
|
|
|
|
|
http_message => $response->message, |
605
|
|
|
|
|
|
|
http_content => $response->content, |
606
|
|
|
|
|
|
|
); |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
sub debug { |
611
|
804
|
|
|
804
|
0
|
1358
|
my $self = shift; |
612
|
804
|
50
|
|
|
|
2367
|
if (@_) { |
613
|
0
|
|
|
|
|
0
|
$self->{debug} = shift; |
614
|
|
|
|
|
|
|
} |
615
|
804
|
|
|
|
|
2590
|
return $self->{debug}; |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
1; |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
=pod |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
=head1 NAME |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
Devel::hdb::Client - Perl bindings for Devel::hdb's REST interface |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
=head1 DESCRIPTION |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
Talks to the REST interface of Devel::hdb to control the debugged program. |
629
|
|
|
|
|
|
|
It uses the same interface the HTML/GUI debugger uses, and has all the same |
630
|
|
|
|
|
|
|
capabilities. |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=head1 SYNOPSIS |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
my $client = Devel::hdb::Client->new(url => 'http://localhost:8080'); |
635
|
|
|
|
|
|
|
my $status = $client->status(); |
636
|
|
|
|
|
|
|
printf("Stopped in %s at %s:%d\n", @status{'subroutine','filename','line}); |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
$status = $client->step(); |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
$client->exit(); |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
my $client = Devel::hdb::Client->new(url => $url); |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
Create a new client instance. C<$url> is the base url the debugger is |
647
|
|
|
|
|
|
|
listening on. In particular, it does _not_ include '/debugger-gui'. |
648
|
|
|
|
|
|
|
new() also accepts the parameter C 1> to turn on the debugging |
649
|
|
|
|
|
|
|
flag; when on, it prints messages to STDERR. |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
=head1 METHODS |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
All methods will throw an exception if the response from the debugger is not |
654
|
|
|
|
|
|
|
a successful response. See L below for more info. |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
=over 4 |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
=item $client->stack(); |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
Perform GET /stack |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
Return an arrayref of hashrefs. Each hashref is a caller frame. It returns |
663
|
|
|
|
|
|
|
all the same data as L. Their keys are the same as |
664
|
|
|
|
|
|
|
is returned by the caller() built-in: |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=over 2 |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
=item filename |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=item line |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=item package |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=item subroutine |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
=item wantarray |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=item hasargs |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=item evaltext |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=item is_require |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
=item hints |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
=item bitmask |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=back |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
and a few derived items |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
=over 2 |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=item args |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
An arrayref of arguments to the function. See L below. |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
=item autoload |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
If this frame is a call to &AUTOLOAD, then this will be the |
701
|
|
|
|
|
|
|
name this function was called as. |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
=item evalfile |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
If this frame is a string eval, this is the file the string eval appears. |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
=item evalline |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
If this frame is a string eval, this is the line the string eval appears. |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
=item subname |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
The subroutine name without the package name. |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
=item level |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
A number indicating how deep this caller frame actually is. |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
=item serial |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
A unique identifier for this caller frame. It will stay the same as long |
722
|
|
|
|
|
|
|
as this frame is still active. |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
=back |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
=item $client->stack_frame($level); |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
Perform GET /stack/$level |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
Get a single caller frame. Returns a hashref representing the requested |
731
|
|
|
|
|
|
|
frame. Frames are numbered starting with 0. Frame 0 is the point the debugged |
732
|
|
|
|
|
|
|
program is stopped at. If using this method to scan for frames by repetedly |
733
|
|
|
|
|
|
|
calling stack_frame() with larger numbers, remember that it will throw an |
734
|
|
|
|
|
|
|
exception when retrieving a frame that does not exist (eg. getting frame 10 |
735
|
|
|
|
|
|
|
when the stack is only 9 deep). |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=item $client->stack_frame_signature($level) |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
Perform HEAD /stack/$level |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
Return a 2-element list for the given frame: serial and line. If a particular |
742
|
|
|
|
|
|
|
frame's serial number changes, it is a new function call. If the serial is |
743
|
|
|
|
|
|
|
the same, but the line changes, then the same function call has moved on to |
744
|
|
|
|
|
|
|
a different line. |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
=item $client->gui() |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
Perform GET /debugger-gui and return a string. |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
=item $client->status() |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
Perform GET /status |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
Return a hashref with short information about the debugged program. It has |
755
|
|
|
|
|
|
|
these keys: |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
=over 2 |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
=item running - Boolean, true if the program has not yet terminated |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
=item subroutine - Subroutine name the program is stopped in |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
=item filename - File the program is stopped in |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
=item line - Line the program is stopped in |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
=back |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
Additionally, if there were any asynchronous events since the last status-like |
770
|
|
|
|
|
|
|
call, there's a key 'events' containing a listref of hashrefs, one for each |
771
|
|
|
|
|
|
|
event. See the section L below. |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
=item $client->stepin() |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
Perform POST /stepin |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
Tell the debugger to step into the next statement, including function calls. |
778
|
|
|
|
|
|
|
Returns the same hashref as status(). |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
=item $client->stepover() |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
Perform POST /stepover |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
Tell the debugger to step over one statement. If the next statment is a |
785
|
|
|
|
|
|
|
function call, it stops immediately after that subroutine returns. Returns |
786
|
|
|
|
|
|
|
the same hashref as status(). |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
=item $client->stepout() |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
Perform POST /stepout |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
Tell the debugger to continue until the current function returns. The |
793
|
|
|
|
|
|
|
debugger stops before the next statment after the function call. Returns |
794
|
|
|
|
|
|
|
the same hashref as status(). |
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
=item $client->continue() |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
Perform POST /continue |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
Tell the debugger to continue running the program. The next time the debugger |
801
|
|
|
|
|
|
|
stops, the call returns the same hashref as status(). |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
=item $client->exit() |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
Perform POST /exit |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
Tell the debugger to exit. Returns true. |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
=item $client->create_breakpoint(filename => $file, line => $line, code => $expr, inactive => $bool) |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
=item $client->create_action(filename => $file, line => $line, code => $expr, inactive => $bool) |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
Perform POST /breakpoints or POST /actions |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
Create a breakpoint or action on the given file and line, which are required |
816
|
|
|
|
|
|
|
arguments. |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
'code' is a Perl expression to execute before the actual program line. For |
819
|
|
|
|
|
|
|
breakpoints, if this expression evaluates to true, the debugger will stop |
820
|
|
|
|
|
|
|
before executing that line. It defaults to '1' to create an unconditional |
821
|
|
|
|
|
|
|
breakpoint. For actions, the result is ignored, but 'code' is a required |
822
|
|
|
|
|
|
|
argument. |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
If 'inactive' is true, the breakpoint/action will be saved, but not actually |
825
|
|
|
|
|
|
|
evaluated. Defaults to false. |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
Returns a scalar value representing the breakpoint/action. |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
=item $client->get_breakpoint($bp) |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
=item $client->get_action($bp) |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
Perform GET /breakpoints/ or GET /actions/ |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
Return a hashref containing information about the requested breakpoint/action. |
836
|
|
|
|
|
|
|
The arg, $bp, is the scalar returned by create_breakpoint() or create_action(). |
837
|
|
|
|
|
|
|
The returned hashref has these keys: |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
=over 2 |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
=item filename |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
=item line |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
=item code |
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
=item inactive |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
=item href |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
=back |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
=item $client->delete_breakpoint($bp) |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
=item $client->delete_action($bp) |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
Perform DELETE /breakpoints/ or DELETE /actions/ |
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
Removes the given breakpoint or action. Returns true. Throws an exception if |
860
|
|
|
|
|
|
|
the given breakpoint/action does not exist. |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
=item $client->change_breakpoint($bp, %changes) |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
=item $client->change_breakpoint($bp, %changes) |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
Perform POST /breakpoints/ or POST /actions/ |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
Changes parameters for the given breakpoint or action. The only 'code' and |
869
|
|
|
|
|
|
|
'inactive' may be changed. |
870
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
=item $client->get_breakpoints(%filter) |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
=item $client->get_actions(%filter) |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
Perform GET /breakpoints or GET /actions with parameters |
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
Find breakpoints or actions matching the given parameters. The %filter |
878
|
|
|
|
|
|
|
is a list of key/value pairs describing what you're looking for. For example: |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
$client->get_breakpoints(filename => 'main.pl') |
881
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
Will return all the breakpoints in the file main.pl. |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
$client->get_breakpoints(inactive => 0) |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
Will return all active breakpoints in the program. |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
You can filter on filename, line, code or inactive. If no filters are used, |
889
|
|
|
|
|
|
|
then it returns all breakpoints or actions. |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
The return value is a listref of hashrefs. |
892
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
=item $client->add_watchpoint($expression) |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
Add a watchpoint expression. These expressions are evaluated before each |
896
|
|
|
|
|
|
|
statement in the program. If their value ever changes, the program will |
897
|
|
|
|
|
|
|
stop and the status will include a 'watchpoint' event indicating which line |
898
|
|
|
|
|
|
|
caused the change. |
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
=item $client->delete_watchpoint($expression) |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
Remove a watchpoint expression. It must have been previously added with |
903
|
|
|
|
|
|
|
C or an exception will be thrown. |
904
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
=item $client->get_watchpoints($expression) |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
Return a listref of hashrefs with all the currently set watchpoints. Each |
908
|
|
|
|
|
|
|
hashref has these keys |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
=over 2 |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=item expr |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
The watchpoint expression |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
=item href |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
A URL uniquely identifying this watchpoint |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
=back |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
=item $client->loaded_files() |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
Perform GET /source |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
Return a listref of hashrefs, one for each file currently loaded in the |
927
|
|
|
|
|
|
|
program. Each hashref has a key 'filename' with the name of the file. |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
=item $client->file_source_and_breakable() |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
Perform GET /source/ |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
Return a listref of 2-element listrefs. For each 2-elt list, the first |
934
|
|
|
|
|
|
|
element is a string containing the perl source code for that line. The |
935
|
|
|
|
|
|
|
second element is true if that line may contain a breakpoint. |
936
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
=item $client->eval($expr) |
938
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
Perform POST /eval |
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
Evaluate an expression in the most recent caller frame of the debugged |
942
|
|
|
|
|
|
|
program. The expression is evaluated in the same context as the call to |
943
|
|
|
|
|
|
|
this method: void, scalar or list. |
944
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
Returns whatever the expression evaluated to. See L below. |
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
=item $client->get_var_at_level($varname, $level) |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
Perform GET /getvar// |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
Get the value of the given variable at the given caller frame depth. The |
952
|
|
|
|
|
|
|
variable must contain the sigil. If the frame does not exist, or the variable |
953
|
|
|
|
|
|
|
does not exist at that depth, it will throw an exception. |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
Returns the value of the variable. See L below. |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
=item $client->load_config($filename) |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
Load configuration information from the given filename. |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
=item $client->save_config($filename) |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
Save configuration such as breakpoints, to the given filename. |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
=item $client->package_info($package) |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
Perform GET /packageinfo/$package |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
Get information about the given package. Returns a hashref with these keys |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
=over 2 |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
=item name |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
Name of the pckage |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
=item packages |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
Listref of hashrefs, one for each package inside this one. Each hashref has |
980
|
|
|
|
|
|
|
a 'name' key with the name of the package. |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
=item subroutines |
983
|
|
|
|
|
|
|
|
984
|
|
|
|
|
|
|
Listref of hashrefs, one for each subroutine inside this package. Each hashref has |
985
|
|
|
|
|
|
|
a 'name' key with the name of the sub. |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
=back |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
=item $client->sub_info($sub_name) |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
Perform GET /subinfo/$sub_name |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
Return a hashref with information about the named sub. $sub_name should |
994
|
|
|
|
|
|
|
include the package, or 'main::' is assummed. |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
=over 2 |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
=item suboroutine |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
Subroutine name, not including the package |
1001
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
=item package |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
Package name |
1005
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
=item filename |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
File the sub is in |
1009
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
=item line |
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
Line the subroutine is defined |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
=item end |
1015
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
Last line where the sub is defined |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
=item source |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
If the sub was created in a string eval, this is the file the eval happened in |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
=item source_line |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
Line the string eval happened at |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
=back |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
=back |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
=head1 EVENTS |
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
The control methods (stepin, stepout, stepover, continue) and status() all |
1033
|
|
|
|
|
|
|
return a data structure that may contain a listref for the key 'events'. |
1034
|
|
|
|
|
|
|
Events are asynchronous events that happened since the last status report. |
1035
|
|
|
|
|
|
|
They all have a 'type' key. Other keys are type specific. |
1036
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
=head2 fork event |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
When the debugged program fork()s, this event is generated in the parent |
1040
|
|
|
|
|
|
|
process. |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
=over 2 |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
=item pid |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
The processID of the child process |
1047
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
=item href |
1049
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
URL for the debugger in the child process. You may use this URL to construct |
1051
|
|
|
|
|
|
|
another Devel::hdb::Client. |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
=item gui_href |
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
URL to bring up the graphical debugger in a browser. |
1056
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
=item href_continue |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
URL to POST to tell the child to run without stopping. |
1060
|
|
|
|
|
|
|
|
1061
|
|
|
|
|
|
|
=back |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
=head2 watchpoint event |
1064
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
When a watchpoint expression's value changes. |
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
=over 2 |
1068
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
=item expr |
1070
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
The perl expression whose value changed |
1072
|
|
|
|
|
|
|
|
1073
|
|
|
|
|
|
|
=item old |
1074
|
|
|
|
|
|
|
|
1075
|
|
|
|
|
|
|
The old value of the expression. Watchpoint expressions are evaluated in |
1076
|
|
|
|
|
|
|
list context, so old will always be a listref. |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
=item new |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
The new value of the expression. Also a listref. |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
=item filename |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
=item line |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
=item package |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
=item subroutine |
1089
|
|
|
|
|
|
|
|
1090
|
|
|
|
|
|
|
The location where the change likely happened. This is whichever line was |
1091
|
|
|
|
|
|
|
executing immediately before the change was detected. |
1092
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
=back |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
=head2 exception event |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
When the program throws an uncaught exception. |
1098
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
=over 2 |
1100
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
=item value |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
The "value" of the exception. Either the string passed to C, or perhaps |
1104
|
|
|
|
|
|
|
an exception object |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
=item package |
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
=item filename |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
=item line |
1111
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
=item subroutine |
1113
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
Location information about where the exception was thrown |
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
=back |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
=head2 exit event |
1119
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
When the debugged program has finished. The debugger is still running. |
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
=over 2 |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
=item value |
1125
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
The process exit code |
1127
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
=back |
1129
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
=head2 hangup event |
1131
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
When the debugger has exited and is no longer listening for requests. |
1133
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
=head2 trace_diff event |
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
When execution has differed from the previous run, when run in follow mode. |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
=over 2 |
1139
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
=item filename |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
=item line |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
=item package |
1145
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
=item subroutine |
1147
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
=item sub_offset |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
Where the program is currently stopped. sub_offset is the line number within |
1151
|
|
|
|
|
|
|
the subroutine. |
1152
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
=item expected_filename |
1154
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
=item expected_line |
1156
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
=item expected_package |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
=item expected_subroutine |
1160
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
=item expected_sub_offset |
1162
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
Where the debugger expected the program to be. |
1164
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
=back |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
=head1 PERL VALUES |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
For methods that return Perl values such as eval(), get_var_at_level(), or the |
1170
|
|
|
|
|
|
|
argument lists in a stack frame, the data is deserialized with |
1171
|
|
|
|
|
|
|
Data::Transform::ExplicitMetadata::decode(). If the variable has special Perl |
1172
|
|
|
|
|
|
|
attributes (such as blessed, tied, filehandle), decode() will try to re-create |
1173
|
|
|
|
|
|
|
that specialness. |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
=head1 EXCEPTIONS |
1176
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
This class uses Exception classes. They stringify to something reasonable. |
1178
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
Devel::hdb::Client::RequiredParameterMissing is thrown when a method requires |
1180
|
|
|
|
|
|
|
a parameter that was missing. The exception's attribute 'params' is a listref |
1181
|
|
|
|
|
|
|
of parameter names that were missing. |
1182
|
|
|
|
|
|
|
|
1183
|
|
|
|
|
|
|
Devel::hdb::Client::Exception::Eval is thrown by eval() when the evaluated |
1184
|
|
|
|
|
|
|
code throws an exception. |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
Devel::hdb::Client::Exception::Error is thrown when data returned from the |
1187
|
|
|
|
|
|
|
debugger is not formatted as expected. |
1188
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
Devel::hdb::Client::Exception::HTTP is thrown when a response is an |
1190
|
|
|
|
|
|
|
unsuccessful response code (4XX, 5XX). The exception's attributes |
1191
|
|
|
|
|
|
|
http_code, http_message and http_content store the code, message |
1192
|
|
|
|
|
|
|
and content from the response. |
1193
|
|
|
|
|
|
|
|
1194
|
|
|
|
|
|
|
=head1 SEE ALSO |
1195
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
L, L |
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
=head1 AUTHOR |
1199
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
Anthony Brummett |
1201
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
=head1 COPYRIGHT |
1203
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
Copyright 2018, Anthony Brummett. This module is free software. It may |
1205
|
|
|
|
|
|
|
be used, redistributed and/or modified under the same terms as Perl itself. |