mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-3823: TraceRmi Launcher framework + dbgeng for Windows.
This commit is contained in:
parent
80d92aa32f
commit
c126cf51c0
33 changed files with 1206 additions and 1303 deletions
|
@ -1,224 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#define INITGUID
|
||||
|
||||
#include <engextcpp.hpp>
|
||||
#include <jni.h>
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
#define CHECK_RESULT(x, y) do { \
|
||||
HRESULT hr = (x); \
|
||||
if (hr != S_OK) { \
|
||||
fprintf(stderr, "HRESULT of %s = %x\n", ##x, hr); \
|
||||
return y; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
class EXT_CLASS : public ExtExtension {
|
||||
public:
|
||||
virtual HRESULT Initialize();
|
||||
virtual void Uninitialize();
|
||||
|
||||
//virtual void OnSessionAccessible(ULONG64 Argument);
|
||||
|
||||
EXT_COMMAND_METHOD(java_add_cp);
|
||||
EXT_COMMAND_METHOD(java_set);
|
||||
EXT_COMMAND_METHOD(java_get);
|
||||
EXT_COMMAND_METHOD(java_run);
|
||||
|
||||
void run_command(PCSTR name);
|
||||
};
|
||||
|
||||
EXT_DECLARE_GLOBALS();
|
||||
|
||||
JavaVM* jvm = NULL;
|
||||
JNIEnv* env = NULL;
|
||||
jclass clsCommands = NULL;
|
||||
|
||||
char JDK_JVM_DLL_PATH[] = "\\jre\\bin\\server\\jvm.dll";
|
||||
char JRE_JVM_DLL_PATH[] = "\\bin\\server\\jvm.dll";
|
||||
|
||||
typedef jint (_cdecl *CreateJavaVMFunc)(JavaVM**, void**, void*);
|
||||
|
||||
HRESULT EXT_CLASS::Initialize() {
|
||||
HRESULT result = ExtExtension::Initialize();
|
||||
if (result != S_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
char* env_java_home = getenv("JAVA_HOME");
|
||||
if (env_java_home == NULL) {
|
||||
fprintf(stderr, "JAVA_HOME is not set\n");
|
||||
fflush(stderr);
|
||||
return E_FAIL;
|
||||
}
|
||||
char* java_home = strdup(env_java_home);
|
||||
size_t home_len = strlen(java_home);
|
||||
if (java_home[home_len - 1] == '\\') {
|
||||
java_home[home_len - 1] = '\0';
|
||||
}
|
||||
size_t full_len = home_len + sizeof(JDK_JVM_DLL_PATH);
|
||||
char* full_path = new char[full_len];
|
||||
HMODULE jvmDll = NULL;
|
||||
// Try the JRE path first;
|
||||
strcpy_s(full_path, full_len, java_home);
|
||||
strcat_s(full_path, full_len, JRE_JVM_DLL_PATH);
|
||||
fprintf(stderr, "Trying to find jvm.dll at %s\n", full_path);
|
||||
fflush(stderr);
|
||||
jvmDll = LoadLibraryA(full_path);
|
||||
if (jvmDll == NULL) {
|
||||
// OK, then try the JDK path
|
||||
strcpy_s(full_path, full_len, java_home);
|
||||
strcat_s(full_path, full_len, JDK_JVM_DLL_PATH);
|
||||
fprintf(stderr, "Trying to find jvm.dll at %s\n", full_path);
|
||||
fflush(stderr);
|
||||
jvmDll = LoadLibraryA(full_path);
|
||||
}
|
||||
free(full_path);
|
||||
free(java_home);
|
||||
if (jvmDll == NULL) {
|
||||
fprintf(stderr, "Could not find the jvm.dll\n");
|
||||
fflush(stderr);
|
||||
return E_FAIL;
|
||||
}
|
||||
fprintf(stderr, "Found it!\n");
|
||||
fflush(stderr);
|
||||
|
||||
JavaVMOption options[2];
|
||||
JavaVMInitArgs vm_args = { 0 };
|
||||
vm_args.version = JNI_VERSION_1_8;
|
||||
vm_args.nOptions = sizeof(options)/sizeof(options[0]);
|
||||
vm_args.options = options;
|
||||
options[0].optionString = "-Xrs";
|
||||
options[1].optionString = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005";
|
||||
vm_args.ignoreUnrecognized = false;
|
||||
CreateJavaVMFunc create_jvm = NULL;
|
||||
//create_jvm = JNI_CreateJavaVM;
|
||||
create_jvm = (CreateJavaVMFunc) GetProcAddress(jvmDll, "JNI_CreateJavaVM");
|
||||
jint jni_result = create_jvm(&jvm, (void**)&env, &vm_args);
|
||||
|
||||
if (jni_result != JNI_OK) {
|
||||
jvm = NULL;
|
||||
fprintf(stderr, "Could not initialize JVM: %d: ", jni_result);
|
||||
switch (jni_result) {
|
||||
case JNI_ERR:
|
||||
fprintf(stderr, "unknown error");
|
||||
break;
|
||||
case JNI_EDETACHED:
|
||||
fprintf(stderr, "thread detached from the VM");
|
||||
break;
|
||||
case JNI_EVERSION:
|
||||
fprintf(stderr, "JNI version error");
|
||||
break;
|
||||
case JNI_ENOMEM:
|
||||
fprintf(stderr, "not enough memory");
|
||||
break;
|
||||
case JNI_EEXIST:
|
||||
fprintf(stderr, "VM already created");
|
||||
break;
|
||||
case JNI_EINVAL:
|
||||
fprintf(stderr, "invalid arguments");
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
HMODULE hJavaProviderModule = GetModuleHandle(TEXT("javaprovider"));
|
||||
HRSRC resCommandsClassfile = FindResource(hJavaProviderModule, MAKEINTRESOURCE(IDR_CLASSFILE1), TEXT("Classfile"));
|
||||
HGLOBAL gblCommandsClassfile = LoadResource(hJavaProviderModule, resCommandsClassfile);
|
||||
LPVOID lpCommandsClassfile = LockResource(gblCommandsClassfile);
|
||||
DWORD szCommandsClassfile = SizeofResource(hJavaProviderModule, resCommandsClassfile);
|
||||
|
||||
clsCommands = env->DefineClass(
|
||||
"javaprovider/Commands", NULL, (jbyte*) lpCommandsClassfile, szCommandsClassfile
|
||||
);
|
||||
if (clsCommands == NULL) {
|
||||
fprintf(stderr, "Could not define Commands class\n");
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void EXT_CLASS::Uninitialize() {
|
||||
if (jvm != NULL) {
|
||||
jvm->DestroyJavaVM();
|
||||
}
|
||||
ExtExtension::Uninitialize();
|
||||
}
|
||||
|
||||
void EXT_CLASS::run_command(PCSTR name) {
|
||||
// TODO: Throw an exception during load, then!
|
||||
if (jvm == NULL) {
|
||||
Out("javaprovider extension did not load properly.\n");
|
||||
return;
|
||||
}
|
||||
if (clsCommands == NULL) {
|
||||
Out("javaprovider extension did not load properly.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
PCSTR args = GetRawArgStr();
|
||||
|
||||
jmethodID mthCommand = env->GetStaticMethodID(clsCommands, name, "(Ljava/lang/String;)V");
|
||||
if (mthCommand == NULL) {
|
||||
Out("INTERNAL ERROR: No such command: %s\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
jstring argsStr = env->NewStringUTF(args);
|
||||
if (argsStr == NULL) {
|
||||
Out("Could not create Java string for arguments.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
env->CallStaticVoidMethod(clsCommands, mthCommand, argsStr);
|
||||
env->DeleteLocalRef(argsStr);
|
||||
if (env->ExceptionCheck()) {
|
||||
Out("Exception during javaprovider command:\n");
|
||||
env->ExceptionDescribe(); // TODO: Send this to output callbacks, not console.
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
|
||||
EXT_COMMAND(java_add_cp, "Add an element to the class path", "{{custom}}") {
|
||||
run_command("java_add_cp");
|
||||
}
|
||||
|
||||
EXT_COMMAND(java_set, "Set a Java system property", "{{custom}}") {
|
||||
run_command("java_set");
|
||||
}
|
||||
|
||||
EXT_COMMAND(java_get, "Get a Java system property", "{{custom}}") {
|
||||
run_command("java_get");
|
||||
}
|
||||
|
||||
EXT_COMMAND(java_run, "Execute the named java class", "{{custom}}") {
|
||||
run_command("java_run");
|
||||
}
|
||||
|
||||
#define JNA extern "C" __declspec(dllexport)
|
||||
|
||||
JNA HRESULT createClient(PDEBUG_CLIENT* client) {
|
||||
return g_ExtInstance.m_Client->CreateClient(client);
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
EXPORTS
|
||||
|
||||
; For ExtCpp
|
||||
DebugExtensionInitialize
|
||||
DebugExtensionUninitialize
|
||||
DebugExtensionNotify
|
||||
help
|
||||
|
||||
; My Commands
|
||||
java_add_cp
|
||||
java_set
|
||||
java_get
|
||||
java_run
|
|
@ -1,16 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <Windows.h>
|
|
@ -1,31 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by javaprovider.rc
|
||||
//
|
||||
#define IDR_CLASSFILE1 101
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
|
@ -19,6 +19,7 @@ import os.path
|
|||
import socket
|
||||
import time
|
||||
import sys
|
||||
import re
|
||||
|
||||
from ghidratrace import sch
|
||||
from ghidratrace.client import Client, Address, AddressRange, TraceObject
|
||||
|
@ -185,7 +186,7 @@ def compute_name(progname=None):
|
|||
progname = buffer.decode('utf-8')
|
||||
except Exception:
|
||||
return 'pydbg/noname'
|
||||
return 'pydbg/' + progname.split('/')[-1]
|
||||
return 'pydbg/' + re.split(r'/|\\', progname)[-1]
|
||||
|
||||
|
||||
def start_trace(name):
|
||||
|
@ -1301,7 +1302,36 @@ def ghidra_util_wait_stopped(timeout=1):
|
|||
time.sleep(0.1)
|
||||
if time.time() - start > timeout:
|
||||
raise RuntimeError('Timed out waiting for thread to stop')
|
||||
|
||||
|
||||
|
||||
|
||||
def dbg():
|
||||
return util.get_debugger()
|
||||
|
||||
|
||||
SHOULD_WAIT = ['GO', 'STEP_BRANCH', 'STEP_INTO', 'STEP_OVER']
|
||||
|
||||
|
||||
def repl():
|
||||
print("This is the dbgeng.dll (WinDbg) REPL. To drop to Python3, press Ctrl-C.")
|
||||
while True:
|
||||
# TODO: Implement prompt retrieval in PR to pybag?
|
||||
print('dbg> ', end='')
|
||||
try:
|
||||
cmd = input().strip()
|
||||
if not cmd:
|
||||
continue
|
||||
dbg().cmd(cmd, quiet=False)
|
||||
stat = dbg().exec_status()
|
||||
if stat != 'BREAK':
|
||||
dbg().wait()
|
||||
else:
|
||||
pass
|
||||
#dbg().dispatch_events()
|
||||
except KeyboardInterrupt as e:
|
||||
print("")
|
||||
print("You have left the dbgeng REPL and are now at the Python3 interpreter.")
|
||||
print("use repl() to re-enter.")
|
||||
return
|
||||
except:
|
||||
# Assume cmd() has already output the error
|
||||
pass
|
||||
|
|
|
@ -383,7 +383,7 @@ def interrupt():
|
|||
|
||||
@REGISTRY.method(action='step_into')
|
||||
def step_into(thread: sch.Schema('Thread'), n: ParamDesc(int, display='N')=1):
|
||||
"""Step on instruction exactly."""
|
||||
"""Step one instruction exactly."""
|
||||
find_thread_by_obj(thread)
|
||||
dbg().stepi(n)
|
||||
|
||||
|
@ -511,7 +511,7 @@ def write_mem(process: sch.Schema('Process'), address: Address, data: bytes):
|
|||
|
||||
|
||||
@REGISTRY.method
|
||||
def write_reg(frame: sch.Schema('Frame'), name: str, value: bytes):
|
||||
def write_reg(frame: sch.Schema('StackFrame'), name: str, value: bytes):
|
||||
"""Write a register."""
|
||||
util.select_frame()
|
||||
nproc = pydbg.selected_process()
|
||||
|
|
|
@ -1,315 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define INITGUID
|
||||
#include <dbgeng.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
JavaVM* jvm = NULL;
|
||||
JNIEnv* env = NULL;
|
||||
|
||||
char JDK_JVM_DLL_PATH[] = "\\jre\\bin\\server\\jvm.dll";
|
||||
char JRE_JVM_DLL_PATH[] = "\\bin\\server\\jvm.dll";
|
||||
|
||||
char MAIN_CLASS[] = "sctldbgeng/sctl/DbgEngSctlServer";
|
||||
|
||||
char CP_PREFIX[] = "-Djava.class.path=";
|
||||
|
||||
typedef jint (_cdecl *CreateJavaVMFunc)(JavaVM**, void**, void*);
|
||||
|
||||
|
||||
#define CHECK_RC(v, f, x) do { \
|
||||
HRESULT ___hr = (x); \
|
||||
if (___hr < 0) { \
|
||||
fprintf(stderr, "FAILED on line %d: HRESULT=%08x\n", __LINE__, ___hr); \
|
||||
goto f; \
|
||||
} else if (___hr == S_OK) { \
|
||||
v = 1; \
|
||||
} else { \
|
||||
v = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#if 0
|
||||
class MyEventCallbacks : public DebugBaseEventCallbacks {
|
||||
public:
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) {
|
||||
InterlockedIncrement(&m_ulRefCount);
|
||||
return m_ulRefCount;
|
||||
}
|
||||
|
||||
STDMETHOD_(ULONG, Release)(THIS) {
|
||||
ULONG ulRefCount = InterlockedDecrement(&m_ulRefCount);
|
||||
if (m_ulRefCount == 0) {
|
||||
delete this;
|
||||
}
|
||||
return ulRefCount;
|
||||
}
|
||||
|
||||
STDMETHOD(GetInterestMask)(_Out_ PULONG Mask) {
|
||||
*Mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_CREATE_THREAD;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHOD(CreateProcess)(
|
||||
THIS_
|
||||
_In_ ULONG64 ImageFileHandle,
|
||||
_In_ ULONG64 Handle,
|
||||
_In_ ULONG64 BaseOffset,
|
||||
_In_ ULONG ModuleSize,
|
||||
_In_ PCSTR ModuleName,
|
||||
_In_ PCSTR ImageName,
|
||||
_In_ ULONG CheckSum,
|
||||
_In_ ULONG TimeDateStamp,
|
||||
_In_ ULONG64 InitialThreadHandle,
|
||||
_In_ ULONG64 ThreadDataOffset,
|
||||
_In_ ULONG64 StartOffset
|
||||
) {
|
||||
UNREFERENCED_PARAMETER(ImageFileHandle);
|
||||
UNREFERENCED_PARAMETER(Handle);
|
||||
UNREFERENCED_PARAMETER(BaseOffset);
|
||||
UNREFERENCED_PARAMETER(ModuleSize);
|
||||
UNREFERENCED_PARAMETER(ModuleName);
|
||||
UNREFERENCED_PARAMETER(ImageName);
|
||||
UNREFERENCED_PARAMETER(CheckSum);
|
||||
UNREFERENCED_PARAMETER(TimeDateStamp);
|
||||
UNREFERENCED_PARAMETER(InitialThreadHandle);
|
||||
UNREFERENCED_PARAMETER(ThreadDataOffset);
|
||||
UNREFERENCED_PARAMETER(StartOffset);
|
||||
return DEBUG_STATUS_BREAK;
|
||||
}
|
||||
|
||||
STDMETHOD(CreateThread)(
|
||||
THIS_
|
||||
_In_ ULONG64 Handle,
|
||||
_In_ ULONG64 DataOffset,
|
||||
_In_ ULONG64 StartOffset
|
||||
) {
|
||||
UNREFERENCED_PARAMETER(Handle);
|
||||
UNREFERENCED_PARAMETER(DataOffset);
|
||||
UNREFERENCED_PARAMETER(StartOffset);
|
||||
return DEBUG_STATUS_BREAK;
|
||||
}
|
||||
private:
|
||||
ULONG m_ulRefCount = 0;
|
||||
};
|
||||
|
||||
int main_exp00(int argc, char** argv) {
|
||||
PDEBUG_CLIENT5 pClient5 = NULL;
|
||||
PDEBUG_CONTROL4 pControl4 = NULL;
|
||||
PDEBUG_SYMBOLS3 pSymbols3 = NULL;
|
||||
int ok = 0;
|
||||
|
||||
CHECK_RC(ok, EXIT, DebugCreate(IID_IDebugClient5, (PVOID*) &pClient5));
|
||||
CHECK_RC(ok, EXIT, pClient5->QueryInterface(IID_IDebugControl4, (PVOID*) &pControl4));
|
||||
CHECK_RC(ok, EXIT, pClient5->QueryInterface(IID_IDebugSymbols3, (PVOID*) &pSymbols3));
|
||||
|
||||
pClient5->SetEventCallbacks(new MyEventCallbacks());
|
||||
|
||||
CHECK_RC(ok, EXIT, pControl4->Execute(DEBUG_OUTCTL_ALL_CLIENTS, ".create notepad", DEBUG_EXECUTE_ECHO));
|
||||
CHECK_RC(ok, EXIT, pControl4->WaitForEvent(0, INFINITE));
|
||||
CHECK_RC(ok, EXIT, pControl4->Execute(DEBUG_OUTCTL_ALL_CLIENTS, "g", DEBUG_EXECUTE_ECHO));
|
||||
CHECK_RC(ok, EXIT, pControl4->WaitForEvent(0, INFINITE));
|
||||
|
||||
ULONG64 ul64MatchHandle = 0;
|
||||
CHECK_RC(ok, EXIT, pSymbols3->StartSymbolMatch("*", &ul64MatchHandle));
|
||||
while (true) {
|
||||
char aBuffer[1024] = { 0 };
|
||||
ULONG64 ul64Offset = 0;
|
||||
CHECK_RC(ok, FINISH, pSymbols3->GetNextSymbolMatch(ul64MatchHandle, aBuffer, sizeof(aBuffer), NULL, &ul64Offset));
|
||||
printf("%016x: %s\n", ul64Offset, aBuffer);
|
||||
}
|
||||
FINISH:
|
||||
|
||||
fprintf(stderr, "SUCCESS\n");
|
||||
EXIT:
|
||||
pClient5->SetEventCallbacks(NULL);
|
||||
pControl4->Release();
|
||||
pClient5->Release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main_exp01(int argc, char** argv) {
|
||||
PDEBUG_CLIENT5 pClient5 = NULL;
|
||||
int ok = 0;
|
||||
|
||||
CHECK_RC(ok, EXIT, DebugCreate(IID_IDebugClient5, (PVOID*) &pClient5));
|
||||
|
||||
CHECK_RC(ok, EXIT, pClient5->StartProcessServerWide(DEBUG_CLASS_USER_WINDOWS, L"tcp:port=11200", NULL));
|
||||
CHECK_RC(ok, EXIT, pClient5->WaitForProcessServerEnd(INFINITE));
|
||||
EXIT:
|
||||
if (pClient5 != NULL) {
|
||||
pClient5->Release();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main_sctldbg(int argc, char** argv) {
|
||||
if (argc < 1) {
|
||||
fprintf(stderr, "Something is terribly wrong: argc == 0\n");
|
||||
}
|
||||
char* env_java_home = getenv("JAVA_HOME");
|
||||
if (env_java_home == NULL) {
|
||||
fprintf(stderr, "JAVA_HOME is not set\n");
|
||||
fflush(stderr);
|
||||
return -1;
|
||||
}
|
||||
char* java_home = strdup(env_java_home);
|
||||
size_t home_len = strlen(java_home);
|
||||
if (java_home[home_len - 1] == '\\') {
|
||||
java_home[home_len - 1] = '\0';
|
||||
}
|
||||
size_t full_len = home_len + sizeof(JDK_JVM_DLL_PATH);
|
||||
char* full_path = new char[full_len];
|
||||
HMODULE jvmDll = NULL;
|
||||
// Try the JRE path first;
|
||||
strcpy_s(full_path, full_len, java_home);
|
||||
strcat_s(full_path, full_len, JRE_JVM_DLL_PATH);
|
||||
fprintf(stderr, "Trying to find jvm.dll at %s\n", full_path);
|
||||
fflush(stderr);
|
||||
jvmDll = LoadLibraryA(full_path);
|
||||
if (jvmDll == NULL) {
|
||||
// OK, then try the JDK path
|
||||
strcpy_s(full_path, full_len, java_home);
|
||||
strcat_s(full_path, full_len, JDK_JVM_DLL_PATH);
|
||||
fprintf(stderr, "Trying to find jvm.dll at %s\n", full_path);
|
||||
fflush(stderr);
|
||||
jvmDll = LoadLibraryA(full_path);
|
||||
}
|
||||
|
||||
free(full_path);
|
||||
free(java_home);
|
||||
|
||||
if (jvmDll == NULL) {
|
||||
fprintf(stderr, "Could not find the jvm.dll\n");
|
||||
fflush(stderr);
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "Found it!\n");
|
||||
fflush(stderr);
|
||||
|
||||
#define USE_EXE_AS_JAR
|
||||
#ifdef USE_EXE_AS_JAR
|
||||
DWORD fullpath_len = GetFullPathNameA(argv[0], 0, NULL, NULL);
|
||||
char* fullpath = new char[fullpath_len];
|
||||
GetFullPathNameA(argv[0], fullpath_len, fullpath, NULL);
|
||||
size_t cp_opt_len = sizeof(CP_PREFIX) + strlen(fullpath);
|
||||
char* cp_opt = new char[cp_opt_len];
|
||||
strcpy_s(cp_opt, cp_opt_len, CP_PREFIX);
|
||||
strcat_s(cp_opt, cp_opt_len, fullpath);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
|
||||
JavaVMOption options[2];
|
||||
JavaVMInitArgs vm_args = { 0 };
|
||||
vm_args.version = JNI_VERSION_1_8;
|
||||
vm_args.nOptions = sizeof(options)/sizeof(options[0]);
|
||||
vm_args.options = options;
|
||||
options[0].optionString = "-Xrs";
|
||||
#ifdef USE_EXE_AS_JAR
|
||||
fprintf(stderr, "Classpath: %s\n", cp_opt);
|
||||
options[1].optionString = cp_opt;
|
||||
#else
|
||||
options[1].optionString = "-Djava.class.path=sctldbgeng.jar";
|
||||
#endif
|
||||
//options[2].optionString = "-verbose:class";
|
||||
vm_args.ignoreUnrecognized = false;
|
||||
CreateJavaVMFunc create_jvm = NULL;
|
||||
//create_jvm = JNI_CreateJavaVM;
|
||||
create_jvm = (CreateJavaVMFunc) GetProcAddress(jvmDll, "JNI_CreateJavaVM");
|
||||
jint jni_result = create_jvm(&jvm, (void**)&env, &vm_args);
|
||||
|
||||
#ifdef USE_EXE_AS_JAR
|
||||
free(cp_opt);
|
||||
#endif
|
||||
|
||||
if (jni_result != JNI_OK) {
|
||||
jvm = NULL;
|
||||
fprintf(stderr, "Could not initialize JVM: %d: ", jni_result);
|
||||
switch (jni_result) {
|
||||
case JNI_ERR:
|
||||
fprintf(stderr, "unknown error");
|
||||
break;
|
||||
case JNI_EDETACHED:
|
||||
fprintf(stderr, "thread detached from the VM");
|
||||
break;
|
||||
case JNI_EVERSION:
|
||||
fprintf(stderr, "JNI version error");
|
||||
break;
|
||||
case JNI_ENOMEM:
|
||||
fprintf(stderr, "not enough memory");
|
||||
break;
|
||||
case JNI_EEXIST:
|
||||
fprintf(stderr, "VM already created");
|
||||
break;
|
||||
case JNI_EINVAL:
|
||||
fprintf(stderr, "invalid arguments");
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
jclass mainCls = env->FindClass(MAIN_CLASS);
|
||||
if (mainCls == NULL) {
|
||||
fprintf(stderr, "Could not find main class: %s\n", MAIN_CLASS);
|
||||
jvm->DestroyJavaVM();
|
||||
return -1;
|
||||
}
|
||||
|
||||
jmethodID mainMeth = env->GetStaticMethodID(mainCls, "main", "([Ljava/lang/String;)V");
|
||||
if (mainMeth == NULL) {
|
||||
fprintf(stderr, "No main(String[] args) method in main class\n");
|
||||
jvm->DestroyJavaVM();
|
||||
return -1;
|
||||
}
|
||||
|
||||
jclass stringCls = env->FindClass("java/lang/String");
|
||||
|
||||
jobjectArray jargs = env->NewObjectArray(argc - 1, stringCls, NULL);
|
||||
for (int i = 1; i < argc; i++) {
|
||||
jstring a = env->NewStringUTF(argv[i]);
|
||||
if (a == NULL) {
|
||||
fprintf(stderr, "Could not create Java string for arguments.\n");
|
||||
jvm->DestroyJavaVM();
|
||||
return -1;
|
||||
}
|
||||
env->SetObjectArrayElement(jargs, i - 1, a);
|
||||
}
|
||||
|
||||
env->CallStaticVoidMethod(mainCls, mainMeth, (jvalue*) jargs);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
jvm->DestroyJavaVM();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
main_sctldbg(argc, argv);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue