@@ -19,9 +19,141 @@ package My::CoreDump;
1919use strict;
2020use Carp;
2121use My::Platform;
22+ use Text::Wrap;
23+ use Data::Dumper;
2224
2325use File::Temp qw/ tempfile tempdir / ;
2426use 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+ }
25157
26158my $hint_mysqld ;# Last resort guess for executable path
27159
@@ -50,8 +182,38 @@ sub _verify_binpath {
50182 return $binpath ;
51183}
52184
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+
53213sub _gdb {
54- my ($core_name )= @_ ;
214+ my ($core_name , $code )= @_ ;
215+ confess " Undefined format"
216+ unless defined $code ;
55217
56218 # Check that gdb exists
57219 ` gdb --version` ;
@@ -61,7 +223,7 @@ sub _gdb {
61223 }
62224
63225 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 " ) ;
65227 } else {
66228 print " \n Coredump $core_name does not exist, cannot run 'gdb'\n " ;
67229 return ;
@@ -76,13 +238,7 @@ sub _gdb {
76238
77239 # Create tempfile containing gdb commands
78240 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 ;
86242 close $tmp or die " Error closing $tmp_name : $! " ;
87243
88244 # Run gdb
105261
106262
107263sub _dbx {
108- my ($core_name )= @_ ;
264+ my ($core_name , $format )= @_ ;
109265
110266 print " \n Trying 'dbx' to get a backtrace\n " ;
111267
@@ -167,7 +323,7 @@ sub cdb_check {
167323
168324
169325sub _cdb {
170- my ($core_name )= @_ ;
326+ my ($core_name , $format )= @_ ;
171327 print " \n Trying 'cdb' to get a backtrace\n " ;
172328 return unless -f $core_name ;
173329
@@ -304,32 +460,47 @@ EOF
304460}
305461
306462
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+
307490
308491sub show {
309492 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 };
332500 }
501+ mtr_verbose2(" Printing core with method ${m} :${f} " );
502+ mtr_debug(" code: ${code} " );
503+ $print_methods {$m }-> {method }-> ($core_name , $code );
333504 }
334505 return ;
335506}
0 commit comments