@@ -19,9 +19,141 @@ package My::CoreDump;
19
19
use strict;
20
20
use Carp;
21
21
use My::Platform;
22
+ use Text::Wrap;
23
+ use Data::Dumper;
22
24
23
25
use File::Temp qw/ tempfile tempdir / ;
24
26
use mtr_results;
27
+ use mtr_report;
28
+
29
+ my %opts ;
30
+ my %config ;
31
+ my $help = " \n\n Options for printing core dumps\n\n " ;
32
+
33
+ sub register_opt ($$$) {
34
+ my ($name , $format , $msg )= @_ ;
35
+ my @names = split (/ \| / , $name );
36
+ my $option_name = $names [0];
37
+ $option_name =~ s / -/ _/ ;
38
+ $opts {$name . $format }= \$config {$option_name };
39
+ $help .= wrap(sprintf (" %-23s" , join (' , ' , @names )), ' ' x 25 , " $msg \n " );
40
+ }
41
+
42
+ # To preserve order we use array instead of hash
43
+ my @print_formats = (
44
+ short => {
45
+ description => " Failing stack trace" ,
46
+ codes => {}
47
+ },
48
+ medium => {
49
+ description => " All stack traces" ,
50
+ codes => {}
51
+ },
52
+ detailed => {
53
+ description => " All stack traces with debug context" ,
54
+ codes => {}
55
+ },
56
+ custom => {
57
+ description => " Custom debugger script for printing stack"
58
+ },
59
+ # 'no' must be last (check generated help)
60
+ no => {
61
+ description => " Skip stack trace printing"
62
+ }
63
+ );
64
+
65
+ # TODO: make class for each {method, get_code}
66
+ my @print_methods = (IS_WINDOWS) ? (cdb => { method => \&_cdb }) : (
67
+ gdb => {
68
+ method => \&_gdb,
69
+ get_code => \&_gdb_format,
70
+ },
71
+ dbx => {
72
+ method => \&_dbx
73
+ },
74
+ lldb => {
75
+ method => \&_lldb
76
+ },
77
+ # 'auto' must be last (check generated help)
78
+ auto => {
79
+ method => \&_auto
80
+ }
81
+ );
82
+
83
+ # But we also use hash
84
+ my %print_formats = @print_formats ;
85
+ my %print_methods = @print_methods ;
86
+
87
+ # and scalar
88
+ my $x = 0;
89
+ my $print_formats = join (' , ' , grep { ++$x % 2 } @print_formats );
90
+ $x = 0;
91
+ my $print_methods = join (' , ' , grep { ++$x % 2 } @print_methods );
92
+
93
+ # Fill 'short' and 'detailed' formats per each print_method
94
+ # that has interface for that
95
+ for my $f (keys %print_formats )
96
+ {
97
+ next unless exists $print_formats {$f }-> {codes };
98
+ for my $m (keys %print_methods )
99
+ {
100
+ next unless exists $print_methods {$m }-> {get_code };
101
+ # That calls f.ex. _gdb_format('short')
102
+ # and assigns { gdb => value-of-_gdb_format } into $print_formats{short}->{format}:
103
+ $print_formats {$f }-> {codes }-> {$m }= $print_methods {$m }-> {get_code }-> ($f );
104
+ }
105
+ }
106
+
107
+ register_opt(' print-core|C' , ' :s' ,
108
+ " Print core dump format: " . $print_formats . " (for not printing cores). " .
109
+ " Defaults to value of MTR_PRINT_CORE or 'short'" );
110
+ if (!IS_WINDOWS)
111
+ {
112
+ register_opt(' print-method' , ' =s' ,
113
+ " Print core method: " . join (' , ' , $print_methods ). " (try each method until success). " .
114
+ " Defaults to 'auto'" );
115
+ }
116
+
117
+ sub options () { %opts }
118
+ sub help () { $help }
119
+
120
+
121
+ sub env_or_default ($$) {
122
+ my ($default , $env )= @_ ;
123
+ if (exists $ENV {$env }) {
124
+ my $f = $ENV {$env };
125
+ $f = ' custom'
126
+ if $f =~ m / ^custom:/ ;
127
+ return $ENV {$env }
128
+ if exists $print_formats {$f };
129
+ mtr_verbose(" $env value ignored: $ENV {$env }" );
130
+ }
131
+ return $default ;
132
+ }
133
+
134
+ sub pre_setup () {
135
+ $config {print_core }= env_or_default(' short' , ' MTR_PRINT_CORE' )
136
+ if not defined $config {print_core };
137
+ $config {print_method }= (IS_WINDOWS) ? ' cdb' : ' auto'
138
+ if not defined $config {print_method };
139
+ # If the user has specified 'custom' we fill appropriate print_format
140
+ # and that will be used automatically
141
+ # Note: this can assign 'custom' to method 'auto'.
142
+ if ($config {print_core } =~ m / ^custom:(.+)$ / ) {
143
+ $config {print_core }= ' custom' ;
144
+ $print_formats {' custom' }= {
145
+ $config {print_method } => $1
146
+ }
147
+ }
148
+ mtr_error " Wrong value for --print-core: $config {print_core}"
149
+ if not exists $print_formats {$config {print_core }};
150
+ mtr_error " Wrong value for --print-method: $config {print_method}"
151
+ if not exists $print_methods {$config {print_method }};
152
+
153
+ mtr_debug(Data::Dumper-> Dump(
154
+ [\%config , \%print_formats , \%print_methods ],
155
+ [qw( config print_formats print_methods) ]));
156
+ }
25
157
26
158
my $hint_mysqld ; # Last resort guess for executable path
27
159
@@ -50,8 +182,38 @@ sub _verify_binpath {
50
182
return $binpath ;
51
183
}
52
184
185
+
186
+ # Returns GDB code according to specified format
187
+
188
+ # Note: this is like simple hash, separate interface was made
189
+ # in advance for implementing below TODO
190
+
191
+ # TODO: _gdb_format() and _gdb() should be separate class
192
+ # (like the other printing methods)
193
+
194
+ sub _gdb_format ($) {
195
+ my ($format )= @_ ;
196
+ my %formats = (
197
+ short => " bt\n " ,
198
+ medium => " thread apply all bt\n " ,
199
+ detailed =>
200
+ " bt\n " .
201
+ " set print sevenbit on\n " .
202
+ " set print static-members off\n " .
203
+ " set print frame-arguments all\n " .
204
+ " thread apply all bt full\n " .
205
+ " quit\n "
206
+ );
207
+ confess " Unknown format: " . $format
208
+ unless exists $formats {$format };
209
+ return $formats {$format };
210
+ }
211
+
212
+
53
213
sub _gdb {
54
- my ($core_name )= @_ ;
214
+ my ($core_name , $code )= @_ ;
215
+ confess " Undefined format"
216
+ unless defined $code ;
55
217
56
218
# Check that gdb exists
57
219
` gdb --version` ;
@@ -61,7 +223,7 @@ sub _gdb {
61
223
}
62
224
63
225
if (-f $core_name ) {
64
- print " \n Trying 'gdb' to get a backtrace from coredump $core_name \n " ;
226
+ mtr_verbose( " Trying 'gdb' to get a backtrace from coredump $core_name " ) ;
65
227
} else {
66
228
print " \n Coredump $core_name does not exist, cannot run 'gdb'\n " ;
67
229
return ;
@@ -76,13 +238,7 @@ sub _gdb {
76
238
77
239
# Create tempfile containing gdb commands
78
240
my ($tmp , $tmp_name ) = tempfile();
79
- print $tmp
80
- " bt\n " ,
81
- " set print sevenbit on\n " ,
82
- " set print static-members off\n " ,
83
- " set print frame-arguments all\n " ,
84
- " thread apply all bt full\n " ,
85
- " quit\n " ;
241
+ print $tmp $code ;
86
242
close $tmp or die " Error closing $tmp_name : $! " ;
87
243
88
244
# Run gdb
105
261
106
262
107
263
sub _dbx {
108
- my ($core_name )= @_ ;
264
+ my ($core_name , $format )= @_ ;
109
265
110
266
print " \n Trying 'dbx' to get a backtrace\n " ;
111
267
@@ -167,7 +323,7 @@ sub cdb_check {
167
323
168
324
169
325
sub _cdb {
170
- my ($core_name )= @_ ;
326
+ my ($core_name , $format )= @_ ;
171
327
print " \n Trying 'cdb' to get a backtrace\n " ;
172
328
return unless -f $core_name ;
173
329
@@ -304,32 +460,47 @@ EOF
304
460
}
305
461
306
462
463
+ sub _auto
464
+ {
465
+ my ($core_name , $code , $rest )= @_ ;
466
+ # We use ordered array @print_methods and omit auto itself
467
+ my @valid_methods = @print_methods [0 .. $#print_methods - 2];
468
+ my $x = 0;
469
+ my @methods = grep { ++$x % 2} @valid_methods ;
470
+ my $f = $config {print_core };
471
+ foreach my $m (@methods )
472
+ {
473
+ my $debugger = $print_methods {$m };
474
+ confess " Broken @print_methods "
475
+ if $debugger -> {method } == \&_auto;
476
+ # If we didn't find format for 'auto' (that is only possible for 'custom')
477
+ # we get format for specific debugger
478
+ if (not defined $code && defined $print_formats {$f } and
479
+ exists $print_formats {$f }-> {codes }-> {$m })
480
+ {
481
+ $code = $print_formats {$f }-> {codes }-> {$m };
482
+ }
483
+ mtr_verbose2(" Trying to print with method ${m} :${f} " );
484
+ if ($debugger -> {method }-> ($core_name , $code )) {
485
+ return ;
486
+ }
487
+ }
488
+ }
489
+
307
490
308
491
sub show {
309
492
my ($class , $core_name , $exe_mysqld , $parallel )= @_ ;
310
- $hint_mysqld = $exe_mysqld ;
311
-
312
- # On Windows, rely on cdb to be there...
313
- if (IS_WINDOWS)
314
- {
315
- _cdb($core_name );
316
- return ;
317
- }
318
-
319
- my @debuggers =
320
- (
321
- \&_gdb,
322
- \&_dbx,
323
- \&_lldb,
324
- # TODO...
325
- );
326
-
327
- # Try debuggers until one succeeds
328
-
329
- foreach my $debugger (@debuggers ){
330
- if ($debugger -> ($core_name )){
331
- return ;
493
+ if ($config {print_core } ne ' no' ) {
494
+ my $f = $config {print_core };
495
+ my $m = $config {print_method };
496
+ my $code = undef ;
497
+ if (exists $print_formats {$f }-> {codes } and
498
+ exists $print_formats {$f }-> {codes }-> {$m }) {
499
+ $code = $print_formats {$f }-> {codes }-> {$m };
332
500
}
501
+ mtr_verbose2(" Printing core with method ${m} :${f} " );
502
+ mtr_debug(" code: ${code} " );
503
+ $print_methods {$m }-> {method }-> ($core_name , $code );
333
504
}
334
505
return ;
335
506
}
0 commit comments