blob: 0ec7b51eb6d35dd0a62de7e81d5d7dcc1aafde0c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 Nokia and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nokia - Initial API and implementation
*******************************************************************************/
#include <string>
#include <vector>
#include <algorithm>
#include "SettingsService.h"
#include "TCFChannel.h"
#include "WinDebugMonitor.h"
#define _EXCEPTION_ACCESS_VIOLATION 1 << 0;
#define _EXCEPTION_ARRAY_BOUNDS_EXCEEDED 1 << 1;
#define _EXCEPTION_DATATYPE_MISALIGNMENT 1 << 2;
#define _EXCEPTION_FLT_DENORMAL_OPERAND 1 << 3;
#define _EXCEPTION_FLT_DIVIDE_BY_ZERO 1 << 4;
#define _EXCEPTION_FLT_INEXACT_RESULT 1 << 5;
#define _EXCEPTION_FLT_INVALID_OPERATION 1 << 6;
#define _EXCEPTION_FLT_OVERFLOW 1 << 7;
#define _EXCEPTION_FLT_STACK_CHECK 1 << 8;
#define _EXCEPTION_FLT_UNDERFLOW 1 << 9;
#define _EXCEPTION_ILLEGAL_INSTRUCTION 1 << 10;
#define _EXCEPTION_IN_PAGE_ERROR 1 << 11;
#define _EXCEPTION_INT_DIVIDE_BY_ZERO 1 << 12;
#define _EXCEPTION_INT_OVERFLOW 1 << 13;
#define _EXCEPTION_INVALID_DISPOSITION 1 << 14;
#define _EXCEPTION_NONCONTINUABLE_EXCEPTION 1 << 15;
#define _EXCEPTION_PRIV_INSTRUCTION 1 << 16;
#define _EXCEPTION_STACK_OVERFLOW 1 << 17;
#define _EXCEPTION_GUARD_PAGE 1 << 18;
#define _EXCEPTION_INVALID_HANDLE 1 << 19;
#define _DBG_CONTROL_C 1 << 20;
#define _DBG_CONTROL_BREAK 1 << 21;
#define _STATUS_NO_MEMORY 1 << 22;
#define _STATUS_DLL_INIT_FAILED 1 << 23;
#define _STATUS_DLL_NOT_FOUND 1 << 24;
#define _STATUS_ENTRYPOINT_NOT_FOUND 1 << 25;
#define _MS_CPLUS_EXCEPTION 1 << 26;
static const char * sServiceName = "Settings";
static std::set<std::string> modulesToDebug;
static bool allowFilenameMatch;
static bool enableDebugStringLogging;
static unsigned long exceptionsBitmask;
static std::vector<std::string> settingIdArray;
static std::vector<std::string> executables;
SettingsService::SettingsService(Protocol * proto) :
TCFService(proto) {
allowFilenameMatch = false;
enableDebugStringLogging = true;
exceptionsBitmask = 0x00000000L; // no exceptions reported by default
AddCommand("get", command_get_settings); // compatibility -- not used
AddCommand("getIds", command_get_settings);
AddCommand("set", command_set_settings);
}
SettingsService::~SettingsService(void) {
}
const char* SettingsService::GetName() {
return sServiceName;
}
void SettingsService::command_get_settings(const char * token, Channel * c) {
TCFChannel channel(c);
channel.readComplete();
channel.writeReplyHeader(token);
channel.writeError(0);
write_stream(&c->out,'[');
write_stream(&c->out,']');
channel.writeZero();
channel.writeComplete();
}
static void read_setting_id(InputStream * inp, void * arg)
{
Channel* c = static_cast<Channel*>(arg);
TCFChannel channel(c);
std::string id = channel.readString();
settingIdArray.push_back(id);
}
static void read_executable(InputStream * inp, void * arg)
{
Channel* c = static_cast<Channel*>(arg);
TCFChannel channel(c);
std::string executable = channel.readString();
// convert to lower case for later case-insensitive comparison (windows is case-insensitive)
std::transform(executable.begin(), executable.end(), executable.begin(), ::tolower);
modulesToDebug.insert(executable);
}
static void read_setting_value(InputStream * inp, void * arg)
{
Channel* c = static_cast<Channel*>(arg);
TCFChannel channel(c);
// the setting ids are stored in settingIdArray in the same
// order as this function gets called with the values. so just
// pop the first one off each time to get the setting id for this value.
std::string id = settingIdArray.front();
settingIdArray.erase(settingIdArray.begin());
if (id.compare("addModules") == 0)
json_read_array(inp, read_executable, c);
else if (id.compare("allowFilenameMatch") == 0)
allowFilenameMatch = json_read_boolean(inp);
else if (id.compare("enableDebugStringLogging") == 0)
enableDebugStringLogging = json_read_boolean(inp);
else if (id.compare("exceptionsBitmask") == 0)
exceptionsBitmask = json_read_ulong(inp);
else {
// skip unknown setting
json_skip_object(&c->inp);
}
}
void SettingsService::command_set_settings(const char * token, Channel * c) {
TCFChannel channel(c);
std::string str = channel.readString(); // ignored
channel.readZero();
settingIdArray.clear();
// read the array of setting ids
json_read_array(&c->inp, read_setting_id, c);
channel.readZero();
// now read the array of setting values
json_read_array(&c->inp, read_setting_value, c);
channel.readZero();
channel.readComplete();
channel.writeReplyHeader(token);
channel.writeError(0);
channel.writeComplete();
}
std::string getFilenameFromPath(std::string path)
{
std::string::size_type pos = path.find_last_of('\\');
if (pos == std::string::npos)
return NULL;
return path.substr(pos + 1, path.size() - pos - 1);
}
/*
* Called when debug session ends. Do any cleanup needed.
*/
void SettingsService::debugSessionEnds()
{
modulesToDebug.clear();
}
bool SettingsService::reportDebugEventForModule(std::string module)
{
// if modulesToDebug is empty then no filter has been set - report all events
if (modulesToDebug.empty())
return true;
// first convert to lower case - windows is case-insensitive after all
std::string moduleLower(module);
std::transform(moduleLower.begin(), moduleLower.end(), moduleLower.begin(), ::tolower);
// first look for an exact, full path match
if (modulesToDebug.count(moduleLower) > 0)
return true;
if (allowFilenameMatch)
{
// now just see if the filenames of any of the modules in the filter match the given module
std::set<std::string>::iterator itModules;
for (itModules = modulesToDebug.begin(); itModules
!= modulesToDebug.end(); itModules++)
{
std::string path = *itModules;
// get the filename
std::string filename = getFilenameFromPath(path);
// search the module string
if (std::string::npos != moduleLower.rfind(filename)) {
return true;
}
}
}
// filter is set but the given module is not in the list - don't report
return false;
}
bool SettingsService::reportDebugStringEvents()
{
return enableDebugStringLogging;
}
bool SettingsService::reportExceptionEvent(const DEBUG_EVENT& debugEvent)
{
switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode) {
// as a debugger we always report these
case EXCEPTION_SINGLE_STEP:
case EXCEPTION_BREAKPOINT:
return true;
// honor the exception settings
case EXCEPTION_ACCESS_VIOLATION:
return exceptionsBitmask & _EXCEPTION_ACCESS_VIOLATION;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
return exceptionsBitmask & _EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
case EXCEPTION_DATATYPE_MISALIGNMENT:
return exceptionsBitmask & _EXCEPTION_DATATYPE_MISALIGNMENT;
case EXCEPTION_FLT_DENORMAL_OPERAND:
return exceptionsBitmask & _EXCEPTION_FLT_DENORMAL_OPERAND;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
return exceptionsBitmask & _EXCEPTION_FLT_DIVIDE_BY_ZERO;
case EXCEPTION_FLT_INEXACT_RESULT:
return exceptionsBitmask & _EXCEPTION_FLT_INEXACT_RESULT;
case EXCEPTION_FLT_INVALID_OPERATION:
return exceptionsBitmask & _EXCEPTION_FLT_INVALID_OPERATION;
case EXCEPTION_FLT_OVERFLOW:
return exceptionsBitmask & _EXCEPTION_FLT_OVERFLOW;
case EXCEPTION_FLT_STACK_CHECK:
return exceptionsBitmask & _EXCEPTION_FLT_STACK_CHECK;
case EXCEPTION_FLT_UNDERFLOW:
return exceptionsBitmask & _EXCEPTION_FLT_UNDERFLOW;
case EXCEPTION_ILLEGAL_INSTRUCTION:
return exceptionsBitmask & _EXCEPTION_ILLEGAL_INSTRUCTION;
case EXCEPTION_IN_PAGE_ERROR:
return exceptionsBitmask & _EXCEPTION_IN_PAGE_ERROR;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
return exceptionsBitmask & _EXCEPTION_INT_DIVIDE_BY_ZERO;
case EXCEPTION_INT_OVERFLOW:
return exceptionsBitmask & _EXCEPTION_INT_OVERFLOW;
case EXCEPTION_INVALID_DISPOSITION:
return exceptionsBitmask & _EXCEPTION_INVALID_DISPOSITION;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
return exceptionsBitmask & _EXCEPTION_NONCONTINUABLE_EXCEPTION;
case EXCEPTION_PRIV_INSTRUCTION:
return exceptionsBitmask & _EXCEPTION_PRIV_INSTRUCTION;
case EXCEPTION_STACK_OVERFLOW:
return exceptionsBitmask & _EXCEPTION_STACK_OVERFLOW;
case EXCEPTION_GUARD_PAGE:
return exceptionsBitmask & _EXCEPTION_GUARD_PAGE;
case EXCEPTION_INVALID_HANDLE:
return exceptionsBitmask & _EXCEPTION_INVALID_HANDLE;
case DBG_CONTROL_C:
return exceptionsBitmask & _DBG_CONTROL_C;
case DBG_CONTROL_BREAK:
return exceptionsBitmask & _DBG_CONTROL_BREAK;
case STATUS_NO_MEMORY:
return exceptionsBitmask & _STATUS_NO_MEMORY;
case STATUS_DLL_INIT_FAILED:
return exceptionsBitmask & _STATUS_DLL_INIT_FAILED;
case STATUS_DLL_NOT_FOUND:
return exceptionsBitmask & _STATUS_DLL_NOT_FOUND;
case STATUS_ENTRYPOINT_NOT_FOUND:
return exceptionsBitmask & _STATUS_ENTRYPOINT_NOT_FOUND;
case MS_CPLUS_EXCEPTION:
return exceptionsBitmask & _MS_CPLUS_EXCEPTION;
default:
// it's not one of the typical exceptions and we have no setting for it.
// if it's first chance, don't report it. give it back for the process/os
// to handle. otherwise we'll report it to the debugger.
trace(LOG_ALWAYS, "\t -- first chance:%d, flags:%d", debugEvent.u.Exception.dwFirstChance, debugEvent.u.Exception.ExceptionRecord.ExceptionFlags);
if (debugEvent.u.Exception.dwFirstChance)
return false;
}
return true;
}