issue #82 support additional launch parameters, plus disable sethook if running under debugger

pull/85/head
Dibyendu Majumdar 8 years ago
parent 33ad11d2e1
commit 7ec2065a66

@ -3,6 +3,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* Parse a VSCode JSON message type
*/
@ -115,41 +116,44 @@ static json_value *get_object_value(json_value *js, const char *key,
}
/*
* Escape certain control characters to match JSON string
* Escape certain control characters to match JSON string
* requirements. 'src' should be 0 terminated, 'len' is the
* size of 'dest' buffer. If the 'dest' buffer is smaller than
* size of 'dest' buffer. If the 'dest' buffer is smaller than
* required then the string will be silently truncated
*/
void vscode_json_stringify(const char *src, char *dest, size_t len) {
char *p = dest;
char *end = dest + len - 1;
for (int i = 0; i < (int)strlen(src) && p < end; i++) {
int n = (int) strlen(src);
for (int i = 0; i < n && p < end; i++) {
char ch = 0;
switch (src[i]) {
case '"': ch = '"'; goto l_escape;
case '\\': ch = '\\'; goto l_escape;
case '\b': ch = 'b'; goto l_escape;
case '\f': ch = 'f'; goto l_escape;
case '\n': ch = 'n'; goto l_escape;
case '\r': ch = 'r'; goto l_escape;
case '\t': {
ch = 't';
l_escape:
if (p + 2 > end)
goto l_done;
*p++ = '\\';
*p++ = ch;
} break;
default:
*p++ = src[i];
case '"': ch = '"'; goto l_escape;
case '\\': ch = '\\'; goto l_escape;
case '\b': ch = 'b'; goto l_escape;
case '\f': ch = 'f'; goto l_escape;
case '\n': ch = 'n'; goto l_escape;
case '\r': ch = 'r'; goto l_escape;
case '\t': {
ch = 't';
l_escape:
if (p + 2 > end) goto l_done;
*p++ = '\\';
*p++ = ch;
} break;
default: {
if (isprint(src[i]))
*p++ = src[i];
else
goto l_done;
}
}
}
l_done:
*p = 0;
}
static json_value *get_array_value(json_value *js, const char *key,
FILE *log) {
static json_value *get_array_value(json_value *js, const char *key, FILE *log) {
(void)log;
if (js->type != json_object) { return NULL; }
for (int i = 0; i < js->u.object.length; i++) {
@ -220,8 +224,8 @@ static int vscode_parse_initialize_request(json_value *js, ProtocolMessage *msg,
adapterID != NULL ? adapterID : "null");
return VSCODE_UNKNOWN_REQUEST;
}
strncpy(msg->u.Request.u.InitializeRequest.adapterID, adapterID,
sizeof msg->u.Request.u.InitializeRequest.adapterID);
ravi_string_copy(msg->u.Request.u.InitializeRequest.adapterID, adapterID,
sizeof msg->u.Request.u.InitializeRequest.adapterID);
const char *pathFormat = get_string_value(args, "pathFormat", log);
if (pathFormat != NULL && strcmp(pathFormat, "path") != 0) {
fprintf(log, "Unsupported pathFormat '%s' in initialize command\n",
@ -229,8 +233,8 @@ static int vscode_parse_initialize_request(json_value *js, ProtocolMessage *msg,
return VSCODE_UNKNOWN_REQUEST;
}
if (pathFormat)
strncpy(msg->u.Request.u.InitializeRequest.pathFormat, pathFormat,
sizeof msg->u.Request.u.InitializeRequest.pathFormat);
ravi_string_copy(msg->u.Request.u.InitializeRequest.pathFormat, pathFormat,
sizeof msg->u.Request.u.InitializeRequest.pathFormat);
int found = 0;
msg->u.Request.u.InitializeRequest.columnsStartAt1 =
get_boolean_value(args, "columnsStartAt1", log, &found);
@ -267,8 +271,8 @@ static int vscode_parse_launch_request(json_value *js, ProtocolMessage *msg,
get_boolean_value(args, "stopOnEntry", log, &found);
const char *prog = get_string_value(args, "program", log);
if (prog == NULL) return VSCODE_UNKNOWN_REQUEST;
strncpy(msg->u.Request.u.LaunchRequest.program, prog,
sizeof msg->u.Request.u.LaunchRequest.program);
ravi_string_copy(msg->u.Request.u.LaunchRequest.program, prog,
sizeof msg->u.Request.u.LaunchRequest.program);
for (char *cp = msg->u.Request.u.LaunchRequest.program; *cp; cp++) {
/* replace back slashes with front slash as the VSCode front end doesn't
* like
@ -277,12 +281,22 @@ static int vscode_parse_launch_request(json_value *js, ProtocolMessage *msg,
if (*cp == '\\') *cp = '/';
}
fprintf(log, "LAUNCH %s\n", prog);
const char *lua_path = get_string_value(args, "LUA_PATH", log);
if (lua_path != NULL) ravi_string_copy(msg->u.Request.u.LaunchRequest.lua_path, lua_path,
sizeof msg->u.Request.u.LaunchRequest.lua_path);
const char *lua_cpath = get_string_value(args, "LUA_CPATH", log);
if (lua_cpath != NULL) ravi_string_copy(msg->u.Request.u.LaunchRequest.lua_cpath, lua_cpath,
sizeof msg->u.Request.u.LaunchRequest.lua_cpath);
const char *cwd = get_string_value(args, "cwd", log);
if (cwd != NULL) ravi_string_copy(msg->u.Request.u.LaunchRequest.cwd, cwd,
sizeof msg->u.Request.u.LaunchRequest.cwd);
msg->u.Request.request_type = msgtype;
return msgtype;
}
static int vscode_parse_set_breakpoints_request(json_value *js, ProtocolMessage *msg,
int msgtype, FILE *log) {
static int vscode_parse_set_breakpoints_request(json_value *js,
ProtocolMessage *msg,
int msgtype, FILE *log) {
int found = 0;
json_value *args = get_object_value(js, "arguments", log);
if (args == NULL) return VSCODE_UNKNOWN_REQUEST;
@ -290,22 +304,22 @@ static int vscode_parse_set_breakpoints_request(json_value *js, ProtocolMessage
if (source == NULL) return VSCODE_UNKNOWN_REQUEST;
const char *prog = get_string_value(source, "path", log);
if (prog == NULL) return VSCODE_UNKNOWN_REQUEST;
strncpy(msg->u.Request.u.SetBreakpointsRequest.source.path, prog,
sizeof msg->u.Request.u.SetBreakpointsRequest.source.path);
for (char *cp = msg->u.Request.u.SetBreakpointsRequest.source.path; *cp; cp++) {
if (*cp == '\\')
*cp = '/';
ravi_string_copy(msg->u.Request.u.SetBreakpointsRequest.source.path, prog,
sizeof msg->u.Request.u.SetBreakpointsRequest.source.path);
for (char *cp = msg->u.Request.u.SetBreakpointsRequest.source.path; *cp;
cp++) {
if (*cp == '\\') *cp = '/';
}
json_value *breakpoints = get_array_value(args, "breakpoints", log);
if (breakpoints == NULL || breakpoints->type != json_array)
return VSCODE_UNKNOWN_REQUEST;
for (int i = 0; i < breakpoints->u.array.length && i < MAX_BREAKPOINTS; i++) {
json_value *element = breakpoints->u.array.values[i];
if (element->type != json_object)
return VSCODE_UNKNOWN_REQUEST;
if (element->type != json_object) return VSCODE_UNKNOWN_REQUEST;
int line = get_int_value(element, "line", log, &found);
fprintf(log, "Set breakpoint line = %d\n", line);
msg->u.Request.u.SetBreakpointsRequest.breakpoints[i].line = found ? line: -1;
msg->u.Request.u.SetBreakpointsRequest.breakpoints[i].line =
found ? line : -1;
}
msg->u.Request.request_type = msgtype;
return msgtype;
@ -335,7 +349,7 @@ static int vscode_parse_request(json_value *js, ProtocolMessage *msg,
if (cmd == NULL) return VSCODE_UNKNOWN_REQUEST;
msg->type = VSCODE_REQUEST;
msg->seq = get_int_value(js, "seq", log, &found);
strncpy(msg->u.Request.command, cmd, sizeof msg->u.Request.command);
ravi_string_copy(msg->u.Request.command, cmd, sizeof msg->u.Request.command);
fprintf(log, "\nRequest --> '%s'\n", cmd);
int cmdtype = get_cmdtype(msg->u.Request.command);
switch (cmdtype) {
@ -358,7 +372,7 @@ static int vscode_parse_request(json_value *js, ProtocolMessage *msg,
log);
case VSCODE_SOURCE_REQUEST:
return vscode_parse_intarg_request(js, msg, cmdtype, "sourceReference",
log);
log);
case VSCODE_LAUNCH_REQUEST:
return vscode_parse_launch_request(js, msg, cmdtype, log);
case VSCODE_STACK_TRACE_REQUEST:
@ -393,11 +407,12 @@ void vscode_make_error_response(ProtocolMessage *req, ProtocolMessage *res,
memset(res, 0, sizeof(ProtocolMessage));
res->seq = seq++;
res->type = VSCODE_RESPONSE;
strncpy(res->u.Response.command, req->u.Request.command,
sizeof res->u.Response.command);
ravi_string_copy(res->u.Response.command, req->u.Request.command,
sizeof res->u.Response.command);
res->u.Response.request_seq = req->seq;
res->u.Response.response_type = restype;
strncpy(res->u.Response.message, errormsg, sizeof res->u.Response.message);
ravi_string_copy(res->u.Response.message, errormsg,
sizeof res->u.Response.message);
res->u.Response.success = 0;
}
@ -406,8 +421,8 @@ void vscode_make_success_response(ProtocolMessage *req, ProtocolMessage *res,
memset(res, 0, sizeof(ProtocolMessage));
res->seq = seq++;
res->type = VSCODE_RESPONSE;
strncpy(res->u.Response.command, req->u.Request.command,
sizeof res->u.Response.command);
ravi_string_copy(res->u.Response.command, req->u.Request.command,
sizeof res->u.Response.command);
res->u.Response.request_seq = req->seq;
res->u.Response.response_type = restype;
res->u.Response.success = 1;
@ -417,17 +432,21 @@ void vscode_make_initialized_event(ProtocolMessage *res) {
memset(res, 0, sizeof(ProtocolMessage));
res->seq = seq++;
res->type = VSCODE_EVENT;
strncpy(res->u.Event.event, "initialized", sizeof res->u.Event.event);
ravi_string_copy(res->u.Event.event, "initialized",
sizeof res->u.Event.event);
res->u.Event.event_type = VSCODE_INITIALIZED_EVENT;
}
static void vscode_make_output_event(ProtocolMessage *res, const char *category, const char *msg) {
static void vscode_make_output_event(ProtocolMessage *res, const char *category,
const char *msg) {
memset(res, 0, sizeof(ProtocolMessage));
res->seq = seq++;
res->type = VSCODE_EVENT;
strncpy(res->u.Event.event, "output", sizeof res->u.Event.event);
strncpy(res->u.Event.u.OutputEvent.category, category, sizeof res->u.Event.u.OutputEvent.category);
vscode_json_stringify(msg, res->u.Event.u.OutputEvent.output, sizeof res->u.Event.u.OutputEvent.output);
ravi_string_copy(res->u.Event.event, "output", sizeof res->u.Event.event);
ravi_string_copy(res->u.Event.u.OutputEvent.category, category,
sizeof res->u.Event.u.OutputEvent.category);
vscode_json_stringify(msg, res->u.Event.u.OutputEvent.output,
sizeof res->u.Event.u.OutputEvent.output);
res->u.Event.event_type = VSCODE_OUTPUT_EVENT;
}
@ -439,10 +458,10 @@ void vscode_make_stopped_event(ProtocolMessage *res, const char *reason) {
res->seq = seq++;
res->type = VSCODE_EVENT;
res->u.Event.event_type = VSCODE_STOPPED_EVENT;
strncpy(res->u.Event.event, "stopped", sizeof res->u.Event.event);
ravi_string_copy(res->u.Event.event, "stopped", sizeof res->u.Event.event);
res->u.Event.u.StoppedEvent.threadId = 1; /* dummy thread id - always 1 */
strncpy(res->u.Event.u.StoppedEvent.reason, reason,
sizeof res->u.Event.u.StoppedEvent.reason);
ravi_string_copy(res->u.Event.u.StoppedEvent.reason, reason,
sizeof res->u.Event.u.StoppedEvent.reason);
}
/*
@ -453,7 +472,7 @@ void vscode_make_terminated_event(ProtocolMessage *res) {
res->seq = seq++;
res->type = VSCODE_EVENT;
res->u.Event.event_type = VSCODE_TERMINATED_EVENT;
strncpy(res->u.Event.event, "terminated", sizeof res->u.Event.event);
ravi_string_copy(res->u.Event.event, "terminated", sizeof res->u.Event.event);
res->u.Event.u.TerminatedEvent.restart = 0;
}
@ -465,10 +484,11 @@ void vscode_make_thread_event(ProtocolMessage *res, bool started) {
res->seq = seq++;
res->type = VSCODE_EVENT;
res->u.Event.event_type = VSCODE_THREAD_EVENT;
strncpy(res->u.Event.event, "thread", sizeof res->u.Event.event);
ravi_string_copy(res->u.Event.event, "thread", sizeof res->u.Event.event);
res->u.Event.u.ThreadEvent.threadId = 1; /* dummy thread id - always 1 */
strncpy(res->u.Event.u.ThreadEvent.reason, started ? "started" : "exited",
sizeof res->u.Event.u.ThreadEvent.reason);
ravi_string_copy(res->u.Event.u.ThreadEvent.reason,
started ? "started" : "exited",
sizeof res->u.Event.u.ThreadEvent.reason);
}
void vscode_serialize_response(char *buf, size_t buflen, ProtocolMessage *res) {
@ -529,24 +549,28 @@ void vscode_serialize_response(char *buf, size_t buflen, ProtocolMessage *res) {
snprintf(cp, sizeof temp - strlen(temp), ",");
cp = temp + strlen(temp);
}
if (res->u.Response.u.StackTraceResponse.stackFrames[d].source.sourceReference == 0) {
snprintf(cp, sizeof temp - strlen(temp),
"{\"id\":%d,\"name\":\"%s\",\"column\":1,\"line\":%d,\"source\":"
"{\"name\":\"%s\",\"path\":\"%s\",\"sourceReference\":0}}",
d, res->u.Response.u.StackTraceResponse.stackFrames[d].name,
res->u.Response.u.StackTraceResponse.stackFrames[d].line,
res->u.Response.u.StackTraceResponse.stackFrames[d].source.name,
res->u.Response.u.StackTraceResponse.stackFrames[d].source.path);
if (res->u.Response.u.StackTraceResponse.stackFrames[d]
.source.sourceReference == 0) {
snprintf(
cp, sizeof temp - strlen(temp),
"{\"id\":%d,\"name\":\"%s\",\"column\":1,\"line\":%d,\"source\":"
"{\"name\":\"%s\",\"path\":\"%s\",\"sourceReference\":0}}",
d, res->u.Response.u.StackTraceResponse.stackFrames[d].name,
res->u.Response.u.StackTraceResponse.stackFrames[d].line,
res->u.Response.u.StackTraceResponse.stackFrames[d].source.name,
res->u.Response.u.StackTraceResponse.stackFrames[d].source.path);
cp = temp + strlen(temp);
}
else {
snprintf(cp, sizeof temp - strlen(temp),
"{\"id\":%d,\"name\":\"%s\",\"column\":1,\"line\":%d,\"source\":"
"{\"name\":\"%s\",\"sourceReference\":%d}}",
d, res->u.Response.u.StackTraceResponse.stackFrames[d].name,
res->u.Response.u.StackTraceResponse.stackFrames[d].line,
res->u.Response.u.StackTraceResponse.stackFrames[d].source.name,
res->u.Response.u.StackTraceResponse.stackFrames[d].source.sourceReference);
snprintf(
cp, sizeof temp - strlen(temp),
"{\"id\":%d,\"name\":\"%s\",\"column\":1,\"line\":%d,\"source\":"
"{\"name\":\"%s\",\"sourceReference\":%d}}",
d, res->u.Response.u.StackTraceResponse.stackFrames[d].name,
res->u.Response.u.StackTraceResponse.stackFrames[d].line,
res->u.Response.u.StackTraceResponse.stackFrames[d].source.name,
res->u.Response.u.StackTraceResponse.stackFrames[d]
.source.sourceReference);
cp = temp + strlen(temp);
}
}
@ -584,41 +608,49 @@ void vscode_serialize_response(char *buf, size_t buflen, ProtocolMessage *res) {
snprintf(cp, sizeof temp - strlen(temp), ",");
cp = temp + strlen(temp);
}
snprintf(cp, sizeof temp - strlen(temp),
"{\"name\":\"%s\",\"variablesReference\":%d,\"value\":\"%s\"}",
res->u.Response.u.VariablesResponse.variables[d].name,
res->u.Response.u.VariablesResponse.variables[d].variablesReference,
res->u.Response.u.VariablesResponse.variables[d].value);
snprintf(
cp, sizeof temp - strlen(temp),
"{\"name\":\"%s\",\"variablesReference\":%d,\"value\":\"%s\"}",
res->u.Response.u.VariablesResponse.variables[d].name,
res->u.Response.u.VariablesResponse.variables[d].variablesReference,
res->u.Response.u.VariablesResponse.variables[d].value);
cp = temp + strlen(temp);
}
snprintf(cp, sizeof temp - strlen(temp), "]}");
cp = temp + strlen(temp);
}
else if (res->u.Response.response_type == VSCODE_SET_BREAKPOINTS_RESPONSE &&
res->u.Response.success) {
res->u.Response.success) {
snprintf(cp, sizeof temp - strlen(temp), ",\"body\":{\"breakpoints\":[");
cp = temp + strlen(temp);
for (int d = 0; d < MAX_BREAKPOINTS; d++) {
if (!res->u.Response.u.SetBreakpointsResponse.breakpoints[d].source.path[0]) break;
if (!res->u.Response.u.SetBreakpointsResponse.breakpoints[d]
.source.path[0])
break;
if (d) {
snprintf(cp, sizeof temp - strlen(temp), ",");
cp = temp + strlen(temp);
}
snprintf(cp, sizeof temp - strlen(temp),
"{\"verified\":%s,\"source\":{\"path\":\"%s\"},\"line\":%d}",
res->u.Response.u.SetBreakpointsResponse.breakpoints[d].verified ? "true" : "false",
res->u.Response.u.SetBreakpointsResponse.breakpoints[d].source.path,
res->u.Response.u.SetBreakpointsResponse.breakpoints[d].line);
snprintf(
cp, sizeof temp - strlen(temp),
"{\"verified\":%s,\"source\":{\"path\":\"%s\"},\"line\":%d}",
res->u.Response.u.SetBreakpointsResponse.breakpoints[d].verified
? "true"
: "false",
res->u.Response.u.SetBreakpointsResponse.breakpoints[d].source.path,
res->u.Response.u.SetBreakpointsResponse.breakpoints[d].line);
cp = temp + strlen(temp);
}
snprintf(cp, sizeof temp - strlen(temp), "]}");
cp = temp + strlen(temp);
}
else if (res->u.Response.response_type == VSCODE_SOURCE_RESPONSE &&
res->u.Response.success) {
res->u.Response.success) {
char buf[SOURCE_LEN * 2];
vscode_json_stringify(res->u.Response.u.SourceResponse.content, buf, sizeof buf);
snprintf(cp, sizeof temp - strlen(temp), ",\"body\":{\"content\":\"%s\"}", buf);
vscode_json_stringify(res->u.Response.u.SourceResponse.content, buf,
sizeof buf);
snprintf(cp, sizeof temp - strlen(temp), ",\"body\":{\"content\":\"%s\"}",
buf);
cp = temp + strlen(temp);
}
snprintf(cp, sizeof temp - strlen(temp), "}");
@ -639,7 +671,8 @@ void vscode_serialize_event(char *buf, size_t buflen, ProtocolMessage *res) {
res->u.Event.event);
cp = temp + strlen(temp);
if (res->u.Event.event_type == VSCODE_OUTPUT_EVENT) {
snprintf(cp, sizeof temp - strlen(temp), ",\"body\":{\"category\":\"%s\",\"output\":\"%s\"}",
snprintf(cp, sizeof temp - strlen(temp),
",\"body\":{\"category\":\"%s\",\"output\":\"%s\"}",
res->u.Event.u.OutputEvent.category,
res->u.Event.u.OutputEvent.output);
cp = temp + strlen(temp);
@ -676,8 +709,8 @@ void vscode_send(ProtocolMessage *msg, FILE *out, FILE *log) {
vscode_serialize_response(buf, sizeof buf, msg);
else
return;
snprintf(json_buf, sizeof json_buf, "Content-Length: %d\r\n\r\n%s", (int)strlen(buf),
buf);
snprintf(json_buf, sizeof json_buf, "Content-Length: %d\r\n\r\n%s",
(int)strlen(buf), buf);
fprintf(log, "%s\n", json_buf);
fprintf(out, "%s", json_buf);
}
@ -712,8 +745,8 @@ void vscode_send_terminated_event(ProtocolMessage *res, FILE *out, FILE *log) {
vscode_send(res, out, log);
}
void vscode_send_output_event(ProtocolMessage *res, const char *category, const char *msg, FILE *out,
FILE *log) {
void vscode_send_output_event(ProtocolMessage *res, const char *category,
const char *msg, FILE *out, FILE *log) {
vscode_make_output_event(res, category, msg);
vscode_send(res, out, log);
}
@ -778,3 +811,8 @@ int vscode_get_request(FILE *in, ProtocolMessage *req, FILE *log) {
return VSCODE_EOF;
}
}
void ravi_string_copy(char *buf, const char *src, size_t buflen) {
strncpy(buf, src, buflen);
buf[buflen - 1] = 0;
}

@ -212,6 +212,9 @@ typedef struct {
int noDebug;
char program[TEXT_LEN];
int stopOnEntry;
char lua_path[PATH_LEN];
char lua_cpath[PATH_LEN];
char cwd[PATH_LEN];
} LaunchRequest;
struct {
@ -369,4 +372,7 @@ extern void vscode_send_success_response(ProtocolMessage *req,
extern int vscode_get_request(FILE *in, ProtocolMessage *req, FILE *log);
extern void vscode_json_stringify(const char *src, char *dest, size_t len);
/* guaranteed null termination */
extern void ravi_string_copy(char *buf, const char *src, size_t buflen);
#endif

@ -13,14 +13,21 @@
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#include <direct.h>
#define chdir _chdir
#else
#include <unistd.h>
#endif
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
#include "protocol.h"
/* debugger state */
enum {
DEBUGGER_BIRTH = 1,
DEBUGGER_INITIALIZED = 2,
@ -31,31 +38,29 @@ enum {
DEBUGGER_PROGRAM_TERMINATED = 7
};
enum {
VAR_TYPE_LOCALS = 1,
VAR_TYPE_UPVALUES = 2,
VAR_TYPE_GLOBALS = 3
};
enum { VAR_TYPE_LOCALS = 1, VAR_TYPE_UPVALUES = 2, VAR_TYPE_GLOBALS = 3 };
/* Some utilities to allow packing of 5 components into a 32-bit integer value
* This is used to encode the stack frame, variable reference
*/
#define MASK0 0x3F
#define MASK 0xFF
#define MASK 0xFF
#define MASK1 0x3
#define MAKENUM(t,a,b,c,d) \
(( ((t)&MASK1) | (((a)&MASK0) << 2) ) | \
( ((b)&MASK) << 8 ) | \
( ((c)&MASK) << 16 ) | \
( ((d)&MASK) << 24 ))
#define MAKENUM(t, a, b, c, d) \
\
((((t)&MASK1) | (((a)&MASK0) << 2)) | (((b)&MASK) << 8) | (((c)&MASK) << 16) | \
(((d)&MASK) << 24))
#define EXTRACT_T(x) ( (x)&MASK1 )
#define EXTRACT_A(x) ( ((x)>>2) & MASK0 )
#define EXTRACT_B(x) ( ((x)>>8) & MASK )
#define EXTRACT_C(x) ( ((x)>>16) & MASK )
#define EXTRACT_D(x) ( ((x)>>24) & MASK )
#define EXTRACT_T(x) ((x)&MASK1)
#define EXTRACT_A(x) (((x) >> 2) & MASK0)
#define EXTRACT_B(x) (((x) >> 8) & MASK)
#define EXTRACT_C(x) (((x) >> 16) & MASK)
#define EXTRACT_D(x) (((x) >> 24) & MASK)
/*
* These statics are temporary - eventually they will be moved to
* the Lua global state; but right now while things are
* the Lua global state; but right now while things are
* evolving this is easier to work with.
*/
static FILE *my_logger = NULL;
@ -63,6 +68,8 @@ static int thread_event_sent = 0;
static int debugger_state = DEBUGGER_BIRTH;
static Breakpoint breakpoints[MAX_TOTAL_BREAKPOINTS];
static ProtocolMessage output_response;
static char LUA_PATH[1024];
static char LUA_CPATH[1024];
/*
* Generate response to InitializeRequest
@ -86,7 +93,8 @@ static void handle_initialize_request(ProtocolMessage *req,
vscode_send(res, out, my_logger);
/* Send notification */
vscode_send_output_event(res, "console", "Debugger initialized\n", out, my_logger);
vscode_send_output_event(res, "console", "Debugger initialized\n", out,
my_logger);
debugger_state = DEBUGGER_INITIALIZED;
}
@ -123,30 +131,37 @@ static void handle_stack_trace_request(ProtocolMessage *req,
const char *last_path_delim = strrchr(src, '/');
char path[1024];
char name[256];
if (last_path_delim) { strncpy(name, last_path_delim + 1, sizeof name); }
if (last_path_delim) {
ravi_string_copy(name, last_path_delim + 1, sizeof name);
}
else {
strncpy(name, src, sizeof name);
ravi_string_copy(name, src, sizeof name);
}
strncpy(path, src, sizeof path);
strncpy(res->u.Response.u.StackTraceResponse.stackFrames[depth].source.path,
path, sizeof res->u.Response.u.StackTraceResponse.stackFrames[depth]
.source.path);
strncpy(res->u.Response.u.StackTraceResponse.stackFrames[depth].source.name,
name, sizeof res->u.Response.u.StackTraceResponse.stackFrames[depth]
.source.name);
ravi_string_copy(path, src, sizeof path);
ravi_string_copy(
res->u.Response.u.StackTraceResponse.stackFrames[depth].source.path,
path, sizeof res->u.Response.u.StackTraceResponse.stackFrames[depth]
.source.path);
ravi_string_copy(
res->u.Response.u.StackTraceResponse.stackFrames[depth].source.name,
name, sizeof res->u.Response.u.StackTraceResponse.stackFrames[depth]
.source.name);
}
else {
/* Source is a string - send a reference to the stack frame */
res->u.Response.u.StackTraceResponse.stackFrames[depth].source.sourceReference = depth + 1;
strncpy(res->u.Response.u.StackTraceResponse.stackFrames[depth].source.name,
"<dynamic function>", sizeof res->u.Response.u.StackTraceResponse.stackFrames[depth]
.source.name);
res->u.Response.u.StackTraceResponse.stackFrames[depth]
.source.sourceReference = depth + 1;
ravi_string_copy(
res->u.Response.u.StackTraceResponse.stackFrames[depth].source.name,
"<dynamic function>",
sizeof res->u.Response.u.StackTraceResponse.stackFrames[depth]
.source.name);
}
res->u.Response.u.StackTraceResponse.stackFrames[depth].id = depth;
res->u.Response.u.StackTraceResponse.stackFrames[depth].line =
entry.currentline;
const char *funcname = entry.name ? entry.name : "?";
strncpy(
ravi_string_copy(
res->u.Response.u.StackTraceResponse.stackFrames[depth].name, funcname,
sizeof res->u.Response.u.StackTraceResponse.stackFrames[depth].name);
depth++;
@ -155,9 +170,8 @@ static void handle_stack_trace_request(ProtocolMessage *req,
vscode_send(res, out, my_logger);
}
static void handle_source_request(ProtocolMessage *req,
ProtocolMessage *res, lua_State *L,
FILE *out) {
static void handle_source_request(ProtocolMessage *req, ProtocolMessage *res,
lua_State *L, FILE *out) {
lua_Debug entry;
int depth = req->u.Request.u.SourceRequest.sourceReference - 1;
vscode_make_success_response(req, res, VSCODE_SOURCE_RESPONSE);
@ -167,45 +181,64 @@ static void handle_source_request(ProtocolMessage *req,
const char *src = entry.source;
if (*src != '@') {
/* Source is a string */
strncpy(res->u.Response.u.SourceResponse.content, src, sizeof res->u.Response.u.SourceResponse.content);
res->u.Response.u.SourceResponse.content[sizeof res->u.Response.u.SourceResponse.content - 1] = 0; // just in case
ravi_string_copy(res->u.Response.u.SourceResponse.content, src,
sizeof res->u.Response.u.SourceResponse.content);
res->u.Response.u.SourceResponse
.content[sizeof res->u.Response.u.SourceResponse.content - 1] =
0; // just in case
}
else {
vscode_make_error_response(req, res, VSCODE_SOURCE_RESPONSE, "Source is in a file");
vscode_make_error_response(req, res, VSCODE_SOURCE_RESPONSE,
"Source is in a file");
}
}
else {
vscode_make_error_response(req, res, VSCODE_SOURCE_RESPONSE, "Unable to get information from Lua");
vscode_make_error_response(req, res, VSCODE_SOURCE_RESPONSE,
"Unable to get information from Lua");
}
}
else {
vscode_make_error_response(req, res, VSCODE_SOURCE_RESPONSE, "Source is in a file");
vscode_make_error_response(req, res, VSCODE_SOURCE_RESPONSE,
"Source is in a file");
}
vscode_send(res, out, my_logger);
}
/*
* Handle StackTraceRequest
*/
static void handle_set_breakpoints_request(ProtocolMessage *req,
ProtocolMessage *res, FILE *out, FILE *my_logger) {
ProtocolMessage *res, FILE *out,
FILE *my_logger) {
vscode_make_success_response(req, res, VSCODE_SET_BREAKPOINTS_RESPONSE);
int j = 0, k = 0;
for (int i = 0; i < MAX_BREAKPOINTS; i++) {
/* Make sure that the breakpoint is in a source file - disallow breakpoints in dynamic code */
if (req->u.Request.u.SetBreakpointsRequest.breakpoints[i].line > 0 && req->u.Request.u.SetBreakpointsRequest.source.sourceReference == 0) {
/* Make sure that the breakpoint is in a source file - disallow breakpoints
* in dynamic code */
if (req->u.Request.u.SetBreakpointsRequest.breakpoints[i].line > 0 &&
req->u.Request.u.SetBreakpointsRequest.source.sourceReference == 0) {
while (j < MAX_TOTAL_BREAKPOINTS) {
int y = j++;
if (breakpoints[y].source.path[0] == 0 || strcmp(breakpoints[y].source.path, req->u.Request.u.SetBreakpointsRequest.source.path) == 0) {
strncpy(breakpoints[y].source.path, req->u.Request.u.SetBreakpointsRequest.source.path, sizeof breakpoints[0].source.path);
breakpoints[y].line = req->u.Request.u.SetBreakpointsRequest.breakpoints[y].line;
if (breakpoints[y].source.path[0] == 0 ||
strcmp(breakpoints[y].source.path,
req->u.Request.u.SetBreakpointsRequest.source.path) == 0) {
ravi_string_copy(breakpoints[y].source.path,
req->u.Request.u.SetBreakpointsRequest.source.path,
sizeof breakpoints[0].source.path);
breakpoints[y].line =
req->u.Request.u.SetBreakpointsRequest.breakpoints[y].line;
fprintf(my_logger, "Saving breakpoint j=%d, k=%d, i=%d\n", y, k, i);
if (k < MAX_BREAKPOINTS) {
res->u.Response.u.SetBreakpointsResponse.breakpoints[k].line = req->u.Request.u.SetBreakpointsRequest.breakpoints[i].line;
res->u.Response.u.SetBreakpointsResponse.breakpoints[k].verified = false;
strncpy(res->u.Response.u.SetBreakpointsResponse.breakpoints[k].source.path, breakpoints[y].source.path,
sizeof res->u.Response.u.SetBreakpointsResponse.breakpoints[k].source.path);
res->u.Response.u.SetBreakpointsResponse.breakpoints[k].line =
req->u.Request.u.SetBreakpointsRequest.breakpoints[i].line;
res->u.Response.u.SetBreakpointsResponse.breakpoints[k].verified =
false;
ravi_string_copy(
res->u.Response.u.SetBreakpointsResponse.breakpoints[k]
.source.path,
breakpoints[y].source.path,
sizeof res->u.Response.u.SetBreakpointsResponse.breakpoints[k]
.source.path);
k++;
}
break;
@ -216,7 +249,8 @@ static void handle_set_breakpoints_request(ProtocolMessage *req,
}
/* Clear any other breakpoints within the same source file */
for (; j < MAX_TOTAL_BREAKPOINTS; j++) {
if (strcmp(breakpoints[j].source.path, req->u.Request.u.SetBreakpointsRequest.source.path) == 0) {
if (strcmp(breakpoints[j].source.path,
req->u.Request.u.SetBreakpointsRequest.source.path) == 0) {
breakpoints[j].source.path[0] = 0;
breakpoints[j].line = 0;
}
@ -224,7 +258,6 @@ static void handle_set_breakpoints_request(ProtocolMessage *req,
vscode_send(res, out, my_logger);
}
/*
* Handle ScopeRequest
*/
@ -238,19 +271,23 @@ static void handle_scopes_request(ProtocolMessage *req, ProtocolMessage *res,
int status = lua_getinfo(L, "u", &entry);
assert(status);
int i = 0;
strncpy(res->u.Response.u.ScopesResponse.scopes[i].name, "Locals",
sizeof res->u.Response.u.ScopesResponse.scopes[0].name);
res->u.Response.u.ScopesResponse.scopes[i].variablesReference = MAKENUM(VAR_TYPE_LOCALS, depth, 0, 0, 0);
ravi_string_copy(res->u.Response.u.ScopesResponse.scopes[i].name, "Locals",
sizeof res->u.Response.u.ScopesResponse.scopes[0].name);
res->u.Response.u.ScopesResponse.scopes[i].variablesReference =
MAKENUM(VAR_TYPE_LOCALS, depth, 0, 0, 0);
res->u.Response.u.ScopesResponse.scopes[i++].expensive = 0;
if (entry.nups > 0) {
strncpy(res->u.Response.u.ScopesResponse.scopes[i].name, "Up Values",
sizeof res->u.Response.u.ScopesResponse.scopes[0].name);
res->u.Response.u.ScopesResponse.scopes[i].variablesReference = MAKENUM(VAR_TYPE_UPVALUES, depth, 0, 0, 0);
ravi_string_copy(res->u.Response.u.ScopesResponse.scopes[i].name,
"Up Values",
sizeof res->u.Response.u.ScopesResponse.scopes[0].name);
res->u.Response.u.ScopesResponse.scopes[i].variablesReference =
MAKENUM(VAR_TYPE_UPVALUES, depth, 0, 0, 0);
res->u.Response.u.ScopesResponse.scopes[i++].expensive = 0;
}
strncpy(res->u.Response.u.ScopesResponse.scopes[i].name, "Globals",
sizeof res->u.Response.u.ScopesResponse.scopes[0].name);
res->u.Response.u.ScopesResponse.scopes[i].variablesReference = MAKENUM(VAR_TYPE_GLOBALS, depth, 0, 0, 0);
ravi_string_copy(res->u.Response.u.ScopesResponse.scopes[i].name, "Globals",
sizeof res->u.Response.u.ScopesResponse.scopes[0].name);
res->u.Response.u.ScopesResponse.scopes[i].variablesReference =
MAKENUM(VAR_TYPE_GLOBALS, depth, 0, 0, 0);
res->u.Response.u.ScopesResponse.scopes[i].expensive = 1;
}
else {
@ -300,7 +337,7 @@ static int get_value(lua_State *L, int stack_idx, char *buf, size_t len) {
}
case LUA_TSTRING: {
char tbuf[1024];
snprintf(tbuf, sizeof tbuf, "%.*s", (int)(sizeof tbuf) - 1, lua_tostring(L, stack_idx));
snprintf(tbuf, sizeof tbuf, "%s", lua_tostring(L, stack_idx));
vscode_json_stringify(tbuf, buf, len);
break;
}
@ -310,7 +347,7 @@ static int get_value(lua_State *L, int stack_idx, char *buf, size_t len) {
break;
}
case LUA_TFUNCTION: {
snprintf(buf, len, "%p", lua_topointer(L, stack_idx));
snprintf(buf, len, "%s", ravi_typename(L, stack_idx));
break;
}
case LUA_TUSERDATA: {
@ -336,7 +373,7 @@ static void handle_variables_request(ProtocolMessage *req, ProtocolMessage *res,
int varRef = req->u.Request.u.VariablesRequest.variablesReference;
/*
* The variable reference is encoded such that it contains:
* type - the scope type
* type - the scope type
* depth - the stack frame
* var - the index of the variable as provided to lua_getlocal()
*/
@ -344,7 +381,7 @@ static void handle_variables_request(ProtocolMessage *req, ProtocolMessage *res,
int depth = EXTRACT_A(varRef);
int var = EXTRACT_B(varRef);
if (lua_getstack(L, depth, &entry)) {
if (type == VAR_TYPE_LOCALS) { // locals
if (type == VAR_TYPE_LOCALS) { // locals
if (var == 0) {
/*
* A top level request - i.e. from the scope
@ -352,21 +389,23 @@ static void handle_variables_request(ProtocolMessage *req, ProtocolMessage *res,
for (int n = 1, v = 0; v < MAX_VARIABLES; n++) {
const char *name = lua_getlocal(L, &entry, n);
if (name) {
/* Temporary variables have names that start with (.
/* Temporary variables have names that start with (.
* Skip such variables
*/
if (*name != '(') {
strncpy(
ravi_string_copy(
res->u.Response.u.VariablesResponse.variables[v].name, name,
sizeof res->u.Response.u.VariablesResponse.variables[0].name);
int is_table = get_value(
L, lua_gettop(L),
res->u.Response.u.VariablesResponse.variables[v].value,
sizeof res->u.Response.u.VariablesResponse.variables[0].value);
sizeof res->u.Response.u.VariablesResponse.variables[0]
.value);
/* If the variable is a table then we pass pack a reference
that is used by the front end to drill down */
res->u.Response.u.VariablesResponse.variables[v].variablesReference = is_table ?
MAKENUM(type, depth, n, 0, 0) : 0;
res->u.Response.u.VariablesResponse.variables[v]
.variablesReference =
is_table ? MAKENUM(type, depth, n, 0, 0) : 0;
v++;
}
lua_pop(L, 1); /* pop the value */
@ -382,7 +421,10 @@ static void handle_variables_request(ProtocolMessage *req, ProtocolMessage *res,
* FIXME - the number of items is limited to MAX_VARIABLES
* but user is not shown any warning if values are truncated
*/
fprintf(my_logger, "\n--> Request to extract local variable %d of type %d at depth %d\n", var, type, depth);
fprintf(my_logger,
"\n--> Request to extract local variable %d of type %d at "
"depth %d\n",
var, type, depth);
const char *name = lua_getlocal(L, &entry, var);
if (name) {
int stack_idx = lua_gettop(L);
@ -396,17 +438,17 @@ static void handle_variables_request(ProtocolMessage *req, ProtocolMessage *res,
lua_pushvalue(L, -2);
// stack now contains: -1 => key; -2 => value; -3 => key
get_value(
L, -1,
res->u.Response.u.VariablesResponse.variables[v].name,
sizeof res->u.Response.u.VariablesResponse.variables[0].name);
get_value(
L, -2,
L, -1, res->u.Response.u.VariablesResponse.variables[v].name,
sizeof res->u.Response.u.VariablesResponse.variables[0].name);
get_value(L, -2,
res->u.Response.u.VariablesResponse.variables[v].value,
sizeof res->u.Response.u.VariablesResponse.variables[0].value);
sizeof res->u.Response.u.VariablesResponse.variables[0]
.value);
/*
* Right now we do not support further drill down
*/
res->u.Response.u.VariablesResponse.variables[v].variablesReference = 0;
res->u.Response.u.VariablesResponse.variables[v]
.variablesReference = 0;
v++;
// pop value + copy of key, leaving original key
lua_pop(L, 2);
@ -424,14 +466,38 @@ static void handle_variables_request(ProtocolMessage *req, ProtocolMessage *res,
vscode_send(res, out, my_logger);
}
static void set_package_var(lua_State *L, const char *key, const char *value) {
lua_getglobal(L, "package");
lua_pushstring(L, value);
lua_setfield(L, -2, key);
lua_pop(L, 1);
}
static void handle_launch_request(ProtocolMessage *req, ProtocolMessage *res,
lua_State *L, FILE *out) {
if (debugger_state != DEBUGGER_INITIALIZED) {
vscode_send_error_response(req, res, VSCODE_LAUNCH_RESPONSE,
"not initialized or unexpected state", out, my_logger);
"not initialized or unexpected state", out,
my_logger);
return;
}
if (req->u.Request.u.LaunchRequest.lua_path[0]) {
set_package_var(L, "path", req->u.Request.u.LaunchRequest.lua_path);
}
if (req->u.Request.u.LaunchRequest.lua_cpath[0]) {
set_package_var(L, "cpath", req->u.Request.u.LaunchRequest.lua_cpath);
}
if (req->u.Request.u.LaunchRequest.cwd[0]) {
if (chdir(req->u.Request.u.LaunchRequest.cwd) != 0) {
char temp[1024];
snprintf(temp, sizeof temp, "Unable to change directory to %s\n",
req->u.Request.u.LaunchRequest.cwd);
vscode_send_output_event(res, "console", temp, out, my_logger);
vscode_send_error_response(req, res, VSCODE_LAUNCH_RESPONSE,
"Launch failed", out, my_logger);
return;
}
}
const char *progname = req->u.Request.u.LaunchRequest.program;
fprintf(my_logger, "\n--> Launching '%s'\n", progname);
int status = luaL_loadfile(L, progname);
@ -446,7 +512,8 @@ static void handle_launch_request(ProtocolMessage *req, ProtocolMessage *res,
return;
}
else {
vscode_send_success_response(req, res, VSCODE_LAUNCH_RESPONSE, out, my_logger);
vscode_send_success_response(req, res, VSCODE_LAUNCH_RESPONSE, out,
my_logger);
}
if (req->u.Request.u.LaunchRequest.stopOnEntry)
debugger_state = DEBUGGER_PROGRAM_STEPPING;
@ -455,7 +522,7 @@ static void handle_launch_request(ProtocolMessage *req, ProtocolMessage *res,
if (lua_pcall(L, 0, 0, 0)) {
char temp[1024];
snprintf(temp, sizeof temp, "Program terminated with error: %s\n",
lua_tostring(L, -1));
lua_tostring(L, -1));
vscode_send_output_event(res, "console", temp, out, my_logger);
lua_pop(L, 1);
}
@ -467,12 +534,9 @@ static void handle_launch_request(ProtocolMessage *req, ProtocolMessage *res,
* Called via Lua Hook or via main
* If called from main then init is true and ar == NULL
*/
static void debugger(lua_State *L, lua_Debug *ar, FILE *in,
FILE *out) {
static void debugger(lua_State *L, lua_Debug *ar, FILE *in, FILE *out) {
ProtocolMessage req, res;
if (debugger_state == DEBUGGER_PROGRAM_TERMINATED) {
return;
}
if (debugger_state == DEBUGGER_PROGRAM_TERMINATED) { return; }
if (debugger_state == DEBUGGER_PROGRAM_RUNNING) {
int initialized = 0;
for (int j = 0; j < 20; j++) {
@ -549,13 +613,13 @@ static void debugger(lua_State *L, lua_Debug *ar, FILE *in,
exit(0);
}
case VSCODE_SET_EXCEPTION_BREAKPOINTS_REQUEST: {
vscode_send_success_response(
&req, &res, VSCODE_SET_EXCEPTION_BREAKPOINTS_RESPONSE, out, my_logger);
vscode_send_success_response(&req, &res,
VSCODE_SET_EXCEPTION_BREAKPOINTS_RESPONSE,
out, my_logger);
break;
}
case VSCODE_SET_BREAKPOINTS_REQUEST: {
handle_set_breakpoints_request(
&req, &res, out, my_logger);
handle_set_breakpoints_request(&req, &res, out, my_logger);
break;
}
case VSCODE_CONFIGURATION_DONE_REQUEST: {
@ -618,9 +682,8 @@ void ravi_debughook(lua_State *L, lua_Debug *ar) {
void ravi_debug_writestring(const char *s, size_t l) {
char temp[256];
if (l >= sizeof temp)
l = sizeof temp-1;
strncpy(temp, s, l+1);
if (l >= sizeof temp) l = sizeof temp - 1;
ravi_string_copy(temp, s, l + 1);
temp[l] = 0;
vscode_send_output_event(&output_response, "stdout", temp, stdout, my_logger);
}
@ -647,8 +710,7 @@ int main(void) {
#else
my_logger = fopen("/tmp/out1.txt", "w");
#endif
if (my_logger == NULL)
my_logger = stderr;
if (my_logger == NULL) my_logger = stderr;
#ifdef _WIN32
/* The VSCode debug protocol requires binary IO */
_setmode(_fileno(stdout), _O_BINARY);
@ -659,12 +721,16 @@ int main(void) {
lua_State *L = luaL_newstate(); /* create Lua state */
if (L == NULL) { return EXIT_FAILURE; }
/* redirect Lua's stdout and stderr */
ravi_set_writefuncs(L, ravi_debug_writestring, ravi_debug_writeline, ravi_debug_writestringerror);
ravi_set_writefuncs(L, ravi_debug_writestring, ravi_debug_writeline,
ravi_debug_writestringerror);
luaL_checkversion(L); /* check that interpreter has correct version */
luaL_openlibs(L); /* open standard libraries */
luaL_openlibs(L); /* open standard libraries */
lua_sethook(L, ravi_debughook, LUA_MASKCALL | LUA_MASKLINE | LUA_MASKRET, 0);
debugger_state = DEBUGGER_BIRTH;
ravi_set_debugger_data(L, &debugger_state); /* This is useless data right now but it ensures that the hook cannot be removed */
ravi_set_debugger_data(
L,
&debugger_state); /* This is useless data right now but it ensures that
the hook cannot be removed */
debugger(L, NULL, stdin, stdout);
lua_close(L);
fclose(my_logger);

Loading…
Cancel
Save