mysqlnd_bt.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2006-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: Georg Richter <georg@mysql.com> |
  16. | Andrey Hristov <andrey@mysql.com> |
  17. | Ulf Wendel <uwendel@mysql.com> |
  18. +----------------------------------------------------------------------+
  19. */
  20. /* $Id: mysqlnd_debug.c 309303 2011-03-16 12:42:59Z andrey $ */
  21. #include "php.h"
  22. #include "Zend/zend_builtin_functions.h"
  23. /* Follows code borrowed from zend_builtin_functions.c because the functions there are static */
  24. /* {{{ gettraceasstring() macros */
  25. #define TRACE_APPEND_CHR(chr) \
  26. *str = (char*)erealloc(*str, *len + 1 + 1); \
  27. (*str)[(*len)++] = chr
  28. #define TRACE_APPEND_STRL(val, vallen) \
  29. { \
  30. int l = vallen; \
  31. *str = (char*)erealloc(*str, *len + l + 1); \
  32. memcpy((*str) + *len, val, l); \
  33. *len += l; \
  34. }
  35. #define TRACE_APPEND_STR(val) \
  36. TRACE_APPEND_STRL(val, sizeof(val)-1)
  37. #define TRACE_APPEND_KEY(key) \
  38. if (zend_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
  39. TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \
  40. }
  41. /* }}} */
  42. static int
  43. mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
  44. {
  45. char **str;
  46. int *len;
  47. str = va_arg(args, char**);
  48. len = va_arg(args, int*);
  49. /* the trivial way would be to do:
  50. * conver_to_string_ex(arg);
  51. * append it and kill the now tmp arg.
  52. * but that could cause some E_NOTICE and also damn long lines.
  53. */
  54. switch (Z_TYPE_PP(arg)) {
  55. case IS_NULL:
  56. TRACE_APPEND_STR("NULL, ");
  57. break;
  58. case IS_STRING: {
  59. int l_added;
  60. TRACE_APPEND_CHR('\'');
  61. if (Z_STRLEN_PP(arg) > 15) {
  62. TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
  63. TRACE_APPEND_STR("...', ");
  64. l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
  65. } else {
  66. l_added = Z_STRLEN_PP(arg);
  67. TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
  68. TRACE_APPEND_STR("', ");
  69. l_added += 3 + 1;
  70. }
  71. while (--l_added) {
  72. if ((*str)[*len - l_added] < 32) {
  73. (*str)[*len - l_added] = '?';
  74. }
  75. }
  76. break;
  77. }
  78. case IS_BOOL:
  79. if (Z_LVAL_PP(arg)) {
  80. TRACE_APPEND_STR("true, ");
  81. } else {
  82. TRACE_APPEND_STR("false, ");
  83. }
  84. break;
  85. case IS_RESOURCE:
  86. TRACE_APPEND_STR("Resource id #");
  87. /* break; */
  88. case IS_LONG: {
  89. long lval = Z_LVAL_PP(arg);
  90. char s_tmp[MAX_LENGTH_OF_LONG + 1];
  91. int l_tmp = zend_sprintf(s_tmp, "%ld", lval); /* SAFE */
  92. TRACE_APPEND_STRL(s_tmp, l_tmp);
  93. TRACE_APPEND_STR(", ");
  94. break;
  95. }
  96. case IS_DOUBLE: {
  97. double dval = Z_DVAL_PP(arg);
  98. char *s_tmp;
  99. int l_tmp;
  100. s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
  101. l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval); /* SAFE */
  102. TRACE_APPEND_STRL(s_tmp, l_tmp);
  103. /* %G already handles removing trailing zeros from the fractional part, yay */
  104. efree(s_tmp);
  105. TRACE_APPEND_STR(", ");
  106. break;
  107. }
  108. case IS_ARRAY:
  109. TRACE_APPEND_STR("Array, ");
  110. break;
  111. case IS_OBJECT: {
  112. char *class_name;
  113. zend_uint class_name_len;
  114. int dupl;
  115. TRACE_APPEND_STR("Object(");
  116. dupl = zend_get_object_classname(*arg, (const char **)&class_name, &class_name_len TSRMLS_CC);
  117. TRACE_APPEND_STRL(class_name, class_name_len);
  118. if (!dupl) {
  119. efree(class_name);
  120. }
  121. TRACE_APPEND_STR("), ");
  122. break;
  123. }
  124. default:
  125. break;
  126. }
  127. return ZEND_HASH_APPLY_KEEP;
  128. }
  129. /* }}} */
  130. static int
  131. mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
  132. {
  133. char *s_tmp, **str;
  134. int *len, *num;
  135. long line;
  136. HashTable *ht = Z_ARRVAL_PP(frame);
  137. zval **file, **tmp;
  138. uint * level;
  139. level = va_arg(args, uint *);
  140. str = va_arg(args, char**);
  141. len = va_arg(args, int*);
  142. num = va_arg(args, int*);
  143. if (!*level) {
  144. return ZEND_HASH_APPLY_KEEP;
  145. }
  146. --*level;
  147. s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
  148. sprintf(s_tmp, "#%d ", (*num)++);
  149. TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
  150. efree(s_tmp);
  151. if (zend_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
  152. if (zend_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
  153. line = Z_LVAL_PP(tmp);
  154. } else {
  155. line = 0;
  156. }
  157. s_tmp = emalloc(Z_STRLEN_PP(file) + MAX_LENGTH_OF_LONG + 4 + 1);
  158. sprintf(s_tmp, "%s(%ld): ", Z_STRVAL_PP(file), line);
  159. TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
  160. efree(s_tmp);
  161. } else {
  162. TRACE_APPEND_STR("[internal function]: ");
  163. }
  164. TRACE_APPEND_KEY("class");
  165. TRACE_APPEND_KEY("type");
  166. TRACE_APPEND_KEY("function");
  167. TRACE_APPEND_CHR('(');
  168. if (zend_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
  169. int last_len = *len;
  170. zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
  171. if (last_len != *len) {
  172. *len -= 2; /* remove last ', ' */
  173. }
  174. }
  175. TRACE_APPEND_STR(")\n");
  176. return ZEND_HASH_APPLY_KEEP;
  177. }
  178. /* }}} */
  179. PHPAPI char *
  180. mysqlnd_get_backtrace(uint max_levels, size_t * length TSRMLS_DC)
  181. {
  182. zval *trace;
  183. char *res = estrdup(""), **str = &res, *s_tmp;
  184. int res_len = 0, *len = &res_len, num = 0;
  185. if (max_levels == 0) {
  186. max_levels = 99999;
  187. }
  188. MAKE_STD_ZVAL(trace);
  189. zend_fetch_debug_backtrace(trace, 0, 0, 0 TSRMLS_CC);
  190. zend_hash_apply_with_arguments(Z_ARRVAL_P(trace) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_string, 4, &max_levels, str, len, &num);
  191. zval_ptr_dtor(&trace);
  192. if (max_levels) {
  193. s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1);
  194. sprintf(s_tmp, "#%d {main}", num);
  195. TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
  196. efree(s_tmp);
  197. }
  198. res[res_len] = '\0';
  199. *length = res_len;
  200. return res;
  201. }
  202. /*
  203. * Local variables:
  204. * tab-width: 4
  205. * c-basic-offset: 4
  206. * End:
  207. * vim600: noet sw=4 ts=4 fdm=marker
  208. * vim<600: noet sw=4 ts=4
  209. */