PageRenderTime 45ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/mysqlnd/mysqlnd_bt.c

https://github.com/Doap/php-src
C | 483 lines | 365 code | 57 blank | 61 comment | 55 complexity | d96edce46acf6ebbecc238c3d8aa7c08 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2006-2011 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. /* Follows code borrowed from zend_builtin_functions.c because the functions there are static */
  23. #if MYSQLND_UNICODE
  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_USTRL(val, vallen) \
  36. { \
  37. zval tmp, copy; \
  38. int use_copy; \
  39. ZVAL_UNICODEL(&tmp, val, vallen, 1); \
  40. zend_make_printable_zval(&tmp, &copy, &use_copy); \
  41. TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
  42. zval_dtor(&copy); \
  43. zval_dtor(&tmp); \
  44. }
  45. #define TRACE_APPEND_ZVAL(zv) \
  46. if (Z_TYPE_P((zv)) == IS_UNICODE) { \
  47. zval copy; \
  48. int use_copy; \
  49. zend_make_printable_zval((zv), &copy, &use_copy); \
  50. TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
  51. zval_dtor(&copy); \
  52. } else { \
  53. TRACE_APPEND_STRL(Z_STRVAL_P((zv)), Z_STRLEN_P((zv))); \
  54. }
  55. #define TRACE_APPEND_STR(val) \
  56. TRACE_APPEND_STRL(val, sizeof(val)-1)
  57. #define TRACE_APPEND_KEY(key) \
  58. if (zend_ascii_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
  59. if (Z_TYPE_PP(tmp) == IS_UNICODE) { \
  60. zval copy; \
  61. int use_copy; \
  62. zend_make_printable_zval(*tmp, &copy, &use_copy); \
  63. TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
  64. zval_dtor(&copy); \
  65. } else { \
  66. TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \
  67. } \
  68. }
  69. /* }}} */
  70. /* {{{ mysqlnd_build_trace_args */
  71. static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
  72. {
  73. char **str;
  74. int *len;
  75. str = va_arg(args, char**);
  76. len = va_arg(args, int*);
  77. /* the trivial way would be to do:
  78. * conver_to_string_ex(arg);
  79. * append it and kill the now tmp arg.
  80. * but that could cause some E_NOTICE and also damn long lines.
  81. */
  82. switch (Z_TYPE_PP(arg)) {
  83. case IS_NULL:
  84. TRACE_APPEND_STR("NULL, ");
  85. break;
  86. case IS_STRING: {
  87. int l_added;
  88. TRACE_APPEND_CHR('\'');
  89. if (Z_STRLEN_PP(arg) > 15) {
  90. TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
  91. TRACE_APPEND_STR("...', ");
  92. l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
  93. } else {
  94. l_added = Z_STRLEN_PP(arg);
  95. TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
  96. TRACE_APPEND_STR("', ");
  97. l_added += 3 + 1;
  98. }
  99. while (--l_added) {
  100. if ((unsigned char)(*str)[*len - l_added] < 32) {
  101. (*str)[*len - l_added] = '?';
  102. }
  103. }
  104. break;
  105. }
  106. case IS_UNICODE: {
  107. int l_added;
  108. /*
  109. * We do not want to apply current error mode here, since
  110. * zend_make_printable_zval() uses output encoding converter.
  111. * Temporarily set output encoding converter to escape offending
  112. * chars with \uXXXX notation.
  113. */
  114. zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, ZEND_CONV_ERROR_ESCAPE_JAVA);
  115. TRACE_APPEND_CHR('\'');
  116. if (Z_USTRLEN_PP(arg) > 15) {
  117. TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), 15);
  118. TRACE_APPEND_STR("...', ");
  119. l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
  120. } else {
  121. l_added = Z_USTRLEN_PP(arg);
  122. TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), l_added);
  123. TRACE_APPEND_STR("', ");
  124. l_added += 3 + 1;
  125. }
  126. /*
  127. * Reset output encoding converter error mode.
  128. */
  129. zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, UG(from_error_mode));
  130. while (--l_added) {
  131. if ((unsigned char)(*str)[*len - l_added] < 32) {
  132. (*str)[*len - l_added] = '?';
  133. }
  134. }
  135. break;
  136. }
  137. case IS_BOOL:
  138. if (Z_LVAL_PP(arg)) {
  139. TRACE_APPEND_STR("true, ");
  140. } else {
  141. TRACE_APPEND_STR("false, ");
  142. }
  143. break;
  144. case IS_RESOURCE:
  145. TRACE_APPEND_STR("Resource id #");
  146. /* break; */
  147. case IS_LONG: {
  148. long lval = Z_LVAL_PP(arg);
  149. char s_tmp[MAX_LENGTH_OF_LONG + 1];
  150. int l_tmp = zend_sprintf(s_tmp, "%ld", lval); /* SAFE */
  151. TRACE_APPEND_STRL(s_tmp, l_tmp);
  152. TRACE_APPEND_STR(", ");
  153. break;
  154. }
  155. case IS_DOUBLE: {
  156. double dval = Z_DVAL_PP(arg);
  157. char *s_tmp;
  158. int l_tmp;
  159. s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
  160. l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval); /* SAFE */
  161. TRACE_APPEND_STRL(s_tmp, l_tmp);
  162. /* %G already handles removing trailing zeros from the fractional part, yay */
  163. efree(s_tmp);
  164. TRACE_APPEND_STR(", ");
  165. break;
  166. }
  167. case IS_ARRAY:
  168. TRACE_APPEND_STR("Array, ");
  169. break;
  170. case IS_OBJECT: {
  171. zval tmp;
  172. zstr class_name;
  173. zend_uint class_name_len;
  174. int dup;
  175. TRACE_APPEND_STR("Object(");
  176. dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
  177. ZVAL_UNICODEL(&tmp, class_name.u, class_name_len, 1);
  178. convert_to_string_with_converter(&tmp, ZEND_U_CONVERTER(UG(output_encoding_conv)));
  179. TRACE_APPEND_STRL(Z_STRVAL(tmp), Z_STRLEN(tmp));
  180. zval_dtor(&tmp);
  181. if(!dup) {
  182. efree(class_name.v);
  183. }
  184. TRACE_APPEND_STR("), ");
  185. break;
  186. }
  187. default:
  188. break;
  189. }
  190. return ZEND_HASH_APPLY_KEEP;
  191. }
  192. /* }}} */
  193. static int mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
  194. {
  195. char *s_tmp, **str;
  196. int *len, *num;
  197. long line;
  198. HashTable *ht = Z_ARRVAL_PP(frame);
  199. zval **file, **tmp;
  200. uint * level;
  201. level = va_arg(args, uint *);
  202. str = va_arg(args, char**);
  203. len = va_arg(args, int*);
  204. num = va_arg(args, int*);
  205. if (!*level) {
  206. return ZEND_HASH_APPLY_KEEP;
  207. }
  208. --*level;
  209. s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
  210. sprintf(s_tmp, "#%d ", (*num)++);
  211. TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
  212. efree(s_tmp);
  213. if (zend_ascii_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
  214. if (zend_ascii_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
  215. line = Z_LVAL_PP(tmp);
  216. } else {
  217. line = 0;
  218. }
  219. TRACE_APPEND_ZVAL(*file);
  220. s_tmp = emalloc(MAX_LENGTH_OF_LONG + 2 + 1);
  221. sprintf(s_tmp, "(%ld): ", line);
  222. TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
  223. efree(s_tmp);
  224. } else {
  225. TRACE_APPEND_STR("[internal function]: ");
  226. }
  227. TRACE_APPEND_KEY("class");
  228. TRACE_APPEND_KEY("type");
  229. TRACE_APPEND_KEY("function");
  230. TRACE_APPEND_CHR('(');
  231. if (zend_ascii_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
  232. int last_len = *len;
  233. zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
  234. if (last_len != *len) {
  235. *len -= 2; /* remove last ', ' */
  236. }
  237. }
  238. TRACE_APPEND_STR(")\n");
  239. return ZEND_HASH_APPLY_KEEP;
  240. }
  241. /* }}} */
  242. #else /* PHP 5*/
  243. /* {{{ gettraceasstring() macros */
  244. #define TRACE_APPEND_CHR(chr) \
  245. *str = (char*)erealloc(*str, *len + 1 + 1); \
  246. (*str)[(*len)++] = chr
  247. #define TRACE_APPEND_STRL(val, vallen) \
  248. { \
  249. int l = vallen; \
  250. *str = (char*)erealloc(*str, *len + l + 1); \
  251. memcpy((*str) + *len, val, l); \
  252. *len += l; \
  253. }
  254. #define TRACE_APPEND_STR(val) \
  255. TRACE_APPEND_STRL(val, sizeof(val)-1)
  256. #define TRACE_APPEND_KEY(key) \
  257. if (zend_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
  258. TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \
  259. }
  260. /* }}} */
  261. static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
  262. {
  263. char **str;
  264. int *len;
  265. str = va_arg(args, char**);
  266. len = va_arg(args, int*);
  267. /* the trivial way would be to do:
  268. * conver_to_string_ex(arg);
  269. * append it and kill the now tmp arg.
  270. * but that could cause some E_NOTICE and also damn long lines.
  271. */
  272. switch (Z_TYPE_PP(arg)) {
  273. case IS_NULL:
  274. TRACE_APPEND_STR("NULL, ");
  275. break;
  276. case IS_STRING: {
  277. int l_added;
  278. TRACE_APPEND_CHR('\'');
  279. if (Z_STRLEN_PP(arg) > 15) {
  280. TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
  281. TRACE_APPEND_STR("...', ");
  282. l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
  283. } else {
  284. l_added = Z_STRLEN_PP(arg);
  285. TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
  286. TRACE_APPEND_STR("', ");
  287. l_added += 3 + 1;
  288. }
  289. while (--l_added) {
  290. if ((*str)[*len - l_added] < 32) {
  291. (*str)[*len - l_added] = '?';
  292. }
  293. }
  294. break;
  295. }
  296. case IS_BOOL:
  297. if (Z_LVAL_PP(arg)) {
  298. TRACE_APPEND_STR("true, ");
  299. } else {
  300. TRACE_APPEND_STR("false, ");
  301. }
  302. break;
  303. case IS_RESOURCE:
  304. TRACE_APPEND_STR("Resource id #");
  305. /* break; */
  306. case IS_LONG: {
  307. long lval = Z_LVAL_PP(arg);
  308. char s_tmp[MAX_LENGTH_OF_LONG + 1];
  309. int l_tmp = zend_sprintf(s_tmp, "%ld", lval); /* SAFE */
  310. TRACE_APPEND_STRL(s_tmp, l_tmp);
  311. TRACE_APPEND_STR(", ");
  312. break;
  313. }
  314. case IS_DOUBLE: {
  315. double dval = Z_DVAL_PP(arg);
  316. char *s_tmp;
  317. int l_tmp;
  318. s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
  319. l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval); /* SAFE */
  320. TRACE_APPEND_STRL(s_tmp, l_tmp);
  321. /* %G already handles removing trailing zeros from the fractional part, yay */
  322. efree(s_tmp);
  323. TRACE_APPEND_STR(", ");
  324. break;
  325. }
  326. case IS_ARRAY:
  327. TRACE_APPEND_STR("Array, ");
  328. break;
  329. case IS_OBJECT: {
  330. char *class_name;
  331. zend_uint class_name_len;
  332. int dupl;
  333. TRACE_APPEND_STR("Object(");
  334. dupl = zend_get_object_classname(*arg, (const char **)&class_name, &class_name_len TSRMLS_CC);
  335. TRACE_APPEND_STRL(class_name, class_name_len);
  336. if (!dupl) {
  337. efree(class_name);
  338. }
  339. TRACE_APPEND_STR("), ");
  340. break;
  341. }
  342. default:
  343. break;
  344. }
  345. return ZEND_HASH_APPLY_KEEP;
  346. }
  347. /* }}} */
  348. static int mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
  349. {
  350. char *s_tmp, **str;
  351. int *len, *num;
  352. long line;
  353. HashTable *ht = Z_ARRVAL_PP(frame);
  354. zval **file, **tmp;
  355. uint * level;
  356. level = va_arg(args, uint *);
  357. str = va_arg(args, char**);
  358. len = va_arg(args, int*);
  359. num = va_arg(args, int*);
  360. if (!*level) {
  361. return ZEND_HASH_APPLY_KEEP;
  362. }
  363. --*level;
  364. s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
  365. sprintf(s_tmp, "#%d ", (*num)++);
  366. TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
  367. efree(s_tmp);
  368. if (zend_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
  369. if (zend_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
  370. line = Z_LVAL_PP(tmp);
  371. } else {
  372. line = 0;
  373. }
  374. s_tmp = emalloc(Z_STRLEN_PP(file) + MAX_LENGTH_OF_LONG + 4 + 1);
  375. sprintf(s_tmp, "%s(%ld): ", Z_STRVAL_PP(file), line);
  376. TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
  377. efree(s_tmp);
  378. } else {
  379. TRACE_APPEND_STR("[internal function]: ");
  380. }
  381. TRACE_APPEND_KEY("class");
  382. TRACE_APPEND_KEY("type");
  383. TRACE_APPEND_KEY("function");
  384. TRACE_APPEND_CHR('(');
  385. if (zend_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
  386. int last_len = *len;
  387. zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
  388. if (last_len != *len) {
  389. *len -= 2; /* remove last ', ' */
  390. }
  391. }
  392. TRACE_APPEND_STR(")\n");
  393. return ZEND_HASH_APPLY_KEEP;
  394. }
  395. /* }}} */
  396. #endif
  397. PHPAPI char * mysqlnd_get_backtrace(uint max_levels, size_t * length TSRMLS_DC)
  398. {
  399. zval *trace;
  400. char *res = estrdup(""), **str = &res, *s_tmp;
  401. int res_len = 0, *len = &res_len, num = 0;
  402. if (max_levels == 0) {
  403. max_levels = 99999;
  404. }
  405. MAKE_STD_ZVAL(trace);
  406. zend_fetch_debug_backtrace(trace, 0, 0, 0 TSRMLS_CC);
  407. 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);
  408. zval_ptr_dtor(&trace);
  409. if (max_levels) {
  410. s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1);
  411. sprintf(s_tmp, "#%d {main}", num);
  412. TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
  413. efree(s_tmp);
  414. }
  415. res[res_len] = '\0';
  416. *length = res_len;
  417. return res;
  418. }
  419. /*
  420. * Local variables:
  421. * tab-width: 4
  422. * c-basic-offset: 4
  423. * End:
  424. * vim600: noet sw=4 ts=4 fdm=marker
  425. * vim<600: noet sw=4 ts=4
  426. */