php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
phpdbg_frame.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Felipe Pena <felipe@php.net> |
14 | Authors: Joe Watkins <joe.watkins@live.co.uk> |
15 | Authors: Bob Weinand <bwoebi@php.net> |
16 +----------------------------------------------------------------------+
17*/
18
19#include "zend.h"
20#include "phpdbg.h"
21#include "phpdbg_utils.h"
22#include "phpdbg_frame.h"
23#include "phpdbg_list.h"
24#include "zend_smart_str.h"
25
27
28static inline void phpdbg_append_individual_arg(smart_str *s, uint32_t i, zend_function *func, zval *arg) {
29 const zend_arg_info *arginfo = func->common.arg_info;
30 char *arg_name = NULL;
31
32 if (i) {
33 smart_str_appends(s, ", ");
34 }
35 if (i < func->common.num_args) {
36 if (arginfo) {
37 if (func->type == ZEND_INTERNAL_FUNCTION) {
38 arg_name = (char *) ((zend_internal_arg_info *) &arginfo[i])->name;
39 } else {
40 arg_name = ZSTR_VAL(arginfo[i].name);
41 }
42 }
43 smart_str_appends(s, arg_name ? arg_name : "?");
44 smart_str_appendc(s, '=');
45 }
46 {
47 char *arg_print = phpdbg_short_zval_print(arg, 40);
48 smart_str_appends(s, arg_print);
49 efree(arg_print);
50 }
51}
52
54 smart_str s = {0};
55 zend_op_array *op_array = &ex->func->op_array;
56 uint32_t i = 0, first_extra_arg = op_array->num_args, num_args = ZEND_CALL_NUM_ARGS(ex);
57 zval *p = ZEND_CALL_ARG(ex, 1);
58
59 if (op_array->scope) {
60 smart_str_append(&s, op_array->scope->name);
61 smart_str_appends(&s, "::");
62 }
63 smart_str_append(&s, op_array->function_name);
64 smart_str_appendc(&s, '(');
65 if (ZEND_CALL_NUM_ARGS(ex) > first_extra_arg) {
66 while (i < first_extra_arg) {
67 phpdbg_append_individual_arg(&s, i, ex->func, p);
68 p++;
69 i++;
70 }
71 p = ZEND_CALL_VAR_NUM(ex, op_array->last_var + op_array->T);
72 }
73 while (i < num_args) {
74 phpdbg_append_individual_arg(&s, i, ex->func, p);
75 p++;
76 i++;
77 }
78 smart_str_appendc(&s, ')');
79
80 if (ex->func->type == ZEND_USER_FUNCTION) {
81 smart_str_appends(&s, " at ");
82 smart_str_append(&s, op_array->filename);
83 smart_str_appendc(&s, ':');
84 smart_str_append_unsigned(&s, ex->opline->lineno);
85 } else {
86 smart_str_appends(&s, " [internal function]");
87 }
88
89 return s.s;
90}
91
93 const char *file_chr = zend_get_executed_filename();
94 zend_string *file = zend_string_init(file_chr, strlen(file_chr), 0);
95
97 efree(file);
98}
99
100void phpdbg_restore_frame(void) /* {{{ */
101{
102 if (PHPDBG_FRAME(num) == 0) {
103 return;
104 }
105
106 if (PHPDBG_FRAME(generator)) {
107 if (PHPDBG_FRAME(generator)->execute_data->call) {
109 }
111 }
112
113 PHPDBG_FRAME(num) = 0;
114
115 /* move things back */
116 EG(current_execute_data) = PHPDBG_FRAME(execute_data);
117} /* }}} */
118
119void phpdbg_switch_frame(int frame) /* {{{ */
120{
121 zend_execute_data *execute_data = PHPDBG_FRAME(num) ? PHPDBG_FRAME(execute_data) : EG(current_execute_data);
122 int i = 0;
123
124 if (PHPDBG_FRAME(num) == frame) {
125 phpdbg_notice("Already in frame #%d", frame);
126 return;
127 }
128
130 while (execute_data) {
131 if (i++ == frame) {
132 break;
133 }
134
135 do {
136 execute_data = execute_data->prev_execute_data;
137 } while (execute_data && execute_data->opline == NULL);
138 }
140 phpdbg_error("Couldn't switch frames, invalid data source");
141 return;
143
144 if (execute_data == NULL) {
145 phpdbg_error("No frame #%d", frame);
146 return;
147 }
148
150
151 if (frame > 0) {
152 PHPDBG_FRAME(num) = frame;
153
154 /* backup things and jump back */
155 PHPDBG_FRAME(execute_data) = EG(current_execute_data);
156 EG(current_execute_data) = execute_data;
157 }
158
160 zend_string *s = phpdbg_compile_stackframe(EG(current_execute_data));
161 phpdbg_notice("Switched to frame #%d: %.*s", frame, (int) ZSTR_LEN(s), ZSTR_VAL(s));
162 zend_string_release(s);
164 phpdbg_notice("Switched to frame #%d", frame);
166
168} /* }}} */
169
170static void phpdbg_dump_prototype(zval *tmp) /* {{{ */
171{
172 zval *funcname, *class, class_zv, *args, *argstmp;
173
174 funcname = zend_hash_find(Z_ARRVAL_P(tmp), ZSTR_KNOWN(ZEND_STR_FUNCTION));
175
176 if ((class = zend_hash_find(Z_ARRVAL_P(tmp), ZSTR_KNOWN(ZEND_STR_OBJECT)))) {
177 ZVAL_NEW_STR(&class_zv, Z_OBJCE_P(class)->name);
178 class = &class_zv;
179 } else {
180 class = zend_hash_find(Z_ARRVAL_P(tmp), ZSTR_KNOWN(ZEND_STR_CLASS));
181 }
182
183 if (class) {
184 zval *type = zend_hash_find(Z_ARRVAL_P(tmp), ZSTR_KNOWN(ZEND_STR_TYPE));
185
186 phpdbg_out("%s%s%s(", Z_STRVAL_P(class), Z_STRVAL_P(type), Z_STRVAL_P(funcname));
187 } else {
188 phpdbg_out("%s(", Z_STRVAL_P(funcname));
189 }
190
191 args = zend_hash_find(Z_ARRVAL_P(tmp), ZSTR_KNOWN(ZEND_STR_ARGS));
192
193 if (args) {
194 const zend_function *func = NULL;
195 const zend_arg_info *arginfo = NULL;
196 bool is_variadic = 0;
197 int j = 0, m;
198
200 /* assuming no autoloader call is necessary, class should have been loaded if it's in backtrace ... */
201 if ((func = phpdbg_get_function(Z_STRVAL_P(funcname), class ? Z_STRVAL_P(class) : NULL))) {
202 arginfo = func->common.arg_info;
203 }
205
206 m = func ? func->common.num_args : 0;
207
209 if (j) {
210 phpdbg_out(", ");
211 }
212 if (m && j < m) {
213 char *arg_name = NULL;
214
215 if (arginfo) {
216 if (func->type == ZEND_INTERNAL_FUNCTION) {
217 arg_name = (char *)((zend_internal_arg_info *)&arginfo[j])->name;
218 } else {
219 arg_name = ZSTR_VAL(arginfo[j].name);
220 }
221 }
222
223 if (!is_variadic) {
224 is_variadic = arginfo ? ZEND_ARG_IS_VARIADIC(&arginfo[j]) : 0;
225 }
226
227 phpdbg_out("%s=%s", arg_name ? arg_name : "?", is_variadic ? "[": "");
228
229 }
230 ++j;
231
232 {
233 char *arg_print = phpdbg_short_zval_print(argstmp, 40);
234 php_printf("%s", arg_print);
235 efree(arg_print);
236 }
238
239 if (is_variadic) {
240 phpdbg_out("]");
241 }
242 }
243 phpdbg_out(")");
244}
245
246void phpdbg_dump_backtrace(size_t num) /* {{{ */
247{
248 HashPosition position;
249 zval zbacktrace;
250 zval *tmp;
251 zval startline, startfile;
252 const char *startfilename;
253 zval *file = &startfile, *line = &startline;
254 int i = 0, limit = num;
255
257
258 if (limit < 0) {
259 phpdbg_error("Invalid backtrace size %d", limit);
260
262 return;
263 }
264
266 zend_fetch_debug_backtrace(&zbacktrace, 0, 0, limit);
268 phpdbg_error("Couldn't fetch backtrace, invalid data source");
269 return;
271
272 Z_LVAL(startline) = zend_get_executed_lineno();
273 startfilename = zend_get_executed_filename();
274 Z_STR(startfile) = zend_string_init(startfilename, strlen(startfilename), 0);
275
276 zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
277
278 zval *function_name = NULL;
279 while ((tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position))) {
280 if (file) { /* userland */
281 phpdbg_out("frame #%d: ", i);
282 phpdbg_dump_prototype(tmp);
284 i++;
285 } else {
286 phpdbg_out(" => ");
287 phpdbg_dump_prototype(tmp);
288 phpdbg_out(" (internal function)\n");
289 }
290
291 file = zend_hash_find(Z_ARRVAL_P(tmp), ZSTR_KNOWN(ZEND_STR_FILE));
292 line = zend_hash_find(Z_ARRVAL_P(tmp), ZSTR_KNOWN(ZEND_STR_LINE));
293 function_name = zend_hash_find(Z_ARRVAL_P(tmp), ZSTR_KNOWN(ZEND_STR_FUNCTION));
294
295 zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position);
296 }
297
298 /* This is possible for fibers' start closure for example, which have a frame that doesn't contain the info
299 * of which location stated the fiber if that stack frame is already torn down. same behaviour with debug_backtrace(). */
300 if (file == NULL) {
301 phpdbg_writeln(" => %s (internal function)", Z_STRVAL_P(function_name));
302 } else {
303 phpdbg_writeln("frame #%d: {main} at %s:"ZEND_LONG_FMT, i, Z_STRVAL_P(file), Z_LVAL_P(line));
304 }
305
306 zval_ptr_dtor_nogc(&zbacktrace);
307 zend_string_release(Z_STR(startfile));
308
310} /* }}} */
311
313 zend_string *s;
314
315 if (EG(current_execute_data) == gen->execute_data) {
316 return;
317 }
318
320
321 PHPDBG_FRAME(num) = -1;
322 PHPDBG_FRAME(generator) = gen;
323
324 EG(current_execute_data) = gen->execute_data;
325 if (gen->frozen_call_stack) {
327 }
329
330 s = phpdbg_compile_stackframe(EG(current_execute_data));
331 phpdbg_notice("Switched to generator with handle #%d: %.*s", gen->std.handle, (int) ZSTR_LEN(s), ZSTR_VAL(s));
332 zend_string_release(s);
334}
file(string $filename, int $flags=0, $context=null)
char s[4]
Definition cdf.c:77
Definition test.php:8
zend_ffi_type * type
Definition ffi.c:3812
zval * arg
Definition ffi.c:3975
#define NULL
Definition gdcache.h:45
again j
PHPAPI size_t php_printf(const char *format,...)
Definition main.c:938
int line
Definition php_ffi.h:54
#define phpdbg_try_access
Definition phpdbg.h:194
#define phpdbg_catch_access
Definition phpdbg.h:201
#define phpdbg_end_try_access()
Definition phpdbg.h:204
phpdbg_frame_t frame
Definition phpdbg.h:236
#define PHPDBG_FRAME(v)
Definition phpdbg_cmd.h:106
void phpdbg_open_generator_frame(zend_generator *gen)
zend_string * phpdbg_compile_stackframe(zend_execute_data *ex)
void phpdbg_dump_backtrace(size_t num)
void phpdbg_switch_frame(int frame)
void phpdbg_restore_frame(void)
void phpdbg_print_cur_frame_info(void)
void phpdbg_list_file(zend_string *filename, uint32_t count, int offset, uint32_t highlight)
#define phpdbg_error(strfmt,...)
Definition phpdbg_out.h:43
#define phpdbg_out(fmt,...)
Definition phpdbg_out.h:49
#define phpdbg_notice(strfmt,...)
Definition phpdbg_out.h:44
#define phpdbg_writeln(strfmt,...)
Definition phpdbg_out.h:45
zend_object * ex
PHPDBG_API const zend_function * phpdbg_get_function(const char *fname, const char *cname)
char * phpdbg_short_zval_print(zval *zv, int maxlen)
#define PHPDBG_OUTPUT_BACKUP()
#define PHPDBG_OUTPUT_BACKUP_RESTORE()
p
Definition session.c:1105
zend_string * name
Definition zend.h:149
zend_execute_data * prev_execute_data
zend_execute_data * execute_data
zend_execute_data * frozen_call_stack
uint32_t handle
Definition zend_types.h:558
zend_string * filename
zend_class_entry * scope
uint32_t num_args
zend_string * function_name
#define ZEND_EXTERN_MODULE_GLOBALS(module_name)
Definition zend_API.h:270
#define efree(ptr)
Definition zend_alloc.h:155
ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int options, int limit)
struct _zval_struct zval
strlen(string $string)
uint32_t num_args
execute_data func
zval * args
#define ZEND_INTERNAL_FUNCTION
#define ZEND_USER_FUNCTION
struct _zend_op_array zend_op_array
struct _zend_internal_arg_info zend_internal_arg_info
#define ZEND_CALL_NUM_ARGS(call)
#define ZEND_ARG_IS_VARIADIC(arg_info)
struct _zend_arg_info zend_arg_info
#define ZEND_CALL_VAR_NUM(call, n)
#define ZEND_CALL_ARG(call, n)
ZEND_API uint32_t zend_get_executed_lineno(void)
ZEND_API const char * zend_get_executed_filename(void)
union _zend_function zend_function
ZEND_API void zend_generator_restore_call_stack(zend_generator *generator)
ZEND_API zend_execute_data * zend_generator_freeze_call_stack(zend_execute_data *execute_data)
struct _zend_generator zend_generator
#define EG(v)
ZEND_API zend_result ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2773
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2733
ZEND_API zval *ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2915
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
Definition zend_hash.c:2668
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define ZEND_HASH_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1102
#define ZEND_LONG_FMT
Definition zend_long.h:87
struct _zend_string zend_string
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_KNOWN(idx)
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define Z_STR(zval)
Definition zend_types.h:971
#define Z_OBJCE_P(zval_p)
#define ZVAL_NEW_STR(z, s)
uint32_t HashPosition
Definition zend_types.h:548
#define Z_ARRVAL(zval)
Definition zend_types.h:986
struct _zend_execute_data zend_execute_data
Definition zend_types.h:91
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define Z_LVAL(zval)
Definition zend_types.h:965
zend_generator * generator
zend_string * name
execute_data