Coverage Report

Created: 2025-06-13 06:43

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