debugger_api.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. /**
  2. * $Id$
  3. *
  4. * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com)
  5. *
  6. * This file is part of Kamailio, a free SIP server.
  7. *
  8. * This file is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. * This file is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21. *
  22. */
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27. #include "../../dprint.h"
  28. #include "../../ut.h"
  29. #include "../../pt.h"
  30. #include "../../events.h"
  31. #include "../../pvar.h"
  32. #include "../../rpc.h"
  33. #include "../../rpc_lookup.h"
  34. #include "../../route_struct.h"
  35. #include "../../mem/shm_mem.h"
  36. #include "debugger_act.h"
  37. #include "debugger_api.h"
  38. #define DBG_CMD_SIZE 256
  39. #define DBG_STATE_INIT 0
  40. #define DBG_STATE_WAIT 1
  41. #define DBG_STATE_NEXT 2
  42. static str _dbg_state_list[] = {
  43. str_init("unknown"),
  44. str_init("init"),
  45. str_init("wait"),
  46. str_init("next"),
  47. {0, 0}
  48. };
  49. str *dbg_get_state_name(int t)
  50. {
  51. switch(t) {
  52. case DBG_STATE_INIT:
  53. return &_dbg_state_list[1];
  54. case DBG_STATE_WAIT:
  55. return &_dbg_state_list[2];
  56. case DBG_STATE_NEXT:
  57. return &_dbg_state_list[3];
  58. }
  59. return &_dbg_state_list[0];
  60. }
  61. #define DBG_CFGTRACE_ON (1<<0)
  62. #define DBG_ABKPOINT_ON (1<<1)
  63. #define DBG_LBKPOINT_ON (1<<2)
  64. static str _dbg_status_list[] = {
  65. str_init("cfgtrace-on"),
  66. str_init("cfgtrace-off"),
  67. str_init("abkpoint-on"),
  68. str_init("abkpoint-off"),
  69. str_init("lbkpoint-on"),
  70. str_init("lbkpoint-off"),
  71. {0, 0}
  72. };
  73. str *dbg_get_status_name(int t)
  74. {
  75. if(t&DBG_CFGTRACE_ON)
  76. return &_dbg_status_list[0];
  77. if(t&DBG_ABKPOINT_ON)
  78. return &_dbg_status_list[2];
  79. if(t&DBG_LBKPOINT_ON)
  80. return &_dbg_status_list[4];
  81. return &_dbg_state_list[0];
  82. }
  83. #define DBG_CMD_NOP 0
  84. #define DBG_CMD_ERR 1
  85. #define DBG_CMD_READ 2
  86. #define DBG_CMD_NEXT 3
  87. #define DBG_CMD_MOVE 4
  88. #define DBG_CMD_SHOW 5
  89. #define DBG_CMD_PVEVAL 6
  90. #define DBG_CMD_PVLOG 7
  91. static str _dbg_cmd_list[] = {
  92. str_init("nop"),
  93. str_init("err"),
  94. str_init("read"),
  95. str_init("next"),
  96. str_init("move"),
  97. str_init("show"),
  98. str_init("pveval"),
  99. str_init("pvlog"),
  100. {0, 0}
  101. };
  102. str *dbg_get_cmd_name(int t)
  103. {
  104. switch(t) {
  105. case DBG_CMD_NOP:
  106. return &_dbg_cmd_list[0];
  107. case DBG_CMD_ERR:
  108. return &_dbg_cmd_list[1];
  109. case DBG_CMD_READ:
  110. return &_dbg_cmd_list[2];
  111. case DBG_CMD_NEXT:
  112. return &_dbg_cmd_list[3];
  113. case DBG_CMD_MOVE:
  114. return &_dbg_cmd_list[4];
  115. case DBG_CMD_SHOW:
  116. return &_dbg_cmd_list[5];
  117. case DBG_CMD_PVEVAL:
  118. return &_dbg_cmd_list[6];
  119. case DBG_CMD_PVLOG:
  120. return &_dbg_cmd_list[7];
  121. }
  122. return &_dbg_state_list[0];
  123. }
  124. /**
  125. *
  126. */
  127. int _dbg_cfgtrace = 0;
  128. /**
  129. *
  130. */
  131. int _dbg_breakpoint = 0;
  132. /**
  133. *
  134. */
  135. int _dbg_cfgtrace_level = L_ERR;
  136. /**
  137. *
  138. */
  139. int _dbg_cfgtrace_facility = DEFAULT_FACILITY;
  140. /**
  141. *
  142. */
  143. char *_dbg_cfgtrace_prefix = "*** cfgtrace:";
  144. /**
  145. *
  146. */
  147. int _dbg_step_usleep = 100000;
  148. /**
  149. *
  150. */
  151. int _dbg_step_loops = 200;
  152. /**
  153. *
  154. */
  155. typedef struct _dbg_cmd
  156. {
  157. unsigned int pid;
  158. unsigned int cmd;
  159. char buf[DBG_CMD_SIZE];
  160. } dbg_cmd_t;
  161. /**
  162. *
  163. */
  164. typedef struct _dbg_pid
  165. {
  166. unsigned int pid;
  167. unsigned int set;
  168. unsigned int state;
  169. dbg_cmd_t in;
  170. dbg_cmd_t out;
  171. } dbg_pid_t;
  172. /**
  173. *
  174. */
  175. static dbg_pid_t *_dbg_pid_list = NULL;
  176. /**
  177. *
  178. */
  179. static int _dbg_pid_no = 0;
  180. /**
  181. *
  182. */
  183. typedef struct _dbg_bp
  184. {
  185. str cfile;
  186. int cline;
  187. int set;
  188. struct _dbg_bp *next;
  189. } dbg_bp_t;
  190. /**
  191. *
  192. */
  193. static dbg_bp_t *_dbg_bp_list = NULL;
  194. /**
  195. * callback executed for each cfg action
  196. */
  197. int dbg_cfg_trace(void *data)
  198. {
  199. struct action *a;
  200. struct sip_msg *msg;
  201. int loop;
  202. int olen;
  203. str pvn;
  204. pv_spec_t pvs;
  205. pv_value_t val;
  206. void **srevp;
  207. str *an;
  208. srevp = (void**)data;
  209. a = (struct action *)srevp[0];
  210. msg = (struct sip_msg *)srevp[1];
  211. if(a==NULL || msg==NULL || _dbg_pid_list==NULL)
  212. return 0;
  213. an = dbg_get_action_name(a);
  214. if(_dbg_pid_list[process_no].set&DBG_CFGTRACE_ON)
  215. {
  216. if(is_printable(_dbg_cfgtrace_level))
  217. {
  218. LOG_(_dbg_cfgtrace_facility, _dbg_cfgtrace_level,
  219. _dbg_cfgtrace_prefix,
  220. " c=[%s] l=%d a=%d n=%.*s\n",
  221. ZSW(a->cfile), a->cline, a->type, an->len, ZSW(an->s)
  222. );
  223. }
  224. }
  225. if(!(_dbg_pid_list[process_no].set&DBG_ABKPOINT_ON))
  226. {
  227. /* no breakpoints to be considered */
  228. return 0;
  229. }
  230. if(_dbg_pid_list[process_no].state==DBG_STATE_INIT)
  231. {
  232. LOG(_dbg_cfgtrace_level,
  233. "breakpoint hit: p=[%u] c=[%s] l=%d a=%d n=%.*s\n",
  234. _dbg_pid_list[process_no].pid,
  235. ZSW(a->cfile), a->cline, a->type, an->len, ZSW(an->s)
  236. );
  237. _dbg_pid_list[process_no].in.cmd = DBG_CMD_NOP;
  238. _dbg_pid_list[process_no].state = DBG_STATE_WAIT;
  239. }
  240. loop = 1;
  241. while(loop)
  242. {
  243. switch(_dbg_pid_list[process_no].in.cmd)
  244. {
  245. case DBG_CMD_NOP:
  246. sleep_us(_dbg_step_usleep);
  247. break;
  248. case DBG_CMD_MOVE:
  249. loop = 0;
  250. _dbg_pid_list[process_no].state=DBG_STATE_INIT;
  251. _dbg_pid_list[process_no].in.cmd = DBG_CMD_NOP;
  252. _dbg_pid_list[process_no].in.pid = 0;
  253. break;
  254. case DBG_CMD_NEXT:
  255. loop = 0;
  256. if(_dbg_pid_list[process_no].state==DBG_STATE_WAIT)
  257. _dbg_pid_list[process_no].state=DBG_STATE_NEXT;
  258. _dbg_pid_list[process_no].in.cmd = DBG_CMD_NOP;
  259. olen = snprintf(_dbg_pid_list[process_no].out.buf,
  260. DBG_CMD_SIZE,
  261. "exec [%s:%d] a=%d n=%.*s",
  262. ZSW(a->cfile), a->cline, a->type, an->len, ZSW(an->s));
  263. if(olen<0)
  264. {
  265. _dbg_pid_list[process_no].out.cmd = DBG_CMD_ERR;
  266. break;
  267. }
  268. _dbg_pid_list[process_no].out.cmd = DBG_CMD_READ;
  269. break;
  270. case DBG_CMD_PVEVAL:
  271. case DBG_CMD_PVLOG:
  272. loop = _dbg_pid_list[process_no].in.cmd;
  273. _dbg_pid_list[process_no].in.cmd = DBG_CMD_NOP;
  274. pvn.s = _dbg_pid_list[process_no].in.buf;
  275. pvn.len = strlen(pvn.s);
  276. if(pvn.len<=0)
  277. {
  278. LM_ERR("no pv to eval\n");
  279. break;
  280. }
  281. LM_DBG("pv to eval: %s\n", pvn.s);
  282. if(pv_parse_spec(&pvn, &pvs)<0)
  283. {
  284. LM_ERR("unable to parse pv [%s]\n", pvn.s);
  285. break;
  286. }
  287. memset(&val, 0, sizeof(pv_value_t));
  288. if(pv_get_spec_value(msg, &pvs, &val) != 0)
  289. {
  290. LM_ERR("unable to get pv value for [%s]\n", pvn.s);
  291. break;
  292. }
  293. if(val.flags&PV_VAL_NULL)
  294. {
  295. if(loop==DBG_CMD_PVEVAL)
  296. {
  297. olen = snprintf(_dbg_pid_list[process_no].out.buf,
  298. DBG_CMD_SIZE,
  299. "%s : t=null",
  300. pvn.s);
  301. if(olen<0)
  302. {
  303. _dbg_pid_list[process_no].out.cmd = DBG_CMD_ERR;
  304. break;
  305. }
  306. _dbg_pid_list[process_no].out.cmd = DBG_CMD_READ;
  307. } else {
  308. LOG(_dbg_cfgtrace_level,
  309. "breakpoint eval: %s : t=null\n",
  310. pvn.s
  311. );
  312. }
  313. break;
  314. }
  315. if(val.flags&PV_TYPE_INT)
  316. {
  317. if(loop==DBG_CMD_PVEVAL)
  318. {
  319. olen = snprintf(_dbg_pid_list[process_no].out.buf,
  320. DBG_CMD_SIZE,
  321. "%s : t=int v=%d",
  322. pvn.s, val.ri);
  323. if(olen<0)
  324. {
  325. _dbg_pid_list[process_no].out.cmd = DBG_CMD_ERR;
  326. break;
  327. }
  328. _dbg_pid_list[process_no].out.cmd = DBG_CMD_READ;
  329. } else {
  330. LOG(_dbg_cfgtrace_level,
  331. "breakpoint eval: %s : t=int v=%d\n",
  332. pvn.s, val.ri
  333. );
  334. }
  335. break;
  336. }
  337. if(loop==DBG_CMD_PVEVAL)
  338. {
  339. olen = snprintf(_dbg_pid_list[process_no].out.buf,
  340. DBG_CMD_SIZE,
  341. "%s : t=str v=%.*s",
  342. pvn.s, val.rs.len, val.rs.s);
  343. if(olen<0)
  344. {
  345. _dbg_pid_list[process_no].out.cmd = DBG_CMD_ERR;
  346. break;
  347. }
  348. _dbg_pid_list[process_no].out.cmd = DBG_CMD_READ;
  349. } else {
  350. LOG(_dbg_cfgtrace_level,
  351. "breakpoint eval: %s : t=str v=%.*s\n",
  352. pvn.s, val.rs.len, val.rs.s
  353. );
  354. }
  355. break;
  356. case DBG_CMD_SHOW:
  357. _dbg_pid_list[process_no].in.cmd = DBG_CMD_NOP;
  358. _dbg_pid_list[process_no].out.cmd = DBG_CMD_NOP;
  359. olen = snprintf(_dbg_pid_list[process_no].out.buf,
  360. DBG_CMD_SIZE,
  361. "at bkp [%s:%d] a=%d n=%.*s",
  362. a->cfile, a->cline, a->type, an->len, an->s);
  363. if(olen<0)
  364. {
  365. _dbg_pid_list[process_no].out.cmd = DBG_CMD_ERR;
  366. break;
  367. }
  368. _dbg_pid_list[process_no].out.cmd = DBG_CMD_READ;
  369. break;
  370. default:
  371. /* unknown command?!? - exit loop */
  372. _dbg_pid_list[process_no].in.cmd = DBG_CMD_NOP;
  373. _dbg_pid_list[process_no].state=DBG_STATE_INIT;
  374. loop = 0;
  375. }
  376. }
  377. return 0;
  378. }
  379. /**
  380. *
  381. */
  382. int dbg_init_bp_list(void)
  383. {
  384. if(_dbg_bp_list!=NULL)
  385. return -1;
  386. _dbg_bp_list = (dbg_bp_t*)shm_malloc(sizeof(dbg_bp_t));
  387. if(_dbg_bp_list==NULL)
  388. return -1;
  389. memset(_dbg_bp_list, 0, sizeof(dbg_bp_t));
  390. if(_dbg_breakpoint==1)
  391. _dbg_bp_list->set |= DBG_ABKPOINT_ON;
  392. if(_dbg_cfgtrace==1)
  393. _dbg_bp_list->set |= DBG_CFGTRACE_ON;
  394. sr_event_register_cb(SREV_CFG_RUN_ACTION, dbg_cfg_trace);
  395. return 0;
  396. }
  397. /**
  398. *
  399. */
  400. int dbg_add_breakpoint(struct action *a, int bpon)
  401. {
  402. int len;
  403. dbg_bp_t *nbp = NULL;
  404. if(_dbg_bp_list==NULL)
  405. return -1;
  406. len = strlen(a->cfile);
  407. len += sizeof(dbg_bp_t) + 1;
  408. nbp = (dbg_bp_t*)shm_malloc(len);
  409. if(nbp==NULL)
  410. return -1;
  411. memset(nbp, 0, len);
  412. nbp->set |= (bpon)?DBG_ABKPOINT_ON:0;
  413. nbp->cline = a->cline;
  414. nbp->cfile.s = (char*)nbp + sizeof(dbg_bp_t);
  415. strcpy(nbp->cfile.s, a->cfile);
  416. nbp->cfile.len = strlen(nbp->cfile.s);
  417. nbp->next = _dbg_bp_list->next;
  418. _dbg_bp_list->next = nbp;
  419. return 0;
  420. }
  421. /**
  422. *
  423. */
  424. int dbg_init_pid_list(void)
  425. {
  426. _dbg_pid_no = get_max_procs();
  427. if(_dbg_pid_no<=0)
  428. return -1;
  429. if(_dbg_pid_list!=NULL)
  430. return -1;
  431. _dbg_pid_list = (dbg_pid_t*)shm_malloc(_dbg_pid_no*sizeof(dbg_pid_t));
  432. if(_dbg_pid_list==NULL)
  433. return -1;
  434. memset(_dbg_pid_list, 0, _dbg_pid_no*sizeof(dbg_pid_t));
  435. return 0;
  436. }
  437. /**
  438. *
  439. */
  440. int dbg_init_mypid(void)
  441. {
  442. if(_dbg_pid_list==NULL)
  443. return -1;
  444. if(process_no>=_dbg_pid_no)
  445. return -1;
  446. _dbg_pid_list[process_no].pid = (unsigned int)my_pid();
  447. if(_dbg_breakpoint==1)
  448. _dbg_pid_list[process_no].set |= DBG_ABKPOINT_ON;
  449. if(_dbg_cfgtrace==1)
  450. _dbg_pid_list[process_no].set |= DBG_CFGTRACE_ON;
  451. return 0;
  452. }
  453. /**
  454. *
  455. */
  456. int dbg_get_pid_index(unsigned int pid)
  457. {
  458. int i;
  459. for(i=0; i<_dbg_pid_no; i++)
  460. {
  461. if(_dbg_pid_list[i].pid == pid)
  462. return i;
  463. }
  464. return -1;
  465. }
  466. /**
  467. *
  468. */
  469. static const char* dbg_rpc_bp_doc[2] = {
  470. "Breakpoint command",
  471. 0
  472. };
  473. /**
  474. *
  475. */
  476. static void dbg_rpc_bp(rpc_t* rpc, void* ctx)
  477. {
  478. int i;
  479. int limit;
  480. int lpid;
  481. str cmd;
  482. str val;
  483. int loop;
  484. if(_dbg_pid_list==NULL)
  485. {
  486. rpc->fault(ctx, 500, "Not initialized");
  487. return;
  488. }
  489. if (rpc->scan(ctx, "S", &cmd) < 1)
  490. {
  491. rpc->fault(ctx, 500, "Config breakpoint command missing");
  492. return;
  493. }
  494. i = 0;
  495. limit = _dbg_pid_no;
  496. if (rpc->scan(ctx, "*d", &lpid) == 1)
  497. {
  498. i = dbg_get_pid_index((unsigned int)lpid);
  499. if(i<0)
  500. {
  501. rpc->fault(ctx, 500, "No such pid");
  502. return;
  503. }
  504. limit = i + 1;
  505. } else {
  506. lpid = -1;
  507. }
  508. if(cmd.len==2 && strncmp(cmd.s, "on", 2)==0)
  509. {
  510. for(; i<limit; i++)
  511. {
  512. _dbg_pid_list[i].set |= DBG_ABKPOINT_ON;
  513. _dbg_pid_list[i].state=DBG_STATE_INIT;
  514. }
  515. } else if(cmd.len==3 && strncmp(cmd.s, "off", 3)==0) {
  516. for(; i<limit; i++)
  517. {
  518. _dbg_pid_list[i].set &= ~DBG_ABKPOINT_ON;
  519. _dbg_pid_list[i].state=DBG_STATE_INIT;
  520. }
  521. } else if(cmd.len==7 && strncmp(cmd.s, "release", 7)==0) {
  522. for(; i<limit; i++)
  523. {
  524. if(_dbg_pid_list[i].state!=DBG_STATE_WAIT)
  525. {
  526. _dbg_pid_list[i].set &= ~DBG_ABKPOINT_ON;
  527. _dbg_pid_list[i].state=DBG_STATE_INIT;
  528. }
  529. }
  530. } else if(cmd.len==4 && strncmp(cmd.s, "keep", 4)==0) {
  531. if(lpid==-1)
  532. {
  533. rpc->fault(ctx, 500, "Missing pid parameter");
  534. return;
  535. }
  536. for(loop=0; loop<_dbg_pid_no; loop++)
  537. {
  538. if(i!=loop)
  539. {
  540. _dbg_pid_list[loop].set &= ~DBG_ABKPOINT_ON;
  541. if(_dbg_pid_list[loop].state!=DBG_STATE_INIT)
  542. {
  543. _dbg_pid_list[loop].in.pid = my_pid();
  544. _dbg_pid_list[loop].in.cmd = DBG_CMD_MOVE;
  545. }
  546. }
  547. }
  548. } else if(cmd.len==4 && strncmp(cmd.s, "move", 4)==0) {
  549. if(lpid==-1)
  550. {
  551. rpc->fault(ctx, 500, "Missing pid parameter");
  552. return;
  553. }
  554. for(; i<limit; i++)
  555. {
  556. if(_dbg_pid_list[i].state!=DBG_STATE_INIT)
  557. {
  558. _dbg_pid_list[i].set &= ~DBG_ABKPOINT_ON;
  559. _dbg_pid_list[i].in.pid = my_pid();
  560. _dbg_pid_list[i].in.cmd = DBG_CMD_MOVE;
  561. }
  562. }
  563. } else if(cmd.len==4 && strncmp(cmd.s, "next", 4)==0) {
  564. if(lpid==-1)
  565. {
  566. rpc->fault(ctx, 500, "Missing pid parameter");
  567. return;
  568. }
  569. _dbg_pid_list[i].in.pid = my_pid();
  570. _dbg_pid_list[i].in.cmd = DBG_CMD_NEXT;
  571. for(loop=0; loop<_dbg_step_loops; loop++)
  572. {
  573. sleep_us(_dbg_step_usleep);
  574. if(_dbg_pid_list[i].out.cmd == DBG_CMD_READ)
  575. {
  576. rpc->add(ctx, "s", _dbg_pid_list[i].out.buf);
  577. _dbg_pid_list[i].out.cmd = DBG_CMD_NOP;
  578. return;
  579. } else if(_dbg_pid_list[i].out.cmd == DBG_CMD_ERR) {
  580. rpc->add(ctx, "s", "cmd execution error");
  581. _dbg_pid_list[i].out.cmd = DBG_CMD_NOP;
  582. return;
  583. }
  584. }
  585. /* nothing to read ... err?!? */
  586. } else if(cmd.len==4 && strncmp(cmd.s, "show", 4)==0) {
  587. if(lpid==-1)
  588. {
  589. rpc->fault(ctx, 500, "Missing pid parameter");
  590. return;
  591. }
  592. _dbg_pid_list[i].in.pid = my_pid();
  593. _dbg_pid_list[i].in.cmd = DBG_CMD_SHOW;
  594. for(loop=0; loop<_dbg_step_loops; loop++)
  595. {
  596. sleep_us(_dbg_step_usleep);
  597. if(_dbg_pid_list[i].out.cmd == DBG_CMD_READ)
  598. {
  599. rpc->add(ctx, "s", _dbg_pid_list[i].out.buf);
  600. _dbg_pid_list[i].out.cmd = DBG_CMD_NOP;
  601. return;
  602. } else if(_dbg_pid_list[i].out.cmd == DBG_CMD_ERR) {
  603. rpc->add(ctx, "s", "cmd execution error");
  604. _dbg_pid_list[i].out.cmd = DBG_CMD_NOP;
  605. return;
  606. }
  607. }
  608. /* nothing to read ... err?!? */
  609. } else if(cmd.len==4 && strncmp(cmd.s, "eval", 4)==0) {
  610. if(lpid==-1)
  611. {
  612. rpc->fault(ctx, 500, "Missing pid parameter");
  613. return;
  614. }
  615. if (rpc->scan(ctx, "S", &val) < 1)
  616. {
  617. rpc->fault(ctx, 500, "pv param missing");
  618. return;
  619. }
  620. if (val.len < 2 || val.len>=DBG_CMD_SIZE)
  621. {
  622. rpc->fault(ctx, 500, "invalid pv param");
  623. return;
  624. }
  625. strncpy(_dbg_pid_list[i].in.buf, val.s, val.len);
  626. _dbg_pid_list[i].in.buf[val.len] = '\0';
  627. _dbg_pid_list[i].in.pid = my_pid();
  628. _dbg_pid_list[i].in.cmd = DBG_CMD_PVEVAL;
  629. for(loop=0; loop<_dbg_step_loops; loop++)
  630. {
  631. sleep_us(_dbg_step_usleep);
  632. if(_dbg_pid_list[i].out.cmd == DBG_CMD_READ)
  633. {
  634. rpc->add(ctx, "s", _dbg_pid_list[i].out.buf);
  635. _dbg_pid_list[i].out.cmd = DBG_CMD_NOP;
  636. return;
  637. } else if(_dbg_pid_list[i].out.cmd == DBG_CMD_ERR) {
  638. rpc->add(ctx, "s", "cmd execution error");
  639. _dbg_pid_list[i].out.cmd = DBG_CMD_NOP;
  640. return;
  641. }
  642. }
  643. /* nothing to read ... err?!? */
  644. } else if(cmd.len==3 && strncmp(cmd.s, "log", 3)==0) {
  645. if(lpid==-1)
  646. {
  647. rpc->fault(ctx, 500, "Missing pid parameter");
  648. return;
  649. }
  650. if (rpc->scan(ctx, "S", &val) < 1)
  651. {
  652. rpc->fault(ctx, 500, "pv param missing");
  653. return;
  654. }
  655. if (val.len < 2 || val.len>=DBG_CMD_SIZE)
  656. {
  657. rpc->fault(ctx, 500, "invalid pv param");
  658. return;
  659. }
  660. strncpy(_dbg_pid_list[i].in.buf, val.s, val.len);
  661. _dbg_pid_list[i].in.buf[val.len] = '\0';
  662. _dbg_pid_list[i].in.pid = my_pid();
  663. _dbg_pid_list[i].in.cmd = DBG_CMD_PVLOG;
  664. } else {
  665. rpc->fault(ctx, 500, "Unknown inner command");
  666. }
  667. rpc->add(ctx, "s", "200 ok");
  668. }
  669. /**
  670. *
  671. */
  672. static const char* dbg_rpc_list_doc[2] = {
  673. "List debugging process array",
  674. 0
  675. };
  676. /**
  677. *
  678. */
  679. static void dbg_rpc_list(rpc_t* rpc, void* ctx)
  680. {
  681. int i;
  682. int limit;
  683. int lpid;
  684. void* th;
  685. if(_dbg_pid_list==NULL)
  686. {
  687. rpc->fault(ctx, 500, "Not initialized");
  688. return;
  689. }
  690. i = 0;
  691. limit = _dbg_pid_no;
  692. if (rpc->scan(ctx, "*d", &lpid) == 1)
  693. {
  694. i = dbg_get_pid_index((unsigned int)lpid);
  695. if(i<0)
  696. {
  697. rpc->fault(ctx, 500, "No such pid");
  698. return;
  699. }
  700. limit = i + 1;
  701. }
  702. for(; i<limit; i++)
  703. {
  704. /* add entry node */
  705. if (rpc->add(ctx, "{", &th) < 0)
  706. {
  707. rpc->fault(ctx, 500, "Internal error creating rpc");
  708. return;
  709. }
  710. if(rpc->struct_add(th, "dddddd",
  711. "entry", i,
  712. "pid", _dbg_pid_list[i].pid,
  713. "set", _dbg_pid_list[i].set,
  714. "state", _dbg_pid_list[i].state,
  715. "in.pid", _dbg_pid_list[i].in.pid,
  716. "in.cmd", _dbg_pid_list[i].in.cmd
  717. )<0)
  718. {
  719. rpc->fault(ctx, 500, "Internal error creating rpc");
  720. return;
  721. }
  722. }
  723. }
  724. /**
  725. *
  726. */
  727. static const char* dbg_rpc_trace_doc[2] = {
  728. "Config trace command",
  729. 0
  730. };
  731. /**
  732. *
  733. */
  734. static void dbg_rpc_trace(rpc_t* rpc, void* ctx)
  735. {
  736. int i;
  737. int limit;
  738. int lpid;
  739. str cmd;
  740. if(_dbg_pid_list==NULL)
  741. {
  742. rpc->fault(ctx, 500, "Not initialized");
  743. return;
  744. }
  745. if (rpc->scan(ctx, "S", &cmd) < 1)
  746. {
  747. rpc->fault(ctx, 500, "Config trace command missing");
  748. return;
  749. }
  750. i = 0;
  751. limit = _dbg_pid_no;
  752. if (rpc->scan(ctx, "*d", &lpid) == 1)
  753. {
  754. i = dbg_get_pid_index((unsigned int)lpid);
  755. if(i<0)
  756. {
  757. rpc->fault(ctx, 500, "No such pid");
  758. return;
  759. }
  760. limit = i + 1;
  761. }
  762. if(cmd.len!=2 && cmd.len!=3)
  763. {
  764. rpc->fault(ctx, 500, "Unknown trace command");
  765. return;
  766. }
  767. if(cmd.len==2)
  768. {
  769. if(strncmp(cmd.s, "on", 2)!=0)
  770. {
  771. rpc->fault(ctx, 500, "Unknown trace command");
  772. return;
  773. }
  774. } else {
  775. if(strncmp(cmd.s, "off", 3)!=0)
  776. {
  777. rpc->fault(ctx, 500, "Unknown trace command");
  778. return;
  779. }
  780. }
  781. for(; i<limit; i++)
  782. {
  783. if(cmd.len==2)
  784. {
  785. _dbg_pid_list[i].set |= DBG_CFGTRACE_ON;
  786. } else {
  787. _dbg_pid_list[i].set &= ~DBG_CFGTRACE_ON;
  788. }
  789. }
  790. rpc->add(ctx, "s", "200 ok");
  791. }
  792. /**
  793. *
  794. */
  795. rpc_export_t dbg_rpc[] = {
  796. {"dbg.bp", dbg_rpc_bp, dbg_rpc_bp_doc, 0},
  797. {"dbg.ls", dbg_rpc_list, dbg_rpc_list_doc, 0},
  798. {"dbg.trace", dbg_rpc_trace, dbg_rpc_trace_doc, 0},
  799. {0, 0, 0, 0}
  800. };
  801. /**
  802. *
  803. */
  804. int dbg_init_rpc(void)
  805. {
  806. if (rpc_register_array(dbg_rpc)!=0)
  807. {
  808. LM_ERR("failed to register RPC commands\n");
  809. return -1;
  810. }
  811. return 0;
  812. }