debug.ipp

来自「Boost provides free peer-reviewed portab」· IPP 代码 · 共 971 行 · 第 1/2 页

IPP
971
字号
//  (C) Copyright Gennadiy Rozental 2006-2008.//  Use, modification, and distribution are subject to the//  Boost Software License, Version 1.0. (See accompanying file//  http://www.boost.org/LICENSE_1_0.txt)//  See http://www.boost.org/libs/test for the library home page.////  File        : $RCSfile$////  Version     : $Revision: 49312 $////  Description : debug interfaces implementation// ***************************************************************************#ifndef BOOST_TEST_DEBUG_API_IPP_112006GER#define BOOST_TEST_DEBUG_API_IPP_112006GER// Boost.Test#include <boost/test/detail/config.hpp>#include <boost/test/detail/workaround.hpp>#include <boost/test/detail/global_typedef.hpp>#include <boost/test/debug.hpp>#include <boost/test/debug_config.hpp>// Implementation in windows#if defined(_WIN32) && !defined(UNDER_CE) && !defined(BOOST_DISABLE_WIN32) // ******* WIN32#  define BOOST_WIN32_BASED_DEBUG// SYSTEM API#  include <windows.h>#  include <winreg.h>#  include <cstdio>#  include <cstring>#  if !defined(NDEBUG) && defined(_MSC_VER)#    define BOOST_MS_CRT_BASED_DEBUG#    include <crtdbg.h>#  endif#  if BOOST_WORKAROUND( BOOST_MSVC, <1300)#    define snprintf _snprintf#  endif#  ifdef BOOST_NO_STDC_NAMESPACEnamespace std { using ::memset; using ::sprintf; }#  endif#elif defined(unix) || defined(__unix) // ********************* UNIX#  define BOOST_UNIX_BASED_DEBUG// Boost.Test#include <boost/test/utils/class_properties.hpp>#include <boost/test/utils/algorithm.hpp>// STL#include <cstring>  // std::memcpy#include <map>#include <cstdio>#include <stdarg.h> // !! ?? cstdarg// SYSTEM API#  include <unistd.h>#  include <signal.h>#  include <fcntl.h>#  include <sys/types.h>#  include <sys/stat.h>#  include <sys/wait.h>#  include <sys/time.h>#  include <stdio.h>#  include <stdlib.h>#  if defined(sun) || defined(__sun)#    define BOOST_SUN_BASED_DEBUG#    ifndef BOOST_TEST_DBG_LIST#      define BOOST_TEST_DBG_LIST dbx;gdb#    endif#    define BOOST_TEST_CNL_DBG  dbx#    define BOOST_TEST_GUI_DBG  dbx-ddd#    include <procfs.h>#  elif defined(linux) || defined(__linux)#    define BOOST_LINUX_BASED_DEBUG#    include <sys/ptrace.h>#    ifndef BOOST_TEST_STAT_LINE_MAX#      define BOOST_TEST_STAT_LINE_MAX 500#    endif#    ifndef BOOST_TEST_DBG_LIST#      define BOOST_TEST_DBG_LIST gdb#    endif#    define BOOST_TEST_CNL_DBG  gdb#    define BOOST_TEST_GUI_DBG  gdb-xterm#  endif#endif#include <boost/test/detail/suppress_warnings.hpp>//____________________________________________________________________________//namespace boost {namespace debug {using unit_test::const_string;// ************************************************************************** //// **************                debug::info_t                 ************** //// ************************************************************************** //namespace {#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32template<typename T>inline voiddyn_symbol( T& res, char const* module_name, char const* symbol_name ){    HMODULE m = ::GetModuleHandleA( module_name );    if( !m )        m = ::LoadLibraryA( module_name );    res = reinterpret_cast<T>( ::GetProcAddress( m, symbol_name ) );}//____________________________________________________________________________//static struct info_t {    typedef BOOL (WINAPI* IsDebuggerPresentT)();    typedef LONG (WINAPI* RegQueryValueExT)( HKEY, char const* /*LPTSTR*/, LPDWORD, LPDWORD, LPBYTE, LPDWORD );    typedef LONG (WINAPI* RegOpenKeyT)( HKEY, char const* /*LPCTSTR*/, PHKEY );    typedef LONG (WINAPI* RegCloseKeyT)( HKEY );    info_t();    IsDebuggerPresentT  m_is_debugger_present;    RegOpenKeyT         m_reg_open_key;    RegQueryValueExT    m_reg_query_value;    RegCloseKeyT        m_reg_close_key;} s_info;//____________________________________________________________________________//info_t::info_t(){    dyn_symbol( m_is_debugger_present, "kernel32", "IsDebuggerPresent" );    dyn_symbol( m_reg_open_key, "advapi32", "RegOpenKeyA" );    dyn_symbol( m_reg_query_value, "advapi32", "RegQueryValueExA" );    dyn_symbol( m_reg_close_key, "advapi32", "RegCloseKey" );}//____________________________________________________________________________//#elif defined(BOOST_UNIX_BASED_DEBUG)// ************************************************************************** //// **************                   fd_holder                  ************** //// ************************************************************************** //struct fd_holder {    explicit fd_holder( int fd ) : m_fd( fd ) {}    ~fd_holder()    {        if( m_fd != -1 )            ::close( m_fd );    }    operator int() { return m_fd; }private:    // Data members    int m_fd;};// ************************************************************************** //// **************                 process_info                 ************** //// ************************************************************************** //struct process_info {    // Constructor    explicit        process_info( int pid );    // access methods    int             parent_pid() const  { return m_parent_pid; }    const_string    binary_name() const { return m_binary_name; }    const_string    binary_path() const { return m_binary_path; }private:    // Data members    int             m_parent_pid;    const_string    m_binary_name;    const_string    m_binary_path;#if defined(BOOST_SUN_BASED_DEBUG)    struct psinfo   m_psi;#elif defined(BOOST_LINUX_BASED_DEBUG)    char            m_stat_line[BOOST_TEST_STAT_LINE_MAX+1];#endif    char            m_binary_path_buff[500+1]; // !! ??};//____________________________________________________________________________//process_info::process_info( int pid ): m_parent_pid( 0 ){#if defined(BOOST_SUN_BASED_DEBUG)    char fname_buff[30];    ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/psinfo", pid );    fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) );    if( psinfo_fd == -1 )        return;    if( ::read( psinfo_fd, &m_psi, sizeof(m_psi) ) == -1 )        return;    m_parent_pid = m_psi.pr_ppid;    m_binary_name.assign( m_psi.pr_fname );    //-------------------------- //        ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/as", pid );    fd_holder as_fd( ::open( fname_buff, O_RDONLY ) );    uintptr_t   binary_name_pos;      // !! ?? could we avoid reading whole m_binary_path_buff?    if( as_fd == -1 ||        ::lseek( as_fd, m_psi.pr_argv, SEEK_SET ) == -1 ||        ::read ( as_fd, &binary_name_pos, sizeof(binary_name_pos) ) == -1 ||        ::lseek( as_fd, binary_name_pos, SEEK_SET ) == -1 ||        ::read ( as_fd, m_binary_path_buff, sizeof(m_binary_path_buff) ) == -1 )        return;            m_binary_path.assign( m_binary_path_buff );        #elif defined(BOOST_LINUX_BASED_DEBUG)    char fname_buff[30];    ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/stat", pid );    fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) );    if( psinfo_fd == -1 )        return;    ssize_t num_read = ::read( psinfo_fd, m_stat_line, sizeof(m_stat_line)-1 );    if( num_read == -1 )        return;    m_stat_line[num_read] = 0;    char const* name_beg = m_stat_line;    while( *name_beg && *name_beg != '(' )        ++name_beg;    char const* name_end = name_beg+1;    while( *name_end && *name_end != ')' )        ++name_end;    std::sscanf( name_end+1, "%*s%d", &m_parent_pid );    m_binary_name.assign( name_beg+1, name_end );    ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/exe", pid );    num_read = ::readlink( fname_buff, m_binary_path_buff, sizeof(m_binary_path_buff)-1 );    if( num_read == -1 )        return;    m_binary_path_buff[num_read] = 0;    m_binary_path.assign( m_binary_path_buff, num_read );#endif}//____________________________________________________________________________//// ************************************************************************** //// **************             prepare_window_title             ************** //// ************************************************************************** //static char*prepare_window_title( dbg_startup_info const& dsi ){    typedef unit_test::const_string str_t;    static char title_str[50];    str_t path_sep( "\\/" );    str_t::iterator  it = unit_test::find_last_of( dsi.binary_path.begin(), dsi.binary_path.end(),                                                   path_sep.begin(), path_sep.end() );    if( it == dsi.binary_path.end() )        it = dsi.binary_path.begin();    else        ++it;    ::snprintf( title_str, sizeof(title_str), "%*s %ld", (int)(dsi.binary_path.end()-it), it, dsi.pid );    return title_str;}//____________________________________________________________________________//// ************************************************************************** //// **************                  save_execlp                 ************** //// ************************************************************************** //typedef unit_test::basic_cstring<char> mbuffer;inline char*copy_arg( mbuffer& dest, const_string arg ){    if( dest.size() < arg.size()+1 )        return 0;    char* res = dest.begin();    std::memcpy( res, arg.begin(), arg.size()+1 );    dest.trim_left( arg.size()+1 );    return res;}//____________________________________________________________________________//boolsafe_execlp( char const* file, ... ){    static char* argv_buff[200];    va_list     args;    char const* arg;    // first calculate actual number of arguments    int         num_args = 2; // file name and 0 at least    va_start( args, file );    while( !!(arg = va_arg( args, char const* )) )        num_args++;    va_end( args );    // reserve space for the argument pointers array    char**      argv_it  = argv_buff;    mbuffer     work_buff( reinterpret_cast<char*>(argv_buff), sizeof(argv_buff) );    work_buff.trim_left( num_args * sizeof(char*) );    // copy all the argument values into local storage    if( !(*argv_it++ = copy_arg( work_buff, file )) )        return false;    printf( "!! %s\n", file );    va_start( args, file );    while( !!(arg = va_arg( args, char const* )) ) {        printf( "!! %s\n", arg );        if( !(*argv_it++ = copy_arg( work_buff, arg )) )            return false;    }    va_end( args );    *argv_it = 0;    return ::execvp( file, argv_buff ) != -1;}//____________________________________________________________________________//// ************************************************************************** //// **************            start_debugger_in_emacs           ************** //// ************************************************************************** //static voidstart_debugger_in_emacs( dbg_startup_info const& dsi, char const* emacs_name, char const* dbg_command ){    char const* title = prepare_window_title( dsi );    if( !title )        return;    dsi.display.is_empty()        ? safe_execlp( emacs_name, "-title", title, "--eval", dbg_command, 0 )        : safe_execlp( emacs_name, "-title", title, "-display", dsi.display.begin(), "--eval", dbg_command, 0 );}//____________________________________________________________________________//// ************************************************************************** //// **************                 gdb starters                 ************** //// ************************************************************************** //static char const*prepare_gdb_cmnd_file( dbg_startup_info const& dsi ){    // prepare pid value    char pid_buff[16];    ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );    unit_test::const_string pid_str( pid_buff );    static char cmd_file_name[] = "/tmp/btl_gdb_cmd_XXXXXX"; // !! ??    // prepare commands    fd_holder cmd_fd( ::mkstemp( cmd_file_name ) );    if( cmd_fd == -1 )        return 0;#define WRITE_STR( str )  if( ::write( cmd_fd, str.begin(), str.size() ) == -1 ) return 0;#define WRITE_CSTR( str ) if( ::write( cmd_fd, str, sizeof( str )-1 ) == -1 ) return 0;    WRITE_CSTR( "file " );    WRITE_STR( dsi.binary_path );    WRITE_CSTR( "\nattach " );    WRITE_STR( pid_str );    WRITE_CSTR( "\nshell unlink " );    WRITE_STR( dsi.init_done_lock );    WRITE_CSTR( "\ncont" );    if( dsi.break_or_continue )        WRITE_CSTR( "\nup 4" );                WRITE_CSTR( "\necho \\n" ); // !! ??    WRITE_CSTR( "\nlist -" );    WRITE_CSTR( "\nlist" );    WRITE_CSTR( "\nshell unlink " );    WRITE_CSTR( cmd_file_name );    return cmd_file_name;}//____________________________________________________________________________//static voidstart_gdb_in_console( dbg_startup_info const& dsi ){    char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );    if( !cmnd_file_name )        return;    safe_execlp( "gdb", "-q", "-x", cmnd_file_name, 0 );}//____________________________________________________________________________//static voidstart_gdb_in_xterm( dbg_startup_info const& dsi ){    char const* title           = prepare_window_title( dsi );    char const* cmnd_file_name  = prepare_gdb_cmnd_file( dsi );    if( !title || !cmnd_file_name )        return;    safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(),                    "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e",                 "gdb", "-q", "-x", cmnd_file_name, 0 );}//____________________________________________________________________________//static voidstart_gdb_in_emacs( dbg_startup_info const& dsi ){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?