1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine, Bytecode Visualisation |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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 | https://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: Dmitry Stogov <dmitry@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #include "zend_compile.h"
20 #include "zend_cfg.h"
21 #include "zend_ssa.h"
22 #include "zend_inference.h"
23 #include "zend_func_info.h"
24 #include "zend_call_graph.h"
25 #include "zend_dump.h"
26 #include "ext/standard/php_string.h"
27
zend_dump_ht(HashTable * ht)28 void zend_dump_ht(HashTable *ht)
29 {
30 zend_ulong index;
31 zend_string *key;
32 zval *val;
33 bool first = 1;
34
35 ZEND_HASH_FOREACH_KEY_VAL(ht, index, key, val) {
36 if (first) {
37 first = 0;
38 } else {
39 fprintf(stderr, ", ");
40 }
41 if (key) {
42 fprintf(stderr, "\"%s\"", ZSTR_VAL(key));
43 } else {
44 fprintf(stderr, ZEND_LONG_FMT, index);
45 }
46 fprintf(stderr, " =>");
47 zend_dump_const(val);
48 } ZEND_HASH_FOREACH_END();
49 }
50
zend_dump_const(const zval * zv)51 void zend_dump_const(const zval *zv)
52 {
53 switch (Z_TYPE_P(zv)) {
54 case IS_NULL:
55 fprintf(stderr, " null");
56 break;
57 case IS_FALSE:
58 fprintf(stderr, " bool(false)");
59 break;
60 case IS_TRUE:
61 fprintf(stderr, " bool(true)");
62 break;
63 case IS_LONG:
64 fprintf(stderr, " int(" ZEND_LONG_FMT ")", Z_LVAL_P(zv));
65 break;
66 case IS_DOUBLE:
67 fprintf(stderr, " float(%g)", Z_DVAL_P(zv));
68 break;
69 case IS_STRING:;
70 zend_string *escaped_string = php_addcslashes(Z_STR_P(zv), "\"\\", 2);
71
72 fprintf(stderr, " string(\"%s\")", ZSTR_VAL(escaped_string));
73
74 zend_string_release(escaped_string);
75 break;
76 case IS_ARRAY:
77 fprintf(stderr, " array(...)");
78 break;
79 default:
80 fprintf(stderr, " zval(type=%d)", Z_TYPE_P(zv));
81 break;
82 }
83 }
84
zend_dump_class_fetch_type(uint32_t fetch_type)85 static void zend_dump_class_fetch_type(uint32_t fetch_type)
86 {
87 switch (fetch_type & ZEND_FETCH_CLASS_MASK) {
88 case ZEND_FETCH_CLASS_SELF:
89 fprintf(stderr, " (self)");
90 break;
91 case ZEND_FETCH_CLASS_PARENT:
92 fprintf(stderr, " (parent)");
93 break;
94 case ZEND_FETCH_CLASS_STATIC:
95 fprintf(stderr, " (static)");
96 break;
97 case ZEND_FETCH_CLASS_AUTO:
98 fprintf(stderr, " (auto)");
99 break;
100 case ZEND_FETCH_CLASS_INTERFACE:
101 fprintf(stderr, " (interface)");
102 break;
103 case ZEND_FETCH_CLASS_TRAIT:
104 fprintf(stderr, " (trait)");
105 break;
106 }
107 if (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) {
108 fprintf(stderr, " (no-autoload)");
109 }
110 if (fetch_type & ZEND_FETCH_CLASS_SILENT) {
111 fprintf(stderr, " (silent)");
112 }
113 if (fetch_type & ZEND_FETCH_CLASS_EXCEPTION) {
114 fprintf(stderr, " (exception)");
115 }
116 }
117
zend_dump_unused_op(const zend_op * opline,znode_op op,uint32_t flags)118 static void zend_dump_unused_op(const zend_op *opline, znode_op op, uint32_t flags) {
119 if (ZEND_VM_OP_NUM == (flags & ZEND_VM_OP_MASK)) {
120 fprintf(stderr, " %u", op.num);
121 } else if (ZEND_VM_OP_TRY_CATCH == (flags & ZEND_VM_OP_MASK)) {
122 if (op.num != (uint32_t)-1) {
123 fprintf(stderr, " try-catch(%u)", op.num);
124 }
125 } else if (ZEND_VM_OP_THIS == (flags & ZEND_VM_OP_MASK)) {
126 fprintf(stderr, " THIS");
127 } else if (ZEND_VM_OP_NEXT == (flags & ZEND_VM_OP_MASK)) {
128 fprintf(stderr, " NEXT");
129 } else if (ZEND_VM_OP_CLASS_FETCH == (flags & ZEND_VM_OP_MASK)) {
130 zend_dump_class_fetch_type(op.num);
131 } else if (ZEND_VM_OP_CONSTRUCTOR == (flags & ZEND_VM_OP_MASK)) {
132 fprintf(stderr, " CONSTRUCTOR");
133 } else if (ZEND_VM_OP_CONST_FETCH == (flags & ZEND_VM_OP_MASK)) {
134 if (op.num & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
135 fprintf(stderr, " (unqualified-in-namespace)");
136 }
137 }
138 }
139
zend_dump_var(const zend_op_array * op_array,uint8_t var_type,int var_num)140 ZEND_API void zend_dump_var(const zend_op_array *op_array, uint8_t var_type, int var_num)
141 {
142 if (var_type == IS_CV && var_num < op_array->last_var) {
143 fprintf(stderr, "CV%d($%s)", var_num, op_array->vars[var_num]->val);
144 } else if (var_type == IS_VAR) {
145 fprintf(stderr, "V%d", var_num);
146 } else if ((var_type & (IS_VAR|IS_TMP_VAR)) == IS_TMP_VAR) {
147 fprintf(stderr, "T%d", var_num);
148 } else {
149 fprintf(stderr, "X%d", var_num);
150 }
151 }
152
zend_dump_range(const zend_ssa_range * r)153 static void zend_dump_range(const zend_ssa_range *r)
154 {
155 if (r->underflow && r->overflow) {
156 return;
157 }
158 fprintf(stderr, " RANGE[");
159 if (r->underflow) {
160 fprintf(stderr, "--..");
161 } else if (r->min == ZEND_LONG_MIN) {
162 fprintf(stderr, "MIN..");
163 } else {
164 fprintf(stderr, ZEND_LONG_FMT "..", r->min);
165 }
166 if (r->overflow) {
167 fprintf(stderr, "++]");
168 } else if (r->max == ZEND_LONG_MAX) {
169 fprintf(stderr, "MAX]");
170 } else {
171 fprintf(stderr, ZEND_LONG_FMT "]", r->max);
172 }
173 }
174
zend_dump_type_info(uint32_t info,zend_class_entry * ce,int is_instanceof,uint32_t dump_flags)175 static void zend_dump_type_info(uint32_t info, zend_class_entry *ce, int is_instanceof, uint32_t dump_flags)
176 {
177 bool first = 1;
178
179 fprintf(stderr, " [");
180 if (info & MAY_BE_GUARD) {
181 fprintf(stderr, "!");
182 }
183 if (info & MAY_BE_UNDEF) {
184 if (first) first = 0; else fprintf(stderr, ", ");
185 fprintf(stderr, "undef");
186 }
187 if (info & MAY_BE_INDIRECT) {
188 if (first) first = 0; else fprintf(stderr, ", ");
189 fprintf(stderr, "ind");
190 }
191 if (info & MAY_BE_REF) {
192 if (first) first = 0; else fprintf(stderr, ", ");
193 fprintf(stderr, "ref");
194 }
195 if (dump_flags & ZEND_DUMP_RC_INFERENCE) {
196 if (info & MAY_BE_RC1) {
197 if (first) first = 0; else fprintf(stderr, ", ");
198 fprintf(stderr, "rc1");
199 }
200 if (info & MAY_BE_RCN) {
201 if (first) first = 0; else fprintf(stderr, ", ");
202 fprintf(stderr, "rcn");
203 }
204 }
205 if (info & MAY_BE_CLASS) {
206 if (first) first = 0; else fprintf(stderr, ", ");
207 fprintf(stderr, "class");
208 if (ce) {
209 if (is_instanceof) {
210 fprintf(stderr, " (instanceof %s)", ce->name->val);
211 } else {
212 fprintf(stderr, " (%s)", ce->name->val);
213 }
214 }
215 } else if ((info & MAY_BE_ANY) == MAY_BE_ANY) {
216 if (first) first = 0; else fprintf(stderr, ", ");
217 fprintf(stderr, "any");
218 } else {
219 if (info & MAY_BE_NULL) {
220 if (first) first = 0; else fprintf(stderr, ", ");
221 fprintf(stderr, "null");
222 }
223 if ((info & MAY_BE_FALSE) && (info & MAY_BE_TRUE)) {
224 if (first) first = 0; else fprintf(stderr, ", ");
225 fprintf(stderr, "bool");
226 } else if (info & MAY_BE_FALSE) {
227 if (first) first = 0; else fprintf(stderr, ", ");
228 fprintf(stderr, "false");
229 } else if (info & MAY_BE_TRUE) {
230 if (first) first = 0; else fprintf(stderr, ", ");
231 fprintf(stderr, "true");
232 }
233 if (info & MAY_BE_LONG) {
234 if (first) first = 0; else fprintf(stderr, ", ");
235 fprintf(stderr, "long");
236 }
237 if (info & MAY_BE_DOUBLE) {
238 if (first) first = 0; else fprintf(stderr, ", ");
239 fprintf(stderr, "double");
240 }
241 if (info & MAY_BE_STRING) {
242 if (first) first = 0; else fprintf(stderr, ", ");
243 fprintf(stderr, "string");
244 }
245 if (info & MAY_BE_ARRAY) {
246 if (first) first = 0; else fprintf(stderr, ", ");
247 if (info & MAY_BE_PACKED_GUARD) {
248 fprintf(stderr, "!");
249 }
250 if (MAY_BE_EMPTY_ONLY(info)) {
251 fprintf(stderr, "empty ");
252 } else if (MAY_BE_PACKED_ONLY(info)) {
253 fprintf(stderr, "packed ");
254 } else if (MAY_BE_HASH_ONLY(info)) {
255 fprintf(stderr, "hash ");
256 } else if ((info & MAY_BE_ARRAY_KEY_ANY) != MAY_BE_ARRAY_KEY_ANY && (info & MAY_BE_ARRAY_KEY_ANY) != 0) {
257 bool afirst = 1;
258 fprintf(stderr, "[");
259 if (info & MAY_BE_ARRAY_EMPTY) {
260 if (afirst) afirst = 0; else fprintf(stderr, ", ");
261 fprintf(stderr, "empty");
262 }
263 if (MAY_BE_PACKED(info)) {
264 if (afirst) afirst = 0; else fprintf(stderr, ", ");
265 fprintf(stderr, "packed");
266 }
267 if (MAY_BE_HASH(info)) {
268 if (afirst) afirst = 0; else fprintf(stderr, ", ");
269 fprintf(stderr, "hash");
270 }
271 fprintf(stderr, "] ");
272 }
273 fprintf(stderr, "array");
274 if ((info & (MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING)) != 0 &&
275 ((info & MAY_BE_ARRAY_KEY_LONG) == 0 ||
276 (info & MAY_BE_ARRAY_KEY_STRING) == 0)) {
277 bool afirst = 1;
278 fprintf(stderr, " [");
279 if (info & MAY_BE_ARRAY_KEY_LONG) {
280 if (afirst) afirst = 0; else fprintf(stderr, ", ");
281 fprintf(stderr, "long");
282 }
283 if (info & MAY_BE_ARRAY_KEY_STRING) {
284 if (afirst) afirst = 0; else fprintf(stderr, ", ");
285 fprintf(stderr, "string");
286 }
287 fprintf(stderr, "]");
288 }
289 if (info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF)) {
290 bool afirst = 1;
291 fprintf(stderr, " of [");
292 if ((info & MAY_BE_ARRAY_OF_ANY) == MAY_BE_ARRAY_OF_ANY) {
293 if (afirst) afirst = 0; else fprintf(stderr, ", ");
294 fprintf(stderr, "any");
295 } else {
296 if (info & MAY_BE_ARRAY_OF_NULL) {
297 if (afirst) afirst = 0; else fprintf(stderr, ", ");
298 fprintf(stderr, "null");
299 }
300 if (info & MAY_BE_ARRAY_OF_FALSE) {
301 if (afirst) afirst = 0; else fprintf(stderr, ", ");
302 fprintf(stderr, "false");
303 }
304 if (info & MAY_BE_ARRAY_OF_TRUE) {
305 if (afirst) afirst = 0; else fprintf(stderr, ", ");
306 fprintf(stderr, "true");
307 }
308 if (info & MAY_BE_ARRAY_OF_LONG) {
309 if (afirst) afirst = 0; else fprintf(stderr, ", ");
310 fprintf(stderr, "long");
311 }
312 if (info & MAY_BE_ARRAY_OF_DOUBLE) {
313 if (afirst) afirst = 0; else fprintf(stderr, ", ");
314 fprintf(stderr, "double");
315 }
316 if (info & MAY_BE_ARRAY_OF_STRING) {
317 if (afirst) afirst = 0; else fprintf(stderr, ", ");
318 fprintf(stderr, "string");
319 }
320 if (info & MAY_BE_ARRAY_OF_ARRAY) {
321 if (afirst) afirst = 0; else fprintf(stderr, ", ");
322 fprintf(stderr, "array");
323 }
324 if (info & MAY_BE_ARRAY_OF_OBJECT) {
325 if (afirst) afirst = 0; else fprintf(stderr, ", ");
326 fprintf(stderr, "object");
327 }
328 if (info & MAY_BE_ARRAY_OF_RESOURCE) {
329 if (afirst) afirst = 0; else fprintf(stderr, ", ");
330 fprintf(stderr, "resource");
331 }
332 }
333 if (info & MAY_BE_ARRAY_OF_REF) {
334 if (afirst) afirst = 0; else fprintf(stderr, ", ");
335 fprintf(stderr, "ref");
336 }
337 fprintf(stderr, "]");
338 }
339 }
340 if (info & MAY_BE_OBJECT) {
341 if (first) first = 0; else fprintf(stderr, ", ");
342 fprintf(stderr, "object");
343 if (ce) {
344 if (is_instanceof) {
345 fprintf(stderr, " (instanceof %s)", ce->name->val);
346 } else {
347 fprintf(stderr, " (%s)", ce->name->val);
348 }
349 }
350 }
351 if (info & MAY_BE_RESOURCE) {
352 if (first) first = 0; else fprintf(stderr, ", ");
353 fprintf(stderr, "resource");
354 }
355 }
356 fprintf(stderr, "]");
357 }
358
zend_dump_ssa_var_info(const zend_ssa * ssa,int ssa_var_num,uint32_t dump_flags)359 static void zend_dump_ssa_var_info(const zend_ssa *ssa, int ssa_var_num, uint32_t dump_flags)
360 {
361 zend_dump_type_info(
362 ssa->var_info[ssa_var_num].type,
363 ssa->var_info[ssa_var_num].ce,
364 ssa->var_info[ssa_var_num].ce ?
365 ssa->var_info[ssa_var_num].is_instanceof : 0,
366 dump_flags);
367 }
368
zend_dump_ssa_var(const zend_op_array * op_array,const zend_ssa * ssa,int ssa_var_num,uint8_t var_type,int var_num,uint32_t dump_flags)369 ZEND_API void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa, int ssa_var_num, uint8_t var_type, int var_num, uint32_t dump_flags)
370 {
371 if (ssa_var_num >= 0) {
372 fprintf(stderr, "#%d.", ssa_var_num);
373 } else {
374 fprintf(stderr, "#?.");
375 }
376 zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : var_type), var_num);
377
378 if (ssa_var_num >= 0 && ssa->vars) {
379 if (ssa->vars[ssa_var_num].no_val) {
380 fprintf(stderr, " NOVAL");
381 }
382 if (ssa->vars[ssa_var_num].escape_state == ESCAPE_STATE_NO_ESCAPE) {
383 fprintf(stderr, " NOESC");
384 }
385 if (ssa->var_info) {
386 zend_dump_ssa_var_info(ssa, ssa_var_num, dump_flags);
387 if (ssa->var_info[ssa_var_num].has_range) {
388 zend_dump_range(&ssa->var_info[ssa_var_num].range);
389 }
390 }
391 }
392 }
393
zend_dump_type_constraint(const zend_op_array * op_array,const zend_ssa * ssa,const zend_ssa_type_constraint * constraint,uint32_t dump_flags)394 static void zend_dump_type_constraint(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_type_constraint *constraint, uint32_t dump_flags)
395 {
396 fprintf(stderr, " TYPE");
397 zend_dump_type_info(constraint->type_mask, constraint->ce, 1, dump_flags);
398 }
399
zend_dump_range_constraint(const zend_op_array * op_array,const zend_ssa * ssa,const zend_ssa_range_constraint * r,uint32_t dump_flags)400 static void zend_dump_range_constraint(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_range_constraint *r, uint32_t dump_flags)
401 {
402 if (r->range.underflow && r->range.overflow) {
403 return;
404 }
405 fprintf(stderr, " RANGE");
406 if (r->negative) {
407 fprintf(stderr, "~");
408 }
409 fprintf(stderr, "[");
410 if (r->range.underflow) {
411 fprintf(stderr, "-- .. ");
412 } else {
413 if (r->min_ssa_var >= 0) {
414 zend_dump_ssa_var(op_array, ssa, r->min_ssa_var, (r->min_var < op_array->last_var ? IS_CV : 0), r->min_var, dump_flags);
415 if (r->range.min > 0) {
416 fprintf(stderr, " + " ZEND_LONG_FMT, r->range.min);
417 } else if (r->range.min < 0) {
418 fprintf(stderr, " - " ZEND_LONG_FMT, -r->range.min);
419 }
420 fprintf(stderr, " .. ");
421 } else {
422 fprintf(stderr, ZEND_LONG_FMT " .. ", r->range.min);
423 }
424 }
425 if (r->range.overflow) {
426 fprintf(stderr, "++]");
427 } else {
428 if (r->max_ssa_var >= 0) {
429 zend_dump_ssa_var(op_array, ssa, r->max_ssa_var, (r->max_var < op_array->last_var ? IS_CV : 0), r->max_var, dump_flags);
430 if (r->range.max > 0) {
431 fprintf(stderr, " + " ZEND_LONG_FMT, r->range.max);
432 } else if (r->range.max < 0) {
433 fprintf(stderr, " - " ZEND_LONG_FMT, -r->range.max);
434 }
435 fprintf(stderr, "]");
436 } else {
437 fprintf(stderr, ZEND_LONG_FMT "]", r->range.max);
438 }
439 }
440 }
441
zend_dump_op(const zend_op_array * op_array,const zend_basic_block * b,const zend_op * opline,uint32_t dump_flags,const zend_ssa * ssa,const zend_ssa_op * ssa_op)442 ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const zend_ssa *ssa, const zend_ssa_op *ssa_op)
443 {
444 const char *name = zend_get_opcode_name(opline->opcode);
445 uint32_t flags = zend_get_opcode_flags(opline->opcode);
446 uint32_t n = 0;
447
448 if (!ssa_op || ssa_op->result_use < 0) {
449 if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
450 if (ssa_op && ssa_op->result_def >= 0) {
451 int ssa_var_num = ssa_op->result_def;
452 zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->result_type, EX_VAR_TO_NUM(opline->result.var), dump_flags);
453 } else {
454 zend_dump_var(op_array, opline->result_type, EX_VAR_TO_NUM(opline->result.var));
455 }
456 fprintf(stderr, " = ");
457 }
458 }
459
460 if (name) {
461 fprintf(stderr, "%s", (name + 5));
462 } else {
463 fprintf(stderr, "OP_%d", (int)opline->opcode);
464 }
465
466 if (ZEND_VM_EXT_NUM == (flags & ZEND_VM_EXT_MASK)) {
467 fprintf(stderr, " %u", opline->extended_value);
468 } else if (ZEND_VM_EXT_OP == (flags & ZEND_VM_EXT_MASK)) {
469 fprintf(stderr, " (%s)", zend_get_opcode_name(opline->extended_value) + 5);
470 } else if (ZEND_VM_EXT_TYPE == (flags & ZEND_VM_EXT_MASK)) {
471 switch (opline->extended_value) {
472 case IS_NULL:
473 fprintf(stderr, " (null)");
474 break;
475 case IS_FALSE:
476 fprintf(stderr, " (false)");
477 break;
478 case IS_TRUE:
479 fprintf(stderr, " (true)");
480 break;
481 case IS_LONG:
482 fprintf(stderr, " (long)");
483 break;
484 case IS_DOUBLE:
485 fprintf(stderr, " (double)");
486 break;
487 case IS_STRING:
488 fprintf(stderr, " (string)");
489 break;
490 case IS_ARRAY:
491 fprintf(stderr, " (array)");
492 break;
493 case IS_OBJECT:
494 fprintf(stderr, " (object)");
495 break;
496 case IS_RESOURCE:
497 fprintf(stderr, " (resource)");
498 break;
499 case _IS_BOOL:
500 fprintf(stderr, " (bool)");
501 break;
502 case IS_CALLABLE:
503 fprintf(stderr, " (callable)");
504 break;
505 case IS_VOID:
506 fprintf(stderr, " (void)");
507 break;
508 case IS_NEVER:
509 fprintf(stderr, " (never)");
510 break;
511 default:
512 fprintf(stderr, " (\?\?\?)");
513 break;
514 }
515 } else if (ZEND_VM_EXT_TYPE_MASK == (flags & ZEND_VM_EXT_MASK)) {
516 switch (opline->extended_value) {
517 case (1<<IS_NULL):
518 fprintf(stderr, " (null)");
519 break;
520 case (1<<IS_FALSE):
521 fprintf(stderr, " (false)");
522 break;
523 case (1<<IS_TRUE):
524 fprintf(stderr, " (true)");
525 break;
526 case (1<<IS_LONG):
527 fprintf(stderr, " (long)");
528 break;
529 case (1<<IS_DOUBLE):
530 fprintf(stderr, " (double)");
531 break;
532 case (1<<IS_STRING):
533 fprintf(stderr, " (string)");
534 break;
535 case (1<<IS_ARRAY):
536 fprintf(stderr, " (array)");
537 break;
538 case (1<<IS_OBJECT):
539 fprintf(stderr, " (object)");
540 break;
541 case (1<<IS_RESOURCE):
542 fprintf(stderr, " (resource)");
543 break;
544 case ((1<<IS_FALSE)|(1<<IS_TRUE)):
545 fprintf(stderr, " (bool)");
546 break;
547 default:
548 fprintf(stderr, " TYPE");
549 zend_dump_type_info(opline->extended_value, NULL, 0, dump_flags);
550 break;
551 }
552 } else if (ZEND_VM_EXT_EVAL == (flags & ZEND_VM_EXT_MASK)) {
553 switch (opline->extended_value) {
554 case ZEND_EVAL:
555 fprintf(stderr, " (eval)");
556 break;
557 case ZEND_INCLUDE:
558 fprintf(stderr, " (include)");
559 break;
560 case ZEND_INCLUDE_ONCE:
561 fprintf(stderr, " (include_once)");
562 break;
563 case ZEND_REQUIRE:
564 fprintf(stderr, " (require)");
565 break;
566 case ZEND_REQUIRE_ONCE:
567 fprintf(stderr, " (require_once)");
568 break;
569 default:
570 fprintf(stderr, " (\?\?\?)");
571 break;
572 }
573 } else if (ZEND_VM_EXT_SRC == (flags & ZEND_VM_EXT_MASK)) {
574 if (opline->extended_value == ZEND_RETURNS_VALUE) {
575 fprintf(stderr, " (value)");
576 } else if (opline->extended_value & ZEND_RETURNS_FUNCTION) {
577 fprintf(stderr, " (function)");
578 }
579 } else {
580 if (ZEND_VM_EXT_VAR_FETCH & flags) {
581 if (opline->extended_value & ZEND_FETCH_GLOBAL) {
582 fprintf(stderr, " (global)");
583 } else if (opline->extended_value & ZEND_FETCH_LOCAL) {
584 fprintf(stderr, " (local)");
585 } else if (opline->extended_value & ZEND_FETCH_GLOBAL_LOCK) {
586 fprintf(stderr, " (global+lock)");
587 }
588 }
589 if (ZEND_VM_EXT_ISSET & flags) {
590 if (!(opline->extended_value & ZEND_ISEMPTY)) {
591 fprintf(stderr, " (isset)");
592 } else {
593 fprintf(stderr, " (empty)");
594 }
595 }
596 if (ZEND_VM_EXT_ARRAY_INIT & flags) {
597 fprintf(stderr, " %u", opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT);
598 if (!(opline->extended_value & ZEND_ARRAY_NOT_PACKED)) {
599 fprintf(stderr, " (packed)");
600 }
601 }
602 if (ZEND_VM_EXT_REF & flags) {
603 if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) {
604 fprintf(stderr, " (ref)");
605 }
606 }
607 if ((ZEND_VM_EXT_DIM_WRITE|ZEND_VM_EXT_FETCH_REF) & flags) {
608 uint32_t obj_flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
609 if (obj_flags == ZEND_FETCH_REF) {
610 fprintf(stderr, " (ref)");
611 } else if (obj_flags == ZEND_FETCH_DIM_WRITE) {
612 fprintf(stderr, " (dim write)");
613 }
614 }
615 }
616
617 if (opline->op1_type == IS_CONST) {
618 zend_dump_const(CRT_CONSTANT(opline->op1));
619 } else if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
620 if (ssa_op) {
621 int ssa_var_num = ssa_op->op1_use;
622 if (ssa_var_num >= 0) {
623 fprintf(stderr, " ");
624 zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->op1_type, EX_VAR_TO_NUM(opline->op1.var), dump_flags);
625 } else if (ssa_op->op1_def < 0) {
626 fprintf(stderr, " ");
627 zend_dump_var(op_array, opline->op1_type, EX_VAR_TO_NUM(opline->op1.var));
628 }
629 } else {
630 fprintf(stderr, " ");
631 zend_dump_var(op_array, opline->op1_type, EX_VAR_TO_NUM(opline->op1.var));
632 }
633 if (ssa_op) {
634 int ssa_var_num = ssa_op->op1_def;
635 if (ssa_var_num >= 0) {
636 fprintf(stderr, " -> ");
637 zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->op1_type, EX_VAR_TO_NUM(opline->op1.var), dump_flags);
638 }
639 }
640 } else {
641 uint32_t op1_flags = ZEND_VM_OP1_FLAGS(flags);
642 if (ZEND_VM_OP_JMP_ADDR == (op1_flags & ZEND_VM_OP_MASK)) {
643 if (b) {
644 fprintf(stderr, " BB%d", b->successors[n++]);
645 } else {
646 fprintf(stderr, " %04u", (uint32_t)(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes));
647 }
648 } else {
649 zend_dump_unused_op(opline, opline->op1, op1_flags);
650 }
651 }
652
653 if (opline->op2_type == IS_CONST) {
654 zval *op = CRT_CONSTANT(opline->op2);
655 if (
656 opline->opcode == ZEND_SWITCH_LONG
657 || opline->opcode == ZEND_SWITCH_STRING
658 || opline->opcode == ZEND_MATCH
659 ) {
660 HashTable *jumptable = Z_ARRVAL_P(op);
661 zend_string *key;
662 zend_ulong num_key;
663 zval *zv;
664 ZEND_HASH_FOREACH_KEY_VAL(jumptable, num_key, key, zv) {
665 if (key) {
666 fprintf(stderr, " \"%s\":", ZSTR_VAL(key));
667 } else {
668 fprintf(stderr, " " ZEND_LONG_FMT ":", num_key);
669 }
670 if (b) {
671 fprintf(stderr, " BB%d,", b->successors[n++]);
672 } else {
673 fprintf(stderr, " %04u,", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv)));
674 }
675 } ZEND_HASH_FOREACH_END();
676 fprintf(stderr, " default:");
677 } else {
678 zend_dump_const(op);
679 }
680 } else if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
681 if (ssa_op) {
682 int ssa_var_num = ssa_op->op2_use;
683 if (ssa_var_num >= 0) {
684 fprintf(stderr, " ");
685 zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->op2_type, EX_VAR_TO_NUM(opline->op2.var), dump_flags);
686 } else if (ssa_op->op2_def < 0) {
687 fprintf(stderr, " ");
688 zend_dump_var(op_array, opline->op2_type, EX_VAR_TO_NUM(opline->op2.var));
689 }
690 } else {
691 fprintf(stderr, " ");
692 zend_dump_var(op_array, opline->op2_type, EX_VAR_TO_NUM(opline->op2.var));
693 }
694 if (ssa_op) {
695 int ssa_var_num = ssa_op->op2_def;
696 if (ssa_var_num >= 0) {
697 fprintf(stderr, " -> ");
698 zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->op2_type, EX_VAR_TO_NUM(opline->op2.var), dump_flags);
699 }
700 }
701 } else {
702 uint32_t op2_flags = ZEND_VM_OP2_FLAGS(flags);
703 if (ZEND_VM_OP_JMP_ADDR == (op2_flags & ZEND_VM_OP_MASK)) {
704 if (opline->opcode != ZEND_CATCH || !(opline->extended_value & ZEND_LAST_CATCH)) {
705 if (b) {
706 fprintf(stderr, " BB%d", b->successors[n++]);
707 } else {
708 fprintf(stderr, " %04u", (uint32_t)(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes));
709 }
710 }
711 } else {
712 zend_dump_unused_op(opline, opline->op2, op2_flags);
713 }
714 }
715
716 if (ZEND_VM_EXT_JMP_ADDR == (flags & ZEND_VM_EXT_MASK)) {
717 if (b) {
718 fprintf(stderr, " BB%d", b->successors[n++]);
719 } else {
720 fprintf(stderr, " %04u", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
721 }
722 }
723 if (opline->result_type == IS_CONST) {
724 zend_dump_const(CRT_CONSTANT(opline->result));
725 #if 0
726 } else if (opline->result_type & IS_SMART_BRANCH_JMPZ) {
727 fprintf(stderr, " jmpz");
728 } else if (opline->result_type & IS_SMART_BRANCH_JMPNZ) {
729 fprintf(stderr, " jmpnz");
730 #endif
731 } else if (ssa_op && ssa_op->result_use >= 0) {
732 if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
733 if (ssa_op) {
734 int ssa_var_num = ssa_op->result_use;
735 if (ssa_var_num >= 0) {
736 fprintf(stderr, " ");
737 zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->result_type, EX_VAR_TO_NUM(opline->result.var), dump_flags);
738 }
739 } else {
740 fprintf(stderr, " ");
741 zend_dump_var(op_array, opline->result_type, EX_VAR_TO_NUM(opline->result.var));
742 }
743 if (ssa_op) {
744 int ssa_var_num = ssa_op->result_def;
745 if (ssa_var_num >= 0) {
746 fprintf(stderr, " -> ");
747 zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->result_type, EX_VAR_TO_NUM(opline->result.var), dump_flags);
748 }
749 }
750 }
751 }
752 }
753
zend_dump_op_line(const zend_op_array * op_array,const zend_basic_block * b,const zend_op * opline,uint32_t dump_flags,const void * data)754 ZEND_API void zend_dump_op_line(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data)
755 {
756 int len = 0;
757 const zend_ssa *ssa = NULL;
758 zend_ssa_op *ssa_op = NULL;
759
760 if (dump_flags & ZEND_DUMP_LINE_NUMBERS) {
761 fprintf(stderr, "L%04u ", opline->lineno);
762 }
763
764 len = fprintf(stderr, "%04u", (uint32_t)(opline - op_array->opcodes));
765 fprintf(stderr, "%*c", 5-len, ' ');
766
767 if (dump_flags & ZEND_DUMP_SSA) {
768 ssa = (const zend_ssa*)data;
769 if (ssa && ssa->ops) {
770 ssa_op = &ssa->ops[opline - op_array->opcodes];
771 }
772 }
773
774 zend_dump_op(op_array, b, opline, dump_flags, ssa, ssa_op);
775 fprintf(stderr, "\n");
776 }
777
zend_dump_block_info(const zend_cfg * cfg,int n,uint32_t dump_flags)778 static void zend_dump_block_info(const zend_cfg *cfg, int n, uint32_t dump_flags)
779 {
780 zend_basic_block *b = cfg->blocks + n;
781
782 if (n > 0) {
783 fprintf(stderr, "\n");
784 }
785 fprintf(stderr, "BB%d:\n ;", n);
786 if (b->flags & ZEND_BB_START) {
787 fprintf(stderr, " start");
788 }
789 if (b->flags & ZEND_BB_RECV_ENTRY) {
790 fprintf(stderr, " recv");
791 }
792 if (b->flags & ZEND_BB_FOLLOW) {
793 fprintf(stderr, " follow");
794 }
795 if (b->flags & ZEND_BB_TARGET) {
796 fprintf(stderr, " target");
797 }
798 if (b->flags & ZEND_BB_EXIT) {
799 fprintf(stderr, " exit");
800 }
801 if (b->flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
802 fprintf(stderr, " entry");
803 }
804 if (b->flags & ZEND_BB_TRY) {
805 fprintf(stderr, " try");
806 }
807 if (b->flags & ZEND_BB_CATCH) {
808 fprintf(stderr, " catch");
809 }
810 if (b->flags & ZEND_BB_FINALLY) {
811 fprintf(stderr, " finally");
812 }
813 if (b->flags & ZEND_BB_FINALLY_END) {
814 fprintf(stderr, " finally_end");
815 }
816 if (!(dump_flags & ZEND_DUMP_HIDE_UNREACHABLE) && !(b->flags & ZEND_BB_REACHABLE)) {
817 fprintf(stderr, " unreachable");
818 }
819 if (b->flags & ZEND_BB_UNREACHABLE_FREE) {
820 fprintf(stderr, " unreachable_free");
821 }
822 if (b->flags & ZEND_BB_LOOP_HEADER) {
823 fprintf(stderr, " loop_header");
824 }
825 if (b->flags & ZEND_BB_IRREDUCIBLE_LOOP) {
826 fprintf(stderr, " irreducible");
827 }
828 if (b->len != 0) {
829 fprintf(stderr, " lines=[%d-%d]", b->start, b->start + b->len - 1);
830 } else {
831 fprintf(stderr, " empty");
832 }
833 fprintf(stderr, "\n");
834
835 if (b->predecessors_count) {
836 int *p = cfg->predecessors + b->predecessor_offset;
837 int *end = p + b->predecessors_count;
838
839 fprintf(stderr, " ; from=(BB%d", *p);
840 for (p++; p < end; p++) {
841 fprintf(stderr, ", BB%d", *p);
842 }
843 fprintf(stderr, ")\n");
844 }
845
846 if (b->successors_count > 0) {
847 int s;
848 fprintf(stderr, " ; to=(BB%d", b->successors[0]);
849 for (s = 1; s < b->successors_count; s++) {
850 fprintf(stderr, ", BB%d", b->successors[s]);
851 }
852 fprintf(stderr, ")\n");
853 }
854
855 if (b->idom >= 0) {
856 fprintf(stderr, " ; idom=BB%d\n", b->idom);
857 }
858 if (b->level >= 0) {
859 fprintf(stderr, " ; level=%d\n", b->level);
860 }
861 if (b->loop_header >= 0) {
862 fprintf(stderr, " ; loop_header=%d\n", b->loop_header);
863 }
864 if (b->children >= 0) {
865 int j = b->children;
866 fprintf(stderr, " ; children=(BB%d", j);
867 j = cfg->blocks[j].next_child;
868 while (j >= 0) {
869 fprintf(stderr, ", BB%d", j);
870 j = cfg->blocks[j].next_child;
871 }
872 fprintf(stderr, ")\n");
873 }
874 }
875
zend_dump_block_header(const zend_cfg * cfg,const zend_op_array * op_array,const zend_ssa * ssa,int n,uint32_t dump_flags)876 static void zend_dump_block_header(const zend_cfg *cfg, const zend_op_array *op_array, const zend_ssa *ssa, int n, uint32_t dump_flags)
877 {
878 zend_dump_block_info(cfg, n, dump_flags);
879 if (ssa && ssa->blocks && ssa->blocks[n].phis) {
880 zend_ssa_phi *p = ssa->blocks[n].phis;
881
882 do {
883 int j;
884
885 fprintf(stderr, " ");
886 zend_dump_ssa_var(op_array, ssa, p->ssa_var, 0, p->var, dump_flags);
887 if (p->pi < 0) {
888 fprintf(stderr, " = Phi(");
889 for (j = 0; j < cfg->blocks[n].predecessors_count; j++) {
890 if (j > 0) {
891 fprintf(stderr, ", ");
892 }
893 zend_dump_ssa_var(op_array, ssa, p->sources[j], 0, p->var, dump_flags);
894 }
895 fprintf(stderr, ")\n");
896 } else {
897 fprintf(stderr, " = Pi<BB%d>(", p->pi);
898 zend_dump_ssa_var(op_array, ssa, p->sources[0], 0, p->var, dump_flags);
899 fprintf(stderr, " &");
900 if (p->has_range_constraint) {
901 zend_dump_range_constraint(op_array, ssa, &p->constraint.range, dump_flags);
902 } else {
903 zend_dump_type_constraint(op_array, ssa, &p->constraint.type, dump_flags);
904 }
905 fprintf(stderr, ")\n");
906 }
907 p = p->next;
908 } while (p);
909 }
910 }
911
zend_dump_op_array_name(const zend_op_array * op_array)912 void zend_dump_op_array_name(const zend_op_array *op_array)
913 {
914 if (op_array->function_name) {
915 if (op_array->scope && op_array->scope->name) {
916 fprintf(stderr, "%s::%s", op_array->scope->name->val, op_array->function_name->val);
917 } else {
918 fprintf(stderr, "%s", op_array->function_name->val);
919 }
920 } else {
921 fprintf(stderr, "%s", "$_main");
922 }
923 }
924
zend_dump_op_array(const zend_op_array * op_array,uint32_t dump_flags,const char * msg,const void * data)925 ZEND_API void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, const char *msg, const void *data)
926 {
927 int i;
928 const zend_cfg *cfg = NULL;
929 const zend_ssa *ssa = NULL;
930 zend_func_info *func_info = NULL;
931 uint32_t func_flags = 0;
932
933 if (dump_flags & (ZEND_DUMP_CFG|ZEND_DUMP_SSA)) {
934 cfg = (const zend_cfg*)data;
935 if (!cfg->blocks) {
936 cfg = data = NULL;
937 }
938 }
939 if (dump_flags & ZEND_DUMP_SSA) {
940 ssa = (const zend_ssa*)data;
941 }
942
943 func_info = ZEND_FUNC_INFO(op_array);
944 if (func_info) {
945 func_flags = func_info->flags;
946 }
947
948 fprintf(stderr, "\n");
949 zend_dump_op_array_name(op_array);
950 fprintf(stderr, ":\n ; (lines=%d, args=%d",
951 op_array->last,
952 op_array->num_args);
953 fprintf(stderr, ", vars=%d, tmps=%d", op_array->last_var, op_array->T);
954 if (ssa) {
955 fprintf(stderr, ", ssa_vars=%d", ssa->vars_count);
956 }
957 if (func_flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) {
958 fprintf(stderr, ", dynamic");
959 }
960 if (func_flags & ZEND_FUNC_RECURSIVE) {
961 fprintf(stderr, ", recursive");
962 if (func_flags & ZEND_FUNC_RECURSIVE_DIRECTLY) {
963 fprintf(stderr, " directly");
964 }
965 if (func_flags & ZEND_FUNC_RECURSIVE_INDIRECTLY) {
966 fprintf(stderr, " indirectly");
967 }
968 }
969 if (func_flags & ZEND_FUNC_IRREDUCIBLE) {
970 fprintf(stderr, ", irreducible");
971 }
972 if (func_flags & ZEND_FUNC_NO_LOOPS) {
973 fprintf(stderr, ", no_loops");
974 }
975 if (func_flags & ZEND_FUNC_HAS_EXTENDED_STMT) {
976 fprintf(stderr, ", extended_stmt");
977 }
978 if (func_flags & ZEND_FUNC_HAS_EXTENDED_FCALL) {
979 fprintf(stderr, ", extended_fcall");
980 }
981 //TODO: this is useful only for JIT???
982 #if 0
983 if (info->flags & ZEND_JIT_FUNC_NO_IN_MEM_CVS) {
984 fprintf(stderr, ", no_in_mem_cvs");
985 }
986 if (info->flags & ZEND_JIT_FUNC_NO_USED_ARGS) {
987 fprintf(stderr, ", no_used_args");
988 }
989 if (info->flags & ZEND_JIT_FUNC_NO_SYMTAB) {
990 fprintf(stderr, ", no_symtab");
991 }
992 if (info->flags & ZEND_JIT_FUNC_NO_FRAME) {
993 fprintf(stderr, ", no_frame");
994 }
995 if (info->flags & ZEND_JIT_FUNC_INLINE) {
996 fprintf(stderr, ", inline");
997 }
998 #endif
999 fprintf(stderr, ")\n");
1000 if (msg) {
1001 fprintf(stderr, " ; (%s)\n", msg);
1002 }
1003 fprintf(stderr, " ; %s:%u-%u\n", op_array->filename->val, op_array->line_start, op_array->line_end);
1004
1005 if (func_info) {
1006 fprintf(stderr, " ; return ");
1007 zend_dump_type_info(func_info->return_info.type, func_info->return_info.ce, func_info->return_info.is_instanceof, dump_flags);
1008 zend_dump_range(&func_info->return_info.range);
1009 fprintf(stderr, "\n");
1010 }
1011
1012 if (ssa && ssa->var_info) {
1013 for (i = 0; i < op_array->last_var; i++) {
1014 fprintf(stderr, " ; ");
1015 zend_dump_ssa_var(op_array, ssa, i, IS_CV, i, dump_flags);
1016 fprintf(stderr, "\n");
1017 }
1018 }
1019
1020 if (cfg) {
1021 int n;
1022 zend_basic_block *b;
1023
1024 for (n = 0; n < cfg->blocks_count; n++) {
1025 b = cfg->blocks + n;
1026 if (!(dump_flags & ZEND_DUMP_HIDE_UNREACHABLE) || (b->flags & ZEND_BB_REACHABLE)) {
1027 const zend_op *opline;
1028 const zend_op *end;
1029
1030 zend_dump_block_header(cfg, op_array, ssa, n, dump_flags);
1031 opline = op_array->opcodes + b->start;
1032 end = opline + b->len;
1033 while (opline < end) {
1034 zend_dump_op_line(op_array, b, opline, dump_flags, data);
1035 opline++;
1036 }
1037 }
1038 }
1039 if (op_array->last_live_range && (dump_flags & ZEND_DUMP_LIVE_RANGES)) {
1040 fprintf(stderr, "LIVE RANGES:\n");
1041 for (i = 0; i < op_array->last_live_range; i++) {
1042 fprintf(stderr,
1043 " %u: %04u - %04u ",
1044 EX_VAR_TO_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK),
1045 op_array->live_range[i].start,
1046 op_array->live_range[i].end);
1047 switch (op_array->live_range[i].var & ZEND_LIVE_MASK) {
1048 case ZEND_LIVE_TMPVAR:
1049 fprintf(stderr, "(tmp/var)\n");
1050 break;
1051 case ZEND_LIVE_LOOP:
1052 fprintf(stderr, "(loop)\n");
1053 break;
1054 case ZEND_LIVE_SILENCE:
1055 fprintf(stderr, "(silence)\n");
1056 break;
1057 case ZEND_LIVE_ROPE:
1058 fprintf(stderr, "(rope)\n");
1059 break;
1060 case ZEND_LIVE_NEW:
1061 fprintf(stderr, "(new)\n");
1062 break;
1063 }
1064 }
1065 }
1066 if (op_array->last_try_catch) {
1067 fprintf(stderr, "EXCEPTION TABLE:\n");
1068 for (i = 0; i < op_array->last_try_catch; i++) {
1069 fprintf(stderr, " BB%u",
1070 cfg->map[op_array->try_catch_array[i].try_op]);
1071 if (op_array->try_catch_array[i].catch_op) {
1072 fprintf(stderr, ", BB%u",
1073 cfg->map[op_array->try_catch_array[i].catch_op]);
1074 } else {
1075 fprintf(stderr, ", -");
1076 }
1077 if (op_array->try_catch_array[i].finally_op) {
1078 fprintf(stderr, ", BB%u",
1079 cfg->map[op_array->try_catch_array[i].finally_op]);
1080 } else {
1081 fprintf(stderr, ", -");
1082 }
1083 if (op_array->try_catch_array[i].finally_end) {
1084 fprintf(stderr, ", BB%u\n",
1085 cfg->map[op_array->try_catch_array[i].finally_end]);
1086 } else {
1087 fprintf(stderr, ", -\n");
1088 }
1089 }
1090 }
1091 } else {
1092 const zend_op *opline = op_array->opcodes;
1093 const zend_op *end = opline + op_array->last;
1094
1095 while (opline < end) {
1096 zend_dump_op_line(op_array, NULL, opline, dump_flags, data);
1097 opline++;
1098 }
1099 if (op_array->last_live_range && (dump_flags & ZEND_DUMP_LIVE_RANGES)) {
1100 fprintf(stderr, "LIVE RANGES:\n");
1101 for (i = 0; i < op_array->last_live_range; i++) {
1102 fprintf(stderr,
1103 " %u: %04u - %04u ",
1104 EX_VAR_TO_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK),
1105 op_array->live_range[i].start,
1106 op_array->live_range[i].end);
1107 switch (op_array->live_range[i].var & ZEND_LIVE_MASK) {
1108 case ZEND_LIVE_TMPVAR:
1109 fprintf(stderr, "(tmp/var)\n");
1110 break;
1111 case ZEND_LIVE_LOOP:
1112 fprintf(stderr, "(loop)\n");
1113 break;
1114 case ZEND_LIVE_SILENCE:
1115 fprintf(stderr, "(silence)\n");
1116 break;
1117 case ZEND_LIVE_ROPE:
1118 fprintf(stderr, "(rope)\n");
1119 break;
1120 case ZEND_LIVE_NEW:
1121 fprintf(stderr, "(new)\n");
1122 break;
1123 }
1124 }
1125 }
1126 if (op_array->last_try_catch) {
1127 fprintf(stderr, "EXCEPTION TABLE:\n");
1128 for (i = 0; i < op_array->last_try_catch; i++) {
1129 fprintf(stderr,
1130 " %04u",
1131 op_array->try_catch_array[i].try_op);
1132
1133 if (op_array->try_catch_array[i].catch_op) {
1134 fprintf(stderr,
1135 ", %04u",
1136 op_array->try_catch_array[i].catch_op);
1137 } else {
1138 fprintf(stderr, ", -");
1139 }
1140 if (op_array->try_catch_array[i].finally_op) {
1141 fprintf(stderr,
1142 ", %04u",
1143 op_array->try_catch_array[i].finally_op);
1144 } else {
1145 fprintf(stderr, ", -");
1146 }
1147 if (op_array->try_catch_array[i].finally_end) {
1148 fprintf(stderr,
1149 ", %04u",
1150 op_array->try_catch_array[i].finally_end);
1151 } else {
1152 fprintf(stderr, ", -\n");
1153 }
1154 }
1155 }
1156 }
1157 }
1158
zend_dump_dominators(const zend_op_array * op_array,const zend_cfg * cfg)1159 void zend_dump_dominators(const zend_op_array *op_array, const zend_cfg *cfg)
1160 {
1161 int j;
1162
1163 fprintf(stderr, "\nDOMINATORS-TREE for \"");
1164 zend_dump_op_array_name(op_array);
1165 fprintf(stderr, "\"\n");
1166 for (j = 0; j < cfg->blocks_count; j++) {
1167 zend_basic_block *b = cfg->blocks + j;
1168 if (b->flags & ZEND_BB_REACHABLE) {
1169 zend_dump_block_info(cfg, j, 0);
1170 }
1171 }
1172 }
1173
zend_dump_variables(const zend_op_array * op_array)1174 void zend_dump_variables(const zend_op_array *op_array)
1175 {
1176 int j;
1177
1178 fprintf(stderr, "\nCV Variables for \"");
1179 zend_dump_op_array_name(op_array);
1180 fprintf(stderr, "\"\n");
1181 for (j = 0; j < op_array->last_var; j++) {
1182 fprintf(stderr, " ");
1183 zend_dump_var(op_array, IS_CV, j);
1184 fprintf(stderr, "\n");
1185 }
1186 }
1187
zend_dump_ssa_variables(const zend_op_array * op_array,const zend_ssa * ssa,uint32_t dump_flags)1188 void zend_dump_ssa_variables(const zend_op_array *op_array, const zend_ssa *ssa, uint32_t dump_flags)
1189 {
1190 int j;
1191
1192 if (ssa->vars) {
1193 fprintf(stderr, "\nSSA Variable for \"");
1194 zend_dump_op_array_name(op_array);
1195 fprintf(stderr, "\"\n");
1196
1197 for (j = 0; j < ssa->vars_count; j++) {
1198 fprintf(stderr, " ");
1199 zend_dump_ssa_var(op_array, ssa, j, IS_CV, ssa->vars[j].var, dump_flags);
1200 if (ssa->vars[j].scc >= 0) {
1201 if (ssa->vars[j].scc_entry) {
1202 fprintf(stderr, " *");
1203 } else {
1204 fprintf(stderr, " ");
1205 }
1206 fprintf(stderr, "SCC=%d", ssa->vars[j].scc);
1207 }
1208 fprintf(stderr, "\n");
1209 }
1210 }
1211 }
1212
zend_dump_var_set(const zend_op_array * op_array,const char * name,zend_bitset set)1213 static void zend_dump_var_set(const zend_op_array *op_array, const char *name, zend_bitset set)
1214 {
1215 bool first = 1;
1216 uint32_t i;
1217
1218 fprintf(stderr, " ; %s = {", name);
1219 for (i = 0; i < op_array->last_var + op_array->T; i++) {
1220 if (zend_bitset_in(set, i)) {
1221 if (first) {
1222 first = 0;
1223 } else {
1224 fprintf(stderr, ", ");
1225 }
1226 zend_dump_var(op_array, IS_CV, i);
1227 }
1228 }
1229 fprintf(stderr, "}\n");
1230 }
1231
zend_dump_dfg(const zend_op_array * op_array,const zend_cfg * cfg,const zend_dfg * dfg)1232 void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zend_dfg *dfg)
1233 {
1234 int j;
1235 fprintf(stderr, "\nVariable Liveness for \"");
1236 zend_dump_op_array_name(op_array);
1237 fprintf(stderr, "\"\n");
1238
1239 for (j = 0; j < cfg->blocks_count; j++) {
1240 fprintf(stderr, " BB%d:\n", j);
1241 zend_dump_var_set(op_array, "def", DFG_BITSET(dfg->def, dfg->size, j));
1242 zend_dump_var_set(op_array, "use", DFG_BITSET(dfg->use, dfg->size, j));
1243 zend_dump_var_set(op_array, "in ", DFG_BITSET(dfg->in, dfg->size, j));
1244 zend_dump_var_set(op_array, "out", DFG_BITSET(dfg->out, dfg->size, j));
1245 }
1246 }
1247
zend_dump_phi_placement(const zend_op_array * op_array,const zend_ssa * ssa)1248 void zend_dump_phi_placement(const zend_op_array *op_array, const zend_ssa *ssa)
1249 {
1250 int j;
1251 zend_ssa_block *ssa_blocks = ssa->blocks;
1252 int blocks_count = ssa->cfg.blocks_count;
1253
1254 fprintf(stderr, "\nSSA Phi() Placement for \"");
1255 zend_dump_op_array_name(op_array);
1256 fprintf(stderr, "\"\n");
1257 for (j = 0; j < blocks_count; j++) {
1258 if (ssa_blocks && ssa_blocks[j].phis) {
1259 zend_ssa_phi *p = ssa_blocks[j].phis;
1260 int first = 1;
1261
1262 fprintf(stderr, " BB%d:\n", j);
1263 if (p->pi >= 0) {
1264 fprintf(stderr, " ; pi={");
1265 } else {
1266 fprintf(stderr, " ; phi={");
1267 }
1268 do {
1269 if (first) {
1270 first = 0;
1271 } else {
1272 fprintf(stderr, ", ");
1273 }
1274 zend_dump_var(op_array, IS_CV, p->var);
1275 p = p->next;
1276 } while (p);
1277 fprintf(stderr, "}\n");
1278 }
1279 }
1280 }
1281