root/sapi/phpdbg/phpdbg_frame.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_EXTERN_MODULE_GLOBALS
  2. phpdbg_switch_frame
  3. phpdbg_dump_prototype
  4. phpdbg_dump_backtrace

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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 
  27 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
  28 
  29 void phpdbg_restore_frame(void) /* {{{ */
  30 {
  31         if (PHPDBG_FRAME(num) == 0) {
  32                 return;
  33         }
  34 
  35         PHPDBG_FRAME(num) = 0;
  36 
  37         /* move things back */
  38         EG(current_execute_data) = PHPDBG_FRAME(execute_data);
  39 
  40         EG(scope) = PHPDBG_EX(func)->op_array.scope;
  41 } /* }}} */
  42 
  43 void phpdbg_switch_frame(int frame) /* {{{ */
  44 {
  45         zend_execute_data *execute_data = PHPDBG_FRAME(num)?PHPDBG_FRAME(execute_data):EG(current_execute_data);
  46         int i = 0;
  47 
  48         if (PHPDBG_FRAME(num) == frame) {
  49                 phpdbg_notice("frame", "id=\"%d\"", "Already in frame #%d", frame);
  50                 return;
  51         }
  52 
  53         phpdbg_try_access {
  54                 while (execute_data) {
  55                         if (i++ == frame) {
  56                                 break;
  57                         }
  58 
  59                         do {
  60                                 execute_data = execute_data->prev_execute_data;
  61                         } while (execute_data && execute_data->opline == NULL);
  62                 }
  63         } phpdbg_catch_access {
  64                 phpdbg_error("signalsegv", "", "Couldn't switch frames, invalid data source");
  65                 return;
  66         } phpdbg_end_try_access();
  67 
  68         if (execute_data == NULL) {
  69                 phpdbg_error("frame", "type=\"maxnum\" id=\"%d\"", "No frame #%d", frame);
  70                 return;
  71         }
  72 
  73         phpdbg_restore_frame();
  74 
  75         if (frame > 0) {
  76                 PHPDBG_FRAME(num) = frame;
  77 
  78                 /* backup things and jump back */
  79                 PHPDBG_FRAME(execute_data) = EG(current_execute_data);
  80                 EG(current_execute_data) = execute_data;
  81 
  82                 EG(scope) = PHPDBG_EX(func)->op_array.scope;
  83         }
  84 
  85         phpdbg_notice("frame", "id=\"%d\"", "Switched to frame #%d", frame);
  86 
  87         {
  88                 const char *file_chr = zend_get_executed_filename();
  89                 zend_string *file = zend_string_init(file_chr, strlen(file_chr), 0);
  90                 phpdbg_list_file(file, 3, zend_get_executed_lineno() - 1, zend_get_executed_lineno());
  91                 efree(file);
  92         }
  93 } /* }}} */
  94 
  95 static void phpdbg_dump_prototype(zval *tmp) /* {{{ */
  96 {
  97         zval *funcname, *class, class_zv, *type, *args, *argstmp;
  98 
  99         funcname = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("function"));
 100 
 101         if ((class = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("object")))) {
 102                 ZVAL_NEW_STR(&class_zv, Z_OBJCE_P(class)->name);
 103                 class = &class_zv;
 104         } else {
 105                 class = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("class"));
 106         }
 107 
 108         if (class) {
 109                 type = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("type"));
 110         }
 111 
 112         args = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("args"));
 113 
 114         phpdbg_xml(" symbol=\"%s%s%s\"", class ? Z_STRVAL_P(class) : "", class ? Z_STRVAL_P(type) : "", Z_STRVAL_P(funcname));
 115 
 116         if (args) {
 117                 phpdbg_xml(">");
 118         } else {
 119                 phpdbg_xml(" />");
 120         }
 121 
 122         phpdbg_out("%s%s%s(", class ? Z_STRVAL_P(class) : "", class ? Z_STRVAL_P(type) : "", Z_STRVAL_P(funcname));
 123 
 124         if (args) {
 125                 const zend_function *func = NULL;
 126                 const zend_arg_info *arginfo = NULL;
 127                 zend_bool is_variadic = 0;
 128                 int j = 0, m;
 129 
 130                 phpdbg_try_access {
 131                         /* assuming no autoloader call is necessary, class should have been loaded if it's in backtrace ... */
 132                         if ((func = phpdbg_get_function(Z_STRVAL_P(funcname), class ? Z_STRVAL_P(class) : NULL))) {
 133                                 arginfo = func->common.arg_info;
 134                         }
 135                 } phpdbg_end_try_access();
 136 
 137                 m = func ? func->common.num_args : 0;
 138 
 139                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), argstmp) {
 140                         if (j) {
 141                                 phpdbg_out(", ");
 142                         }
 143                         phpdbg_xml("<arg %r");
 144                         if (m && j < m) {
 145                                 char *arg_name = NULL;
 146 
 147                                 if (arginfo) {
 148                                         if (func->type == ZEND_INTERNAL_FUNCTION) {
 149                                                 arg_name = (char *)((zend_internal_arg_info *)&arginfo[j])->name;
 150                                         } else {
 151                                                 arg_name = ZSTR_VAL(arginfo[j].name);
 152                                         }
 153                                 }
 154 
 155                                 if (!is_variadic) {
 156                                         is_variadic = arginfo ? arginfo[j].is_variadic : 0;
 157                                 }
 158 
 159                                 phpdbg_xml(" variadic=\"%s\" name=\"%s\">", is_variadic ? "variadic" : "", arg_name ? arg_name : "");
 160                                 phpdbg_out("%s=%s", arg_name ? arg_name : "?", is_variadic ? "[": "");
 161 
 162                         } else {
 163                                 phpdbg_xml(">");
 164                         }
 165                         ++j;
 166 
 167                         {
 168                                 char *arg_print = phpdbg_short_zval_print(argstmp, 40);
 169                                 php_printf("%s", arg_print);
 170                                 efree(arg_print);
 171                         }
 172 
 173                         phpdbg_xml("</arg>");
 174                 } ZEND_HASH_FOREACH_END();
 175 
 176                 if (is_variadic) {
 177                         phpdbg_out("]");
 178                 }
 179                 phpdbg_xml("</frame>");
 180         }
 181         phpdbg_out(")");
 182 }
 183 
 184 void phpdbg_dump_backtrace(size_t num) /* {{{ */
 185 {
 186         HashPosition position;
 187         zval zbacktrace;
 188         zval *tmp;
 189         zval startline, startfile;
 190         const char *startfilename;
 191         zval *file = &startfile, *line = &startline;
 192         int i = 0, limit = num;
 193 
 194         PHPDBG_OUTPUT_BACKUP();
 195 
 196         if (limit < 0) {
 197                 phpdbg_error("backtrace", "type=\"minnum\"", "Invalid backtrace size %d", limit);
 198 
 199                 PHPDBG_OUTPUT_BACKUP_RESTORE();
 200                 return;
 201         }
 202 
 203         phpdbg_try_access {
 204                 zend_fetch_debug_backtrace(&zbacktrace, 0, 0, limit);
 205         } phpdbg_catch_access {
 206                 phpdbg_error("signalsegv", "", "Couldn't fetch backtrace, invalid data source");
 207                 return;
 208         } phpdbg_end_try_access();
 209 
 210         phpdbg_xml("<backtrace %r>");
 211 
 212         Z_LVAL(startline) = zend_get_executed_lineno();
 213         startfilename = zend_get_executed_filename();
 214         Z_STR(startfile) = zend_string_init(startfilename, strlen(startfilename), 0);
 215 
 216         zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
 217         tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position);
 218         while ((tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position))) {
 219                 if (file) { /* userland */
 220                         phpdbg_out("frame #%d: ", i);
 221                         phpdbg_xml("<frame %r id=\"%d\" file=\"%s\" line=\"" ZEND_LONG_FMT "\"", i, Z_STRVAL_P(file), Z_LVAL_P(line));
 222                         phpdbg_dump_prototype(tmp);
 223                         phpdbg_out(" at %s:%ld\n", Z_STRVAL_P(file), Z_LVAL_P(line));
 224                         i++;
 225                 } else {
 226                         phpdbg_out(" => ");
 227                         phpdbg_xml("<frame %r id=\"%d\" internal=\"internal\"", i);
 228                         phpdbg_dump_prototype(tmp);
 229                         phpdbg_out(" (internal function)\n");
 230                 }
 231 
 232                 file = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("file"));
 233                 line = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("line"));
 234                 zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position);
 235         }
 236 
 237         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));
 238         phpdbg_xml("</backtrace>");
 239 
 240         zval_dtor(&zbacktrace);
 241         zend_string_release(Z_STR(startfile));
 242 
 243         PHPDBG_OUTPUT_BACKUP_RESTORE();
 244 } /* }}} */

/* [<][>][^][v][top][bottom][index][help] */