File indexing completed on 2025-01-30 10:00:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef BOOST_TEST_DEBUG_API_IPP_112006GER
0016 #define BOOST_TEST_DEBUG_API_IPP_112006GER
0017
0018
0019 #include <boost/test/detail/config.hpp>
0020 #include <boost/test/detail/global_typedef.hpp>
0021
0022 #include <boost/test/debug.hpp>
0023 #include <boost/test/debug_config.hpp>
0024
0025 #include <boost/core/ignore_unused.hpp>
0026
0027
0028 #if defined(_WIN32) && !defined(UNDER_CE) && !defined(BOOST_DISABLE_WIN32)
0029
0030 # define BOOST_WIN32_BASED_DEBUG
0031
0032
0033 # include <windows.h>
0034 # include <winreg.h>
0035 # include <cstdio>
0036 # include <cstring>
0037
0038 # if !defined(NDEBUG) && defined(_MSC_VER)
0039 # define BOOST_MS_CRT_BASED_DEBUG
0040 # include <crtdbg.h>
0041 # endif
0042
0043
0044 # ifdef BOOST_NO_STDC_NAMESPACE
0045 namespace std { using ::memset; using ::sprintf; }
0046 # endif
0047
0048 #elif defined(unix) || defined(__unix)
0049
0050 # define BOOST_UNIX_BASED_DEBUG
0051
0052
0053 #include <boost/test/utils/class_properties.hpp>
0054 #include <boost/test/utils/algorithm.hpp>
0055
0056
0057 #include <cstring> // std::memcpy
0058 #include <map>
0059 #include <cstdio>
0060 #include <stdarg.h> // !! ?? cstdarg
0061
0062
0063 # include <unistd.h>
0064 # include <signal.h>
0065 # include <fcntl.h>
0066
0067 # include <sys/types.h>
0068 # include <sys/stat.h>
0069 # include <sys/wait.h>
0070 # include <sys/time.h>
0071 # include <stdio.h>
0072 # include <stdlib.h>
0073
0074 # if defined(sun) || defined(__sun)
0075
0076 # define BOOST_SUN_BASED_DEBUG
0077
0078 # ifndef BOOST_TEST_DBG_LIST
0079 # define BOOST_TEST_DBG_LIST dbx;gdb
0080 # endif
0081
0082 # define BOOST_TEST_CNL_DBG dbx
0083 # define BOOST_TEST_GUI_DBG dbx-ddd
0084
0085 # include <procfs.h>
0086
0087 # elif defined(linux) || defined(__linux__)
0088
0089 # define BOOST_LINUX_BASED_DEBUG
0090
0091 # include <sys/ptrace.h>
0092
0093 # ifndef BOOST_TEST_STAT_LINE_MAX
0094 # define BOOST_TEST_STAT_LINE_MAX 500
0095 # endif
0096
0097 # ifndef BOOST_TEST_DBG_LIST
0098 # define BOOST_TEST_DBG_LIST gdb;lldb
0099 # endif
0100
0101 # define BOOST_TEST_CNL_DBG gdb
0102 # define BOOST_TEST_GUI_DBG gdb-xterm
0103
0104 # endif
0105
0106 #elif defined(__APPLE__)
0107
0108 # define BOOST_APPLE_BASED_DEBUG
0109
0110 # include <assert.h>
0111 # include <sys/types.h>
0112 # include <unistd.h>
0113 # include <sys/sysctl.h>
0114
0115 #endif
0116
0117 #include <boost/test/detail/suppress_warnings.hpp>
0118
0119
0120
0121 namespace boost {
0122 namespace debug {
0123
0124 using unit_test::const_string;
0125
0126
0127
0128
0129
0130 namespace {
0131
0132 #if defined(BOOST_WIN32_BASED_DEBUG)
0133
0134 template<typename T>
0135 inline void
0136 dyn_symbol( T& res, char const* module_name, char const* symbol_name )
0137 {
0138 HMODULE m = ::GetModuleHandleA( module_name );
0139
0140 if( !m )
0141 m = ::LoadLibraryA( module_name );
0142
0143 res = reinterpret_cast<T>( ::GetProcAddress( m, symbol_name ) );
0144 }
0145
0146
0147
0148 static struct info_t {
0149 typedef BOOL (WINAPI* IsDebuggerPresentT)();
0150 typedef LONG (WINAPI* RegQueryValueExT)( HKEY, char const* , LPDWORD, LPDWORD, LPBYTE, LPDWORD );
0151 typedef LONG (WINAPI* RegOpenKeyT)( HKEY, char const* , PHKEY );
0152 typedef LONG (WINAPI* RegCloseKeyT)( HKEY );
0153
0154 info_t();
0155
0156 IsDebuggerPresentT m_is_debugger_present;
0157 RegOpenKeyT m_reg_open_key;
0158 RegQueryValueExT m_reg_query_value;
0159 RegCloseKeyT m_reg_close_key;
0160
0161 } s_info;
0162
0163
0164
0165 info_t::info_t()
0166 {
0167 dyn_symbol( m_is_debugger_present, "kernel32", "IsDebuggerPresent" );
0168 dyn_symbol( m_reg_open_key, "advapi32", "RegOpenKeyA" );
0169 dyn_symbol( m_reg_query_value, "advapi32", "RegQueryValueExA" );
0170 dyn_symbol( m_reg_close_key, "advapi32", "RegCloseKey" );
0171 }
0172
0173
0174
0175 #elif defined(BOOST_UNIX_BASED_DEBUG)
0176
0177
0178
0179
0180
0181 struct fd_holder {
0182 explicit fd_holder( int fd ) : m_fd( fd ) {}
0183 ~fd_holder()
0184 {
0185 if( m_fd != -1 )
0186 ::close( m_fd );
0187 }
0188
0189 operator int() { return m_fd; }
0190
0191 private:
0192
0193 int m_fd;
0194 };
0195
0196
0197
0198
0199
0200
0201 struct process_info {
0202
0203 explicit process_info( int pid );
0204
0205
0206 int parent_pid() const { return m_parent_pid; }
0207 const_string binary_name() const { return m_binary_name; }
0208 const_string binary_path() const { return m_binary_path; }
0209
0210 private:
0211
0212 int m_parent_pid;
0213 const_string m_binary_name;
0214 const_string m_binary_path;
0215
0216 #if defined(BOOST_SUN_BASED_DEBUG)
0217 struct psinfo m_psi;
0218 char m_binary_path_buff[500+1];
0219 #elif defined(BOOST_LINUX_BASED_DEBUG)
0220 char m_stat_line[BOOST_TEST_STAT_LINE_MAX+1];
0221 char m_binary_path_buff[500+1];
0222 #endif
0223 };
0224
0225
0226
0227 process_info::process_info( int pid )
0228 : m_parent_pid( 0 )
0229 {
0230 #if defined(BOOST_SUN_BASED_DEBUG)
0231 char fname_buff[30];
0232
0233 ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/psinfo", pid );
0234
0235 fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) );
0236
0237 if( psinfo_fd == -1 )
0238 return;
0239
0240 if( ::read( psinfo_fd, &m_psi, sizeof(m_psi) ) == -1 )
0241 return;
0242
0243 m_parent_pid = m_psi.pr_ppid;
0244
0245 m_binary_name.assign( m_psi.pr_fname );
0246
0247
0248
0249 ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/as", pid );
0250
0251 fd_holder as_fd( ::open( fname_buff, O_RDONLY ) );
0252 uintptr_t binary_name_pos;
0253
0254
0255 if( as_fd == -1 ||
0256 ::lseek( as_fd, m_psi.pr_argv, SEEK_SET ) == -1 ||
0257 ::read ( as_fd, &binary_name_pos, sizeof(binary_name_pos) ) == -1 ||
0258 ::lseek( as_fd, binary_name_pos, SEEK_SET ) == -1 ||
0259 ::read ( as_fd, m_binary_path_buff, sizeof(m_binary_path_buff) ) == -1 )
0260 return;
0261
0262 m_binary_path.assign( m_binary_path_buff );
0263
0264 #elif defined(BOOST_LINUX_BASED_DEBUG)
0265 char fname_buff[30];
0266
0267 ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/stat", pid );
0268
0269 fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) );
0270
0271 if( psinfo_fd == -1 )
0272 return;
0273
0274 ssize_t num_read = ::read( psinfo_fd, m_stat_line, sizeof(m_stat_line)-1 );
0275 if( num_read == -1 )
0276 return;
0277
0278 m_stat_line[num_read] = 0;
0279
0280 char const* name_beg = m_stat_line;
0281 while( *name_beg && *name_beg != '(' )
0282 ++name_beg;
0283
0284 char const* name_end = name_beg+1;
0285 while( *name_end && *name_end != ')' )
0286 ++name_end;
0287
0288 std::sscanf( name_end+1, "%*s%d", &m_parent_pid );
0289
0290 m_binary_name.assign( name_beg+1, name_end );
0291
0292 ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/exe", pid );
0293 num_read = ::readlink( fname_buff, m_binary_path_buff, sizeof(m_binary_path_buff)-1 );
0294
0295 if( num_read == -1 )
0296 return;
0297
0298 m_binary_path_buff[num_read] = 0;
0299 m_binary_path.assign( m_binary_path_buff, num_read );
0300 #else
0301 (void) pid;
0302 #endif
0303 }
0304
0305
0306
0307
0308
0309
0310
0311 static char*
0312 prepare_window_title( dbg_startup_info const& dsi )
0313 {
0314 typedef unit_test::const_string str_t;
0315
0316 static char title_str[50];
0317
0318 str_t path_sep( "\\/" );
0319
0320 str_t::iterator it = unit_test::utils::find_last_of( dsi.binary_path.begin(), dsi.binary_path.end(),
0321 path_sep.begin(), path_sep.end() );
0322
0323 if( it == dsi.binary_path.end() )
0324 it = dsi.binary_path.begin();
0325 else
0326 ++it;
0327
0328 ::snprintf( title_str, sizeof(title_str), "%*s %ld", (int)(dsi.binary_path.end()-it), it, dsi.pid );
0329
0330 return title_str;
0331 }
0332
0333
0334
0335
0336
0337
0338
0339 typedef unit_test::basic_cstring<char> mbuffer;
0340
0341 inline char*
0342 copy_arg( mbuffer& dest, const_string arg )
0343 {
0344 if( dest.size() < arg.size()+1 )
0345 return 0;
0346
0347 char* res = dest.begin();
0348
0349 std::memcpy( res, arg.begin(), arg.size()+1 );
0350
0351 dest.trim_left( arg.size()+1 );
0352
0353 return res;
0354 }
0355
0356
0357
0358 bool
0359 safe_execlp( char const* file, ... )
0360 {
0361 static char* argv_buff[200];
0362
0363 va_list args;
0364 char const* arg;
0365
0366
0367 int num_args = 2;
0368
0369 va_start( args, file );
0370 while( !!(arg = va_arg( args, char const* )) )
0371 num_args++;
0372 va_end( args );
0373
0374
0375 char** argv_it = argv_buff;
0376 mbuffer work_buff( reinterpret_cast<char*>(argv_buff), sizeof(argv_buff) );
0377 work_buff.trim_left( num_args * sizeof(char*) );
0378
0379
0380 if( !(*argv_it++ = copy_arg( work_buff, file )) )
0381 return false;
0382
0383 printf( "!! %s\n", file );
0384
0385 va_start( args, file );
0386 while( !!(arg = va_arg( args, char const* )) ) {
0387 printf( "!! %s\n", arg );
0388 if( !(*argv_it++ = copy_arg( work_buff, arg )) ) {
0389 va_end( args );
0390 return false;
0391 }
0392 }
0393 va_end( args );
0394
0395 *argv_it = 0;
0396
0397 return ::execvp( file, argv_buff ) != -1;
0398 }
0399
0400
0401
0402
0403
0404
0405
0406 static void
0407 start_debugger_in_emacs( dbg_startup_info const& dsi, char const* emacs_name, char const* dbg_command )
0408 {
0409 char const* title = prepare_window_title( dsi );
0410
0411 if( !title )
0412 return;
0413
0414 dsi.display.is_empty()
0415 ? safe_execlp( emacs_name, "-title", title, "--eval", dbg_command, 0 )
0416 : safe_execlp( emacs_name, "-title", title, "-display", dsi.display.begin(), "--eval", dbg_command, 0 );
0417 }
0418
0419
0420
0421
0422
0423
0424
0425 static char const*
0426 prepare_gdb_cmnd_file( dbg_startup_info const& dsi )
0427 {
0428
0429 char pid_buff[16];
0430 ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
0431 unit_test::const_string pid_str( pid_buff );
0432
0433 static char cmd_file_name[] = "/tmp/btl_gdb_cmd_XXXXXX";
0434
0435
0436 const mode_t cur_umask = ::umask( S_IRWXO | S_IRWXG );
0437 fd_holder cmd_fd( ::mkstemp( cmd_file_name ) );
0438 ::umask( cur_umask );
0439
0440 if( cmd_fd == -1 )
0441 return 0;
0442
0443 #define WRITE_STR( str ) if( ::write( cmd_fd, str.begin(), str.size() ) == -1 ) return 0;
0444 #define WRITE_CSTR( str ) if( ::write( cmd_fd, str, sizeof( str )-1 ) == -1 ) return 0;
0445
0446 WRITE_CSTR( "file " );
0447 WRITE_STR( dsi.binary_path );
0448 WRITE_CSTR( "\nattach " );
0449 WRITE_STR( pid_str );
0450 WRITE_CSTR( "\nshell unlink " );
0451 WRITE_STR( dsi.init_done_lock );
0452 WRITE_CSTR( "\ncont" );
0453 if( dsi.break_or_continue )
0454 WRITE_CSTR( "\nup 4" );
0455
0456 WRITE_CSTR( "\necho \\n" );
0457 WRITE_CSTR( "\nlist -" );
0458 WRITE_CSTR( "\nlist" );
0459 WRITE_CSTR( "\nshell unlink " );
0460 WRITE_CSTR( cmd_file_name );
0461
0462 return cmd_file_name;
0463 }
0464
0465
0466
0467 static void
0468 start_gdb_in_console( dbg_startup_info const& dsi )
0469 {
0470 char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
0471
0472 if( !cmnd_file_name )
0473 return;
0474
0475 safe_execlp( "gdb", "-q", "-x", cmnd_file_name, 0 );
0476 }
0477
0478
0479
0480 static void
0481 start_gdb_in_xterm( dbg_startup_info const& dsi )
0482 {
0483 char const* title = prepare_window_title( dsi );
0484 char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
0485
0486 if( !title || !cmnd_file_name )
0487 return;
0488
0489 safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(),
0490 "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e",
0491 "gdb", "-q", "-x", cmnd_file_name, 0 );
0492 }
0493
0494
0495
0496 static void
0497 start_gdb_in_emacs( dbg_startup_info const& dsi )
0498 {
0499 char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
0500 if( !cmnd_file_name )
0501 return;
0502
0503 char dbg_cmd_buff[500];
0504 ::snprintf( dbg_cmd_buff, sizeof(dbg_cmd_buff), "(progn (gdb \"gdb -q -x %s\"))", cmnd_file_name );
0505
0506 start_debugger_in_emacs( dsi, "emacs", dbg_cmd_buff );
0507 }
0508
0509
0510
0511 static void
0512 start_gdb_in_xemacs( dbg_startup_info const& )
0513 {
0514
0515 }
0516
0517
0518
0519
0520
0521
0522
0523 static char const*
0524 prepare_dbx_cmd_line( dbg_startup_info const& dsi, bool list_source = true )
0525 {
0526 static char cmd_line_buff[500];
0527
0528 ::snprintf( cmd_line_buff, sizeof(cmd_line_buff), "unlink %s;cont;%s%s",
0529 dsi.init_done_lock.begin(),
0530 dsi.break_or_continue ? "up 2;": "",
0531 list_source ? "echo \" \";list -w3;" : "" );
0532
0533 return cmd_line_buff;
0534 }
0535
0536
0537
0538 static void
0539 start_dbx_in_console( dbg_startup_info const& dsi )
0540 {
0541 char pid_buff[16];
0542 ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
0543
0544 safe_execlp( "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 );
0545 }
0546
0547
0548
0549 static void
0550 start_dbx_in_xterm( dbg_startup_info const& dsi )
0551 {
0552 char const* title = prepare_window_title( dsi );
0553 if( !title )
0554 return;
0555
0556 char pid_buff[16];
0557 ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
0558
0559 safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(),
0560 "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e",
0561 "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 );
0562 }
0563
0564
0565
0566 static void
0567 start_dbx_in_emacs( dbg_startup_info const& )
0568 {
0569
0570
0571
0572
0573
0574 }
0575
0576
0577
0578 static void
0579 start_dbx_in_xemacs( dbg_startup_info const& )
0580 {
0581
0582 }
0583
0584
0585
0586 static void
0587 start_dbx_in_ddd( dbg_startup_info const& dsi )
0588 {
0589 char const* title = prepare_window_title( dsi );
0590 if( !title )
0591 return;
0592
0593 char pid_buff[16];
0594 ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
0595
0596 safe_execlp( "ddd", "-display", dsi.display.begin(),
0597 "--dbx", "-q", "-c", prepare_dbx_cmd_line( dsi, false ), dsi.binary_path.begin(), pid_buff, 0 );
0598 }
0599
0600
0601
0602
0603
0604
0605
0606 static struct info_t {
0607
0608 info_t();
0609
0610
0611 unit_test::readwrite_property<std::string> p_dbg;
0612
0613
0614 std::map<std::string,dbg_starter> m_dbg_starter_reg;
0615 } s_info;
0616
0617
0618
0619 info_t::info_t()
0620 {
0621 p_dbg.value = ::getenv( "DISPLAY" )
0622 ? std::string( BOOST_STRINGIZE( BOOST_TEST_GUI_DBG ) )
0623 : std::string( BOOST_STRINGIZE( BOOST_TEST_CNL_DBG ) );
0624
0625 m_dbg_starter_reg[std::string("gdb")] = &start_gdb_in_console;
0626 m_dbg_starter_reg[std::string("gdb-emacs")] = &start_gdb_in_emacs;
0627 m_dbg_starter_reg[std::string("gdb-xterm")] = &start_gdb_in_xterm;
0628 m_dbg_starter_reg[std::string("gdb-xemacs")] = &start_gdb_in_xemacs;
0629
0630 m_dbg_starter_reg[std::string("dbx")] = &start_dbx_in_console;
0631 m_dbg_starter_reg[std::string("dbx-emacs")] = &start_dbx_in_emacs;
0632 m_dbg_starter_reg[std::string("dbx-xterm")] = &start_dbx_in_xterm;
0633 m_dbg_starter_reg[std::string("dbx-xemacs")] = &start_dbx_in_xemacs;
0634 m_dbg_starter_reg[std::string("dbx-ddd")] = &start_dbx_in_ddd;
0635 }
0636
0637
0638
0639 #endif
0640
0641 }
0642
0643
0644
0645
0646
0647 bool
0648 under_debugger()
0649 {
0650 #if defined(BOOST_WIN32_BASED_DEBUG)
0651
0652 return !!s_info.m_is_debugger_present && s_info.m_is_debugger_present();
0653
0654 #elif defined(BOOST_UNIX_BASED_DEBUG)
0655
0656
0657 const_string dbg_list = BOOST_TEST_STRINGIZE( BOOST_TEST_DBG_LIST );
0658
0659 pid_t pid = ::getpid();
0660
0661 while( pid != 0 ) {
0662 process_info pi( pid );
0663
0664
0665 if( dbg_list.find( pi.binary_name() ) != const_string::npos )
0666 return true;
0667
0668 pid = (pi.parent_pid() == pid ? 0 : pi.parent_pid());
0669 }
0670
0671 return false;
0672
0673 #elif defined(BOOST_APPLE_BASED_DEBUG)
0674
0675
0676 int junk;
0677 int mib[4];
0678 struct kinfo_proc info;
0679 size_t size;
0680
0681
0682
0683 info.kp_proc.p_flag = 0;
0684
0685
0686
0687 mib[0] = CTL_KERN;
0688 mib[1] = KERN_PROC;
0689 mib[2] = KERN_PROC_PID;
0690 mib[3] = getpid();
0691
0692
0693 size = sizeof(info);
0694 junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
0695 assert(junk == 0);
0696 (void)junk;
0697
0698
0699 return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
0700
0701 #else
0702
0703 return false;
0704
0705 #endif
0706 }
0707
0708
0709
0710
0711
0712
0713
0714
0715 void
0716 debugger_break()
0717 {
0718
0719
0720 #if defined(BOOST_WIN32_BASED_DEBUG)
0721
0722 #if defined(__GNUC__) && !defined(__MINGW32__) || \
0723 defined(__INTEL_COMPILER) || defined(BOOST_EMBTC)
0724 # define BOOST_DEBUG_BREAK __debugbreak
0725 #else
0726 # define BOOST_DEBUG_BREAK DebugBreak
0727 #endif
0728
0729 #ifndef __MINGW32__
0730 if( !under_debugger() ) {
0731 __try {
0732 __try {
0733 BOOST_DEBUG_BREAK();
0734 }
0735 __except( UnhandledExceptionFilter(GetExceptionInformation()) )
0736 {
0737
0738 return;
0739 }
0740 }
0741 __except (EXCEPTION_EXECUTE_HANDLER)
0742 {
0743
0744
0745 }
0746 }
0747 #endif
0748
0749 BOOST_DEBUG_BREAK();
0750
0751 #elif defined(BOOST_UNIX_BASED_DEBUG)
0752
0753 ::kill( ::getpid(), SIGTRAP );
0754
0755 #else
0756
0757 #endif
0758 }
0759
0760
0761
0762
0763
0764
0765
0766 #if defined(BOOST_UNIX_BASED_DEBUG)
0767
0768 std::string
0769 set_debugger( unit_test::const_string dbg_id, dbg_starter s )
0770 {
0771 std::string old = s_info.p_dbg;
0772
0773 assign_op( s_info.p_dbg.value, dbg_id, 0 );
0774
0775 if( !!s )
0776 s_info.m_dbg_starter_reg[s_info.p_dbg.get()] = s;
0777
0778 return old;
0779 }
0780
0781 #else
0782
0783 std::string
0784 set_debugger( unit_test::const_string, dbg_starter )
0785 {
0786 return std::string();
0787 }
0788
0789 #endif
0790
0791
0792
0793
0794
0795
0796
0797 #if defined(BOOST_WIN32_BASED_DEBUG)
0798
0799 struct safe_handle_helper
0800 {
0801 HANDLE& handle;
0802 safe_handle_helper(HANDLE &handle_) : handle(handle_) {}
0803
0804 void close_handle()
0805 {
0806 if( handle != INVALID_HANDLE_VALUE )
0807 {
0808 ::CloseHandle( handle );
0809 handle = INVALID_HANDLE_VALUE;
0810 }
0811 }
0812
0813 ~safe_handle_helper()
0814 {
0815 close_handle();
0816 }
0817 };
0818 #endif
0819
0820 bool
0821 attach_debugger( bool break_or_continue )
0822 {
0823 if( under_debugger() )
0824 return false;
0825
0826 #if defined(BOOST_WIN32_BASED_DEBUG)
0827
0828 const int MAX_CMD_LINE = 200;
0829
0830
0831
0832
0833 SECURITY_ATTRIBUTES attr;
0834 attr.nLength = sizeof(attr);
0835 attr.lpSecurityDescriptor = NULL;
0836 attr.bInheritHandle = true;
0837
0838
0839
0840 HANDLE dbg_init_done_ev = ::CreateEvent(
0841 &attr,
0842 true,
0843 false,
0844 NULL
0845 );
0846
0847 if( !dbg_init_done_ev )
0848 return false;
0849
0850 safe_handle_helper safe_handle_obj( dbg_init_done_ev );
0851
0852
0853
0854
0855 HKEY reg_key;
0856
0857 if( !s_info.m_reg_open_key || (*s_info.m_reg_open_key)(
0858 HKEY_LOCAL_MACHINE,
0859 "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug",
0860 ®_key ) != ERROR_SUCCESS )
0861 return false;
0862
0863 char format[MAX_CMD_LINE];
0864 DWORD format_size = MAX_CMD_LINE;
0865 DWORD type = REG_SZ;
0866
0867 bool b_read_key = s_info.m_reg_query_value &&
0868 ((*s_info.m_reg_query_value)(
0869 reg_key,
0870 "Debugger",
0871 0,
0872 &type,
0873 (LPBYTE)format,
0874 &format_size ) == ERROR_SUCCESS );
0875
0876 if( !s_info.m_reg_close_key || (*s_info.m_reg_close_key)( reg_key ) != ERROR_SUCCESS )
0877 return false;
0878
0879 if( !b_read_key )
0880 return false;
0881
0882
0883
0884
0885 char cmd_line[MAX_CMD_LINE];
0886 std::sprintf( cmd_line, format, ::GetCurrentProcessId(), dbg_init_done_ev );
0887
0888
0889
0890
0891 STARTUPINFOA startup_info;
0892 std::memset( &startup_info, 0, sizeof(startup_info) );
0893
0894 startup_info.cb = sizeof(startup_info);
0895 startup_info.dwFlags = STARTF_USESHOWWINDOW;
0896 startup_info.wShowWindow = SW_SHOWNORMAL;
0897
0898
0899 PROCESS_INFORMATION debugger_info;
0900
0901 bool created = !!::CreateProcessA(
0902 NULL,
0903 cmd_line,
0904 NULL,
0905 NULL,
0906 true,
0907 0,
0908 NULL,
0909 NULL,
0910 &startup_info,
0911 &debugger_info
0912 );
0913
0914 bool debugger_run_ok = false;
0915 if( created )
0916 {
0917 DWORD ret_code = ::WaitForSingleObject( dbg_init_done_ev, INFINITE );
0918 debugger_run_ok = ( ret_code == WAIT_OBJECT_0 );
0919 }
0920
0921 safe_handle_obj.close_handle();
0922
0923 if( !created || !debugger_run_ok )
0924 return false;
0925
0926 if( break_or_continue )
0927 debugger_break();
0928
0929 return true;
0930
0931 #elif defined(BOOST_UNIX_BASED_DEBUG)
0932
0933 char init_done_lock_fn[] = "/tmp/btl_dbg_init_done_XXXXXX";
0934 const mode_t cur_umask = ::umask( S_IRWXO | S_IRWXG );
0935 fd_holder init_done_lock_fd( ::mkstemp( init_done_lock_fn ) );
0936 ::umask( cur_umask );
0937
0938 if( init_done_lock_fd == -1 )
0939 return false;
0940
0941 pid_t child_pid = fork();
0942
0943 if( child_pid == -1 )
0944 return false;
0945
0946 if( child_pid != 0 ) {
0947 dbg_startup_info dsi;
0948
0949 process_info pi( child_pid );
0950 if( pi.binary_path().is_empty() )
0951 ::exit( -1 );
0952
0953 dsi.pid = child_pid;
0954 dsi.break_or_continue = break_or_continue;
0955 dsi.binary_path = pi.binary_path();
0956 dsi.display = ::getenv( "DISPLAY" );
0957 dsi.init_done_lock = init_done_lock_fn;
0958
0959 dbg_starter starter = s_info.m_dbg_starter_reg[s_info.p_dbg];
0960 if( !!starter )
0961 starter( dsi );
0962
0963 ::perror( "Boost.Test execution monitor failed to start a debugger:" );
0964
0965 ::exit( -1 );
0966 }
0967
0968
0969
0970 while( ::access( init_done_lock_fn, F_OK ) == 0 ) {
0971 struct timeval to = { 0, 100 };
0972
0973 ::select( 0, 0, 0, 0, &to );
0974 }
0975
0976
0977
0978
0979 if( break_or_continue )
0980 debugger_break();
0981
0982 return true;
0983
0984 #else
0985 (void) break_or_continue;
0986 return false;
0987
0988 #endif
0989 }
0990
0991
0992
0993
0994
0995
0996
0997 void
0998 detect_memory_leaks( bool on_off, unit_test::const_string report_file )
0999 {
1000 boost::ignore_unused( on_off );
1001
1002 #ifdef BOOST_MS_CRT_BASED_DEBUG
1003 int flags = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
1004
1005 if( !on_off )
1006 flags &= ~_CRTDBG_LEAK_CHECK_DF;
1007 else {
1008 flags |= _CRTDBG_LEAK_CHECK_DF;
1009 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1010
1011 if( report_file.is_empty() )
1012 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1013 else {
1014 HANDLE hreport_f = ::CreateFileA( report_file.begin(),
1015 GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1016 _CrtSetReportFile(_CRT_WARN, hreport_f );
1017 }
1018 }
1019
1020 _CrtSetDbgFlag ( flags );
1021 #else
1022 boost::ignore_unused( report_file );
1023 #endif
1024 }
1025
1026
1027
1028
1029
1030
1031
1032
1033 void
1034 break_memory_alloc( long mem_alloc_order_num )
1035 {
1036 boost::ignore_unused( mem_alloc_order_num );
1037
1038 #ifdef BOOST_MS_CRT_BASED_DEBUG
1039
1040 if( mem_alloc_order_num > 1 )
1041 _CrtSetBreakAlloc( mem_alloc_order_num );
1042 #endif
1043 }
1044
1045
1046
1047 }
1048 }
1049
1050 #include <boost/test/detail/enable_warnings.hpp>
1051
1052 #endif