Skip to content

Commit

Permalink
more docs, support finding class instances
Browse files Browse the repository at this point in the history
  • Loading branch information
jbalint committed Sep 1, 2015
1 parent 656a934 commit a9dee5a
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 78 deletions.
41 changes: 41 additions & 0 deletions Lua_Java.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#+TITLE: Lua/Java

* Description

Lua/Java is the low-level library that interacts with the JVM and
exposes a Lua API.

* Notes
+ =GlobalRef(jobject)= indicates that we return a global reference
+ Most functions may return =nil=
+ All functions return "raw" (pointer) jobjects. They must be
wrapped by Lua OO wrappers

* Internal Utilities

** Environment References
+ =current_jni()= provides access to the appropriate JNI
environment via =AttachCurrentThread()=
+ =current_jvmti()= provides access to the JVM TI environment for
the agent.
+ =get_current_java_thread()= provides access to the =jthread=

** Others
+ =lj_check_jvmti_error()= provides an assertion-like interface to
check JVM TI return values.
+ =lj_print_message()= provides a printf-style interface to stdout.

* External API by Module

** LJ Class

| Function | Notes |
|---------------------------------------------------------+-------------------------------------------------|
| *=jobject lj_find_class(string class_name)=* | Uses =FindClass()= which is quite basi |
| *=[jfield_id] lj_get_class_fields(jobject class)=* | |
| *=[jmethod_id] lj_get_class_methods(jobject class)=* | |
| *=string lj_get_source_filename(jobject class)=* | |
| *=[sig => GlobalRef(jobject)] lj_get_loaded_classes()=* | sig is internal name, e.g. =Ljava/lang/String;= |

** LJ Field

72 changes: 1 addition & 71 deletions changes_before_failed_hd.diff
Original file line number Diff line number Diff line change
Expand Up @@ -213,28 +213,6 @@ diff --git a/lua_java.c b/lua_java.c
index 549b516..4ebabd9 100644
--- a/lua_java.c
+++ b/lua_java.c
@@ -60,6 +60,21 @@ void lj_check_jvmti_error(lua_State *L)
(void)lua_interface_error(L, "Error %d from JVMTI: %s", lj_err, errmsg);
}

+void lj_check_jvmti_error2(lua_State *L, jvmtiEnv *jvmti)
+{
+ char *errmsg = "<Unknown Error>";
+ if(lj_err == JVMTI_ERROR_NONE)
+ return;
+
+ (*jvmti)->GetErrorName(jvmti, lj_err, &errmsg);
+ /* we never Deallocate() the errmsg returned from JVMTI */
+
+ if (IsDebuggerPresent())
+ DebugBreak();
+
+ (void)lua_interface_error(L, "Error %d from JVMTI: %s", lj_err, errmsg);
+}
+
jobject get_current_java_thread()
{
JNIEnv *jni = current_jni();
@@ -751,7 +766,6 @@ static int lj_set_array_element(lua_State *L)
(*jni)->SetObjectArrayElement(jni, array, index, val.l);
EXCEPTION_CHECK(jni);
Expand All @@ -243,45 +221,6 @@ index 549b516..4ebabd9 100644
case 'Z':
luaL_checktype(L, val_num, LUA_TBOOLEAN);
val.z = lua_toboolean(L, val_num);
diff --git a/lua_java/lj_class.c b/lua_java/lj_class.c
index ab2ab86..c1254f2 100644
--- a/lua_java/lj_class.c
+++ b/lua_java/lj_class.c
@@ -111,10 +111,34 @@ static int lj_get_source_filename(lua_State *L)
return 1;
}

