blob: a956d45141b4f050a306500824728dc19db903af [file]
/* **********************************************************
* Copyright (c) 2013 Google, Inc. All rights reserved.
* Copyright (c) 2007-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2002-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2002 Hewlett-Packard Company */
// OptionsDlg.cpp : implementation file
//
#include "configure.h"
#ifndef DRSTATS_DEMO /* around whole file */
#include "stdafx.h"
#include "DynamoRIO.h"
#include "OptionsDlg.h"
#include "LoggingDlg.h"
#include <assert.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
enum {
HOT_THRESHOLD = 0,
INSTRLIBNAME,
CACHE_BB_MAX,
CACHE_TRACE_MAX,
LOGLEVEL,
LOGMASK,
PROF_COUNTS,
PROF_PCS,
NOASYNCH,
NOLINK,
NULLCALLS,
STATS,
NOTIFY,
TRACEDUMP_TEXT,
TRACEDUMP_BINARY,
TRACEDUMP_ORIGINS,
};
static const TCHAR * names[] = {
_T("-hot_threshold"),
_T("-client_lib"),
_T("-cache_bb_max"),
_T("-cache_trace_max"),
_T("-loglevel"),
_T("-logmask"),
_T("-prof_counts"),
_T("-prof_pcs"),
_T("-noasynch"),
_T("-nolink"),
_T("-nullcalls"),
_T("-stats"),
_T("-notify"),
_T("-tracedump_text"),
_T("-tracedump_binary"),
_T("-tracedump_origins"),
};
// numeric values are always positive! (no leading - assumed)
enum value_type {
NOVALUE = 0,
NUM_DECIMAL,
NUM_HEX,
STRING
};
static const value_type hasvalue[] = {
NUM_DECIMAL,
STRING,
NUM_DECIMAL,
NUM_DECIMAL,
NUM_DECIMAL,
NUM_HEX, // logmask
NOVALUE,
NOVALUE,
NOVALUE, // noasynch
NOVALUE,
NOVALUE,
NOVALUE, // stats
NOVALUE, // notify
NOVALUE, // tracedump_text
NOVALUE,
NOVALUE,
};
static const int checkboxes[] = {
IDC_HOT_THRESHOLD,
IDC_INSTRLIBNAME,
IDC_CACHE_BB_MAX,
IDC_CACHE_TRACE_MAX,
IDC_LOGLEVEL,
IDC_LOGMASK,
IDC_PROF_COUNTS,
IDC_PROF_PCS,
IDC_NOASYNCH,
IDC_NOLINK,
IDC_NULLCALLS,
IDC_STATS,
IDC_NOTIFY,
IDC_TRACEDUMP_TEXT,
IDC_TRACEDUMP_BINARY,
IDC_TRACEDUMP_ORIGINS,
};
static const BOOL ok_with_release[] = {
TRUE,
TRUE,
TRUE,
TRUE,
FALSE, // loglevel
FALSE, // logmask
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
FALSE, // stats
FALSE, // notify
TRUE,
TRUE,
TRUE,
};
static const int num_options = sizeof(checkboxes) / sizeof(int);
static CString * values[num_options];
/////////////////////////////////////////////////////////////////////////////
// COptionsDlg dialog
COptionsDlg::COptionsDlg(CWnd* pParent /*=NULL*/)
: CDialog(COptionsDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(COptionsDlg)
m_opstring = _T("");
m_HotThreshold = _T("50");
m_InstrLibName = _T("");
m_CacheBBMax = _T("0");
m_CacheTraceMax = _T("0");
m_LogLevel = _T("0");
m_LogMask = _T("0x3FFF");
//}}AFX_DATA_INIT
values[HOT_THRESHOLD] = &m_HotThreshold;
values[INSTRLIBNAME] = &m_InstrLibName;
values[CACHE_BB_MAX] = &m_CacheBBMax;
values[CACHE_TRACE_MAX] = &m_CacheTraceMax;
values[LOGLEVEL] = &m_LogLevel;
values[LOGMASK] = &m_LogMask;
// rest of initialization goes in OnInitDialog, once controls are built
}
void COptionsDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(COptionsDlg)
DDX_Control(pDX, IDOK, m_OKButton);
DDX_Text(pDX, IDC_OPTIONS_EDIT, m_opstring);
DDX_Text(pDX, IDC_EDIT_HOT_THRESHOLD, m_HotThreshold);
DDX_Text(pDX, IDC_EDIT_INSTRLIBNAME, m_InstrLibName);
DDX_Text(pDX, IDC_EDIT_CACHE_BB_MAX, m_CacheBBMax);
DDX_Text(pDX, IDC_EDIT_CACHE_TRACE_MAX, m_CacheTraceMax);
DDX_Text(pDX, IDC_EDIT_LOGLEVEL, m_LogLevel);
DDX_Text(pDX, IDC_EDIT_LOGMASK, m_LogMask);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(COptionsDlg, CDialog)
//{{AFX_MSG_MAP(COptionsDlg)
ON_BN_CLICKED(IDC_HOT_THRESHOLD, OnHotThreshold)
ON_BN_CLICKED(IDC_BROWSE_INSTRLIBNAME, OnBrowseInstrlibname)
ON_BN_CLICKED(IDC_INSTRLIBNAME, OnInstrlibname)
ON_BN_CLICKED(IDC_LOGGING_BUTTON, OnLoggingButton)
ON_EN_CHANGE(IDC_OPTIONS_EDIT, OnChangeOptionsEdit)
ON_BN_CLICKED(IDC_CACHE_BB_MAX, OnCacheBBMax)
ON_BN_CLICKED(IDC_CACHE_TRACE_MAX, OnCacheTraceMax)
ON_BN_CLICKED(IDC_LOGLEVEL, OnLoglevel)
ON_BN_CLICKED(IDC_LOGMASK, OnLogmask)
ON_BN_CLICKED(IDC_PROF_PCS, OnProfPcs)
ON_BN_CLICKED(IDC_PROF_COUNTS, OnProfCounts)
ON_BN_CLICKED(IDC_STATS, OnStats)
ON_BN_CLICKED(IDC_NOTIFY, OnNotify)
ON_BN_CLICKED(IDC_NULLCALLS, OnNullcalls)
ON_BN_CLICKED(IDC_NOLINK, OnNolink)
ON_BN_CLICKED(IDC_NOASYNCH, OnNoasynch)
ON_BN_CLICKED(IDC_TRACEDUMP_TEXT, OnTraceDumpText)
ON_BN_CLICKED(IDC_TRACEDUMP_BINARY, OnTraceDumpBinary)
ON_BN_CLICKED(IDC_TRACEDUMP_ORIGINS, OnTraceDumpOrigins)
ON_EN_CHANGE(IDC_EDIT_INSTRLIBNAME, OnChangeEditInstrlibname)
ON_BN_CLICKED(IDC_SET_PERMANENT, OnSetPermanent)
ON_EN_CHANGE(IDC_EDIT_CACHE_BB_MAX, OnChangeEditCacheBbMax)
ON_EN_CHANGE(IDC_EDIT_CACHE_TRACE_MAX, OnChangeEditCacheTraceMax)
ON_EN_CHANGE(IDC_EDIT_HOT_THRESHOLD, OnChangeEditHotThreshold)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COptionsDlg message handlers
BOOL COptionsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// get current options string
TCHAR path[MAX_PATH];
int len = GetEnvironmentVariable(_T("DYNAMORIO_OPTIONS"), path, MAX_PATH);
assert(len <= MAX_PATH);
if (len > 0 && len <= MAX_PATH)
m_opstring = path; // makes new storage, right?
UpdateData(FALSE); // FALSE means set controls
// set controls based on opstring
if (!CheckOpstring()) {
MessageBox(_T("Invalid DYNAMORIO_OPTIONS string!\nThis dialog ")
_T("may not work properly with it."), _T("Error"),
MB_OK | MYMBFLAGS);
}
// now disable appropriate options
// always disabled, only there so can see all options
DisableCheckbox(IDC_PROF_PCS);
DLL_TYPE dll_type = CDynamoRIOApp::GetDllType();
if (dll_type != DLL_PROFILE) {
DisableCheckbox(IDC_PROF_COUNTS);
}
if (dll_type == DLL_RELEASE) {
int i;
for (i=0; i<num_options; i++) {
if (!ok_with_release[i]) {
DisableCheckbox(checkboxes[i]);
}
}
}
UpdateData(FALSE); // FALSE means set controls
return TRUE;
}
void COptionsDlg::OnOK()
{
UpdateData(TRUE); // TRUE means read from controls
// set options string
BOOL res = SetEnvironmentVariable(_T("DYNAMORIO_OPTIONS"), m_opstring);
assert(res);
CDialog::OnOK();
}
void COptionsDlg::OnChangeOptionsEdit()
{
if (CheckOpstring()) {
m_OKButton.EnableWindow(TRUE);
} else {
m_OKButton.EnableWindow(FALSE);
}
}
static BOOL
is_quote(TCHAR ch)
{
return (ch == _T('\'') || ch == _T('\"') || ch == _T('`'));
}
static BOOL
is_whitespace(TCHAR ch)
{
return (ch == _T(' ') || ch == _T('\t') ||
ch == _T('\n') || ch == _T('\r'));
}
// returns the space delimited or quote-delimited word
// starting at strpos in the string str
// maximum word length: MAX_PATH*2
static BOOL
getword(TCHAR *str, TCHAR **strpos, TCHAR *result)
{
result[0] = _T('\0');
int i = 0;
TCHAR *pos = *strpos;
TCHAR quote = _T('\0');
if (pos < str || pos >= str + _tcslen(str))
return FALSE;
if (*pos == _T('\0'))
return FALSE; /* no more words */
/* eat leading spaces */
while (is_whitespace(*pos)) {
pos++;
}
/* extract the word */
if (is_quote(*pos)) {
quote = *pos;
pos++; /* don't include surrounding quotes in word */
}
while (*pos) {
if (quote != _T('\0')) {
/* if quoted, only end on matching quote */
if (*pos == quote) {
pos++; /* include the quote */
break;
}
} else {
/* if not quoted, end on whitespace */
if (is_whitespace(*pos))
break;
}
result[i++] = *pos;
pos++;
assert(i < MAX_PATH*2);
}
if (i == 0)
return NULL; /* no more words */
result[i] = _T('\0');
*strpos = pos;
return TRUE;
}
// returns the beginning and ending positions of the
// parameter names[id] in the string str, including its value,
// if it has one (based on has_value[id]).
// beginning position includes leading whitespace!
// start is inclusive, end is exclusive
static BOOL
find_param(TCHAR *str, int id, int &start, int &end)
{
TCHAR *pos = str;
TCHAR *prev_pos = str;
TCHAR word[MAX_PATH*2];
while (true) {
if (!getword(str, &pos, word))
break;
if (_tcscmp(word, names[id]) == 0) {
if (hasvalue[id] != NOVALUE) {
TCHAR *last_pos = pos;
if (!getword(str, &pos, word)) {
// don't return FALSE, just return empty value
} else if ((hasvalue[id] == NUM_DECIMAL || hasvalue[id] == NUM_HEX) &&
word[0] == '-') {
// assumption: no numeric value begins with - (no negative numbers)
pos = last_pos;
}
}
start = (int) (prev_pos - str);
end = (int) (pos - str);
return TRUE;
}
prev_pos = pos;
}
return FALSE;
}
static void
expand_ws_quotes(CString str, int &start, int &end)
{
// start is inclusive, end is exclusive
// remove preceding quote, if present
while (start > 0 && is_quote(str.GetAt(start-1))) {
start--;
}
// now remove preceding spaces
while (start > 0 && is_whitespace(str.GetAt(start-1))) {
start--;
}
// remove following quote, if present
while (end < str.GetLength() && is_quote(str.GetAt(end))) {
end++;
}
// remove following spaces beyond a single space
while (end + 1 < str.GetLength() &&
(is_whitespace(str.GetAt(end)) || is_quote(str.GetAt(end))) &&
(is_whitespace(str.GetAt(end+1)) || is_quote(str.GetAt(end+1)))) {
end++;
}
// remove following space if at start
if (start == 0 && end < str.GetLength() &&
(is_whitespace(str.GetAt(end)) || is_quote(str.GetAt(end)))) {
end++;
}
}
// FIXME: share parsing code with non-static routines?
/*static*/ BOOL COptionsDlg::CheckOptionsVersusDllType(DLL_TYPE dll_type)
{
TCHAR msg[MAX_PATH];
// this is independent of dialog box -- so grab string separately
int len = GetEnvironmentVariable(_T("DYNAMORIO_OPTIONS"), msg, MAX_PATH);
if (len == 0 || len > MAX_PATH)
msg[0] = _T('\0');
CString opstring = msg;
// now parse string
int i;
TCHAR param[MAX_PATH];
TCHAR value[MAX_PATH];
TCHAR *pos = opstring.GetBuffer(0);
TCHAR *prev_pos = pos;
while (TRUE) {
if (!getword(opstring.GetBuffer(0), &pos, param))
break;
for (i=0; i<num_options; i++) {
if (_tcscmp(param, names[i]) == 0) {
if (hasvalue[i] != NOVALUE) {
// grab next space-delimited word
getword(opstring.GetBuffer(0), &pos, value);
} else
value[0] = _T('\0');
if ((dll_type == DLL_RELEASE && !ok_with_release[i]) ||
(dll_type != DLL_PROFILE && i == PROF_COUNTS)) {
_stprintf(msg, _T("Option \"%s%s%s\" is incompatible with the selected library.\n")
_T("Remove it? Incompatible options cause failure.\n"),
param, (hasvalue[i] != NOVALUE) ? _T(" ") : _T(""), value);
int res = ::MessageBox(NULL, msg, _T("Confirmation"), MB_YESNO | MYMBFLAGS);
if (res == IDYES) {
int start = (prev_pos - opstring.GetBuffer(0));
int end = (pos - opstring.GetBuffer(0));
BOOL ok;
expand_ws_quotes(opstring, start, end);
opstring = opstring.Left(start) +
opstring.Right(opstring.GetLength() - end);
// update pos
pos = opstring.GetBuffer(0) + start;
ok = SetEnvironmentVariable(_T("DYNAMORIO_OPTIONS"), opstring);
assert(ok);
}
}
}
}
prev_pos = pos;
}
return TRUE;
}
// examines m_opstring, sets checkboxes and edit boxes from it, and returns
// false if an error is found (doesn't finish reading string if error is found)
BOOL COptionsDlg::CheckOpstring()
{
UpdateData(TRUE); // TRUE means read from controls
// now parse string
TCHAR param[MAX_PATH];
TCHAR value[MAX_PATH];
TCHAR *pos = m_opstring.GetBuffer(0);
TCHAR *prev_pos;
BOOL valid = TRUE;
BOOL matched_any;
BOOL match[num_options];
int i;
for (i=0; i<num_options; i++)
match[i] = FALSE;
DLL_TYPE dll_type = CDynamoRIOApp::GetDllType();
while (TRUE) {
if (!getword(m_opstring.GetBuffer(0), &pos, param))
break;
matched_any = FALSE;
for (i=0; i<num_options; i++) {
if (_tcscmp(param, names[i]) == 0) {
CButton *button = (CButton *) GetDlgItem(checkboxes[i]);
assert(button != NULL);
if (button->GetCheck() == 0)
button->SetCheck(1);
match[i] = TRUE;
matched_any = TRUE;
if (hasvalue[i] != NOVALUE) {
prev_pos = pos;
if (!getword(m_opstring.GetBuffer(0), &pos, value)) {
match[i] = FALSE;
valid = FALSE;
*values[i] = _T("");
} else {
*values[i] = value;
if (i == INSTRLIBNAME) {
if (!CheckLibraryExists(value, FALSE)) {
match[i] = FALSE;
valid = FALSE;
}
}
if (hasvalue[i] == NUM_DECIMAL || hasvalue[i] == NUM_HEX) {
if (value[0] == _T('-')) {
// value is missing, don't claim next param as value!
// (for string (non-numeric) values, go ahead and do so)
pos = prev_pos;
*values[i] = _T("");
match[i] = FALSE;
valid = FALSE;
break;
}
int j;
int len = _tcslen(value);
for (j=0; j<len; j++) {
if ((hasvalue[i] == NUM_DECIMAL && !_istdigit(value[j])) ||
(hasvalue[i] == NUM_HEX &&
((j == 0 && value[j] != _T('0')) ||
(j == 1 && value[j] != _T('x') && value[j] != _T('X')) ||
(j > 1 && !_istxdigit(value[j]))))) {
match[i] = FALSE;
valid = FALSE;
break;
}
}
}
}
} else {
match[i] = TRUE;
matched_any = TRUE;
}
if (match[i]) {
// if made it this far, now check vs. dll type
if ((dll_type == DLL_RELEASE && !ok_with_release[i]) ||
(dll_type != DLL_PROFILE && i == PROF_COUNTS)) {
// leave it checked
valid = FALSE;
}
}
break;
}
}
if (!matched_any)
valid = FALSE;
}
for (i=0; i<num_options; i++) {
if (!match[i]) {
CButton *button = (CButton *) GetDlgItem(checkboxes[i]);
assert(button != NULL);
if (button->GetCheck() > 0)
button->SetCheck(0);
}
}
UpdateData(FALSE); // FALSE means set controls
return valid;
}
// common code for all the checkboxes
void COptionsDlg::CheckOption(int param)
{
CButton *button = (CButton *) GetDlgItem(checkboxes[param]);
assert(button != NULL);
BOOL has_value = (hasvalue[param] != NOVALUE);
CString *value = values[param];
assert(!has_value || value != NULL);
UpdateData(TRUE); // TRUE means read from controls
int start, end;
BOOL found = find_param(m_opstring.GetBuffer(0), param, start, end);
int checked = button->GetCheck();
if (checked) {
if (has_value && value->IsEmpty()) {
button->SetCheck(0);
return;
}
if (found) {
// occurs if things get out of sync...try to recover
RemoveOption(param);
OnChangeOptionsEdit();
}
if (!m_opstring.IsEmpty() &&
m_opstring.GetAt(m_opstring.GetLength()-1) != _T(' ')) {
m_opstring += CString(_T(" "));
}
m_opstring += CString(names[param]);
if (has_value) {
// if has spaces, put quotes around
CString val = *value;
if (val.Find(_T(' '), 0) != -1)
val.Format(_T("\"%s\""), *value);
m_opstring += CString(_T(" ")) + val;
}
} else {
assert(found);
RemoveOption(param);
}
UpdateData(FALSE); // FALSE means set controls
}
void COptionsDlg::RemoveOption(int param)
{
UpdateData(TRUE); // TRUE means read from controls
int start, end;
BOOL found = find_param(m_opstring.GetBuffer(0), param, start, end);
if (found) {
expand_ws_quotes(m_opstring, start, end);
m_opstring = m_opstring.Left(start) +
m_opstring.Right(m_opstring.GetLength() - end);
UpdateData(FALSE); // FALSE means set controls
}
}
BOOL COptionsDlg::UpdateValue(int param)
{
if (hasvalue[param] == NOVALUE)
return FALSE;
UpdateData(TRUE); // TRUE means read from controls
CString *value = values[param];
// if has spaces, put quotes around
CString newval = *value;
if (newval.Find(_T(' '), 0) != -1)
newval.Format(_T("\"%s\""), *value);
int start, end;
BOOL found = find_param(m_opstring.GetBuffer(0), param, start, end);
if (!found)
return FALSE;
TCHAR *buf = m_opstring.GetBuffer(0);
TCHAR *pos = buf + start;
TCHAR val[MAX_PATH];
getword(buf, &pos, val); // param
TCHAR *val_pos = pos;
getword(buf, &pos, val); // value
int val_start = (val_pos - buf);
expand_ws_quotes(m_opstring, val_start, end);
m_opstring = m_opstring.Left(val_start) + CString(_T(" ")) + newval +
m_opstring.Right(m_opstring.GetLength() - end);
UpdateData(FALSE); // FALSE means set controls
return TRUE;
}
static TCHAR szFilter[] = _T("Dynamic-Linked Libraries (*.dll)|*.dll|All Files (*.*)|*.*||");
void COptionsDlg::OnBrowseInstrlibname()
{
CFileDialog fileDlg(TRUE, _T(".dll"), NULL,
// hide the "open as read-only" checkbox
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
szFilter);
int res = fileDlg.DoModal();
if (res == IDCANCEL)
return;
CButton *button = (CButton *) GetDlgItem(checkboxes[INSTRLIBNAME]);
assert(button != NULL);
if (button->GetCheck() > 0 && _tcscmp(m_InstrLibName, fileDlg.GetPathName()) != 0) {
m_InstrLibName = fileDlg.GetPathName();
UpdateData(FALSE); // FALSE means set controls
RemoveOption(INSTRLIBNAME);
CheckOption(INSTRLIBNAME);
} else {
m_InstrLibName = fileDlg.GetPathName();
UpdateData(FALSE); // FALSE means set controls
}
}
void COptionsDlg::OnInstrlibname()
{
UpdateData(TRUE); // TRUE means read from controls
if (CheckLibraryExists(m_InstrLibName.GetBuffer(0), TRUE))
CheckOption(INSTRLIBNAME);
else {
CButton *button = (CButton *) GetDlgItem(IDC_INSTRLIBNAME);
button->SetCheck(0);
}
}
void COptionsDlg::OnChangeEditInstrlibname()
{
if (UpdateValue(INSTRLIBNAME)) {
OnChangeOptionsEdit();
}
}
BOOL COptionsDlg::CheckLibraryExists(TCHAR *libname, BOOL notify)
{
// make sure file exists
TCHAR msg[MAX_PATH*2];
CFile check;
if (!check.Open(libname, CFile::modeRead|CFile::shareDenyNone)) {
if (notify) {
_stprintf(msg, _T("Library %s does not exist"), libname);
MessageBox(msg, _T("Error"), MB_OK | MYMBFLAGS);
}
return FALSE;
}
check.Close();
return TRUE;
}
void COptionsDlg::OnLoggingButton()
{
UpdateData(TRUE); // get values from controls
int level = _ttoi(m_LogLevel);
if (level < 0)
level = 0;
if (level > 4)
level = 4;
int mask;
int res = _stscanf(m_LogMask, _T("%X"), &mask);
if (res <= 0 || res == EOF)
mask = 0;
CLoggingDlg dlg(level, mask);
res = dlg.DoModal();
if (res == IDCANCEL)
return;
m_LogLevel.Format(_T("%d"), dlg.GetLevel());
m_LogMask.Format(_T("0x%04X"), dlg.GetMask());
UpdateData(FALSE); // write to controls
#if 1
UpdateValue(LOGLEVEL);
UpdateValue(LOGMASK);
#else
// FIXME: change in place...for now we just remove and re-add
CButton *button = (CButton *) GetDlgItem(checkboxes[LOGLEVEL]);
assert(button != NULL);
if (button->GetCheck() > 0) {
RemoveOption(LOGLEVEL);
CheckOption(LOGLEVEL);
}
button = (CButton *) GetDlgItem(checkboxes[LOGMASK]);
assert(button != NULL);
if (button->GetCheck() > 0) {
RemoveOption(LOGMASK);
CheckOption(LOGMASK);
}
#endif
}
void COptionsDlg::DisableCheckbox(int id)
{
CButton *button = (CButton *) GetDlgItem(id);
assert(button != NULL);
button->EnableWindow(FALSE);
}
void COptionsDlg::OnHotThreshold() { CheckOption(HOT_THRESHOLD); }
void COptionsDlg::OnCacheBBMax() { CheckOption(CACHE_BB_MAX); }
void COptionsDlg::OnCacheTraceMax() { CheckOption(CACHE_TRACE_MAX); }
void COptionsDlg::OnLoglevel() { CheckOption(LOGLEVEL); }
void COptionsDlg::OnLogmask() { CheckOption(LOGMASK); }
void COptionsDlg::OnProfPcs() { CheckOption(PROF_PCS); }
void COptionsDlg::OnStats() { CheckOption(STATS); }
void COptionsDlg::OnNullcalls() { CheckOption(NULLCALLS); }
void COptionsDlg::OnNolink() { CheckOption(NOLINK); }
void COptionsDlg::OnNoasynch() { CheckOption(NOASYNCH); }
void COptionsDlg::OnTraceDumpOrigins() { CheckOption(TRACEDUMP_ORIGINS); }
// remind to pick trace dump too
void COptionsDlg::OnProfCounts() {
CButton *button = (CButton *) GetDlgItem(IDC_NOTIFY);
assert(button != NULL);
if (button->GetCheck() == 1) {
CButton *text = (CButton *) GetDlgItem(IDC_TRACEDUMP_TEXT);
assert(text != NULL);
CButton *binary = (CButton *) GetDlgItem(IDC_TRACEDUMP_BINARY);
assert(binary != NULL);
if (text->GetCheck() == 0 && binary->GetCheck() == 0) {
::MessageBox(NULL, _T("Count profiling results are only visible in a trace dump.\n")
_T("Don't forget to select either a text or binary trace dump."),
_T("Reminder"), MB_OK | MYMBFLAGS);
}
}
CheckOption(PROF_COUNTS);
}
// mutually exclusive
void COptionsDlg::OnTraceDumpText() {
CButton *text = (CButton *) GetDlgItem(IDC_TRACEDUMP_TEXT);
assert(text != NULL);
CButton *binary = (CButton *) GetDlgItem(IDC_TRACEDUMP_BINARY);
assert(binary != NULL);
if (text->GetCheck() == 1 && binary->GetCheck() == 1) {
::MessageBox(NULL, _T("Trace dump must be either text or binary, not both"),
_T("Mutually Exclusive"), MB_OK | MYMBFLAGS);
text->SetCheck(0);
} else {
CheckOption(TRACEDUMP_TEXT);
}
}
void COptionsDlg::OnTraceDumpBinary() {
CButton *text = (CButton *) GetDlgItem(IDC_TRACEDUMP_TEXT);
assert(text != NULL);
CButton *binary = (CButton *) GetDlgItem(IDC_TRACEDUMP_BINARY);
assert(binary != NULL);
if (text->GetCheck() == 1 && binary->GetCheck() == 1) {
::MessageBox(NULL, _T("Trace dump must be either text or binary, not both"),
_T("Mutually Exclusive"), MB_OK | MYMBFLAGS);
binary->SetCheck(0);
} else {
CheckOption(TRACEDUMP_BINARY);
}
}
// ask for confirmation since stderr sticky issue
// in fact, could not even let them set notify within GUI,
// but would be nice if env var brought in from cmd line showed up
void COptionsDlg::OnNotify() {
TCHAR msg[MAX_PATH];
CButton *button = (CButton *) GetDlgItem(IDC_NOTIFY);
assert(button != NULL);
if (button->GetCheck() == 1) {
_stprintf(msg, _T("Printing to stderr can cause unexpected failures.\n")
_T("Are you sure you want to set this option?\n"));
int res = ::MessageBox(NULL, msg, _T("Confirmation"), MB_YESNO | MYMBFLAGS);
if (res == IDYES) {
CheckOption(NOTIFY);
} else {
button->SetCheck(0);
}
} else {
CheckOption(NOTIFY);
}
}
// set env var not just for this process but permanently for this user
void COptionsDlg::OnSetPermanent()
{
// it takes a while to broadcast the "we've changed env vars" message,
// so set a wait cursor
HCURSOR prev_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
TCHAR msg[MAX_PATH];
HKEY hk;
int res;
// current user only
res = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Environment"), 0, KEY_WRITE, &hk);
if (res != ERROR_SUCCESS) {
_stprintf(msg, _T("Error writing to HKEY_CURRENT_USER\\Environment"));
MessageBox(msg, _T("Error"), MB_OK | MYMBFLAGS);
}
UpdateData(TRUE); // get values from controls
TCHAR *val = m_opstring.GetBuffer(0);
res = RegSetValueEx(hk, _T("DYNAMORIO_OPTIONS"), 0, REG_SZ,
(LPBYTE) val, _tcslen(val)+1);
assert(res == ERROR_SUCCESS);
RegCloseKey(hk);
// tell system that we've changed environment (else won't take effect until
// user logs out and back in)
DWORD dwReturnValue;
// Code I copied this from used an ANSI string...I'm leaving
// it like that FIXME
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
SetCursor(prev_cursor);
// set local env var too, and avoid questions of ability to
// cancel the permanent operation
OnOK();
}
void COptionsDlg::OnChangeEditCacheBbMax()
{
if (UpdateValue(CACHE_BB_MAX)) {
OnChangeOptionsEdit();
}
}
void COptionsDlg::OnChangeEditCacheTraceMax()
{
if (UpdateValue(CACHE_TRACE_MAX)) {
OnChangeOptionsEdit();
}
}
void COptionsDlg::OnChangeEditHotThreshold()
{
if (UpdateValue(HOT_THRESHOLD)) {
OnChangeOptionsEdit();
}
}
#endif /* !DRSTATS_DEMO */ /* around whole file */