Author: ahristov
Date: 2007-09-24 15:10:13 +0200 (Mon, 24 Sep 2007)
New Revision: 1058
Modified:
trunk/mysqlnd/mysqlnd_debug.c
trunk/mysqlnd/mysqlnd_debug.h
trunk/mysqlnd/mysqlnd_result.c
Log:
Add backtrace extraction. Still undecided where to dump it,
probably additional dump file, a mysqlnd setting?
Modified: trunk/mysqlnd/mysqlnd_debug.c
===================================================================
--- trunk/mysqlnd/mysqlnd_debug.c 2007-09-24 13:08:05 UTC (rev 1057)
+++ trunk/mysqlnd/mysqlnd_debug.c 2007-09-24 13:10:13 UTC (rev 1058)
@@ -27,6 +27,7 @@
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_palloc.h"
#include "mysqlnd_statistics.h"
+#include "zend_builtin_functions.h"
static const char * const mysqlnd_debug_default_trace_file = "/tmp/mysqlnd.trace";
@@ -395,7 +396,6 @@
static void
MYSQLND_METHOD(mysqlnd_debug, set_mode)(MYSQLND_DEBUG * self, const char * const mode)
{
- MYSQLND_ZTS(self);
size_t mode_len = strlen(mode), i;
enum mysqlnd_debug_parser_state state = PARSER_WAIT_MODIFIER;
@@ -888,6 +888,271 @@
/* }}} */
+/* {{{ gettraceasstring() macros */
+#define TRACE_APPEND_CHR(chr) \
+ *str = (char*)erealloc(*str, *len + 1 + 1); \
+ (*str)[(*len)++] = chr
+
+#define TRACE_APPEND_STRL(val, vallen) \
+ { \
+ int l = vallen; \
+ *str = (char*)erealloc(*str, *len + l + 1); \
+ memcpy((*str) + *len, val, l); \
+ *len += l; \
+ }
+
+#define TRACE_APPEND_USTRL(val, vallen) \
+ { \
+ zval tmp, copy; \
+ int use_copy; \
+ ZVAL_UNICODEL(&tmp, val, vallen, 1); \
+ zend_make_printable_zval(&tmp, ©, &use_copy); \
+ TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
+ zval_dtor(©); \
+ zval_dtor(&tmp); \
+ }
+
+#define TRACE_APPEND_ZVAL(zv) \
+ if (Z_TYPE_P((zv)) == IS_UNICODE) { \
+ zval copy; \
+ int use_copy; \
+ zend_make_printable_zval((zv), ©, &use_copy); \
+ TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
+ zval_dtor(©); \
+ } else { \
+ TRACE_APPEND_STRL(Z_STRVAL_P((zv)), Z_STRLEN_P((zv))); \
+ }
+
+#define TRACE_APPEND_STR(val) \
+ TRACE_APPEND_STRL(val, sizeof(val)-1)
+
+#define TRACE_APPEND_KEY(key) \
+ if (zend_ascii_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
+ if (Z_TYPE_PP(tmp) == IS_UNICODE) { \
+ zval copy; \
+ int use_copy; \
+ zend_make_printable_zval(*tmp, ©, &use_copy); \
+ TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
+ zval_dtor(©); \
+ } else { \
+ TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \
+ } \
+ }
+/* }}} */
+
+
+/* {{{ mysqlnd_build_trace_args */
+static int mysqlnd_build_trace_args(zval **arg, int num_args, va_list args, zend_hash_key
*hash_key)
+{
+ char **str;
+ int *len;
+
+ str = va_arg(args, char**);
+ len = va_arg(args, int*);
+
+ /* the trivial way would be to do:
+ * conver_to_string_ex(arg);
+ * append it and kill the now tmp arg.
+ * but that could cause some E_NOTICE and also damn long lines.
+ */
+
+ switch (Z_TYPE_PP(arg)) {
+ case IS_NULL:
+ TRACE_APPEND_STR("NULL, ");
+ break;
+ case IS_STRING: {
+ int l_added;
+ TRACE_APPEND_CHR('\'');
+ if (Z_STRLEN_PP(arg) > 15) {
+ TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
+ TRACE_APPEND_STR("...', ");
+ l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
+ } else {
+ l_added = Z_STRLEN_PP(arg);
+ TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
+ TRACE_APPEND_STR("', ");
+ l_added += 3 + 1;
+ }
+ while (--l_added) {
+ if ((unsigned char)(*str)[*len - l_added] < 32) {
+ (*str)[*len - l_added] = '?';
+ }
+ }
+ break;
+ }
+ case IS_UNICODE: {
+ int l_added;
+ TSRMLS_FETCH();
+
+ /*
+ * We do not want to apply current error mode here, since
+ * zend_make_printable_zval() uses output encoding converter.
+ * Temporarily set output encoding converter to escape offending
+ * chars with \uXXXX notation.
+ */
+ zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)),
ZEND_FROM_UNICODE, ZEND_CONV_ERROR_ESCAPE_JAVA);
+ TRACE_APPEND_CHR('\'');
+ if (Z_USTRLEN_PP(arg) > 15) {
+ TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), 15);
+ TRACE_APPEND_STR("...', ");
+ l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
+ } else {
+ l_added = Z_USTRLEN_PP(arg);
+ TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), l_added);
+ TRACE_APPEND_STR("', ");
+ l_added += 3 + 1;
+ }
+ /*
+ * Reset output encoding converter error mode.
+ */
+ zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)),
ZEND_FROM_UNICODE, UG(from_error_mode));
+ while (--l_added) {
+ if ((unsigned char)(*str)[*len - l_added] < 32) {
+ (*str)[*len - l_added] = '?';
+ }
+ }
+ break;
+ }
+ case IS_BOOL:
+ if (Z_LVAL_PP(arg)) {
+ TRACE_APPEND_STR("true, ");
+ } else {
+ TRACE_APPEND_STR("false, ");
+ }
+ break;
+ case IS_RESOURCE:
+ TRACE_APPEND_STR("Resource id #");
+ /* break; */
+ case IS_LONG: {
+ long lval = Z_LVAL_PP(arg);
+ char s_tmp[MAX_LENGTH_OF_LONG + 1];
+ int l_tmp = zend_sprintf(s_tmp, "%ld", lval); /* SAFE */
+ TRACE_APPEND_STRL(s_tmp, l_tmp);
+ TRACE_APPEND_STR(", ");
+ break;
+ }
+ case IS_DOUBLE: {
+ double dval = Z_DVAL_PP(arg);
+ char *s_tmp;
+ int l_tmp;
+ TSRMLS_FETCH();
+
+ s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
+ l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval); /* SAFE */
+ TRACE_APPEND_STRL(s_tmp, l_tmp);
+ /* %G already handles removing trailing zeros from the fractional part, yay */
+ efree(s_tmp);
+ TRACE_APPEND_STR(", ");
+ break;
+ }
+ case IS_ARRAY:
+ TRACE_APPEND_STR("Array, ");
+ break;
+ case IS_OBJECT: {
+ zstr class_name;
+ zend_uint class_name_len;
+ int dup;
+ TSRMLS_FETCH();
+
+ TRACE_APPEND_STR("Object(");
+
+ dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
+
+ if (UG(unicode)) {
+ zval tmp;
+
+ ZVAL_UNICODEL(&tmp, class_name.u, class_name_len, 1);
+ convert_to_string_with_converter(&tmp,
ZEND_U_CONVERTER(UG(output_encoding_conv)));
+ TRACE_APPEND_STRL(Z_STRVAL(tmp), Z_STRLEN(tmp));
+ zval_dtor(&tmp);
+ } else {
+ TRACE_APPEND_STRL(class_name.s, class_name_len);
+ }
+ if(!dup) {
+ efree(class_name.v);
+ }
+
+ TRACE_APPEND_STR("), ");
+ break;
+ }
+ default:
+ break;
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_build_trace_string */
+static int mysqlnd_build_trace_string(zval **frame, int num_args, va_list args,
zend_hash_key *hash_key)
+{
+ char *s_tmp, **str;
+ int *len, *num;
+ long line;
+ HashTable *ht = Z_ARRVAL_PP(frame);
+ zval **file, **tmp;
+
+ str = va_arg(args, char**);
+ len = va_arg(args, int*);
+ num = va_arg(args, int*);
+
+ s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
+ sprintf(s_tmp, "#%d ", (*num)++);
+ TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+ efree(s_tmp);
+ if (zend_ascii_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
+ if (zend_ascii_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
+ line = Z_LVAL_PP(tmp);
+ } else {
+ line = 0;
+ }
+ TRACE_APPEND_ZVAL(*file);
+ s_tmp = emalloc(MAX_LENGTH_OF_LONG + 2 + 1);
+ sprintf(s_tmp, "(%ld): ", line);
+ TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+ efree(s_tmp);
+ } else {
+ TRACE_APPEND_STR("[internal function]: ");
+ }
+ TRACE_APPEND_KEY("class");
+ TRACE_APPEND_KEY("type");
+ TRACE_APPEND_KEY("function");
+ TRACE_APPEND_CHR('(');
+ if (zend_ascii_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
+ int last_len = *len;
+ zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp),
(apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
+ if (last_len != *len) {
+ *len -= 2; /* remove last ', ' */
+ }
+ }
+ TRACE_APPEND_STR(")\n");
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+
+char * mysqlnd_get_backtrace(TSRMLS_D)
+{
+ zval *trace;
+ char *res = estrdup(""), **str = &res, *s_tmp;
+ int res_len = 0, *len = &res_len, num = 0;
+
+ MAKE_STD_ZVAL(trace);
+ zend_fetch_debug_backtrace(trace, 0, 0 TSRMLS_CC);
+
+ zend_hash_apply_with_arguments(Z_ARRVAL_P(trace),
(apply_func_args_t)mysqlnd_build_trace_string, 3, str, len, &num);
+ zval_ptr_dtor(&trace);
+
+ s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1);
+ sprintf(s_tmp, "#%d {main}", num);
+ TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+ efree(s_tmp);
+
+ res[res_len] = '\0';
+
+ return res;
+}
+
/*
* Local variables:
* tab-width: 4
Modified: trunk/mysqlnd/mysqlnd_debug.h
===================================================================
--- trunk/mysqlnd/mysqlnd_debug.h 2007-09-24 13:08:05 UTC (rev 1057)
+++ trunk/mysqlnd/mysqlnd_debug.h 2007-09-24 13:10:13 UTC (rev 1058)
@@ -76,6 +76,8 @@
void * _mysqlnd_realloc(void *ptr, size_t new_size MYSQLND_MEM_D);
void _mysqlnd_free(void *ptr MYSQLND_MEM_D);
+char * mysqlnd_get_backtrace(TSRMLS_D);
+
#if PHP_DEBUG && !defined(PHP_WIN32)
#define DBG_INF(msg) do { if (dbg_skip_trace == FALSE)
MYSQLND_G(dbg)->m->log(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "info : ", (msg)); }
while (0)
#define DBG_ERR(msg) do { if (dbg_skip_trace == FALSE)
MYSQLND_G(dbg)->m->log(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "error: ", (msg)); }
while (0)
Modified: trunk/mysqlnd/mysqlnd_result.c
===================================================================
--- trunk/mysqlnd/mysqlnd_result.c 2007-09-24 13:08:05 UTC (rev 1057)
+++ trunk/mysqlnd/mysqlnd_result.c 2007-09-24 13:10:13 UTC (rev 1058)
@@ -324,7 +324,7 @@
default:{ /* Result set */
php_mysql_packet_eof fields_eof;
MYSQLND_RES *result;
- uint stat = -1;
+ enum_mysqlnd_collected_stats stat = STAT_LAST;
DBG_INF("Result set pending");
SET_EMPTY_MESSAGE(conn->last_message, conn->last_message_len,
conn->persistent);
@@ -404,7 +404,12 @@
} else if (fields_eof.server_status & MYSQLND_SERVER_QUERY_NO_INDEX_USED) {
stat = STAT_NO_INDEX_USED;
}
- if (stat != -1) {
+ if (stat != STAT_LAST) {
+ char *backtrace = mysqlnd_get_backtrace(TSRMLS_C);
+#if A0
+ php_log_err(backtrace TSRMLS_CC);
+#endif
+ efree(backtrace);
MYSQLND_INC_CONN_STATISTIC(&conn->stats, stat);
}
}
| Thread |
|---|
| • PHP mysqlnd svn commit: r1058 - trunk/mysqlnd | ahristov | 24 Sep |