| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# -*- coding: utf-8 -*- |
|
2
|
|
|
|
|
|
|
# Copyright (C) 2011, 2014-2015 Rocky Bernstein <rocky@gnu.org> |
|
3
|
|
|
|
|
|
|
# |
|
4
|
|
|
|
|
|
|
# This program is free software: you can redistribute it and/or modify |
|
5
|
|
|
|
|
|
|
# it under the terms of the GNU General Public License as published by |
|
6
|
|
|
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or |
|
7
|
|
|
|
|
|
|
# (at your option) any later version. |
|
8
|
|
|
|
|
|
|
# |
|
9
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
|
10
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12
|
|
|
|
|
|
|
# GNU General Public License for more details. |
|
13
|
|
|
|
|
|
|
# |
|
14
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License |
|
15
|
|
|
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
#TODO: |
|
18
|
|
|
|
|
|
|
# - Doublecheck handle_pass and other routines. |
|
19
|
|
|
|
|
|
|
# - can remove signal handler altogether when |
|
20
|
|
|
|
|
|
|
# ignore=True, print=False, pass=True |
|
21
|
|
|
|
|
|
|
# |
|
22
|
|
|
|
|
|
|
# |
|
23
|
3
|
|
|
3
|
|
23282
|
use rlib '../..'; |
|
|
3
|
|
|
|
|
8
|
|
|
|
3
|
|
|
|
|
19
|
|
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# Manages Signal Handling information for the debugger |
|
26
|
|
|
|
|
|
|
package Devel::Trepan::SigMgr; |
|
27
|
3
|
|
|
3
|
|
1075
|
use Devel::Trepan::Util; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
351
|
|
|
28
|
3
|
|
|
3
|
|
20
|
use Exporter; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
88
|
|
|
29
|
3
|
|
|
3
|
|
16
|
use vars qw(@EXPORT %signo @signame); |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
198
|
|
|
30
|
|
|
|
|
|
|
@EXPORT = qw( lookup_signum lookup_signame %signo @signame); |
|
31
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
|
32
|
|
|
|
|
|
|
|
|
33
|
3
|
|
|
3
|
|
17
|
use warnings; use strict; |
|
|
3
|
|
|
3
|
|
5
|
|
|
|
3
|
|
|
|
|
57
|
|
|
|
3
|
|
|
|
|
14
|
|
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
87
|
|
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
our %signo; |
|
36
|
|
|
|
|
|
|
our @signame; |
|
37
|
|
|
|
|
|
|
|
|
38
|
3
|
|
|
3
|
|
13
|
use Config; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
6336
|
|
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
my $i=0; |
|
41
|
|
|
|
|
|
|
for my $name (split(' ', $Config{sig_name})) { |
|
42
|
|
|
|
|
|
|
$signo{$name} = $i; |
|
43
|
|
|
|
|
|
|
$signame[$i] = $name; |
|
44
|
|
|
|
|
|
|
$i++; |
|
45
|
|
|
|
|
|
|
} |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Find the corresponding signal name for 'num'. Return undef |
|
49
|
|
|
|
|
|
|
# if 'num' is invalid. |
|
50
|
|
|
|
|
|
|
sub lookup_signame($) |
|
51
|
|
|
|
|
|
|
{ |
|
52
|
74
|
|
|
74
|
|
29494
|
my $num = shift; |
|
53
|
74
|
|
|
|
|
142
|
$num = abs($num); |
|
54
|
74
|
100
|
|
|
|
245
|
return undef unless $num < scalar @signame; |
|
55
|
72
|
|
|
|
|
235
|
return $signame[$num]; |
|
56
|
|
|
|
|
|
|
} |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# Find the corresponding signal number for 'name'. Return under |
|
59
|
|
|
|
|
|
|
# if 'name' is invalid. |
|
60
|
|
|
|
|
|
|
sub lookup_signum($) |
|
61
|
|
|
|
|
|
|
{ |
|
62
|
954
|
|
|
954
|
|
3228
|
my $name = shift; |
|
63
|
954
|
|
|
|
|
1565
|
my $uname = uc $name; |
|
64
|
954
|
100
|
|
|
|
2364
|
$uname = substr($uname, 3) if 0 == index($uname, 'SIG'); |
|
65
|
954
|
100
|
|
|
|
3486
|
return $signo{$uname} if exists $signo{$uname}; |
|
66
|
5
|
|
|
|
|
16
|
return undef; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# Return a signal name for a signal name or signal |
|
70
|
|
|
|
|
|
|
# number. Return undef is $name_num is an int but not a valid signal |
|
71
|
|
|
|
|
|
|
# number and undef if $name_num is a not number. If $name_num is a |
|
72
|
|
|
|
|
|
|
# signal name or signal number, the canonic if name is returned. |
|
73
|
|
|
|
|
|
|
sub canonic_signame($) |
|
74
|
|
|
|
|
|
|
{ |
|
75
|
287
|
|
|
287
|
|
3570
|
my $name_num = shift; |
|
76
|
287
|
|
|
|
|
532
|
my $signum = lookup_signum($name_num); |
|
77
|
287
|
|
|
|
|
454
|
my $signame; |
|
78
|
287
|
100
|
|
|
|
614
|
unless (defined $signum) { |
|
79
|
|
|
|
|
|
|
# Maybe signame is a number? |
|
80
|
4
|
100
|
|
|
|
27
|
if ($name_num =~ /^[+-]?[0-9]+$/) { |
|
81
|
3
|
|
|
|
|
12
|
$signame = lookup_signame($name_num); |
|
82
|
3
|
100
|
|
|
|
16
|
return undef unless defined($signame); |
|
83
|
|
|
|
|
|
|
} else { |
|
84
|
1
|
|
|
|
|
7
|
return undef; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
2
|
|
|
|
|
12
|
return $signame |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
283
|
|
|
|
|
433
|
$signame = uc $name_num; |
|
90
|
283
|
100
|
|
|
|
624
|
return substr($signame, 3) if 0 == index($signame, 'SIG'); |
|
91
|
282
|
|
|
|
|
825
|
return $signame; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
my %FATAL_SIGNALS = ('KILL' => 1, 'STOP' => 1); |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# I copied these from GDB source code. |
|
97
|
|
|
|
|
|
|
my %SIGNAL_DESCRIPTION = ( |
|
98
|
|
|
|
|
|
|
"HUP" => "Hangup", |
|
99
|
|
|
|
|
|
|
"INT" => "Interrupt", |
|
100
|
|
|
|
|
|
|
"QUIT" => "Quit", |
|
101
|
|
|
|
|
|
|
"ILL" => "Illegal instruction", |
|
102
|
|
|
|
|
|
|
"TRAP" => "Trace/breakpoint trap", |
|
103
|
|
|
|
|
|
|
"ABRT" => "Aborted", |
|
104
|
|
|
|
|
|
|
"EMT" => "Emulation trap", |
|
105
|
|
|
|
|
|
|
"FPE" => "Arithmetic exception", |
|
106
|
|
|
|
|
|
|
"KILL" => "Killed", |
|
107
|
|
|
|
|
|
|
"BUS" => "Bus error", |
|
108
|
|
|
|
|
|
|
"SEGV" => "Segmentation fault", |
|
109
|
|
|
|
|
|
|
"SYS" => "Bad system call", |
|
110
|
|
|
|
|
|
|
"PIPE" => "Broken pipe", |
|
111
|
|
|
|
|
|
|
"ALRM" => "Alarm clock", |
|
112
|
|
|
|
|
|
|
"TERM" => "Terminated", |
|
113
|
|
|
|
|
|
|
"URG" => "Urgent I/O condition", |
|
114
|
|
|
|
|
|
|
"STOP" => "Stopped (signal)", |
|
115
|
|
|
|
|
|
|
"TSTP" => "Stopped (user)", |
|
116
|
|
|
|
|
|
|
"CONT" => "Continued", |
|
117
|
|
|
|
|
|
|
"CHLD" => "Child status changed", |
|
118
|
|
|
|
|
|
|
"TTIN" => "Stopped (tty input)", |
|
119
|
|
|
|
|
|
|
"TTOU" => "Stopped (tty output)", |
|
120
|
|
|
|
|
|
|
"IO" => "I/O possible", |
|
121
|
|
|
|
|
|
|
"XCPU" => "CPU time limit exceeded", |
|
122
|
|
|
|
|
|
|
"XFSZ" => "File size limit exceeded", |
|
123
|
|
|
|
|
|
|
"VTALRM" => "Virtual timer expired", |
|
124
|
|
|
|
|
|
|
"PROF" => "Profiling timer expired", |
|
125
|
|
|
|
|
|
|
"WINCH" => "Window size changed", |
|
126
|
|
|
|
|
|
|
"LOST" => "Resource lost", |
|
127
|
|
|
|
|
|
|
"USR1" => "User-defined signal 1", |
|
128
|
|
|
|
|
|
|
"USR2" => "User-defined signal 2", |
|
129
|
|
|
|
|
|
|
"PWR" => "Power fail/restart", |
|
130
|
|
|
|
|
|
|
"POLL" => "Pollable event occurred", |
|
131
|
|
|
|
|
|
|
"WIND" => "WIND", |
|
132
|
|
|
|
|
|
|
"PHONE" => "PHONE", |
|
133
|
|
|
|
|
|
|
"WAITING"=> "Process's LWPs are blocked", |
|
134
|
|
|
|
|
|
|
"LWP" => "Signal LWP", |
|
135
|
|
|
|
|
|
|
"DANGER" => "Swap space dangerously low", |
|
136
|
|
|
|
|
|
|
"GRANT" => "Monitor mode granted", |
|
137
|
|
|
|
|
|
|
"RETRACT"=> "Need to relinquish monitor mode", |
|
138
|
|
|
|
|
|
|
"MSG" => "Monitor mode data available", |
|
139
|
|
|
|
|
|
|
"SOUND" => "Sound completed", |
|
140
|
|
|
|
|
|
|
"SAK" => "Secure attention" |
|
141
|
|
|
|
|
|
|
); |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# Signal Handling information Object for the debugger |
|
145
|
|
|
|
|
|
|
# - Do we print/not print when signal is caught |
|
146
|
|
|
|
|
|
|
# - Do we pass/not pass the signal to the program |
|
147
|
|
|
|
|
|
|
# - Do we stop/not stop when signal is caught |
|
148
|
|
|
|
|
|
|
# |
|
149
|
|
|
|
|
|
|
# Parameter dbgr is a Debugger object. ignore is a list of |
|
150
|
|
|
|
|
|
|
# signals to ignore. If you want no signals, use [] as None uses the |
|
151
|
|
|
|
|
|
|
# default set. Parameter default_print specifies whether or not we |
|
152
|
|
|
|
|
|
|
# print receiving a signals that is not ignored. |
|
153
|
|
|
|
|
|
|
# |
|
154
|
|
|
|
|
|
|
# All the methods which change these attributes return None on error, or |
|
155
|
|
|
|
|
|
|
# True/False if we have set the action (pass/print/stop) for a signal |
|
156
|
|
|
|
|
|
|
# handler. |
|
157
|
|
|
|
|
|
|
sub new($$$$$$) |
|
158
|
|
|
|
|
|
|
{ |
|
159
|
4
|
|
|
4
|
|
489
|
my ($class, $handler, $print_fn, $errprint_fn, $secprint_fn, |
|
160
|
|
|
|
|
|
|
$ignore_list) = @_; |
|
161
|
|
|
|
|
|
|
# Ignore signal handling initially for these known signals. |
|
162
|
4
|
50
|
|
|
|
21
|
unless (defined($ignore_list)) { |
|
163
|
4
|
|
|
|
|
79
|
$ignore_list = { |
|
164
|
|
|
|
|
|
|
'ALRM' => 1, |
|
165
|
|
|
|
|
|
|
'CHLD' => 1, |
|
166
|
|
|
|
|
|
|
'URG' => 1, |
|
167
|
|
|
|
|
|
|
'IO' => 1, |
|
168
|
|
|
|
|
|
|
'CLD' => 1, |
|
169
|
|
|
|
|
|
|
'VTALRM' => 1, |
|
170
|
|
|
|
|
|
|
'PROF' => 1, |
|
171
|
|
|
|
|
|
|
'WINCH' => 1, |
|
172
|
|
|
|
|
|
|
'POLL' => 1, |
|
173
|
|
|
|
|
|
|
'WAITING' => 1, |
|
174
|
|
|
|
|
|
|
'LWP' => 1, |
|
175
|
|
|
|
|
|
|
'CANCEL' => 1, |
|
176
|
|
|
|
|
|
|
'TRAP' => 1, |
|
177
|
|
|
|
|
|
|
'TERM' => 1, |
|
178
|
|
|
|
|
|
|
'TSTP' => 1, |
|
179
|
|
|
|
|
|
|
'QUIT' => 1, |
|
180
|
|
|
|
|
|
|
'ILL' => 1 |
|
181
|
|
|
|
|
|
|
}; |
|
182
|
|
|
|
|
|
|
}; |
|
183
|
|
|
|
|
|
|
|
|
184
|
4
|
|
66
|
|
|
71
|
my $self = { |
|
|
|
|
66
|
|
|
|
|
|
185
|
|
|
|
|
|
|
handler => $handler, |
|
186
|
|
|
|
|
|
|
print_fn => $print_fn, |
|
187
|
|
|
|
|
|
|
errprint_fn => $errprint_fn || $print_fn, |
|
188
|
|
|
|
|
|
|
secprint_fn => $secprint_fn || $print_fn, |
|
189
|
|
|
|
|
|
|
sigs => {}, |
|
190
|
|
|
|
|
|
|
ignore_list => $ignore_list, |
|
191
|
|
|
|
|
|
|
orig_set_signal => \%SIG, |
|
192
|
|
|
|
|
|
|
info_fmt => "%-14s%-4s\t%-4s\t%-5s\t%-4s\t%s", |
|
193
|
|
|
|
|
|
|
}; |
|
194
|
|
|
|
|
|
|
|
|
195
|
4
|
|
|
|
|
15
|
bless $self, $class; |
|
196
|
|
|
|
|
|
|
|
|
197
|
4
|
|
|
|
|
58
|
$self->{header} = sprintf($self->{info_fmt}, 'Signal', 'Stop', 'Print', |
|
198
|
|
|
|
|
|
|
'Stack', 'Pass', 'Description'); |
|
199
|
|
|
|
|
|
|
|
|
200
|
4
|
|
|
|
|
80
|
for my $signame (keys %SIG) { |
|
201
|
272
|
|
|
|
|
614
|
initialize_handler($self, $signame); |
|
202
|
272
|
100
|
100
|
|
|
1081
|
next if $signame eq 'CHLD' || $signame eq 'CLD'; |
|
203
|
264
|
|
|
|
|
540
|
$self->check_and_adjust_sighandler($signame); |
|
204
|
|
|
|
|
|
|
} |
|
205
|
4
|
|
|
|
|
41
|
$self->action('INT stop print nostack nopass'); |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# printing WINCH is annoying, especially in Emacs |
|
208
|
4
|
|
|
|
|
51
|
$self->action('WINCH nostop noprint nostack pass'); |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
# for my $sig ('CHLD', 'CLD') { |
|
211
|
|
|
|
|
|
|
# $self->action("$sig nostop noprint nostack pass") if exists $SIG{$sig}; |
|
212
|
|
|
|
|
|
|
# } |
|
213
|
4
|
|
|
|
|
37
|
$self; |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub initialize_handler($$) |
|
217
|
|
|
|
|
|
|
{ |
|
218
|
272
|
|
|
272
|
|
526
|
my ($self, $sig) = @_; |
|
219
|
272
|
|
|
|
|
492
|
my $signame = canonic_signame($sig); |
|
220
|
272
|
50
|
|
|
|
591
|
return 0 unless defined($signame); |
|
221
|
272
|
100
|
|
|
|
593
|
return 0 if exists($FATAL_SIGNALS{$signame}); |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# try: |
|
224
|
|
|
|
|
|
|
# except ValueError: |
|
225
|
|
|
|
|
|
|
# On some OS's (Redhat 8), SIGNUM's are listed (like |
|
226
|
|
|
|
|
|
|
# SIGRTMAX) that getsignal can't handle. |
|
227
|
|
|
|
|
|
|
# if (exists($self->{sigs}{$signame})) { |
|
228
|
|
|
|
|
|
|
# $self->{sigs}->pop($signame); |
|
229
|
|
|
|
|
|
|
# } |
|
230
|
|
|
|
|
|
|
|
|
231
|
264
|
|
|
|
|
460
|
my $signum = lookup_signum($signame); |
|
232
|
264
|
|
|
|
|
480
|
my $print_fn = $self->{print_fn}; |
|
233
|
264
|
100
|
|
|
|
549
|
if (exists($self->{ignore_list}{$signame})) { |
|
234
|
|
|
|
|
|
|
$self->{sigs}{$signame} = |
|
235
|
|
|
|
|
|
|
Devel::Trepan::SigHandler->new($print_fn, $signame, |
|
236
|
56
|
|
|
|
|
138
|
$self->{handler}, 0, 0, 1); |
|
237
|
|
|
|
|
|
|
} else { |
|
238
|
|
|
|
|
|
|
$self->{sigs}{$signame} = |
|
239
|
|
|
|
|
|
|
Devel::Trepan::SigHandler->new($print_fn, $signame, |
|
240
|
208
|
|
|
|
|
468
|
$self->{handler}, 1, 0, 0); |
|
241
|
|
|
|
|
|
|
} |
|
242
|
264
|
|
|
|
|
438
|
return 1; |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# Check to see if a single signal handler that we are interested in |
|
246
|
|
|
|
|
|
|
# has changed or has not been set initially. On return self->{sigs}{$signame} |
|
247
|
|
|
|
|
|
|
# should have our signal handler. True is returned if the same or adjusted, |
|
248
|
|
|
|
|
|
|
# False or undef if error or not found. |
|
249
|
|
|
|
|
|
|
sub check_and_adjust_sighandler($$) |
|
250
|
|
|
|
|
|
|
{ |
|
251
|
272
|
|
|
272
|
|
472
|
my ($self, $signame) = @_; |
|
252
|
272
|
|
|
|
|
447
|
my $sigs = $self->{sigs}; |
|
253
|
|
|
|
|
|
|
# try: |
|
254
|
272
|
|
|
|
|
494
|
my $current_handler = $SIG{$signame}; |
|
255
|
|
|
|
|
|
|
# except ValueError: |
|
256
|
|
|
|
|
|
|
# On some OS's (Redhat 8), SIGNUM's are listed (like |
|
257
|
|
|
|
|
|
|
# SIGRTMAX) that getsignal can't handle. |
|
258
|
|
|
|
|
|
|
#if signame in self.sigs: |
|
259
|
|
|
|
|
|
|
# sigs.pop(signame) |
|
260
|
|
|
|
|
|
|
# pass |
|
261
|
|
|
|
|
|
|
# return None |
|
262
|
272
|
|
|
|
|
412
|
my $sig = $sigs->{$signame}; |
|
263
|
272
|
100
|
66
|
|
|
992
|
if (!defined($current_handler) || |
|
|
|
|
100
|
|
|
|
|
|
264
|
|
|
|
|
|
|
(defined($sig->{handle}) && $current_handler ne $sig->{handle})) { |
|
265
|
|
|
|
|
|
|
# if old_handler not in [signal.SIG_IGN, signal.SIG_DFL]: |
|
266
|
|
|
|
|
|
|
# Save the debugged program's signal handler |
|
267
|
264
|
100
|
|
|
|
553
|
$sig->{old_handler} = $current_handler if defined $current_handler; |
|
268
|
|
|
|
|
|
|
# (re)set signal handler the debugger signal handler. |
|
269
|
|
|
|
|
|
|
# |
|
270
|
264
|
100
|
|
|
|
566
|
if (exists $sig->{handle}) { |
|
271
|
256
|
|
|
|
|
987
|
$SIG{$signame} = $sig->{handle}; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
} |
|
274
|
272
|
|
|
|
|
580
|
return 1; |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# Check to see if any of the signal handlers we are interested in have |
|
278
|
|
|
|
|
|
|
# changed or is not initially set. Change any that are not right. |
|
279
|
|
|
|
|
|
|
sub check_and_adjust_sighandlers($) |
|
280
|
|
|
|
|
|
|
{ |
|
281
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
282
|
0
|
|
|
|
|
0
|
for my $signame (keys %{$self->{sigs}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
283
|
0
|
0
|
|
|
|
0
|
last unless ($self->check_and_adjust_sighandler($signame)); |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
# Print status for a single signal name (signame) |
|
288
|
|
|
|
|
|
|
sub print_info_signal_entry($$) |
|
289
|
|
|
|
|
|
|
{ |
|
290
|
0
|
|
|
0
|
|
0
|
my ($self, $signame) = @_; |
|
291
|
|
|
|
|
|
|
my $description = (exists $SIGNAL_DESCRIPTION{$signame}) ? |
|
292
|
0
|
0
|
|
|
|
0
|
$SIGNAL_DESCRIPTION{$signame} : ''; |
|
293
|
0
|
|
|
|
|
0
|
my $msg; |
|
294
|
0
|
|
|
|
|
0
|
my $sig_obj = $self->{sigs}{$signame}; |
|
295
|
0
|
0
|
|
|
|
0
|
if (exists $self->{sigs}{$signame}) { |
|
296
|
|
|
|
|
|
|
$msg = sprintf($self->{info_fmt}, $signame, |
|
297
|
|
|
|
|
|
|
bool2YN($sig_obj->{b_stop}), |
|
298
|
|
|
|
|
|
|
bool2YN($sig_obj->{print_fn}), |
|
299
|
|
|
|
|
|
|
bool2YN($sig_obj->{print_stack}), |
|
300
|
0
|
|
|
|
|
0
|
bool2YN($sig_obj->{pass_along}), |
|
301
|
|
|
|
|
|
|
$description); |
|
302
|
|
|
|
|
|
|
} else { |
|
303
|
|
|
|
|
|
|
# Fake up an entry as though signame were in sigs. |
|
304
|
0
|
|
|
|
|
0
|
$msg = sprintf($self->{info_fmt}, $signame, |
|
305
|
|
|
|
|
|
|
'No', 'No', 'No', 'Yes', $description); |
|
306
|
|
|
|
|
|
|
} |
|
307
|
0
|
|
|
|
|
0
|
$self->{print_fn}->($msg); |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# Print information about a signal |
|
311
|
|
|
|
|
|
|
sub info_signal($$) |
|
312
|
|
|
|
|
|
|
{ |
|
313
|
0
|
|
|
0
|
|
0
|
my ($self, $args) = @_; |
|
314
|
0
|
|
|
|
|
0
|
my @args = @$args; |
|
315
|
0
|
|
|
|
|
0
|
my $print_fn = $self->{print_fn}; |
|
316
|
0
|
|
|
|
|
0
|
my $secprint_fn = $self->{secprint_fn}; |
|
317
|
0
|
0
|
|
|
|
0
|
@args = @signame if (0 == scalar @args); |
|
318
|
0
|
|
|
|
|
0
|
$secprint_fn->($self->{header}); |
|
319
|
0
|
|
|
|
|
0
|
for my $signame (@args) { |
|
320
|
0
|
|
|
|
|
0
|
my $canonic_signame = canonic_signame($signame); |
|
321
|
0
|
0
|
|
|
|
0
|
if (defined($canonic_signame)) { |
|
322
|
0
|
|
|
|
|
0
|
$self->print_info_signal_entry($canonic_signame); |
|
323
|
|
|
|
|
|
|
} else { |
|
324
|
0
|
|
|
|
|
0
|
$self->{errprint_fn}->("$signame is not a signal I know about"); |
|
325
|
|
|
|
|
|
|
} |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# Delegate the actions specified in string $arg to another |
|
330
|
|
|
|
|
|
|
# method. |
|
331
|
|
|
|
|
|
|
sub action($$) |
|
332
|
|
|
|
|
|
|
{ |
|
333
|
8
|
|
|
8
|
|
28
|
my ($self, $arg) = @_; |
|
334
|
8
|
50
|
|
|
|
30
|
if (!defined($arg)) { |
|
335
|
0
|
|
|
|
|
0
|
$self->info_signal(['handle']); |
|
336
|
0
|
|
|
|
|
0
|
return 1; |
|
337
|
|
|
|
|
|
|
} |
|
338
|
8
|
|
|
|
|
50
|
my @args = split ' ', $arg; |
|
339
|
8
|
|
|
|
|
29
|
my $signame = canonic_signame(shift @args); |
|
340
|
8
|
50
|
|
|
|
30
|
return 0 unless defined $signame; |
|
341
|
|
|
|
|
|
|
|
|
342
|
8
|
50
|
|
|
|
34
|
if (scalar @args == 0) { |
|
343
|
0
|
|
|
|
|
0
|
$self->info_signal([$signame]); |
|
344
|
0
|
|
|
|
|
0
|
return 1; |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
# We can display information about 'fatal' signals, but not |
|
348
|
|
|
|
|
|
|
# change their actions. |
|
349
|
8
|
50
|
|
|
|
29
|
return 0 if (exists $FATAL_SIGNALS{$signame}); |
|
350
|
|
|
|
|
|
|
|
|
351
|
8
|
50
|
|
|
|
28
|
unless (exists $self->{sigs}{$signame}) { |
|
352
|
0
|
0
|
|
|
|
0
|
return 0 unless $self->initialize_handler($signame); |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
# multiple commands might be specified, i.e. 'nopass nostop' |
|
356
|
8
|
|
|
|
|
27
|
for my $attr (@args) { |
|
357
|
32
|
|
|
|
|
50
|
my $on = 1; |
|
358
|
32
|
100
|
|
|
|
87
|
if (0 == index($attr, 'no')) { |
|
359
|
20
|
|
|
|
|
36
|
$on = 0; |
|
360
|
20
|
|
|
|
|
46
|
$attr = substr($attr, 2); |
|
361
|
|
|
|
|
|
|
} |
|
362
|
32
|
100
|
|
|
|
126
|
if (0 == index($attr, 'stop')) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
363
|
8
|
|
|
|
|
31
|
$self->handle_stop($signame, $on); |
|
364
|
|
|
|
|
|
|
} elsif (0 == index($attr, 'print')) { |
|
365
|
8
|
|
|
|
|
33
|
$self->handle_print($signame, $on); |
|
366
|
|
|
|
|
|
|
} elsif (0 == index($attr, 'pass')) { |
|
367
|
8
|
|
|
|
|
26
|
$self->handle_pass($signame, $on); |
|
368
|
|
|
|
|
|
|
} elsif (0 == index($attr, 'ignore')) { |
|
369
|
0
|
|
|
|
|
0
|
$self->handle_ignore($signame, $on); |
|
370
|
|
|
|
|
|
|
} elsif (0 == index($attr, 'stack')) { |
|
371
|
8
|
|
|
|
|
35
|
$self->handle_print_stack($signame, $on); |
|
372
|
|
|
|
|
|
|
} else { |
|
373
|
0
|
|
|
|
|
0
|
$self->{errprint_fn}->("Invalid argument $attr"); |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
} |
|
376
|
8
|
|
|
|
|
27
|
$self->check_and_adjust_sighandler($signame); |
|
377
|
8
|
|
|
|
|
21
|
return 1; |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# Set whether we stop or not when this signal is caught. |
|
382
|
|
|
|
|
|
|
# If 'set_stop' is True your program will stop when this signal |
|
383
|
|
|
|
|
|
|
# happens. |
|
384
|
|
|
|
|
|
|
sub handle_print_stack($$$) |
|
385
|
|
|
|
|
|
|
{ |
|
386
|
8
|
|
|
8
|
|
26
|
my ($self, $signame, $print_stack) = @_; |
|
387
|
8
|
|
|
|
|
24
|
$self->{sigs}{$signame}{print_stack} = $print_stack; |
|
388
|
|
|
|
|
|
|
} |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
# Set whether we stop or not when this signal is caught. |
|
391
|
|
|
|
|
|
|
# If 'set_stop' is True your program will stop when this signal |
|
392
|
|
|
|
|
|
|
# happens. |
|
393
|
|
|
|
|
|
|
sub handle_stop($$$) |
|
394
|
|
|
|
|
|
|
{ |
|
395
|
8
|
|
|
8
|
|
21
|
my ($self, $signame, $set_stop) = @_; |
|
396
|
8
|
100
|
|
|
|
26
|
if ($set_stop) { |
|
397
|
4
|
|
|
|
|
15
|
$self->{sigs}{$signame}{b_stop} = 1; |
|
398
|
|
|
|
|
|
|
# stop keyword implies print AND nopass |
|
399
|
4
|
|
|
|
|
14
|
$self->{sigs}{$signame}{print_fn} = $self->{print_fn}; |
|
400
|
4
|
|
|
|
|
13
|
$self->{sigs}{$signame}{pass_along} = 0; |
|
401
|
|
|
|
|
|
|
} else { |
|
402
|
4
|
|
|
|
|
14
|
$self->{sigs}{$signame}{b_stop} = 0; |
|
403
|
|
|
|
|
|
|
} |
|
404
|
|
|
|
|
|
|
} |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
# Set whether we pass this signal to the program (or not) |
|
407
|
|
|
|
|
|
|
# when this signal is caught. If set_pass is True, Dbgr should allow |
|
408
|
|
|
|
|
|
|
# your program to see this signal. |
|
409
|
|
|
|
|
|
|
sub handle_pass($$$) |
|
410
|
|
|
|
|
|
|
{ |
|
411
|
8
|
|
|
8
|
|
21
|
my ($self, $signame, $set_pass) = @_; |
|
412
|
8
|
|
|
|
|
20
|
$self->{sigs}{$signame}{pass_along} = $set_pass; |
|
413
|
8
|
100
|
|
|
|
30
|
if ($set_pass) { |
|
414
|
|
|
|
|
|
|
# Pass implies nostop |
|
415
|
4
|
|
|
|
|
14
|
$self->{sigs}{$signame}{b_stop} = 0; |
|
416
|
|
|
|
|
|
|
} |
|
417
|
|
|
|
|
|
|
} |
|
418
|
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
# 'pass' and 'noignore' are synonyms. 'nopass and 'ignore' are |
|
420
|
|
|
|
|
|
|
# synonyms. |
|
421
|
|
|
|
|
|
|
sub handle_ignore($$$) |
|
422
|
|
|
|
|
|
|
{ |
|
423
|
0
|
|
|
0
|
|
0
|
my ($self, $signame, $set_ignore) = @_; |
|
424
|
0
|
|
|
|
|
0
|
$self->handle_pass($signame, !$set_ignore); |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
# Set whether we print or not when this signal is caught. |
|
428
|
|
|
|
|
|
|
sub handle_print($$$) |
|
429
|
|
|
|
|
|
|
{ |
|
430
|
8
|
|
|
8
|
|
25
|
my ($self, $signame, $set_print) = @_; |
|
431
|
8
|
100
|
|
|
|
24
|
if ($set_print) { |
|
432
|
4
|
|
|
|
|
20
|
$self->{sigs}{$signame}{print_fn} = $self->{print_fn}; |
|
433
|
|
|
|
|
|
|
} else { |
|
434
|
4
|
|
|
|
|
14
|
$self->{sigs}{$signame}{print_fn} = undef; |
|
435
|
|
|
|
|
|
|
} |
|
436
|
|
|
|
|
|
|
} |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# Store information about what we do when we handle a signal, |
|
439
|
|
|
|
|
|
|
# |
|
440
|
|
|
|
|
|
|
# - Do we print/not print when signal is caught |
|
441
|
|
|
|
|
|
|
# - Do we pass/not pass the signal to the program |
|
442
|
|
|
|
|
|
|
# - Do we stop/not stop when signal is caught |
|
443
|
|
|
|
|
|
|
# |
|
444
|
|
|
|
|
|
|
# Parameters: |
|
445
|
|
|
|
|
|
|
# signame : name of signal (e.g. SIGUSR1 or USR1) |
|
446
|
|
|
|
|
|
|
# print_fn routine to use for "print" |
|
447
|
|
|
|
|
|
|
# stop routine to call to invoke debugger when stopping |
|
448
|
|
|
|
|
|
|
# pass_along: True is signal is to be passed to user's handler |
|
449
|
|
|
|
|
|
|
package Devel::Trepan::SigHandler; |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
sub new($$$$$;$$) |
|
452
|
|
|
|
|
|
|
{ |
|
453
|
264
|
|
|
264
|
0
|
540
|
my($class, $print_fn, $signame, $handler, |
|
454
|
|
|
|
|
|
|
$b_stop, $print_stack, $pass_along) = @_; |
|
455
|
|
|
|
|
|
|
|
|
456
|
264
|
50
|
|
|
|
557
|
$print_stack = 0 unless defined $print_stack; |
|
457
|
264
|
50
|
|
|
|
520
|
$pass_along = 1 unless defined $pass_along; |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
my $self = { |
|
460
|
|
|
|
|
|
|
print_fn => $print_fn, |
|
461
|
|
|
|
|
|
|
handler => $handler, |
|
462
|
264
|
|
|
|
|
698
|
old_handler => $SIG{$signame}, |
|
463
|
|
|
|
|
|
|
pass_along => $pass_along, |
|
464
|
|
|
|
|
|
|
print_stack => $print_stack, |
|
465
|
|
|
|
|
|
|
signame => $signame, |
|
466
|
|
|
|
|
|
|
signum => Devel::Trepan::SigMgr::lookup_signum($signame), |
|
467
|
|
|
|
|
|
|
b_stop => $b_stop, |
|
468
|
|
|
|
|
|
|
}; |
|
469
|
264
|
|
|
|
|
521
|
bless $self, $class; |
|
470
|
264
|
|
|
0
|
|
953
|
$self->{handle} = sub{ $self->handle(@_) }; |
|
|
0
|
|
|
|
|
0
|
|
|
471
|
264
|
|
|
|
|
732
|
$self; |
|
472
|
|
|
|
|
|
|
} |
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
# This method is called when a signal is received. |
|
475
|
|
|
|
|
|
|
sub handle |
|
476
|
|
|
|
|
|
|
{ |
|
477
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
|
478
|
0
|
|
|
|
|
|
my $signame = $self->{signame}; |
|
479
|
0
|
0
|
0
|
|
|
|
if (exists($self->{print_fn}) && $self->{print_fn}) { |
|
480
|
0
|
|
|
|
|
|
my $msg = sprintf("\ntrepan.pl: Program received signal $signame."); |
|
481
|
0
|
|
|
|
|
|
$self->{print_fn}->($msg); |
|
482
|
|
|
|
|
|
|
} |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# if ($self->{print_stack}) { |
|
485
|
|
|
|
|
|
|
# import traceback; |
|
486
|
|
|
|
|
|
|
# my @strings = traceback.format_stack(frame); |
|
487
|
|
|
|
|
|
|
# for my $s (@strings) { |
|
488
|
|
|
|
|
|
|
# chomp $s; |
|
489
|
|
|
|
|
|
|
# $self->{print_fn}->($s); |
|
490
|
|
|
|
|
|
|
# } |
|
491
|
|
|
|
|
|
|
# } |
|
492
|
|
|
|
|
|
|
|
|
493
|
0
|
0
|
|
|
|
|
if ($self->{b_stop}) { |
|
494
|
0
|
|
|
|
|
|
$self->{handler}->($signame); |
|
495
|
|
|
|
|
|
|
} |
|
496
|
|
|
|
|
|
|
|
|
497
|
0
|
0
|
|
|
|
|
if ($self->{pass_along}) { |
|
498
|
|
|
|
|
|
|
# pass the signal to the program |
|
499
|
0
|
0
|
|
|
|
|
if ($self->{old_handler}) { |
|
500
|
0
|
0
|
|
|
|
|
if (ref($self->{old_handler})) { |
|
|
|
0
|
|
|
|
|
|
|
501
|
0
|
|
|
|
|
|
$self->{old_handler}->($signame); |
|
502
|
|
|
|
|
|
|
} elsif ($self->{old_handler}) { |
|
503
|
0
|
0
|
0
|
|
|
|
eval {$self->{old_handler}($signame)}; warn $@ if $@ and $^W; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
} |
|
505
|
|
|
|
|
|
|
} else { |
|
506
|
|
|
|
|
|
|
# Set default and reraise |
|
507
|
0
|
0
|
|
|
|
|
if ($signame eq 'TSTP') { |
|
508
|
|
|
|
|
|
|
# in principle, SIGSTOP cannot be trapped. |
|
509
|
|
|
|
|
|
|
# This also might not work on Windows |
|
510
|
0
|
|
|
|
|
|
return kill 'STOP', $$; |
|
511
|
|
|
|
|
|
|
} else { |
|
512
|
0
|
|
|
|
|
|
$SIG{$signame} = 'DEFAULT'; |
|
513
|
0
|
|
|
|
|
|
kill $signame, $$; |
|
514
|
|
|
|
|
|
|
} |
|
515
|
|
|
|
|
|
|
# $SIG{$signame} = $self->{handle}; |
|
516
|
|
|
|
|
|
|
} |
|
517
|
|
|
|
|
|
|
} |
|
518
|
|
|
|
|
|
|
} |
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
# When invoked as main program, do some basic tests of a couple of functions |
|
521
|
|
|
|
|
|
|
unless (caller) { |
|
522
|
|
|
|
|
|
|
print join(', ', keys %Devel::Trepan::SigMgr::signo), "\n"; |
|
523
|
|
|
|
|
|
|
print join(', ', sort {$a <=> $b} values %Devel::Trepan::SigMgr::signo), "\n"; |
|
524
|
|
|
|
|
|
|
for my $i (15, -15, 300) { |
|
525
|
|
|
|
|
|
|
printf("lookup_signame(%d) => %s\n", $i, |
|
526
|
|
|
|
|
|
|
Devel::Trepan::SigMgr::lookup_signame($i) || 'undef'); |
|
527
|
|
|
|
|
|
|
} |
|
528
|
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
for my $sig ('term', 'TERM', 'NotThere') { |
|
530
|
|
|
|
|
|
|
printf("lookup_signum(%s) => %s\n", $sig, |
|
531
|
|
|
|
|
|
|
Devel::Trepan::SigMgr::lookup_signum($sig) || 'undef'); |
|
532
|
|
|
|
|
|
|
} |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
for my $i ('15', '-15', 'term', 'sigterm', 'TERM', '300', 'bogus') { |
|
535
|
|
|
|
|
|
|
printf("canonic_signame(%s) => %s\n", $i, |
|
536
|
|
|
|
|
|
|
Devel::Trepan::SigMgr::canonic_signame($i) || 'undef'); |
|
537
|
|
|
|
|
|
|
} |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
my $h; # Is used in myhandler. |
|
540
|
|
|
|
|
|
|
eval <<'EOE'; # Have to eval else fns defined when caller() is false |
|
541
|
|
|
|
|
|
|
sub do_action($$$) { |
|
542
|
|
|
|
|
|
|
my ($h, $arg, $sig) = @_; |
|
543
|
|
|
|
|
|
|
print "$arg\n"; |
|
544
|
|
|
|
|
|
|
$h->action($arg); |
|
545
|
|
|
|
|
|
|
} |
|
546
|
|
|
|
|
|
|
sub myprint($) { |
|
547
|
|
|
|
|
|
|
my $msg = shift; |
|
548
|
|
|
|
|
|
|
print "$msg\n"; |
|
549
|
|
|
|
|
|
|
} |
|
550
|
|
|
|
|
|
|
sub orig_sighandler($) { |
|
551
|
|
|
|
|
|
|
my $name = shift; |
|
552
|
|
|
|
|
|
|
print "++ Orig Signal $name caught\n"; |
|
553
|
|
|
|
|
|
|
$h->info_signal(["USR1"]); |
|
554
|
|
|
|
|
|
|
} |
|
555
|
|
|
|
|
|
|
sub stop_sighandler($) { |
|
556
|
|
|
|
|
|
|
my $name = shift; |
|
557
|
|
|
|
|
|
|
print "++ Stop Signal $name caught\n"; |
|
558
|
|
|
|
|
|
|
$h->info_signal(["USR1"]); |
|
559
|
|
|
|
|
|
|
} |
|
560
|
|
|
|
|
|
|
EOE |
|
561
|
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
$SIG{'USR1'} = \&orig_sighandler; |
|
563
|
|
|
|
|
|
|
$h = Devel::Trepan::SigMgr->new(\&stop_sighandler, \&myprint); |
|
564
|
|
|
|
|
|
|
$h->info_signal(["TRAP"]); |
|
565
|
|
|
|
|
|
|
# USR1 is set to known value |
|
566
|
|
|
|
|
|
|
$h->action('SIGUSR1'); |
|
567
|
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
do_action($h, 'usr1 print pass', 'USR1'); |
|
569
|
|
|
|
|
|
|
$h->info_signal(['USR1']); |
|
570
|
|
|
|
|
|
|
# noprint implies no stop |
|
571
|
|
|
|
|
|
|
# do_action($h, 'usr1 noprint'); |
|
572
|
|
|
|
|
|
|
print '-' x 30, "\n"; |
|
573
|
|
|
|
|
|
|
kill 10, $$; |
|
574
|
|
|
|
|
|
|
do_action($h, 'foo nostop'); |
|
575
|
|
|
|
|
|
|
do_action($h, 'usr1 print nopass', 'USR1'); |
|
576
|
|
|
|
|
|
|
$h->info_signal(['USR1']); |
|
577
|
|
|
|
|
|
|
kill 10, $$; |
|
578
|
|
|
|
|
|
|
# stop keyword implies print |
|
579
|
|
|
|
|
|
|
do_action($h, 'USR1 stop', 'USR1'); |
|
580
|
|
|
|
|
|
|
$h->info_signal(['USR2', 'USR1']); |
|
581
|
|
|
|
|
|
|
kill 10, $$; |
|
582
|
|
|
|
|
|
|
# h.action('SIGUSR1 noprint') |
|
583
|
|
|
|
|
|
|
print '-' x 30, "\n"; |
|
584
|
|
|
|
|
|
|
$h->info_signal([]); |
|
585
|
|
|
|
|
|
|
# $h->action('SIGUSR1 nopass stack'); |
|
586
|
|
|
|
|
|
|
# $h->info_signal(['SIGUSR1']); |
|
587
|
|
|
|
|
|
|
} |