+static int lj_get_loaded_classes(lua_State *L)
+{
+ JNIEnv *jni = current_jni();
+ int i;
+ jint class_count;
+ jclass *classes;
+
+ lj_err = (*current_jvmti())->GetLoadedClasses(current_jvmti(), &class_count, &classes);
+ lj_check_jvmti_error(L);
+
+ lua_newtable(L);
+
+ for (i = 0; i < class_count; ++i)
+ {
+ new_jobject(L, (*jni)->NewGlobalRef(jni, classes[i]));
+ lua_rawseti(L, -2, i+1);
+ }
+
+ free_jvmti_refs(current_jvmti(), classes, (void *)-1);
+
+ return 1;
+}
+
void lj_class_register(lua_State *L)
{
lua_register(L, "lj_find_class", lj_find_class);
lua_register(L, "lj_get_class_fields", lj_get_class_fields);
lua_register(L, "lj_get_class_methods", lj_get_class_methods);
lua_register(L, "lj_get_source_filename", lj_get_source_filename);
+ lua_register(L, "lj_get_loaded_classes", lj_get_loaded_classes);
}
diff --git a/lua_java/lj_method.c b/lua_java/lj_method.c
index 6e505ec..6399434 100644
--- a/lua_java/lj_method.c
Expand Down Expand Up @@ -363,15 +302,6 @@ diff --git a/lua_jvmti_event.c b/lua_jvmti_event.c
index 89715f9..a5e3c2f 100644
--- a/lua_jvmti_event.c
+++ b/lua_jvmti_event.c
@@ -18,6 +18,8 @@ extern lua_State *lj_L;

void lj_check_jvmti_error(lua_State *L);

+void lj_check_jvmti_error2(lua_State *L, jvmtiEnv *jvmti);
+
extern jthread lj_current_thread;

/* function references for callback functions */
@@ -28,6 +30,7 @@ static struct {
int cb_single_step_ref;
int cb_exception_throw_ref;
Expand Down Expand Up @@ -405,7 +335,7 @@ index 89715f9..a5e3c2f 100644
+ //
+ lj_err = (*jvmti)->GetMethodName(jvmti, method_id, &method_name, &sig, NULL);
+ siglen = strlen(sig);
+ lj_check_jvmti_error2(L, jvmti);
+ lj_check_jvmti_error(L);
+ printf("Returning an object: %s %s\n", method_name, sig);
+ //new_string(L, jni, "abc");
+ //lua_pushstring(L, "abc");
Expand Down
3 changes: 2 additions & 1 deletion grimple-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
:group 'grimple)

(setq grimple-soot-jar
"/home/jbalint/sw/java-sw/soot-2.5.0.jar")
;; "/home/jbalint/sw/java-sw/soot-2.5.0.jar")
"/home/jbalint/sw/java-sw/soot-trunk-2015-04-19.jar")

(setq grimple-soot-classpath nil)
;;'("/home/jbalint/sw/stardog-2.1.3/expand"))
Expand Down
11 changes: 11 additions & 0 deletions java_bridge/jclass.lua
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,17 @@ function jclass:find_field(search_name)
return nil
end

-- ============================================================
-- Find all instances of the current class
function jclass:find_instances()
local instances = lj_get_class_instances(self.object_raw)
-- transform the raw instances to jobject instances
for i = 1, #instances do
instances[i] = jobject.create(instances[i])
end
return instances
end

-- bootstrap the lowest-level class
jclass.java_lang_Class_instance = {}
jclass.java_lang_Class_instance.object_raw = lj_new_global_ref(lj_find_class("java/lang/Class"))
Expand Down
5 changes: 3 additions & 2 deletions lua_java.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ jvmtiEnv *current_jvmti()
return lj_jvmti;
}

void lj_check_jvmti_error(lua_State *L)
/* TODO: should wrap this in a macro to better report error location */
void lj_check_jvmti_error_internal(lua_State *L, const char *file, int line, const char *func)
{
char *errmsg = "<Unknown Error>";
if(lj_err == JVMTI_ERROR_NONE)
Expand All @@ -54,7 +55,7 @@ void lj_check_jvmti_error(lua_State *L)
if (IsDebuggerPresent())
DebugBreak();

(void)lua_interface_error(L, "Error %d from JVMTI: %s", lj_err, errmsg);
(void) lua_interface_error(L, "[%s:%d:%s] Error %d from JVMTI: %s", file, line, func, lj_err, errmsg);
}

jobject get_current_java_thread()
Expand Down
59 changes: 59 additions & 0 deletions lua_java/lj_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "java_bridge.h"
#include "lj_internal.h"

#include <string.h>

/* Lua wrappers for class operations */

