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