blob: 1a76d892e729ec2a5aaaab1d3948082d4e5bb478 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <jvmpi.h>
#include <string.h>
#include <stdlib.h>
static JavaVM *jvm;
static JNIEnv *env;
static JVMPI_Interface *jvmpi;
extern "C" JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM *jvm, char *options, void *reserved);
static void notifyEvent(JVMPI_Event *event);
static int total = 0;
const char * traced_methods[] = {
// java.beans.PropertyChangeListener
"propertyChange", "(Ljava/beans/PropertyChangeEvent;)V",
// java.beans.VetoableChangeListener
"vetoableChange", "(Ljava/beans/PropertyChangeEvent;)V",
// javax.swing.event.ChangeListener
"stateChanged", "(Ljavax/swing/event/ChangeEvent;)V",
// javax.swing.event.DocumentListener
"insertUpdate", "(Ljavax/swing/event/DocumentEvent;)V",
"removeUpdate", "(Ljavax/swing/event/DocumentEvent;)V",
"changedUpdate", "(Ljavax/swing/event/DocumentEvent;)V",
// javax.swing.event.UndoableEditListener
"undoableEditHappened", "(Ljavax/swing/event/UndoableEditEvent;)V",
// org.netbeans.core.awt.BuButtonBar$ButtonBarListener
"buttonPressed", "(L(org/netbeans/core/awt/ButtonBar$ButtonBarEvent;)V",
// org.openide.util.datatransfer.ClipboardListener
"clipboardChanged", "(Lorg/openide/util/datatransfer/ClipboardEvent;)V",
// org.openide.compiler.CompilerListener
"compilerProgress", "(Lorg.openide.compiler/ProgressEvent;)V",
"compilerError", "(Lorg.openide.compiler.ErrorEvent;)V",
// org.netbeans.core.execution.ExecutionListener
"startedExecution", "(Lorg/netbeans/core/execution/ExecutionEvent;)V",
"finishedExecution", "(Lorg/netbeans/core/execution/ExecutionEvent;)V",
// org.openide.filesystems.FileChangeListener
"fileFolderCreated", "(Lorg/openide/filesystems/FileEvent;)V",
"fileDataCreated", "(Lorg/openide/filesystems/FileEvent;)V",
"fileChanged", "(Lorg/openide/filesystems/FileEvent;)V",
"fileDeleted", "(Lorg/openide/filesystems/FileEvent;)V",
"fileRenamed", "(Lorg/openide/filesystems/FileRenameEvent;)V",
"fileAttributeChanged", "(Lorg/openide/filesystems/FileAttributeEvent;)V"
//org.netbeans.core.projects.FileStateManager$FileStatusListener
"fileStatusChanged", "(Lorg/openide/filesystems/FileObject;)V",
// org.openide.filesystems.FileStatusListener
"annotationChanged", "(Lorg/openide/filesystems/FileStatusEvent;)V",
// org.netbeans.core.windows.frames.FrameTypeListener
"frameDeactivated", "(Lorg/netbeans/core/windows/frames/FrameTypeEvent;)V",
"frameClosed", "(Lorg/netbeans/core/windows/frames/FrameTypeEvent;)V",
"frameDeiconified", "(Lorg/netbeans/core/windows/frames/FrameTypeEvent;)V",
"frameNormalized", "(Lorg/netbeans/core/windows/frames/FrameTypeEvent;)V",
"frameOpened", "(Lorg/netbeans/core/windows/frames/FrameTypeEvent;)V",
"frameIconified", "(Lorg/netbeans/core/windows/frames/FrameTypeEvent;)V",
"frameClosing", "(Lorg/netbeans/core/windows/frames/FrameTypeEvent;)V",
"frameActivated", "(Lorg/netbeans/core/windows/frames/FrameTypeEvent;)V",
"frameMaximized", "(Lorg/netbeans/core/windows/frames/FrameTypeEvent;)V",
// org.openide.util.LookupListener
"resultChanged", "(Lorg/openide/util/LookupEvent;)V",
// org.openide.nodes.NodeListener
"childrenAdded", "(Lorg/openide/nodes/NodeMemberEvent;)V",
"childrenRemoved", "(Lorg/openide/nodes/NodeMemberEvent;)V",
"childrenReordered", "(Lorg/openide/nodes/NodeReorderEvent;)V",
"nodeDestroyed", "(Lorg/openide/nodes/NodeEvent;)V",
// org.openide.loaders.OperationListener
"operationPostCreate", "(Lorg/openide/loaders/OperationEvent;)V",
"operationCopy", "(Lorg/openide/loaders/OperationEvent$Copy;)V",
"operationMove", "(Lorg/openide/loaders/OperationEvent$Move;)V",
"operationDelete", "(Lorg/openide/loaders/OperationEvent;)V",
"operationRename", "(Lorg/openide/loaders/OperationEvent$Rename;)V",
"operationCreateShadow", "(Lorg/openide/loaders/OperationEvent$Copy;)V",
"operationCreateFromTemplate", "(Lorg/openide/loaders/OperationEvent$Copy;)V",
// org.openide.filesystems.RepositoryListener
"fileSystemAdded", "(Lorg/openide/filesystems/RepositoryEvent;)V",
"fileSystemRemoved", "(Lorg/openide/filesystems/RepositoryEvent;)V",
"fileSystemPoolReordered", "(Lorg/openide/filesystems/RepositoryReorderedEvent;)V",
// org.openide.util.TaskListener
"taskFinished", "(Lorg/openide/util/Task;)V",
// org.netbeans.core.windows.TopComponentListener
"topComponentActivated", "(Lorg/netbeans/core/windows/TopComponentChangedEvent;)V",
"topComponentOpened", "(Lorg/netbeans/core/windows/TopComponentChangedEvent;)V",
"topComponentClosed", "(Lorg/netbeans/core/windows/TopComponentChangedEvent;)V",
"selectedNodesChanged", "(Lorg/netbeans/core/windows/SelectedNodesChangedEvent;)V",
// org.openide.util.datatransfer.TransferListener
"accepted", "(I)V",
"rejected", "(V)V"
"ownershipLost", "(V)V",
NULL };
typedef struct {
jmethodID method_id;
const char *class_name;
const char *method_name;
const char *method_sig;
int counter;
} mentry_t;
static mentry_t* allMethods[1024 * 16];
static int allMethodsLength = 0;
mentry_t* lookupMethodIDHelper(jmethodID mid, int start, int end) {
if (start >= end)
return NULL;
int pivot = (start + end) / 2;
if (mid == allMethods[pivot]->method_id)
return allMethods[pivot];
mentry_t* e = lookupMethodIDHelper(mid, start, pivot - 1);
if (e != NULL)
return e;
else
return lookupMethodIDHelper(mid, pivot + 1, end);
}
mentry_t* lookupMethodID(jmethodID mid) {
return lookupMethodIDHelper(mid, 0, allMethodsLength);
}
void storeNewMethodID(jmethodID mid, const char* classname, const char* mname, const char* msig) {
if (allMethodsLength >= (sizeof allMethods / sizeof allMethods[0])) {
fprintf(stderr, "jtrace> allMethods buffer exceeded\n");
exit(1);
}
mentry_t* e = new mentry_t;
e->method_id = mid;
e->class_name = strdup(classname);
e->method_name = strdup(mname);
e->method_sig = strdup(msig);
e->counter = 0;
int i = 0;
while (i < allMethodsLength && allMethods[i]->method_id < mid) {
i++;
}
int j = allMethodsLength;
while (j > i) {
allMethods[j] = allMethods[j-1];
j--;
}
allMethods[i] = e;
allMethodsLength++;
}
JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM *aJvm, char *options, void *reserved) {
fprintf(stderr, "jtrace> %s\n", "initializing .....");
jvm = aJvm;
if (jvm->GetEnv((void**)&env, JNI_VERSION_1_2)) {
fprintf(stderr, "jtrace> %s\n", "error in obtaining JNI interface pointer");
return JNI_ERR;
}
if ((jvm->GetEnv((void **)&jvmpi, JVMPI_VERSION_1)) < 0) {
fprintf(stderr, "jtrace> %s\n", "error in obtaining JVMPI interface pointer");
return JNI_ERR;
}
jvmpi->NotifyEvent = notifyEvent;
jvmpi->EnableEvent(JVMPI_EVENT_CLASS_LOAD, NULL);
jvmpi->EnableEvent(JVMPI_EVENT_METHOD_ENTRY2, NULL);
jvmpi->EnableEvent(JVMPI_EVENT_METHOD_EXIT, NULL);
fprintf(stderr, "jtrace> %s\n", ".... ok\n");
return JNI_OK;
}
void notifyEvent(JVMPI_Event *event) {
switch (event->event_type) {
case JVMPI_EVENT_CLASS_LOAD:
{
// fprintf(stderr, "jtrace> loaded %s\n", event->u.class_load.class_name);
for (int i = 0; i < event->u.class_load.num_methods; i++) {
JVMPI_Method *m = & event->u.class_load.methods[i];
// fprintf(stderr, "jtrace> %s%s\n", m->method_name, m->method_signature);
for (const char **p = traced_methods; *p != NULL; p += 2) {
if (0 == strcmp(m->method_name, *p) && 0 == strcmp(m->method_signature, *(p+1))) {
storeNewMethodID(m->method_id, event->u.class_load.class_name,
m->method_name, m->method_signature);
break;
}
}
}
}
break;
case JVMPI_EVENT_METHOD_ENTRY2:
{
jmethodID mid = event->u.method_entry2.method_id;
jobjectID obj = event->u.method_entry2.obj_id;
mentry_t* e = lookupMethodID(mid);
// if (e == NULL) {
// jobjectID classid = jvmpi->GetMethodClass(mid);
// jint res = jvmpi->RequestEvent(JVMPI_EVENT_CLASS_LOAD, classid);
// if (res != JVMPI_SUCCESS) {
// // warning
// }
// e = lookupMethodID(mid);
// }
if (e != NULL) {
fprintf(stderr, "jtrace> [%5d,%5d] <<< ENTERED %s.%s%s\n", (total++), (e->counter++), e->class_name, e->method_name, e->method_sig);
}
}
break;
case JVMPI_EVENT_METHOD_EXIT:
{
jmethodID mid = event->u.method.method_id;
mentry_t* e = lookupMethodID(mid);
if (e != NULL) {
fprintf(stderr, "jtrace> [%5d,%5d] >>> EXITED %s.%s%s\n", (total), (e->counter), e->class_name, e->method_name, e->method_sig);
}
}
break;
}
}