static int lj_find_class(lua_State *L)
Expand Down Expand Up @@ -133,6 +135,7 @@ static int lj_get_loaded_classes(lua_State *L)
lj_check_jvmti_error(L);
lua_pushstring(L, class_sig);
new_jobject(L, (*jni)->NewGlobalRef(jni, classes[i]));
EXCEPTION_CHECK(jni);
/* newtable[class_sig] = classes[i] */
lua_rawset(L, -3);
free_jvmti_refs(current_jvmti(), class_sig, (void *) -1);
Expand All @@ -144,11 +147,67 @@ static int lj_get_loaded_classes(lua_State *L)
return 1;
}

/* This value is used to tag all objects visited. It is then
incremented for the next iteration. We need to tag all items and
then retrieve them. There is no reason/method to clear all tags so
we increment the number so it's different next time. It's
*possible* that if you used this method a (max jlong) times that
there may be objects leftover with an old tag.
*/
static jlong class_instances_search_tag = 1000;

static jint heap_iter_tag_item(jlong class_tag, jlong size, jlong* tag_ptr, jint length, void* user_data) {
*tag_ptr = class_instances_search_tag;
return 0;
}

static int lj_get_class_instances(lua_State *L) {
jclass class;
jvmtiHeapCallbacks callbacks;
JNIEnv *jni = current_jni();
jobject *obj_output;
jlong *tag_output;
jint output_count;
int i;

class = *(jclass *)luaL_checkudata(L, 1, "jobject");
lua_pop(L, 1);

/* get a new tag for this search */
class_instances_search_tag++;

memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
callbacks.heap_iteration_callback = &heap_iter_tag_item;

lj_err = (*current_jvmti())->IterateThroughHeap(current_jvmti(), 0, class, &callbacks, L);
lj_check_jvmti_error(L);

/* get all tagged objects */
lj_err = (*current_jvmti())->GetObjectsWithTags(current_jvmti(), 1, &class_instances_search_tag, &output_count, &obj_output, &tag_output);
lj_check_jvmti_error(L);

fprintf(stderr, "output_count=%d\n", output_count);

/* add it to the result */
lua_createtable(L, output_count, 0);
for (i = 0; i < output_count; ++i) {
new_jobject(L, (*jni)->NewGlobalRef(jni, obj_output[i]));
EXCEPTION_CHECK(jni);
lua_rawseti(L, -2, i + 1);
}

if (obj_output)
free_jvmti_refs(current_jvmti(), obj_output, tag_output, (void *)-1);

return 1;
}

void lj_class_register(lua_State *L)
{
lua_register(L, "lj_find_class", lj_find_class);
lua_register(L, "lj_get_class_fields", lj_get_class_fields);
lua_register(L, "lj_get_class_methods", lj_get_class_methods);
lua_register(L, "lj_get_source_filename", lj_get_source_filename);
lua_register(L, "lj_get_loaded_classes", lj_get_loaded_classes);
lua_register(L, "lj_get_class_instances", lj_get_class_instances);
}
3 changes: 2 additions & 1 deletion lua_java/lj_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ jobject get_current_java_thread();
jvmtiEnv *current_jvmti();
JNIEnv *current_jni();

void lj_check_jvmti_error(lua_State *L);
void lj_check_jvmti_error_internal(lua_State *, const char *, int, const char *);
#define lj_check_jvmti_error(L) lj_check_jvmti_error_internal(L, __FILE__, __LINE__, __FUNCTION__)

extern jvmtiError lj_err;

Expand Down
2 changes: 0 additions & 2 deletions lua_jvmti_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
/* from lua_java.c */
extern lua_State *lj_L;

void lj_check_jvmti_error(lua_State *L);

extern jthread lj_current_thread;

/* function references for callback functions */
Expand Down
2 changes: 1 addition & 1 deletion yt.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
caps.can_generate_method_entry_events = 1;
caps.can_generate_method_exit_events = 1;
caps.can_generate_exception_events = 1;
/* caps.can_tag_objects = 1; */
caps.can_tag_objects = 1;
caps.can_get_source_file_name = 1;
caps.can_get_line_numbers = 1;
caps.can_access_local_variables = 1;
Expand Down

0 comments on commit a9dee5a

Please sign in to comment.