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.

669 lines
15 KiB

13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2013 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Felipe Pena <felipe@php.net> |
  16. | Authors: Joe Watkins <joe.watkins@live.co.uk> |
  17. | Authors: Bob Weinand <bwoebi@php.net> |
  18. +----------------------------------------------------------------------+
  19. */
  20. #include "phpdbg.h"
  21. #include "phpdbg_cmd.h"
  22. #include "phpdbg_utils.h"
  23. #include "phpdbg_set.h"
  24. ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
  25. PHPDBG_API const char *phpdbg_get_param_type(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */
  26. {
  27. switch (param->type) {
  28. case EMPTY_PARAM:
  29. return "empty";
  30. case ADDR_PARAM:
  31. return "address";
  32. case NUMERIC_PARAM:
  33. return "numeric";
  34. case METHOD_PARAM:
  35. return "method";
  36. case NUMERIC_FUNCTION_PARAM:
  37. return "function opline";
  38. case NUMERIC_METHOD_PARAM:
  39. return "method opline";
  40. case FILE_PARAM:
  41. return "file or file opline";
  42. case STR_PARAM:
  43. return "string";
  44. default: /* this is bad */
  45. return "unknown";
  46. }
  47. }
  48. PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char *str, size_t len, phpdbg_param_t *param TSRMLS_DC) /* {{{ */
  49. {
  50. char *class_name, *func_name;
  51. if (len == 0) {
  52. param->type = EMPTY_PARAM;
  53. goto parsed;
  54. }
  55. if (phpdbg_is_addr(str)) {
  56. param->addr = strtoul(str, 0, 16);
  57. param->type = ADDR_PARAM;
  58. goto parsed;
  59. } else if (phpdbg_is_numeric(str)) {
  60. param->num = strtol(str, NULL, 0);
  61. param->type = NUMERIC_PARAM;
  62. goto parsed;
  63. } else if (phpdbg_is_class_method(str, len+1, &class_name, &func_name)) {
  64. param->method.class = class_name;
  65. param->method.name = func_name;
  66. param->type = METHOD_PARAM;
  67. goto parsed;
  68. } else {
  69. char *line_pos = strrchr(str, ':');
  70. if (line_pos && phpdbg_is_numeric(line_pos+1)) {
  71. if (strchr(str, ':') == line_pos) {
  72. char path[MAXPATHLEN];
  73. memcpy(path, str, line_pos - str);
  74. path[line_pos - str] = 0;
  75. *line_pos = 0;
  76. param->file.name = phpdbg_resolve_path(path TSRMLS_CC);
  77. param->file.line = strtol(line_pos+1, NULL, 0);
  78. param->type = FILE_PARAM;
  79. goto parsed;
  80. }
  81. }
  82. line_pos = strrchr(str, '#');
  83. if (line_pos && phpdbg_is_numeric(line_pos+1)) {
  84. if (strchr(str, '#') == line_pos) {
  85. param->num = strtol(line_pos + 1, NULL, 0);
  86. if (phpdbg_is_class_method(str, line_pos - str, &class_name, &func_name)) {
  87. param->method.class = class_name;
  88. param->method.name = func_name;
  89. param->type = NUMERIC_METHOD_PARAM;
  90. } else {
  91. param->len = line_pos - str;
  92. param->str = estrndup(str, param->len);
  93. param->type = NUMERIC_FUNCTION_PARAM;
  94. }
  95. goto parsed;
  96. }
  97. }
  98. }
  99. param->str = estrndup(str, len);
  100. param->len = len;
  101. param->type = STR_PARAM;
  102. parsed:
  103. phpdbg_debug("phpdbg_parse_param(\"%s\", %lu): %s",
  104. str, len, phpdbg_get_param_type(param TSRMLS_CC));
  105. return param->type;
  106. } /* }}} */
  107. PHPDBG_API void phpdbg_clear_param(phpdbg_param_t *param TSRMLS_DC) /* {{{ */
  108. {
  109. if (param) {
  110. switch (param->type) {
  111. case FILE_PARAM:
  112. efree(param->file.name);
  113. break;
  114. case METHOD_PARAM:
  115. efree(param->method.class);
  116. efree(param->method.name);
  117. break;
  118. case STR_PARAM:
  119. efree(param->str);
  120. break;
  121. default:
  122. break;
  123. }
  124. }
  125. } /* }}} */
  126. PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer TSRMLS_DC) /* {{{ */
  127. {
  128. switch (param->type) {
  129. case STR_PARAM:
  130. asprintf(pointer,
  131. "%s", param->str);
  132. break;
  133. case ADDR_PARAM:
  134. asprintf(pointer,
  135. "%#lx", param->addr);
  136. break;
  137. case NUMERIC_PARAM:
  138. asprintf(pointer,
  139. "%li",
  140. param->num);
  141. break;
  142. case METHOD_PARAM:
  143. asprintf(pointer,
  144. "%s::%s",
  145. param->method.class,
  146. param->method.name);
  147. break;
  148. case FILE_PARAM:
  149. if (param->num) {
  150. asprintf(pointer,
  151. "%s:%lu#%lu",
  152. param->file.name,
  153. param->file.line,
  154. param->num);
  155. } else {
  156. asprintf(pointer,
  157. "%s:%lu",
  158. param->file.name,
  159. param->file.line);
  160. }
  161. break;
  162. case NUMERIC_FUNCTION_PARAM:
  163. asprintf(pointer,
  164. "%s#%lu", param->str, param->num);
  165. break;
  166. case NUMERIC_METHOD_PARAM:
  167. asprintf(pointer,
  168. "%s::%s#%lu",
  169. param->method.class,
  170. param->method.name,
  171. param->num);
  172. break;
  173. default:
  174. asprintf(pointer,
  175. "%s", "unknown");
  176. }
  177. return *pointer;
  178. } /* }}} */
  179. PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* dest TSRMLS_DC) /* {{{ */
  180. {
  181. switch ((dest->type = src->type)) {
  182. case STR_PARAM:
  183. dest->str = estrndup(src->str, src->len);
  184. dest->len = src->len;
  185. break;
  186. case ADDR_PARAM:
  187. dest->addr = src->addr;
  188. break;
  189. case NUMERIC_PARAM:
  190. dest->num = src->num;
  191. break;
  192. case METHOD_PARAM:
  193. dest->method.class = estrdup(src->method.class);
  194. dest->method.name = estrdup(src->method.name);
  195. break;
  196. case FILE_PARAM:
  197. dest->file.name = estrdup(src->file.name);
  198. dest->file.line = src->file.line;
  199. if (src->num)
  200. dest->num = src->num;
  201. break;
  202. case NUMERIC_FUNCTION_PARAM:
  203. dest->str = estrndup(src->str, src->len);
  204. dest->num = src->num;
  205. dest->len = src->len;
  206. break;
  207. case NUMERIC_METHOD_PARAM:
  208. dest->method.class = estrdup(src->method.class);
  209. dest->method.name = estrdup(src->method.name);
  210. dest->num = src->num;
  211. break;
  212. case EMPTY_PARAM: { /* do nothing */ } break;
  213. }
  214. } /* }}} */
  215. PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */
  216. {
  217. zend_ulong hash = param->type;
  218. switch (param->type) {
  219. case STR_PARAM:
  220. hash += zend_inline_hash_func(param->str, param->len);
  221. break;
  222. case METHOD_PARAM:
  223. hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
  224. hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
  225. break;
  226. case FILE_PARAM:
  227. hash += zend_inline_hash_func(param->file.name, strlen(param->file.name));
  228. hash += param->file.line;
  229. if (param->num)
  230. hash += param->num;
  231. break;
  232. case ADDR_PARAM:
  233. hash += param->addr;
  234. break;
  235. case NUMERIC_PARAM:
  236. hash += param->num;
  237. break;
  238. case NUMERIC_FUNCTION_PARAM:
  239. hash += zend_inline_hash_func(param->str, param->len);
  240. hash += param->num;
  241. break;
  242. case NUMERIC_METHOD_PARAM:
  243. hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
  244. hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
  245. if (param->num)
  246. hash+= param->num;
  247. break;
  248. case EMPTY_PARAM: { /* do nothing */ } break;
  249. }
  250. return hash;
  251. } /* }}} */
  252. PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_param_t *r TSRMLS_DC) /* {{{ */
  253. {
  254. if (l && r) {
  255. if (l->type == r->type) {
  256. switch (l->type) {
  257. case NUMERIC_FUNCTION_PARAM:
  258. if (l->num != r->num) {
  259. break;
  260. }
  261. /* break intentionally omitted */
  262. case STR_PARAM:
  263. return (l->len == r->len) &&
  264. (memcmp(l->str, r->str, l->len) == SUCCESS);
  265. case NUMERIC_PARAM:
  266. return (l->num == r->num);
  267. case ADDR_PARAM:
  268. return (l->addr == r->addr);
  269. case FILE_PARAM: {
  270. if (l->file.line == r->file.line) {
  271. size_t lengths[2] = {
  272. strlen(l->file.name), strlen(r->file.name)};
  273. if (lengths[0] == lengths[1]) {
  274. if ((!l->num && !r->num) || (l->num == r->num)) {
  275. return (memcmp(
  276. l->file.name, r->file.name, lengths[0]) == SUCCESS);
  277. }
  278. }
  279. }
  280. } break;
  281. case NUMERIC_METHOD_PARAM:
  282. if (l->num != r->num) {
  283. break;
  284. }
  285. /* break intentionally omitted */
  286. case METHOD_PARAM: {
  287. size_t lengths[2] = {
  288. strlen(l->method.class), strlen(r->method.class)};
  289. if (lengths[0] == lengths[1]) {
  290. if (memcmp(l->method.class, r->method.class, lengths[0]) == SUCCESS) {
  291. lengths[0] = strlen(l->method.name);
  292. lengths[1] = strlen(r->method.name);
  293. if (lengths[0] == lengths[1]) {
  294. return (memcmp(
  295. l->method.name, r->method.name, lengths[0]) == SUCCESS);
  296. }
  297. }
  298. }
  299. } break;
  300. case EMPTY_PARAM:
  301. return 1;
  302. }
  303. }
  304. }
  305. return 0;
  306. } /* }}} */
  307. PHPDBG_API phpdbg_input_t **phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC) /* {{{ */
  308. {
  309. char *p;
  310. char b[PHPDBG_MAX_CMD];
  311. int l=0;
  312. enum states {
  313. IN_BETWEEN,
  314. IN_WORD,
  315. IN_STRING
  316. } state = IN_BETWEEN;
  317. phpdbg_input_t **argv = NULL;
  318. argv = (phpdbg_input_t**) emalloc(sizeof(phpdbg_input_t*));
  319. (*argc) = 0;
  320. #define RESET_STATE() do { \
  321. phpdbg_input_t *arg = emalloc(sizeof(phpdbg_input_t)); \
  322. if (arg) { \
  323. b[l]=0; \
  324. arg->length = l; \
  325. arg->string = estrndup(b, arg->length); \
  326. arg->argv = NULL; \
  327. arg->argc = 0; \
  328. argv = (phpdbg_input_t**) erealloc(argv, sizeof(phpdbg_input_t*) * ((*argc)+1)); \
  329. argv[(*argc)++] = arg; \
  330. l = 0; \
  331. } \
  332. state = IN_BETWEEN; \
  333. } while (0)
  334. for (p = buffer; *p != '\0'; p++) {
  335. int c = (unsigned char) *p;
  336. switch (state) {
  337. case IN_BETWEEN:
  338. if (isspace(c)) {
  339. continue;
  340. }
  341. if (c == '"') {
  342. state = IN_STRING;
  343. continue;
  344. }
  345. state = IN_WORD;
  346. b[l++]=c;
  347. continue;
  348. case IN_STRING:
  349. if (c == '"') {
  350. if (buffer[(p - buffer)-1] == '\\') {
  351. b[l-1]=c;
  352. continue;
  353. }
  354. RESET_STATE();
  355. } else {
  356. b[l++]=c;
  357. }
  358. continue;
  359. case IN_WORD:
  360. if (isspace(c)) {
  361. RESET_STATE();
  362. } else {
  363. b[l++]=c;
  364. }
  365. continue;
  366. }
  367. }
  368. switch (state) {
  369. case IN_WORD: {
  370. RESET_STATE();
  371. } break;
  372. case IN_STRING:
  373. phpdbg_error(
  374. "Malformed command line (unclosed quote) @ %ld: %s!",
  375. (p - buffer)-1, &buffer[(p - buffer)-1]);
  376. break;
  377. case IN_BETWEEN:
  378. break;
  379. }
  380. if ((*argc) == 0) {
  381. /* not needed */
  382. efree(argv);
  383. /* to be sure */
  384. return NULL;
  385. }
  386. return argv;
  387. } /* }}} */
  388. PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
  389. {
  390. phpdbg_input_t *buffer = NULL;
  391. char *cmd = NULL;
  392. if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
  393. if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) &&
  394. (buffered == NULL)) {
  395. fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
  396. }
  397. if (buffered == NULL) {
  398. #ifndef HAVE_LIBREADLINE
  399. char buf[PHPDBG_MAX_CMD];
  400. if ((!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && !phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) ||
  401. !fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
  402. /* the user has gone away */
  403. phpdbg_error("Failed to read console!");
  404. PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
  405. zend_bailout();
  406. return NULL;
  407. }
  408. cmd = buf;
  409. #else
  410. if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
  411. char buf[PHPDBG_MAX_CMD];
  412. if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
  413. cmd = buf;
  414. } else cmd = NULL;
  415. } else cmd = readline(phpdbg_get_prompt(TSRMLS_C));
  416. if (!cmd) {
  417. /* the user has gone away */
  418. phpdbg_error("Failed to read console!");
  419. PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
  420. zend_bailout();
  421. return NULL;
  422. }
  423. if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
  424. add_history(cmd);
  425. }
  426. #endif
  427. } else cmd = buffered;
  428. /* allocate and sanitize buffer */
  429. buffer = (phpdbg_input_t*) ecalloc(1, sizeof(phpdbg_input_t));
  430. if (!buffer) {
  431. return NULL;
  432. }
  433. buffer->string = phpdbg_trim(cmd, strlen(cmd), &buffer->length);
  434. /* store constant pointer to start of buffer */
  435. buffer->start = (char* const*) buffer->string;
  436. buffer->argv = phpdbg_read_argv(
  437. buffer->string, &buffer->argc TSRMLS_CC);
  438. #ifdef PHPDBG_DEBUG
  439. if (buffer->argc) {
  440. int arg = 0;
  441. while (arg < buffer->argc) {
  442. phpdbg_debug(
  443. "argv %d=%s", arg, buffer->argv[arg]->string);
  444. arg++;
  445. }
  446. }
  447. #endif
  448. #ifdef HAVE_LIBREADLINE
  449. if (!buffered && cmd &&
  450. !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
  451. free(cmd);
  452. }
  453. #endif
  454. return buffer;
  455. }
  456. return NULL;
  457. } /* }}} */
  458. PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC) /* {{{ */
  459. {
  460. if (argv) {
  461. if (argc) {
  462. int arg;
  463. for (arg=0; arg<argc; arg++) {
  464. phpdbg_destroy_input(
  465. &argv[arg] TSRMLS_CC);
  466. }
  467. }
  468. efree(argv);
  469. }
  470. } /* }}} */
  471. PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t **input TSRMLS_DC) /*{{{ */
  472. {
  473. if (*input) {
  474. if ((*input)->string) {
  475. efree((*input)->string);
  476. }
  477. phpdbg_destroy_argv(
  478. (*input)->argv, (*input)->argc TSRMLS_CC);
  479. efree(*input);
  480. }
  481. } /* }}} */
  482. PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t *command, phpdbg_input_t *input TSRMLS_DC) /* {{{ */
  483. {
  484. int rc = FAILURE;
  485. if (input->argc > 0) {
  486. while (command && command->name && command->handler) {
  487. if (((command->name_len == input->argv[0]->length) &&
  488. (memcmp(command->name, input->argv[0]->string, command->name_len) == SUCCESS)) ||
  489. (command->alias &&
  490. (input->argv[0]->length == 1) &&
  491. (command->alias == *input->argv[0]->string))) {
  492. phpdbg_param_t param;
  493. param.type = EMPTY_PARAM;
  494. if (input->argc > 1) {
  495. if (command->subs) {
  496. phpdbg_input_t sub = *input;
  497. sub.string += input->argv[0]->length;
  498. sub.length -= input->argv[0]->length;
  499. sub.string = phpdbg_trim(
  500. sub.string, sub.length, &sub.length);
  501. sub.argc--;
  502. sub.argv++;
  503. phpdbg_debug(
  504. "trying sub commands in \"%s\" for \"%s\" with %d arguments",
  505. command->name, sub.argv[0]->string, sub.argc-1);
  506. if (phpdbg_do_cmd(command->subs, &sub TSRMLS_CC) == SUCCESS) {
  507. efree(sub.string);
  508. return SUCCESS;
  509. }
  510. efree(sub.string);
  511. }
  512. /* no sub command found */
  513. {
  514. char *store = input->string;
  515. input->string += input->argv[0]->length;
  516. input->length -= input->argv[0]->length;
  517. input->string = phpdbg_trim(
  518. input->string, input->length, &input->length);
  519. efree(store);
  520. }
  521. /* pass parameter on */
  522. phpdbg_parse_param(
  523. input->string,
  524. input->length,
  525. &param TSRMLS_CC);
  526. }
  527. phpdbg_debug(
  528. "found command %s for %s with %d arguments",
  529. command->name, input->argv[0]->string, input->argc-1);
  530. {
  531. int arg;
  532. for (arg=1; arg<input->argc; arg++) {
  533. phpdbg_debug(
  534. "\t#%d: [%s=%zu]",
  535. arg,
  536. input->argv[arg]->string,
  537. input->argv[arg]->length);
  538. }
  539. }
  540. rc = command->handler(&param, input TSRMLS_CC);
  541. /* only set last command when it is worth it! */
  542. if ((rc != FAILURE) &&
  543. !(PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) {
  544. PHPDBG_G(lcmd) = (phpdbg_command_t*) command;
  545. phpdbg_clear_param(
  546. &PHPDBG_G(lparam) TSRMLS_CC);
  547. PHPDBG_G(lparam) = param;
  548. }
  549. break;
  550. }
  551. command++;
  552. }
  553. } else {
  554. /* this should NEVER happen */
  555. phpdbg_error(
  556. "No function executed!!");
  557. }
  558. return rc;
  559. } /* }}} */