Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

694 lines
14 KiB

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