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