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