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
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