Skip to content

Commit

Permalink
moved stuff into jni_util
Browse files Browse the repository at this point in the history
implemented breakpoints in lua
add debuglib.lua
  • Loading branch information
jbalint committed Feb 18, 2013
1 parent ee12d0d commit 8216b23
Show file tree
Hide file tree
Showing 10 changed files with 453 additions and 368 deletions.
4 changes: 2 additions & 2 deletions Makefile.win32
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ LDFLAGS += /LIBPATH:"%LUA_HOME%"\lib
.c.obj:
$(CC) $(CFLAGS) /c $<

yt.dll: yt.obj list.obj lua_interface.obj lua_java.obj
yt.dll: yt.obj list.obj lua_interface.obj lua_java.obj jni_util.obj
link /DLL /DEBUG /OUT:yt.dll /INCREMENTAL:NO $(LDFLAGS) $^ lua52.lib

clean:
-rm yt.obj list.obj lua_interface.obj yt.dll
-rm yt.obj list.obj lua_interface.obj lua_java.obj jni_util.obj yt.dll
96 changes: 96 additions & 0 deletions debuglib.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
-- debuglib.lua
-- Commands implementing the debugger
-- Loaded automatically at debugger start

-- current stack depth
depth = 0

-- breakpoint list
breakpoints = {}

function test()
print("Testing function")
end

function where()
local frame_count = lj_get_frame_count()
for i = 0, frame_count - 1 do
f = lj_get_stack_frame(i)
dump(f)
end
end

-- takes a method declaration and an optional line number
function bp(method_decl, line_num)
local b = {}
b.method_decl = method_decl
b.line_num = line_num

-- make sure bp doesn't already exist
for idx, bp in ipairs(breakpoints) do
if bp.method_decl == b.method_decl and bp.line_num == b.line_num then
print("Breakpoint already exists")
return
end
end

b.method = method_decl_parse(method_decl)
lj_set_breakpoint(b.method, b.line_num)
table.insert(breakpoints, b)
print("ok")
end

-- List breakpoints
function bl()
for idx, bp in ipairs(breakpoints) do
local disp = string.format("%4d: %s", idx, bp.method_decl)
if (bp.line_num) then
disp = disp .. " (line " .. bp.line_num .. ")"
end
print(disp)
end
end

-- Clear breakpoints
function bc()
-- TODO
end

-- Parse a method declaration of the form
-- java/io/PrintStream.println(Ljava/lang/String;)V
function method_decl_parse(method_decl)
local chars = 0
local md = {}

md.class = string.match(method_decl, "^.*%.") -- up until .
chars = string.len(md.class)
md.class = string.sub(md.class, 0, string.len(md.class) - 1) -- remove .

md.method = string.match(method_decl, "^.*%(", chars + 1) -- up until (
chars = chars + string.len(md.method)
md.method = string.sub(md.method, 0, string.len(md.method) - 1) -- remove (

md.args = string.match(method_decl, "^.*%)", chars + 1) -- up until )
chars = chars + string.len(md.args)
md.args = string.sub(md.args, 0, string.len(md.args) - 1) -- remove )

md.ret = string.sub(method_decl, chars + 1) -- rest

return md
end

-- http://snippets.luacode.org/?p=snippets/Simple_Table_Dump_7
function dump(o)
if type(o) == 'table' then
local s = '{ '
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"'..k..'"' end
s = s .. '['..k..'] = ' .. dump(v) .. ','
end
return s .. '} '
else
return tostring(o)
end
end

print("debuglib.lua - loaded with " .. _VERSION)
146 changes: 146 additions & 0 deletions jni_util.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#include "jni_util.h"

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

/*
* Free a set of JVMTI references. Pass (void *)-1 as the last parameter.
* Be *sure* to cast the last argument to a pointer.
*/
jvmtiError free_jvmti_refs(jvmtiEnv *jvmti, ...)
{
jvmtiError jerr = JVMTI_ERROR_NONE;
va_list s;
unsigned char *p;
va_start(s, jvmti);
while((p = va_arg(s, unsigned char *)) != (unsigned char *)-1)
{
if(!p)
continue;
jerr = (*jvmti)->Deallocate(jvmti, p);
/* if(check_jvmti_error(Gagent.jvmti, Gagent.jerr) != JVMTI_ERROR_NONE) */
/* jerr = Gagent.jerr; */
}
va_end(s);
return jerr;
}

/*
* XXX
* desc1 - from app, can have M;
* desc2 - from jvm, cannot have M;
* TODO not tested with inner classes from the JVM
*/
static int
method_desc_compare(char *desc1, char *desc2)
{
int cllen; /* class name length */
char *end;
char *end2;
while(*desc1 && *desc2)
{
if(*desc1 == 'L')
{
if(*desc2 != 'L')
return 1;
end = strchr(desc1, ';');
if(!end) /* something is corrupt */
return 1;
cllen = end - desc1;
if(strncmp(desc1, desc2, cllen+1))
return 1;
desc1 += cllen + 1;
desc2 += cllen + 1;
}
else if(*desc1 == 'M')
{
if(*desc2 != 'L')
return 1;
end = strchr(desc1, ';');
end2 = strchr(desc2, ';');
cllen = (end - ++desc1);
desc2 += (end2 - desc2) - cllen;
if(strncmp(desc1, desc2, cllen + 1) || *(desc2 - 1) != '/')
return 1;
desc1 = end + 1;
desc2 = end2 + 1;
}
else if(*desc1 != *desc2)
return 1;
desc1++;
desc2++;
}
if(*desc1 || *desc2)
return 1;
return 0;
}

