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 "zend.h"
22 #include "phpdbg.h"
23 #include "phpdbg_utils.h"
24 #include "phpdbg_frame.h"
25 #include "phpdbg_list.h"
26
27 ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
28
phpdbg_restore_frame(TSRMLS_D)29 void phpdbg_restore_frame(TSRMLS_D) /* {{{ */
30 {
31 if (PHPDBG_FRAME(num) == 0) {
32 return;
33 }
34
35 PHPDBG_FRAME(num) = 0;
36
37 /* move things back */
38 EG(current_execute_data) = PHPDBG_FRAME(execute_data);
39
40 EG(opline_ptr) = &PHPDBG_EX(opline);
41 EG(active_op_array) = PHPDBG_EX(op_array);
42 EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value);
43 EG(active_symbol_table) = PHPDBG_EX(symbol_table);
44 EG(This) = PHPDBG_EX(current_this);
45 EG(scope) = PHPDBG_EX(current_scope);
46 EG(called_scope) = PHPDBG_EX(current_called_scope);
47 } /* }}} */
48
phpdbg_switch_frame(int frame TSRMLS_DC)49 void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */
50 {
51 zend_execute_data *execute_data = PHPDBG_FRAME(num)?PHPDBG_FRAME(execute_data):EG(current_execute_data);
52 int i = 0;
53
54 if (PHPDBG_FRAME(num) == frame) {
55 phpdbg_notice("Already in frame #%d", frame);
56 return;
57 }
58
59 while (execute_data) {
60 if (i++ == frame) {
61 break;
62 }
63
64 do {
65 execute_data = execute_data->prev_execute_data;
66 } while (execute_data && execute_data->opline == NULL);
67 }
68
69 if (execute_data == NULL) {
70 phpdbg_error("No frame #%d", frame);
71 return;
72 }
73
74 phpdbg_restore_frame(TSRMLS_C);
75
76 if (frame > 0) {
77 PHPDBG_FRAME(num) = frame;
78
79 /* backup things and jump back */
80 PHPDBG_FRAME(execute_data) = EG(current_execute_data);
81 EG(current_execute_data) = execute_data;
82
83 EG(opline_ptr) = &PHPDBG_EX(opline);
84 EG(active_op_array) = PHPDBG_EX(op_array);
85 PHPDBG_FRAME(execute_data)->original_return_value = EG(return_value_ptr_ptr);
86 EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value);
87 EG(active_symbol_table) = PHPDBG_EX(symbol_table);
88 EG(This) = PHPDBG_EX(current_this);
89 EG(scope) = PHPDBG_EX(current_scope);
90 EG(called_scope) = PHPDBG_EX(current_called_scope);
91 }
92
93 phpdbg_notice("Switched to frame #%d", frame);
94 phpdbg_list_file(
95 zend_get_executed_filename(TSRMLS_C),
96 3,
97 zend_get_executed_lineno(TSRMLS_C)-1,
98 zend_get_executed_lineno(TSRMLS_C)
99 TSRMLS_CC
100 );
101 } /* }}} */
102
phpdbg_dump_prototype(zval ** tmp TSRMLS_DC)103 static void phpdbg_dump_prototype(zval **tmp TSRMLS_DC) /* {{{ */
104 {
105 zval **funcname, **class, **type, **args, **argstmp;
106 char is_class;
107
108 zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"),
109 (void **)&funcname);
110
111 if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp),
112 "object", sizeof("object"), (void **)&class)) == FAILURE) {
113 is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"),
114 (void **)&class);
115 } else {
116 zend_get_object_classname(*class, (const char **)&Z_STRVAL_PP(class),
117 (zend_uint *)&Z_STRLEN_PP(class) TSRMLS_CC);
118 }
119
120 if (is_class == SUCCESS) {
121 zend_hash_find(Z_ARRVAL_PP(tmp), "type", sizeof("type"), (void **)&type);
122 }
123
124 phpdbg_write("%s%s%s(",
125 is_class == FAILURE?"":Z_STRVAL_PP(class),
126 is_class == FAILURE?"":Z_STRVAL_PP(type),
127 Z_STRVAL_PP(funcname)
128 );
129
130 if (zend_hash_find(Z_ARRVAL_PP(tmp), "args", sizeof("args"),
131 (void **)&args) == SUCCESS) {
132 HashPosition iterator;
133 const zend_function *func = phpdbg_get_function(
134 Z_STRVAL_PP(funcname), is_class == FAILURE ? NULL : Z_STRVAL_PP(class) TSRMLS_CC);
135 const zend_arg_info *arginfo = func ? func->common.arg_info : NULL;
136 int j = 0, m = func ? func->common.num_args : 0;
137 zend_bool is_variadic = 0;
138
139 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(args), &iterator);
140 while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args),
141 (void **) &argstmp, &iterator) == SUCCESS) {
142 if (j) {
143 phpdbg_write(", ");
144 }
145 if (m && j < m) {
146 #if PHP_VERSION_ID >= 50600
147 is_variadic = arginfo[j].is_variadic;
148 #endif
149 phpdbg_write("%s=%s",
150 arginfo[j].name, is_variadic ? "[": "");
151 }
152 ++j;
153
154 zend_print_flat_zval_r(*argstmp TSRMLS_CC);
155 zend_hash_move_forward_ex(Z_ARRVAL_PP(args), &iterator);
156 }
157 if (is_variadic) {
158 phpdbg_write("]");
159 }
160 }
161 phpdbg_write(")");
162 }
163
phpdbg_dump_backtrace(size_t num TSRMLS_DC)164 void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */
165 {
166 zval zbacktrace;
167 zval **tmp;
168 zval **file, **line;
169 HashPosition position;
170 int i = 0, limit = num;
171 int user_defined;
172
173 if (limit < 0) {
174 phpdbg_error("Invalid backtrace size %d", limit);
175 }
176
177 zend_fetch_debug_backtrace(
178 &zbacktrace, 0, 0, limit TSRMLS_CC);
179
180 zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
181 zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position);
182 while (1) {
183 user_defined = zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **)&file);
184 zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **)&line);
185 zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position);
186
187 if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace),
188 (void**)&tmp, &position) == FAILURE) {
189 phpdbg_write("frame #%d: {main} at %s:%ld", i, Z_STRVAL_PP(file), Z_LVAL_PP(line));
190 break;
191 }
192
193 if (user_defined == SUCCESS) {
194 phpdbg_write("frame #%d: ", i++);
195 phpdbg_dump_prototype(tmp TSRMLS_CC);
196 phpdbg_writeln(" at %s:%ld", Z_STRVAL_PP(file), Z_LVAL_PP(line));
197 } else {
198 phpdbg_write(" => ");
199 phpdbg_dump_prototype(tmp TSRMLS_CC);
200 phpdbg_writeln(" (internal function)");
201 }
202 }
203
204 phpdbg_writeln(EMPTY);
205 zval_dtor(&zbacktrace);
206 } /* }}} */
207