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
|
|
|
|
|
|
|
} |