mirror of
https://github.com/fluencelabs/redis
synced 2025-03-29 05:41:03 +00:00
Lua debugger: output improvements, eval command.
This commit is contained in:
parent
1f8d614423
commit
cf4700bda4
@ -526,11 +526,9 @@ sds sdsCatColorizedLdbReply(sds o, char *s, size_t len) {
|
|||||||
if (strstr(s,"<reply>")) color = "cyan";
|
if (strstr(s,"<reply>")) color = "cyan";
|
||||||
if (strstr(s,"<error>")) color = "red";
|
if (strstr(s,"<error>")) color = "red";
|
||||||
if (strstr(s,"<value>")) color = "magenta";
|
if (strstr(s,"<value>")) color = "magenta";
|
||||||
if (isdigit(s[0])) {
|
if (len > 4 && isdigit(s[3])) {
|
||||||
char *p = s+1;
|
if (s[1] == '>') color = "yellow"; /* Current line. */
|
||||||
while(isdigit(*p)) p++;
|
else if (s[2] == '#') color = "bold"; /* Break point. */
|
||||||
if (*p == '*') color = "yellow"; /* Current line. */
|
|
||||||
else if (*p == '#') color = "bold"; /* Break point. */
|
|
||||||
}
|
}
|
||||||
return sdscatcolor(o,s,len,color);
|
return sdscatcolor(o,s,len,color);
|
||||||
}
|
}
|
||||||
@ -1030,6 +1028,28 @@ static int issueCommand(int argc, char **argv) {
|
|||||||
return issueCommandRepeat(argc, argv, config.repeat);
|
return issueCommandRepeat(argc, argv, config.repeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Split the user provided command into multiple SDS arguments.
|
||||||
|
* This function normally uses sdssplitargs() from sds.c which is able
|
||||||
|
* to understand "quoted strings", escapes and so forth. However when
|
||||||
|
* we are in Lua debugging mode and the "eval" command is used, we want
|
||||||
|
* the remaining Lua script (after "e " or "eval ") to be passed verbatim
|
||||||
|
* as a single big argument. */
|
||||||
|
static sds *cliSplitArgs(char *line, int *argc) {
|
||||||
|
if (config.eval_ldb && (strstr(line,"eval ") == line ||
|
||||||
|
strstr(line,"e ") == line))
|
||||||
|
{
|
||||||
|
sds *argv = zmalloc(sizeof(sds)*2);
|
||||||
|
*argc = 2;
|
||||||
|
int len = strlen(line);
|
||||||
|
int elen = line[1] == ' ' ? 2 : 5; /* "e " or "eval "? */
|
||||||
|
argv[0] = sdsnewlen(line,elen-1);
|
||||||
|
argv[1] = sdsnewlen(line+elen,len-elen);
|
||||||
|
return argv;
|
||||||
|
} else {
|
||||||
|
return sdssplitargs(line,argc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void repl(void) {
|
static void repl(void) {
|
||||||
sds historyfile = NULL;
|
sds historyfile = NULL;
|
||||||
int history = 0;
|
int history = 0;
|
||||||
@ -1053,7 +1073,7 @@ static void repl(void) {
|
|||||||
cliRefreshPrompt();
|
cliRefreshPrompt();
|
||||||
while((line = linenoise(context ? config.prompt : "not connected> ")) != NULL) {
|
while((line = linenoise(context ? config.prompt : "not connected> ")) != NULL) {
|
||||||
if (line[0] != '\0') {
|
if (line[0] != '\0') {
|
||||||
argv = sdssplitargs(line,&argc);
|
argv = cliSplitArgs(line,&argc);
|
||||||
if (history) linenoiseHistoryAdd(line);
|
if (history) linenoiseHistoryAdd(line);
|
||||||
if (historyfile) linenoiseHistorySave(historyfile);
|
if (historyfile) linenoiseHistorySave(historyfile);
|
||||||
|
|
||||||
|
208
src/scripting.c
208
src/scripting.c
@ -51,9 +51,11 @@ void ldbEnable(client *c);
|
|||||||
void evalGenericCommandWithDebugging(client *c, int evalsha);
|
void evalGenericCommandWithDebugging(client *c, int evalsha);
|
||||||
void luaLdbLineHook(lua_State *lua, lua_Debug *ar);
|
void luaLdbLineHook(lua_State *lua, lua_Debug *ar);
|
||||||
void ldbLog(sds entry);
|
void ldbLog(sds entry);
|
||||||
|
void ldbLogRedisReply(char *reply, size_t maxlen);
|
||||||
|
|
||||||
/* Debugger shared state is stored inside this global structure. */
|
/* Debugger shared state is stored inside this global structure. */
|
||||||
#define LDB_BREAKPOINTS_MAX 64
|
#define LDB_BREAKPOINTS_MAX 64 /* Max number of breakpoints. */
|
||||||
|
#define LDB_REPLY_MAX_LOG_LEN 60 /* Max chars when logging a reply. */
|
||||||
struct ldbState {
|
struct ldbState {
|
||||||
int fd; /* Socket of the debugging client. */
|
int fd; /* Socket of the debugging client. */
|
||||||
int active; /* Are we debugging EVAL right now? */
|
int active; /* Are we debugging EVAL right now? */
|
||||||
@ -107,13 +109,11 @@ void sha1hex(char *digest, char *script, size_t len) {
|
|||||||
* Basically we take the arguments, execute the Redis command in the context
|
* Basically we take the arguments, execute the Redis command in the context
|
||||||
* of a non connected client, then take the generated reply and convert it
|
* of a non connected client, then take the generated reply and convert it
|
||||||
* into a suitable Lua type. With this trick the scripting feature does not
|
* into a suitable Lua type. With this trick the scripting feature does not
|
||||||
* need the introduction of a full Redis internals API. Basically the script
|
* need the introduction of a full Redis internals API. The script
|
||||||
* is like a normal client that bypasses all the slow I/O paths.
|
* is like a normal client that bypasses all the slow I/O paths.
|
||||||
*
|
*
|
||||||
* Note: in this function we do not do any sanity check as the reply is
|
* Note: in this function we do not do any sanity check as the reply is
|
||||||
* generated by Redis directly. This allows us to go faster.
|
* generated by Redis directly. This allows us to go faster.
|
||||||
* The reply string can be altered during the parsing as it is discarded
|
|
||||||
* after the conversion is completed.
|
|
||||||
*
|
*
|
||||||
* Errors are returned as a table with a single 'err' field set to the
|
* Errors are returned as a table with a single 'err' field set to the
|
||||||
* error string.
|
* error string.
|
||||||
@ -123,21 +123,11 @@ char *redisProtocolToLuaType(lua_State *lua, char* reply) {
|
|||||||
char *p = reply;
|
char *p = reply;
|
||||||
|
|
||||||
switch(*p) {
|
switch(*p) {
|
||||||
case ':':
|
case ':': p = redisProtocolToLuaType_Int(lua,reply); break;
|
||||||
p = redisProtocolToLuaType_Int(lua,reply);
|
case '$': p = redisProtocolToLuaType_Bulk(lua,reply); break;
|
||||||
break;
|
case '+': p = redisProtocolToLuaType_Status(lua,reply); break;
|
||||||
case '$':
|
case '-': p = redisProtocolToLuaType_Error(lua,reply); break;
|
||||||
p = redisProtocolToLuaType_Bulk(lua,reply);
|
case '*': p = redisProtocolToLuaType_MultiBulk(lua,reply); break;
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
p = redisProtocolToLuaType_Status(lua,reply);
|
|
||||||
break;
|
|
||||||
case '-':
|
|
||||||
p = redisProtocolToLuaType_Error(lua,reply);
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
p = redisProtocolToLuaType_MultiBulk(lua,reply);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -579,12 +569,8 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
|
|||||||
redisProtocolToLuaType(lua,reply);
|
redisProtocolToLuaType(lua,reply);
|
||||||
|
|
||||||
/* If the debugger is active, log the reply from Redis. */
|
/* If the debugger is active, log the reply from Redis. */
|
||||||
if (ldb.active && ldb.step) {
|
if (ldb.active && ldb.step)
|
||||||
sds replycopy = sdsnew("<reply> ");
|
ldbLogRedisReply(reply,LDB_REPLY_MAX_LOG_LEN);
|
||||||
replycopy = sdscat(replycopy,reply); /* It's always null terminated. */
|
|
||||||
if (sdslen(replycopy) > 70) sdsrange(replycopy,0,69);
|
|
||||||
ldbLog(replycopy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sort the output array if needed, assuming it is a non-null multi bulk
|
/* Sort the output array if needed, assuming it is a non-null multi bulk
|
||||||
* reply as expected. */
|
* reply as expected. */
|
||||||
@ -1687,6 +1673,25 @@ protoerr:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Log the specified line in the Lua debugger output. */
|
||||||
|
void ldbLogSourceLine(int lnum) {
|
||||||
|
char *line = ldbGetSourceLine(lnum);
|
||||||
|
char *prefix;
|
||||||
|
int bp = ldbIsBreakpoint(lnum);
|
||||||
|
int current = ldb.currentline == lnum;
|
||||||
|
|
||||||
|
if (current && bp)
|
||||||
|
prefix = "->#";
|
||||||
|
else if (current)
|
||||||
|
prefix = "-> ";
|
||||||
|
else if (bp)
|
||||||
|
prefix = " #";
|
||||||
|
else
|
||||||
|
prefix = " ";
|
||||||
|
sds thisline = sdscatprintf(sdsempty(),"%s%-3d %s", prefix, lnum, line);
|
||||||
|
ldbLog(thisline);
|
||||||
|
}
|
||||||
|
|
||||||
/* Implement the "list" command of the Lua debugger. If around is 0
|
/* Implement the "list" command of the Lua debugger. If around is 0
|
||||||
* the whole file is listed, otherwise only a small portion of the file
|
* the whole file is listed, otherwise only a small portion of the file
|
||||||
* around the specified line is shown. When a line number is specified
|
* around the specified line is shown. When a line number is specified
|
||||||
@ -1697,22 +1702,16 @@ void ldbList(int around, int context) {
|
|||||||
|
|
||||||
for (j = 1; j <= ldb.lines; j++) {
|
for (j = 1; j <= ldb.lines; j++) {
|
||||||
if (around != 0 && abs(around-j) > context) continue;
|
if (around != 0 && abs(around-j) > context) continue;
|
||||||
char *line = ldbGetSourceLine(j);
|
ldbLogSourceLine(j);
|
||||||
int mark;
|
|
||||||
if (ldb.currentline == j)
|
|
||||||
mark = '*';
|
|
||||||
else
|
|
||||||
mark = ldbIsBreakpoint(j) ? '#' : ':';
|
|
||||||
sds thisline = sdscatprintf(sdsempty(),"%d%c %s", j, mark, line);
|
|
||||||
ldbLog(thisline);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Produce a debugger log entry representing the value of the Lua object
|
/* Produce a debugger log entry representing the value of the Lua object
|
||||||
* currently on the top of the stack. */
|
* currently on the top of the stack. As a side effect the element is
|
||||||
void ldbLogStackValue(lua_State *lua) {
|
* popped. */
|
||||||
|
void ldbLogStackValue(lua_State *lua, char *prefix) {
|
||||||
int t = lua_type(lua,-1);
|
int t = lua_type(lua,-1);
|
||||||
sds s = sdsnew("<value> ");
|
sds s = sdsnew(prefix);
|
||||||
|
|
||||||
switch(t) {
|
switch(t) {
|
||||||
case LUA_TSTRING:
|
case LUA_TSTRING:
|
||||||
@ -1751,6 +1750,91 @@ void ldbLogStackValue(lua_State *lua) {
|
|||||||
lua_pop(lua,1);
|
lua_pop(lua,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *ldbRedisProtocolToHuman_Int(sds *o, char *reply);
|
||||||
|
char *ldbRedisProtocolToHuman_Bulk(sds *o, char *reply);
|
||||||
|
char *ldbRedisProtocolToHuman_Status(sds *o, char *reply);
|
||||||
|
char *ldbRedisProtocolToHuman_MultiBulk(sds *o, char *reply);
|
||||||
|
|
||||||
|
/* Get Redis protocol from 'reply' and appends it in human readable form to
|
||||||
|
* the passed SDS string 'o'.
|
||||||
|
*
|
||||||
|
* Note that the SDS string is passed by reference (pointer of pointer to
|
||||||
|
* char*) so that we can return a modified pointer, as for SDS semantics. */
|
||||||
|
char *ldbRedisProtocolToHuman(sds *o, char *reply) {
|
||||||
|
char *p = reply;
|
||||||
|
switch(*p) {
|
||||||
|
case ':': p = ldbRedisProtocolToHuman_Int(o,reply); break;
|
||||||
|
case '$': p = ldbRedisProtocolToHuman_Bulk(o,reply); break;
|
||||||
|
case '+': p = ldbRedisProtocolToHuman_Status(o,reply); break;
|
||||||
|
case '-': p = ldbRedisProtocolToHuman_Status(o,reply); break;
|
||||||
|
case '*': p = ldbRedisProtocolToHuman_MultiBulk(o,reply); break;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ldbRedisProtocolToHuman_Int(sds *o, char *reply) {
|
||||||
|
char *p = strchr(reply+1,'\r');
|
||||||
|
*o = sdscatlen(*o,reply+1,p-reply-1);
|
||||||
|
return p+2;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ldbRedisProtocolToHuman_Bulk(sds *o, char *reply) {
|
||||||
|
char *p = strchr(reply+1,'\r');
|
||||||
|
long long bulklen;
|
||||||
|
|
||||||
|
string2ll(reply+1,p-reply-1,&bulklen);
|
||||||
|
if (bulklen == -1) {
|
||||||
|
*o = sdscatlen(*o,"NULL",4);
|
||||||
|
return p+2;
|
||||||
|
} else {
|
||||||
|
*o = sdscatrepr(*o,p+2,bulklen);
|
||||||
|
return p+2+bulklen+2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ldbRedisProtocolToHuman_Status(sds *o, char *reply) {
|
||||||
|
char *p = strchr(reply+1,'\r');
|
||||||
|
|
||||||
|
*o = sdscatrepr(*o,reply,p-reply);
|
||||||
|
return p+2;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ldbRedisProtocolToHuman_MultiBulk(sds *o, char *reply) {
|
||||||
|
char *p = strchr(reply+1,'\r');
|
||||||
|
long long mbulklen;
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
string2ll(reply+1,p-reply-1,&mbulklen);
|
||||||
|
p += 2;
|
||||||
|
if (mbulklen == -1) {
|
||||||
|
*o = sdscatlen(*o,"NULL",4);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
*o = sdscatlen(*o,"[",1);
|
||||||
|
for (j = 0; j < mbulklen; j++) {
|
||||||
|
p = ldbRedisProtocolToHuman(o,p);
|
||||||
|
if (j != mbulklen-1) *o = sdscatlen(*o,",",1);
|
||||||
|
}
|
||||||
|
*o = sdscatlen(*o,"]",1);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Log a Redis reply as debugger output, in an human readable format.
|
||||||
|
* If the resulting string is longer than 'len' plus a few more chars
|
||||||
|
* used as prefix, it gets truncated. */
|
||||||
|
void ldbLogRedisReply(char *reply, size_t maxlen) {
|
||||||
|
sds log = sdsnew("<reply> ");
|
||||||
|
maxlen += sdslen(log);
|
||||||
|
ldbRedisProtocolToHuman(&log,reply);
|
||||||
|
/* Trip and add ... if the length was reached, to hint the user it's not
|
||||||
|
* the whole reply. */
|
||||||
|
if (sdslen(log) > maxlen) {
|
||||||
|
sdsrange(log,0,maxlen-1);
|
||||||
|
log = sdscatlen(log," ...",4);
|
||||||
|
}
|
||||||
|
ldbLog(log);
|
||||||
|
}
|
||||||
|
|
||||||
/* Implements the "print" command of the Lua debugger. It scans for Lua
|
/* Implements the "print" command of the Lua debugger. It scans for Lua
|
||||||
* var "varname" starting from the current stack frame up to the top stack
|
* var "varname" starting from the current stack frame up to the top stack
|
||||||
* frame. The first matching variable is printed. */
|
* frame. The first matching variable is printed. */
|
||||||
@ -1765,7 +1849,7 @@ void ldbPrint(lua_State *lua, char *varname) {
|
|||||||
while((name = lua_getlocal(lua,&ar,i)) != NULL) {
|
while((name = lua_getlocal(lua,&ar,i)) != NULL) {
|
||||||
i++;
|
i++;
|
||||||
if (strcmp(varname,name) == 0) {
|
if (strcmp(varname,name) == 0) {
|
||||||
ldbLogStackValue(lua);
|
ldbLogStackValue(lua,"<value> ");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
lua_pop(lua,1); /* Discard the var name on the stack. */
|
lua_pop(lua,1); /* Discard the var name on the stack. */
|
||||||
@ -1784,10 +1868,8 @@ void ldbBreak(sds *argv, int argc) {
|
|||||||
} else {
|
} else {
|
||||||
ldbLog(sdscatfmt(sdsempty(),"%i breakpoints set:",ldb.bpcount));
|
ldbLog(sdscatfmt(sdsempty(),"%i breakpoints set:",ldb.bpcount));
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < ldb.bpcount; j++) {
|
for (j = 0; j < ldb.bpcount; j++)
|
||||||
ldbLog(sdscatfmt(sdsempty(),"%i# %s", ldb.bp[j],
|
ldbLogSourceLine(ldb.bp[j]);
|
||||||
ldbGetSourceLine(ldb.bp[j])));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int j;
|
int j;
|
||||||
@ -1819,6 +1901,28 @@ void ldbBreak(sds *argv, int argc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Implements the Lua debugger "eval" command. It just compiles the user
|
||||||
|
* passed fragment of code and executes it, showing the result left on
|
||||||
|
* the stack. */
|
||||||
|
void ldbEval(lua_State *lua, sds *argv, int argc) {
|
||||||
|
/* Glue the script together if it is composed of multiple arguments. */
|
||||||
|
sds code = sdsjoinsds(argv+1,argc-1," ",1);
|
||||||
|
|
||||||
|
if (luaL_loadbuffer(lua,code,sdslen(code),"@ldb_eval")) {
|
||||||
|
ldbLog(sdscatfmt(sdsempty(),"<error> %s",lua_tostring(lua,-1)));
|
||||||
|
lua_pop(lua,1);
|
||||||
|
sdsfree(code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sdsfree(code);
|
||||||
|
if (lua_pcall(lua,0,1,0)) {
|
||||||
|
ldbLog(sdscatfmt(sdsempty(),"<error> %s",lua_tostring(lua,-1)));
|
||||||
|
lua_pop(lua,1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ldbLogStackValue(lua,"<retval> ");
|
||||||
|
}
|
||||||
|
|
||||||
/* Read debugging commands from client. */
|
/* Read debugging commands from client. */
|
||||||
void ldbRepl(lua_State *lua) {
|
void ldbRepl(lua_State *lua) {
|
||||||
sds *argv;
|
sds *argv;
|
||||||
@ -1845,8 +1949,9 @@ void ldbRepl(lua_State *lua) {
|
|||||||
ldb.cbuf = sdsempty();
|
ldb.cbuf = sdsempty();
|
||||||
|
|
||||||
/* Execute the command. */
|
/* Execute the command. */
|
||||||
if (!strcasecmp(argv[0],"help")) {
|
if (!strcasecmp(argv[0],"h") || !strcasecmp(argv[0],"help")) {
|
||||||
ldbLog(sdsnew("Redis Lua debugger help:"));
|
ldbLog(sdsnew("Redis Lua debugger help:"));
|
||||||
|
ldbLog(sdsnew("[h]elp Show this help."));
|
||||||
ldbLog(sdsnew("[s]tep Run current line and stop again."));
|
ldbLog(sdsnew("[s]tep Run current line and stop again."));
|
||||||
ldbLog(sdsnew("[n]ext Alias for step."));
|
ldbLog(sdsnew("[n]ext Alias for step."));
|
||||||
ldbLog(sdsnew("[c]continue Run till next breakpoint."));
|
ldbLog(sdsnew("[c]continue Run till next breakpoint."));
|
||||||
@ -1857,6 +1962,7 @@ ldbLog(sdsnew("[b]eark Show all breakpoints."));
|
|||||||
ldbLog(sdsnew("[b]eark <line> Add a breakpoint to the specified line."));
|
ldbLog(sdsnew("[b]eark <line> Add a breakpoint to the specified line."));
|
||||||
ldbLog(sdsnew("[b]eark -<line> Remove breakpoint from the specified line."));
|
ldbLog(sdsnew("[b]eark -<line> Remove breakpoint from the specified line."));
|
||||||
ldbLog(sdsnew("[b]eark 0 Remove all breakpoints."));
|
ldbLog(sdsnew("[b]eark 0 Remove all breakpoints."));
|
||||||
|
ldbLog(sdsnew("[e]eval <code> Execute some Lua code in a new callframe."));
|
||||||
ldbSendLogs();
|
ldbSendLogs();
|
||||||
} else if (!strcasecmp(argv[0],"s") || !strcasecmp(argv[0],"step") ||
|
} else if (!strcasecmp(argv[0],"s") || !strcasecmp(argv[0],"step") ||
|
||||||
!strcasecmp(argv[0],"n") || !strcasecmp(argv[0],"next")) {
|
!strcasecmp(argv[0],"n") || !strcasecmp(argv[0],"next")) {
|
||||||
@ -1864,9 +1970,12 @@ ldbLog(sdsnew("[b]eark 0 Remove all breakpoints."));
|
|||||||
break;
|
break;
|
||||||
} else if (!strcasecmp(argv[0],"c") || !strcasecmp(argv[0],"continue")){
|
} else if (!strcasecmp(argv[0],"c") || !strcasecmp(argv[0],"continue")){
|
||||||
break;
|
break;
|
||||||
} else if (!strcasecmp(argv[0],"b") || !strcasecmp(argv[0],"break")){
|
} else if (!strcasecmp(argv[0],"b") || !strcasecmp(argv[0],"break")) {
|
||||||
ldbBreak(argv,argc);
|
ldbBreak(argv,argc);
|
||||||
ldbSendLogs();
|
ldbSendLogs();
|
||||||
|
} else if (!strcasecmp(argv[0],"e") || !strcasecmp(argv[0],"eval")) {
|
||||||
|
ldbEval(lua,argv,argc);
|
||||||
|
ldbSendLogs();
|
||||||
} else if (argc == 2 &&
|
} else if (argc == 2 &&
|
||||||
(!strcasecmp(argv[0],"p") || !strcasecmp(argv[0],"print")))
|
(!strcasecmp(argv[0],"p") || !strcasecmp(argv[0],"print")))
|
||||||
{
|
{
|
||||||
@ -1879,7 +1988,7 @@ ldbLog(sdsnew("[b]eark 0 Remove all breakpoints."));
|
|||||||
ldbList(around,ctx);
|
ldbList(around,ctx);
|
||||||
ldbSendLogs();
|
ldbSendLogs();
|
||||||
} else {
|
} else {
|
||||||
ldbLog(sdsnew("Unknown Redis Lua debugger command or "
|
ldbLog(sdsnew("<error> Unknown Redis Lua debugger command or "
|
||||||
"wrong number of arguments."));
|
"wrong number of arguments."));
|
||||||
ldbSendLogs();
|
ldbSendLogs();
|
||||||
}
|
}
|
||||||
@ -1899,12 +2008,15 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
|
|||||||
lua_getinfo(lua,"Sl",ar);
|
lua_getinfo(lua,"Sl",ar);
|
||||||
if(strstr(ar->short_src,"user_script") == NULL) return;
|
if(strstr(ar->short_src,"user_script") == NULL) return;
|
||||||
|
|
||||||
if (ldb.step || ldbIsBreakpoint(ar->currentline)) {
|
int bp = ldbIsBreakpoint(ar->currentline);
|
||||||
|
if (ldb.step || bp) {
|
||||||
|
char *reason = bp ? "break point" : "step over";
|
||||||
ldb.currentline = ar->currentline;
|
ldb.currentline = ar->currentline;
|
||||||
ldb.step = 0;
|
ldb.step = 0;
|
||||||
int mark = ldbIsBreakpoint(ldb.currentline) ? '#' : '*';
|
ldbLog(sdscatprintf(sdsempty(),
|
||||||
ldbLog(sdscatprintf(sdsempty(),"%d%c %s", (int)ar->currentline,
|
"* Stopped at %d, stop reason = %s",
|
||||||
mark, ldbGetSourceLine(ar->currentline)));
|
ldb.currentline, reason));
|
||||||
|
ldbLogSourceLine(ldb.currentline);
|
||||||
ldbSendLogs();
|
ldbSendLogs();
|
||||||
ldbRepl(lua);
|
ldbRepl(lua);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user