xref: /PHP-5.6/sapi/phpdbg/phpdbg_info.c (revision 49493a2d)
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