PageRenderTime 65ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/xdebug_var.c

http://github.com/derickr/xdebug
C | 2912 lines | 2781 code | 90 blank | 41 comment | 193 complexity | 60df2dfa2e3b85949f700adcfd32b3f7 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | Xdebug |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2002-2016 Derick Rethans |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 1.0 of the Xdebug license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available at through the world-wide-web at |
  10. | http://xdebug.derickrethans.nl/license.php |
  11. | If you did not receive a copy of the Xdebug license and are unable |
  12. | to obtain it through the world-wide-web, please send a note to |
  13. | xdebug@derickrethans.nl so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Derick Rethans <derick@xdebug.org> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #include "php.h"
  19. #include "ext/standard/php_string.h"
  20. #include "ext/standard/url.h"
  21. #include "zend.h"
  22. #include "zend_extensions.h"
  23. #if PHP_VERSION_ID >= 70000
  24. # include "ext/standard/php_smart_string.h"
  25. # include "zend_smart_str.h"
  26. #else
  27. # include "ext/standard/php_smart_str.h"
  28. #endif
  29. #include "php_xdebug.h"
  30. #include "xdebug_compat.h"
  31. #include "xdebug_private.h"
  32. #include "xdebug_mm.h"
  33. #include "xdebug_var.h"
  34. #include "xdebug_xml.h"
  35. /* Set correct int format to use */
  36. #if PHP_VERSION_ID >= 70000
  37. # include "Zend/zend_long.h"
  38. # if SIZEOF_ZEND_LONG == 4
  39. # define XDEBUG_INT_FMT "%ld"
  40. # else
  41. # define XDEBUG_INT_FMT "%lld"
  42. # endif
  43. #else
  44. # define XDEBUG_INT_FMT "%ld"
  45. #endif
  46. ZEND_EXTERN_MODULE_GLOBALS(xdebug)
  47. HashTable *xdebug_objdebug_pp(zval **zval_pp, int *is_tmp TSRMLS_DC)
  48. {
  49. zval dzval = **zval_pp;
  50. HashTable *tmp;
  51. if (!XG(in_debug_info) && Z_OBJ_HANDLER(dzval, get_debug_info)) {
  52. zend_bool old_trace = XG(do_trace);
  53. #if PHP_VERSION_ID >= 70000
  54. zend_object *orig_exception;
  55. #else
  56. zval *orig_exception;
  57. #endif
  58. XG(do_trace) = 0;
  59. XG(in_debug_info) = 1;
  60. orig_exception = EG(exception);
  61. EG(exception) = NULL;
  62. tmp = Z_OBJ_HANDLER(dzval, get_debug_info)(&dzval, is_tmp TSRMLS_CC);
  63. XG(in_debug_info) = 0;
  64. XG(do_trace) = old_trace;
  65. EG(exception) = orig_exception;
  66. return tmp;
  67. } else {
  68. *is_tmp = 0;
  69. if (Z_OBJ_HANDLER(dzval, get_properties)) {
  70. return Z_OBJPROP(dzval);
  71. }
  72. }
  73. return NULL;
  74. }
  75. char* xdebug_error_type_simple(int type)
  76. {
  77. switch (type) {
  78. case E_ERROR:
  79. case E_CORE_ERROR:
  80. case E_COMPILE_ERROR:
  81. case E_USER_ERROR:
  82. return xdstrdup("fatal-error");
  83. break;
  84. case E_RECOVERABLE_ERROR:
  85. return xdstrdup("catchable-fatal-error");
  86. break;
  87. case E_WARNING:
  88. case E_CORE_WARNING:
  89. case E_COMPILE_WARNING:
  90. case E_USER_WARNING:
  91. return xdstrdup("warning");
  92. break;
  93. case E_PARSE:
  94. return xdstrdup("parse-error");
  95. break;
  96. case E_NOTICE:
  97. case E_USER_NOTICE:
  98. return xdstrdup("notice");
  99. break;
  100. case E_STRICT:
  101. return xdstrdup("strict-standards");
  102. break;
  103. case E_DEPRECATED:
  104. case E_USER_DEPRECATED:
  105. return xdstrdup("deprecated");
  106. break;
  107. case 0:
  108. return xdstrdup("xdebug");
  109. break;
  110. default:
  111. return xdstrdup("unknown-error");
  112. break;
  113. }
  114. }
  115. char* xdebug_error_type(int type)
  116. {
  117. switch (type) {
  118. case E_ERROR:
  119. case E_CORE_ERROR:
  120. case E_COMPILE_ERROR:
  121. case E_USER_ERROR:
  122. return xdstrdup("Fatal error");
  123. break;
  124. case E_RECOVERABLE_ERROR:
  125. return xdstrdup("Catchable fatal error");
  126. break;
  127. case E_WARNING:
  128. case E_CORE_WARNING:
  129. case E_COMPILE_WARNING:
  130. case E_USER_WARNING:
  131. return xdstrdup("Warning");
  132. break;
  133. case E_PARSE:
  134. return xdstrdup("Parse error");
  135. break;
  136. case E_NOTICE:
  137. case E_USER_NOTICE:
  138. return xdstrdup("Notice");
  139. break;
  140. case E_STRICT:
  141. return xdstrdup("Strict standards");
  142. break;
  143. case E_DEPRECATED:
  144. case E_USER_DEPRECATED:
  145. return xdstrdup("Deprecated");
  146. break;
  147. case 0:
  148. return xdstrdup("Xdebug");
  149. break;
  150. default:
  151. return xdstrdup("Unknown error");
  152. break;
  153. }
  154. }
  155. /*************************************************************************************************************************************/
  156. #if PHP_VERSION_ID >= 70000
  157. # define T(offset) (*(union _temp_variable *)((char*)zdata->current_execute_data->Ts + offset))
  158. #elif PHP_VERSION_ID >= 50500
  159. # define T(offset) (*EX_TMP_VAR(zdata, offset))
  160. #else
  161. # define T(offset) (*(temp_variable *)((char*)zdata->Ts + offset))
  162. #endif
  163. #if PHP_VERSION_ID >= 70000
  164. zval *xdebug_get_zval(zend_execute_data *zdata, int node_type, const znode_op *node, int *is_var)
  165. {
  166. zend_free_op should_free;
  167. return zend_get_zval_ptr(node_type, node, zdata, &should_free, BP_VAR_IS);
  168. }
  169. #else
  170. zval *xdebug_get_zval(zend_execute_data *zdata, int node_type, const znode_op *node, int *is_var)
  171. {
  172. switch (node_type) {
  173. case IS_CONST:
  174. #if PHP_VERSION_ID >= 50300
  175. return node->zv;
  176. #else
  177. return &node->u.constant;
  178. #endif
  179. break;
  180. case IS_TMP_VAR:
  181. *is_var = 1;
  182. return &T(node->var).tmp_var;
  183. break;
  184. case IS_VAR:
  185. *is_var = 1;
  186. if (T(node->var).var.ptr) {
  187. return T(node->var).var.ptr;
  188. }
  189. break;
  190. case IS_CV: {
  191. zval **tmp;
  192. tmp = zend_get_compiled_variable_value(zdata, node->constant);
  193. if (tmp) {
  194. return *tmp;
  195. }
  196. break;
  197. }
  198. case IS_UNUSED:
  199. fprintf(stderr, "\nIS_UNUSED\n");
  200. break;
  201. default:
  202. fprintf(stderr, "\ndefault %d\n", node_type);
  203. break;
  204. }
  205. *is_var = 1;
  206. return NULL;
  207. }
  208. #endif
  209. /*****************************************************************************
  210. ** PHP Variable related utility functions
  211. */
  212. /*****************************************************************************
  213. ** Data returning functions
  214. */
  215. #define XF_ST_ROOT 0
  216. #define XF_ST_ARRAY_INDEX_NUM 1
  217. #define XF_ST_ARRAY_INDEX_ASSOC 2
  218. #define XF_ST_OBJ_PROPERTY 3
  219. #define XF_ST_STATIC_ROOT 4
  220. #define XF_ST_STATIC_PROPERTY 5
  221. inline static HashTable *fetch_ht_from_zval(zval *z TSRMLS_DC)
  222. {
  223. #if PHP_VERSION_ID >= 70000
  224. if (Z_TYPE_P(z) == IS_REFERENCE) {
  225. z = &z->value.ref->val;
  226. }
  227. #endif
  228. switch (Z_TYPE_P(z)) {
  229. case IS_ARRAY:
  230. return Z_ARRVAL_P(z);
  231. break;
  232. case IS_OBJECT:
  233. return Z_OBJPROP_P(z);
  234. break;
  235. }
  236. return NULL;
  237. }
  238. #if PHP_VERSION_ID >= 70000
  239. inline static char *fetch_classname_from_zval(zval *z, int *length, zend_class_entry **ce TSRMLS_DC)
  240. {
  241. zend_string *class_name;
  242. if (Z_TYPE_P(z) != IS_OBJECT) {
  243. return NULL;
  244. }
  245. class_name = Z_OBJ_HANDLER_P(z, get_class_name)(Z_OBJ_P(z));
  246. *ce = Z_OBJCE_P(z);
  247. *length = class_name->len;
  248. return estrdup(class_name->val);
  249. }
  250. #else
  251. inline static char *fetch_classname_from_zval(zval *z, int *length, zend_class_entry **ce TSRMLS_DC)
  252. {
  253. char *name;
  254. SIZETorZUINT name_len;
  255. zend_class_entry *tmp_ce;
  256. if (Z_TYPE_P(z) != IS_OBJECT) {
  257. return NULL;
  258. }
  259. tmp_ce = zend_get_class_entry(z TSRMLS_CC);
  260. if (Z_OBJ_HT_P(z)->get_class_name == NULL ||
  261. Z_OBJ_HT_P(z)->get_class_name(z, (const char **) &name, &name_len, 0 TSRMLS_CC) != SUCCESS) {
  262. if (!tmp_ce) {
  263. return NULL;
  264. }
  265. *length = tmp_ce->name_length;
  266. *ce = tmp_ce;
  267. return estrdup(tmp_ce->name);
  268. } else {
  269. *ce = tmp_ce;
  270. }
  271. *length = name_len;
  272. return name;
  273. }
  274. #endif
  275. static char* prepare_search_key(char *name, unsigned int *name_length, char *prefix, int prefix_length)
  276. {
  277. char *element;
  278. int extra_length = 0;
  279. if (prefix_length) {
  280. if (prefix[0] == '*') {
  281. extra_length = 3;
  282. } else {
  283. extra_length = 2 + prefix_length;
  284. }
  285. }
  286. element = malloc(*name_length + 1 + extra_length);
  287. memset(element, 0, *name_length + 1 + extra_length);
  288. if (extra_length) {
  289. memcpy(element + 1, prefix, extra_length - 2);
  290. }
  291. memcpy(element + extra_length, name, *name_length);
  292. *name_length += extra_length;
  293. return element;
  294. }
  295. static zval *get_arrayobject_storage(zval *parent TSRMLS_DC)
  296. {
  297. int is_temp;
  298. HashTable *properties = Z_OBJDEBUG_P(parent, is_temp);
  299. #if PHP_VERSION_ID >= 70000
  300. zval *tmp = NULL;
  301. if ((tmp = zend_hash_str_find(properties, "\0ArrayObject\0storage", sizeof("*ArrayObject*storage") - 1)) != NULL) {
  302. return tmp;
  303. #else
  304. zval **tmp = NULL;
  305. if (zend_hash_find(properties, "\0ArrayObject\0storage", sizeof("*ArrayObject*storage"), (void **) &tmp) == SUCCESS) {
  306. return *tmp;
  307. #endif
  308. }
  309. return NULL;
  310. }
  311. static zval *get_splobjectstorage_storage(zval *parent TSRMLS_DC)
  312. {
  313. int is_temp;
  314. HashTable *properties = Z_OBJDEBUG_P(parent, is_temp);
  315. #if PHP_VERSION_ID >= 70000
  316. zval *tmp = NULL;
  317. if ((tmp = zend_hash_str_find(properties, "\0SplObjectStorage\0storage", sizeof("*SplObjectStorage*storage") - 1)) != NULL) {
  318. return tmp;
  319. #else
  320. zval **tmp = NULL;
  321. if (zend_hash_find(properties, "\0SplObjectStorage\0storage", sizeof("*SplObjectStorage*storage"), (void **) &tmp) == SUCCESS) {
  322. return *tmp;
  323. #endif
  324. }
  325. return NULL;
  326. }
  327. static zval *get_arrayiterator_storage(zval *parent TSRMLS_DC)
  328. {
  329. int is_temp;
  330. HashTable *properties = Z_OBJDEBUG_P(parent, is_temp);
  331. #if PHP_VERSION_ID >= 70000
  332. zval *tmp = NULL;
  333. if ((tmp = zend_hash_str_find(properties, "\0ArrayIterator\0storage", sizeof("*ArrayIterator*storage") - 1)) != NULL) {
  334. return tmp;
  335. #else
  336. zval **tmp = NULL;
  337. if (zend_hash_find(properties, "\0ArrayIterator\0storage", sizeof("*ArrayIterator*storage"), (void **) &tmp) == SUCCESS) {
  338. return *tmp;
  339. #endif
  340. }
  341. return NULL;
  342. }
  343. static zval* fetch_zval_from_symbol_table(zval *parent, char* name, unsigned int name_length, int type, char* ccn, int ccnl, zend_class_entry *cce TSRMLS_DC)
  344. {
  345. HashTable *ht = NULL;
  346. zval *retval_p = NULL;
  347. #if PHP_VERSION_ID < 70000
  348. zval **retval_pp = NULL;
  349. #endif
  350. char *element = NULL;
  351. unsigned int element_length = name_length;
  352. zend_property_info *zpp;
  353. if (parent) {
  354. ht = fetch_ht_from_zval(parent TSRMLS_CC);
  355. }
  356. switch (type) {
  357. case XF_ST_STATIC_ROOT:
  358. case XF_ST_STATIC_PROPERTY:
  359. /* First we try a public,private,protected property */
  360. element = prepare_search_key(name, &element_length, "", 0);
  361. #if PHP_VERSION_ID >= 70000
  362. if (cce && &cce->properties_info && ((zpp = zend_hash_str_find_ptr(&cce->properties_info, element, element_length)) != NULL) && cce->static_members_table) {
  363. retval_p = &cce->static_members_table[zpp->offset];
  364. #else
  365. if (cce && &cce->properties_info && zend_hash_find(&cce->properties_info, element, element_length + 1, (void **) &zpp) == SUCCESS) {
  366. retval_p = cce->static_members_table[zpp->offset];
  367. #endif
  368. goto cleanup;
  369. }
  370. element_length = name_length;
  371. /* Then we try to see whether the first char is * and use the part between * and * as class name for the private property */
  372. if (name[0] == '*') {
  373. char *secondStar;
  374. secondStar = strstr(name + 1, "*");
  375. if (secondStar) {
  376. free(element);
  377. element_length = name_length - (secondStar + 1 - name);
  378. element = prepare_search_key(secondStar + 1, &element_length, "", 0);
  379. #if PHP_VERSION_ID >= 70000
  380. if (cce && &cce->properties_info && ((zpp = zend_hash_str_find_ptr(&cce->properties_info, element, element_length)) != NULL)) {
  381. retval_p = &cce->static_members_table[zpp->offset];
  382. #else
  383. if (cce && &cce->properties_info && zend_hash_find(&cce->properties_info, element, element_length + 1, (void **) &zpp) == SUCCESS) {
  384. retval_p = cce->static_members_table[zpp->offset];
  385. #endif
  386. goto cleanup;
  387. }
  388. }
  389. }
  390. break;
  391. case XF_ST_ROOT:
  392. /* Check for compiled vars */
  393. element = prepare_search_key(name, &element_length, "", 0);
  394. #if PHP_VERSION_ID >= 70000
  395. if (XG(active_execute_data) && XG(active_execute_data)->func) {
  396. #else
  397. if (XG(active_execute_data) && XG(active_execute_data)->op_array) {
  398. #endif
  399. int i = 0;
  400. #if PHP_VERSION_ID >= 70000
  401. hashULONG hash_value = zend_inline_hash_func(element, element_length);
  402. zend_op_array *opa = &XG(active_execute_data)->func->op_array;
  403. #else
  404. hashULONG hash_value = zend_inline_hash_func(element, element_length + 1);
  405. zend_op_array *opa = XG(active_execute_data)->op_array;
  406. #endif
  407. zval **CV;
  408. while (i < opa->last_var) {
  409. #if PHP_VERSION_ID >= 70000
  410. if (ZSTR_H(opa->vars[i]) == hash_value &&
  411. ZSTR_LEN(opa->vars[i]) == element_length &&
  412. strncmp(STR_NAME_VAL(opa->vars[i]), element, element_length) == 0)
  413. #else
  414. if (opa->vars[i].hash_value == hash_value &&
  415. opa->vars[i].name_len == (int) element_length &&
  416. strcmp(STR_NAME_VAL(opa->vars[i].name), element) == 0)
  417. #endif
  418. {
  419. #if PHP_VERSION_ID >= 70000
  420. zval *CV_z = ZEND_CALL_VAR_NUM(XG(active_execute_data), i);
  421. CV = &CV_z;
  422. #elif PHP_VERSION_ID >= 50500
  423. CV = (*EX_CV_NUM(XG(active_execute_data), i));
  424. #else
  425. CV = XG(active_execute_data)->CVs[i];
  426. #endif
  427. if (CV) {
  428. retval_p = *CV;
  429. goto cleanup;
  430. }
  431. }
  432. i++;
  433. }
  434. }
  435. free(element);
  436. ht = XG(active_symbol_table);
  437. /* break intentionally missing */
  438. case XF_ST_ARRAY_INDEX_ASSOC:
  439. element = prepare_search_key(name, &name_length, "", 0);
  440. /* Handle "this" in a different way */
  441. if (type == XF_ST_ROOT && strcmp("this", element) == 0) {
  442. if (XG(This)) {
  443. retval_p = XG(This);
  444. } else {
  445. retval_p = NULL;
  446. }
  447. goto cleanup;
  448. }
  449. #if PHP_VERSION_ID >= 70000
  450. if (ht && ((retval_p = zend_hash_str_find(ht, element, name_length)) != NULL)) {
  451. #else
  452. if (ht && zend_hash_find(ht, element, name_length + 1, (void **) &retval_pp) == SUCCESS) {
  453. retval_p = *retval_pp;
  454. #endif
  455. goto cleanup;
  456. }
  457. break;
  458. case XF_ST_ARRAY_INDEX_NUM:
  459. element = prepare_search_key(name, &name_length, "", 0);
  460. #if PHP_VERSION_ID >= 70000
  461. if (ht && ((retval_p = zend_hash_index_find(ht, strtoull(element, NULL, 10))) != NULL)) {
  462. #else
  463. if (ht && zend_hash_index_find(ht, strtoul(element, NULL, 10), (void **) &retval_pp) == SUCCESS) {
  464. retval_p = *retval_pp;
  465. #endif
  466. goto cleanup;
  467. }
  468. break;
  469. case XF_ST_OBJ_PROPERTY:
  470. /* First we try an object handler */
  471. if (cce) {
  472. zval *tmp_val;
  473. #if PHP_VERSION_ID >= 70000
  474. zval dummy;
  475. tmp_val = zend_read_property(cce, parent, name, name_length, 0, &dummy);
  476. if (tmp_val && tmp_val != &EG(uninitialized_zval)) {
  477. #else
  478. tmp_val = zend_read_property(cce, parent, name, name_length, 0 TSRMLS_CC);
  479. if (tmp_val && tmp_val != EG(uninitialized_zval_ptr)) {
  480. #endif
  481. retval_p = tmp_val;
  482. goto cleanup;
  483. }
  484. if (EG(exception)) {
  485. zend_clear_exception(TSRMLS_C);
  486. }
  487. }
  488. /* Then we try a public property */
  489. element = prepare_search_key(name, &element_length, "", 0);
  490. #if PHP_VERSION_ID >= 70000
  491. if (ht && ((retval_p = zend_symtable_str_find(ht, element, element_length)) != NULL)) {
  492. #else
  493. if (ht && zend_symtable_find(ht, element, element_length + 1, (void **) &retval_pp) == SUCCESS) {
  494. retval_p = *retval_pp;
  495. #endif
  496. goto cleanup;
  497. }
  498. element_length = name_length;
  499. /* Then we try it again as protected property */
  500. free(element);
  501. element = prepare_search_key(name, &element_length, "*", 1);
  502. #if PHP_VERSION_ID >= 70000
  503. if (ht && ((retval_p = zend_hash_str_find(ht, element, element_length)) != NULL)) {
  504. #else
  505. if (ht && zend_hash_find(ht, element, element_length + 1, (void **) &retval_pp) == SUCCESS) {
  506. retval_p = *retval_pp;
  507. #endif
  508. goto cleanup;
  509. }
  510. element_length = name_length;
  511. /* Then we try it again as private property */
  512. free(element);
  513. element = prepare_search_key(name, &element_length, ccn, ccnl);
  514. #if PHP_VERSION_ID >= 70000
  515. if (ht && ((retval_p = zend_hash_str_find(ht, element, element_length)) != NULL)) {
  516. #else
  517. if (ht && zend_hash_find(ht, element, element_length + 1, (void **) &retval_pp) == SUCCESS) {
  518. retval_p = *retval_pp;
  519. #endif
  520. goto cleanup;
  521. }
  522. element_length = name_length;
  523. /* All right, time for a mega hack. It's SplObjectStorage access time! */
  524. if (strncmp(ccn, "SplObjectStorage", ccnl) == 0 && strncmp(name, "storage", name_length) == 0) {
  525. element = NULL;
  526. if ((retval_p = get_splobjectstorage_storage(parent TSRMLS_CC)) != NULL) {
  527. if (retval_p) {
  528. goto cleanup;
  529. }
  530. }
  531. }
  532. /* Then we try to see whether the first char is * and use the part between * and * as class name for the private property */
  533. if (name[0] == '*') {
  534. char *secondStar;
  535. secondStar = strstr(name + 1, "*");
  536. if (secondStar) {
  537. free(element);
  538. element_length = name_length - (secondStar + 1 - name);
  539. /* All right, time for a mega hack. It's ArrayObject access time! */
  540. if (strncmp(name + 1, "ArrayObject", secondStar - name - 1) == 0 && strncmp(secondStar + 1, "storage", element_length) == 0) {
  541. element = NULL;
  542. if ((retval_p = get_arrayobject_storage(parent TSRMLS_CC)) != NULL) {
  543. if (retval_p) {
  544. goto cleanup;
  545. }
  546. }
  547. }
  548. /* All right, time for a mega hack. It's ArrayIterator access time! */
  549. if (strncmp(name + 1, "ArrayIterator", secondStar - name - 1) == 0 && strncmp(secondStar + 1, "storage", element_length) == 0) {
  550. element = NULL;
  551. if ((retval_p = get_arrayiterator_storage(parent TSRMLS_CC)) != NULL) {
  552. if (retval_p) {
  553. goto cleanup;
  554. }
  555. }
  556. }
  557. /* The normal one */
  558. element = prepare_search_key(secondStar + 1, &element_length, name + 1, secondStar - name - 1);
  559. #if PHP_VERSION_ID >= 70000
  560. if (ht && ((retval_p = zend_hash_str_find(ht, element, element_length)) != NULL)) {
  561. #else
  562. if (ht && zend_hash_find(ht, element, element_length + 1, (void **) &retval_pp) == SUCCESS) {
  563. retval_p = *retval_pp;
  564. #endif
  565. goto cleanup;
  566. }
  567. }
  568. }
  569. break;
  570. }
  571. cleanup:
  572. if (element) {
  573. free(element);
  574. }
  575. return retval_p;
  576. }
  577. zval* xdebug_get_php_symbol(char* name TSRMLS_DC)
  578. {
  579. int found = -1;
  580. int state = 0;
  581. char **p = &name;
  582. char *keyword = NULL, *keyword_end = NULL;
  583. int type = XF_ST_ROOT;
  584. zval *retval = NULL;
  585. char *current_classname = NULL;
  586. zend_class_entry *current_ce = NULL;
  587. int cc_length = 0;
  588. char quotechar = 0;
  589. do {
  590. if (*p[0] == '\0') {
  591. found = 0;
  592. } else {
  593. switch (state) {
  594. case 0:
  595. if (*p[0] == '$') {
  596. keyword = *p + 1;
  597. break;
  598. }
  599. if (*p[0] == ':') { /* special tricks */
  600. keyword = *p;
  601. state = 7;
  602. break;
  603. }
  604. keyword = *p;
  605. state = 1;
  606. /* break intentionally missing */
  607. case 1:
  608. if (*p[0] == '[') {
  609. keyword_end = *p;
  610. if (keyword) {
  611. retval = fetch_zval_from_symbol_table(retval, keyword, keyword_end - keyword, type, current_classname, cc_length, current_ce TSRMLS_CC);
  612. if (current_classname) {
  613. efree(current_classname);
  614. }
  615. current_classname = NULL;
  616. cc_length = 0;
  617. current_ce = NULL;
  618. keyword = NULL;
  619. }
  620. state = 3;
  621. } else if (*p[0] == '-') {
  622. keyword_end = *p;
  623. if (keyword) {
  624. retval = fetch_zval_from_symbol_table(retval, keyword, keyword_end - keyword, type, current_classname, cc_length, current_ce TSRMLS_CC);
  625. if (current_classname) {
  626. efree(current_classname);
  627. }
  628. current_classname = NULL;
  629. cc_length = 0;
  630. current_ce = NULL;
  631. if (retval) {
  632. current_classname = fetch_classname_from_zval(retval, &cc_length, &current_ce TSRMLS_CC);
  633. }
  634. keyword = NULL;
  635. }
  636. state = 2;
  637. type = XF_ST_OBJ_PROPERTY;
  638. } else if (*p[0] == ':') {
  639. keyword_end = *p;
  640. if (keyword) {
  641. retval = fetch_zval_from_symbol_table(retval, keyword, keyword_end - keyword, type, current_classname, cc_length, current_ce TSRMLS_CC);
  642. if (current_classname) {
  643. efree(current_classname);
  644. }
  645. current_classname = NULL;
  646. cc_length = 0;
  647. if (retval) {
  648. current_classname = fetch_classname_from_zval(retval, &cc_length, &current_ce TSRMLS_CC);
  649. }
  650. keyword = NULL;
  651. }
  652. state = 8;
  653. type = XF_ST_STATIC_PROPERTY;
  654. }
  655. break;
  656. case 2:
  657. if (*p[0] != '>') {
  658. keyword = *p;
  659. state = 1;
  660. }
  661. break;
  662. case 8:
  663. if (*p[0] != ':') {
  664. keyword = *p;
  665. state = 1;
  666. }
  667. break;
  668. case 3: /* Parsing in [...] */
  669. /* Associative arrays */
  670. if (*p[0] == '\'' || *p[0] == '"') {
  671. state = 4;
  672. keyword = *p + 1;
  673. quotechar = *p[0];
  674. type = XF_ST_ARRAY_INDEX_ASSOC;
  675. }
  676. /* Numerical index */
  677. if (*p[0] >= '0' && *p[0] <= '9') {
  678. cc_length = 0;
  679. state = 6;
  680. keyword = *p;
  681. type = XF_ST_ARRAY_INDEX_NUM;
  682. }
  683. /* Numerical index starting with a - */
  684. if (*p[0] == '-') {
  685. state = 9;
  686. keyword = *p;
  687. }
  688. break;
  689. case 9:
  690. /* Numerical index starting with a - */
  691. if (*p[0] >= '0' && *p[0] <= '9') {
  692. state = 6;
  693. type = XF_ST_ARRAY_INDEX_NUM;
  694. }
  695. break;
  696. case 4:
  697. if (*p[0] == quotechar) {
  698. quotechar = 0;
  699. state = 5;
  700. keyword_end = *p;
  701. retval = fetch_zval_from_symbol_table(retval, keyword, keyword_end - keyword, type, current_classname, cc_length, current_ce TSRMLS_CC);
  702. if (current_classname) {
  703. efree(current_classname);
  704. }
  705. current_classname = NULL;
  706. cc_length = 0;
  707. if (retval) {
  708. current_classname = fetch_classname_from_zval(retval, &cc_length, &current_ce TSRMLS_CC);
  709. }
  710. keyword = NULL;
  711. }
  712. break;
  713. case 5:
  714. if (*p[0] == ']') {
  715. state = 1;
  716. }
  717. break;
  718. case 6:
  719. if (*p[0] == ']') {
  720. state = 1;
  721. keyword_end = *p;
  722. retval = fetch_zval_from_symbol_table(retval, keyword, keyword_end - keyword, type, current_classname, cc_length, current_ce TSRMLS_CC);
  723. if (current_classname) {
  724. efree(current_classname);
  725. }
  726. current_classname = NULL;
  727. cc_length = 0;
  728. if (retval) {
  729. current_classname = fetch_classname_from_zval(retval, &cc_length, &current_ce TSRMLS_CC);
  730. }
  731. keyword = NULL;
  732. }
  733. break;
  734. case 7: /* special cases, started with a ":" */
  735. if (*p[0] == ':') {
  736. state = 1;
  737. keyword_end = *p;
  738. if (strncmp(keyword, "::", 2) == 0 && XG(active_fse)->function.class) { /* static class properties */
  739. zend_class_entry *ce = xdebug_fetch_class(XG(active_fse)->function.class, strlen(XG(active_fse)->function.class), ZEND_FETCH_CLASS_SELF TSRMLS_CC);
  740. current_classname = estrdup(STR_NAME_VAL(ce->name));
  741. cc_length = strlen(STR_NAME_VAL(ce->name));
  742. current_ce = ce;
  743. keyword = *p + 1;
  744. type = XF_ST_STATIC_ROOT;
  745. } else {
  746. keyword = NULL;
  747. }
  748. }
  749. break;
  750. }
  751. (*p)++;
  752. }
  753. } while (found < 0);
  754. if (keyword != NULL) {
  755. retval = fetch_zval_from_symbol_table(retval, keyword, *p - keyword, type, current_classname, cc_length, current_ce TSRMLS_CC);
  756. }
  757. if (current_classname) {
  758. efree(current_classname);
  759. }
  760. return retval;
  761. }
  762. char* xdebug_get_property_info(char *mangled_property, int mangled_len, char **property_name, char **class_name)
  763. {
  764. const char *prop_name, *cls_name;
  765. #if PHP_VERSION_ID >= 70000
  766. zend_string *i_mangled = zend_string_init(mangled_property, mangled_len - 1, 0);
  767. zend_unmangle_property_name(i_mangled, &cls_name, &prop_name);
  768. #else
  769. zend_unmangle_property_name(mangled_property, mangled_len, &cls_name, &prop_name);
  770. #endif
  771. *property_name = (char *) xdstrdup(prop_name);
  772. *class_name = cls_name ? xdstrdup(cls_name) : NULL;
  773. #if PHP_VERSION_ID >= 70000
  774. zend_string_release(i_mangled);
  775. #endif
  776. if (*class_name) {
  777. if (*class_name[0] == '*') {
  778. return "protected";
  779. } else {
  780. return "private";
  781. }
  782. } else {
  783. return "public";
  784. }
  785. }
  786. #define XDEBUG_MAX_INT 2147483647
  787. xdebug_var_export_options* xdebug_var_export_options_from_ini(TSRMLS_D)
  788. {
  789. xdebug_var_export_options *options;
  790. options = xdmalloc(sizeof(xdebug_var_export_options));
  791. options->max_children = XG(display_max_children);
  792. options->max_data = XG(display_max_data);
  793. options->max_depth = XG(display_max_depth);
  794. options->show_hidden = 0;
  795. options->show_location = XG(overload_var_dump) > 1;
  796. if (options->max_children == -1 || options->max_children > XDEBUG_MAX_INT) {
  797. options->max_children = XDEBUG_MAX_INT;
  798. } else if (options->max_children < 1) {
  799. options->max_children = 0;
  800. }
  801. if (options->max_data == -1 || options->max_data > XDEBUG_MAX_INT) {
  802. options->max_data = XDEBUG_MAX_INT;
  803. } else if (options->max_data < 1) {
  804. options->max_data = 0;
  805. }
  806. if (options->max_depth == -1 || options->max_depth > 1023) {
  807. options->max_depth = 1023;
  808. } else if (options->max_depth < 1) {
  809. options->max_depth = 0;
  810. }
  811. options->runtime = (xdebug_var_runtime_page*) xdmalloc((options->max_depth + 1) * sizeof(xdebug_var_runtime_page));
  812. options->no_decoration = 0;
  813. return options;
  814. }
  815. xdebug_var_export_options xdebug_var_nolimit_options = { XDEBUG_MAX_INT, XDEBUG_MAX_INT, 1023, 1, 0, NULL, 0 };
  816. xdebug_var_export_options* xdebug_var_get_nolimit_options(TSRMLS_D)
  817. {
  818. return &xdebug_var_nolimit_options;
  819. }
  820. /*****************************************************************************
  821. ** Normal variable printing routines
  822. */
  823. #if PHP_VERSION_ID >= 70000
  824. static int xdebug_array_element_export(zval *zv_nptr, zend_ulong index, zend_string *hash_key, int level, xdebug_str *str, int debug_zval, xdebug_var_export_options *options)
  825. {
  826. zval **zv = &zv_nptr;
  827. #else
  828. static int xdebug_array_element_export(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
  829. {
  830. int level = va_arg(args, int);
  831. xdebug_str *str = va_arg(args, struct xdebug_str*);
  832. int debug_zval = va_arg(args, int);
  833. xdebug_var_export_options *options = va_arg(args, xdebug_var_export_options*);
  834. #endif
  835. if (options->runtime[level].current_element_nr >= options->runtime[level].start_element_nr &&
  836. options->runtime[level].current_element_nr < options->runtime[level].end_element_nr)
  837. {
  838. if (HASH_KEY_IS_NUMERIC(hash_key)) { /* numeric key */
  839. xdebug_str_add(str, xdebug_sprintf("%ld => ", HASH_APPLY_NUMERIC(hash_key)), 1);
  840. } else { /* string key */
  841. SIZETorINT newlen = 0;
  842. char *tmp, *tmp2;
  843. tmp = xdebug_str_to_str((char*) HASH_APPLY_KEY_VAL(hash_key), HASH_APPLY_KEY_LEN(hash_key), "'", 1, "\\'", 2, &newlen);
  844. tmp2 = xdebug_str_to_str(tmp, newlen - 1, "\0", 1, "\\0", 2, &newlen);
  845. if (tmp) {
  846. efree(tmp);
  847. }
  848. xdebug_str_addl(str, "'", 1, 0);
  849. if (tmp2) {
  850. xdebug_str_addl(str, tmp2, newlen, 0);
  851. efree(tmp2);
  852. }
  853. xdebug_str_add(str, "' => ", 0);
  854. }
  855. xdebug_var_export(zv, str, level + 2, debug_zval, options TSRMLS_CC);
  856. xdebug_str_addl(str, ", ", 2, 0);
  857. }
  858. if (options->runtime[level].current_element_nr == options->runtime[level].end_element_nr) {
  859. xdebug_str_addl(str, "..., ", 5, 0);
  860. }
  861. options->runtime[level].current_element_nr++;
  862. return 0;
  863. }
  864. #if PHP_VERSION_ID >= 70000
  865. static int xdebug_object_element_export(zval *zv_nptr, zend_ulong index, zend_string *hash_key, int level, xdebug_str *str, int debug_zval, xdebug_var_export_options *options, char *class_name)
  866. {
  867. zval **zv = &zv_nptr;
  868. #else
  869. static int xdebug_object_element_export(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
  870. {
  871. int level = va_arg(args, int);
  872. xdebug_str *str = va_arg(args, struct xdebug_str*);
  873. int debug_zval = va_arg(args, int);
  874. xdebug_var_export_options *options = va_arg(args, xdebug_var_export_options*);
  875. char *class_name = va_arg(args, char*);
  876. #endif
  877. if (options->runtime[level].current_element_nr >= options->runtime[level].start_element_nr &&
  878. options->runtime[level].current_element_nr < options->runtime[level].end_element_nr)
  879. {
  880. if (!HASH_KEY_IS_NUMERIC(hash_key)) {
  881. char *prop_name, *modifier, *prop_class_name;
  882. modifier = xdebug_get_property_info((char*) HASH_APPLY_KEY_VAL(hash_key), HASH_APPLY_KEY_LEN(hash_key), &prop_name, &prop_class_name);
  883. if (strcmp(modifier, "private") != 0 || strcmp(class_name, prop_class_name) == 0) {
  884. xdebug_str_add(str, xdebug_sprintf("%s $%s = ", modifier, prop_name), 1);
  885. } else {
  886. xdebug_str_add(str, xdebug_sprintf("%s ${%s}:%s = ", modifier, prop_class_name, prop_name), 1);
  887. }
  888. xdfree(prop_name);
  889. xdfree(prop_class_name);
  890. } else {
  891. xdebug_str_add(str, xdebug_sprintf("public $%d = ", HASH_APPLY_NUMERIC(hash_key)), 1);
  892. }
  893. xdebug_var_export(zv, str, level + 2, debug_zval, options TSRMLS_CC);
  894. xdebug_str_addl(str, "; ", 2, 0);
  895. }
  896. if (options->runtime[level].current_element_nr == options->runtime[level].end_element_nr) {
  897. xdebug_str_addl(str, "...; ", 5, 0);
  898. }
  899. options->runtime[level].current_element_nr++;
  900. return 0;
  901. }
  902. void xdebug_var_export(zval **struc, xdebug_str *str, int level, int debug_zval, xdebug_var_export_options *options TSRMLS_DC)
  903. {
  904. HashTable *myht;
  905. char* tmp_str;
  906. int is_temp;
  907. #if PHP_VERSION_ID >= 70000
  908. zend_ulong num;
  909. zend_string *key;
  910. zval *val;
  911. zval *tmpz;
  912. #endif
  913. if (!struc || !(*struc)) {
  914. return;
  915. }
  916. #if PHP_VERSION_ID >= 70000
  917. if (debug_zval) {
  918. if (Z_TYPE_P(*struc) >= IS_STRING && Z_TYPE_P(*struc) != IS_INDIRECT) {
  919. xdebug_str_add(str, xdebug_sprintf("(refcount=%d, is_ref=%d)=", (*struc)->value.counted->gc.refcount, Z_TYPE_P(*struc) == IS_REFERENCE), 1);
  920. } else {
  921. xdebug_str_add(str, "(refcount=0, is_ref=0)=", 0);
  922. }
  923. }
  924. if (Z_TYPE_P(*struc) == IS_REFERENCE) {
  925. tmpz = &((*struc)->value.ref->val);
  926. struc = &tmpz;
  927. }
  928. #else
  929. if (debug_zval) {
  930. xdebug_str_add(str, xdebug_sprintf("(refcount=%d, is_ref=%d)=", (*struc)->refcount__gc, (*struc)->is_ref__gc), 1);
  931. }
  932. #endif
  933. switch (Z_TYPE_P(*struc)) {
  934. #if PHP_VERSION_ID >= 70000
  935. case IS_TRUE:
  936. case IS_FALSE:
  937. xdebug_str_add(str, xdebug_sprintf("%s", Z_TYPE_P(*struc) == IS_TRUE ? "TRUE" : "FALSE"), 1);
  938. break;
  939. #else
  940. case IS_BOOL:
  941. xdebug_str_add(str, xdebug_sprintf("%s", Z_LVAL_P(*struc) ? "TRUE" : "FALSE"), 1);
  942. break;
  943. #endif
  944. case IS_NULL:
  945. xdebug_str_addl(str, "NULL", 4, 0);
  946. break;
  947. case IS_LONG:
  948. xdebug_str_add(str, xdebug_sprintf(XDEBUG_INT_FMT, Z_LVAL_P(*struc)), 1);
  949. break;
  950. case IS_DOUBLE:
  951. xdebug_str_add(str, xdebug_sprintf("%.*G", (int) EG(precision), Z_DVAL_P(*struc)), 1);
  952. break;
  953. case IS_STRING: {
  954. #if PHP_VERSION_ID >= 70000
  955. zend_string *i_string = zend_string_init(Z_STRVAL_P(*struc), Z_STRLEN_P(*struc), 0);
  956. zend_string *tmp_zstr;
  957. tmp_zstr = php_addcslashes(i_string, 0, "'\\\0..\37", 7);
  958. tmp_str = estrndup(tmp_zstr->val, tmp_zstr->len);
  959. zend_string_release(tmp_zstr);
  960. zend_string_release(i_string);
  961. #else
  962. int tmp_len;
  963. tmp_str = php_addcslashes(Z_STRVAL_P(*struc), Z_STRLEN_P(*struc), &tmp_len, 0, "'\\\0..\37", 7 TSRMLS_CC);
  964. #endif
  965. if (options->no_decoration) {
  966. xdebug_str_add(str, tmp_str, 0);
  967. } else if ((size_t) Z_STRLEN_P(*struc) <= (size_t) options->max_data) {
  968. xdebug_str_add(str, xdebug_sprintf("'%s'", tmp_str), 1);
  969. } else {
  970. xdebug_str_addl(str, "'", 1, 0);
  971. xdebug_str_addl(str, xdebug_sprintf("%s", tmp_str), options->max_data, 1);
  972. xdebug_str_addl(str, "...'", 4, 0);
  973. }
  974. efree(tmp_str);
  975. } break;
  976. case IS_ARRAY:
  977. myht = Z_ARRVAL_P(*struc);
  978. if (XDEBUG_APPLY_COUNT(myht) < 1) {
  979. xdebug_str_addl(str, "array (", 7, 0);
  980. if (level <= options->max_depth) {
  981. options->runtime[level].current_element_nr = 0;
  982. options->runtime[level].start_element_nr = 0;
  983. options->runtime[level].end_element_nr = options->max_children;
  984. #if PHP_VERSION_ID >= 70000
  985. ZEND_HASH_INC_APPLY_COUNT(myht);
  986. ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
  987. xdebug_array_element_export(val, num, key, level, str, debug_zval, options);
  988. } ZEND_HASH_FOREACH_END();
  989. ZEND_HASH_DEC_APPLY_COUNT(myht);
  990. #else
  991. zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) xdebug_array_element_export, 4, level, str, debug_zval, options);
  992. #endif
  993. /* Remove the ", " at the end of the string */
  994. if (myht->nNumOfElements > 0) {
  995. xdebug_str_chop(str, 2);
  996. }
  997. } else {
  998. xdebug_str_addl(str, "...", 3, 0);
  999. }
  1000. xdebug_str_addl(str, ")", 1, 0);
  1001. } else {
  1002. xdebug_str_addl(str, "...", 3, 0);
  1003. }
  1004. break;
  1005. case IS_OBJECT:
  1006. myht = xdebug_objdebug_pp(struc, &is_temp TSRMLS_CC);
  1007. if (XDEBUG_APPLY_COUNT(myht) < 1) {
  1008. char *class_name = (char*) STR_NAME_VAL(Z_OBJCE_P(*struc)->name);
  1009. xdebug_str_add(str, xdebug_sprintf("class %s { ", class_name), 1);
  1010. if (level <= options->max_depth) {
  1011. options->runtime[level].current_element_nr = 0;
  1012. options->runtime[level].start_element_nr = 0;
  1013. options->runtime[level].end_element_nr = options->max_children;
  1014. #if PHP_VERSION_ID >= 70000
  1015. ZEND_HASH_INC_APPLY_COUNT(myht);
  1016. ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
  1017. xdebug_object_element_export(val, num, key, level, str, debug_zval, options, class_name);
  1018. } ZEND_HASH_FOREACH_END();
  1019. ZEND_HASH_DEC_APPLY_COUNT(myht);
  1020. #else
  1021. zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) xdebug_object_element_export, 5, level, str, debug_zval, options, class_name);
  1022. #endif
  1023. /* Remove the ", " at the end of the string */
  1024. if (myht->nNumOfElements > 0) {
  1025. xdebug_str_chop(str, 2);
  1026. }
  1027. } else {
  1028. xdebug_str_addl(str, "...", 3, 0);
  1029. }
  1030. xdebug_str_addl(str, " }", 2, 0);
  1031. } else {
  1032. xdebug_str_addl(str, "...", 3, 0);
  1033. }
  1034. if (is_temp) {
  1035. zend_hash_destroy(myht);
  1036. efree(myht);
  1037. }
  1038. break;
  1039. case IS_RESOURCE: {
  1040. char *type_name;
  1041. #if PHP_VERSION_ID >= 70000
  1042. type_name = (char *) zend_rsrc_list_get_rsrc_type(Z_RES_P(*struc) TSRMLS_CC);
  1043. xdebug_str_add(str, xdebug_sprintf("resource(%ld) of type (%s)", Z_RES_P(*struc)->handle, type_name ? type_name : "Unknown"), 1);
  1044. #else
  1045. type_name = (char *) zend_rsrc_list_get_rsrc_type(Z_LVAL_P(*struc) TSRMLS_CC);
  1046. xdebug_str_add(str, xdebug_sprintf("resource(%ld) of type (%s)", Z_LVAL_P(*struc), type_name ? type_name : "Unknown"), 1);
  1047. #endif
  1048. break;
  1049. }
  1050. #if PHP_VERSION_ID >= 70000
  1051. case IS_UNDEF:
  1052. xdebug_str_addl(str, "*uninitialized*", sizeof("*uninitialized*") - 1, 0);
  1053. break;
  1054. #endif
  1055. default:
  1056. xdebug_str_addl(str, "NFC", 3, 0);
  1057. break;
  1058. }
  1059. }
  1060. char* xdebug_get_zval_value(zval *val, int debug_zval, xdebug_var_export_options *options)
  1061. {
  1062. xdebug_str str = XDEBUG_STR_INITIALIZER;
  1063. int default_options = 0;
  1064. TSRMLS_FETCH();
  1065. if (!options) {
  1066. options = xdebug_var_export_options_from_ini(TSRMLS_C);
  1067. default_options = 1;
  1068. }
  1069. xdebug_var_export(&val, (xdebug_str*) &str, 1, debug_zval, options TSRMLS_CC);
  1070. if (default_options) {
  1071. xdfree(options->runtime);
  1072. xdfree(options);
  1073. }
  1074. return str.d;
  1075. }
  1076. static void xdebug_var_synopsis(zval **struc, xdebug_str *str, int level, int debug_zval, xdebug_var_export_options *options TSRMLS_DC)
  1077. {
  1078. HashTable *myht;
  1079. #if PHP_VERSION_ID >= 70000
  1080. zval *tmpz;
  1081. #endif
  1082. if (!struc || !(*struc)) {
  1083. return;
  1084. }
  1085. #if PHP_VERSION_ID >= 70000
  1086. if (debug_zval) {
  1087. if (Z_TYPE_P(*struc) >= IS_STRING && Z_TYPE_P(*struc) != IS_INDIRECT) {
  1088. xdebug_str_add(str, xdebug_sprintf("(refcount=%d, is_ref=%d)=", (*struc)->value.counted->gc.refcount, Z_TYPE_P(*struc) == IS_REFERENCE), 1);
  1089. } else {
  1090. xdebug_str_add(str, "(refcount=0, is_ref=0)=", 0);
  1091. }
  1092. }
  1093. if (Z_TYPE_P(*struc) == IS_REFERENCE) {
  1094. tmpz = &((*struc)->value.ref->val);
  1095. struc = &tmpz;
  1096. }
  1097. #else
  1098. if (debug_zval) {
  1099. xdebug_str_add(str, xdebug_sprintf("(refcount=%d, is_ref=%d)=", (*struc)->refcount__gc, (*struc)->is_ref__gc), 1);
  1100. }
  1101. #endif
  1102. switch (Z_TYPE_P(*struc)) {
  1103. #if PHP_VERSION_ID >= 70000
  1104. case IS_TRUE:
  1105. xdebug_str_addl(str, "true", 4, 0);
  1106. break;
  1107. case IS_FALSE:
  1108. xdebug_str_addl(str, "false", 5, 0);
  1109. break;
  1110. #else
  1111. case IS_BOOL:
  1112. xdebug_str_addl(str, "bool", 4, 0);
  1113. break;
  1114. #endif
  1115. case IS_NULL:
  1116. xdebug_str_addl(str, "null", 4, 0);
  1117. break;
  1118. case IS_LONG:
  1119. xdebug_str_addl(str, "long", 4, 0);
  1120. break;
  1121. case IS_DOUBLE:
  1122. xdebug_str_addl(str, "double", 6, 0);
  1123. break;
  1124. case IS_STRING:
  1125. xdebug_str_add(str, xdebug_sprintf("string(%d)", Z_STRLEN_P(*struc)), 1);
  1126. break;
  1127. case IS_ARRAY:
  1128. myht = Z_ARRVAL_P(*struc);
  1129. xdebug_str_add(str, xdebug_sprintf("array(%d)", myht->nNumOfElements), 1);
  1130. break;
  1131. case IS_OBJECT: {
  1132. xdebug_str_add(str, xdebug_sprintf("class %s", STR_NAME_VAL(Z_OBJCE_P(*struc)->name)), 1);
  1133. break;
  1134. }
  1135. case IS_RESOURCE: {
  1136. char *type_name;
  1137. #if PHP_VERSION_ID >= 70000
  1138. type_name = (char *) zend_rsrc_list_get_rsrc_type(Z_RES_P(*struc) TSRMLS_CC);
  1139. xdebug_str_add(str, xdebug_sprintf("resource(%ld) of type (%s)", Z_RES_P(*struc)->handle, type_name ? type_name : "Unknown"), 1);
  1140. #else
  1141. type_name = (char *) zend_rsrc_list_get_rsrc_type(Z_LVAL_P(*struc) TSRMLS_CC);
  1142. xdebug_str_add(str, xdebug_sprintf("resource(%ld) of type (%s)", Z_LVAL_P(*struc), type_name ? type_name : "Unknown"), 1);
  1143. #endif
  1144. break;
  1145. }
  1146. #if PHP_VERSION_ID >= 70000
  1147. case IS_UNDEF:
  1148. xdebug_str_addl(str, "*uninitialized*", sizeof("*uninitialized*") - 1, 0);
  1149. break;
  1150. #endif
  1151. default:
  1152. xdebug_str_addl(str, "NFC", 3, 0);
  1153. break;
  1154. }
  1155. }
  1156. char* xdebug_get_zval_synopsis(zval *val, int debug_zval, xdebug_var_export_options *options)
  1157. {
  1158. xdebug_str str = XDEBUG_STR_INITIALIZER;
  1159. int default_options = 0;
  1160. TSRMLS_FETCH();
  1161. if (!options) {
  1162. options = xdebug_var_export_options_from_ini(TSRMLS_C);
  1163. default_options = 1;
  1164. }
  1165. xdebug_var_synopsis(&val, (xdebug_str*) &str, 1, debug_zval, options TSRMLS_CC);
  1166. if (default_options) {
  1167. xdfree(options->runtime);
  1168. xdfree(options);
  1169. }
  1170. return str.d;
  1171. }
  1172. /*****************************************************************************
  1173. ** Plain text/ANSI coloured variable printing routines
  1174. */
  1175. #define ANSI_COLOR_POINTER (mode == 1 ? "" : "")
  1176. #define ANSI_COLOR_BOOL (mode == 1 ? "" : "")
  1177. #define ANSI_COLOR_LONG (mode == 1 ? "" : "")
  1178. #define ANSI_COLOR_NULL (mode == 1 ? "" : "")
  1179. #define ANSI_COLOR_DOUBLE (mode == 1 ? "" : "")
  1180. #define ANSI_COLOR_STRING (mode == 1 ? "" : "")
  1181. #define ANSI_COLOR_EMPTY (mode == 1 ? "" : "")
  1182. #define ANSI_COLOR_ARRAY (mode == 1 ? "" : "")
  1183. #define ANSI_COLOR_OBJECT (mode == 1 ? "" : "")
  1184. #define ANSI_COLOR_RESOURCE (mode == 1 ? "" : "")
  1185. #define ANSI_COLOR_MODIFIER (mode == 1 ? "" : "")
  1186. #define ANSI_COLOR_RESET (mode == 1 ? "" : "")
  1187. #define ANSI_COLOR_BOLD (mode == 1 ? "" : "")
  1188. #define ANSI_COLOR_BOLD_OFF (mode == 1 ? "" : "")
  1189. #if PHP_VERSION_ID >= 70000
  1190. static int xdebug_array_element_export_text_ansi(zval *zv_nptr, zend_ulong index, zend_string *hash_key, int level, int mode, xdebug_str *str, int debug_zval, xdebug_var_export_options *options)
  1191. {
  1192. zval **zv = &zv_nptr;
  1193. #else
  1194. static int xdebug_array_element_export_text_ansi(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
  1195. {
  1196. int level = va_arg(args, int);
  1197. int mode = va_arg(args, int);
  1198. xdebug_str *str = va_arg(args, struct xdebug_str*);
  1199. int debug_zval = va_arg(args, int);
  1200. xdebug_var_export_options *options = va_arg(args, xdebug_var_export_options*);
  1201. #endif
  1202. if (options->runtime[level].current_element_nr >= options->runtime[level].start_element_nr &&
  1203. options->runtime[level].current_element_nr < options->runtime[level].end_element_nr)
  1204. {
  1205. xdebug_str_add(str, xdebug_sprintf("%*s", (level * 2), ""), 1);
  1206. if (HASH_KEY_IS_NUMERIC(hash_key)) { /* numeric key */
  1207. xdebug_str_add(str, xdebug_sprintf("[%ld] %s=>%s\n", HASH_APPLY_NUMERIC(hash_key), ANSI_COLOR_POINTER, ANSI_COLOR_RESET), 1);
  1208. } else { /* string key */
  1209. SIZETorINT newlen = 0;
  1210. char *tmp, *tmp2;
  1211. tmp = xdebug_str_to_str((char*) HASH_APPLY_KEY_VAL(hash_key), HASH_APPLY_KEY_LEN(hash_key), "'", 1, "\\'", 2, &newlen);
  1212. tmp2 = xdebug_str_to_str(tmp, newlen - 1, "\0", 1, "\\0", 2, &newlen);
  1213. if (tmp) {
  1214. efree(tmp);
  1215. }
  1216. xdebug_str_addl(str, "'", 1, 0);
  1217. if (tmp2) {
  1218. xdebug_str_addl(str, tmp2, newlen, 0);
  1219. efree(tmp2);
  1220. }
  1221. xdebug_str_add(str, "' =>\n", 0);
  1222. }
  1223. xdebug_var_export_text_ansi(zv, str, mode, level + 1, debug_zval, options TSRMLS_CC);
  1224. }
  1225. if (options->runtime[level].current_element_nr == options->runtime[level].end_element_nr) {
  1226. xdebug_str_add(str, xdebug_sprintf("\n%*s(more elements)...\n", (level * 2), ""), 1);
  1227. }
  1228. options->runtime[level].current_element_nr++;
  1229. return 0;
  1230. }
  1231. #if PHP_VERSION_ID >= 70000
  1232. static int xdebug_object_element_export_text_ansi(zval *zv_nptr, zend_ulong index, zend_string *hash_key, int level, int mode, xdebug_str *str, int debug_zval, xdebug_var_export_options *options)
  1233. {
  1234. zval **zv = &zv_nptr;
  1235. #else
  1236. static int xdebug_object_element_export_text_ansi(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
  1237. {
  1238. int level = va_arg(args, int);
  1239. int mode = va_arg(args, int);
  1240. xdebug_str *str = va_arg(args, struct xdebug_str*);
  1241. int debug_zval = va_arg(args, int);
  1242. xdebug_var_export_options *options = va_arg(args, xdebug_var_export_options*);
  1243. #endif
  1244. if (options->runtime[level].current_element_nr >= options->runtime[level].start_element_nr &&
  1245. options->runtime[level].current_element_nr < options->runtime[level].end_element_nr)
  1246. {
  1247. xdebug_str_add(str, xdebug_sprintf("%*s", (level * 2), ""), 1);
  1248. if (!HASH_KEY_IS_NUMERIC(hash_key)) {
  1249. char *prop_name, *class_name, *modifier;
  1250. modifier = xdebug_get_property_info((char*) HASH_APPLY_KEY_VAL(hash_key), HASH_APPLY_KEY_LEN(hash_key), &prop_name, &class_name);
  1251. xdebug_str_add(str, xdebug_sprintf("%s%s%s%s%s $%s %s=>%s\n",
  1252. ANSI_COLOR_MODIFIER, ANSI_COLOR_BOLD, modifier, ANSI_COLOR_BOLD_OFF, ANSI_COLOR_RESET,
  1253. prop_name, ANSI_COLOR_POINTER, ANSI_COLOR_RESET), 1);
  1254. xdfree(prop_name);
  1255. xdfree(class_name);
  1256. } else {
  1257. xdebug_str_add(str, xdebug_sprintf("%s%spublic%s%s ${%d} %s=>%s\n",
  1258. ANSI_COLOR_MODIFIER, ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF, ANSI_COLOR_RESET,
  1259. HASH_APPLY_NUMERIC(hash_key), ANSI_COLOR_POINTER, ANSI_COLOR_RESET), 1);
  1260. }
  1261. xdebug_var_export_text_ansi(zv, str, mode, level + 1, debug_zval, options TSRMLS_CC);
  1262. }
  1263. if (options->runtime[level].current_element_nr == options->runtime[level].end_element_nr) {
  1264. xdebug_str_add(str, xdebug_sprintf("\n%*s(more elements)...\n", (level * 2), ""), 1);
  1265. }
  1266. options->runtime[level].current_element_nr++;
  1267. return 0;
  1268. }
  1269. void xdebug_var_export_text_ansi(zval **struc, xdebug_str *str, int mode, int level, int debug_zval, xdebug_var_export_options *options TSRMLS_DC)
  1270. {
  1271. HashTable *myht;
  1272. char* tmp_str;
  1273. int tmp_len;
  1274. int is_temp;
  1275. #if PHP_VERSION_ID >= 70000
  1276. zend_ulong num;
  1277. zend_string *key;
  1278. zval *val;
  1279. zval *tmpz;
  1280. #endif
  1281. if (!struc || !(*struc)) {
  1282. return;
  1283. }
  1284. xdebug_str_add(str, xdebug_sprintf("%*s", (level * 2) - 2, ""), 1);
  1285. #if PHP_VERSION_ID >= 70000
  1286. if (debug_zval) {
  1287. if (Z_TYPE_P(*struc) >= IS_STRING && Z_TYPE_P(*struc) != IS_INDIRECT) {
  1288. xdebug_str_add(str, xdebug_sprintf("(refcount=%d, is_ref=%d)=", (*struc)->value.counted->gc.refcount, Z_TYPE_P(*struc) == IS_REFERENCE), 1);
  1289. } else {
  1290. xdebug_str_add(str, "(refcount=0, is_ref=0)=", 0);
  1291. }
  1292. }
  1293. if (Z_TYPE_P(*struc) == IS_REFERENCE) {
  1294. tmpz = &((*struc)->value.ref->val);
  1295. struc = &tmpz;
  1296. }
  1297. #else
  1298. if (debug_zval) {
  1299. xdebug_str_add(str, xdebug_sprintf("(refcount=%d, is_ref=%d)=", (*struc)->refcount__gc, (*struc)->is_ref__gc), 1);
  1300. }
  1301. #endif
  1302. switch (Z_TYPE_P(*struc)) {
  1303. #if PHP_VERSION_ID >= 70000
  1304. case IS_TRUE:
  1305. case IS_FALSE:
  1306. xdebug_str_add(str, xdebug_sprintf("%sbool%s(%s%s%s)", ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF, ANSI_COLOR_BOOL, Z_TYPE_P(*struc) == IS_TRUE ? "true" : "false", ANSI_COLOR_RESET), 1);
  1307. break;
  1308. #else
  1309. case IS_BOOL:
  1310. xdebug_str_add(str, xdebug_sprintf("%sbool%s(%s%s%s)", ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF, ANSI_COLOR_BOOL, Z_LVAL_P(*struc) ? "true" : "false", ANSI_COLOR_RESET), 1);
  1311. break;
  1312. #endif
  1313. case IS_NULL:
  1314. xdebug_str_add(str, xdebug_sprintf("%s%sNULL%s%s", ANSI_COLOR_BOLD, ANSI_COLOR_NULL, ANSI_COLOR_RESET, ANSI_COLOR_BOLD_OFF), 1);
  1315. break;
  1316. case IS_LONG:
  1317. xdebug_str_add(str, xdebug_sprintf("%sint%s(%s" XDEBUG_INT_FMT "%s)", ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF, ANSI_COLOR_LONG, Z_LVAL_P(*struc), ANSI_COLOR_RESET), 1);
  1318. break;
  1319. case IS_DOUBLE:
  1320. xdebug_str_add(str, xdebug_sprintf("%sdouble%s(%s%.*G%s)", ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF, ANSI_COLOR_DOUBLE, (int) EG(precision), Z_DVAL_P(*struc), ANSI_COLOR_RESET), 1);
  1321. break;
  1322. case IS_STRING: {
  1323. char *pattern = (mode == 1) ? "'\\\0..\37" : "\0";
  1324. size_t pattern_len = (mode == 1) ? 7 : 1;
  1325. #if PHP_VERSION_ID >= 70000
  1326. zend_string *i_string = zend_string_init(Z_STRVAL_P(*struc), Z_STRLEN_P(*struc), 0);
  1327. zend_string *tmp_zstr;
  1328. tmp_zstr = php_addcslashes(i_string, 0, pattern, pattern_len);
  1329. tmp_str = estrndup(tmp_zstr->val, tmp_zstr->len);
  1330. tmp_len = tmp_zstr->len;
  1331. zend_string_release(tmp_zstr);
  1332. zend_string_release(i_string);
  1333. #else
  1334. tmp_str = php_addcslashes(Z_STRVAL_P(*struc), Z_STRLEN_P(*struc), &tmp_len, 0, pattern, pattern_len TSRMLS_CC);
  1335. #endif
  1336. if (options->no_decoration) {
  1337. xdebug_str_addl(str, tmp_str, tmp_len, 0);
  1338. } else if ((size_t) Z_STRLEN_P(*struc) <= (size_t) options->max_data) {
  1339. xdebug_str_add(str, xdebug_sprintf("%sstring%s(%s%ld%s) \"%s%s%s\"",
  1340. ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF,
  1341. ANSI_COLOR_LONG, Z_STRLEN_P(*struc), ANSI_COLOR_RESET,
  1342. ANSI_COLOR_STRING, tmp_str, ANSI_COLOR_RESET), 1);
  1343. } else {
  1344. xdebug_str_add(str, xdebug_sprintf("%sstring%s(%s%ld%s) \"%s",
  1345. ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF,
  1346. ANSI_COLOR_LONG, Z_STRLEN_P(*struc), ANSI_COLOR_RESET, ANSI_COLOR_STRING), 1);
  1347. xdebug_str_addl(str, tmp_str, options->max_data, 0);
  1348. xdebug_str_add(str, xdebug_sprintf("%s\"...", ANSI_COLOR_RESET), 1);
  1349. }
  1350. efree(tmp_str);
  1351. } break;
  1352. case IS_ARRAY:
  1353. myht = Z_ARRVAL_P(*struc);
  1354. if (XDEBUG_APPLY_COUNT(myht) < 1) {
  1355. xdebug_str_add(str, xdebug_sprintf("%sarray%s(%s%d%s) {\n", ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF, ANSI_COLOR_LONG, myht->nNumOfElements, ANSI_COLOR_RESET), 1);
  1356. if (level <= options->max_depth) {
  1357. options->runtime[level].current_element_nr = 0;
  1358. options->runtime[level].start_element_nr = 0;
  1359. options->runtime[level].end_element_nr = options->max_children;
  1360. #if PHP_VERSION_ID >= 70000
  1361. ZEND_HASH_INC_APPLY_COUNT(myht);
  1362. ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
  1363. xdebug_array_element_export_text_ansi(val, num, key, level, mode, str, debug_zval, options);
  1364. } ZEND_HASH_FOREACH_END();
  1365. ZEND_HASH_DEC_APPLY_COUNT(myht);
  1366. #else
  1367. zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) xdebug_array_element_export_text_ansi, 5, level, mode, str, debug_zval, options);
  1368. #endif
  1369. } else {
  1370. xdebug_str_add(str, xdebug_sprintf("%*s...\n", (level * 2), ""), 1);
  1371. }
  1372. xdebug_str_add(str, xdebug_sprintf("%*s}", (level * 2) - 2 , ""), 1);
  1373. } else {
  1374. xdebug_str_add(str, xdebug_sprintf("&%sarray%s", ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF), 1);
  1375. }
  1376. break;
  1377. case IS_OBJECT:
  1378. myht = xdebug_objdebug_pp(struc, &is_temp TSRMLS_CC);
  1379. if (myht && XDEBUG_APPLY_COUNT(myht) < 1) {
  1380. xdebug_str_add(str, xdebug_sprintf("%sclass%s %s%s%s#%d (%s%d%s) {\n",
  1381. ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF,
  1382. ANSI_COLOR_OBJECT, STR_NAME_VAL(Z_OBJCE_P(*struc)->name), ANSI_COLOR_RESET,
  1383. Z_OBJ_HANDLE_P(*struc),
  1384. ANSI_COLOR_LONG, myht->nNumOfElements, ANSI_COLOR_RESET), 1);
  1385. if (level <= options->max_depth) {
  1386. options->runtime[level].current_element_nr = 0;
  1387. options->runtime[level].start_element_nr = 0;
  1388. options->runtime[level].end_element_nr = options->max_children;
  1389. #if PHP_VERSION_ID >= 70000
  1390. ZEND_HASH_INC_APPLY_COUNT(myht);
  1391. ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
  1392. xdebug_object_element_export_text_ansi(val, num, key, level, mode, str, debug_zval, options);
  1393. } ZEND_HASH_FOREACH_END();
  1394. ZEND_HASH_DEC_APPLY_COUNT(myht);
  1395. #else
  1396. zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) xdebug_object_element_export_text_ansi, 5, level, mode, str, debug_zval, options);
  1397. #endif
  1398. } else {
  1399. xdebug_str_add(str, xdebug_sprintf("%*s...\n", (level * 2), ""), 1);
  1400. }
  1401. xdebug_str_add(str, xdebug_sprintf("%*s}", (level * 2) - 2, ""), 1);
  1402. } else {
  1403. xdebug_str_add(str, xdebug_sprintf("%*s...\n", (level * 2), ""), 1);
  1404. }
  1405. if (is_temp) {
  1406. zend_hash_destroy(myht);
  1407. efree(myht);
  1408. }
  1409. break;
  1410. case IS_RESOURCE: {
  1411. char *type_name;
  1412. #if PHP_VERSION_ID >= 70000
  1413. type_name = (char *) zend_rsrc_list_get_rsrc_type(Z_RES_P(*struc) TSRMLS_CC);
  1414. xdebug_str_add(str, xdebug_sprintf("%sresource%s(%s%ld%s) of type (%s)",
  1415. ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF,
  1416. ANSI_COLOR_RESOURCE, Z_RES_P(*struc)->handle, ANSI_COLOR_RESET, type_name ? type_name : "Unknown"), 1);
  1417. #else
  1418. type_name = (char *) zend_rsrc_list_get_rsrc_type(Z_LVAL_P(*struc) TSRMLS_CC);
  1419. xdebug_str_add(str, xdebug_sprintf("%sresource%s(%s%ld%s) of type (%s)",
  1420. ANSI_COLOR_BOLD, ANSI_COLOR_BOLD_OFF,
  1421. ANSI_COLOR_RESOURCE, Z_LVAL_P(*struc), ANSI_COLOR_RESET, type_name ? type_name : "Unknown"), 1);
  1422. #endif
  1423. break;
  1424. }
  1425. #if PHP_VERSION_ID >= 70000
  1426. case IS_UNDEF:
  1427. xdebug_str_add(str, xdebug_sprintf("%s*uninitialized*%s", ANSI_COLOR_NULL, ANSI_COLOR_RESET), 0);
  1428. break;
  1429. #endif
  1430. default:
  1431. xdebug_str_add(str, xdebug_sprintf("%sNFC%s", ANSI_COLOR_NULL, ANSI_COLOR_RESET), 0);
  1432. break;
  1433. }
  1434. xdebug_str_addl(str, "\n", 1, 0);
  1435. }
  1436. char* xdebug_get_zval_value_text_ansi(zval *val, int mode, int debug_zval, xdebug_var_export_options *options TSRMLS_DC)
  1437. {
  1438. xdebug_str str = XDEBUG_STR_INITIALIZER;
  1439. int default_options = 0;
  1440. if (!options) {
  1441. options = xdebug_var_export_options_from_ini(TSRMLS_C);
  1442. default_options = 1;
  1443. }
  1444. if (options->show_location && !debug_zval) {
  1445. xdebug_str_add(&str, xdebug_sprintf("%s%s%s:%s%d%…

Large files files are truncated, but you can click here to view the full file