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