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