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