/*
* Lookup a method declaration. Instance method is searched first and
* class method is tried second.
*/
jmethodID method_decl_lookup(jvmtiEnv *jvmti, JNIEnv *jni,
const char *class_name, const char *method_name,
const char *args, const char *ret)
{
/* int i; */
/* jint method_count; */
/* char *mname; */
/* char *msig; */

jvmtiError jerr;
jclass class;
jmethodID method_id;
char *sig;

/* get class */
class = (*jni)->FindClass(jni, class_name);
EXCEPTION_CLEAR(jni);
if(class == NULL)
return NULL;

/* build signature string */
sig = malloc(strlen(args) + strlen(ret) + 10);
sprintf(sig, "(%s)%s", args, ret);

/* try instance method */
method_id = (*jni)->GetMethodID(jni, class, method_name, sig);
EXCEPTION_CLEAR(jni);

/* otherwise try static method */
if(method_id == NULL)
method_id = (*jni)->GetStaticMethodID(jni, class, method_name, sig);
EXCEPTION_CLEAR(jni);
free(sig);

return method_id;
}

/*
* Find the byte code index of a line number in a given method.
*/
jint method_find_line_bytecode_index(jvmtiEnv *jvmti, jmethodID method_id, jint line_num)
{
jint linescount;
jint bytecode_index = 0;
int i;
jvmtiLineNumberEntry *lines;
jvmtiError jerr;
jerr = (*jvmti)->GetLineNumberTable(jvmti, method_id, &linescount, &lines);
/* TODO don't check jvmti error for native methods, and not debug methods */
/* TODO check error */
/* if(check_jvmti_error(jvmti, jerr) != JVMTI_ERROR_NONE) */
/* return 0; */
for(i = 0; i < linescount; ++i)
{
if(lines[i].line_number == line_num)
{
bytecode_index = lines[i].start_location;
break;
}
}
(*jvmti)->Deallocate(jvmti, (unsigned char *)lines);
return bytecode_index;
}
43 changes: 43 additions & 0 deletions jni_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Java utilities for JNI and JVMTI APIs.
*/
#ifndef JNI_UTIL_H_
#define JNI_UTIL_H_

#include <jni.h>
#include <jvmti.h>

typedef struct {
char *cls;
char *func;
char *sig;
jclass jcls;
jmethodID mid;
} method_decl;

jvmtiError free_jvmti_refs(jvmtiEnv *jvmti, ...);
jmethodID method_decl_lookup(jvmtiEnv *jvmti, JNIEnv *jni,
const char *class_name, const char *method_name,
const char *args, const char *ret);
jint method_find_line_bci(jvmtiEnv *jvmti, method_decl *method, jint linenum);

/* utility macros to check and clear exceptions on JNI env */
#define EXCEPTION_CLEAR(JNI) \
do { \
if((*(JNI))->ExceptionCheck(JNI)) { \
(*(JNI))->ExceptionClear(JNI); \
} \
} while(0)

#define EXCEPTION_CHECK(JNI) \
do { \
if ((*(JNI))->ExceptionCheck(JNI)) { \
if(IsDebuggerPresent()) \
DebugBreak(); \
fprintf(stderr, "EXCEPTION EXISTS at %s:%d\n", __FILE__, __LINE__); \
(*(JNI))->ExceptionDescribe(JNI); \
(*(JNI))->ExceptionClear(JNI); \
} \
} while(0)

#endif /* JNI_UTIL_H_ */
30 changes: 16 additions & 14 deletions lua_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,39 @@

static lua_State *lua_state;

void lua_interface_init(jvmtiEnv *jvmti) {
void lua_interface_init(jvmtiEnv *jvmti)
{
lua_state = luaL_newstate();
if (lua_state == NULL) {
if (lua_state == NULL)
{
fprintf(stderr, "Failed to initialize Lua");
abort();
}
luaL_openlibs(lua_state);
lj_init(lua_state, jvmti);
if (luaL_dofile(lua_state, "debuglib.lua"))
{
fprintf(stderr, "Failed to load debuglib.lua: %s\n", lua_tostring(lua_state, -1));
abort();
}
}

void lua_command_loop() {
void lua_command_loop(JNIEnv *jni)
{
char cmd[255];
size_t len;

printf("Starting lua command loop\n");
lj_set_jni(jni);

printf("yt> ");
while(fgets(cmd, 255, stdin))
{
len = strlen(cmd) - 1;
cmd[len] = 0;
if(!strcmp(cmd, "run") || !strcmp(cmd, "cont"))
break;
else if(!strcmp(cmd, "where"))
/*dump_stack(-1, 0);*/
printf("dump stack\n");
else
{
if (luaL_dostring(lua_state, cmd)) {
printf("%s\n", lua_tostring(lua_state, -1));
}
if (!strcmp(cmd, "g"))
return;
if (luaL_dostring(lua_state, cmd)) {
printf("%s\n", lua_tostring(lua_state, -1));
}
printf("yt> ");
}
Expand Down
2 changes: 1 addition & 1 deletion lua_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
#include <jvmti.h>

void lua_interface_init(jvmtiEnv *jvmti);
void lua_command_loop();
void lua_command_loop(JNIEnv *jni);

#endif /* LUA_INTERFACE_H_ */
Loading

0 comments on commit 8216b23

Please sign in to comment.