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 + -
显示快捷键?