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 "php.h"
22 #include "phpdbg.h"
23 #include "phpdbg_utils.h"
24 #include "phpdbg_info.h"
25 #include "phpdbg_bp.h"
26 #include "phpdbg_prompt.h"
27
28 ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
29
30 #define PHPDBG_INFO_COMMAND_D(f, h, a, m, l, s) \
31 PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[14])
32
33 const phpdbg_command_t phpdbg_info_commands[] = {
34 PHPDBG_INFO_COMMAND_D(break, "show breakpoints", 'b', info_break, NULL, 0),
35 PHPDBG_INFO_COMMAND_D(files, "show included files", 'F', info_files, NULL, 0),
36 PHPDBG_INFO_COMMAND_D(classes, "show loaded classes", 'c', info_classes, NULL, 0),
37 PHPDBG_INFO_COMMAND_D(funcs, "show loaded classes", 'f', info_funcs, NULL, 0),
38 PHPDBG_INFO_COMMAND_D(error, "show last error", 'e', info_error, NULL, 0),
39 PHPDBG_INFO_COMMAND_D(vars, "show active variables", 'v', info_vars, NULL, 0),
40 PHPDBG_INFO_COMMAND_D(literal, "show active literal constants", 'l', info_literal, NULL, 0),
41 PHPDBG_INFO_COMMAND_D(memory, "show memory manager stats", 'm', info_memory, NULL, 0),
42 PHPDBG_END_COMMAND
43 };
44
PHPDBG_INFO(break)45 PHPDBG_INFO(break) /* {{{ */
46 {
47 phpdbg_print_breakpoints(PHPDBG_BREAK_FILE TSRMLS_CC);
48 phpdbg_print_breakpoints(PHPDBG_BREAK_SYM TSRMLS_CC);
49 phpdbg_print_breakpoints(PHPDBG_BREAK_METHOD TSRMLS_CC);
50 phpdbg_print_breakpoints(PHPDBG_BREAK_OPLINE TSRMLS_CC);
51 phpdbg_print_breakpoints(PHPDBG_BREAK_FILE_OPLINE TSRMLS_CC);
52 phpdbg_print_breakpoints(PHPDBG_BREAK_FUNCTION_OPLINE TSRMLS_CC);
53 phpdbg_print_breakpoints(PHPDBG_BREAK_METHOD_OPLINE TSRMLS_CC);
54 phpdbg_print_breakpoints(PHPDBG_BREAK_COND TSRMLS_CC);
55 phpdbg_print_breakpoints(PHPDBG_BREAK_OPCODE TSRMLS_CC);
56
57 return SUCCESS;
58 } /* }}} */
59
PHPDBG_INFO(files)60 PHPDBG_INFO(files) /* {{{ */
61 {
62 HashPosition pos;
63 char *fname;
64
65 phpdbg_notice("Included files: %d",
66 zend_hash_num_elements(&EG(included_files)));
67
68 zend_hash_internal_pointer_reset_ex(&EG(included_files), &pos);
69 while (zend_hash_get_current_key_ex(&EG(included_files), &fname,
70 NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) {
71 phpdbg_writeln("File: %s", fname);
72 zend_hash_move_forward_ex(&EG(included_files), &pos);
73 }
74
75 return SUCCESS;
76 } /* }}} */
77
PHPDBG_INFO(error)78 PHPDBG_INFO(error) /* {{{ */
79 {
80 if (PG(last_error_message)) {
81 phpdbg_writeln("Last error: %s at %s line %d",
82 PG(last_error_message), PG(last_error_file), PG(last_error_lineno));
83 } else {
84 phpdbg_notice("No error found!");
85 }
86 return SUCCESS;
87 } /* }}} */
88
PHPDBG_INFO(vars)89 PHPDBG_INFO(vars) /* {{{ */
90 {
91 HashTable vars;
92 HashPosition pos;
93 char *var;
94 zval **data;
95
96 if (!EG(active_op_array)) {
97 phpdbg_error("No active op array!");
98 return SUCCESS;
99 }
100
101 if (!EG(active_symbol_table)) {
102 zend_rebuild_symbol_table(TSRMLS_C);
103
104 if (!EG(active_symbol_table)) {
105 phpdbg_error("No active symbol table!");
106 return SUCCESS;
107 }
108 }
109
110 zend_hash_init(&vars, 8, NULL, NULL, 0);
111
112 zend_hash_internal_pointer_reset_ex(EG(active_symbol_table), &pos);
113 while (zend_hash_get_current_key_ex(EG(active_symbol_table), &var,
114 NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) {
115 zend_hash_get_current_data_ex(EG(active_symbol_table), (void **)&data, &pos);
116 if (*var != '_') {
117 zend_hash_update(
118 &vars, var, strlen(var)+1, (void**)data, sizeof(zval*), NULL);
119 }
120 zend_hash_move_forward_ex(EG(active_symbol_table), &pos);
121 }
122
123 {
124 zend_op_array *ops = EG(active_op_array);
125
126 if (ops->function_name) {
127 if (ops->scope) {
128 phpdbg_notice(
129 "Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars));
130 } else {
131 phpdbg_notice(
132 "Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars));
133 }
134 } else {
135 if (ops->filename) {
136 phpdbg_notice(
137 "Variables in %s (%d)", ops->filename, zend_hash_num_elements(&vars));
138 } else {
139 phpdbg_notice(
140 "Variables @ %p (%d)", ops, zend_hash_num_elements(&vars));
141 }
142 }
143 }
144
145 if (zend_hash_num_elements(&vars)) {
146 phpdbg_writeln("Address\t\tRefs\tType\t\tVariable");
147 for (zend_hash_internal_pointer_reset_ex(&vars, &pos);
148 zend_hash_get_current_data_ex(&vars, (void**) &data, &pos) == SUCCESS;
149 zend_hash_move_forward_ex(&vars, &pos)) {
150 char *var;
151
152 zend_hash_get_current_key_ex(&vars, &var, NULL, NULL, 0, &pos);
153
154 if (*data) {
155 phpdbg_write(
156 "%p\t%d\t",
157 *data,
158 Z_REFCOUNT_PP(data));
159
160 switch (Z_TYPE_PP(data)) {
161 case IS_STRING: phpdbg_write("(string)\t"); break;
162 case IS_LONG: phpdbg_write("(integer)\t"); break;
163 case IS_DOUBLE: phpdbg_write("(float)\t"); break;
164 case IS_RESOURCE: phpdbg_write("(resource)\t"); break;
165 case IS_ARRAY: phpdbg_write("(array)\t"); break;
166 case IS_OBJECT: phpdbg_write("(object)\t"); break;
167 case IS_NULL: phpdbg_write("(null)\t"); break;
168 }
169
170 if (Z_TYPE_PP(data) == IS_RESOURCE) {
171 int type;
172
173 phpdbg_writeln(
174 "%s$%s", Z_ISREF_PP(data) ? "&": "", var);
175 if (zend_list_find(Z_RESVAL_PP(data), &type)) {
176 phpdbg_write(
177 "|-------(typeof)------> (%s)",
178 zend_rsrc_list_get_rsrc_type(type TSRMLS_CC));
179 } else {
180 phpdbg_write(
181 "|-------(typeof)------> (unknown)");
182 }
183 phpdbg_writeln(EMPTY);
184 } else if (Z_TYPE_PP(data) == IS_OBJECT) {
185 phpdbg_writeln(
186 "%s$%s", Z_ISREF_PP(data) ? "&": "", var);
187 phpdbg_write(
188 "|-----(instanceof)----> (%s)", Z_OBJCE_PP(data)->name);
189 phpdbg_writeln(EMPTY);
190 } else {
191 phpdbg_write(
192 "%s$%s", Z_ISREF_PP(data) ? "&": "", var);
193 }
194 } else {
195 phpdbg_write(
196 "n/a\tn/a\tn/a\t$%s", var);
197 }
198 phpdbg_writeln(EMPTY);
199 }
200 }
201
202 zend_hash_destroy(&vars);
203
204 return SUCCESS;
205 } /* }}} */
206
PHPDBG_INFO(literal)207 PHPDBG_INFO(literal) /* {{{ */
208 {
209 if ((EG(in_execution) && EG(active_op_array)) || PHPDBG_G(ops)) {
210 zend_op_array *ops = EG(active_op_array) ? EG(active_op_array) : PHPDBG_G(ops);
211 int literal = 0, count = ops->last_literal-1;
212
213 if (ops->function_name) {
214 if (ops->scope) {
215 phpdbg_notice(
216 "Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count);
217 } else {
218 phpdbg_notice(
219 "Literal Constants in %s() (%d)", ops->function_name, count);
220 }
221 } else {
222 if (ops->filename) {
223 phpdbg_notice(
224 "Literal Constants in %s (%d)", ops->filename, count);
225 } else {
226 phpdbg_notice(
227 "Literal Constants @ %p (%d)", ops, count);
228 }
229 }
230
231 while (literal < ops->last_literal) {
232 if (Z_TYPE(ops->literals[literal].constant) != IS_NULL) {
233 phpdbg_write("|-------- C%u -------> [", literal);
234 zend_print_zval(
235 &ops->literals[literal].constant, 0);
236 phpdbg_write("]");
237 phpdbg_writeln(EMPTY);
238 }
239 literal++;
240 }
241 } else {
242 phpdbg_error("Not executing!");
243 }
244
245 return SUCCESS;
246 } /* }}} */
247
PHPDBG_INFO(memory)248 PHPDBG_INFO(memory) /* {{{ */
249 {
250 if (is_zend_mm(TSRMLS_C)) {
251 phpdbg_notice("Memory Manager Information");
252 phpdbg_notice("Current");
253 phpdbg_writeln("|-------> Used:\t%.3f kB",
254 (float) (zend_memory_usage(0 TSRMLS_CC)/1024));
255 phpdbg_writeln("|-------> Real:\t%.3f kB",
256 (float) (zend_memory_usage(1 TSRMLS_CC)/1024));
257 phpdbg_notice("Peak");
258 phpdbg_writeln("|-------> Used:\t%.3f kB",
259 (float) (zend_memory_peak_usage(0 TSRMLS_CC)/1024));
260 phpdbg_writeln("|-------> Real:\t%.3f kB",
261 (float) (zend_memory_peak_usage(1 TSRMLS_CC)/1024));
262 } else {
263 phpdbg_error("Memory Manager Disabled!");
264 }
265 return SUCCESS;
266 } /* }}} */
267
phpdbg_print_class_name(zend_class_entry ** ce TSRMLS_DC)268 static inline void phpdbg_print_class_name(zend_class_entry **ce TSRMLS_DC) /* {{{ */
269 {
270 phpdbg_write(
271 "%s %s %s (%d)",
272 ((*ce)->type == ZEND_USER_CLASS) ?
273 "User" : "Internal",
274 ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ?
275 "Interface" :
276 ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ?
277 "Abstract Class" :
278 "Class",
279 (*ce)->name, zend_hash_num_elements(&(*ce)->function_table));
280 } /* }}} */
281
PHPDBG_INFO(classes)282 PHPDBG_INFO(classes) /* {{{ */
283 {
284 HashPosition position;
285 zend_class_entry **ce;
286 HashTable classes;
287
288 zend_hash_init(&classes, 8, NULL, NULL, 0);
289
290 for (zend_hash_internal_pointer_reset_ex(EG(class_table), &position);
291 zend_hash_get_current_data_ex(EG(class_table), (void**)&ce, &position) == SUCCESS;
292 zend_hash_move_forward_ex(EG(class_table), &position)) {
293
294 if ((*ce)->type == ZEND_USER_CLASS) {
295 zend_hash_next_index_insert(
296 &classes, ce, sizeof(ce), NULL);
297 }
298 }
299
300 phpdbg_notice("User Classes (%d)",
301 zend_hash_num_elements(&classes));
302
303 for (zend_hash_internal_pointer_reset_ex(&classes, &position);
304 zend_hash_get_current_data_ex(&classes, (void**)&ce, &position) == SUCCESS;
305 zend_hash_move_forward_ex(&classes, &position)) {
306
307 phpdbg_print_class_name(ce TSRMLS_CC);
308 phpdbg_writeln(EMPTY);
309
310 if ((*ce)->parent) {
311 zend_class_entry *pce = (*ce)->parent;
312 do {
313 phpdbg_write("|-------- ");
314 phpdbg_print_class_name(&pce TSRMLS_CC);
315 phpdbg_writeln(EMPTY);
316 } while ((pce = pce->parent));
317 }
318
319 if ((*ce)->info.user.filename) {
320 phpdbg_writeln(
321 "|---- in %s on line %u",
322 (*ce)->info.user.filename,
323 (*ce)->info.user.line_start);
324 } else {
325 phpdbg_writeln("|---- no source code");
326 }
327 phpdbg_writeln(EMPTY);
328 }
329
330 zend_hash_destroy(&classes);
331
332 return SUCCESS;
333 } /* }}} */
334
PHPDBG_INFO(funcs)335 PHPDBG_INFO(funcs) /* {{{ */
336 {
337 HashPosition position;
338 zend_function *zf, **pzf;
339 HashTable functions;
340
341 zend_hash_init(&functions, 8, NULL, NULL, 0);
342
343 for (zend_hash_internal_pointer_reset_ex(EG(function_table), &position);
344 zend_hash_get_current_data_ex(EG(function_table), (void**)&zf, &position) == SUCCESS;
345 zend_hash_move_forward_ex(EG(function_table), &position)) {
346
347 if (zf->type == ZEND_USER_FUNCTION) {
348 zend_hash_next_index_insert(
349 &functions, (void**) &zf, sizeof(zend_function), NULL);
350 }
351 }
352
353 phpdbg_notice("User Functions (%d)",
354 zend_hash_num_elements(&functions));
355
356 for (zend_hash_internal_pointer_reset_ex(&functions, &position);
357 zend_hash_get_current_data_ex(&functions, (void**)&pzf, &position) == SUCCESS;
358 zend_hash_move_forward_ex(&functions, &position)) {
359 zend_op_array *op_array = &((*pzf)->op_array);
360
361 phpdbg_writeln(
362 "|-------- %s in %s on line %d",
363 op_array->function_name ? op_array->function_name : "{main}",
364 op_array->filename ? op_array->filename : "(no source code)",
365 op_array->line_start);
366 }
367
368 zend_hash_destroy(&functions);
369
370 return SUCCESS;
371 } /* }}} */
372