-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implemented breakpoints in lua add debuglib.lua
- Loading branch information
Showing
10 changed files
with
453 additions
and
368 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.