sqdbgserver.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. #include <squirrel.h>
  2. #include <assert.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <sqstdblob.h>
  7. #include "sqrdbg.h"
  8. #include "sqdbgserver.h"
  9. #ifndef _WIN32
  10. # define Sleep sleep
  11. # include <sys/types.h>
  12. # include <sys/socket.h>
  13. #endif
  14. #ifndef _UNICODE
  15. #define scstrcpy strcpy
  16. #else
  17. #define scstrcpy wcscpy
  18. #endif
  19. struct XMLEscape{
  20. const SQChar c;
  21. const SQChar *esc;
  22. };
  23. #define SQDBG_DEBUG_HOOK _SC("_sqdbg_debug_hook_")
  24. #define SQDBG_ERROR_HANDLER _SC("_sqdbg_error_handler_")
  25. XMLEscape g_escapes[]={
  26. {_SC('<'),_SC("&lt;")},{'>',_SC("&gt;")},{_SC('&'),_SC("&amp;")},{_SC('\''),_SC("&apos;")},{_SC('\"'),_SC("&quot;")},{_SC('\n'),_SC("&quot;n")},{_SC('\r'),_SC("&quot;r")},{NULL,NULL}
  27. };
  28. const SQChar *IntToString(SQInteger n)
  29. {
  30. static SQChar temp[256];
  31. scsprintf(temp,_SC("%d"),n);
  32. return temp;
  33. }
  34. const SQChar *PtrToString(void *p)
  35. {
  36. static SQChar temp[256];
  37. scsprintf(temp,_SC("%p"),p);
  38. return temp;
  39. }
  40. SQInteger debug_hook(HSQUIRRELVM v);
  41. SQInteger error_handler(HSQUIRRELVM v);
  42. SQInteger beginelement(HSQUIRRELVM v)
  43. {
  44. SQUserPointer up;
  45. const SQChar *name;
  46. sq_getuserpointer(v,-1,&up);
  47. SQDbgServer *self = (SQDbgServer*)up;
  48. sq_getuserpointer(v,-1,&up);
  49. sq_getstring(v,2,&name);
  50. self->BeginElement(name);
  51. return 0;
  52. }
  53. SQInteger endelement(HSQUIRRELVM v)
  54. {
  55. SQUserPointer up;
  56. const SQChar *name;
  57. sq_getuserpointer(v,-1,&up);
  58. SQDbgServer *self = (SQDbgServer*)up;
  59. sq_getuserpointer(v,-1,&up);
  60. sq_getstring(v,2,&name);
  61. self->EndElement(name);
  62. return 0;
  63. }
  64. SQInteger attribute(HSQUIRRELVM v)
  65. {
  66. SQUserPointer up;
  67. const SQChar *name,*value;
  68. sq_getuserpointer(v,-1,&up);
  69. SQDbgServer *self = (SQDbgServer*)up;
  70. sq_getuserpointer(v,-1,&up);
  71. sq_getstring(v,2,&name);
  72. sq_getstring(v,3,&value);
  73. self->Attribute(name,value);
  74. return 0;
  75. }
  76. SQDbgServer::SQDbgServer(HSQUIRRELVM v)
  77. {
  78. _ready = false;
  79. //_nestedcalls = 0;
  80. _autoupdate = false;
  81. _v = v;
  82. _state = eDBG_Running;
  83. _accept = INVALID_SOCKET;
  84. _endpoint = INVALID_SOCKET;
  85. //_maxrecursion = 10;
  86. sq_resetobject(&_debugroot);
  87. }
  88. SQDbgServer::~SQDbgServer()
  89. {
  90. VMStateMap::iterator itr = _vmstate.begin();
  91. while(itr != _vmstate.end()) {
  92. VMState *vs = itr->second;
  93. delete vs;
  94. ++itr;
  95. }
  96. _vmstate.clear();
  97. sq_pushobject(_v,_debugroot);
  98. sq_clear(_v,-1);
  99. sq_release(_v,&_debugroot);
  100. if(_accept != INVALID_SOCKET)
  101. sqdbg_closesocket(_accept);
  102. if(_endpoint != INVALID_SOCKET)
  103. sqdbg_closesocket(_endpoint);
  104. }
  105. bool SQDbgServer::Init()
  106. {
  107. //creates an environment table for the debugger
  108. sq_newtable(_v);
  109. sq_getstackobj(_v,-1,&_debugroot);
  110. sq_addref(_v,&_debugroot);
  111. //creates a emptyslot to store the watches
  112. sq_pushstring(_v,_SC("watches"),-1);
  113. sq_pushnull(_v);
  114. sq_newslot(_v,-3, SQFalse);
  115. sq_pushstring(_v,_SC("beginelement"),-1);
  116. sq_pushuserpointer(_v,this);
  117. sq_newclosure(_v,beginelement,1);
  118. sq_setparamscheck(_v,2,_SC(".s"));
  119. sq_newslot(_v,-3, SQFalse);
  120. sq_pushstring(_v,_SC("endelement"),-1);
  121. sq_pushuserpointer(_v,this);
  122. sq_newclosure(_v,endelement,1);
  123. sq_setparamscheck(_v,2,_SC(".s"));
  124. sq_newslot(_v,-3, SQFalse);
  125. sq_pushstring(_v,_SC("attribute"),-1);
  126. sq_pushuserpointer(_v,this);
  127. sq_newclosure(_v,attribute,1);
  128. sq_setparamscheck(_v,3,_SC(".ss"));
  129. sq_newslot(_v,-3, SQFalse);
  130. sq_pop(_v,1);
  131. //stores debug hook and error handler in the registry
  132. sq_pushregistrytable(_v);
  133. sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);
  134. sq_pushuserpointer(_v,this);
  135. sq_newclosure(_v,debug_hook,1);
  136. sq_newslot(_v,-3, SQFalse);
  137. sq_pushstring(_v,SQDBG_ERROR_HANDLER,-1);
  138. sq_pushuserpointer(_v,this);
  139. sq_newclosure(_v,error_handler,1);
  140. sq_newslot(_v,-3, SQFalse);
  141. sq_pop(_v,1);
  142. //sets the error handlers
  143. SetErrorHandlers(_v);
  144. return true;
  145. }
  146. bool SQDbgServer::ReadMsg()
  147. {
  148. return false;
  149. }
  150. void SQDbgServer::BusyWait()
  151. {
  152. while( !ReadMsg() )
  153. Sleep(0);
  154. }
  155. void SQDbgServer::SendChunk(const SQChar *chunk)
  156. {
  157. char *buf=NULL;
  158. int buf_len=0;
  159. #ifdef _UNICODE
  160. buf_len=(int)scstrlen(chunk)+1;
  161. buf=(char *)sq_getscratchpad(_v,(buf_len)*3);
  162. //wcstombs((char *)buf,chunk,buf_len*3);
  163. WideCharToMultiByte(CP_UTF8,0,chunk,-1,buf,buf_len*3,NULL,NULL);
  164. #else
  165. buf_len=(int)scstrlen(chunk);
  166. buf=(char *)chunk;
  167. #endif
  168. send(_endpoint,(const char*)buf,(int)strlen((const char *)buf),0);
  169. }
  170. void SQDbgServer::Terminated()
  171. {
  172. BeginElement(_SC("terminated"));
  173. EndElement(_SC("terminated"));
  174. ::Sleep(200);
  175. }
  176. VMState *SQDbgServer::GetVMState(HSQUIRRELVM v)
  177. {
  178. VMState *ret = NULL;
  179. VMStateMap::iterator itr = _vmstate.find(v);
  180. if(itr == _vmstate.end()) {
  181. ret = new VMState();
  182. _vmstate.insert(VMStateMap::value_type(v,ret));
  183. }
  184. else {
  185. ret = itr->second;
  186. }
  187. return ret;
  188. }
  189. void SQDbgServer::Hook(HSQUIRRELVM v,SQInteger type,SQInteger line,const SQChar *src,const SQChar *func)
  190. {
  191. VMState *vs = GetVMState(v);
  192. switch(_state){
  193. case eDBG_Running:
  194. if(type==_SC('l') && _breakpoints.size()) {
  195. BreakPointSetItor itr = _breakpoints.find(BreakPoint(line,src));
  196. if(itr != _breakpoints.end()) {
  197. Break(v,line,src,_SC("breakpoint"));
  198. BreakExecution();
  199. }
  200. }
  201. break;
  202. case eDBG_Suspended:
  203. vs->_nestedcalls=0;
  204. case eDBG_StepOver:
  205. switch(type){
  206. case _SC('l'):
  207. if(vs->_nestedcalls==0) {
  208. Break(v,line,src,_SC("step"));
  209. BreakExecution();
  210. }
  211. break;
  212. case _SC('c'):
  213. vs->_nestedcalls++;
  214. break;
  215. case _SC('r'):
  216. if(vs->_nestedcalls==0){
  217. vs->_nestedcalls=0;
  218. }else{
  219. vs->_nestedcalls--;
  220. }
  221. break;
  222. }
  223. break;
  224. case eDBG_StepInto:
  225. switch(type){
  226. case _SC('l'):
  227. vs->_nestedcalls=0;
  228. Break(v,line,src,_SC("step"));
  229. BreakExecution();
  230. break;
  231. }
  232. break;
  233. case eDBG_StepReturn:
  234. switch(type){
  235. case _SC('l'):
  236. break;
  237. case _SC('c'):
  238. vs->_nestedcalls++;
  239. break;
  240. case _SC('r'):
  241. if(vs->_nestedcalls==0){
  242. vs->_nestedcalls=0;
  243. _state=eDBG_StepOver;
  244. }else{
  245. vs->_nestedcalls--;
  246. }
  247. break;
  248. }
  249. break;
  250. case eDBG_Disabled:
  251. break;
  252. }
  253. }
  254. #define MSG_ID(x,y) ((y<<8)|x)
  255. //ab Add Breakpoint
  256. //rb Remove Breakpoint
  257. //sp Suspend
  258. void SQDbgServer::ParseMsg(const char *msg)
  259. {
  260. switch(*((unsigned short *)msg)){
  261. case MSG_ID('a','b'): {
  262. BreakPoint bp;
  263. if(ParseBreakpoint(msg+3,bp)){
  264. AddBreakpoint(bp);
  265. scprintf(_SC("added bp %d %s\n"),bp._line,bp._src.c_str());
  266. }
  267. else
  268. scprintf(_SC("error parsing add breakpoint"));
  269. }
  270. break;
  271. case MSG_ID('r','b'): {
  272. BreakPoint bp;
  273. if(ParseBreakpoint(msg+3,bp)){
  274. RemoveBreakpoint(bp);
  275. scprintf(_SC("removed bp %d %s\n"),bp._line,bp._src.c_str());
  276. }else
  277. scprintf(_SC("error parsing remove breakpoint"));
  278. }
  279. break;
  280. case MSG_ID('g','o'):
  281. if(_state!=eDBG_Running){
  282. _state=eDBG_Running;
  283. BeginDocument();
  284. BeginElement(_SC("resumed"));
  285. EndElement(_SC("resumed"));
  286. EndDocument();
  287. // Send(_SC("<resumed/>\r\n"));
  288. scprintf(_SC("go (execution resumed)\n"));
  289. }
  290. break;
  291. case MSG_ID('s','p'):
  292. if(_state!=eDBG_Suspended){
  293. _state=eDBG_Suspended;
  294. scprintf(_SC("suspend\n"));
  295. }
  296. break;
  297. case MSG_ID('s','o'):
  298. if(_state==eDBG_Suspended){
  299. _state=eDBG_StepOver;
  300. }
  301. break;
  302. case MSG_ID('s','i'):
  303. if(_state==eDBG_Suspended){
  304. _state=eDBG_StepInto;
  305. scprintf(_SC("step into\n"));
  306. }
  307. break;
  308. case MSG_ID('s','r'):
  309. if(_state==eDBG_Suspended){
  310. _state=eDBG_StepReturn;
  311. scprintf(_SC("step return\n"));
  312. }
  313. break;
  314. case MSG_ID('d','i'):
  315. if(_state!=eDBG_Disabled){
  316. _state=eDBG_Disabled;
  317. scprintf(_SC("disabled\n"));
  318. }
  319. break;
  320. case MSG_ID('a','w'): {
  321. Watch w;
  322. if(ParseWatch(msg+3,w))
  323. {
  324. AddWatch(w);
  325. scprintf(_SC("added watch %d %s\n"),w._id,w._exp.c_str());
  326. /*if(_state == eDBG_Suspended) {
  327. Break(_line,_src.c_str(),_break_type.c_str());
  328. }*/
  329. }
  330. else
  331. scprintf(_SC("error parsing add watch"));
  332. }
  333. break;
  334. case MSG_ID('r','w'): {
  335. SQInteger id;
  336. if(ParseRemoveWatch(msg+3,id))
  337. {
  338. RemoveWatch(id);
  339. scprintf(_SC("added watch %d\n"),id);
  340. }
  341. else
  342. scprintf(_SC("error parsing remove watch"));
  343. }
  344. break;
  345. case MSG_ID('t','r'):
  346. scprintf(_SC("terminate from user\n"));
  347. break;
  348. case MSG_ID('r','d'):
  349. scprintf(_SC("ready\n"));
  350. _ready=true;
  351. break;
  352. default:
  353. scprintf(_SC("unknown packet"));
  354. }
  355. }
  356. bool SQDbgServer::ParseBreakpoint(const char *msg,BreakPoint &out)
  357. {
  358. static char stemp[MAX_BP_PATH];
  359. static SQChar desttemp[MAX_BP_PATH];
  360. char *ep=NULL;
  361. out._line=strtoul(msg,&ep,16);
  362. if(ep==msg || (*ep)!=':')return false;
  363. char *dest=stemp;
  364. ep++;
  365. while((*ep)!='\n' && (*ep)!='\0')
  366. {
  367. *dest=tolower(*ep);
  368. *dest++;*ep++;
  369. }
  370. *dest='\0';
  371. *dest++;
  372. *dest='\0';
  373. #ifdef _UNICODE
  374. int len=(int)strlen(stemp);
  375. SQChar *p = desttemp;
  376. size_t destlen = mbstowcs(p,stemp,len);
  377. p[destlen]=_SC('\0');
  378. out._src=p;
  379. #else
  380. out._src=stemp;
  381. #endif
  382. return true;
  383. }
  384. bool SQDbgServer::ParseWatch(const char *msg,Watch &out)
  385. {
  386. char *ep=NULL;
  387. out._id=strtoul(msg,&ep,16);
  388. if(ep==msg || (*ep)!=':')return false;
  389. //char *dest=out._src;
  390. ep++;
  391. while((*ep)!='\n' && (*ep)!='\0')
  392. {
  393. out._exp.append(1,*ep);
  394. *ep++;
  395. }
  396. return true;
  397. }
  398. bool SQDbgServer::ParseRemoveWatch(const char *msg,SQInteger &id)
  399. {
  400. char *ep=NULL;
  401. id=strtoul(msg,&ep,16);
  402. if(ep==msg)return false;
  403. return true;
  404. }
  405. void SQDbgServer::BreakExecution()
  406. {
  407. _state=eDBG_Suspended;
  408. while(_state==eDBG_Suspended){
  409. if(SQ_FAILED(sq_rdbg_update(this)))
  410. exit(0);
  411. Sleep(10);
  412. }
  413. }
  414. //COMMANDS
  415. void SQDbgServer::AddBreakpoint(BreakPoint &bp)
  416. {
  417. _breakpoints.insert(bp);
  418. BeginDocument();
  419. BeginElement(_SC("addbreakpoint"));
  420. Attribute(_SC("line"),IntToString(bp._line));
  421. Attribute(_SC("src"),bp._src.c_str());
  422. EndElement(_SC("addbreakpoint"));
  423. EndDocument();
  424. }
  425. void SQDbgServer::AddWatch(Watch &w)
  426. {
  427. _watches.insert(w);
  428. }
  429. void SQDbgServer::RemoveWatch(SQInteger id)
  430. {
  431. WatchSetItor itor=_watches.find(Watch(id,_SC("")));
  432. if(itor==_watches.end()){
  433. BeginDocument();
  434. BeginElement(_SC("error"));
  435. Attribute(_SC("desc"),_SC("the watch does not exists"));
  436. EndElement(_SC("error"));
  437. EndDocument();
  438. }
  439. else{
  440. _watches.erase(itor);
  441. scprintf(_SC("removed watch %d\n"),id);
  442. }
  443. }
  444. void SQDbgServer::RemoveBreakpoint(BreakPoint &bp)
  445. {
  446. BreakPointSetItor itor=_breakpoints.find(bp);
  447. if(itor==_breakpoints.end()){
  448. BeginDocument();
  449. BeginElement(_SC("break"));
  450. Attribute(_SC("desc"),_SC("the breakpoint doesn't exists"));
  451. EndElement(_SC("break"));
  452. EndDocument();
  453. }
  454. else{
  455. BeginDocument();
  456. BeginElement(_SC("removebreakpoint"));
  457. Attribute(_SC("line"),IntToString(bp._line));
  458. Attribute(_SC("src"),bp._src.c_str());
  459. EndElement(_SC("removebreakpoint"));
  460. EndDocument();
  461. _breakpoints.erase(itor);
  462. }
  463. }
  464. void SQDbgServer::Break(HSQUIRRELVM v,SQInteger line,const SQChar *src,const SQChar *type,const SQChar *error)
  465. {
  466. _line = line;
  467. _src = src;
  468. _break_type = src;
  469. if(!error){
  470. BeginDocument();
  471. BeginElement(_SC("break"));
  472. Attribute(_SC("thread"),PtrToString(v));
  473. Attribute(_SC("line"),IntToString(line));
  474. Attribute(_SC("src"),src);
  475. Attribute(_SC("type"),type);
  476. SerializeState(v);
  477. EndElement(_SC("break"));
  478. EndDocument();
  479. }else{
  480. BeginDocument();
  481. BeginElement(_SC("break"));
  482. Attribute(_SC("thread"),PtrToString(v));
  483. Attribute(_SC("line"),IntToString(line));
  484. Attribute(_SC("src"),src);
  485. Attribute(_SC("type"),type);
  486. Attribute(_SC("error"),error);
  487. SerializeState(v);
  488. EndElement(_SC("break"));
  489. EndDocument();
  490. }
  491. }
  492. void SQDbgServer::SerializeState(HSQUIRRELVM v)
  493. {
  494. sq_pushnull(v);
  495. sq_setdebughook(v);
  496. sq_pushnull(v);
  497. sq_seterrorhandler(v);
  498. sq_pushobject(v,_serializefunc);
  499. sq_pushobject(v,_debugroot);
  500. sq_pushstring(v,_SC("watches"),-1);
  501. sq_newtable(v);
  502. for(WatchSetItor i=_watches.begin(); i!=_watches.end(); ++i)
  503. {
  504. sq_pushinteger(v,i->_id);
  505. sq_pushstring(v,i->_exp.c_str(),(SQInteger)i->_exp.length());
  506. sq_createslot(v,-3);
  507. }
  508. sq_rawset(v,-3);
  509. if(SQ_SUCCEEDED(sq_call(v,1,SQTrue,SQFalse))){
  510. //if(SQ_SUCCEEDED(sqstd_getblob(v,-1,(SQUserPointer*)&sz)))
  511. //SendChunk(sz);
  512. }
  513. sq_pop(v,2);
  514. SetErrorHandlers(v);
  515. }
  516. void SQDbgServer::SetErrorHandlers(HSQUIRRELVM v)
  517. {
  518. sq_pushregistrytable(v);
  519. sq_pushstring(v,SQDBG_DEBUG_HOOK,-1);
  520. sq_rawget(v,-2);
  521. sq_setdebughook(v);
  522. sq_pushstring(v,SQDBG_ERROR_HANDLER,-1);
  523. sq_rawget(v,-2);
  524. sq_seterrorhandler(v);
  525. sq_pop(v,1);
  526. }
  527. void SQDbgServer::BeginDocument()
  528. {
  529. _xmlcurrentement = -1;
  530. SendChunk(_SC("<?xml version='1.0' encoding='utf-8'?>"));
  531. }
  532. void SQDbgServer::BeginElement(const SQChar *name)
  533. {
  534. _xmlcurrentement++;
  535. XMLElementState *self = &xmlstate[_xmlcurrentement];
  536. scstrcpy(self->name,name);
  537. self->haschildren = false;
  538. if(_xmlcurrentement > 0) {
  539. XMLElementState *parent = &xmlstate[_xmlcurrentement-1];
  540. if(!parent->haschildren) {
  541. SendChunk(_SC(">")); // closes the parent tag
  542. parent->haschildren = true;
  543. }
  544. }
  545. _scratchstring.resize(2+scstrlen(name));
  546. scsprintf(&_scratchstring[0],_SC("<%s"),name);
  547. SendChunk(&_scratchstring[0]);
  548. }
  549. void SQDbgServer::Attribute(const SQChar *name,const SQChar *value)
  550. {
  551. XMLElementState *self = &xmlstate[_xmlcurrentement];
  552. assert(!self->haschildren); //cannot have attributes if already has children
  553. const SQChar *escval = escape_xml(value);
  554. _scratchstring.resize(10+scstrlen(name)+scstrlen(escval));
  555. scsprintf(&_scratchstring[0],_SC(" %s=\"%s\""),name,escval);
  556. SendChunk(&_scratchstring[0]);
  557. }
  558. void SQDbgServer::EndElement(const SQChar *name)
  559. {
  560. XMLElementState *self = &xmlstate[_xmlcurrentement];
  561. assert(scstrcmp(self->name,name) == 0);
  562. if(self->haschildren) {
  563. _scratchstring.resize(10+scstrlen(name));
  564. scsprintf(&_scratchstring[0],_SC("</%s>"),name);
  565. SendChunk(&_scratchstring[0]);
  566. }
  567. else {
  568. SendChunk(_SC("/>"));
  569. }
  570. _xmlcurrentement--;
  571. }
  572. void SQDbgServer::EndDocument()
  573. {
  574. SendChunk(_SC("\r\n"));
  575. }
  576. //this can be done much better/faster(do we need that?)
  577. const SQChar *SQDbgServer::escape_xml(const SQChar *s)
  578. {
  579. SQChar *temp=sq_getscratchpad(_v,((SQInteger)scstrlen(s)*6) + sizeof(SQChar));
  580. SQChar *dest=temp;
  581. while(*s!=_SC('\0')){
  582. const SQChar *escape = NULL;
  583. switch(*s) {
  584. case _SC('<'): escape = _SC("&lt;"); break;
  585. case _SC('>'): escape = _SC("&gt;"); break;
  586. case _SC('&'): escape = _SC("&amp;"); break;
  587. case _SC('\''): escape = _SC("&apos;"); break;
  588. case _SC('\"'): escape = _SC("&quot;"); break;
  589. case _SC('\n'): escape = _SC("\\n"); break;
  590. case _SC('\r'): escape = _SC("\\r"); break;
  591. }
  592. if(escape) {
  593. scstrcpy(dest,escape);
  594. dest += scstrlen(escape);
  595. }
  596. else {
  597. *dest=*s;*dest++;
  598. }
  599. *s++;
  600. }
  601. *dest=_SC('\0');
  602. return temp;
  603. }