annotate DEPENDENCIES/generic/include/boost/test/impl/debug.ipp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 // (C) Copyright Gennadiy Rozental 2006-2008.
Chris@16 2 // Use, modification, and distribution are subject to the
Chris@16 3 // Boost Software License, Version 1.0. (See accompanying file
Chris@16 4 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 5
Chris@16 6 // See http://www.boost.org/libs/test for the library home page.
Chris@16 7 //
Chris@16 8 // File : $RCSfile$
Chris@16 9 //
Chris@101 10 // Version : $Revision$
Chris@16 11 //
Chris@16 12 // Description : debug interfaces implementation
Chris@16 13 // ***************************************************************************
Chris@16 14
Chris@16 15 #ifndef BOOST_TEST_DEBUG_API_IPP_112006GER
Chris@16 16 #define BOOST_TEST_DEBUG_API_IPP_112006GER
Chris@16 17
Chris@16 18 // Boost.Test
Chris@16 19 #include <boost/test/detail/config.hpp>
Chris@16 20 #include <boost/test/detail/workaround.hpp>
Chris@16 21 #include <boost/test/detail/global_typedef.hpp>
Chris@16 22
Chris@16 23 #include <boost/test/debug.hpp>
Chris@16 24 #include <boost/test/debug_config.hpp>
Chris@16 25
Chris@16 26 // Implementation on Windows
Chris@16 27 #if defined(_WIN32) && !defined(UNDER_CE) && !defined(BOOST_DISABLE_WIN32) // ******* WIN32
Chris@16 28
Chris@16 29 # define BOOST_WIN32_BASED_DEBUG
Chris@16 30
Chris@16 31 // SYSTEM API
Chris@16 32 # include <windows.h>
Chris@16 33 # include <winreg.h>
Chris@16 34 # include <cstdio>
Chris@16 35 # include <cstring>
Chris@16 36
Chris@16 37 # if !defined(NDEBUG) && defined(_MSC_VER)
Chris@16 38 # define BOOST_MS_CRT_BASED_DEBUG
Chris@16 39 # include <crtdbg.h>
Chris@16 40 # endif
Chris@16 41
Chris@16 42
Chris@16 43 # if BOOST_WORKAROUND( BOOST_MSVC, <1300)
Chris@16 44 # define snprintf _snprintf
Chris@16 45 # endif
Chris@16 46
Chris@16 47 # ifdef BOOST_NO_STDC_NAMESPACE
Chris@16 48 namespace std { using ::memset; using ::sprintf; }
Chris@16 49 # endif
Chris@16 50
Chris@16 51 #elif defined(unix) || defined(__unix) // ********************* UNIX
Chris@16 52
Chris@16 53 # define BOOST_UNIX_BASED_DEBUG
Chris@16 54
Chris@16 55 // Boost.Test
Chris@16 56 #include <boost/test/utils/class_properties.hpp>
Chris@16 57 #include <boost/test/utils/algorithm.hpp>
Chris@16 58
Chris@16 59 // STL
Chris@16 60 #include <cstring> // std::memcpy
Chris@16 61 #include <map>
Chris@16 62 #include <cstdio>
Chris@16 63 #include <stdarg.h> // !! ?? cstdarg
Chris@16 64
Chris@16 65 // SYSTEM API
Chris@16 66 # include <unistd.h>
Chris@16 67 # include <signal.h>
Chris@16 68 # include <fcntl.h>
Chris@16 69
Chris@16 70 # include <sys/types.h>
Chris@16 71 # include <sys/stat.h>
Chris@16 72 # include <sys/wait.h>
Chris@16 73 # include <sys/time.h>
Chris@16 74 # include <stdio.h>
Chris@16 75 # include <stdlib.h>
Chris@16 76
Chris@16 77 # if defined(sun) || defined(__sun)
Chris@16 78
Chris@16 79 # define BOOST_SUN_BASED_DEBUG
Chris@16 80
Chris@16 81 # ifndef BOOST_TEST_DBG_LIST
Chris@16 82 # define BOOST_TEST_DBG_LIST dbx;gdb
Chris@16 83 # endif
Chris@16 84
Chris@16 85 # define BOOST_TEST_CNL_DBG dbx
Chris@16 86 # define BOOST_TEST_GUI_DBG dbx-ddd
Chris@16 87
Chris@16 88 # include <procfs.h>
Chris@16 89
Chris@16 90 # elif defined(linux) || defined(__linux)
Chris@16 91
Chris@16 92 # define BOOST_LINUX_BASED_DEBUG
Chris@16 93
Chris@16 94 # include <sys/ptrace.h>
Chris@16 95
Chris@16 96 # ifndef BOOST_TEST_STAT_LINE_MAX
Chris@16 97 # define BOOST_TEST_STAT_LINE_MAX 500
Chris@16 98 # endif
Chris@16 99
Chris@16 100 # ifndef BOOST_TEST_DBG_LIST
Chris@16 101 # define BOOST_TEST_DBG_LIST gdb
Chris@16 102 # endif
Chris@16 103
Chris@16 104 # define BOOST_TEST_CNL_DBG gdb
Chris@16 105 # define BOOST_TEST_GUI_DBG gdb-xterm
Chris@16 106
Chris@16 107 # endif
Chris@16 108
Chris@16 109 #endif
Chris@16 110
Chris@16 111 #include <boost/test/detail/suppress_warnings.hpp>
Chris@16 112
Chris@16 113 //____________________________________________________________________________//
Chris@16 114
Chris@16 115 namespace boost {
Chris@16 116
Chris@16 117 namespace debug {
Chris@16 118
Chris@16 119 using unit_test::const_string;
Chris@16 120
Chris@16 121 // ************************************************************************** //
Chris@16 122 // ************** debug::info_t ************** //
Chris@16 123 // ************************************************************************** //
Chris@16 124
Chris@16 125 namespace {
Chris@16 126
Chris@16 127 #if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
Chris@16 128
Chris@16 129 template<typename T>
Chris@16 130 inline void
Chris@16 131 dyn_symbol( T& res, char const* module_name, char const* symbol_name )
Chris@16 132 {
Chris@16 133 HMODULE m = ::GetModuleHandleA( module_name );
Chris@16 134
Chris@16 135 if( !m )
Chris@16 136 m = ::LoadLibraryA( module_name );
Chris@16 137
Chris@16 138 res = reinterpret_cast<T>( ::GetProcAddress( m, symbol_name ) );
Chris@16 139 }
Chris@16 140
Chris@16 141 //____________________________________________________________________________//
Chris@16 142
Chris@16 143 static struct info_t {
Chris@16 144 typedef BOOL (WINAPI* IsDebuggerPresentT)();
Chris@16 145 typedef LONG (WINAPI* RegQueryValueExT)( HKEY, char const* /*LPTSTR*/, LPDWORD, LPDWORD, LPBYTE, LPDWORD );
Chris@16 146 typedef LONG (WINAPI* RegOpenKeyT)( HKEY, char const* /*LPCTSTR*/, PHKEY );
Chris@16 147 typedef LONG (WINAPI* RegCloseKeyT)( HKEY );
Chris@16 148
Chris@16 149 info_t();
Chris@16 150
Chris@16 151 IsDebuggerPresentT m_is_debugger_present;
Chris@16 152 RegOpenKeyT m_reg_open_key;
Chris@16 153 RegQueryValueExT m_reg_query_value;
Chris@16 154 RegCloseKeyT m_reg_close_key;
Chris@16 155
Chris@16 156 } s_info;
Chris@16 157
Chris@16 158 //____________________________________________________________________________//
Chris@16 159
Chris@16 160 info_t::info_t()
Chris@16 161 {
Chris@16 162 dyn_symbol( m_is_debugger_present, "kernel32", "IsDebuggerPresent" );
Chris@16 163 dyn_symbol( m_reg_open_key, "advapi32", "RegOpenKeyA" );
Chris@16 164 dyn_symbol( m_reg_query_value, "advapi32", "RegQueryValueExA" );
Chris@16 165 dyn_symbol( m_reg_close_key, "advapi32", "RegCloseKey" );
Chris@16 166 }
Chris@16 167
Chris@16 168 //____________________________________________________________________________//
Chris@16 169
Chris@16 170 #elif defined(BOOST_UNIX_BASED_DEBUG)
Chris@16 171
Chris@16 172 // ************************************************************************** //
Chris@16 173 // ************** fd_holder ************** //
Chris@16 174 // ************************************************************************** //
Chris@16 175
Chris@16 176 struct fd_holder {
Chris@16 177 explicit fd_holder( int fd ) : m_fd( fd ) {}
Chris@16 178 ~fd_holder()
Chris@16 179 {
Chris@16 180 if( m_fd != -1 )
Chris@16 181 ::close( m_fd );
Chris@16 182 }
Chris@16 183
Chris@16 184 operator int() { return m_fd; }
Chris@16 185
Chris@16 186 private:
Chris@16 187 // Data members
Chris@16 188 int m_fd;
Chris@16 189 };
Chris@16 190
Chris@16 191
Chris@16 192 // ************************************************************************** //
Chris@16 193 // ************** process_info ************** //
Chris@16 194 // ************************************************************************** //
Chris@16 195
Chris@16 196 struct process_info {
Chris@16 197 // Constructor
Chris@16 198 explicit process_info( int pid );
Chris@16 199
Chris@16 200 // access methods
Chris@16 201 int parent_pid() const { return m_parent_pid; }
Chris@16 202 const_string binary_name() const { return m_binary_name; }
Chris@16 203 const_string binary_path() const { return m_binary_path; }
Chris@16 204
Chris@16 205 private:
Chris@16 206 // Data members
Chris@16 207 int m_parent_pid;
Chris@16 208 const_string m_binary_name;
Chris@16 209 const_string m_binary_path;
Chris@16 210
Chris@16 211 #if defined(BOOST_SUN_BASED_DEBUG)
Chris@16 212 struct psinfo m_psi;
Chris@16 213 #elif defined(BOOST_LINUX_BASED_DEBUG)
Chris@16 214 char m_stat_line[BOOST_TEST_STAT_LINE_MAX+1];
Chris@16 215 #endif
Chris@16 216 char m_binary_path_buff[500+1]; // !! ??
Chris@16 217 };
Chris@16 218
Chris@16 219 //____________________________________________________________________________//
Chris@16 220
Chris@16 221 process_info::process_info( int pid )
Chris@16 222 : m_parent_pid( 0 )
Chris@16 223 {
Chris@16 224 #if defined(BOOST_SUN_BASED_DEBUG)
Chris@16 225 char fname_buff[30];
Chris@16 226
Chris@16 227 ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/psinfo", pid );
Chris@16 228
Chris@16 229 fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) );
Chris@16 230
Chris@16 231 if( psinfo_fd == -1 )
Chris@16 232 return;
Chris@16 233
Chris@16 234 if( ::read( psinfo_fd, &m_psi, sizeof(m_psi) ) == -1 )
Chris@16 235 return;
Chris@16 236
Chris@16 237 m_parent_pid = m_psi.pr_ppid;
Chris@16 238
Chris@16 239 m_binary_name.assign( m_psi.pr_fname );
Chris@16 240
Chris@16 241 //-------------------------- //
Chris@16 242
Chris@16 243 ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/as", pid );
Chris@16 244
Chris@16 245 fd_holder as_fd( ::open( fname_buff, O_RDONLY ) );
Chris@16 246 uintptr_t binary_name_pos;
Chris@16 247
Chris@16 248 // !! ?? could we avoid reading whole m_binary_path_buff?
Chris@16 249 if( as_fd == -1 ||
Chris@16 250 ::lseek( as_fd, m_psi.pr_argv, SEEK_SET ) == -1 ||
Chris@16 251 ::read ( as_fd, &binary_name_pos, sizeof(binary_name_pos) ) == -1 ||
Chris@16 252 ::lseek( as_fd, binary_name_pos, SEEK_SET ) == -1 ||
Chris@16 253 ::read ( as_fd, m_binary_path_buff, sizeof(m_binary_path_buff) ) == -1 )
Chris@16 254 return;
Chris@16 255
Chris@16 256 m_binary_path.assign( m_binary_path_buff );
Chris@16 257
Chris@16 258 #elif defined(BOOST_LINUX_BASED_DEBUG)
Chris@16 259 char fname_buff[30];
Chris@16 260
Chris@16 261 ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/stat", pid );
Chris@16 262
Chris@16 263 fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) );
Chris@16 264
Chris@16 265 if( psinfo_fd == -1 )
Chris@16 266 return;
Chris@16 267
Chris@16 268 ssize_t num_read = ::read( psinfo_fd, m_stat_line, sizeof(m_stat_line)-1 );
Chris@16 269 if( num_read == -1 )
Chris@16 270 return;
Chris@16 271
Chris@16 272 m_stat_line[num_read] = 0;
Chris@16 273
Chris@16 274 char const* name_beg = m_stat_line;
Chris@16 275 while( *name_beg && *name_beg != '(' )
Chris@16 276 ++name_beg;
Chris@16 277
Chris@16 278 char const* name_end = name_beg+1;
Chris@16 279 while( *name_end && *name_end != ')' )
Chris@16 280 ++name_end;
Chris@16 281
Chris@16 282 std::sscanf( name_end+1, "%*s%d", &m_parent_pid );
Chris@16 283
Chris@16 284 m_binary_name.assign( name_beg+1, name_end );
Chris@16 285
Chris@16 286 ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/exe", pid );
Chris@16 287 num_read = ::readlink( fname_buff, m_binary_path_buff, sizeof(m_binary_path_buff)-1 );
Chris@16 288
Chris@16 289 if( num_read == -1 )
Chris@16 290 return;
Chris@16 291
Chris@16 292 m_binary_path_buff[num_read] = 0;
Chris@16 293 m_binary_path.assign( m_binary_path_buff, num_read );
Chris@16 294 #endif
Chris@16 295 }
Chris@16 296
Chris@16 297 //____________________________________________________________________________//
Chris@16 298
Chris@16 299 // ************************************************************************** //
Chris@16 300 // ************** prepare_window_title ************** //
Chris@16 301 // ************************************************************************** //
Chris@16 302
Chris@16 303 static char*
Chris@16 304 prepare_window_title( dbg_startup_info const& dsi )
Chris@16 305 {
Chris@16 306 typedef unit_test::const_string str_t;
Chris@16 307
Chris@16 308 static char title_str[50];
Chris@16 309
Chris@16 310 str_t path_sep( "\\/" );
Chris@16 311
Chris@16 312 str_t::iterator it = unit_test::find_last_of( dsi.binary_path.begin(), dsi.binary_path.end(),
Chris@16 313 path_sep.begin(), path_sep.end() );
Chris@16 314
Chris@16 315 if( it == dsi.binary_path.end() )
Chris@16 316 it = dsi.binary_path.begin();
Chris@16 317 else
Chris@16 318 ++it;
Chris@16 319
Chris@16 320 ::snprintf( title_str, sizeof(title_str), "%*s %ld", (int)(dsi.binary_path.end()-it), it, dsi.pid );
Chris@16 321
Chris@16 322 return title_str;
Chris@16 323 }
Chris@16 324
Chris@16 325 //____________________________________________________________________________//
Chris@16 326
Chris@16 327 // ************************************************************************** //
Chris@16 328 // ************** save_execlp ************** //
Chris@16 329 // ************************************************************************** //
Chris@16 330
Chris@16 331 typedef unit_test::basic_cstring<char> mbuffer;
Chris@16 332
Chris@16 333 inline char*
Chris@16 334 copy_arg( mbuffer& dest, const_string arg )
Chris@16 335 {
Chris@16 336 if( dest.size() < arg.size()+1 )
Chris@16 337 return 0;
Chris@16 338
Chris@16 339 char* res = dest.begin();
Chris@16 340
Chris@16 341 std::memcpy( res, arg.begin(), arg.size()+1 );
Chris@16 342
Chris@16 343 dest.trim_left( arg.size()+1 );
Chris@16 344
Chris@16 345 return res;
Chris@16 346 }
Chris@16 347
Chris@16 348 //____________________________________________________________________________//
Chris@16 349
Chris@16 350 bool
Chris@16 351 safe_execlp( char const* file, ... )
Chris@16 352 {
Chris@16 353 static char* argv_buff[200];
Chris@16 354
Chris@16 355 va_list args;
Chris@16 356 char const* arg;
Chris@16 357
Chris@16 358 // first calculate actual number of arguments
Chris@16 359 int num_args = 2; // file name and 0 at least
Chris@16 360
Chris@16 361 va_start( args, file );
Chris@16 362 while( !!(arg = va_arg( args, char const* )) )
Chris@16 363 num_args++;
Chris@16 364 va_end( args );
Chris@16 365
Chris@16 366 // reserve space for the argument pointers array
Chris@16 367 char** argv_it = argv_buff;
Chris@16 368 mbuffer work_buff( reinterpret_cast<char*>(argv_buff), sizeof(argv_buff) );
Chris@16 369 work_buff.trim_left( num_args * sizeof(char*) );
Chris@16 370
Chris@16 371 // copy all the argument values into local storage
Chris@16 372 if( !(*argv_it++ = copy_arg( work_buff, file )) )
Chris@16 373 return false;
Chris@16 374
Chris@16 375 printf( "!! %s\n", file );
Chris@16 376
Chris@16 377 va_start( args, file );
Chris@16 378 while( !!(arg = va_arg( args, char const* )) ) {
Chris@16 379 printf( "!! %s\n", arg );
Chris@16 380 if( !(*argv_it++ = copy_arg( work_buff, arg )) )
Chris@16 381 return false;
Chris@16 382 }
Chris@16 383 va_end( args );
Chris@16 384
Chris@16 385 *argv_it = 0;
Chris@16 386
Chris@16 387 return ::execvp( file, argv_buff ) != -1;
Chris@16 388 }
Chris@16 389
Chris@16 390 //____________________________________________________________________________//
Chris@16 391
Chris@16 392 // ************************************************************************** //
Chris@16 393 // ************** start_debugger_in_emacs ************** //
Chris@16 394 // ************************************************************************** //
Chris@16 395
Chris@16 396 static void
Chris@16 397 start_debugger_in_emacs( dbg_startup_info const& dsi, char const* emacs_name, char const* dbg_command )
Chris@16 398 {
Chris@16 399 char const* title = prepare_window_title( dsi );
Chris@16 400
Chris@16 401 if( !title )
Chris@16 402 return;
Chris@16 403
Chris@16 404 dsi.display.is_empty()
Chris@16 405 ? safe_execlp( emacs_name, "-title", title, "--eval", dbg_command, 0 )
Chris@16 406 : safe_execlp( emacs_name, "-title", title, "-display", dsi.display.begin(), "--eval", dbg_command, 0 );
Chris@16 407 }
Chris@16 408
Chris@16 409 //____________________________________________________________________________//
Chris@16 410
Chris@16 411 // ************************************************************************** //
Chris@16 412 // ************** gdb starters ************** //
Chris@16 413 // ************************************************************************** //
Chris@16 414
Chris@16 415 static char const*
Chris@16 416 prepare_gdb_cmnd_file( dbg_startup_info const& dsi )
Chris@16 417 {
Chris@16 418 // prepare pid value
Chris@16 419 char pid_buff[16];
Chris@16 420 ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
Chris@16 421 unit_test::const_string pid_str( pid_buff );
Chris@16 422
Chris@16 423 static char cmd_file_name[] = "/tmp/btl_gdb_cmd_XXXXXX"; // !! ??
Chris@16 424
Chris@16 425 // prepare commands
Chris@16 426 fd_holder cmd_fd( ::mkstemp( cmd_file_name ) );
Chris@16 427
Chris@16 428 if( cmd_fd == -1 )
Chris@16 429 return 0;
Chris@16 430
Chris@16 431 #define WRITE_STR( str ) if( ::write( cmd_fd, str.begin(), str.size() ) == -1 ) return 0;
Chris@16 432 #define WRITE_CSTR( str ) if( ::write( cmd_fd, str, sizeof( str )-1 ) == -1 ) return 0;
Chris@16 433
Chris@16 434 WRITE_CSTR( "file " );
Chris@16 435 WRITE_STR( dsi.binary_path );
Chris@16 436 WRITE_CSTR( "\nattach " );
Chris@16 437 WRITE_STR( pid_str );
Chris@16 438 WRITE_CSTR( "\nshell unlink " );
Chris@16 439 WRITE_STR( dsi.init_done_lock );
Chris@16 440 WRITE_CSTR( "\ncont" );
Chris@16 441 if( dsi.break_or_continue )
Chris@16 442 WRITE_CSTR( "\nup 4" );
Chris@16 443
Chris@16 444 WRITE_CSTR( "\necho \\n" ); // !! ??
Chris@16 445 WRITE_CSTR( "\nlist -" );
Chris@16 446 WRITE_CSTR( "\nlist" );
Chris@16 447 WRITE_CSTR( "\nshell unlink " );
Chris@16 448 WRITE_CSTR( cmd_file_name );
Chris@16 449
Chris@16 450 return cmd_file_name;
Chris@16 451 }
Chris@16 452
Chris@16 453 //____________________________________________________________________________//
Chris@16 454
Chris@16 455 static void
Chris@16 456 start_gdb_in_console( dbg_startup_info const& dsi )
Chris@16 457 {
Chris@16 458 char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
Chris@16 459
Chris@16 460 if( !cmnd_file_name )
Chris@16 461 return;
Chris@16 462
Chris@16 463 safe_execlp( "gdb", "-q", "-x", cmnd_file_name, 0 );
Chris@16 464 }
Chris@16 465
Chris@16 466 //____________________________________________________________________________//
Chris@16 467
Chris@16 468 static void
Chris@16 469 start_gdb_in_xterm( dbg_startup_info const& dsi )
Chris@16 470 {
Chris@16 471 char const* title = prepare_window_title( dsi );
Chris@16 472 char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
Chris@16 473
Chris@16 474 if( !title || !cmnd_file_name )
Chris@16 475 return;
Chris@16 476
Chris@16 477 safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(),
Chris@16 478 "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e",
Chris@16 479 "gdb", "-q", "-x", cmnd_file_name, 0 );
Chris@16 480 }
Chris@16 481
Chris@16 482 //____________________________________________________________________________//
Chris@16 483
Chris@16 484 static void
Chris@16 485 start_gdb_in_emacs( dbg_startup_info const& dsi )
Chris@16 486 {
Chris@16 487 char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
Chris@16 488 if( !cmnd_file_name )
Chris@16 489 return;
Chris@16 490
Chris@16 491 char dbg_cmd_buff[500]; // !! ??
Chris@16 492 ::snprintf( dbg_cmd_buff, sizeof(dbg_cmd_buff), "(progn (gdb \"gdb -q -x %s\"))", cmnd_file_name );
Chris@16 493
Chris@16 494 start_debugger_in_emacs( dsi, "emacs", dbg_cmd_buff );
Chris@16 495 }
Chris@16 496
Chris@16 497 //____________________________________________________________________________//
Chris@16 498
Chris@16 499 static void
Chris@16 500 start_gdb_in_xemacs( dbg_startup_info const& )
Chris@16 501 {
Chris@16 502 // !! ??
Chris@16 503 }
Chris@16 504
Chris@16 505 //____________________________________________________________________________//
Chris@16 506
Chris@16 507 // ************************************************************************** //
Chris@16 508 // ************** dbx starters ************** //
Chris@16 509 // ************************************************************************** //
Chris@16 510
Chris@16 511 static char const*
Chris@16 512 prepare_dbx_cmd_line( dbg_startup_info const& dsi, bool list_source = true )
Chris@16 513 {
Chris@16 514 static char cmd_line_buff[500]; // !! ??
Chris@16 515
Chris@16 516 ::snprintf( cmd_line_buff, sizeof(cmd_line_buff), "unlink %s;cont;%s%s",
Chris@16 517 dsi.init_done_lock.begin(),
Chris@16 518 dsi.break_or_continue ? "up 2;": "",
Chris@16 519 list_source ? "echo \" \";list -w3;" : "" );
Chris@16 520
Chris@16 521 return cmd_line_buff;
Chris@16 522 }
Chris@16 523
Chris@16 524 //____________________________________________________________________________//
Chris@16 525
Chris@16 526 static void
Chris@16 527 start_dbx_in_console( dbg_startup_info const& dsi )
Chris@16 528 {
Chris@16 529 char pid_buff[16];
Chris@16 530 ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
Chris@16 531
Chris@16 532 safe_execlp( "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 );
Chris@16 533 }
Chris@16 534
Chris@16 535 //____________________________________________________________________________//
Chris@16 536
Chris@16 537 static void
Chris@16 538 start_dbx_in_xterm( dbg_startup_info const& dsi )
Chris@16 539 {
Chris@16 540 char const* title = prepare_window_title( dsi );
Chris@16 541 if( !title )
Chris@16 542 return;
Chris@16 543
Chris@16 544 char pid_buff[16]; // !! ??
Chris@16 545 ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
Chris@16 546
Chris@16 547 safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(),
Chris@16 548 "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e",
Chris@16 549 "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 );
Chris@16 550 }
Chris@16 551
Chris@16 552 //____________________________________________________________________________//
Chris@16 553
Chris@16 554 static void
Chris@16 555 start_dbx_in_emacs( dbg_startup_info const& /*dsi*/ )
Chris@16 556 {
Chris@16 557 // char dbg_cmd_buff[500]; // !! ??
Chris@16 558 //
Chris@16 559 // ::snprintf( dbg_cmd_buff, sizeof(dbg_cmd_buff), "(progn (dbx \"dbx -q -c cont %s %ld\"))", dsi.binary_path.begin(), dsi.pid );
Chris@16 560
Chris@16 561 // start_debugger_in_emacs( dsi, "emacs", dbg_cmd_buff );
Chris@16 562 }
Chris@16 563
Chris@16 564 //____________________________________________________________________________//
Chris@16 565
Chris@16 566 static void
Chris@16 567 start_dbx_in_xemacs( dbg_startup_info const& )
Chris@16 568 {
Chris@16 569 // !! ??
Chris@16 570 }
Chris@16 571
Chris@16 572 //____________________________________________________________________________//
Chris@16 573
Chris@16 574 static void
Chris@16 575 start_dbx_in_ddd( dbg_startup_info const& dsi )
Chris@16 576 {
Chris@16 577 char const* title = prepare_window_title( dsi );
Chris@16 578 if( !title )
Chris@16 579 return;
Chris@16 580
Chris@16 581 char pid_buff[16]; // !! ??
Chris@16 582 ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
Chris@16 583
Chris@16 584 safe_execlp( "ddd", "-display", dsi.display.begin(),
Chris@16 585 "--dbx", "-q", "-c", prepare_dbx_cmd_line( dsi, false ), dsi.binary_path.begin(), pid_buff, 0 );
Chris@16 586 }
Chris@16 587
Chris@16 588 //____________________________________________________________________________//
Chris@16 589
Chris@16 590 // ************************************************************************** //
Chris@16 591 // ************** debug::info_t ************** //
Chris@16 592 // ************************************************************************** //
Chris@16 593
Chris@16 594 static struct info_t {
Chris@16 595 // Constructor
Chris@16 596 info_t();
Chris@16 597
Chris@16 598 // Public properties
Chris@16 599 unit_test::readwrite_property<std::string> p_dbg;
Chris@16 600
Chris@16 601 // Data members
Chris@16 602 std::map<std::string,dbg_starter> m_dbg_starter_reg;
Chris@16 603 } s_info;
Chris@16 604
Chris@16 605 //____________________________________________________________________________//
Chris@16 606
Chris@16 607 info_t::info_t()
Chris@16 608 {
Chris@16 609 p_dbg.value = ::getenv( "DISPLAY" )
Chris@16 610 ? std::string( BOOST_STRINGIZE( BOOST_TEST_GUI_DBG ) )
Chris@16 611 : std::string( BOOST_STRINGIZE( BOOST_TEST_CNL_DBG ) );
Chris@16 612
Chris@16 613 m_dbg_starter_reg[std::string("gdb")] = &start_gdb_in_console;
Chris@16 614 m_dbg_starter_reg[std::string("gdb-emacs")] = &start_gdb_in_emacs;
Chris@16 615 m_dbg_starter_reg[std::string("gdb-xterm")] = &start_gdb_in_xterm;
Chris@16 616 m_dbg_starter_reg[std::string("gdb-xemacs")] = &start_gdb_in_xemacs;
Chris@16 617
Chris@16 618 m_dbg_starter_reg[std::string("dbx")] = &start_dbx_in_console;
Chris@16 619 m_dbg_starter_reg[std::string("dbx-emacs")] = &start_dbx_in_emacs;
Chris@16 620 m_dbg_starter_reg[std::string("dbx-xterm")] = &start_dbx_in_xterm;
Chris@16 621 m_dbg_starter_reg[std::string("dbx-xemacs")] = &start_dbx_in_xemacs;
Chris@16 622 m_dbg_starter_reg[std::string("dbx-ddd")] = &start_dbx_in_ddd;
Chris@16 623 }
Chris@16 624
Chris@16 625 //____________________________________________________________________________//
Chris@16 626
Chris@16 627 #endif
Chris@16 628
Chris@16 629 } // local namespace
Chris@16 630
Chris@16 631 // ************************************************************************** //
Chris@16 632 // ************** check if program is running under debugger ************** //
Chris@16 633 // ************************************************************************** //
Chris@16 634
Chris@16 635 bool
Chris@16 636 under_debugger()
Chris@16 637 {
Chris@16 638 #if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
Chris@16 639
Chris@16 640 return !!s_info.m_is_debugger_present && s_info.m_is_debugger_present();
Chris@16 641
Chris@16 642 #elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX
Chris@16 643
Chris@16 644 // !! ?? could/should we cache the result somehow?
Chris@16 645 const_string dbg_list = BOOST_TEST_STRINGIZE( BOOST_TEST_DBG_LIST );
Chris@16 646
Chris@16 647 pid_t pid = ::getpid();
Chris@16 648
Chris@16 649 while( pid != 0 ) {
Chris@16 650 process_info pi( pid );
Chris@16 651
Chris@16 652 // !! ?? should we use tokenizer here instead?
Chris@16 653 if( dbg_list.find( pi.binary_name() ) != const_string::npos )
Chris@16 654 return true;
Chris@16 655
Chris@16 656 pid = (pi.parent_pid() == pid ? 0 : pi.parent_pid());
Chris@16 657 }
Chris@16 658
Chris@16 659 return false;
Chris@16 660
Chris@16 661 #else // ****************************************************** default
Chris@16 662
Chris@16 663 return false;
Chris@16 664
Chris@16 665 #endif
Chris@16 666 }
Chris@16 667
Chris@16 668 //____________________________________________________________________________//
Chris@16 669
Chris@16 670 // ************************************************************************** //
Chris@16 671 // ************** cause program to break execution ************** //
Chris@16 672 // ************** in debugger at call point ************** //
Chris@16 673 // ************************************************************************** //
Chris@16 674
Chris@16 675 void
Chris@16 676 debugger_break()
Chris@16 677 {
Chris@16 678 // !! ?? auto-start debugger?
Chris@16 679
Chris@16 680 #if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
Chris@16 681
Chris@16 682 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1300) || \
Chris@16 683 BOOST_WORKAROUND(__GNUC__, >= 3) && !defined(__MINGW32__) || \
Chris@16 684 defined(__INTEL_COMPILER)
Chris@16 685 # define BOOST_DEBUG_BREAK __debugbreak
Chris@16 686 #else
Chris@16 687 # define BOOST_DEBUG_BREAK DebugBreak
Chris@16 688 #endif
Chris@16 689
Chris@16 690 #ifndef __MINGW32__
Chris@16 691 if( !under_debugger() ) {
Chris@16 692 __try {
Chris@16 693 __try {
Chris@16 694 BOOST_DEBUG_BREAK();
Chris@16 695 }
Chris@16 696 __except( UnhandledExceptionFilter(GetExceptionInformation()) )
Chris@16 697 {
Chris@16 698 // User opted to ignore the breakpoint
Chris@16 699 return;
Chris@16 700 }
Chris@16 701 }
Chris@16 702 __except (EXCEPTION_EXECUTE_HANDLER)
Chris@16 703 {
Chris@16 704 // If we got here, the user has pushed Debug. Debugger is already attached to our process and we
Chris@16 705 // continue to let the another BOOST_DEBUG_BREAK to be called.
Chris@16 706 }
Chris@16 707 }
Chris@16 708 #endif
Chris@16 709
Chris@16 710 BOOST_DEBUG_BREAK();
Chris@16 711
Chris@16 712 #elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX
Chris@16 713
Chris@16 714 ::kill( ::getpid(), SIGTRAP );
Chris@16 715
Chris@16 716 #else // ****************************************************** default
Chris@16 717
Chris@16 718 #endif
Chris@16 719 }
Chris@16 720
Chris@16 721 //____________________________________________________________________________//
Chris@16 722
Chris@16 723 // ************************************************************************** //
Chris@16 724 // ************** console debugger setup ************** //
Chris@16 725 // ************************************************************************** //
Chris@16 726
Chris@16 727 #if defined(BOOST_UNIX_BASED_DEBUG) // ************************ UNIX
Chris@16 728
Chris@16 729 std::string
Chris@16 730 set_debugger( unit_test::const_string dbg_id, dbg_starter s )
Chris@16 731 {
Chris@16 732 std::string old = s_info.p_dbg;
Chris@16 733
Chris@16 734 assign_op( s_info.p_dbg.value, dbg_id, 0 );
Chris@16 735
Chris@16 736 if( !!s )
Chris@16 737 s_info.m_dbg_starter_reg[s_info.p_dbg] = s;
Chris@16 738
Chris@16 739 return old;
Chris@16 740 }
Chris@16 741
Chris@16 742 #else // ***************************************************** default
Chris@16 743
Chris@16 744 std::string
Chris@16 745 set_debugger( unit_test::const_string, dbg_starter )
Chris@16 746 {
Chris@16 747 return std::string();
Chris@16 748 }
Chris@16 749
Chris@16 750 #endif
Chris@16 751
Chris@16 752 //____________________________________________________________________________//
Chris@16 753
Chris@16 754 // ************************************************************************** //
Chris@16 755 // ************** attach debugger to the current process ************** //
Chris@16 756 // ************************************************************************** //
Chris@16 757
Chris@16 758 bool
Chris@16 759 attach_debugger( bool break_or_continue )
Chris@16 760 {
Chris@16 761 if( under_debugger() )
Chris@16 762 return false;
Chris@16 763
Chris@16 764 #if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
Chris@16 765
Chris@16 766 const int MAX_CMD_LINE = 200;
Chris@16 767
Chris@16 768 // *************************************************** //
Chris@16 769 // Debugger "ready" event
Chris@16 770
Chris@16 771 SECURITY_ATTRIBUTES attr;
Chris@16 772 attr.nLength = sizeof(attr);
Chris@16 773 attr.lpSecurityDescriptor = NULL;
Chris@16 774 attr.bInheritHandle = true;
Chris@16 775
Chris@16 776 // manual resettable, initially non signaled, unnamed event,
Chris@16 777 // that will signal me that debugger initialization is done
Chris@16 778 HANDLE dbg_init_done_ev = ::CreateEvent(
Chris@16 779 &attr, // pointer to security attributes
Chris@16 780 true, // flag for manual-reset event
Chris@16 781 false, // flag for initial state
Chris@16 782 NULL // pointer to event-object name
Chris@16 783 );
Chris@16 784
Chris@16 785 if( !dbg_init_done_ev )
Chris@16 786 return false;
Chris@16 787
Chris@16 788 // *************************************************** //
Chris@16 789 // Debugger command line format
Chris@16 790
Chris@16 791 HKEY reg_key;
Chris@16 792
Chris@16 793 if( !s_info.m_reg_open_key || (*s_info.m_reg_open_key)(
Chris@16 794 HKEY_LOCAL_MACHINE, // handle of open key
Chris@16 795 "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", // name of subkey to open
Chris@16 796 &reg_key ) != ERROR_SUCCESS ) // address of handle of open key
Chris@16 797 return false;
Chris@16 798
Chris@16 799 char format[MAX_CMD_LINE];
Chris@16 800 DWORD format_size = MAX_CMD_LINE;
Chris@16 801 DWORD type = REG_SZ;
Chris@16 802
Chris@16 803 if( !s_info.m_reg_query_value || (*s_info.m_reg_query_value)(
Chris@16 804 reg_key, // handle of open key
Chris@16 805 "Debugger", // name of subkey to query
Chris@16 806 0, // reserved
Chris@16 807 &type, // value type
Chris@16 808 (LPBYTE)format, // buffer for returned string
Chris@16 809 &format_size ) != ERROR_SUCCESS ) // in: buffer size; out: actual size of returned string
Chris@16 810 return false;
Chris@16 811
Chris@16 812 if( !s_info.m_reg_close_key || (*s_info.m_reg_close_key)( reg_key ) != ERROR_SUCCESS )
Chris@16 813 return false;
Chris@16 814
Chris@16 815 // *************************************************** //
Chris@16 816 // Debugger command line
Chris@16 817
Chris@16 818 char cmd_line[MAX_CMD_LINE];
Chris@16 819 std::sprintf( cmd_line, format, ::GetCurrentProcessId(), dbg_init_done_ev );
Chris@16 820
Chris@16 821 // *************************************************** //
Chris@16 822 // Debugger window parameters
Chris@16 823
Chris@16 824 STARTUPINFOA startup_info;
Chris@16 825 std::memset( &startup_info, 0, sizeof(startup_info) );
Chris@16 826
Chris@16 827 startup_info.cb = sizeof(startup_info);
Chris@16 828 startup_info.dwFlags = STARTF_USESHOWWINDOW;
Chris@16 829 startup_info.wShowWindow = SW_SHOWNORMAL;
Chris@16 830
Chris@16 831 // debugger process s_info
Chris@16 832 PROCESS_INFORMATION debugger_info;
Chris@16 833
Chris@16 834 bool created = !!::CreateProcessA(
Chris@16 835 NULL, // pointer to name of executable module; NULL - use the one in command line
Chris@16 836 cmd_line, // pointer to command line string
Chris@16 837 NULL, // pointer to process security attributes; NULL - debugger's handle can't be inherited
Chris@16 838 NULL, // pointer to thread security attributes; NULL - debugger's handle can't be inherited
Chris@16 839 true, // debugger inherit opened handles
Chris@16 840 0, // priority flags; 0 - normal priority
Chris@16 841 NULL, // pointer to new environment block; NULL - use this process environment
Chris@16 842 NULL, // pointer to current directory name; NULL - use this process correct directory
Chris@16 843 &startup_info, // pointer to STARTUPINFO that specifies main window appearance
Chris@16 844 &debugger_info // pointer to PROCESS_INFORMATION that will contain the new process identification
Chris@16 845 );
Chris@16 846
Chris@16 847 if( created )
Chris@16 848 ::WaitForSingleObject( dbg_init_done_ev, INFINITE );
Chris@16 849
Chris@16 850 ::CloseHandle( dbg_init_done_ev );
Chris@16 851
Chris@16 852 if( !created )
Chris@16 853 return false;
Chris@16 854
Chris@16 855 if( break_or_continue )
Chris@16 856 debugger_break();
Chris@16 857
Chris@16 858 return true;
Chris@16 859
Chris@16 860 #elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX
Chris@16 861
Chris@16 862 char init_done_lock_fn[] = "/tmp/btl_dbg_init_done_XXXXXX";
Chris@16 863 fd_holder init_done_lock_fd( ::mkstemp( init_done_lock_fn ) );
Chris@16 864
Chris@16 865 if( init_done_lock_fd == -1 )
Chris@16 866 return false;
Chris@16 867
Chris@16 868 pid_t child_pid = fork();
Chris@16 869
Chris@16 870 if( child_pid == -1 )
Chris@16 871 return false;
Chris@16 872
Chris@16 873 if( child_pid != 0 ) { // parent process - here we will start the debugger
Chris@16 874 dbg_startup_info dsi;
Chris@16 875
Chris@16 876 process_info pi( child_pid );
Chris@16 877 if( pi.binary_path().is_empty() )
Chris@16 878 ::exit( -1 );
Chris@16 879
Chris@16 880 dsi.pid = child_pid;
Chris@16 881 dsi.break_or_continue = break_or_continue;
Chris@16 882 dsi.binary_path = pi.binary_path();
Chris@16 883 dsi.display = ::getenv( "DISPLAY" );
Chris@16 884 dsi.init_done_lock = init_done_lock_fn;
Chris@16 885
Chris@16 886 dbg_starter starter = s_info.m_dbg_starter_reg[s_info.p_dbg];
Chris@16 887 if( !!starter )
Chris@16 888 starter( dsi );
Chris@16 889
Chris@16 890 ::perror( "Boost.Test execution monitor failed to start a debugger:" );
Chris@16 891
Chris@16 892 ::exit( -1 );
Chris@16 893 }
Chris@16 894
Chris@16 895 // child process - here we will continue our test module execution ; // !! ?? should it be vice versa
Chris@16 896
Chris@16 897 while( ::access( init_done_lock_fn, F_OK ) == 0 ) {
Chris@16 898 struct timeval to = { 0, 100 };
Chris@16 899
Chris@16 900 ::select( 0, 0, 0, 0, &to );
Chris@16 901 }
Chris@16 902
Chris@16 903 // char dummy;
Chris@16 904 // while( ::read( init_done_lock_fd, &dummy, sizeof(char) ) == 0 );
Chris@16 905
Chris@16 906 if( break_or_continue )
Chris@16 907 debugger_break();
Chris@16 908
Chris@16 909 return true;
Chris@16 910
Chris@16 911 #else // ****************************************************** default
Chris@16 912
Chris@16 913 return false;
Chris@16 914
Chris@16 915 #endif
Chris@16 916 }
Chris@16 917
Chris@16 918 //____________________________________________________________________________//
Chris@16 919
Chris@16 920 // ************************************************************************** //
Chris@16 921 // ************** switch on/off detect memory leaks feature ************** //
Chris@16 922 // ************************************************************************** //
Chris@16 923
Chris@16 924 void
Chris@16 925 detect_memory_leaks( bool on_off )
Chris@16 926 {
Chris@16 927 unit_test::ut_detail::ignore_unused_variable_warning( on_off );
Chris@16 928
Chris@16 929 #ifdef BOOST_MS_CRT_BASED_DEBUG
Chris@16 930 int flags = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
Chris@16 931
Chris@16 932 if( !on_off )
Chris@16 933 flags &= ~_CRTDBG_LEAK_CHECK_DF;
Chris@16 934 else {
Chris@16 935 flags |= _CRTDBG_LEAK_CHECK_DF;
Chris@16 936 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
Chris@16 937 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
Chris@16 938 }
Chris@16 939
Chris@16 940 _CrtSetDbgFlag ( flags );
Chris@16 941 #endif // BOOST_MS_CRT_BASED_DEBUG
Chris@16 942 }
Chris@16 943
Chris@16 944 //____________________________________________________________________________//
Chris@16 945
Chris@16 946 // ************************************************************************** //
Chris@16 947 // ************** cause program to break execution in ************** //
Chris@16 948 // ************** debugger at specific allocation point ************** //
Chris@16 949 // ************************************************************************** //
Chris@16 950
Chris@16 951 void
Chris@16 952 break_memory_alloc( long mem_alloc_order_num )
Chris@16 953 {
Chris@16 954 unit_test::ut_detail::ignore_unused_variable_warning( mem_alloc_order_num );
Chris@16 955
Chris@16 956 #ifdef BOOST_MS_CRT_BASED_DEBUG
Chris@16 957 _CrtSetBreakAlloc( mem_alloc_order_num );
Chris@16 958 #endif // BOOST_MS_CRT_BASED_DEBUG
Chris@16 959 }
Chris@16 960
Chris@16 961 } // namespace debug
Chris@16 962
Chris@16 963 } // namespace boost
Chris@16 964
Chris@16 965 //____________________________________________________________________________//
Chris@16 966
Chris@16 967 #include <boost/test/detail/enable_warnings.hpp>
Chris@16 968
Chris@16 969 #endif // BOOST_TEST_DEBUG_API_IPP_112006GER
Chris@16 970