Coverage Report

Created: 2026-01-18 06:48

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