mirror of
https://github.com/Ylianst/MeshAgent
synced 2025-12-06 00:13:33 +00:00
2. Updated debugger to work with updated promise 3. Fixed bug in event emitter where 'explicit' event type wasn't honored 4. Updated _GenericMarshal to support interface and function marshaling 5. Added COM/WMI support to windows
794 lines
29 KiB
C
794 lines
29 KiB
C
/*
|
|
Copyright 2006 - 2017 Intel Corporation
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
#ifdef WIN32
|
|
#include <WinSock2.h>
|
|
#include <ws2tcpip.h>
|
|
#endif
|
|
|
|
#include "microstack/ILibParsers.h"
|
|
#include "microstack/ILibAsyncServerSocket.h"
|
|
#include "microstack/ILibSimpleDataStore.h"
|
|
#include "ILibDuktape_Helpers.h"
|
|
#include "duktape.h"
|
|
#include "ILibDuktape_ScriptContainer.h"
|
|
#include "ILibDuktape_Debugger.h"
|
|
#include "ILibDuktapeModSearch.h"
|
|
|
|
#define ILibDuktape_Debugger_SCRIPT_SOURCE "_scriptSourceForDebugger"
|
|
#define ILibDuktape_Debugger_SCRIPT_PATH "_scriptPathForDebugger"
|
|
#define ILibDuktape_Debugger_AttachOptions "\xFF_debugger_attachOptions"
|
|
#define ILibDuktape_Debugger_Options_Rejector "\xFF_rejector"
|
|
#define ILibDuktape_Debugger_Options_Resolver "\xFF_resolver"
|
|
#define ILibDuktape_Debugger_DebugObject "_DbgObj"
|
|
#define ILibDuktape_Debugger_HostChain "_HostChain"
|
|
#define ILibDuktape_Debugger_MemoryReportInterval "_Debugger_MemoryReporting"
|
|
extern size_t ILibDuktape_ScriptContainer_TotalAllocations;
|
|
|
|
typedef struct ILibDuktape_Debugger
|
|
{
|
|
ILibChain_Link *chainedObject;
|
|
duk_context *ctx;
|
|
duk_thread_state hoststate;
|
|
sem_t hostlock;
|
|
int waitConnection;
|
|
void *debugThread;
|
|
int webport;
|
|
void *interval;
|
|
char data[sizeof(char*)];
|
|
#ifdef WIN32
|
|
SOCKET listener;
|
|
SOCKET client;
|
|
#else
|
|
int listener;
|
|
int client;
|
|
#endif
|
|
}ILibDuktape_Debugger;
|
|
|
|
void *DebugWebEngine_Context;
|
|
void *DebugWebEngine_Chain;
|
|
void *DebugWebEngine_Thread;
|
|
|
|
void ILibDuktape_Debugger_AsyncWaitConn(ILibDuktape_Debugger *dbg);
|
|
duk_ret_t ILibDuktape_Debugger_MemoryReportingSink(duk_context *ctx)
|
|
{
|
|
duk_push_string(ctx, "MemoryAllocations");
|
|
duk_push_int(ctx, (duk_int_t)ILibDuktape_ScriptContainer_TotalAllocations);
|
|
duk_debugger_notify(ctx, 2);
|
|
return(0);
|
|
}
|
|
void ILibDuktape_Debugger_StartMemoryReporting(duk_context *ctx)
|
|
{
|
|
duk_push_global_object(ctx); // [g]
|
|
duk_get_prop_string(ctx, -1, "setInterval"); // [g][setInterval]
|
|
duk_swap_top(ctx, -2); // [setInterVal][this]
|
|
duk_push_c_function(ctx, ILibDuktape_Debugger_MemoryReportingSink, 0); // [setInterVal][this][func]
|
|
duk_push_int(ctx, 5000); // [setInterVal][this][func][delay]
|
|
if (duk_pcall_method(ctx, 2) != 0) { duk_pop(ctx); return; } // [interval]
|
|
duk_push_heap_stash(ctx); // [interval][stash]
|
|
duk_swap_top(ctx, -2); // [stash][interval]
|
|
duk_put_prop_string(ctx, -2, ILibDuktape_Debugger_MemoryReportInterval);// [stash]
|
|
duk_pop(ctx); // ...
|
|
}
|
|
void ILibDuktape_Debugger_StopMemoryReporting(duk_context *ctx)
|
|
{
|
|
duk_push_heap_stash(ctx);
|
|
duk_del_prop_string(ctx, -1, ILibDuktape_Debugger_MemoryReportInterval);
|
|
duk_pop(ctx);
|
|
}
|
|
|
|
void ILibDuktape_Debugger_Socket_finish(void *udata)
|
|
{
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)udata;
|
|
|
|
if (dbg->client != ~0)
|
|
{
|
|
#ifdef WIN32
|
|
closesocket(dbg->client);
|
|
#else
|
|
shutdown(dbg->client, SHUT_RDWR);
|
|
close(dbg->client);
|
|
#endif
|
|
dbg->client = ~0;
|
|
}
|
|
|
|
ILibDuktape_Debugger_StopMemoryReporting(dbg->ctx);
|
|
}
|
|
|
|
void ILibDuktape_Debugger_Socket_waitconn(void *udata)
|
|
{
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)udata;
|
|
if (!ILibMemory_CanaryOK(dbg))
|
|
{
|
|
printf("INVALID CANARY\n");
|
|
}
|
|
|
|
|
|
dbg->client = accept(dbg->listener, NULL, NULL);
|
|
((void**)dbg->data)[0] = dbg;
|
|
|
|
if (dbg->client == ~0)
|
|
{
|
|
#ifdef WIN32
|
|
printf("Ooops, invalid socket: %d\n", WSAGetLastError());
|
|
#else
|
|
printf("Ooops, invalid socket: %d\n", errno);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
duk_size_t ILibDuktape_Debugger_PeekCB(void *udata)
|
|
{
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)udata;
|
|
int bytes = 0;
|
|
#ifndef WIN32
|
|
char tmp[8];
|
|
#endif
|
|
|
|
// Set the socket to non-blocking mode, because we need to play nice and share the MicroStack thread
|
|
#if defined(WIN32)
|
|
|
|
if (dbg->client == ~0)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
|
|
//// On Windows must set NON_BLOCK to check this
|
|
//int flags = 1;
|
|
//ioctlsocket(dbg->client, FIONBIO, (u_long *)(&flags));
|
|
|
|
//bytes = recv(dbg->client, tmp, sizeof(tmp), MSG_PEEK);
|
|
|
|
//flags = 0;
|
|
//ioctlsocket(dbg->client, FIONBIO, (u_long *)(&flags));
|
|
u_long avail = 0;
|
|
int rc = ioctlsocket(dbg->client, FIONREAD, &avail);
|
|
if (rc != 0)
|
|
{
|
|
fprintf(stderr, "%s: ioctlsocket() returned %d, closing connection\n",
|
|
__FILE__, rc);
|
|
fflush(stderr);
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
if (avail == 0)
|
|
{
|
|
return 0; /* nothing to read */
|
|
}
|
|
else
|
|
{
|
|
return 1; /* something to read */
|
|
}
|
|
}
|
|
#else
|
|
// Everything else, use MSG_DONTWAIT
|
|
bytes = recv(dbg->client, tmp, sizeof(tmp), MSG_PEEK | MSG_DONTWAIT);
|
|
#endif
|
|
|
|
return(bytes > 0 ? 1 : 0);
|
|
}
|
|
duk_size_t ILibDuktape_Debugger_ReadCB(void *udata, char *buffer, duk_size_t length)
|
|
{
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)udata;
|
|
|
|
return (duk_size_t)recv(dbg->client, buffer, (int)length, 0);
|
|
}
|
|
duk_size_t ILibDuktape_Debugger_WriteCB(void *udata, const char *buffer, duk_size_t length)
|
|
{
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)udata;
|
|
return (duk_size_t)send(dbg->client, buffer, (int)length, 0);
|
|
}
|
|
void ILibDuktape_Debugger_DetachCB(duk_context *ctx, void *udata)
|
|
{
|
|
ILibDuktape_Debugger_Socket_finish(udata);
|
|
ILibDuktape_Debugger_AsyncWaitConn((ILibDuktape_Debugger*)udata);
|
|
UNREFERENCED_PARAMETER(ctx);
|
|
}
|
|
|
|
void ILibDuktape_Debugger_AsyncWaitConn_PreSelect(void* object, fd_set *readset, fd_set *writeset, fd_set *errorset, int* blocktime)
|
|
{
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)((void**)((ILibChain_Link*)object)->ExtraMemoryPtr)[0];
|
|
if (dbg == NULL || !ILibMemory_CanaryOK(dbg))
|
|
{
|
|
((void**)((ILibChain_Link*)object)->ExtraMemoryPtr)[0] = NULL;
|
|
ILibChain_SafeRemove(((ILibChain_Link*)object)->ParentChain, object);
|
|
return;
|
|
}
|
|
|
|
if (dbg->waitConnection != 0 && dbg->listener != (SOCKET)~0)
|
|
{
|
|
FD_SET(dbg->listener, readset);
|
|
}
|
|
}
|
|
|
|
void ILibDuktape_Debugger_AsyncWaitConn_PostSelect(void* object, int slct, fd_set *readset, fd_set *writeset, fd_set *errorset)
|
|
{
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)((void**)((ILibChain_Link*)object)->ExtraMemoryPtr)[0];
|
|
if (dbg == NULL || !ILibMemory_CanaryOK(dbg)) { return; }
|
|
|
|
if (dbg->waitConnection != 0 && dbg->listener != (SOCKET)~0 && FD_ISSET(dbg->listener, readset))
|
|
{
|
|
dbg->waitConnection = 0;
|
|
dbg->client = accept(dbg->listener, NULL, NULL);
|
|
((void**)dbg->data)[0] = dbg;
|
|
|
|
if (dbg->client != ~0)
|
|
{
|
|
ILibDuktape_Debugger_StartMemoryReporting(dbg->ctx);
|
|
duk_debugger_attach(dbg->ctx, ILibDuktape_Debugger_ReadCB, ILibDuktape_Debugger_WriteCB, ILibDuktape_Debugger_PeekCB, NULL, NULL, NULL, ILibDuktape_Debugger_DetachCB, (void*)dbg);
|
|
}
|
|
}
|
|
}
|
|
void ILibDuktape_Debugger_AsyncWaitConn(ILibDuktape_Debugger *dbg)
|
|
{
|
|
if (dbg->chainedObject == NULL)
|
|
{
|
|
dbg->chainedObject = ILibChain_Link_Allocate(sizeof(ILibChain_Link), sizeof(void*));
|
|
dbg->chainedObject->MetaData = "ILibDuktape_Debugger_AsyncWaitConn";
|
|
((void**)dbg->chainedObject->ExtraMemoryPtr)[0] = dbg;
|
|
dbg->chainedObject->PreSelectHandler = ILibDuktape_Debugger_AsyncWaitConn_PreSelect;
|
|
dbg->chainedObject->PostSelectHandler = ILibDuktape_Debugger_AsyncWaitConn_PostSelect;
|
|
ILibChain_SafeAdd(Duktape_GetChain(dbg->ctx), dbg->chainedObject);
|
|
}
|
|
else
|
|
{
|
|
ILibForceUnBlockChain(Duktape_GetChain(dbg->ctx));
|
|
}
|
|
dbg->waitConnection = 1;
|
|
}
|
|
|
|
void ILibDuktape_Debugger_DestroyEx(void *chain, void *user)
|
|
{
|
|
Duktape_SafeDestroyHeap(DebugWebEngine_Context);
|
|
}
|
|
|
|
void DebugWebEngine_RunEx(void *chain, void *user)
|
|
{
|
|
ILibChain_OnDestroyEvent_AddHandler(chain, ILibDuktape_Debugger_DestroyEx, NULL);
|
|
if (duk_peval_string(DebugWebEngine_Context, "process.on('uncaughtException', function(e){console.log('Uncaught:', e);}); var duktape_debugger = require('duktape-debugger'); var dbg = new duktape_debugger(); dbg.run();") == 0)
|
|
{
|
|
printf("Debugger Initialized...\n");
|
|
}
|
|
else
|
|
{
|
|
printf("Unable to launch debugger client: %s\n", duk_safe_to_string(DebugWebEngine_Context, -1));
|
|
}
|
|
duk_pop(DebugWebEngine_Context);
|
|
}
|
|
|
|
void DebugWebEngine_Run(void *obj)
|
|
{
|
|
ILibChain_RunOnMicrostackThreadEx(DebugWebEngine_Chain, DebugWebEngine_RunEx, NULL);
|
|
ILibStartChain(DebugWebEngine_Chain);
|
|
}
|
|
void ILibDuktape_Debugger_Destroy(void *chain, void *user)
|
|
{
|
|
ILibStopChain(DebugWebEngine_Chain);
|
|
#ifdef WIN32
|
|
WaitForSingleObject(DebugWebEngine_Thread, INFINITE);
|
|
#endif
|
|
}
|
|
|
|
duk_ret_t ILibDuktape_Debugger_StartEngine_UpdatePort(duk_context *ctx)
|
|
{
|
|
duk_push_current_function(ctx);
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_Debugger_DebugObject);
|
|
int port = duk_require_int(ctx, 0);
|
|
if (dbg != NULL && ILibMemory_CanaryOK(dbg))
|
|
{
|
|
dbg->webport = port;
|
|
sem_post(&(dbg->hostlock));
|
|
}
|
|
return(0);
|
|
}
|
|
void ILibDuktape_Debugger_hostCooperate_Sink(void *chain, void *user)
|
|
{
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)user;
|
|
if (ILibMemory_CanaryOK(dbg))
|
|
{
|
|
duk_debugger_cooperate(dbg->ctx);
|
|
}
|
|
}
|
|
duk_ret_t ILibDuktape_Debugger_hostCooperate(duk_context *ctx)
|
|
{
|
|
duk_push_current_function(ctx);
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_Debugger_DebugObject);
|
|
void *chain = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_Debugger_HostChain);
|
|
if (chain != NULL && dbg != NULL && ILibMemory_CanaryOK(dbg))
|
|
{
|
|
ILibChain_RunOnMicrostackThreadEx(chain, ILibDuktape_Debugger_hostCooperate_Sink, dbg);
|
|
}
|
|
return(0);
|
|
}
|
|
void ILibDuktape_Debugger_detachCleanup_Sink(void *chain, void *user)
|
|
{
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)user;
|
|
if (ILibMemory_CanaryOK(dbg))
|
|
{
|
|
if (dbg->client != (SOCKET)~0 && dbg->waitConnection==0)
|
|
{
|
|
ILibDuktape_Debugger_Socket_finish((void*)dbg);
|
|
ILibDuktape_Debugger_AsyncWaitConn(dbg);
|
|
}
|
|
}
|
|
}
|
|
duk_ret_t ILibDuktape_Debugger_detachCleanup(duk_context *ctx)
|
|
{
|
|
duk_push_current_function(ctx);
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_Debugger_DebugObject);
|
|
void *chain = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_Debugger_HostChain);
|
|
if (chain != NULL && dbg != NULL && ILibMemory_CanaryOK(dbg))
|
|
{
|
|
ILibChain_RunOnMicrostackThreadEx(chain, ILibDuktape_Debugger_detachCleanup_Sink, dbg);
|
|
}
|
|
return(0);
|
|
}
|
|
void ILibDuktape_Debugger_hostGC_sink(void *chain, void *user)
|
|
{
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)user;
|
|
if (ILibMemory_CanaryOK(dbg))
|
|
{
|
|
duk_peval_string(dbg->ctx, "_debugGC();"); duk_pop(dbg->ctx);
|
|
duk_push_string(dbg->ctx, "MemoryAllocations");
|
|
duk_push_int(dbg->ctx, (duk_int_t)ILibDuktape_ScriptContainer_TotalAllocations);
|
|
duk_debugger_notify(dbg->ctx, 2);
|
|
}
|
|
}
|
|
duk_ret_t ILibDuktape_Debugger_hostGC(duk_context *ctx)
|
|
{
|
|
duk_push_current_function(ctx);
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_Debugger_DebugObject);
|
|
void *chain = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_Debugger_HostChain);
|
|
if (chain != NULL && dbg != NULL && ILibMemory_CanaryOK(dbg))
|
|
{
|
|
ILibChain_RunOnMicrostackThreadEx(chain, ILibDuktape_Debugger_hostGC_sink, dbg);
|
|
}
|
|
return(0);
|
|
|
|
}
|
|
void* ILibDuktape_Debugger_StartEngine(duk_context *ctx, int transport, int webport)
|
|
{
|
|
char *promise = NULL, *duktapeDebugger = NULL;
|
|
duk_size_t promiseLen, duktapeDebuggerLen;
|
|
ILibDuktape_Debugger *retVal = NULL;
|
|
|
|
if (ILibDuktape_ScriptContainer_DebuggingOK(ctx) != 0)
|
|
{
|
|
// Check to made sure we have the debugger dependencies
|
|
int argTop = duk_get_top(ctx);
|
|
if (duk_peval_string(ctx, "getJSModule('promise');") == 0 && duk_peval_string(ctx, "getJSModule('duktape-debugger');") == 0)
|
|
{
|
|
promise = (char*)duk_to_lstring(ctx, -2, &promiseLen);
|
|
duktapeDebugger = (char*)duk_to_lstring(ctx, -1, &duktapeDebuggerLen);
|
|
}
|
|
else
|
|
{
|
|
// Missing Dependencies, so cannot continue with setup
|
|
duk_peval_string(ctx, "process.emit('uncaughtException', 'Cannot setup debugger, missing promise and/or duktape-debugger');");
|
|
duk_set_top(ctx, argTop);
|
|
return(NULL);
|
|
}
|
|
|
|
// Setup WebEngine
|
|
DebugWebEngine_Chain = ILibCreateChain();
|
|
DebugWebEngine_Context = ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx(SCRIPT_ENGINE_NO_DEBUGGER | SCRIPT_ENGINE_NO_MESH_AGENT_ACCESS | SCRIPT_ENGINE_NO_GENERIC_MARSHAL_ACCESS | SCRIPT_ENGINE_NO_PROCESS_SPAWNING, 0, DebugWebEngine_Chain, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
ILibChain_OnDestroyEvent_AddHandler(Duktape_GetChain(ctx), ILibDuktape_Debugger_Destroy, NULL);
|
|
|
|
ILibDuktape_ModSearch_AddModule(DebugWebEngine_Context, "promise", promise, (int)promiseLen);
|
|
ILibDuktape_ModSearch_AddModule(DebugWebEngine_Context, "duktape-debugger", duktapeDebugger, (int)duktapeDebuggerLen);
|
|
|
|
duk_push_heap_stash(ctx);
|
|
char *src = Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_Debugger_SCRIPT_SOURCE, NULL);
|
|
char *srcPath = Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_Debugger_SCRIPT_PATH, NULL);
|
|
duk_pop(ctx);
|
|
|
|
if (src != NULL)
|
|
{
|
|
if (srcPath == NULL)
|
|
{
|
|
duk_push_global_object(ctx); // [g]
|
|
duk_get_prop_string(ctx, -1, "process"); // [g][process]
|
|
duk_get_prop_string(ctx, -1, "argv0"); // [g][process][argv0]
|
|
srcPath = (char*)duk_get_string(ctx, -1);
|
|
duk_pop_n(ctx, 3); // ...
|
|
}
|
|
duk_push_global_object(DebugWebEngine_Context); // [g]
|
|
duk_push_string(DebugWebEngine_Context, src); // [g][str]
|
|
duk_get_prop_string(DebugWebEngine_Context, -1, "split"); // [g][str][split]
|
|
duk_swap_top(DebugWebEngine_Context, -2); // [g][split][this]
|
|
duk_push_string(DebugWebEngine_Context, "\n"); // [g][split][this][\n]
|
|
duk_pcall_method(DebugWebEngine_Context, 1); // [g][tokens]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "_scriptTokens"); // [g]
|
|
duk_push_string(DebugWebEngine_Context, srcPath); // [g][path]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "_scriptPath"); // [g]
|
|
duk_pop(DebugWebEngine_Context); // ...
|
|
}
|
|
|
|
duk_push_heap_stash(ctx); // [stash]
|
|
retVal = (ILibDuktape_Debugger*)Duktape_PushBuffer(ctx, sizeof(ILibDuktape_Debugger)); // [stash][dbgobj]
|
|
duk_put_prop_string(ctx, -2, ILibDuktape_Debugger_DebugObject); // [stash]
|
|
duk_pop(ctx); // ...
|
|
|
|
duk_push_global_object(DebugWebEngine_Context); // [g]
|
|
duk_push_c_function(DebugWebEngine_Context, ILibDuktape_Debugger_StartEngine_UpdatePort, 1); // [g][func]
|
|
duk_push_pointer(DebugWebEngine_Context, retVal); // [g][func][ptr]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, ILibDuktape_Debugger_DebugObject); // [g][func]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "updateWebPort"); // [g]
|
|
|
|
duk_push_c_function(DebugWebEngine_Context, ILibDuktape_Debugger_hostCooperate, 0); // [g][func]
|
|
duk_push_pointer(DebugWebEngine_Context, retVal); // [g][func][ptr]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, ILibDuktape_Debugger_DebugObject); // [g][func]
|
|
duk_push_pointer(DebugWebEngine_Context, Duktape_GetChain(ctx)); // [g][func][ptr]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, ILibDuktape_Debugger_HostChain); // [g][func]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "hostCooperate"); // [g]
|
|
|
|
duk_push_c_function(DebugWebEngine_Context, ILibDuktape_Debugger_hostGC, 0); // [g][func]
|
|
duk_push_pointer(DebugWebEngine_Context, retVal); // [g][func][ptr]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, ILibDuktape_Debugger_DebugObject); // [g][func]
|
|
duk_push_pointer(DebugWebEngine_Context, Duktape_GetChain(ctx)); // [g][func][ptr]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, ILibDuktape_Debugger_HostChain); // [g][func]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "hostGC"); // [g]
|
|
|
|
|
|
duk_push_c_function(DebugWebEngine_Context, ILibDuktape_Debugger_detachCleanup, 0); // [g][func]
|
|
duk_push_pointer(DebugWebEngine_Context, retVal); // [g][func][ptr]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, ILibDuktape_Debugger_DebugObject); // [g][func]
|
|
duk_push_pointer(DebugWebEngine_Context, Duktape_GetChain(ctx)); // [g][func][ptr]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, ILibDuktape_Debugger_HostChain); // [g][func]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "detachCleanup"); // [g]
|
|
|
|
|
|
duk_push_int(DebugWebEngine_Context, transport);
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "transport");
|
|
duk_push_int(DebugWebEngine_Context, webport);
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "webport");
|
|
duk_pop(DebugWebEngine_Context); // ...
|
|
|
|
retVal->ctx = ctx;
|
|
sem_init(&(retVal->hostlock), 0, 0);
|
|
retVal->webport = webport;
|
|
|
|
duk_push_global_object(DebugWebEngine_Context); // *[g]
|
|
duk_push_object(DebugWebEngine_Context); // *[g][obj]
|
|
char *strkey, *strval;
|
|
duk_double_t nval;
|
|
|
|
duk_push_heap_stash(ctx); // [stash]
|
|
duk_get_prop_string(ctx, -1, ILibDuktape_Debugger_AttachOptions); // [stash][options]
|
|
duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY); // [stash][options][enum]
|
|
while (duk_next(ctx, -1, 1)) // [stash][options][enum][key][val]
|
|
{
|
|
if (duk_is_string(ctx, -2) && duk_is_string(ctx, -1))
|
|
{
|
|
strkey = (char*)duk_get_string(ctx, -2);
|
|
strval = (char*)duk_get_string(ctx, -1);
|
|
duk_push_string(DebugWebEngine_Context, strkey); // *[g][obj][key]
|
|
duk_push_string(DebugWebEngine_Context, strval); // *[g][obj][key][val]
|
|
duk_put_prop(DebugWebEngine_Context, -3); // *[g][obj]
|
|
}
|
|
else if (duk_is_string(ctx, -2) && duk_is_number(ctx, -1))
|
|
{
|
|
strkey = (char*)duk_get_string(ctx, -2);
|
|
nval = duk_get_number(ctx, -1);
|
|
duk_push_string(DebugWebEngine_Context, strkey); // *[g][obj][key]
|
|
duk_push_number(DebugWebEngine_Context, nval); // *[g][obj][key][val]
|
|
duk_put_prop(DebugWebEngine_Context, -3); // *[g][obj]
|
|
}
|
|
duk_pop_2(ctx); // [stash][options][enum]
|
|
}
|
|
duk_pop_3(ctx); // ...
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "attachOptions"); // *[g]
|
|
duk_pop(DebugWebEngine_Context); // ...
|
|
|
|
DebugWebEngine_Thread = ILibSpawnNormalThread(DebugWebEngine_Run, NULL);
|
|
}
|
|
return(retVal);
|
|
}
|
|
duk_ret_t ILibDuktape_Debugger_JSAttach_promise_wait(duk_context *ctx)
|
|
{
|
|
char *eventName = (char*)duk_require_string(ctx, 0);
|
|
if (strcmp(eventName, "settled") != 0) { return(0); }
|
|
|
|
duk_push_heap_stash(ctx);
|
|
duk_get_prop_string(ctx, -1, ILibDuktape_Debugger_DebugObject);
|
|
ILibDuktape_Debugger *dbg = (ILibDuktape_Debugger*)Duktape_GetBuffer(ctx, -1, NULL);
|
|
if (dbg == NULL)
|
|
{
|
|
printf("Error setting up debugger...\n");
|
|
}
|
|
else
|
|
{
|
|
listen(dbg->listener, 1);
|
|
ILibDuktape_Debugger_Socket_waitconn(dbg);
|
|
ILibDuktape_Debugger_StartMemoryReporting(dbg->ctx);
|
|
duk_debugger_attach(dbg->ctx, ILibDuktape_Debugger_ReadCB, ILibDuktape_Debugger_WriteCB, ILibDuktape_Debugger_PeekCB, NULL, NULL, NULL, ILibDuktape_Debugger_DetachCB, (void*)dbg);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
void ILibDuktape_Debugger_JSAttach_PopulateSource(duk_context *ctx, char *source)
|
|
{
|
|
if (source != NULL)
|
|
{
|
|
duk_push_heap_stash(ctx); // [stash]
|
|
duk_push_string(ctx, source); // [stash][src]
|
|
duk_put_prop_string(ctx, -2, ILibDuktape_Debugger_SCRIPT_SOURCE); // [stash]
|
|
duk_pop(ctx); // ...
|
|
}
|
|
else
|
|
{
|
|
char *script, *scriptPath;
|
|
int scriptLen;
|
|
|
|
duk_push_global_object(ctx); // [g]
|
|
duk_get_prop_string(ctx, -1, "process"); // [g][process]
|
|
duk_get_prop_string(ctx, -1, "argv0"); // [g][process][argv0]
|
|
scriptPath = (char*)duk_to_string(ctx, -1);
|
|
ILibDuktape_ScriptContainer_CheckEmbeddedEx(scriptPath, &script, &scriptLen);
|
|
duk_pop_3(ctx); // ...
|
|
|
|
if (script != NULL)
|
|
{
|
|
duk_push_heap_stash(ctx); // [stash]
|
|
duk_push_lstring(ctx, script, (duk_size_t)scriptLen); // [stash][src]
|
|
duk_put_prop_string(ctx, -2, ILibDuktape_Debugger_SCRIPT_SOURCE); // [stash]
|
|
duk_push_string(ctx, "[embedded].js");
|
|
duk_put_prop_string(ctx, -2, ILibDuktape_Debugger_SCRIPT_PATH); // [stash]
|
|
|
|
duk_pop(ctx); // ...
|
|
free(script);
|
|
}
|
|
else
|
|
{
|
|
duk_push_global_object(ctx); // [g]
|
|
duk_get_prop_string(ctx, -1, "process"); // [g][process]
|
|
duk_get_prop_string(ctx, -1, "argv0"); // [g][process][argv0]
|
|
if (duk_get_length(ctx, -1) == 0)
|
|
{
|
|
// JS was not specified on command line
|
|
if (duk_peval_string(ctx, "require('MeshAgent');") == 0)
|
|
{
|
|
int CoreModuleLen = 0;
|
|
ILibSimpleDataStore *db = (ILibSimpleDataStore*)Duktape_GetPointerProperty(ctx, -1, "\xFF_MasterDB");
|
|
if (db == NULL || (CoreModuleLen = ILibSimpleDataStore_Get(db, "CoreModule", NULL, 0)) <= 4)
|
|
{
|
|
ILibDuktape_Error(ctx, "Could Not retrive CoreModule from MeshAgent"); return;
|
|
}
|
|
// [g][process][argv0][MeshAgent]
|
|
char* CoreModule = ILibMemory_Allocate(CoreModuleLen, 0, NULL, NULL);
|
|
ILibSimpleDataStore_Get(db, "CoreModule", CoreModule, CoreModuleLen);
|
|
duk_push_lstring(ctx, CoreModule + 4, CoreModuleLen - 4); // [g][process][argv0][MeshAgent][CoreModule]
|
|
duk_push_heap_stash(ctx);
|
|
duk_swap_top(ctx, -2);
|
|
duk_put_prop_string(ctx, -2, ILibDuktape_Debugger_SCRIPT_SOURCE);
|
|
duk_push_string(ctx, "CoreModule.js");
|
|
duk_put_prop_string(ctx, -2, ILibDuktape_Debugger_SCRIPT_PATH);
|
|
free(CoreModule);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
ILibDuktape_Error(ctx, "Unable to retrive running java script"); return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
duk_eval_string(ctx, "require('fs');"); // [g][process][argv0][fs]
|
|
duk_get_prop_string(ctx, -1, "readFileSync"); // [g][process][argv0][fs][rfs]
|
|
duk_swap_top(ctx, -2); // [g][process][argv0][rfs][this]
|
|
duk_dup(ctx, -3); // [g][process][argv0][rfs][this][path]
|
|
duk_call_method(ctx, 1); // [g][process][argv0][sourceBuffer]
|
|
}
|
|
duk_get_prop_string(ctx, -1, "toString"); // [g][process][argv0][sourceBuffer][toString]
|
|
duk_swap_top(ctx, -2); // [g][process][argv0][toString][this]
|
|
duk_call_method(ctx, 0); // [g][process][argv0][sourceBuffer]
|
|
duk_push_heap_stash(ctx); // [g][process][argv0][source][stash]
|
|
duk_dup(ctx, -2); // [g][process][argv0][source][stash][source]
|
|
duk_put_prop_string(ctx, -2, ILibDuktape_Debugger_SCRIPT_SOURCE); // [g][process][argv0][source][stash]
|
|
}
|
|
}
|
|
}
|
|
|
|
duk_ret_t ILibDuktape_Debugger_JSAttach_promise(duk_context *ctx)
|
|
{
|
|
int needWait = 0;
|
|
#ifndef DUK_USE_DEBUGGER_SUPPORT
|
|
duk_dup(ctx, 1); // [rejector]
|
|
duk_push_this(ctx); // [rejector][this]
|
|
duk_push_string(ctx, "No debugger support"); // [rejector][this][err]
|
|
duk_call_method(ctx, 1); // [ret]
|
|
return(0);
|
|
#endif
|
|
#ifdef WIN32
|
|
SOCKET listenerSocket;
|
|
#else
|
|
int listenerSocket;
|
|
#endif
|
|
struct sockaddr_in6 *local_int;
|
|
struct sockaddr_in6 localBounded;
|
|
int localBoundedSize = sizeof(struct sockaddr_in);
|
|
|
|
duk_push_heap_stash(ctx); // [stash]
|
|
if (duk_has_prop_string(ctx, -1, ILibDuktape_Debugger_AttachOptions))
|
|
{
|
|
duk_dup(ctx, 1); // [stash][rejector]
|
|
duk_push_this(ctx); // [stash][rejector][this]
|
|
duk_push_string(ctx, "attachDebugger() already called"); // [stash][rejector][this][err]
|
|
duk_call_method(ctx, 1); // [stash][ret]
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
duk_push_current_function(ctx); // [stash][func]
|
|
duk_get_prop_string(ctx, -1, "options"); // [stash][func][options]
|
|
duk_remove(ctx, -2); // [stash][options]
|
|
duk_dup(ctx, -1); // [stash][options][options]
|
|
duk_put_prop_string(ctx, -3, ILibDuktape_Debugger_AttachOptions); // [stash][options]
|
|
duk_dup(ctx, 0); duk_put_prop_string(ctx, -2, ILibDuktape_Debugger_Options_Resolver);
|
|
duk_dup(ctx, 1); duk_put_prop_string(ctx, -2, ILibDuktape_Debugger_Options_Rejector);
|
|
}
|
|
|
|
int transport = Duktape_GetIntPropertyValue(ctx, -1, "transport", 0);
|
|
int webport = Duktape_GetIntPropertyValue(ctx, -1, "webport", 0);
|
|
char *source = Duktape_GetStringPropertyValue(ctx, -1, "source", NULL);
|
|
|
|
local_int = Duktape_IPAddress4_FromString("127.0.0.1", transport);
|
|
#ifdef WIN32
|
|
if ((listenerSocket = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT)) == -1) { listenerSocket = (SOCKET)~0; }
|
|
#else
|
|
if ((listenerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { listenerSocket = (SOCKET)~0; }
|
|
#endif
|
|
if (listenerSocket == (SOCKET)~0)
|
|
{
|
|
// Error creating socket
|
|
duk_dup(ctx, 1); // [rejector]
|
|
duk_push_this(ctx); // [rejector][this]
|
|
duk_push_string(ctx, "Error Creating Debug Transport Socket"); // [rejector][this][err]
|
|
duk_call_method(ctx, 1);
|
|
return(0);
|
|
}
|
|
if (bind(listenerSocket, (struct sockaddr*)local_int, sizeof(struct sockaddr_in)) != 0) { return(ILibDuktape_Error(ctx, "BIND error")); }
|
|
#if defined(WINSOCK2)
|
|
getsockname(listenerSocket, (struct sockaddr*)&localBounded, (int*)&localBoundedSize);
|
|
#else
|
|
if (getsockname(listenerSocket, (struct sockaddr*)&localBounded, (socklen_t*)&localBoundedSize) != 0)
|
|
{
|
|
localBoundedSize = (int)sizeof(struct sockaddr_in);
|
|
if (getsockname(listenerSocket, (struct sockaddr*)&localBounded, (socklen_t*)&localBoundedSize) != 0)
|
|
{
|
|
}
|
|
}
|
|
#endif
|
|
transport = (int)ntohs(localBounded.sin6_port);
|
|
|
|
if (Duktape_GetIntPropertyValue(ctx, -1, "wait", 0) == 1)
|
|
{
|
|
needWait = 1;
|
|
|
|
// WaitForDebugger... We'll hookup an event hook, so we can be notified when somebody calls 'then'
|
|
duk_push_this(ctx); // [promise]
|
|
duk_get_prop_string(ctx, -1, "_internal"); // [promise][internal]
|
|
duk_get_prop_string(ctx, -1, "once"); // [promise][internal][once]
|
|
duk_swap_top(ctx, -2); // [promise][on][this]
|
|
duk_push_string(ctx, "newListener"); // [promise][on][this][newListener]
|
|
duk_push_c_function(ctx, ILibDuktape_Debugger_JSAttach_promise_wait, 2);// [promise][on][this][newListener][func]
|
|
duk_call_method(ctx, 2);
|
|
}
|
|
|
|
// Before we do anything, we need to setup the source
|
|
ILibDuktape_Debugger_JSAttach_PopulateSource(ctx, source);
|
|
|
|
ILibDuktape_Debugger *dbg;
|
|
if ((dbg = ILibDuktape_Debugger_StartEngine(ctx, transport, webport)) == NULL)
|
|
{
|
|
// error
|
|
duk_dup(ctx, 1); // [rejector]
|
|
duk_push_this(ctx); // [rejector][this]
|
|
duk_push_string(ctx, "Error Starting Debug Engine");// [rejector][this][err]
|
|
duk_call_method(ctx, 1);
|
|
}
|
|
else
|
|
{
|
|
// success
|
|
duk_suspend(ctx, &(dbg->hoststate));
|
|
dbg->listener = listenerSocket;
|
|
sem_wait(&(dbg->hostlock));
|
|
sem_destroy(&(dbg->hostlock));
|
|
duk_resume(ctx, &(dbg->hoststate));
|
|
|
|
if (needWait == 0)
|
|
{
|
|
listen(dbg->listener, 1);
|
|
ILibDuktape_Debugger_AsyncWaitConn(dbg);
|
|
}
|
|
|
|
// Resolve the promise with the bounded WebPort
|
|
duk_dup(ctx, 0); // [resolver]
|
|
duk_push_this(ctx); // [resolver][this]
|
|
duk_push_int(ctx, dbg->webport); // [resolver][this][webport]
|
|
duk_call_method(ctx, 1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
duk_ret_t ILibDuktape_Debugger_JSAttach(duk_context *ctx)
|
|
{
|
|
int nargs = duk_get_top(ctx);
|
|
duk_eval_string(ctx, "require('promise');"); // [promisectr]
|
|
duk_push_c_function(ctx, ILibDuktape_Debugger_JSAttach_promise, 2); // [promisectr][func]
|
|
if (nargs > 0 && duk_is_object(ctx, 0))
|
|
{
|
|
duk_dup(ctx, 0); duk_put_prop_string(ctx, -2, "options");
|
|
}
|
|
else
|
|
{
|
|
duk_push_object(ctx); duk_put_prop_string(ctx, -2, "options");
|
|
}
|
|
duk_new(ctx, 1); // [promise]
|
|
return(1);
|
|
}
|
|
void ILibDuktape_Debugger_Init(duk_context *ctx, unsigned short debugPort)
|
|
{
|
|
duk_push_global_object(ctx);
|
|
ILibDuktape_CreateInstanceMethod(ctx, "attachDebugger", ILibDuktape_Debugger_JSAttach, DUK_VARARGS);
|
|
duk_pop(ctx);
|
|
}
|
|
void ILibDuktape_Debugger_SetScriptEx(void *chain, void *user)
|
|
{
|
|
if (ILibMemory_CanaryOK(user))
|
|
{
|
|
duk_push_global_object(DebugWebEngine_Context);
|
|
if (!duk_has_prop_string(DebugWebEngine_Context, -1, "_scriptTokens"))
|
|
{
|
|
duk_push_lstring(DebugWebEngine_Context, ILibMemory_Extra(user), ILibMemory_ExtraSize(user));
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "_scriptPath");
|
|
duk_pop(DebugWebEngine_Context);
|
|
|
|
duk_push_lstring(DebugWebEngine_Context, (char*)user, (duk_size_t)ILibMemory_Size(user)); // [str]
|
|
duk_get_prop_string(DebugWebEngine_Context, -1, "split"); // [str][split]
|
|
duk_swap_top(DebugWebEngine_Context, -2); // [split][this]
|
|
duk_push_string(DebugWebEngine_Context, "\n"); // [split][this][\n]
|
|
if (duk_pcall_method(DebugWebEngine_Context, 1) == 0)
|
|
{ // [tokens]
|
|
duk_push_global_object(DebugWebEngine_Context); // [tokens][g]
|
|
duk_swap_top(DebugWebEngine_Context, -2); // [g][tokens]
|
|
duk_put_prop_string(DebugWebEngine_Context, -2, "_scriptTokens"); // [g]
|
|
}
|
|
}
|
|
duk_pop(DebugWebEngine_Context);
|
|
ILibMemory_Free(user);
|
|
}
|
|
}
|
|
void ILibDuktape_Debugger_SetScript(char *js, int jsLen, char *fileName, int fileNameLen)
|
|
{
|
|
if (DebugWebEngine_Chain != NULL)
|
|
{
|
|
if (fileNameLen <= 0 && fileName != NULL)
|
|
{
|
|
fileNameLen = (int)strnlen_s(fileName, _MAX_PATH);
|
|
}
|
|
char *jsRef = (char*)ILibMemory_SmartAllocateEx(jsLen, fileNameLen);
|
|
memcpy_s(jsRef, jsLen, js, jsLen);
|
|
if (fileNameLen > 0)
|
|
{
|
|
memcpy_s(ILibMemory_Extra(jsRef), ILibMemory_ExtraSize(jsRef), fileName, fileNameLen);
|
|
}
|
|
ILibChain_RunOnMicrostackThreadEx(DebugWebEngine_Chain, ILibDuktape_Debugger_SetScriptEx, jsRef);
|
|
}
|
|
}
|