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