📄 memcheck_object.cpp
字号:
/* --------------------------------------------------------------------- * Implementation of class Memcheck memcheck_object.cpp * Memcheck-specific options / flags / fns * --------------------------------------------------------------------- * This file is part of Valkyrie, a front-end for Valgrind * Copyright (c) 2000-2006, OpenWorks LLP <info@open-works.co.uk> * This program is released under the terms of the GNU GPL v.2 * See the file LICENSE.GPL for the full license details. */#include "memcheck_object.h"#include "valkyrie_object.h"#include "vk_config.h"#include "html_urls.h"#include "vk_messages.h"#include "vk_option.h" // PERROR* and friends #include "vk_file_utils.h" // FileCopy()#include "vk_utils.h" // vk_assert, VK_DEBUG, etc.#include <qapplication.h>#include <qtimer.h>/* class Memcheck ------------------------------------------------------ */Memcheck::~Memcheck(){ if (m_vgproc) { m_vgproc->disconnect(); /* so no signal calling processDone() */ if (m_vgproc->isRunning()) { m_vgproc->stop(); } delete m_vgproc; m_vgproc = 0; } if (m_vgreader) { delete m_vgreader; m_vgreader = 0; } /* m_logpoller deleted by it's parent: 'this' */ /* unsaved log... delete our temp file */ if (!m_fileSaved && !m_saveFname.isEmpty()) QDir().remove( m_saveFname );}Memcheck::Memcheck( int objId ) : ToolObject( "Memcheck", "&Memcheck", Qt::SHIFT+Qt::Key_M, objId ) { /* init vars */ m_fileSaved = true; m_vgproc = 0; m_vgreader = 0; m_logpoller = new VkLogPoller( this, "memcheck logpoller" ); connect( m_logpoller, SIGNAL(logUpdated()), this, SLOT(readVgLog()) ); /* these opts should be kept in exactly the same order as valgrind outputs them, as it makes keeping up-to-date a lot easier. */ addOpt( LEAK_CHECK, VkOPTION::ARG_STRING, VkOPTION::WDG_COMBO, "memcheck", '\0', "leak-check", "<no|summary|full>", "no|summary|full", "full", "Search for memory leaks at exit:", "search for memory leaks at exit?", urlMemcheck::Leakcheck ); addOpt( LEAK_RES, VkOPTION::ARG_STRING, VkOPTION::WDG_COMBO, "memcheck", '\0', "leak-resolution", "<low|med|high>", "low|med|high", "low", "Degree of backtrace merging:", "how much backtrace merging in leak check", urlMemcheck::Leakres ); addOpt( SHOW_REACH, VkOPTION::ARG_BOOL, VkOPTION::WDG_CHECK, "memcheck", '\0', "show-reachable", "<yes|no>", "yes|no", "no", "Show reachable blocks in leak check", "show reachable blocks in leak check?", urlMemcheck::Showreach ); addOpt( UNDEF_VAL, VkOPTION::ARG_BOOL, VkOPTION::WDG_CHECK, "memcheck", '\0', "undef-value-errors", "<yes|no>", "yes|no", "yes", "Check for undefined value errors", "check for undefined value errors?", urlMemcheck::UndefVal ); addOpt( PARTIAL, VkOPTION::ARG_BOOL, VkOPTION::WDG_CHECK, "memcheck", '\0', "partial-loads-ok", "<yes|no>", "yes|no", "no", "Ignore errors on partially invalid addresses", "too hard to explain here; see manual", urlMemcheck::Partial ); addOpt( FREELIST, VkOPTION::ARG_UINT, VkOPTION::WDG_LEDIT, "memcheck", '\0', "freelist-vol", "<number>", "0|1000000000", "5000000", "Volume of freed blocks queue:", "volume of freed blocks queue", urlMemcheck::Freelist ); addOpt( GCC_296, VkOPTION::ARG_BOOL, VkOPTION::WDG_CHECK, "memcheck", '\0', "workaround-gcc296-bugs", "<yes|no>", "yes|no", "no", "Work around gcc-296 bugs", "self explanatory", urlMemcheck::gcc296 ); addOpt( ALIGNMENT, VkOPTION::ARG_PWR2, VkOPTION::WDG_SPINBOX, "memcheck", '\0', "alignment", "<number>", "8|1048576", "8", "Minimum alignment of allocations", "set minimum alignment of allocations", urlVgCore::Alignment );}/* check argval for this option, updating if necessary. called by parseCmdArgs() and gui option pages -------------------- */int Memcheck::checkOptArg( int optid, QString& argval ){ vk_assert( optid >= 0 && optid < NUM_OPTS ); int errval = PARSED_OK; Option* opt = findOption( optid ); switch ( (Memcheck::mcOpts)optid ) { case PARTIAL: case FREELIST: case LEAK_RES: case SHOW_REACH: case UNDEF_VAL: case GCC_296: case ALIGNMENT: opt->isValidArg( &errval, argval ); break; /* when using xml output from valgrind, this option is preset to 'full' by valgrind, so this option should not be used. */ case LEAK_CHECK: /* Note: gui options disabled, so only reaches here from cmdline */ errval = PERROR_BADOPT; vkPrintErr("Option disabled '--%s'", opt->m_longFlag.latin1()); vkPrintErr(" - Memcheck presets this option to 'full' when generating the required xml output."); vkPrintErr(" - See valgrind/docs/internals/xml_output.txt."); break; default: vk_assert_never_reached(); } return errval;}/* called from Valkyrie::updateVgFlags() whenever flags have been changed */QStringList Memcheck::modifiedVgFlags(){ QStringList modFlags; QString defVal, cfgVal, flag; Option* opt; for ( opt = m_optList.first(); opt; opt = m_optList.next() ) { flag = opt->m_longFlag.isEmpty() ? opt->m_shortFlag : opt->m_longFlag; defVal = opt->m_defaultValue; /* opt holds the default */ cfgVal = vkConfig->rdEntry( opt->m_longFlag, name() ); switch ( (Memcheck::mcOpts)opt->m_key ) { /* when using xml output from valgrind, this option is preset to 'full' by valgrind, so this option should not be used. */ case LEAK_CHECK: /* ignore this opt */ break; default: if ( defVal != cfgVal ) modFlags << "--" + opt->m_longFlag + "=" + cfgVal; } } return modFlags;}/* Creates this tool's ToolView window, and sets up and connections between them */ToolView* Memcheck::createView( QWidget* parent ){ m_view = new MemcheckView( parent, this->name() ); /* signals view --> tool */ connect( m_view, SIGNAL(saveLogFile()), this, SLOT(fileSaveDialog()) ); /* signals tool --> view */ connect( this, SIGNAL(running(bool)), m_view, SLOT(setState(bool)) ); setRunState( VkRunState::STOPPED ); return m_view;}/* outputs a message to the status bar. */void Memcheck::statusMsg( QString hdr, QString msg ) { emit message( hdr + ": " + msg );}/* are we done and dusted? anything we need to check/do before being deleted/closed?*/bool Memcheck::queryDone(){ vk_assert( view() != 0 ); /* if current process is not yet finished, ask user if they really want to close */ if ( isRunning() ) { int ok = vkQuery( view(), "Process Running", "&Abort;&Cancel", "<p>The current process is not yet finished.</p>" "<p>Do you want to abort it ?</p>" ); /* Note: process may have finished while waiting for user */ if ( ok == MsgBox::vkYes ) { stop(); /* abort */ vk_assert( !isRunning() ); } else if ( ok == MsgBox::vkNo ) { return false; /* continue */ } } if (!queryFileSave()) return false; // not saved: procrastinate. return true;}/* if current output not saved, ask user if want to save returns false if not saved, but user wants to procrastinate.*/bool Memcheck::queryFileSave(){ vk_assert( view() != 0 ); vk_assert( !isRunning() ); /* currently loaded / parsed stuff is saved to tmp file - ask user if they want to save it to a 'real' file */ if ( !m_fileSaved ) { int ok = vkQuery( view(), "Unsaved File", "&Save;&Discard;&Cancel", "<p>The current output is not saved, " " and will be deleted.<br/>" "Do you want to save it ?</p>" ); if ( ok == MsgBox::vkYes ) { /* save */ if ( !fileSaveDialog() ) { /* user clicked Cancel, but we already have the auto-fname saved anyway, so get outta here. */ return false; } } else if ( ok == MsgBox::vkCancel ) { /* procrastinate */ return false; } else { /* discard */ QFile::remove( m_saveFname ); m_fileSaved = true; } } return true;}bool Memcheck::start( VkRunState::State rs, QStringList vgflags ){ bool ok = false; vk_assert( rs != VkRunState::STOPPED ); vk_assert( !isRunning() ); switch ( rs ) { case VkRunState::VALGRIND: { ok = runValgrind( vgflags ); break; } case VkRunState::TOOL1: { ok = parseLogFile(); break; } case VkRunState::TOOL2: { ok = mergeLogFiles(); break; } default: vk_assert_never_reached(); } return ok;}/* stop a process - doesn't exit until process stopped. - may take some time for process to respond: too much time and it just gets terminated. */void Memcheck::stop(){ if ( !isRunning() ) return; switch ( runState() ) { case VkRunState::VALGRIND: { if (m_vgproc && m_vgproc->isRunning() ) m_vgproc->stop(); /* signal -> processDone() */ } break; case VkRunState::TOOL1: { /* parse log */ /* TODO: make log parsing a VkProcess. This will allow - valkyrie to stay responsive - the ability to interrupt the process if taking too long */ VK_DEBUG("TODO: Memcheck::stop(parse log)" ); } break; case VkRunState::TOOL2: { /* merge logs */ if (m_vgproc && m_vgproc->isRunning() ) m_vgproc->stop(); /* signal -> processDone() */ } break; default: vk_assert_never_reached(); } /* spin until done */ while ( isRunning() ) qApp->processEvents(); return;}/* if --vg-opt=<arg> was specified on the cmd-line, called by valkyrie->runTool(); if set via the run-button in the gui, then MainWindow::run() calls valkyrie->runTool(). */bool Memcheck::runValgrind( QStringList vgflags ){ m_saveFname = vk_mkstemp( vkConfig->logsDir() + "mc_log", "xml" ); vk_assert( !m_saveFname.isEmpty() ); /* fill in filename in flags list */#if (QT_VERSION-0 >= 0x030200) vgflags.gres( "--log-file-exactly", "--log-file-exactly=" + m_saveFname );#else // QT_VERSION < 3.2 QStringList::iterator it_str = vgflags.find("--log-file-exactly"); if (it_str != vgflags.end()) (*it_str) += ("=" + m_saveFname);#endif setRunState( VkRunState::VALGRIND ); m_fileSaved = false; statusMsg( "Memcheck", "Running ... " ); bool ok = startProcess( vgflags ); if (!ok) { statusMsg( "Memcheck", "Failed" ); m_fileSaved = true; setRunState( VkRunState::STOPPED ); } return ok;}/* Parse log file given by [valkyrie::view-log] entry. Called by valkyrie->runTool() if cmdline --view-log=<file> specified. MemcheckView::openLogFile() if gui parse-log selected. If 'checked' == true, file perms/format has already been checked */bool Memcheck::parseLogFile()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -