Exemplo n.º 1
0
JSTrapStatus CThreadDebugger::BreakHandler(JSContext* cx, JSScript* script, jsbytecode* pc, jsval* UNUSED(rval), jsval UNUSED(closure), BREAK_SRC breakSrc) 
{
	uint line = JS_PCToLineNumber(cx, script, pc);
	std::string filename(JS_GetScriptFilename(cx, script));

	SetIsInBreak(true);
	SaveCallstack();
	SetLastBreakLine(line);
	SetBreakFileName(filename);
	*m->m_pLastBreakFrame = NULL;
	
	if (breakSrc == BREAK_SRC_INTERRUP)
	{
		JS_ClearInterrupt(m->m_pScriptInterface->GetRuntime(), NULL, NULL);
		JS_SetSingleStepMode(cx, script, false);
	}
	
	if (m->m_pDebuggingServer->GetSettingSimultaneousThreadBreak())
	{
		m->m_pDebuggingServer->SetBreakRequestedByThread(true);
	}
	
	// Wait until the user continues the execution
	while (1)
	{
		DBGCMD nextDbgCmd = GetNextDbgCmd();
		
		while (!m->m_StackInfoRequests.empty())
		{
			StackInfoRequest request = m->m_StackInfoRequests.front();
			SaveStackFrameData(request.requestType, request.nestingLevel);
			SDL_SemPost(request.semaphore);
			m->m_StackInfoRequests.pop();
		}
		
		if (nextDbgCmd == DBG_CMD_NONE)
		{
			// Wait a while before checking for new m_NextDbgCmd again.
			// We don't want this loop to take 100% of a CPU core for each thread that is in break mode.
			// On the other hande we don't want the debugger to become unresponsive.
			SDL_Delay(100);
		}
		else if (nextDbgCmd == DBG_CMD_SINGLESTEP || nextDbgCmd == DBG_CMD_STEPINTO || nextDbgCmd == DBG_CMD_STEPOUT)
		{
			JSStackFrame* iter = NULL;
			*m->m_pLastBreakFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
			
			if (!JS_SetSingleStepMode(cx, script, true))
				LOGERROR(L"JS_SetSingleStepMode returned false!"); // TODO: When can this happen?
			else
			{
				if (nextDbgCmd == DBG_CMD_SINGLESTEP)
				{
					JS_SetInterrupt(m->m_pScriptInterface->GetRuntime(), StepHandler_, this);
					break;
				}
				else if (nextDbgCmd == DBG_CMD_STEPINTO)
				{
					JS_SetInterrupt(m->m_pScriptInterface->GetRuntime(), StepIntoHandler_, this);
					break;
				}
				else if (nextDbgCmd == DBG_CMD_STEPOUT)
				{
					JS_SetInterrupt(m->m_pScriptInterface->GetRuntime(), StepOutHandler_, this);
					break;
				}
			}
		}
		else if (nextDbgCmd == DBG_CMD_CONTINUE)
		{
			if (!JS_SetSingleStepMode(cx, script, true))
				LOGERROR(L"JS_SetSingleStepMode returned false!"); // TODO: When can this happen?
			else
			{
				// Setup a handler to check for break-requests from the DebuggingServer regularly
				JS_SetInterrupt(m->m_pScriptInterface->GetRuntime(), CheckForBreakRequestHandler_, this);
			}
			break;
		}
		else 
			debug_warn("Invalid DBGCMD found in CThreadDebugger::BreakHandler!");
	}
	ClearTrapsToRemove();
	SetAllNewTraps();
	SetNextDbgCmd(DBG_CMD_NONE);
	SetIsInBreak(false);
	SetBreakFileName("");
	
	// All saved stack data becomes invalid
	{
		CScopeLock lock(m->m_Mutex);
		m->m_StackFrameData.clear();
	}
	
	return JSTRAP_CONTINUE;
}
Exemplo n.º 2
0
void* CDebuggingServer::MgDebuggingServerCallback(mg_event event, struct mg_connection *conn, const struct mg_request_info *request_info)
{
	void* handled = (void*)""; // arbitrary non-NULL pointer to indicate successful handling

	const char* header200 =
		"HTTP/1.1 200 OK\r\n"
		"Access-Control-Allow-Origin: *\r\n" // TODO: not great for security
		"Content-Type: text/plain; charset=utf-8\r\n\r\n";

	const char* header404 =
		"HTTP/1.1 404 Not Found\r\n"
		"Content-Type: text/plain; charset=utf-8\r\n\r\n"
		"Unrecognised URI";

	switch (event)
	{
	case MG_NEW_REQUEST:
	{
		std::stringstream stream;
		std::string uri = request_info->uri;
		
		if (uri == "/GetThreadDebuggerStatus")
		{
			GetThreadDebuggerStatus(stream);
		}
		else if (uri == "/EnumVfsJSFiles")
		{
			EnumVfsJSFiles(stream);
		}
		else if (uri == "/GetAllCallstacks")
		{
			GetAllCallstacks(stream);
		}
		else if (uri == "/Continue")
		{
			uint threadDebuggerID;
			if (!GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID))
				return handled;
			// TODO: handle the return value
			SetNextDbgCmd(threadDebuggerID, DBG_CMD_CONTINUE);	
		}
		else if (uri == "/Break")
		{
			SetBreakRequestedByUser(true);
		}
		else if (uri == "/SetSettingSimultaneousThreadBreak")
		{
			std::string strEnabled;
			bool bEnabled = false;
			if (!GetWebArgs(conn, request_info, "enabled", strEnabled))
				return handled;
			// TODO: handle the return value
			if (strEnabled == "true")
				bEnabled = true;
			else if (strEnabled == "false")
				bEnabled = false;
			else
				return handled; // TODO: return an error state
			SetSettingSimultaneousThreadBreak(bEnabled);
		}
		else if (uri == "/GetSettingSimultaneousThreadBreak")
		{
			stream << "{ \"Enabled\" : " << (GetSettingSimultaneousThreadBreak() ? "true" : "false") << " } ";
		}
		else if (uri == "/SetSettingBreakOnException")
		{
			std::string strEnabled;
			bool bEnabled = false;
			if (!GetWebArgs(conn, request_info, "enabled", strEnabled))
				return handled;
			// TODO: handle the return value
			if (strEnabled == "true")
				bEnabled = true;
			else if (strEnabled == "false")
				bEnabled = false;
			else
				return handled; // TODO: return an error state
			SetSettingBreakOnException(bEnabled);
		}
		else if (uri == "/GetSettingBreakOnException")
		{
			stream << "{ \"Enabled\" : " << (GetSettingBreakOnException() ? "true" : "false") << " } ";
		}
		else if (uri == "/Step")
		{
			uint threadDebuggerID;
			if (!GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID))
				return handled;
			// TODO: handle the return value
			SetNextDbgCmd(threadDebuggerID, DBG_CMD_SINGLESTEP);
		}
		else if (uri == "/StepInto")
		{
			uint threadDebuggerID;
			if (!GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID))
				return handled;
			// TODO: handle the return value
			SetNextDbgCmd(threadDebuggerID, DBG_CMD_STEPINTO);
		}
		else if (uri == "/StepOut")
		{
			uint threadDebuggerID;
			if (!GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID))
				return handled;
			// TODO: handle the return value
			SetNextDbgCmd(threadDebuggerID, DBG_CMD_STEPOUT);
		}
		else if (uri == "/GetStackFrame")
		{
			uint nestingLevel;
			uint threadDebuggerID;
			if (!GetWebArgs(conn, request_info, "nestingLevel", nestingLevel) || 
				!GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID))
			{
				return handled;
			}
			GetStackFrameData(stream, nestingLevel, threadDebuggerID, STACK_INFO_LOCALS);
		}
		else if (uri == "/GetStackFrameThis")
		{
			uint nestingLevel;
			uint threadDebuggerID;
			if (!GetWebArgs(conn, request_info, "nestingLevel", nestingLevel) || 
				!GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID))
			{
				return handled;
			}
			GetStackFrameData(stream, nestingLevel, threadDebuggerID, STACK_INFO_THIS);
		}
		else if (uri == "/GetCurrentGlobalObject")
		{
			uint threadDebuggerID;
			if (!GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID))
			{
				return handled;
			}
			GetStackFrameData(stream, 0, threadDebuggerID, STACK_INFO_GLOBALOBJECT);
		}
		else if (uri == "/ToggleBreakpoint")
		{
			std::string filename;
			uint line;
			if (!GetWebArgs(conn, request_info, "filename", filename) ||
				!GetWebArgs(conn, request_info, "line", line))
			{
				return handled;
			}
			ToggleBreakPoint(filename, line);
		}
		else if (uri == "/GetFile")
		{
			std::string filename;
			if (!GetWebArgs(conn, request_info, "filename", filename))
				return handled;
			GetFile(filename, stream);
		}
		else
		{
			mg_printf(conn, "%s", header404);
			return handled;
		}

		mg_printf(conn, "%s", header200);
		std::string str = stream.str();
		mg_write(conn, str.c_str(), str.length());
		return handled;
	}

	case MG_HTTP_ERROR:
		return NULL;

	case MG_EVENT_LOG:
		// Called by Mongoose's cry()
		LOGERROR(L"Mongoose error: %hs", request_info->log_message);
		return NULL;

	case MG_INIT_SSL:
		return NULL;

	default:
		debug_warn(L"Invalid Mongoose event type");
		return NULL;
	}
};