* 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.
*/
#include "configure.h"
#ifndef DRSTATS_DEMO
# 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"),
};
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,
NOVALUE, NOVALUE,
NOVALUE,
NOVALUE, NOVALUE,
NOVALUE,
NOVALUE,
NOVALUE,
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,
FALSE,
TRUE, TRUE, TRUE, TRUE, TRUE,
FALSE,
FALSE,
TRUE, TRUE,
TRUE,
};
static const int num_options = sizeof(checkboxes) / sizeof(int);
static CString *values[num_options];
COptionsDlg::COptionsDlg(CWnd *pParent )
: CDialog(COptionsDlg::IDD, pParent)
{
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");
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;
}
void
COptionsDlg::DoDataExchange(CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
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);
}
BEGIN_MESSAGE_MAP(COptionsDlg, CDialog)
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)
END_MESSAGE_MAP()
BOOL
COptionsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
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;
UpdateData(FALSE);
if (!CheckOpstring()) {
MessageBox(_T("Invalid DYNAMORIO_OPTIONS string!\nThis dialog ")
_T("may not work properly with it."),
_T("Error"), MB_OK | MYMBFLAGS);
}
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);
return TRUE;
}
void
COptionsDlg::OnOK()
{
UpdateData(TRUE);
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'));
}
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;
while (is_whitespace(*pos)) {
pos++;
}
if (is_quote(*pos)) {
quote = *pos;
pos++;
}
while (*pos) {
if (quote != _T('\0')) {
if (*pos == quote) {
pos++;
break;
}
} else {
if (is_whitespace(*pos))
break;
}
result[i++] = *pos;
pos++;
assert(i < MAX_PATH * 2);
}
if (i == 0)
return NULL;
result[i] = _T('\0');
*strpos = pos;
return TRUE;
}
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)) {
} else if ((hasvalue[id] == NUM_DECIMAL || hasvalue[id] == NUM_HEX) &&
word[0] == '-') {
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)
{
while (start > 0 && is_quote(str.GetAt(start - 1))) {
start--;
}
while (start > 0 && is_whitespace(str.GetAt(start - 1))) {
start--;
}
while (end < str.GetLength() && is_quote(str.GetAt(end))) {
end++;
}
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++;
}
if (start == 0 && end < str.GetLength() &&
(is_whitespace(str.GetAt(end)) || is_quote(str.GetAt(end)))) {
end++;
}
}
BOOL
COptionsDlg::CheckOptionsVersusDllType(DLL_TYPE dll_type)
{
TCHAR msg[MAX_PATH];
int len = GetEnvironmentVariable(_T("DYNAMORIO_OPTIONS"), msg, MAX_PATH);
if (len == 0 || len > MAX_PATH)
msg[0] = _T('\0');
CString opstring = msg;
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) {
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 ")
_T("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);
pos = opstring.GetBuffer(0) + start;
ok = SetEnvironmentVariable(_T("DYNAMORIO_OPTIONS"), opstring);
assert(ok);
}
}
}
}
prev_pos = pos;
}
return TRUE;
}
BOOL
COptionsDlg::CheckOpstring()
{
UpdateData(TRUE);
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('-')) {
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 ((dll_type == DLL_RELEASE && !ok_with_release[i]) ||
(dll_type != DLL_PROFILE && i == PROF_COUNTS)) {
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);
return valid;
}
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);
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) {
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) {
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);
}
void
COptionsDlg::RemoveOption(int param)
{
UpdateData(TRUE);
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);
}
}
BOOL
COptionsDlg::UpdateValue(int param)
{
if (hasvalue[param] == NOVALUE)
return FALSE;
UpdateData(TRUE);
CString *value = values[param];
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);
TCHAR *val_pos = pos;
getword(buf, &pos, val);
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);
return TRUE;
}
static TCHAR szFilter[] =
_T("Dynamic-Linked Libraries (*.dll)|*.dll|All Files (*.*)|*.*||");
void
COptionsDlg::OnBrowseInstrlibname()
{
CFileDialog fileDlg(TRUE, _T(".dll"), NULL,
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);
RemoveOption(INSTRLIBNAME);
CheckOption(INSTRLIBNAME);
} else {
m_InstrLibName = fileDlg.GetPathName();
UpdateData(FALSE);
}
}
void
COptionsDlg::OnInstrlibname()
{
UpdateData(TRUE);
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)
{
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);
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);
# if 1
UpdateValue(LOGLEVEL);
UpdateValue(LOGMASK);
# else
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);
}
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);
}
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);
}
}
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);
}
}
void
COptionsDlg::OnSetPermanent()
{
HCURSOR prev_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
TCHAR msg[MAX_PATH];
HKEY hk;
int res;
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);
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);
DWORD dwReturnValue;
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment",
SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
SetCursor(prev_cursor);
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