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