Coverage Report

Created: 2026-06-02 06:39

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