2013-11-14 20:55:18 +00:00
|
|
|
#include "simplescript.h"
|
2014-02-09 12:47:47 +00:00
|
|
|
#include "value.h"
|
2013-11-14 20:55:18 +00:00
|
|
|
#include "console.h"
|
2014-02-09 20:44:05 +00:00
|
|
|
#include "argument.h"
|
2014-02-10 20:32:17 +00:00
|
|
|
#include "variable.h"
|
2014-02-10 23:41:35 +00:00
|
|
|
#include "threading.h"
|
|
|
|
#include "x64_dbg.h"
|
2014-03-24 20:39:43 +00:00
|
|
|
#include "debugger.h"
|
2013-11-14 20:55:18 +00:00
|
|
|
|
2014-02-09 20:44:05 +00:00
|
|
|
static std::vector<LINEMAPENTRY> linemap;
|
|
|
|
static std::vector<SCRIPTBP> scriptbplist;
|
2014-03-24 20:39:43 +00:00
|
|
|
static std::vector<int> scriptstack;
|
2014-02-09 20:44:05 +00:00
|
|
|
static int scriptIp=0;
|
2014-04-21 23:39:09 +00:00
|
|
|
static bool volatile bAbort=false;
|
|
|
|
static bool volatile bIsRunning=false;
|
2014-02-09 14:30:30 +00:00
|
|
|
|
2014-02-09 21:02:28 +00:00
|
|
|
static SCRIPTBRANCHTYPE scriptgetbranchtype(const char* text)
|
2014-02-09 14:30:30 +00:00
|
|
|
{
|
2014-02-10 21:05:23 +00:00
|
|
|
char newtext[MAX_SCRIPT_LINE_SIZE]="";
|
|
|
|
strcpy(newtext, text);
|
|
|
|
argformat(newtext); //format jump commands
|
2014-02-10 22:08:19 +00:00
|
|
|
if(!strstr(newtext, " "))
|
|
|
|
strcat(newtext, " ");
|
2014-02-10 21:44:35 +00:00
|
|
|
if(!strncmp(newtext, "jmp ", 4) or !strncmp(newtext, "goto ", 5))
|
2014-02-09 20:44:05 +00:00
|
|
|
return scriptjmp;
|
2014-02-10 21:44:35 +00:00
|
|
|
else if(!strncmp(newtext, "jbe ", 4) or !strncmp(newtext, "ifbe ", 5) or !strncmp(newtext, "ifbeq ", 6) or !strncmp(newtext, "jle ", 4) or !strncmp(newtext, "ifle ", 5) or !strncmp(newtext, "ifleq ", 6))
|
|
|
|
return scriptjbejle;
|
|
|
|
else if(!strncmp(newtext, "jae ", 4) or !strncmp(newtext, "ifae ", 5) or !strncmp(newtext, "ifaeq ", 6) or !strncmp(newtext, "jge ", 4) or !strncmp(newtext, "ifge ", 5) or !strncmp(newtext, "ifgeq ", 6))
|
|
|
|
return scriptjaejge;
|
|
|
|
else if(!strncmp(newtext, "jne ", 4) or !strncmp(newtext, "ifne ", 5) or !strncmp(newtext, "ifneq ", 6) or !strncmp(newtext, "jnz ", 4) or !strncmp(newtext, "ifnz ", 5))
|
2014-02-09 20:44:05 +00:00
|
|
|
return scriptjnejnz;
|
2014-02-10 21:44:35 +00:00
|
|
|
else if(!strncmp(newtext, "je ", 3) or !strncmp(newtext, "ife ", 4) or !strncmp(newtext, "ifeq ", 5) or !strncmp(newtext, "jz ", 3) or !strncmp(newtext, "ifz ", 4))
|
2014-02-10 20:40:06 +00:00
|
|
|
return scriptjejz;
|
2014-02-10 21:44:35 +00:00
|
|
|
else if(!strncmp(newtext, "jb ", 3) or !strncmp(newtext, "ifb ", 4) or !strncmp(newtext, "jl ", 3) or !strncmp(newtext, "ifl ", 4))
|
2014-02-10 20:40:06 +00:00
|
|
|
return scriptjbjl;
|
2014-02-10 21:44:35 +00:00
|
|
|
else if(!strncmp(newtext, "ja ", 3) or !strncmp(newtext, "ifa ", 4) or !strncmp(newtext, "jg ", 3) or !strncmp(newtext, "ifg ", 4))
|
2014-02-10 20:40:06 +00:00
|
|
|
return scriptjajg;
|
2014-03-24 20:39:43 +00:00
|
|
|
else if(!strncmp(newtext, "call ", 5))
|
|
|
|
return scriptcall;
|
2014-02-09 20:44:05 +00:00
|
|
|
return scriptnobranch;
|
2014-02-09 14:30:30 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 21:02:28 +00:00
|
|
|
static int scriptlabelfind(const char* labelname)
|
|
|
|
{
|
|
|
|
int linecount=linemap.size();
|
|
|
|
for(int i=0; i<linecount; i++)
|
|
|
|
if(linemap.at(i).type==linelabel && !strcmp(linemap.at(i).u.label, labelname))
|
|
|
|
return i+1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-26 18:41:03 +00:00
|
|
|
static int scriptinternalstep(int fromIp) //internal step routine
|
|
|
|
{
|
|
|
|
int maxIp=linemap.size(); //maximum ip
|
|
|
|
if(fromIp>=maxIp) //script end
|
|
|
|
return fromIp;
|
|
|
|
while((linemap.at(fromIp).type==lineempty or linemap.at(fromIp).type==linecomment or linemap.at(fromIp).type==linelabel) and fromIp<maxIp) //skip empty lines
|
|
|
|
fromIp++;
|
|
|
|
fromIp++;
|
|
|
|
return fromIp;
|
|
|
|
}
|
|
|
|
|
2014-02-09 21:02:28 +00:00
|
|
|
static bool scriptcreatelinemap(const char* filename)
|
2014-02-09 14:30:30 +00:00
|
|
|
{
|
2014-02-09 20:44:05 +00:00
|
|
|
HANDLE hFile=CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
|
|
|
if(hFile==INVALID_HANDLE_VALUE)
|
2014-02-10 20:01:20 +00:00
|
|
|
{
|
|
|
|
GuiScriptError(0, "CreateFile failed...");
|
2014-02-09 20:44:05 +00:00
|
|
|
return false;
|
2014-02-10 20:01:20 +00:00
|
|
|
}
|
2014-02-09 20:44:05 +00:00
|
|
|
unsigned int filesize=GetFileSize(hFile, 0);
|
2014-05-18 12:13:07 +00:00
|
|
|
if(!filesize)
|
|
|
|
{
|
|
|
|
CloseHandle(hFile);
|
|
|
|
GuiScriptError(0, "Empty script...");
|
|
|
|
return false;
|
|
|
|
}
|
2014-02-09 20:44:05 +00:00
|
|
|
char* filedata=(char*)emalloc(filesize+1, "createlinemap:filedata");
|
|
|
|
memset(filedata, 0, filesize+1);
|
|
|
|
DWORD read=0;
|
|
|
|
if(!ReadFile(hFile, filedata, filesize, &read, 0))
|
|
|
|
{
|
|
|
|
CloseHandle(hFile);
|
|
|
|
GuiScriptError(0, "ReadFile failed...");
|
|
|
|
efree(filedata, "createlinemap:filedata");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
|
|
int len=strlen(filedata);
|
|
|
|
char temp[256]="";
|
|
|
|
LINEMAPENTRY entry;
|
|
|
|
memset(&entry, 0, sizeof(entry));
|
2014-02-18 13:36:32 +00:00
|
|
|
std::vector<LINEMAPENTRY>().swap(linemap);
|
2014-02-09 20:44:05 +00:00
|
|
|
for(int i=0,j=0; i<len; i++) //make raw line map
|
|
|
|
{
|
|
|
|
if(filedata[i]=='\r' and filedata[i+1]=='\n') //windows file
|
|
|
|
{
|
|
|
|
memset(&entry, 0, sizeof(entry));
|
2014-04-26 18:41:03 +00:00
|
|
|
int add=0;
|
|
|
|
while(temp[add]==' ')
|
|
|
|
add++;
|
|
|
|
strcpy(entry.raw, temp+add);
|
2014-02-09 20:44:05 +00:00
|
|
|
*temp=0;
|
|
|
|
j=0;
|
|
|
|
i++;
|
|
|
|
linemap.push_back(entry);
|
|
|
|
}
|
|
|
|
else if(filedata[i]=='\n') //other file
|
|
|
|
{
|
|
|
|
memset(&entry, 0, sizeof(entry));
|
2014-04-26 18:41:03 +00:00
|
|
|
int add=0;
|
|
|
|
while(temp[add]==' ')
|
|
|
|
add++;
|
|
|
|
strcpy(entry.raw, temp+add);
|
2014-02-09 20:44:05 +00:00
|
|
|
*temp=0;
|
|
|
|
j=0;
|
|
|
|
linemap.push_back(entry);
|
|
|
|
}
|
|
|
|
else if(j>=254)
|
|
|
|
{
|
|
|
|
memset(&entry, 0, sizeof(entry));
|
2014-04-26 18:41:03 +00:00
|
|
|
int add=0;
|
|
|
|
while(temp[add]==' ')
|
|
|
|
add++;
|
|
|
|
strcpy(entry.raw, temp+add);
|
2014-02-09 20:44:05 +00:00
|
|
|
*temp=0;
|
|
|
|
j=0;
|
|
|
|
linemap.push_back(entry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
j+=sprintf(temp+j, "%c", filedata[i]);
|
|
|
|
}
|
|
|
|
if(*temp)
|
|
|
|
{
|
|
|
|
memset(&entry, 0, sizeof(entry));
|
|
|
|
strcpy(entry.raw, temp);
|
|
|
|
linemap.push_back(entry);
|
|
|
|
}
|
|
|
|
efree(filedata, "createlinemap:filedata");
|
|
|
|
unsigned int linemapsize=linemap.size();
|
2014-04-26 18:41:03 +00:00
|
|
|
while(!*linemap.at(linemapsize-1).raw) //remove empty lines from the end
|
2014-02-09 20:44:05 +00:00
|
|
|
{
|
|
|
|
linemapsize--;
|
|
|
|
linemap.pop_back();
|
|
|
|
}
|
|
|
|
for(unsigned int i=0; i<linemapsize; i++)
|
|
|
|
{
|
|
|
|
LINEMAPENTRY cur=linemap.at(i);
|
2014-04-26 18:41:03 +00:00
|
|
|
|
|
|
|
//temp. remove comments from the raw line
|
|
|
|
char line_comment[256]="";
|
|
|
|
char* comment=strstr(&cur.raw[0], "//");
|
|
|
|
if(comment && comment!=cur.raw) //only when the line doesnt start with a comment
|
|
|
|
{
|
|
|
|
if(*(comment-1)==' ') //space before comment
|
|
|
|
{
|
|
|
|
strcpy(line_comment, comment);
|
|
|
|
*(comment-1)='\0';
|
|
|
|
}
|
|
|
|
else //no space before comment
|
|
|
|
{
|
|
|
|
strcpy(line_comment, comment);
|
2014-06-10 13:56:42 +00:00
|
|
|
*comment=0;
|
2014-04-26 18:41:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-09 20:44:05 +00:00
|
|
|
int rawlen=strlen(cur.raw);
|
|
|
|
if(!strlen(cur.raw)) //empty
|
|
|
|
{
|
|
|
|
cur.type=lineempty;
|
|
|
|
}
|
|
|
|
else if(!strncmp(cur.raw, "//", 2)) //comment
|
|
|
|
{
|
|
|
|
cur.type=linecomment;
|
|
|
|
strcpy(cur.u.comment, cur.raw);
|
|
|
|
}
|
2014-02-10 21:05:23 +00:00
|
|
|
else if(cur.raw[rawlen-1]==':') //label
|
2014-02-09 20:44:05 +00:00
|
|
|
{
|
|
|
|
cur.type=linelabel;
|
2014-02-10 21:05:23 +00:00
|
|
|
sprintf(cur.u.label, "l %.*s", rawlen-1, cur.raw); //create a fake command for formatting
|
|
|
|
argformat(cur.u.label); //format labels
|
|
|
|
strcpy(cur.u.label, cur.u.label+2); //remove fake command
|
2014-02-10 22:08:19 +00:00
|
|
|
if(!*cur.u.label or !strcmp(cur.u.label, "\"\"")) //no label text
|
|
|
|
{
|
|
|
|
char message[256]="";
|
|
|
|
sprintf(message, "Empty label detected on line %d!", i+1);
|
|
|
|
GuiScriptError(0, message);
|
2014-02-18 13:36:32 +00:00
|
|
|
std::vector<LINEMAPENTRY>().swap(linemap);
|
2014-02-10 22:08:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
2014-02-09 21:02:28 +00:00
|
|
|
int foundlabel=scriptlabelfind(cur.u.label);
|
|
|
|
if(foundlabel) //label defined twice
|
|
|
|
{
|
|
|
|
char message[256]="";
|
|
|
|
sprintf(message, "Duplicate label \"%s\" detected on lines %d and %d!", cur.u.label, foundlabel, i+1);
|
|
|
|
GuiScriptError(0, message);
|
2014-02-18 13:36:32 +00:00
|
|
|
std::vector<LINEMAPENTRY>().swap(linemap);
|
2014-02-09 21:02:28 +00:00
|
|
|
return false;
|
|
|
|
}
|
2014-02-09 20:44:05 +00:00
|
|
|
}
|
2014-02-09 21:02:28 +00:00
|
|
|
else if(scriptgetbranchtype(cur.raw)!=scriptnobranch) //branch
|
2014-02-09 20:44:05 +00:00
|
|
|
{
|
|
|
|
cur.type=linebranch;
|
2014-02-09 21:02:28 +00:00
|
|
|
cur.u.branch.type=scriptgetbranchtype(cur.raw);
|
2014-02-10 21:05:23 +00:00
|
|
|
char newraw[MAX_SCRIPT_LINE_SIZE]="";
|
|
|
|
strcpy(newraw, cur.raw);
|
|
|
|
argformat(newraw);
|
|
|
|
int len=strlen(newraw);
|
2014-02-09 20:44:05 +00:00
|
|
|
for(int i=0; i<len; i++)
|
2014-02-10 21:05:23 +00:00
|
|
|
if(newraw[i]==' ')
|
2014-02-09 20:44:05 +00:00
|
|
|
{
|
2014-02-10 21:05:23 +00:00
|
|
|
strcpy(cur.u.branch.branchlabel, newraw+i+1);
|
2014-02-09 20:44:05 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cur.type=linecommand;
|
2014-04-26 18:41:03 +00:00
|
|
|
strcpy(cur.u.command, cur.raw);
|
2014-02-09 20:44:05 +00:00
|
|
|
}
|
2014-04-26 18:41:03 +00:00
|
|
|
|
|
|
|
//append the comment to the raw line again
|
|
|
|
if(*line_comment)
|
|
|
|
sprintf(cur.raw+rawlen, " %s", line_comment);
|
2014-02-09 20:44:05 +00:00
|
|
|
linemap.at(i)=cur;
|
|
|
|
}
|
|
|
|
linemapsize=linemap.size();
|
2014-02-09 21:02:28 +00:00
|
|
|
for(unsigned int i=0; i<linemapsize; i++)
|
|
|
|
{
|
2014-04-26 18:41:03 +00:00
|
|
|
if(linemap.at(i).type==linebranch) //invalid branch label
|
2014-02-09 21:02:28 +00:00
|
|
|
{
|
2014-04-26 18:41:03 +00:00
|
|
|
int labelline=scriptlabelfind(linemap.at(i).u.branch.branchlabel);
|
|
|
|
if(!labelline) //invalid branch label
|
|
|
|
{
|
|
|
|
char message[256]="";
|
|
|
|
sprintf(message, "Invalid branch label \"%s\" detected on line %d!", linemap.at(i).u.branch.branchlabel, i+1);
|
|
|
|
GuiScriptError(0, message);
|
|
|
|
std::vector<LINEMAPENTRY>().swap(linemap);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else //set the branch destination line
|
|
|
|
linemap.at(i).u.branch.dest=scriptinternalstep(labelline);
|
2014-02-09 21:02:28 +00:00
|
|
|
}
|
|
|
|
}
|
2014-02-09 20:44:05 +00:00
|
|
|
if(linemap.at(linemapsize-1).type==linecomment or linemap.at(linemapsize-1).type==linelabel) //label/comment on the end
|
|
|
|
{
|
|
|
|
memset(&entry, 0, sizeof(entry));
|
|
|
|
entry.type=linecommand;
|
|
|
|
strcpy(entry.raw, "ret");
|
|
|
|
strcpy(entry.u.command, "ret");
|
|
|
|
linemap.push_back(entry);
|
|
|
|
}
|
|
|
|
return true;
|
2014-02-09 14:30:30 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 20:44:05 +00:00
|
|
|
static bool scriptinternalbpget(int line) //internal bpget routine
|
2014-02-09 14:30:30 +00:00
|
|
|
{
|
2014-02-09 20:44:05 +00:00
|
|
|
int bpcount=scriptbplist.size();
|
|
|
|
for(int i=0; i<bpcount; i++)
|
|
|
|
if(scriptbplist.at(i).line==line)
|
|
|
|
return true;
|
2014-02-09 14:30:30 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-02-09 20:44:05 +00:00
|
|
|
static bool scriptinternalbptoggle(int line) //internal breakpoint
|
2014-02-09 14:30:30 +00:00
|
|
|
{
|
2014-02-09 20:44:05 +00:00
|
|
|
if(!line or line>(int)linemap.size()) //invalid line
|
|
|
|
return false;
|
|
|
|
line=scriptinternalstep(line-1); //no breakpoints on non-executable locations
|
|
|
|
if(scriptinternalbpget(line)) //remove breakpoint
|
|
|
|
{
|
|
|
|
int bpcount=scriptbplist.size();
|
|
|
|
for(int i=0; i<bpcount; i++)
|
|
|
|
if(scriptbplist.at(i).line==line)
|
|
|
|
{
|
|
|
|
scriptbplist.erase(scriptbplist.begin()+i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else //add breakpoint
|
|
|
|
{
|
|
|
|
SCRIPTBP newbp;
|
|
|
|
newbp.silent=true;
|
|
|
|
newbp.line=line;
|
|
|
|
scriptbplist.push_back(newbp);
|
|
|
|
}
|
2014-02-09 14:30:30 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-02-22 15:24:31 +00:00
|
|
|
static bool scriptisruncommand(const char* cmdlist)
|
2014-02-10 23:41:35 +00:00
|
|
|
{
|
|
|
|
if(arraycontains(cmdlist, "run"))
|
|
|
|
return true;
|
|
|
|
else if(arraycontains(cmdlist, "erun"))
|
|
|
|
return true;
|
|
|
|
else if(arraycontains(cmdlist, "sti"))
|
|
|
|
return true;
|
|
|
|
else if(arraycontains(cmdlist, "esti"))
|
|
|
|
return true;
|
|
|
|
else if(arraycontains(cmdlist, "step"))
|
|
|
|
return true;
|
|
|
|
else if(arraycontains(cmdlist, "estep"))
|
|
|
|
return true;
|
|
|
|
else if(arraycontains(cmdlist, "sstep"))
|
|
|
|
return true;
|
|
|
|
else if(arraycontains(cmdlist, "rtr"))
|
|
|
|
return true;
|
|
|
|
else if(arraycontains(cmdlist, "ertr"))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-04-22 17:25:37 +00:00
|
|
|
static bool scriptisinternalcommand(const char* text, const char* cmd)
|
|
|
|
{
|
|
|
|
int len=strlen(text);
|
|
|
|
int cmdlen=strlen(cmd);
|
|
|
|
if(cmdlen>len)
|
|
|
|
return false;
|
|
|
|
else if(cmdlen==len)
|
|
|
|
return scmp(text, cmd);
|
|
|
|
else if(text[cmdlen]==' ')
|
2014-06-10 13:56:42 +00:00
|
|
|
return (!_strnicmp(text, cmd, cmdlen));
|
2014-04-22 17:25:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-03-24 20:39:43 +00:00
|
|
|
static CMDRESULT scriptinternalcmdexec(const char* cmd)
|
2014-02-09 14:30:30 +00:00
|
|
|
{
|
2014-04-22 17:25:37 +00:00
|
|
|
if(scriptisinternalcommand(cmd, "ret")) //script finished
|
2014-02-09 20:44:05 +00:00
|
|
|
{
|
2014-03-24 20:39:43 +00:00
|
|
|
if(!scriptstack.size()) //nothing on the stack
|
|
|
|
{
|
|
|
|
GuiScriptMessage("Script finished!");
|
|
|
|
return STATUS_EXIT;
|
|
|
|
}
|
|
|
|
scriptIp=scriptstack.back(); //set scriptIp to the call address (scriptinternalstep will step over it)
|
|
|
|
scriptstack.pop_back(); //remove last stack entry
|
|
|
|
return STATUS_CONTINUE;
|
2014-02-09 20:44:05 +00:00
|
|
|
}
|
2014-04-22 17:25:37 +00:00
|
|
|
else if(scriptisinternalcommand(cmd, "invalid")) //invalid command for testing
|
2014-02-09 20:44:05 +00:00
|
|
|
return STATUS_ERROR;
|
2014-04-22 17:25:37 +00:00
|
|
|
else if(scriptisinternalcommand(cmd, "pause")) //pause the script
|
2014-03-24 20:39:43 +00:00
|
|
|
return STATUS_PAUSE;
|
2014-04-26 18:41:03 +00:00
|
|
|
else if(scriptisinternalcommand(cmd, "nop")) //do nothing
|
|
|
|
return STATUS_CONTINUE;
|
2014-03-24 20:39:43 +00:00
|
|
|
char command[deflen]="";
|
|
|
|
strcpy(command, cmd);
|
|
|
|
argformat(command);
|
|
|
|
COMMAND* found=cmdfindmain(dbggetcommandlist(), command);
|
|
|
|
if(!found) //invalid command
|
2014-02-10 23:41:35 +00:00
|
|
|
return STATUS_ERROR;
|
2014-03-24 20:39:43 +00:00
|
|
|
if(arraycontains(found->name, "var")) //var
|
2014-02-22 15:24:31 +00:00
|
|
|
{
|
|
|
|
cmddirectexec(dbggetcommandlist(), command);
|
|
|
|
return STATUS_CONTINUE;
|
|
|
|
}
|
2014-03-24 20:39:43 +00:00
|
|
|
CMDRESULT res=cmddirectexec(dbggetcommandlist(), command);
|
2014-04-14 21:02:32 +00:00
|
|
|
if(DbgIsDebugging())
|
2014-03-24 20:39:43 +00:00
|
|
|
{
|
|
|
|
while(!waitislocked(WAITID_RUN)) //while not locked (NOTE: possible deadlock)
|
|
|
|
Sleep(10);
|
|
|
|
}
|
|
|
|
return res;
|
2014-02-09 14:30:30 +00:00
|
|
|
}
|
|
|
|
|
2014-02-10 20:32:17 +00:00
|
|
|
static bool scriptinternalbranch(SCRIPTBRANCHTYPE type) //determine if we should jump
|
|
|
|
{
|
|
|
|
uint ezflag=0;
|
|
|
|
uint bsflag=0;
|
|
|
|
varget("$_EZ_FLAG", &ezflag, 0, 0);
|
|
|
|
varget("$_BS_FLAG", &bsflag, 0, 0);
|
|
|
|
bool bJump=false;
|
|
|
|
switch(type)
|
|
|
|
{
|
2014-03-24 20:39:43 +00:00
|
|
|
case scriptcall:
|
2014-02-10 20:32:17 +00:00
|
|
|
case scriptjmp:
|
|
|
|
bJump=true;
|
|
|
|
break;
|
|
|
|
case scriptjnejnz: //$_EZ_FLAG=0
|
|
|
|
if(!ezflag)
|
|
|
|
bJump=true;
|
|
|
|
break;
|
|
|
|
case scriptjejz: //$_EZ_FLAG=1
|
|
|
|
if(ezflag)
|
|
|
|
bJump=true;
|
|
|
|
break;
|
|
|
|
case scriptjbjl: //$_BS_FLAG=0 and $_EZ_FLAG=0 //below, not equal
|
|
|
|
if(!bsflag and !ezflag)
|
|
|
|
bJump=true;
|
|
|
|
break;
|
|
|
|
case scriptjajg: //$_BS_FLAG=1 and $_EZ_FLAG=0 //above, not equal
|
|
|
|
if(bsflag and !ezflag)
|
|
|
|
bJump=true;
|
|
|
|
break;
|
|
|
|
case scriptjbejle: //$_BS_FLAG=0 or $_EZ_FLAG=1
|
|
|
|
if(!bsflag or ezflag)
|
|
|
|
bJump=true;
|
|
|
|
break;
|
|
|
|
case scriptjaejge: //$_BS_FLAG=1 or $_EZ_FLAG=1
|
|
|
|
if(bsflag or ezflag)
|
|
|
|
bJump=true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
bJump=false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return bJump;
|
|
|
|
}
|
|
|
|
|
2014-02-10 20:01:20 +00:00
|
|
|
static bool scriptinternalcmd()
|
|
|
|
{
|
|
|
|
bool bContinue=true;
|
|
|
|
LINEMAPENTRY cur=linemap.at(scriptIp-1);
|
|
|
|
if(cur.type==linecommand)
|
|
|
|
{
|
|
|
|
switch(scriptinternalcmdexec(cur.u.command))
|
|
|
|
{
|
|
|
|
case STATUS_CONTINUE:
|
|
|
|
break;
|
|
|
|
case STATUS_ERROR:
|
|
|
|
bContinue=false;
|
|
|
|
GuiScriptError(scriptIp, "Error executing command!");
|
|
|
|
break;
|
|
|
|
case STATUS_EXIT:
|
|
|
|
bContinue=false;
|
|
|
|
scriptIp=scriptinternalstep(0);
|
|
|
|
GuiScriptSetIp(scriptIp);
|
|
|
|
break;
|
2014-03-24 20:39:43 +00:00
|
|
|
case STATUS_PAUSE:
|
|
|
|
bContinue=false; //stop running the script
|
|
|
|
scriptIp=scriptinternalstep(scriptIp);
|
|
|
|
GuiScriptSetIp(scriptIp);
|
|
|
|
break;
|
2014-02-10 20:01:20 +00:00
|
|
|
}
|
|
|
|
}
|
2014-03-24 20:39:43 +00:00
|
|
|
else if(cur.type==linebranch)
|
|
|
|
{
|
|
|
|
if(cur.u.branch.type==scriptcall) //calls have a special meaning
|
|
|
|
scriptstack.push_back(scriptIp);
|
|
|
|
if(scriptinternalbranch(cur.u.branch.type))
|
|
|
|
scriptIp=scriptlabelfind(cur.u.branch.branchlabel);
|
|
|
|
}
|
2014-02-10 20:01:20 +00:00
|
|
|
return bContinue;
|
|
|
|
}
|
|
|
|
|
2014-02-09 21:02:28 +00:00
|
|
|
static DWORD WINAPI scriptRunThread(void* arg)
|
2013-11-14 20:55:18 +00:00
|
|
|
{
|
2014-02-10 20:32:17 +00:00
|
|
|
int destline=(int)(uint)arg;
|
2014-02-09 20:44:05 +00:00
|
|
|
if(!destline or destline>(int)linemap.size()) //invalid line
|
|
|
|
destline=0;
|
|
|
|
if(destline)
|
2014-02-09 12:34:48 +00:00
|
|
|
{
|
2014-02-09 20:44:05 +00:00
|
|
|
destline=scriptinternalstep(destline-1); //no breakpoints on non-executable locations
|
|
|
|
if(!scriptinternalbpget(destline)) //no breakpoint set
|
|
|
|
scriptinternalbptoggle(destline);
|
2014-02-09 12:34:48 +00:00
|
|
|
}
|
2014-02-09 20:44:05 +00:00
|
|
|
bAbort=false;
|
|
|
|
if(scriptIp)
|
|
|
|
scriptIp--;
|
|
|
|
scriptIp=scriptinternalstep(scriptIp);
|
|
|
|
bool bContinue=true;
|
|
|
|
while(bContinue && !bAbort) //run loop
|
|
|
|
{
|
2014-02-10 20:01:20 +00:00
|
|
|
bContinue=scriptinternalcmd();
|
2014-02-09 20:44:05 +00:00
|
|
|
if(scriptIp==scriptinternalstep(scriptIp)) //end of script
|
|
|
|
{
|
|
|
|
bContinue=false;
|
|
|
|
scriptIp=scriptinternalstep(0);
|
|
|
|
}
|
|
|
|
if(bContinue)
|
|
|
|
scriptIp=scriptinternalstep(scriptIp); //this is the next ip
|
|
|
|
if(scriptinternalbpget(scriptIp)) //breakpoint=stop run loop
|
|
|
|
bContinue=false;
|
|
|
|
Sleep(1); //don't fry the processor
|
|
|
|
}
|
|
|
|
bIsRunning=false; //not running anymore
|
|
|
|
GuiScriptSetIp(scriptIp);
|
|
|
|
return 0;
|
2013-11-14 20:55:18 +00:00
|
|
|
}
|
|
|
|
|
2014-02-13 14:42:53 +00:00
|
|
|
static DWORD WINAPI scriptLoadThread(void* filename)
|
2013-11-14 20:55:18 +00:00
|
|
|
{
|
2014-02-09 12:34:48 +00:00
|
|
|
GuiScriptClear();
|
2014-05-20 23:18:20 +00:00
|
|
|
GuiScriptEnableHighlighting(true); //enable default script syntax highlighting
|
2014-02-09 20:44:05 +00:00
|
|
|
scriptIp=0;
|
2014-02-18 13:36:32 +00:00
|
|
|
std::vector<SCRIPTBP>().swap(scriptbplist); //clear breakpoints
|
2014-03-24 20:39:43 +00:00
|
|
|
std::vector<int>().swap(scriptstack); //clear script stack
|
2014-02-09 20:44:05 +00:00
|
|
|
bAbort=false;
|
2014-02-13 14:42:53 +00:00
|
|
|
if(!scriptcreatelinemap((const char*)filename))
|
|
|
|
return 0;
|
|
|
|
int lines=linemap.size();
|
|
|
|
const char** script=(const char**)BridgeAlloc(lines*sizeof(const char*));
|
|
|
|
for(int i=0; i<lines; i++) //add script lines
|
|
|
|
script[i]=linemap.at(i).raw;
|
|
|
|
GuiScriptAdd(lines, script);
|
2014-02-09 20:44:05 +00:00
|
|
|
scriptIp=scriptinternalstep(0);
|
|
|
|
GuiScriptSetIp(scriptIp);
|
2014-02-13 14:42:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void scriptload(const char* filename)
|
|
|
|
{
|
|
|
|
static char filename_[MAX_PATH]="";
|
|
|
|
strcpy(filename_, filename);
|
2014-04-21 23:39:09 +00:00
|
|
|
CloseHandle(CreateThread(0, 0, scriptLoadThread, filename_, 0, 0));
|
2013-11-14 20:55:18 +00:00
|
|
|
}
|
2014-02-09 12:47:47 +00:00
|
|
|
|
2014-02-09 20:44:05 +00:00
|
|
|
void scriptunload()
|
2014-02-09 12:47:47 +00:00
|
|
|
{
|
2014-02-09 20:44:05 +00:00
|
|
|
GuiScriptClear();
|
|
|
|
scriptIp=0;
|
2014-02-18 13:36:32 +00:00
|
|
|
std::vector<SCRIPTBP>().swap(scriptbplist); //clear breakpoints
|
2014-02-09 20:44:05 +00:00
|
|
|
bAbort=false;
|
2014-02-09 12:47:47 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 20:44:05 +00:00
|
|
|
void scriptrun(int destline)
|
2014-02-09 12:47:47 +00:00
|
|
|
{
|
2014-05-18 12:13:07 +00:00
|
|
|
if(DbgIsDebugging() && !waitislocked(WAITID_RUN))
|
2014-04-21 23:39:09 +00:00
|
|
|
{
|
|
|
|
GuiScriptError(0, "Debugger must be paused to run a script!");
|
|
|
|
return;
|
|
|
|
}
|
2014-02-09 20:44:05 +00:00
|
|
|
if(bIsRunning) //already running
|
|
|
|
return;
|
|
|
|
bIsRunning=true;
|
2014-04-21 23:39:09 +00:00
|
|
|
CloseHandle(CreateThread(0, 0, scriptRunThread, (void*)(uint)destline, 0, 0));
|
2014-02-09 12:47:47 +00:00
|
|
|
}
|
|
|
|
|
2014-02-13 14:42:53 +00:00
|
|
|
DWORD WINAPI scriptStepThread(void* param)
|
2014-02-09 12:47:47 +00:00
|
|
|
{
|
2014-02-09 20:44:05 +00:00
|
|
|
if(bIsRunning) //already running
|
2014-02-13 14:42:53 +00:00
|
|
|
return 0;
|
2014-02-09 20:44:05 +00:00
|
|
|
scriptIp=scriptinternalstep(scriptIp-1); //probably useless
|
2014-02-10 20:01:20 +00:00
|
|
|
if(!scriptinternalcmd())
|
2014-02-13 14:42:53 +00:00
|
|
|
return 0;
|
2014-02-09 20:44:05 +00:00
|
|
|
if(scriptIp==scriptinternalstep(scriptIp)) //end of script
|
|
|
|
scriptIp=0;
|
|
|
|
scriptIp=scriptinternalstep(scriptIp);
|
|
|
|
GuiScriptSetIp(scriptIp);
|
2014-02-13 14:42:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void scriptstep()
|
|
|
|
{
|
2014-04-21 23:39:09 +00:00
|
|
|
CloseHandle(CreateThread(0, 0, scriptStepThread, 0, 0, 0));
|
2014-02-09 12:47:47 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 20:44:05 +00:00
|
|
|
bool scriptbptoggle(int line)
|
2014-02-09 12:47:47 +00:00
|
|
|
{
|
2014-02-09 20:44:05 +00:00
|
|
|
if(!line or line>(int)linemap.size()) //invalid line
|
|
|
|
return false;
|
|
|
|
line=scriptinternalstep(line-1); //no breakpoints on non-executable locations
|
|
|
|
if(scriptbpget(line)) //remove breakpoint
|
2014-02-09 12:47:47 +00:00
|
|
|
{
|
2014-02-09 20:44:05 +00:00
|
|
|
int bpcount=scriptbplist.size();
|
|
|
|
for(int i=0; i<bpcount; i++)
|
|
|
|
if(scriptbplist.at(i).line==line && !scriptbplist.at(i).silent)
|
|
|
|
{
|
|
|
|
scriptbplist.erase(scriptbplist.begin()+i);
|
|
|
|
break;
|
|
|
|
}
|
2014-02-09 12:47:47 +00:00
|
|
|
}
|
2014-02-09 20:44:05 +00:00
|
|
|
else //add breakpoint
|
|
|
|
{
|
|
|
|
SCRIPTBP newbp;
|
|
|
|
newbp.silent=false;
|
|
|
|
newbp.line=line;
|
|
|
|
scriptbplist.push_back(newbp);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool scriptbpget(int line)
|
|
|
|
{
|
|
|
|
int bpcount=scriptbplist.size();
|
|
|
|
for(int i=0; i<bpcount; i++)
|
|
|
|
if(scriptbplist.at(i).line==line && !scriptbplist.at(i).silent)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool scriptcmdexec(const char* command)
|
|
|
|
{
|
2014-02-09 21:23:22 +00:00
|
|
|
switch(scriptinternalcmdexec(command))
|
|
|
|
{
|
|
|
|
case STATUS_ERROR:
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
case STATUS_EXIT:
|
|
|
|
scriptIp=scriptinternalstep(0);
|
|
|
|
GuiScriptSetIp(scriptIp);
|
|
|
|
break;
|
2014-03-24 20:39:43 +00:00
|
|
|
case STATUS_PAUSE:
|
2014-02-09 21:23:22 +00:00
|
|
|
case STATUS_CONTINUE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
2014-02-09 20:44:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void scriptabort()
|
|
|
|
{
|
|
|
|
if(bIsRunning)
|
|
|
|
bAbort=true;
|
2014-04-21 23:39:09 +00:00
|
|
|
else //reset the script
|
|
|
|
scriptsetip(0);
|
2014-02-09 20:44:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SCRIPTLINETYPE scriptgetlinetype(int line)
|
|
|
|
{
|
|
|
|
if(line>(int)linemap.size())
|
|
|
|
return lineempty;
|
|
|
|
return linemap.at(line-1).type;
|
2014-02-09 12:47:47 +00:00
|
|
|
}
|
2014-02-09 21:23:22 +00:00
|
|
|
|
|
|
|
void scriptsetip(int line)
|
|
|
|
{
|
|
|
|
if(line)
|
|
|
|
line--;
|
|
|
|
scriptIp=scriptinternalstep(line);
|
|
|
|
GuiScriptSetIp(scriptIp);
|
|
|
|
}
|
2014-02-13 14:42:53 +00:00
|
|
|
|
2014-04-21 23:39:09 +00:00
|
|
|
void scriptreset()
|
|
|
|
{
|
|
|
|
while(bIsRunning)
|
|
|
|
{
|
|
|
|
bAbort=true;
|
|
|
|
Sleep(1);
|
|
|
|
}
|
|
|
|
Sleep(10);
|
|
|
|
scriptsetip(0);
|
|
|
|
}
|
|
|
|
|
2014-04-26 18:41:03 +00:00
|
|
|
bool scriptgetbranchinfo(int line, SCRIPTBRANCH* info)
|
|
|
|
{
|
|
|
|
if(!info or !line or line>(int)linemap.size()) //invalid line
|
|
|
|
return false;
|
|
|
|
if(linemap.at(line-1).type!=linebranch) //no branch
|
|
|
|
return false;
|
|
|
|
memcpy(info, &linemap.at(line-1).u.branch, sizeof(SCRIPTBRANCH));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-02-13 14:42:53 +00:00
|
|
|
CMDRESULT cbScriptLoad(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
if(argc<2)
|
|
|
|
return STATUS_ERROR;
|
|
|
|
scriptload(argv[1]);
|
|
|
|
return STATUS_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
CMDRESULT cbScriptMsg(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
if(argc<2)
|
|
|
|
{
|
|
|
|
dputs("not enough arguments!");
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
GuiScriptMessage(argv[1]);
|
|
|
|
return STATUS_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
CMDRESULT cbScriptMsgyn(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
if(argc<2)
|
|
|
|
{
|
|
|
|
dputs("not enough arguments!");
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
varset("$RESULT", GuiScriptMsgyn(argv[1]), false);
|
|
|
|
return STATUS_CONTINUE;
|
|
|
|
}
|