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.

448 lines
10 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
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2014 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 <stdio.h>
  21. #include <ctype.h>
  22. #include <string.h>
  23. #include "zend.h"
  24. #include "php.h"
  25. #include "spprintf.h"
  26. #include "phpdbg.h"
  27. #include "phpdbg_opcode.h"
  28. #include "phpdbg_utils.h"
  29. #ifdef _WIN32
  30. # include "win32/time.h"
  31. #elif defined(HAVE_SYS_IOCTL_H)
  32. # include "sys/ioctl.h"
  33. #endif
  34. ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
  35. /* {{{ color structures */
  36. const static phpdbg_color_t colors[] = {
  37. PHPDBG_COLOR_D("none", "0;0"),
  38. PHPDBG_COLOR_D("white", "0;64"),
  39. PHPDBG_COLOR_D("white-bold", "1;64"),
  40. PHPDBG_COLOR_D("white-underline", "4;64"),
  41. PHPDBG_COLOR_D("red", "0;31"),
  42. PHPDBG_COLOR_D("red-bold", "1;31"),
  43. PHPDBG_COLOR_D("red-underline", "4;31"),
  44. PHPDBG_COLOR_D("green", "0;32"),
  45. PHPDBG_COLOR_D("green-bold", "1;32"),
  46. PHPDBG_COLOR_D("green-underline", "4;32"),
  47. PHPDBG_COLOR_D("yellow", "0;33"),
  48. PHPDBG_COLOR_D("yellow-bold", "1;33"),
  49. PHPDBG_COLOR_D("yellow-underline", "4;33"),
  50. PHPDBG_COLOR_D("blue", "0;34"),
  51. PHPDBG_COLOR_D("blue-bold", "1;34"),
  52. PHPDBG_COLOR_D("blue-underline", "4;34"),
  53. PHPDBG_COLOR_D("purple", "0;35"),
  54. PHPDBG_COLOR_D("purple-bold", "1;35"),
  55. PHPDBG_COLOR_D("purple-underline", "4;35"),
  56. PHPDBG_COLOR_D("cyan", "0;36"),
  57. PHPDBG_COLOR_D("cyan-bold", "1;36"),
  58. PHPDBG_COLOR_D("cyan-underline", "4;36"),
  59. PHPDBG_COLOR_D("black", "0;30"),
  60. PHPDBG_COLOR_D("black-bold", "1;30"),
  61. PHPDBG_COLOR_D("black-underline", "4;30"),
  62. PHPDBG_COLOR_END
  63. }; /* }}} */
  64. /* {{{ */
  65. const static phpdbg_element_t elements[] = {
  66. PHPDBG_ELEMENT_D("prompt", PHPDBG_COLOR_PROMPT),
  67. PHPDBG_ELEMENT_D("error", PHPDBG_COLOR_ERROR),
  68. PHPDBG_ELEMENT_D("notice", PHPDBG_COLOR_NOTICE),
  69. PHPDBG_ELEMENT_END
  70. }; /* }}} */
  71. PHPDBG_API int phpdbg_is_numeric(const char *str) /* {{{ */
  72. {
  73. if (!str)
  74. return 0;
  75. for (; *str; str++) {
  76. if (isspace(*str) || *str == '-') {
  77. continue;
  78. }
  79. return isdigit(*str);
  80. }
  81. return 0;
  82. } /* }}} */
  83. PHPDBG_API int phpdbg_is_empty(const char *str) /* {{{ */
  84. {
  85. if (!str)
  86. return 1;
  87. for (; *str; str++) {
  88. if (isspace(*str)) {
  89. continue;
  90. }
  91. return 0;
  92. }
  93. return 1;
  94. } /* }}} */
  95. PHPDBG_API int phpdbg_is_addr(const char *str) /* {{{ */
  96. {
  97. return str[0] && str[1] && memcmp(str, "0x", 2) == 0;
  98. } /* }}} */
  99. PHPDBG_API int phpdbg_is_class_method(const char *str, size_t len, char **class, char **method) /* {{{ */
  100. {
  101. char *sep = NULL;
  102. if (strstr(str, "#") != NULL)
  103. return 0;
  104. if (strstr(str, " ") != NULL)
  105. return 0;
  106. sep = strstr(str, "::");
  107. if (!sep || sep == str || sep+2 == str+len-1) {
  108. return 0;
  109. }
  110. if (class != NULL) {
  111. if (str[0] == '\\') {
  112. str++;
  113. len--;
  114. }
  115. *class = estrndup(str, sep - str);
  116. (*class)[sep - str] = 0;
  117. }
  118. if (method != NULL) {
  119. *method = estrndup(sep+2, str + len - (sep + 2));
  120. }
  121. return 1;
  122. } /* }}} */
  123. PHPDBG_API char *phpdbg_resolve_path(const char *path TSRMLS_DC) /* {{{ */
  124. {
  125. char resolved_name[MAXPATHLEN];
  126. if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) {
  127. return NULL;
  128. }
  129. return estrdup(resolved_name);
  130. } /* }}} */
  131. PHPDBG_API const char *phpdbg_current_file(TSRMLS_D) /* {{{ */
  132. {
  133. const char *file = zend_get_executed_filename(TSRMLS_C);
  134. if (memcmp(file, "[no active file]", sizeof("[no active file]")) == 0) {
  135. return PHPDBG_G(exec);
  136. }
  137. return file;
  138. } /* }}} */
  139. PHPDBG_API const zend_function *phpdbg_get_function(const char *fname, const char *cname TSRMLS_DC) /* {{{ */
  140. {
  141. zend_function *func = NULL;
  142. size_t fname_len = strlen(fname);
  143. char *lcname = zend_str_tolower_dup(fname, fname_len);
  144. if (cname) {
  145. zend_class_entry **ce;
  146. size_t cname_len = strlen(cname);
  147. char *lc_cname = zend_str_tolower_dup(cname, cname_len);
  148. int ret = zend_lookup_class(lc_cname, cname_len, &ce TSRMLS_CC);
  149. efree(lc_cname);
  150. if (ret == SUCCESS) {
  151. zend_hash_find(&(*ce)->function_table, lcname, fname_len+1,
  152. (void**)&func);
  153. }
  154. } else {
  155. zend_hash_find(EG(function_table), lcname, fname_len+1,
  156. (void**)&func);
  157. }
  158. efree(lcname);
  159. return func;
  160. } /* }}} */
  161. PHPDBG_API char *phpdbg_trim(const char *str, size_t len, size_t *new_len) /* {{{ */
  162. {
  163. const char *p = str;
  164. char *new = NULL;
  165. while (p && isspace(*p)) {
  166. ++p;
  167. --len;
  168. }
  169. while (*p && isspace(*(p + len -1))) {
  170. --len;
  171. }
  172. if (len == 0) {
  173. new = estrndup("", sizeof(""));
  174. *new_len = 0;
  175. } else {
  176. new = estrndup(p, len);
  177. *(new + len) = '\0';
  178. if (new_len) {
  179. *new_len = len;
  180. }
  181. }
  182. return new;
  183. } /* }}} */
  184. PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ...) /* {{{ */
  185. {
  186. int rc = 0;
  187. char *buffer = NULL;
  188. va_list args;
  189. if (format != NULL && strlen(format) > 0L) {
  190. va_start(args, format);
  191. vspprintf(&buffer, 0, format, args);
  192. va_end(args);
  193. }
  194. /* TODO(anyone) colours */
  195. switch (type) {
  196. case P_ERROR:
  197. if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
  198. rc = fprintf(fp,
  199. "\033[%sm[%s]\033[0m\n",
  200. PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, buffer);
  201. } else {
  202. rc = fprintf(fp, "[%s]\n", buffer);
  203. }
  204. break;
  205. case P_NOTICE:
  206. if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
  207. rc = fprintf(fp,
  208. "\033[%sm[%s]\033[0m\n",
  209. PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, buffer);
  210. } else {
  211. rc = fprintf(fp, "[%s]\n", buffer);
  212. }
  213. break;
  214. case P_WRITELN: {
  215. if (buffer) {
  216. rc = fprintf(fp, "%s\n", buffer);
  217. } else {
  218. rc = fprintf(fp, "\n");
  219. }
  220. } break;
  221. case P_WRITE:
  222. if (buffer) {
  223. rc = fprintf(fp, "%s", buffer);
  224. }
  225. break;
  226. /* no formatting on logging output */
  227. case P_LOG:
  228. if (buffer) {
  229. struct timeval tp;
  230. if (gettimeofday(&tp, NULL) == SUCCESS) {
  231. rc = fprintf(fp, "[%ld %.8F]: %s\n", tp.tv_sec, tp.tv_usec / 1000000.00, buffer);
  232. } else {
  233. rc = FAILURE;
  234. }
  235. }
  236. break;
  237. }
  238. if (buffer) {
  239. efree(buffer);
  240. }
  241. return rc;
  242. } /* }}} */
  243. PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */
  244. int rc = 0;
  245. va_list args;
  246. struct timeval tp;
  247. va_start(args, fmt);
  248. if (gettimeofday(&tp, NULL) == SUCCESS) {
  249. char friendly[100];
  250. char *format = NULL, *buffer = NULL;
  251. const time_t tt = tp.tv_sec;
  252. strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tt));
  253. asprintf(
  254. &buffer, friendly, tp.tv_usec/1000);
  255. asprintf(
  256. &format, "[%s]: %s\n", buffer, fmt);
  257. rc = vfprintf(
  258. fp, format, args);
  259. free(format);
  260. free(buffer);
  261. }
  262. va_end(args);
  263. return rc;
  264. } /* }}} */
  265. PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC) /* {{{ */
  266. {
  267. const phpdbg_color_t *color = colors;
  268. while (color && color->name) {
  269. if (name_length == color->name_length &&
  270. memcmp(name, color->name, name_length) == SUCCESS) {
  271. phpdbg_debug(
  272. "phpdbg_get_color(%s, %lu): %s", name, name_length, color->code);
  273. return color;
  274. }
  275. ++color;
  276. }
  277. phpdbg_debug(
  278. "phpdbg_get_color(%s, %lu): failed", name, name_length);
  279. return NULL;
  280. } /* }}} */
  281. PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC) /* {{{ */
  282. {
  283. PHPDBG_G(colors)[element] = color;
  284. } /* }}} */
  285. PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC) /* {{{ */
  286. {
  287. const phpdbg_color_t *color = phpdbg_get_color(name, name_length TSRMLS_CC);
  288. if (color) {
  289. phpdbg_set_color(element, color TSRMLS_CC);
  290. } else PHPDBG_G(colors)[element] = colors;
  291. } /* }}} */
  292. PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D) /* {{{ */
  293. {
  294. return colors;
  295. } /* }}} */
  296. PHPDBG_API int phpdbg_get_element(const char *name, size_t len TSRMLS_DC) {
  297. const phpdbg_element_t *element = elements;
  298. while (element && element->name) {
  299. if (len == element->name_length) {
  300. if (strncasecmp(name, element->name, len) == SUCCESS) {
  301. return element->id;
  302. }
  303. }
  304. element++;
  305. }
  306. return PHPDBG_COLOR_INVALID;
  307. }
  308. PHPDBG_API void phpdbg_set_prompt(const char *prompt TSRMLS_DC) /* {{{ */
  309. {
  310. /* free formatted prompt */
  311. if (PHPDBG_G(prompt)[1]) {
  312. free(PHPDBG_G(prompt)[1]);
  313. PHPDBG_G(prompt)[1] = NULL;
  314. }
  315. /* free old prompt */
  316. if (PHPDBG_G(prompt)[0]) {
  317. free(PHPDBG_G(prompt)[0]);
  318. PHPDBG_G(prompt)[0] = NULL;
  319. }
  320. /* copy new prompt */
  321. PHPDBG_G(prompt)[0] = strdup(prompt);
  322. } /* }}} */
  323. PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */
  324. {
  325. /* find cached prompt */
  326. if (PHPDBG_G(prompt)[1]) {
  327. return PHPDBG_G(prompt)[1];
  328. }
  329. /* create cached prompt */
  330. if ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED)) {
  331. asprintf(
  332. &PHPDBG_G(prompt)[1], "\033[%sm%s\033[0m ",
  333. PHPDBG_G(colors)[PHPDBG_COLOR_PROMPT]->code,
  334. PHPDBG_G(prompt)[0]);
  335. } else {
  336. asprintf(
  337. &PHPDBG_G(prompt)[1], "%s ",
  338. PHPDBG_G(prompt)[0]);
  339. }
  340. return PHPDBG_G(prompt)[1];
  341. } /* }}} */
  342. int phpdbg_rebuild_symtable(TSRMLS_D) {
  343. if (!EG(active_op_array)) {
  344. phpdbg_error("No active op array!");
  345. return FAILURE;
  346. }
  347. if (!EG(active_symbol_table)) {
  348. zend_rebuild_symbol_table(TSRMLS_C);
  349. if (!EG(active_symbol_table)) {
  350. phpdbg_error("No active symbol table!");
  351. return FAILURE;
  352. }
  353. }
  354. return SUCCESS;
  355. }
  356. PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D) /* {{{ */
  357. {
  358. int columns;
  359. #ifdef _WIN32
  360. CONSOLE_SCREEN_BUFFER_INFO csbi;
  361. GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
  362. columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
  363. #elif defined(HAVE_SYS_IOCTL_H)
  364. struct winsize w;
  365. columns = ioctl(fileno(stdout), TIOCGWINSZ, &w) == 0 ? w.ws_col : 100;
  366. #else
  367. columns = 100;
  368. #endif
  369. return columns;
  370. } /* }}} */