4444#include "internal/symbol.h"
4545#include "internal/thread.h"
4646#include "internal/variable.h"
47+ #include "internal/util.h"
4748#include "ruby/encoding.h"
4849#include "ruby/st.h"
4950#include "ruby/util.h"
@@ -866,45 +867,124 @@ expand_report_argument(const char **input_template, struct report_expansion *val
866867
867868FILE * ruby_popen_writer (char * const * argv , rb_pid_t * pid );
868869
870+ struct crash_report_config {
871+ struct vm_dump_conf dump ;
872+ const char * begin ;
873+ int len ;
874+ bool pipe ; // write to pipe
875+ };
876+
877+ static bool
878+ boolconv (const char * word , int len , bool * ret )
879+ {
880+ #define boolword (n , v ) \
881+ if (len == rb_strlen_lit(#n) && strncmp(word, #n, len) == 0) {*ret = v; return true;}
882+ boolword (false, false);
883+ boolword (true, true);
884+ boolword (yes , true);
885+ boolword (no , false);
886+ #undef boolword
887+ if (len == 1 ) {
888+ switch (* word ) {
889+ case 't' : case 'y' : case '1' : * ret = true; return true;
890+ case 'f' : case 'n' : case '0' : * ret = false; return true;
891+ }
892+ }
893+ return false;
894+ }
895+
896+ static int
897+ handle_crash_report_word (const char * word , int len , void * arg )
898+ {
899+ struct crash_report_config * cf = arg ;
900+ #define isconfname (conf ) \
901+ (len > (int)sizeof(#conf) && strncmp(word, #conf "=", sizeof(#conf)) == 0 ? \
902+ (word += sizeof(#conf), len -= sizeof(#conf), 1) : 0)
903+ #define boolconf (conf ) \
904+ if (isconfname(conf)) { \
905+ bool v = cf->dump.conf; \
906+ if (boolconv(word, len, &v)) cf->dump.conf = v; \
907+ return 0; \
908+ }
909+ if (isconfname (dump )) {
910+ bool v ;
911+ if (boolconv (word , len , & v )) {
912+ cf -> dump .bt = v ;
913+ cf -> dump .vmbt = v ;
914+ cf -> dump .cbt = v ;
915+ cf -> dump .box = v ;
916+ cf -> dump .thread = v ;
917+ cf -> dump .regs = v ;
918+ cf -> dump .lf = v ;
919+ cf -> dump .mm = v ;
920+ cf -> dump .additional = v ;
921+ }
922+ return 0 ;
923+ }
924+ boolconf (bt );
925+ boolconf (vmbt );
926+ boolconf (cbt );
927+ boolconf (box );
928+ boolconf (thread );
929+ boolconf (regs );
930+ boolconf (lf );
931+ boolconf (mm );
932+ if (!cf -> begin ) {
933+ if (word [0 ] == '|' || isconfname (pipe )) {
934+ if (* ++ word ) cf -> begin = word ;
935+ cf -> pipe = true;
936+ return 1 ;
937+ }
938+ else {
939+ isconfname (path ); // skip "path="
940+ cf -> begin = word ;
941+ cf -> len = len ;
942+ return 0 ;
943+ }
944+ }
945+ return 0 ;
946+ }
947+
869948static FILE *
870- open_report_path (const char * template , char * buf , size_t size , rb_pid_t * pid )
949+ open_report_path (struct crash_report_config * conf , char * buf , size_t size , rb_pid_t * pid )
871950{
872951 struct report_expansion values = {{0 }};
873-
874- if (!template ) return NULL ;
875- if (0 ) fprintf (stderr , "RUBY_CRASH_REPORT=%s\n" , buf );
876- if (* template == '|' ) {
952+ const char * str = conf -> begin ;
953+ if (!str ) return NULL ;
954+ if (conf -> pipe ) {
877955 char * argv [16 ], * bufend = buf + size , * p ;
878956 int argc ;
879- template ++ ;
880957 for (argc = 0 ; argc < numberof (argv ) - 1 ; ++ argc ) {
881- while (* template && ISSPACE (* template )) template ++ ;
882- p = expand_report_argument (& template , & values , buf , bufend - buf , true);
958+ while (* str && ISSPACE (* str )) str ++ ;
959+ p = expand_report_argument (& str , & values , buf , bufend - buf , true);
883960 if (!p ) break ;
884961 argv [argc ] = buf ;
885962 buf = p ;
886963 }
887964 argv [argc ] = NULL ;
888965 if (!p ) return ruby_popen_writer (argv , pid );
889966 }
890- else if (* template ) {
891- expand_report_argument (& template , & values , buf , size , false);
967+ else if (* str ) {
968+ expand_report_argument (& str , & values , buf , size , false);
892969 return fopen (buf , "w" );
893970 }
894971 return NULL ;
895972}
896973
897- static const char * crash_report ;
974+ static struct crash_report_config crash_report = { VM_DUMP_CONF_DEFAULT } ;
898975
899976/* SIGSEGV handler might have a very small stack. Thus we need to use it carefully. */
900977#define REPORT_BUG_BUFSIZ 256
901978static FILE *
902979bug_report_file (const char * file , int line , rb_pid_t * pid )
903980{
904981 char buf [REPORT_BUG_BUFSIZ ];
905- const char * report = crash_report ;
906- if (!report ) report = getenv ("RUBY_CRASH_REPORT" );
907- FILE * out = open_report_path (report , buf , sizeof (buf ), pid );
982+ if (!crash_report .begin ) {
983+ const char * report = getenv ("RUBY_CRASH_REPORT" );
984+ if (0 ) fprintf (stderr , "RUBY_CRASH_REPORT=%s\n" , report );
985+ if (report ) ruby_set_crash_report (report );
986+ }
987+ FILE * out = open_report_path (& crash_report , buf , sizeof (buf ), pid );
908988 int len = err_position_0 (buf , sizeof (buf ), file , line );
909989
910990 if (out ) {
@@ -1011,7 +1091,7 @@ bug_report_begin_valist(FILE *out, const char *fmt, va_list args)
10111091 fputs (buf , out );
10121092 snprintf (buf , sizeof (buf ), "\n%s\n\n" , rb_dynamic_description );
10131093 fputs (buf , out );
1014- preface_dump (out );
1094+ if ( vm_dump_conf_enabled_any ( & crash_report . dump )) preface_dump (out );
10151095}
10161096
10171097#define bug_report_begin (out , fmt ) do { \
@@ -1025,14 +1105,14 @@ static void
10251105bug_report_end (FILE * out , rb_pid_t pid )
10261106{
10271107 /* call additional bug reporters */
1028- {
1108+ if ( crash_report . dump . additional ) {
10291109 int i ;
10301110 for (i = 0 ; i < bug_reporters_size ; i ++ ) {
10311111 struct bug_reporters * reporter = & bug_reporters [i ];
10321112 (* reporter -> func )(out , reporter -> data );
10331113 }
10341114 }
1035- postscript_dump (out );
1115+ if ( vm_dump_conf_enabled_any ( & crash_report . dump )) postscript_dump (out );
10361116 finish_report (out , pid );
10371117}
10381118
@@ -1041,7 +1121,7 @@ bug_report_end(FILE *out, rb_pid_t pid)
10411121 FILE *out = bug_report_file(file, line, &pid); \
10421122 if (out) { \
10431123 bug_report_begin(out, fmt); \
1044- rb_vm_bugreport(ctx, out); \
1124+ rb_vm_bugreport(&crash_report.dump, ctx, out); \
10451125 bug_report_end(out, pid); \
10461126 } \
10471127} while (0) \
@@ -1051,25 +1131,15 @@ bug_report_end(FILE *out, rb_pid_t pid)
10511131 FILE *out = bug_report_file(file, line, &pid); \
10521132 if (out) { \
10531133 bug_report_begin_valist(out, fmt, args); \
1054- rb_vm_bugreport(ctx, out); \
1134+ rb_vm_bugreport(&crash_report.dump, ctx, out); \
10551135 bug_report_end(out, pid); \
10561136 } \
10571137} while (0) \
10581138
10591139void
10601140ruby_set_crash_report (const char * template )
10611141{
1062- crash_report = template ;
1063- #if RUBY_DEBUG
1064- rb_pid_t pid = -1 ;
1065- char buf [REPORT_BUG_BUFSIZ ];
1066- FILE * out = open_report_path (template , buf , sizeof (buf ), & pid );
1067- if (out ) {
1068- time_t t = time (NULL );
1069- fprintf (out , "ruby_test_bug_report: %s" , ctime (& t ));
1070- finish_report (out , pid );
1071- }
1072- #endif
1142+ ruby_each_words_until (template , handle_crash_report_word , "|" , & crash_report );
10731143}
10741144
10751145NORETURN (static void die (void ));
@@ -1212,9 +1282,10 @@ rb_assert_failure_detail(const char *file, int line, const char *name, const cha
12121282 }
12131283 fprintf (out , "\n%s\n\n" , rb_dynamic_description );
12141284
1215- preface_dump (out );
1216- rb_vm_bugreport (NULL , out );
1217- bug_report_end (out , pid );
1285+ bool dump_any = vm_dump_conf_enabled_any (& crash_report .dump );
1286+ if (dump_any ) preface_dump (out );
1287+ rb_vm_bugreport (& crash_report .dump , NULL , out );
1288+ if (dump_any ) bug_report_end (out , pid );
12181289 }
12191290
12201291 die ();
0 commit comments