| /******************************************************************************* | |
| * 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 "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(); | |
| 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 look for an exact, full path match | |
| if (modulesToDebug.count(module) > 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 != module.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; | |
| } |