PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - sapi/phpdbg - phpdbg_frame.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 55 181 30.4 %
Date: 2018-06-14 Functions: 3 8 37.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2018 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             :    | http://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: Felipe Pena <felipe@php.net>                                |
      16             :    | Authors: Joe Watkins <joe.watkins@live.co.uk>                        |
      17             :    | Authors: Bob Weinand <bwoebi@php.net>                                |
      18             :    +----------------------------------------------------------------------+
      19             : */
      20             : 
      21             : #include "zend.h"
      22             : #include "phpdbg.h"
      23             : #include "phpdbg_utils.h"
      24             : #include "phpdbg_frame.h"
      25             : #include "phpdbg_list.h"
      26             : #include "zend_smart_str.h"
      27             : 
      28             : ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
      29             : 
      30           0 : static inline void phpdbg_append_individual_arg(smart_str *s, uint32_t i, zend_function *func, zval *arg) {
      31           0 :         const zend_arg_info *arginfo = func->common.arg_info;
      32           0 :         char *arg_name = NULL;
      33             : 
      34           0 :         if (i) {
      35             :                 smart_str_appends(s, ", ");
      36             :         }
      37           0 :         if (i < func->common.num_args) {
      38           0 :                 if (arginfo) {
      39           0 :                         if (func->type == ZEND_INTERNAL_FUNCTION) {
      40           0 :                                 arg_name = (char *) ((zend_internal_arg_info *) &arginfo[i])->name;
      41             :                         } else {
      42           0 :                                 arg_name = ZSTR_VAL(arginfo[i].name);
      43             :                         }
      44             :                 }
      45           0 :                 smart_str_appends(s, arg_name ? arg_name : "?");
      46             :                 smart_str_appendc(s, '=');
      47             :         }
      48             :         {
      49           0 :                 char *arg_print = phpdbg_short_zval_print(arg, 40);
      50           0 :                 smart_str_appends(s, arg_print);
      51           0 :                 efree(arg_print);
      52             :         }
      53           0 : }
      54             : 
      55           0 : zend_string *phpdbg_compile_stackframe(zend_execute_data *ex) {
      56           0 :         smart_str s = {0};
      57           0 :         zend_op_array *op_array = &ex->func->op_array;
      58           0 :         uint32_t i = 0, first_extra_arg = op_array->num_args, num_args = ZEND_CALL_NUM_ARGS(ex);
      59           0 :         zval *p = ZEND_CALL_ARG(ex, 1);
      60             : 
      61           0 :         if (op_array->scope) {
      62           0 :                 smart_str_append(&s, op_array->scope->name);
      63             :                 smart_str_appends(&s, "::");
      64             :         }
      65           0 :         smart_str_append(&s, op_array->function_name);
      66             :         smart_str_appendc(&s, '(');
      67           0 :         if (ZEND_CALL_NUM_ARGS(ex) > first_extra_arg) {
      68           0 :                 while (i < first_extra_arg) {
      69           0 :                         phpdbg_append_individual_arg(&s, i, ex->func, p);
      70           0 :                         p++;
      71           0 :                         i++;
      72             :                 }
      73           0 :                 p = ZEND_CALL_VAR_NUM(ex, op_array->last_var + op_array->T);
      74             :         }
      75           0 :         while (i < num_args) {
      76           0 :                 phpdbg_append_individual_arg(&s, i, ex->func, p);
      77           0 :                 p++;
      78           0 :                 i++;
      79             :         }
      80             :         smart_str_appendc(&s, ')');
      81             : 
      82           0 :         if (ex->func->type == ZEND_USER_FUNCTION) {
      83             :                 smart_str_appends(&s, " at ");
      84           0 :                 smart_str_append(&s, op_array->filename);
      85             :                 smart_str_appendc(&s, ':');
      86             :                 smart_str_append_unsigned(&s, ex->opline->lineno);
      87             :         } else {
      88             :                 smart_str_appends(&s, " [internal function]");
      89             :         }
      90             : 
      91           0 :         return s.s;
      92             : }
      93             : 
      94           0 : void phpdbg_print_cur_frame_info() {
      95           0 :         const char *file_chr = zend_get_executed_filename();
      96           0 :         zend_string *file = zend_string_init(file_chr, strlen(file_chr), 0);
      97             : 
      98           0 :         phpdbg_list_file(file, 3, zend_get_executed_lineno() - 1, zend_get_executed_lineno());
      99           0 :         efree(file);
     100           0 : }
     101             : 
     102          54 : void phpdbg_restore_frame(void) /* {{{ */
     103             : {
     104          54 :         if (PHPDBG_FRAME(num) == 0) {
     105          54 :                 return;
     106             :         }
     107             : 
     108           0 :         if (PHPDBG_FRAME(generator)) {
     109           0 :                 if (PHPDBG_FRAME(generator)->execute_data->call) {
     110           0 :                         PHPDBG_FRAME(generator)->frozen_call_stack = zend_generator_freeze_call_stack(PHPDBG_FRAME(generator)->execute_data);
     111             :                 }
     112           0 :                 PHPDBG_FRAME(generator) = NULL;
     113             :         }
     114             : 
     115           0 :         PHPDBG_FRAME(num) = 0;
     116             : 
     117             :         /* move things back */
     118           0 :         EG(current_execute_data) = PHPDBG_FRAME(execute_data);
     119             : } /* }}} */
     120             : 
     121           0 : void phpdbg_switch_frame(int frame) /* {{{ */
     122             : {
     123           0 :         zend_execute_data *execute_data = PHPDBG_FRAME(num) ? PHPDBG_FRAME(execute_data) : EG(current_execute_data);
     124           0 :         int i = 0;
     125             : 
     126           0 :         if (PHPDBG_FRAME(num) == frame) {
     127           0 :                 phpdbg_notice("frame", "id=\"%d\"", "Already in frame #%d", frame);
     128           0 :                 return;
     129             :         }
     130             : 
     131           0 :         phpdbg_try_access {
     132           0 :                 while (execute_data) {
     133           0 :                         if (i++ == frame) {
     134           0 :                                 break;
     135             :                         }
     136             : 
     137             :                         do {
     138           0 :                                 execute_data = execute_data->prev_execute_data;
     139           0 :                         } while (execute_data && execute_data->opline == NULL);
     140             :                 }
     141           0 :         } phpdbg_catch_access {
     142           0 :                 phpdbg_error("signalsegv", "", "Couldn't switch frames, invalid data source");
     143           0 :                 return;
     144           0 :         } phpdbg_end_try_access();
     145             : 
     146           0 :         if (execute_data == NULL) {
     147           0 :                 phpdbg_error("frame", "type=\"maxnum\" id=\"%d\"", "No frame #%d", frame);
     148           0 :                 return;
     149             :         }
     150             : 
     151           0 :         phpdbg_restore_frame();
     152             : 
     153           0 :         if (frame > 0) {
     154           0 :                 PHPDBG_FRAME(num) = frame;
     155             : 
     156             :                 /* backup things and jump back */
     157           0 :                 PHPDBG_FRAME(execute_data) = EG(current_execute_data);
     158           0 :                 EG(current_execute_data) = execute_data;
     159             :         }
     160             : 
     161           0 :         phpdbg_try_access {
     162           0 :                 zend_string *s = phpdbg_compile_stackframe(EG(current_execute_data));
     163           0 :                 phpdbg_notice("frame", "id=\"%d\" frameinfo=\"%.*s\"", "Switched to frame #%d: %.*s", frame, (int) ZSTR_LEN(s), ZSTR_VAL(s));
     164             :                 zend_string_release(s);
     165           0 :         } phpdbg_catch_access {
     166           0 :                 phpdbg_notice("frame", "id=\"%d\"", "Switched to frame #%d", frame);
     167           0 :         } phpdbg_end_try_access();
     168             : 
     169           0 :         phpdbg_print_cur_frame_info();
     170             : } /* }}} */
     171             : 
     172           1 : static void phpdbg_dump_prototype(zval *tmp) /* {{{ */
     173             : {
     174             :         zval *funcname, *class, class_zv, *type, *args, *argstmp;
     175             : 
     176           1 :         funcname = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("function"));
     177             : 
     178           1 :         if ((class = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("object")))) {
     179           0 :                 ZVAL_NEW_STR(&class_zv, Z_OBJCE_P(class)->name);
     180           0 :                 class = &class_zv;
     181             :         } else {
     182           1 :                 class = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("class"));
     183             :         }
     184             : 
     185           1 :         if (class) {
     186           0 :                 type = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("type"));
     187             :         }
     188             : 
     189           1 :         args = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("args"));
     190             : 
     191           1 :         phpdbg_xml(" symbol=\"%s%s%s\"", class ? Z_STRVAL_P(class) : "", class ? Z_STRVAL_P(type) : "", Z_STRVAL_P(funcname));
     192             : 
     193           1 :         if (args) {
     194           1 :                 phpdbg_xml(">");
     195             :         } else {
     196           0 :                 phpdbg_xml(" />");
     197             :         }
     198             : 
     199           1 :         phpdbg_out("%s%s%s(", class ? Z_STRVAL_P(class) : "", class ? Z_STRVAL_P(type) : "", Z_STRVAL_P(funcname));
     200             : 
     201           1 :         if (args) {
     202           1 :                 const zend_function *func = NULL;
     203           1 :                 const zend_arg_info *arginfo = NULL;
     204           1 :                 zend_bool is_variadic = 0;
     205           1 :                 int j = 0, m;
     206             : 
     207           1 :                 phpdbg_try_access {
     208             :                         /* assuming no autoloader call is necessary, class should have been loaded if it's in backtrace ... */
     209           1 :                         if ((func = phpdbg_get_function(Z_STRVAL_P(funcname), class ? Z_STRVAL_P(class) : NULL))) {
     210           0 :                                 arginfo = func->common.arg_info;
     211             :                         }
     212           1 :                 } phpdbg_end_try_access();
     213             : 
     214           1 :                 m = func ? func->common.num_args : 0;
     215             : 
     216           1 :                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), argstmp) {
     217           0 :                         if (j) {
     218           0 :                                 phpdbg_out(", ");
     219             :                         }
     220           0 :                         phpdbg_xml("<arg %r");
     221           0 :                         if (m && j < m) {
     222           0 :                                 char *arg_name = NULL;
     223             : 
     224           0 :                                 if (arginfo) {
     225           0 :                                         if (func->type == ZEND_INTERNAL_FUNCTION) {
     226           0 :                                                 arg_name = (char *)((zend_internal_arg_info *)&arginfo[j])->name;
     227             :                                         } else {
     228           0 :                                                 arg_name = ZSTR_VAL(arginfo[j].name);
     229             :                                         }
     230             :                                 }
     231             : 
     232           0 :                                 if (!is_variadic) {
     233           0 :                                         is_variadic = arginfo ? arginfo[j].is_variadic : 0;
     234             :                                 }
     235             : 
     236           0 :                                 phpdbg_xml(" variadic=\"%s\" name=\"%s\">", is_variadic ? "variadic" : "", arg_name ? arg_name : "");
     237           0 :                                 phpdbg_out("%s=%s", arg_name ? arg_name : "?", is_variadic ? "[": "");
     238             : 
     239             :                         } else {
     240           0 :                                 phpdbg_xml(">");
     241             :                         }
     242           0 :                         ++j;
     243             : 
     244             :                         {
     245           0 :                                 char *arg_print = phpdbg_short_zval_print(argstmp, 40);
     246           0 :                                 php_printf("%s", arg_print);
     247           0 :                                 efree(arg_print);
     248             :                         }
     249             : 
     250           0 :                         phpdbg_xml("</arg>");
     251             :                 } ZEND_HASH_FOREACH_END();
     252             : 
     253           1 :                 if (is_variadic) {
     254           0 :                         phpdbg_out("]");
     255             :                 }
     256           1 :                 phpdbg_xml("</frame>");
     257             :         }
     258           1 :         phpdbg_out(")");
     259           1 : }
     260             : 
     261           1 : void phpdbg_dump_backtrace(size_t num) /* {{{ */
     262             : {
     263             :         HashPosition position;
     264             :         zval zbacktrace;
     265             :         zval *tmp;
     266             :         zval startline, startfile;
     267             :         const char *startfilename;
     268           1 :         zval *file = &startfile, *line = &startline;
     269           1 :         int i = 0, limit = num;
     270             : 
     271           1 :         PHPDBG_OUTPUT_BACKUP();
     272             : 
     273           1 :         if (limit < 0) {
     274           0 :                 phpdbg_error("backtrace", "type=\"minnum\"", "Invalid backtrace size %d", limit);
     275             : 
     276           0 :                 PHPDBG_OUTPUT_BACKUP_RESTORE();
     277           0 :                 return;
     278             :         }
     279             : 
     280           1 :         phpdbg_try_access {
     281           1 :                 zend_fetch_debug_backtrace(&zbacktrace, 0, 0, limit);
     282           0 :         } phpdbg_catch_access {
     283           0 :                 phpdbg_error("signalsegv", "", "Couldn't fetch backtrace, invalid data source");
     284           0 :                 return;
     285           1 :         } phpdbg_end_try_access();
     286             : 
     287           1 :         phpdbg_xml("<backtrace %r>");
     288             : 
     289           1 :         Z_LVAL(startline) = zend_get_executed_lineno();
     290           1 :         startfilename = zend_get_executed_filename();
     291           2 :         Z_STR(startfile) = zend_string_init(startfilename, strlen(startfilename), 0);
     292             : 
     293           1 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
     294           1 :         tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position);
     295           3 :         while ((tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position))) {
     296           1 :                 if (file) { /* userland */
     297           1 :                         phpdbg_out("frame #%d: ", i);
     298           1 :                         phpdbg_xml("<frame %r id=\"%d\" file=\"%s\" line=\"" ZEND_LONG_FMT "\"", i, Z_STRVAL_P(file), Z_LVAL_P(line));
     299           1 :                         phpdbg_dump_prototype(tmp);
     300           1 :                         phpdbg_out(" at %s:%ld\n", Z_STRVAL_P(file), Z_LVAL_P(line));
     301           1 :                         i++;
     302             :                 } else {
     303           0 :                         phpdbg_out(" => ");
     304           0 :                         phpdbg_xml("<frame %r id=\"%d\" internal=\"internal\"", i);
     305           0 :                         phpdbg_dump_prototype(tmp);
     306           0 :                         phpdbg_out(" (internal function)\n");
     307             :                 }
     308             : 
     309           1 :                 file = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("file"));
     310           1 :                 line = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("line"));
     311           1 :                 zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position);
     312             :         }
     313             : 
     314           1 :         phpdbg_writeln("frame", "id=\"%d\" symbol=\"{main}\" file=\"%s\" line=\"%d\"", "frame #%d: {main} at %s:%ld", i, Z_STRVAL_P(file), Z_LVAL_P(line));
     315           1 :         phpdbg_xml("</backtrace>");
     316             : 
     317             :         zval_dtor(&zbacktrace);
     318           1 :         zend_string_release(Z_STR(startfile));
     319             : 
     320           1 :         PHPDBG_OUTPUT_BACKUP_RESTORE();
     321             : } /* }}} */
     322             : 
     323           0 : void phpdbg_open_generator_frame(zend_generator *gen) {
     324             :         zend_string *s;
     325             : 
     326           0 :         if (EG(current_execute_data) == gen->execute_data) {
     327           0 :                 return;
     328             :         }
     329             : 
     330           0 :         phpdbg_restore_frame();
     331             : 
     332           0 :         PHPDBG_FRAME(num) = -1;
     333           0 :         PHPDBG_FRAME(generator) = gen;
     334             : 
     335           0 :         EG(current_execute_data) = gen->execute_data;
     336           0 :         if (gen->frozen_call_stack) {
     337           0 :                 zend_generator_restore_call_stack(gen);
     338             :         }
     339           0 :         gen->execute_data->prev_execute_data = NULL;
     340             : 
     341           0 :         s = phpdbg_compile_stackframe(EG(current_execute_data));
     342           0 :         phpdbg_notice("frame", "handle=\"%d\" frameinfo=\"%.*s\"", "Switched to generator with handle #%d: %.*s", gen->std.handle, (int) ZSTR_LEN(s), ZSTR_VAL(s));
     343             :         zend_string_release(s);
     344           0 :         phpdbg_print_cur_frame_info();
     345             : }

Generated by: LCOV version 1.10

Generated at Thu, 14 Jun 2018 10:45:11 +0000 (5 days ago)

Copyright © 2005-2018 The PHP Group
All rights reserved.