Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_debug.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 2006-2012 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 321634 2012-01-01 13:15:04Z felipe $ */
! 22:
! 23: #include "php.h"
! 24: #include "mysqlnd.h"
! 25: #include "mysqlnd_priv.h"
! 26: #include "mysqlnd_debug.h"
! 27: #include "mysqlnd_wireprotocol.h"
! 28: #include "mysqlnd_statistics.h"
! 29: #include "zend_builtin_functions.h"
! 30:
! 31: static const char * const mysqlnd_debug_default_trace_file = "/tmp/mysqlnd.trace";
! 32:
! 33: #ifdef ZTS
! 34: #define MYSQLND_ZTS(self) TSRMLS_D = (self)->TSRMLS_C
! 35: #else
! 36: #define MYSQLND_ZTS(self)
! 37: #endif
! 38:
! 39: static const char mysqlnd_emalloc_name[] = "_mysqlnd_emalloc";
! 40: static const char mysqlnd_pemalloc_name[] = "_mysqlnd_pemalloc";
! 41: static const char mysqlnd_ecalloc_name[] = "_mysqlnd_ecalloc";
! 42: static const char mysqlnd_pecalloc_name[] = "_mysqlnd_pecalloc";
! 43: static const char mysqlnd_erealloc_name[] = "_mysqlnd_erealloc";
! 44: static const char mysqlnd_perealloc_name[] = "_mysqlnd_perealloc";
! 45: static const char mysqlnd_efree_name[] = "_mysqlnd_efree";
! 46: static const char mysqlnd_pefree_name[] = "_mysqlnd_pefree";
! 47: static const char mysqlnd_malloc_name[] = "_mysqlnd_malloc";
! 48: static const char mysqlnd_calloc_name[] = "_mysqlnd_calloc";
! 49: static const char mysqlnd_realloc_name[] = "_mysqlnd_realloc";
! 50: static const char mysqlnd_free_name[] = "_mysqlnd_free";
! 51: static const char mysqlnd_pestrndup_name[] = "_mysqlnd_pestrndup";
! 52: static const char mysqlnd_pestrdup_name[] = "_mysqlnd_pestrdup";
! 53:
! 54: const char * mysqlnd_debug_std_no_trace_funcs[] =
! 55: {
! 56: mysqlnd_emalloc_name,
! 57: mysqlnd_ecalloc_name,
! 58: mysqlnd_efree_name,
! 59: mysqlnd_erealloc_name,
! 60: mysqlnd_pemalloc_name,
! 61: mysqlnd_pecalloc_name,
! 62: mysqlnd_pefree_name,
! 63: mysqlnd_perealloc_name,
! 64: mysqlnd_malloc_name,
! 65: mysqlnd_calloc_name,
! 66: mysqlnd_realloc_name,
! 67: mysqlnd_free_name,
! 68: mysqlnd_pestrndup_name,
! 69: mysqlnd_read_header_name,
! 70: mysqlnd_read_body_name,
! 71: NULL /* must be always last */
! 72: };
! 73:
! 74:
! 75: /* {{{ mysqlnd_debug::open */
! 76: static enum_func_status
! 77: MYSQLND_METHOD(mysqlnd_debug, open)(MYSQLND_DEBUG * self, zend_bool reopen)
! 78: {
! 79: MYSQLND_ZTS(self);
! 80:
! 81: if (!self->file_name) {
! 82: return FAIL;
! 83: }
! 84:
! 85: self->stream = php_stream_open_wrapper(self->file_name,
! 86: reopen == TRUE || self->flags & MYSQLND_DEBUG_APPEND? "ab":"wb",
! 87: REPORT_ERRORS, NULL);
! 88: return self->stream? PASS:FAIL;
! 89: }
! 90: /* }}} */
! 91:
! 92:
! 93: /* {{{ mysqlnd_debug::log */
! 94: static enum_func_status
! 95: MYSQLND_METHOD(mysqlnd_debug, log)(MYSQLND_DEBUG * self,
! 96: unsigned int line, const char * const file,
! 97: unsigned int level, const char * type, const char * message)
! 98: {
! 99: char pipe_buffer[512];
! 100: enum_func_status ret;
! 101: int i;
! 102: char * message_line;
! 103: unsigned int message_line_len;
! 104: unsigned int flags = self->flags;
! 105: char pid_buffer[10], time_buffer[30], file_buffer[200],
! 106: line_buffer[6], level_buffer[7];
! 107: MYSQLND_ZTS(self);
! 108:
! 109: if (!self->stream && FAIL == self->m->open(self, FALSE)) {
! 110: return FAIL;
! 111: }
! 112:
! 113: if (level == -1) {
! 114: level = zend_stack_count(&self->call_stack);
! 115: }
! 116: i = MIN(level, sizeof(pipe_buffer) / 2 - 1);
! 117: pipe_buffer[i*2] = '\0';
! 118: for (;i > 0;i--) {
! 119: pipe_buffer[i*2 - 1] = ' ';
! 120: pipe_buffer[i*2 - 2] = '|';
! 121: }
! 122:
! 123:
! 124: if (flags & MYSQLND_DEBUG_DUMP_PID) {
! 125: snprintf(pid_buffer, sizeof(pid_buffer) - 1, "%5u: ", self->pid);
! 126: pid_buffer[sizeof(pid_buffer) - 1 ] = '\0';
! 127: }
! 128: if (flags & MYSQLND_DEBUG_DUMP_TIME) {
! 129: /* The following from FF's DBUG library, which is in the public domain */
! 130: #if defined(PHP_WIN32)
! 131: /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
! 132: in system ticks, 10 ms intervals. See my_getsystime.c for high res */
! 133: SYSTEMTIME loc_t;
! 134: GetLocalTime(&loc_t);
! 135: snprintf(time_buffer, sizeof(time_buffer) - 1,
! 136: /* "%04d-%02d-%02d " */
! 137: "%02d:%02d:%02d.%06d ",
! 138: /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
! 139: loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
! 140: time_buffer[sizeof(time_buffer) - 1 ] = '\0';
! 141: #else
! 142: struct timeval tv;
! 143: struct tm *tm_p;
! 144: if (gettimeofday(&tv, NULL) != -1) {
! 145: if ((tm_p= localtime((const time_t *)&tv.tv_sec))) {
! 146: snprintf(time_buffer, sizeof(time_buffer) - 1,
! 147: /* "%04d-%02d-%02d " */
! 148: "%02d:%02d:%02d.%06d ",
! 149: /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
! 150: tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
! 151: (int) (tv.tv_usec));
! 152: time_buffer[sizeof(time_buffer) - 1 ] = '\0';
! 153: }
! 154: }
! 155: #endif
! 156: }
! 157: if (flags & MYSQLND_DEBUG_DUMP_FILE) {
! 158: snprintf(file_buffer, sizeof(file_buffer) - 1, "%14s: ", file);
! 159: file_buffer[sizeof(file_buffer) - 1 ] = '\0';
! 160: }
! 161: if (flags & MYSQLND_DEBUG_DUMP_LINE) {
! 162: snprintf(line_buffer, sizeof(line_buffer) - 1, "%5u: ", line);
! 163: line_buffer[sizeof(line_buffer) - 1 ] = '\0';
! 164: }
! 165: if (flags & MYSQLND_DEBUG_DUMP_LEVEL) {
! 166: snprintf(level_buffer, sizeof(level_buffer) - 1, "%4u: ", level);
! 167: level_buffer[sizeof(level_buffer) - 1 ] = '\0';
! 168: }
! 169:
! 170: message_line_len = spprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n",
! 171: flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"",
! 172: flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"",
! 173: flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"",
! 174: flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"",
! 175: flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"",
! 176: pipe_buffer, type? type:"", message);
! 177:
! 178: ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL;
! 179: efree(message_line); /* allocated by spprintf */
! 180: if (flags & MYSQLND_DEBUG_FLUSH) {
! 181: self->m->close(self);
! 182: self->m->open(self, TRUE);
! 183: }
! 184: return ret;
! 185: }
! 186: /* }}} */
! 187:
! 188:
! 189: /* {{{ mysqlnd_debug::log_va */
! 190: static enum_func_status
! 191: MYSQLND_METHOD(mysqlnd_debug, log_va)(MYSQLND_DEBUG *self,
! 192: unsigned int line, const char * const file,
! 193: unsigned int level, const char * type,
! 194: const char *format, ...)
! 195: {
! 196: char pipe_buffer[512];
! 197: int i;
! 198: enum_func_status ret;
! 199: char * message_line, *buffer;
! 200: unsigned int message_line_len;
! 201: va_list args;
! 202: unsigned int flags = self->flags;
! 203: char pid_buffer[10], time_buffer[30], file_buffer[200],
! 204: line_buffer[6], level_buffer[7];
! 205: MYSQLND_ZTS(self);
! 206:
! 207: if (!self->stream && FAIL == self->m->open(self, FALSE)) {
! 208: return FAIL;
! 209: }
! 210:
! 211: if (level == -1) {
! 212: level = zend_stack_count(&self->call_stack);
! 213: }
! 214: i = MIN(level, sizeof(pipe_buffer) / 2 - 1);
! 215: pipe_buffer[i*2] = '\0';
! 216: for (;i > 0;i--) {
! 217: pipe_buffer[i*2 - 1] = ' ';
! 218: pipe_buffer[i*2 - 2] = '|';
! 219: }
! 220:
! 221:
! 222: if (flags & MYSQLND_DEBUG_DUMP_PID) {
! 223: snprintf(pid_buffer, sizeof(pid_buffer) - 1, "%5u: ", self->pid);
! 224: pid_buffer[sizeof(pid_buffer) - 1 ] = '\0';
! 225: }
! 226: if (flags & MYSQLND_DEBUG_DUMP_TIME) {
! 227: /* The following from FF's DBUG library, which is in the public domain */
! 228: #if defined(PHP_WIN32)
! 229: /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
! 230: in system ticks, 10 ms intervals. See my_getsystime.c for high res */
! 231: SYSTEMTIME loc_t;
! 232: GetLocalTime(&loc_t);
! 233: snprintf(time_buffer, sizeof(time_buffer) - 1,
! 234: /* "%04d-%02d-%02d " */
! 235: "%02d:%02d:%02d.%06d ",
! 236: /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
! 237: loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
! 238: time_buffer[sizeof(time_buffer) - 1 ] = '\0';
! 239: #else
! 240: struct timeval tv;
! 241: struct tm *tm_p;
! 242: if (gettimeofday(&tv, NULL) != -1) {
! 243: if ((tm_p= localtime((const time_t *)&tv.tv_sec))) {
! 244: snprintf(time_buffer, sizeof(time_buffer) - 1,
! 245: /* "%04d-%02d-%02d " */
! 246: "%02d:%02d:%02d.%06d ",
! 247: /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
! 248: tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
! 249: (int) (tv.tv_usec));
! 250: time_buffer[sizeof(time_buffer) - 1 ] = '\0';
! 251: }
! 252: }
! 253: #endif
! 254: }
! 255: if (flags & MYSQLND_DEBUG_DUMP_FILE) {
! 256: snprintf(file_buffer, sizeof(file_buffer) - 1, "%14s: ", file);
! 257: file_buffer[sizeof(file_buffer) - 1 ] = '\0';
! 258: }
! 259: if (flags & MYSQLND_DEBUG_DUMP_LINE) {
! 260: snprintf(line_buffer, sizeof(line_buffer) - 1, "%5u: ", line);
! 261: line_buffer[sizeof(line_buffer) - 1 ] = '\0';
! 262: }
! 263: if (flags & MYSQLND_DEBUG_DUMP_LEVEL) {
! 264: snprintf(level_buffer, sizeof(level_buffer) - 1, "%4u: ", level);
! 265: level_buffer[sizeof(level_buffer) - 1 ] = '\0';
! 266: }
! 267:
! 268:
! 269: va_start(args, format);
! 270: vspprintf(&buffer, 0, format, args);
! 271: va_end(args);
! 272:
! 273: message_line_len = spprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n",
! 274: flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"",
! 275: flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"",
! 276: flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"",
! 277: flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"",
! 278: flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"",
! 279: pipe_buffer, type? type:"", buffer);
! 280: efree(buffer);
! 281: ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL;
! 282: efree(message_line); /* allocated by spprintf */
! 283:
! 284: if (flags & MYSQLND_DEBUG_FLUSH) {
! 285: self->m->close(self);
! 286: self->m->open(self, TRUE);
! 287: }
! 288: return ret;
! 289: }
! 290: /* }}} */
! 291:
! 292:
! 293: /* FALSE - The DBG_ calls won't be traced, TRUE - will be traced */
! 294: /* {{{ mysqlnd_debug::func_enter */
! 295: static zend_bool
! 296: MYSQLND_METHOD(mysqlnd_debug, func_enter)(MYSQLND_DEBUG * self,
! 297: unsigned int line, const char * const file,
! 298: const char * const func_name, unsigned int func_name_len)
! 299: {
! 300: if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) {
! 301: return FALSE;
! 302: }
! 303: if ((uint) zend_stack_count(&self->call_stack) >= self->nest_level_limit) {
! 304: return FALSE;
! 305: }
! 306:
! 307: if ((self->flags & MYSQLND_DEBUG_TRACE_MEMORY_CALLS) == 0 && self->skip_functions) {
! 308: const char ** p = self->skip_functions;
! 309: while (*p) {
! 310: if (*p == func_name) {
! 311: zend_stack_push(&self->call_stack, "", sizeof(""));
! 312: #ifndef MYSQLND_PROFILING_DISABLED
! 313: if (self->flags & MYSQLND_DEBUG_PROFILE_CALLS) {
! 314: uint64_t some_time = 0;
! 315: zend_stack_push(&self->call_time_stack, &some_time, sizeof(some_time));
! 316: }
! 317: #endif
! 318: return FALSE;
! 319: }
! 320: p++;
! 321: }
! 322: }
! 323:
! 324: zend_stack_push(&self->call_stack, func_name, func_name_len + 1);
! 325: #ifndef MYSQLND_PROFILING_DISABLED
! 326: if (self->flags & MYSQLND_DEBUG_PROFILE_CALLS) {
! 327: uint64_t some_time = 0;
! 328: zend_stack_push(&self->call_time_stack, &some_time, sizeof(some_time));
! 329: }
! 330: #endif
! 331:
! 332: if (zend_hash_num_elements(&self->not_filtered_functions) &&
! 333: 0 == zend_hash_exists(&self->not_filtered_functions, func_name, strlen(func_name) + 1))
! 334: {
! 335: return FALSE;
! 336: }
! 337:
! 338: self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, ">%s", func_name);
! 339: return TRUE;
! 340: }
! 341: /* }}} */
! 342:
! 343: #ifndef MYSQLND_PROFILING_DISABLED
! 344: struct st_mysqlnd_dbg_function_profile {
! 345: uint64_t calls;
! 346: uint64_t min_own;
! 347: uint64_t max_own;
! 348: uint64_t avg_own;
! 349: uint64_t own_underporm_calls;
! 350: uint64_t min_in_calls;
! 351: uint64_t max_in_calls;
! 352: uint64_t avg_in_calls;
! 353: uint64_t in_calls_underporm_calls;
! 354: uint64_t min_total;
! 355: uint64_t max_total;
! 356: uint64_t avg_total;
! 357: uint64_t total_underporm_calls;
! 358: };
! 359: #define PROFILE_UNDERPERFORM_THRESHOLD 10
! 360: #endif
! 361:
! 362: /* {{{ mysqlnd_debug::func_leave */
! 363: static enum_func_status
! 364: MYSQLND_METHOD(mysqlnd_debug, func_leave)(MYSQLND_DEBUG * self, unsigned int line, const char * const file, uint64_t call_time)
! 365: {
! 366: char *func_name;
! 367: uint64_t * parent_non_own_time_ptr = NULL, * mine_non_own_time_ptr = NULL;
! 368: uint64_t mine_non_own_time = 0;
! 369: zend_bool profile_calls = self->flags & MYSQLND_DEBUG_PROFILE_CALLS? TRUE:FALSE;
! 370:
! 371: if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) {
! 372: return PASS;
! 373: }
! 374: if ((uint) zend_stack_count(&self->call_stack) >= self->nest_level_limit) {
! 375: return PASS;
! 376: }
! 377:
! 378: zend_stack_top(&self->call_stack, (void **)&func_name);
! 379:
! 380: #ifndef MYSQLND_PROFILING_DISABLED
! 381: if (profile_calls) {
! 382: zend_stack_top(&self->call_time_stack, (void **)&mine_non_own_time_ptr);
! 383: mine_non_own_time = *mine_non_own_time_ptr;
! 384: zend_stack_del_top(&self->call_time_stack); /* callee - removing ourselves */
! 385: }
! 386: #endif
! 387:
! 388: if (func_name[0] == '\0') {
! 389: ; /* don't log that function */
! 390: } else if (!zend_hash_num_elements(&self->not_filtered_functions) ||
! 391: 1 == zend_hash_exists(&self->not_filtered_functions, func_name, strlen(func_name) + 1))
! 392: {
! 393: #ifndef MYSQLND_PROFILING_DISABLED
! 394: if (FALSE == profile_calls) {
! 395: #endif
! 396: self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s", func_name);
! 397:
! 398: #ifndef MYSQLND_PROFILING_DISABLED
! 399: } else {
! 400: struct st_mysqlnd_dbg_function_profile f_profile_stack = {0};
! 401: struct st_mysqlnd_dbg_function_profile * f_profile = NULL;
! 402: uint64_t own_time = call_time - mine_non_own_time;
! 403: uint func_name_len = strlen(func_name);
! 404:
! 405: self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s (total=%u own=%u in_calls=%u)",
! 406: func_name, (unsigned int) call_time, (unsigned int) own_time, (unsigned int) mine_non_own_time
! 407: );
! 408:
! 409: if (SUCCESS == zend_hash_find(&self->function_profiles, func_name, func_name_len + 1, (void **) &f_profile)) {
! 410: /* found */
! 411: if (f_profile) {
! 412: if (mine_non_own_time < f_profile->min_in_calls) {
! 413: f_profile->min_in_calls = mine_non_own_time;
! 414: } else if (mine_non_own_time > f_profile->max_in_calls) {
! 415: f_profile->max_in_calls = mine_non_own_time;
! 416: }
! 417: f_profile->avg_in_calls = (f_profile->avg_in_calls * f_profile->calls + mine_non_own_time) / (f_profile->calls + 1);
! 418:
! 419: if (own_time < f_profile->min_own) {
! 420: f_profile->min_own = own_time;
! 421: } else if (own_time > f_profile->max_own) {
! 422: f_profile->max_own = own_time;
! 423: }
! 424: f_profile->avg_own = (f_profile->avg_own * f_profile->calls + own_time) / (f_profile->calls + 1);
! 425:
! 426: if (call_time < f_profile->min_total) {
! 427: f_profile->min_total = call_time;
! 428: } else if (call_time > f_profile->max_total) {
! 429: f_profile->max_total = call_time;
! 430: }
! 431: f_profile->avg_total = (f_profile->avg_total * f_profile->calls + call_time) / (f_profile->calls + 1);
! 432:
! 433: ++f_profile->calls;
! 434: if (f_profile->calls > PROFILE_UNDERPERFORM_THRESHOLD) {
! 435: if (f_profile->avg_in_calls < mine_non_own_time) {
! 436: f_profile->in_calls_underporm_calls++;
! 437: }
! 438: if (f_profile->avg_own < own_time) {
! 439: f_profile->own_underporm_calls++;
! 440: }
! 441: if (f_profile->avg_total < call_time) {
! 442: f_profile->total_underporm_calls++;
! 443: }
! 444: }
! 445: }
! 446: } else {
! 447: /* add */
! 448: f_profile = &f_profile_stack;
! 449: f_profile->min_in_calls = f_profile->max_in_calls = f_profile->avg_in_calls = mine_non_own_time;
! 450: f_profile->min_total = f_profile->max_total = f_profile->avg_total = call_time;
! 451: f_profile->min_own = f_profile->max_own = f_profile->avg_own = own_time;
! 452: f_profile->calls = 1;
! 453: zend_hash_add(&self->function_profiles, func_name, func_name_len+1, f_profile, sizeof(struct st_mysqlnd_dbg_function_profile), NULL);
! 454: }
! 455: if ((uint) zend_stack_count(&self->call_time_stack)) {
! 456: uint64_t parent_non_own_time = 0;
! 457:
! 458: zend_stack_top(&self->call_time_stack, (void **)&parent_non_own_time_ptr);
! 459: parent_non_own_time = *parent_non_own_time_ptr;
! 460: parent_non_own_time += call_time;
! 461: zend_stack_del_top(&self->call_time_stack); /* the caller */
! 462: zend_stack_push(&self->call_time_stack, &parent_non_own_time, sizeof(parent_non_own_time)); /* add back the caller */
! 463: }
! 464: }
! 465: #endif
! 466: }
! 467:
! 468: return zend_stack_del_top(&self->call_stack) == SUCCESS? PASS:FAIL;
! 469: }
! 470: /* }}} */
! 471:
! 472:
! 473: /* {{{ mysqlnd_debug::close */
! 474: static enum_func_status
! 475: MYSQLND_METHOD(mysqlnd_debug, close)(MYSQLND_DEBUG * self)
! 476: {
! 477: MYSQLND_ZTS(self);
! 478: if (self->stream) {
! 479: #ifndef MYSQLND_PROFILING_DISABLED
! 480: if (!(self->flags & MYSQLND_DEBUG_FLUSH) && (self->flags & MYSQLND_DEBUG_PROFILE_CALLS)) {
! 481: struct st_mysqlnd_dbg_function_profile * f_profile;
! 482: HashPosition pos_values;
! 483:
! 484: self->m->log_va(self, __LINE__, __FILE__, 0, "info : ",
! 485: "number of functions: %d", zend_hash_num_elements(&self->function_profiles));
! 486: zend_hash_internal_pointer_reset_ex(&self->function_profiles, &pos_values);
! 487: while (zend_hash_get_current_data_ex(&self->function_profiles, (void **) &f_profile, &pos_values) == SUCCESS) {
! 488: char *string_key = NULL;
! 489: uint string_key_len;
! 490: ulong num_key;
! 491:
! 492: zend_hash_get_current_key_ex(&self->function_profiles, &string_key, &string_key_len, &num_key, 0, &pos_values);
! 493:
! 494: self->m->log_va(self, __LINE__, __FILE__, -1, "info : ",
! 495: "%-40s\tcalls=%5llu own_slow=%5llu in_calls_slow=%5llu total_slow=%5llu"
! 496: " min_own=%5llu max_own=%7llu avg_own=%7llu "
! 497: " min_in_calls=%5llu max_in_calls=%7llu avg_in_calls=%7llu"
! 498: " min_total=%5llu max_total=%7llu avg_total=%7llu"
! 499: ,string_key
! 500: ,(uint64_t) f_profile->calls
! 501: ,(uint64_t) f_profile->own_underporm_calls
! 502: ,(uint64_t) f_profile->in_calls_underporm_calls
! 503: ,(uint64_t) f_profile->total_underporm_calls
! 504:
! 505: ,(uint64_t) f_profile->min_own
! 506: ,(uint64_t) f_profile->max_own
! 507: ,(uint64_t) f_profile->avg_own
! 508: ,(uint64_t) f_profile->min_in_calls
! 509: ,(uint64_t) f_profile->max_in_calls
! 510: ,(uint64_t) f_profile->avg_in_calls
! 511: ,(uint64_t) f_profile->min_total
! 512: ,(uint64_t) f_profile->max_total
! 513: ,(uint64_t) f_profile->avg_total
! 514: );
! 515: zend_hash_move_forward_ex(&self->function_profiles, &pos_values);
! 516: }
! 517: }
! 518: #endif
! 519:
! 520: php_stream_free(self->stream, PHP_STREAM_FREE_CLOSE);
! 521: self->stream = NULL;
! 522: }
! 523: /* no DBG_RETURN please */
! 524: return PASS;
! 525: }
! 526: /* }}} */
! 527:
! 528:
! 529: /* {{{ mysqlnd_res_meta::free */
! 530: static enum_func_status
! 531: MYSQLND_METHOD(mysqlnd_debug, free)(MYSQLND_DEBUG * self)
! 532: {
! 533: if (self->file_name && self->file_name != mysqlnd_debug_default_trace_file) {
! 534: efree(self->file_name);
! 535: self->file_name = NULL;
! 536: }
! 537: zend_stack_destroy(&self->call_stack);
! 538: zend_stack_destroy(&self->call_time_stack);
! 539: zend_hash_destroy(&self->not_filtered_functions);
! 540: zend_hash_destroy(&self->function_profiles);
! 541: efree(self);
! 542: return PASS;
! 543: }
! 544: /* }}} */
! 545:
! 546: enum mysqlnd_debug_parser_state
! 547: {
! 548: PARSER_WAIT_MODIFIER,
! 549: PARSER_WAIT_COLON,
! 550: PARSER_WAIT_VALUE
! 551: };
! 552:
! 553:
! 554: /* {{{ mysqlnd_res_meta::set_mode */
! 555: static void
! 556: MYSQLND_METHOD(mysqlnd_debug, set_mode)(MYSQLND_DEBUG * self, const char * const mode)
! 557: {
! 558: unsigned int mode_len = strlen(mode), i;
! 559: enum mysqlnd_debug_parser_state state = PARSER_WAIT_MODIFIER;
! 560:
! 561: self->flags = 0;
! 562: self->nest_level_limit = 0;
! 563: if (self->file_name && self->file_name != mysqlnd_debug_default_trace_file) {
! 564: efree(self->file_name);
! 565: self->file_name = NULL;
! 566: }
! 567: if (zend_hash_num_elements(&self->not_filtered_functions)) {
! 568: zend_hash_destroy(&self->not_filtered_functions);
! 569: zend_hash_init(&self->not_filtered_functions, 0, NULL, NULL, 0);
! 570: }
! 571:
! 572: for (i = 0; i < mode_len; i++) {
! 573: switch (mode[i]) {
! 574: case 'O':
! 575: case 'A':
! 576: self->flags |= MYSQLND_DEBUG_FLUSH;
! 577: case 'a':
! 578: case 'o':
! 579: if (mode[i] == 'a' || mode[i] == 'A') {
! 580: self->flags |= MYSQLND_DEBUG_APPEND;
! 581: }
! 582: if (i + 1 < mode_len && mode[i+1] == ',') {
! 583: unsigned int j = i + 2;
! 584: #ifdef PHP_WIN32
! 585: if (i+4 < mode_len && mode[i+3] == ':' && (mode[i+4] == '\\' || mode[i+5] == '/')) {
! 586: j = i + 5;
! 587: }
! 588: #endif
! 589: while (j < mode_len) {
! 590: if (mode[j] == ':') {
! 591: break;
! 592: }
! 593: j++;
! 594: }
! 595: if (j > i + 2) {
! 596: self->file_name = estrndup(mode + i + 2, j - i - 2);
! 597: }
! 598: i = j;
! 599: } else {
! 600: if (!self->file_name)
! 601: self->file_name = (char *) mysqlnd_debug_default_trace_file;
! 602: }
! 603: state = PARSER_WAIT_COLON;
! 604: break;
! 605: case ':':
! 606: #if 0
! 607: if (state != PARSER_WAIT_COLON) {
! 608: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Consecutive semicolons at position %u", i);
! 609: }
! 610: #endif
! 611: state = PARSER_WAIT_MODIFIER;
! 612: break;
! 613: case 'f': /* limit output to these functions */
! 614: if (i + 1 < mode_len && mode[i+1] == ',') {
! 615: unsigned int j = i + 2;
! 616: i++;
! 617: while (j < mode_len) {
! 618: if (mode[j] == ':') {
! 619: /* function names with :: */
! 620: if ((j + 1 < mode_len) && mode[j+1] == ':') {
! 621: j += 2;
! 622: continue;
! 623: }
! 624: }
! 625: if (mode[j] == ',' || mode[j] == ':') {
! 626: if (j > i + 2) {
! 627: char func_name[1024];
! 628: unsigned int func_name_len = MIN(sizeof(func_name) - 1, j - i - 1);
! 629: memcpy(func_name, mode + i + 1, func_name_len);
! 630: func_name[func_name_len] = '\0';
! 631:
! 632: zend_hash_add_empty_element(&self->not_filtered_functions,
! 633: func_name, func_name_len + 1);
! 634: i = j;
! 635: }
! 636: if (mode[j] == ':') {
! 637: break;
! 638: }
! 639: }
! 640: j++;
! 641: }
! 642: i = j;
! 643: } else {
! 644: #if 0
! 645: php_error_docref(NULL TSRMLS_CC, E_WARNING,
! 646: "Expected list of functions for '%c' found none", mode[i]);
! 647: #endif
! 648: }
! 649: state = PARSER_WAIT_COLON;
! 650: break;
! 651: case 'D':
! 652: case 'd':
! 653: case 'g':
! 654: case 'p':
! 655: /* unsupported */
! 656: if ((i + 1) < mode_len && mode[i+1] == ',') {
! 657: i+= 2;
! 658: while (i < mode_len) {
! 659: if (mode[i] == ':') {
! 660: break;
! 661: }
! 662: i++;
! 663: }
! 664: }
! 665: state = PARSER_WAIT_COLON;
! 666: break;
! 667: case 'F':
! 668: self->flags |= MYSQLND_DEBUG_DUMP_FILE;
! 669: state = PARSER_WAIT_COLON;
! 670: break;
! 671: case 'i':
! 672: self->flags |= MYSQLND_DEBUG_DUMP_PID;
! 673: state = PARSER_WAIT_COLON;
! 674: break;
! 675: case 'L':
! 676: self->flags |= MYSQLND_DEBUG_DUMP_LINE;
! 677: state = PARSER_WAIT_COLON;
! 678: break;
! 679: case 'n':
! 680: self->flags |= MYSQLND_DEBUG_DUMP_LEVEL;
! 681: state = PARSER_WAIT_COLON;
! 682: break;
! 683: case 't':
! 684: if (mode[i+1] == ',') {
! 685: unsigned int j = i + 2;
! 686: while (j < mode_len) {
! 687: if (mode[j] == ':') {
! 688: break;
! 689: }
! 690: j++;
! 691: }
! 692: if (j > i + 2) {
! 693: char *value_str = estrndup(mode + i + 2, j - i - 2);
! 694: self->nest_level_limit = atoi(value_str);
! 695: efree(value_str);
! 696: }
! 697: i = j;
! 698: } else {
! 699: self->nest_level_limit = 200; /* default value for FF DBUG */
! 700: }
! 701: self->flags |= MYSQLND_DEBUG_DUMP_TRACE;
! 702: state = PARSER_WAIT_COLON;
! 703: break;
! 704: case 'T':
! 705: self->flags |= MYSQLND_DEBUG_DUMP_TIME;
! 706: state = PARSER_WAIT_COLON;
! 707: break;
! 708: case 'N':
! 709: case 'P':
! 710: case 'r':
! 711: case 'S':
! 712: state = PARSER_WAIT_COLON;
! 713: break;
! 714: case 'm': /* mysqlnd extension - trace memory functions */
! 715: self->flags |= MYSQLND_DEBUG_TRACE_MEMORY_CALLS;
! 716: state = PARSER_WAIT_COLON;
! 717: break;
! 718: case 'x': /* mysqlnd extension - profile calls */
! 719: self->flags |= MYSQLND_DEBUG_PROFILE_CALLS;
! 720: state = PARSER_WAIT_COLON;
! 721: break;
! 722: default:
! 723: if (state == PARSER_WAIT_MODIFIER) {
! 724: #if 0
! 725: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized format '%c'", mode[i]);
! 726: #endif
! 727: if (i+1 < mode_len && mode[i+1] == ',') {
! 728: i+= 2;
! 729: while (i < mode_len) {
! 730: if (mode[i] == ':') {
! 731: break;
! 732: }
! 733: i++;
! 734: }
! 735: }
! 736: state = PARSER_WAIT_COLON;
! 737: } else if (state == PARSER_WAIT_COLON) {
! 738: #if 0
! 739: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Colon expected, '%c' found", mode[i]);
! 740: #endif
! 741: }
! 742: break;
! 743: }
! 744: }
! 745: }
! 746: /* }}} */
! 747:
! 748: MYSQLND_CLASS_METHODS_START(mysqlnd_debug)
! 749: MYSQLND_METHOD(mysqlnd_debug, open),
! 750: MYSQLND_METHOD(mysqlnd_debug, set_mode),
! 751: MYSQLND_METHOD(mysqlnd_debug, log),
! 752: MYSQLND_METHOD(mysqlnd_debug, log_va),
! 753: MYSQLND_METHOD(mysqlnd_debug, func_enter),
! 754: MYSQLND_METHOD(mysqlnd_debug, func_leave),
! 755: MYSQLND_METHOD(mysqlnd_debug, close),
! 756: MYSQLND_METHOD(mysqlnd_debug, free),
! 757: MYSQLND_CLASS_METHODS_END;
! 758:
! 759:
! 760: /* {{{ mysqlnd_debug_init */
! 761: PHPAPI MYSQLND_DEBUG *
! 762: mysqlnd_debug_init(const char * skip_functions[] TSRMLS_DC)
! 763: {
! 764: MYSQLND_DEBUG *ret = ecalloc(1, sizeof(MYSQLND_DEBUG));
! 765: #ifdef ZTS
! 766: ret->TSRMLS_C = TSRMLS_C;
! 767: #endif
! 768: ret->nest_level_limit = 0;
! 769: ret->pid = getpid();
! 770: zend_stack_init(&ret->call_stack);
! 771: zend_stack_init(&ret->call_time_stack);
! 772: zend_hash_init(&ret->not_filtered_functions, 0, NULL, NULL, 0);
! 773: zend_hash_init(&ret->function_profiles, 0, NULL, NULL, 0);
! 774:
! 775: ret->m = & mysqlnd_mysqlnd_debug_methods;
! 776: ret->skip_functions = skip_functions;
! 777:
! 778: return ret;
! 779: }
! 780: /* }}} */
! 781:
! 782:
! 783: /* {{{ _mysqlnd_debug */
! 784: PHPAPI void _mysqlnd_debug(const char * mode TSRMLS_DC)
! 785: {
! 786: #ifdef PHP_DEBUG
! 787: MYSQLND_DEBUG *dbg = MYSQLND_G(dbg);
! 788: if (!dbg) {
! 789: MYSQLND_G(dbg) = dbg = mysqlnd_debug_init(mysqlnd_debug_std_no_trace_funcs TSRMLS_CC);
! 790: if (!dbg) {
! 791: return;
! 792: }
! 793: }
! 794:
! 795: dbg->m->close(dbg);
! 796: dbg->m->set_mode(dbg, mode);
! 797: while (zend_stack_count(&dbg->call_stack)) {
! 798: zend_stack_del_top(&dbg->call_stack);
! 799: }
! 800: while (zend_stack_count(&dbg->call_time_stack)) {
! 801: zend_stack_del_top(&dbg->call_time_stack);
! 802: }
! 803: #endif
! 804: }
! 805: /* }}} */
! 806:
! 807:
! 808: #if ZEND_DEBUG
! 809: #else
! 810: #define __zend_filename "/unknown/unknown"
! 811: #define __zend_lineno 0
! 812: #endif
! 813:
! 814: #define REAL_SIZE(s) (collect_memory_statistics? (s) + sizeof(size_t) : (s))
! 815: #define REAL_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) - sizeof(size_t)) : (p))
! 816: #define FAKE_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) + sizeof(size_t)) : (p))
! 817:
! 818: /* {{{ _mysqlnd_emalloc */
! 819: void * _mysqlnd_emalloc(size_t size MYSQLND_MEM_D)
! 820: {
! 821: void *ret;
! 822: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 823: long * threshold = &MYSQLND_G(debug_emalloc_fail_threshold);
! 824: DBG_ENTER(mysqlnd_emalloc_name);
! 825:
! 826: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 827:
! 828: #ifdef PHP_DEBUG
! 829: /* -1 is also "true" */
! 830: if (*threshold) {
! 831: #endif
! 832: ret = emalloc(REAL_SIZE(size));
! 833: #ifdef PHP_DEBUG
! 834: --*threshold;
! 835: } else if (*threshold == 0) {
! 836: ret = NULL;
! 837: }
! 838: #endif
! 839:
! 840: DBG_INF_FMT("size=%lu ptr=%p", size, ret);
! 841:
! 842: if (ret && collect_memory_statistics) {
! 843: *(size_t *) ret = size;
! 844: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EMALLOC_COUNT, 1, STAT_MEM_EMALLOC_AMOUNT, size);
! 845: }
! 846: DBG_RETURN(FAKE_PTR(ret));
! 847: }
! 848: /* }}} */
! 849:
! 850:
! 851: /* {{{ _mysqlnd_pemalloc */
! 852: void * _mysqlnd_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D)
! 853: {
! 854: void *ret;
! 855: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 856: long * threshold = persistent? &MYSQLND_G(debug_malloc_fail_threshold):&MYSQLND_G(debug_emalloc_fail_threshold);
! 857: DBG_ENTER(mysqlnd_pemalloc_name);
! 858: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 859:
! 860: #ifdef PHP_DEBUG
! 861: /* -1 is also "true" */
! 862: if (*threshold) {
! 863: #endif
! 864: ret = pemalloc(REAL_SIZE(size), persistent);
! 865: #ifdef PHP_DEBUG
! 866: --*threshold;
! 867: } else if (*threshold == 0) {
! 868: ret = NULL;
! 869: }
! 870: #endif
! 871:
! 872: DBG_INF_FMT("size=%lu ptr=%p persistent=%u", size, ret, persistent);
! 873:
! 874: if (ret && collect_memory_statistics) {
! 875: enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_MALLOC_COUNT:STAT_MEM_EMALLOC_COUNT;
! 876: enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_MALLOC_AMOUNT:STAT_MEM_EMALLOC_AMOUNT;
! 877: *(size_t *) ret = size;
! 878: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, size);
! 879: }
! 880:
! 881: DBG_RETURN(FAKE_PTR(ret));
! 882: }
! 883: /* }}} */
! 884:
! 885:
! 886: /* {{{ _mysqlnd_ecalloc */
! 887: void * _mysqlnd_ecalloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
! 888: {
! 889: void *ret;
! 890: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 891: long * threshold = &MYSQLND_G(debug_ecalloc_fail_threshold);
! 892: DBG_ENTER(mysqlnd_ecalloc_name);
! 893: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 894: DBG_INF_FMT("before: %lu", zend_memory_usage(FALSE TSRMLS_CC));
! 895:
! 896: #ifdef PHP_DEBUG
! 897: /* -1 is also "true" */
! 898: if (*threshold) {
! 899: #endif
! 900: ret = ecalloc(nmemb, REAL_SIZE(size));
! 901: #ifdef PHP_DEBUG
! 902: --*threshold;
! 903: } else if (*threshold == 0) {
! 904: ret = NULL;
! 905: }
! 906: #endif
! 907:
! 908: DBG_INF_FMT("after : %lu", zend_memory_usage(FALSE TSRMLS_CC));
! 909: DBG_INF_FMT("size=%lu ptr=%p", size, ret);
! 910: if (ret && collect_memory_statistics) {
! 911: *(size_t *) ret = size;
! 912: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_ECALLOC_COUNT, 1, STAT_MEM_ECALLOC_AMOUNT, size);
! 913: }
! 914: DBG_RETURN(FAKE_PTR(ret));
! 915: }
! 916: /* }}} */
! 917:
! 918:
! 919: /* {{{ _mysqlnd_pecalloc */
! 920: void * _mysqlnd_pecalloc(unsigned int nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D)
! 921: {
! 922: void *ret;
! 923: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 924: long * threshold = persistent? &MYSQLND_G(debug_calloc_fail_threshold):&MYSQLND_G(debug_ecalloc_fail_threshold);
! 925: DBG_ENTER(mysqlnd_pecalloc_name);
! 926: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 927:
! 928: #ifdef PHP_DEBUG
! 929: /* -1 is also "true" */
! 930: if (*threshold) {
! 931: #endif
! 932: ret = pecalloc(nmemb, REAL_SIZE(size), persistent);
! 933: #ifdef PHP_DEBUG
! 934: --*threshold;
! 935: } else if (*threshold == 0) {
! 936: ret = NULL;
! 937: }
! 938: #endif
! 939:
! 940: DBG_INF_FMT("size=%lu ptr=%p", size, ret);
! 941:
! 942: if (ret && collect_memory_statistics) {
! 943: enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_CALLOC_COUNT:STAT_MEM_ECALLOC_COUNT;
! 944: enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_CALLOC_AMOUNT:STAT_MEM_ECALLOC_AMOUNT;
! 945: *(size_t *) ret = size;
! 946: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, size);
! 947: }
! 948:
! 949: DBG_RETURN(FAKE_PTR(ret));
! 950: }
! 951: /* }}} */
! 952:
! 953:
! 954: /* {{{ _mysqlnd_erealloc */
! 955: void * _mysqlnd_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D)
! 956: {
! 957: void *ret;
! 958: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 959: size_t old_size = collect_memory_statistics && ptr? *(size_t *) (((char*)ptr) - sizeof(size_t)) : 0;
! 960: long * threshold = &MYSQLND_G(debug_erealloc_fail_threshold);
! 961: DBG_ENTER(mysqlnd_erealloc_name);
! 962: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 963: DBG_INF_FMT("ptr=%p old_size=%lu, new_size=%lu", ptr, old_size, new_size);
! 964:
! 965: #ifdef PHP_DEBUG
! 966: /* -1 is also "true" */
! 967: if (*threshold) {
! 968: #endif
! 969: ret = erealloc(REAL_PTR(ptr), REAL_SIZE(new_size));
! 970: #ifdef PHP_DEBUG
! 971: --*threshold;
! 972: } else if (*threshold == 0) {
! 973: ret = NULL;
! 974: }
! 975: #endif
! 976:
! 977: DBG_INF_FMT("new_ptr=%p", (char*)ret);
! 978: if (ret && collect_memory_statistics) {
! 979: *(size_t *) ret = new_size;
! 980: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EREALLOC_COUNT, 1, STAT_MEM_EREALLOC_AMOUNT, new_size);
! 981: }
! 982: DBG_RETURN(FAKE_PTR(ret));
! 983: }
! 984: /* }}} */
! 985:
! 986:
! 987: /* {{{ _mysqlnd_perealloc */
! 988: void * _mysqlnd_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D)
! 989: {
! 990: void *ret;
! 991: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 992: size_t old_size = collect_memory_statistics && ptr? *(size_t *) (((char*)ptr) - sizeof(size_t)) : 0;
! 993: long * threshold = persistent? &MYSQLND_G(debug_realloc_fail_threshold):&MYSQLND_G(debug_erealloc_fail_threshold);
! 994: DBG_ENTER(mysqlnd_perealloc_name);
! 995: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 996: DBG_INF_FMT("ptr=%p old_size=%lu new_size=%lu persistent=%u", ptr, old_size, new_size, persistent);
! 997:
! 998: #ifdef PHP_DEBUG
! 999: /* -1 is also "true" */
! 1000: if (*threshold) {
! 1001: #endif
! 1002: ret = perealloc(REAL_PTR(ptr), REAL_SIZE(new_size), persistent);
! 1003: #ifdef PHP_DEBUG
! 1004: --*threshold;
! 1005: } else if (*threshold == 0) {
! 1006: ret = NULL;
! 1007: }
! 1008: #endif
! 1009:
! 1010: DBG_INF_FMT("new_ptr=%p", (char*)ret);
! 1011:
! 1012: if (ret && collect_memory_statistics) {
! 1013: enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_REALLOC_COUNT:STAT_MEM_EREALLOC_COUNT;
! 1014: enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_REALLOC_AMOUNT:STAT_MEM_EREALLOC_AMOUNT;
! 1015: *(size_t *) ret = new_size;
! 1016: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, new_size);
! 1017: }
! 1018: DBG_RETURN(FAKE_PTR(ret));
! 1019: }
! 1020: /* }}} */
! 1021:
! 1022:
! 1023: /* {{{ _mysqlnd_efree */
! 1024: void _mysqlnd_efree(void *ptr MYSQLND_MEM_D)
! 1025: {
! 1026: size_t free_amount = 0;
! 1027: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 1028: DBG_ENTER(mysqlnd_efree_name);
! 1029: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 1030: DBG_INF_FMT("ptr=%p", ptr);
! 1031:
! 1032: if (ptr) {
! 1033: if (collect_memory_statistics) {
! 1034: free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
! 1035: DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
! 1036: }
! 1037: efree(REAL_PTR(ptr));
! 1038: }
! 1039:
! 1040: if (collect_memory_statistics) {
! 1041: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EFREE_COUNT, 1, STAT_MEM_EFREE_AMOUNT, free_amount);
! 1042: }
! 1043: DBG_VOID_RETURN;
! 1044: }
! 1045: /* }}} */
! 1046:
! 1047:
! 1048: /* {{{ _mysqlnd_pefree */
! 1049: void _mysqlnd_pefree(void *ptr, zend_bool persistent MYSQLND_MEM_D)
! 1050: {
! 1051: size_t free_amount = 0;
! 1052: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 1053: DBG_ENTER(mysqlnd_pefree_name);
! 1054: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 1055: DBG_INF_FMT("ptr=%p persistent=%u", ptr, persistent);
! 1056:
! 1057: if (ptr) {
! 1058: if (collect_memory_statistics) {
! 1059: free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
! 1060: DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
! 1061: }
! 1062: pefree(REAL_PTR(ptr), persistent);
! 1063: }
! 1064:
! 1065: if (collect_memory_statistics) {
! 1066: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(persistent? STAT_MEM_FREE_COUNT:STAT_MEM_EFREE_COUNT, 1,
! 1067: persistent? STAT_MEM_FREE_AMOUNT:STAT_MEM_EFREE_AMOUNT, free_amount);
! 1068: }
! 1069: DBG_VOID_RETURN;
! 1070: }
! 1071:
! 1072:
! 1073: /* {{{ _mysqlnd_malloc */
! 1074: void * _mysqlnd_malloc(size_t size MYSQLND_MEM_D)
! 1075: {
! 1076: void *ret;
! 1077: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 1078: long * threshold = &MYSQLND_G(debug_malloc_fail_threshold);
! 1079: DBG_ENTER(mysqlnd_malloc_name);
! 1080: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 1081:
! 1082: #ifdef PHP_DEBUG
! 1083: /* -1 is also "true" */
! 1084: if (*threshold) {
! 1085: #endif
! 1086: ret = malloc(REAL_SIZE(size));
! 1087: #ifdef PHP_DEBUG
! 1088: --*threshold;
! 1089: } else if (*threshold == 0) {
! 1090: ret = NULL;
! 1091: }
! 1092: #endif
! 1093:
! 1094: DBG_INF_FMT("size=%lu ptr=%p", size, ret);
! 1095: if (ret && collect_memory_statistics) {
! 1096: *(size_t *) ret = size;
! 1097: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_MALLOC_COUNT, 1, STAT_MEM_MALLOC_AMOUNT, size);
! 1098: }
! 1099: DBG_RETURN(FAKE_PTR(ret));
! 1100: }
! 1101: /* }}} */
! 1102:
! 1103:
! 1104: /* {{{ _mysqlnd_calloc */
! 1105: void * _mysqlnd_calloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
! 1106: {
! 1107: void *ret;
! 1108: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 1109: long * threshold = &MYSQLND_G(debug_calloc_fail_threshold);
! 1110: DBG_ENTER(mysqlnd_calloc_name);
! 1111: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 1112:
! 1113: #ifdef PHP_DEBUG
! 1114: /* -1 is also "true" */
! 1115: if (*threshold) {
! 1116: #endif
! 1117: ret = calloc(nmemb, REAL_SIZE(size));
! 1118: #ifdef PHP_DEBUG
! 1119: --*threshold;
! 1120: } else if (*threshold == 0) {
! 1121: ret = NULL;
! 1122: }
! 1123: #endif
! 1124:
! 1125: DBG_INF_FMT("size=%lu ptr=%p", size, ret);
! 1126: if (ret && collect_memory_statistics) {
! 1127: *(size_t *) ret = size;
! 1128: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_CALLOC_COUNT, 1, STAT_MEM_CALLOC_AMOUNT, size);
! 1129: }
! 1130: DBG_RETURN(FAKE_PTR(ret));
! 1131: }
! 1132: /* }}} */
! 1133:
! 1134:
! 1135: /* {{{ _mysqlnd_realloc */
! 1136: void * _mysqlnd_realloc(void *ptr, size_t new_size MYSQLND_MEM_D)
! 1137: {
! 1138: void *ret;
! 1139: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 1140: long * threshold = &MYSQLND_G(debug_realloc_fail_threshold);
! 1141: DBG_ENTER(mysqlnd_realloc_name);
! 1142: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 1143: DBG_INF_FMT("ptr=%p new_size=%lu ", new_size, ptr);
! 1144: DBG_INF_FMT("before: %lu", zend_memory_usage(TRUE TSRMLS_CC));
! 1145:
! 1146: #ifdef PHP_DEBUG
! 1147: /* -1 is also "true" */
! 1148: if (*threshold) {
! 1149: #endif
! 1150: ret = realloc(REAL_PTR(ptr), REAL_SIZE(new_size));
! 1151: #ifdef PHP_DEBUG
! 1152: --*threshold;
! 1153: } else if (*threshold == 0) {
! 1154: ret = NULL;
! 1155: }
! 1156: #endif
! 1157:
! 1158: DBG_INF_FMT("new_ptr=%p", (char*)ret);
! 1159:
! 1160: if (ret && collect_memory_statistics) {
! 1161: *(size_t *) ret = new_size;
! 1162: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_REALLOC_COUNT, 1, STAT_MEM_REALLOC_AMOUNT, new_size);
! 1163: }
! 1164: DBG_RETURN(FAKE_PTR(ret));
! 1165: }
! 1166: /* }}} */
! 1167:
! 1168:
! 1169: /* {{{ _mysqlnd_free */
! 1170: void _mysqlnd_free(void *ptr MYSQLND_MEM_D)
! 1171: {
! 1172: size_t free_amount = 0;
! 1173: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 1174: DBG_ENTER(mysqlnd_free_name);
! 1175: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 1176: DBG_INF_FMT("ptr=%p", ptr);
! 1177:
! 1178: if (ptr) {
! 1179: if (collect_memory_statistics) {
! 1180: free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
! 1181: DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
! 1182: }
! 1183: free(REAL_PTR(ptr));
! 1184: }
! 1185:
! 1186: if (collect_memory_statistics) {
! 1187: MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_FREE_COUNT, 1, STAT_MEM_FREE_AMOUNT, free_amount);
! 1188: }
! 1189: DBG_VOID_RETURN;
! 1190: }
! 1191: /* }}} */
! 1192:
! 1193: #define SMART_STR_START_SIZE 2048
! 1194: #define SMART_STR_PREALLOC 512
! 1195: #include "ext/standard/php_smart_str.h"
! 1196:
! 1197:
! 1198: /* {{{ _mysqlnd_pestrndup */
! 1199: char * _mysqlnd_pestrndup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D)
! 1200: {
! 1201: char * ret;
! 1202: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 1203: DBG_ENTER(mysqlnd_pestrndup_name);
! 1204: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 1205: DBG_INF_FMT("ptr=%p", ptr);
! 1206:
! 1207: ret = pemalloc(REAL_SIZE(length) + 1, persistent);
! 1208: {
! 1209: size_t l = length;
! 1210: char * p = (char *) ptr;
! 1211: char * dest = (char *) FAKE_PTR(ret);
! 1212: while (*p && l--) {
! 1213: *dest++ = *p++;
! 1214: }
! 1215: *dest = '\0';
! 1216: }
! 1217:
! 1218: if (collect_memory_statistics) {
! 1219: *(size_t *) ret = length;
! 1220: MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_STRNDUP_COUNT : STAT_MEM_ESTRNDUP_COUNT);
! 1221: }
! 1222:
! 1223: DBG_RETURN(FAKE_PTR(ret));
! 1224: }
! 1225: /* }}} */
! 1226:
! 1227:
! 1228: /* {{{ _mysqlnd_pestrdup */
! 1229: char * _mysqlnd_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_MEM_D)
! 1230: {
! 1231: char * ret;
! 1232: smart_str tmp_str = {0, 0, 0};
! 1233: const char * p = ptr;
! 1234: zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
! 1235: DBG_ENTER(mysqlnd_pestrdup_name);
! 1236: DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
! 1237: DBG_INF_FMT("ptr=%p", ptr);
! 1238: do {
! 1239: smart_str_appendc(&tmp_str, *p);
! 1240: } while (*p++);
! 1241:
! 1242: ret = pemalloc(tmp_str.len + sizeof(size_t), persistent);
! 1243: memcpy(FAKE_PTR(ret), tmp_str.c, tmp_str.len);
! 1244:
! 1245: if (ret && collect_memory_statistics) {
! 1246: *(size_t *) ret = tmp_str.len;
! 1247: MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_STRDUP_COUNT : STAT_MEM_ESTRDUP_COUNT);
! 1248: }
! 1249: smart_str_free(&tmp_str);
! 1250:
! 1251: DBG_RETURN(FAKE_PTR(ret));
! 1252: }
! 1253: /* }}} */
! 1254:
! 1255: #define MYSQLND_DEBUG_MEMORY 1
! 1256:
! 1257: #if MYSQLND_DEBUG_MEMORY == 0
! 1258:
! 1259: /* {{{ mysqlnd_zend_mm_emalloc */
! 1260: static void * mysqlnd_zend_mm_emalloc(size_t size MYSQLND_MEM_D)
! 1261: {
! 1262: return emalloc(size);
! 1263: }
! 1264: /* }}} */
! 1265:
! 1266:
! 1267: /* {{{ mysqlnd_zend_mm_pemalloc */
! 1268: static void * mysqlnd_zend_mm_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D)
! 1269: {
! 1270: return pemalloc(size, persistent);
! 1271: }
! 1272: /* }}} */
! 1273:
! 1274:
! 1275: /* {{{ mysqlnd_zend_mm_ecalloc */
! 1276: static void * mysqlnd_zend_mm_ecalloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
! 1277: {
! 1278: return ecalloc(nmemb, size);
! 1279: }
! 1280: /* }}} */
! 1281:
! 1282:
! 1283: /* {{{ mysqlnd_zend_mm_pecalloc */
! 1284: static void * mysqlnd_zend_mm_pecalloc(unsigned int nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D)
! 1285: {
! 1286: return pecalloc(nmemb, size, persistent);
! 1287: }
! 1288: /* }}} */
! 1289:
! 1290:
! 1291: /* {{{ mysqlnd_zend_mm_erealloc */
! 1292: static void * mysqlnd_zend_mm_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D)
! 1293: {
! 1294: return erealloc(ptr, new_size);
! 1295: }
! 1296: /* }}} */
! 1297:
! 1298:
! 1299: /* {{{ mysqlnd_zend_mm_perealloc */
! 1300: static void * mysqlnd_zend_mm_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D)
! 1301: {
! 1302: return perealloc(ptr, new_size, persistent);
! 1303: }
! 1304: /* }}} */
! 1305:
! 1306:
! 1307: /* {{{ mysqlnd_zend_mm_efree */
! 1308: static void mysqlnd_zend_mm_efree(void * ptr MYSQLND_MEM_D)
! 1309: {
! 1310: efree(ptr);
! 1311: }
! 1312: /* }}} */
! 1313:
! 1314:
! 1315: /* {{{ mysqlnd_zend_mm_pefree */
! 1316: static void mysqlnd_zend_mm_pefree(void * ptr, zend_bool persistent MYSQLND_MEM_D)
! 1317: {
! 1318: pefree(ptr, persistent);
! 1319: }
! 1320: /* }}} */
! 1321:
! 1322:
! 1323: /* {{{ mysqlnd_zend_mm_malloc */
! 1324: static void * mysqlnd_zend_mm_malloc(size_t size MYSQLND_MEM_D)
! 1325: {
! 1326: return malloc(size);
! 1327: }
! 1328: /* }}} */
! 1329:
! 1330:
! 1331: /* {{{ mysqlnd_zend_mm_calloc */
! 1332: static void * mysqlnd_zend_mm_calloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
! 1333: {
! 1334: return calloc(nmemb, size);
! 1335: }
! 1336: /* }}} */
! 1337:
! 1338:
! 1339: /* {{{ mysqlnd_zend_mm_realloc */
! 1340: static void * mysqlnd_zend_mm_realloc(void * ptr, size_t new_size MYSQLND_MEM_D)
! 1341: {
! 1342: return realloc(ptr, new_size);
! 1343: }
! 1344: /* }}} */
! 1345:
! 1346:
! 1347: /* {{{ mysqlnd_zend_mm_free */
! 1348: static void mysqlnd_zend_mm_free(void * ptr MYSQLND_MEM_D)
! 1349: {
! 1350: free(ptr);
! 1351: }
! 1352: /* }}} */
! 1353:
! 1354:
! 1355: /* {{{ mysqlnd_zend_mm_pestrndup */
! 1356: static char * mysqlnd_zend_mm_pestrndup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D)
! 1357: {
! 1358: return pestrndup(ptr, length, persistent);
! 1359: }
! 1360: /* }}} */
! 1361:
! 1362:
! 1363: /* {{{ mysqlnd_zend_mm_pestrdup */
! 1364: static char * mysqlnd_zend_mm_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_MEM_D)
! 1365: {
! 1366: return pestrdup(ptr, persistent);
! 1367: }
! 1368: /* }}} */
! 1369:
! 1370: #endif
! 1371:
! 1372:
! 1373: PHPAPI struct st_mysqlnd_allocator_methods mysqlnd_allocator =
! 1374: {
! 1375: #if MYSQLND_DEBUG_MEMORY
! 1376: _mysqlnd_emalloc,
! 1377: _mysqlnd_pemalloc,
! 1378: _mysqlnd_ecalloc,
! 1379: _mysqlnd_pecalloc,
! 1380: _mysqlnd_erealloc,
! 1381: _mysqlnd_perealloc,
! 1382: _mysqlnd_efree,
! 1383: _mysqlnd_pefree,
! 1384: _mysqlnd_malloc,
! 1385: _mysqlnd_calloc,
! 1386: _mysqlnd_realloc,
! 1387: _mysqlnd_free,
! 1388: _mysqlnd_pestrndup,
! 1389: _mysqlnd_pestrdup
! 1390: #else
! 1391: mysqlnd_zend_mm_emalloc,
! 1392: mysqlnd_zend_mm_pemalloc,
! 1393: mysqlnd_zend_mm_ecalloc,
! 1394: mysqlnd_zend_mm_pecalloc,
! 1395: mysqlnd_zend_mm_erealloc,
! 1396: mysqlnd_zend_mm_perealloc,
! 1397: mysqlnd_zend_mm_efree,
! 1398: mysqlnd_zend_mm_pefree,
! 1399: mysqlnd_zend_mm_malloc,
! 1400: mysqlnd_zend_mm_calloc,
! 1401: mysqlnd_zend_mm_realloc,
! 1402: mysqlnd_zend_mm_free,
! 1403: mysqlnd_zend_mm_pestrndup,
! 1404: mysqlnd_zend_mm_pestrdup
! 1405: #endif
! 1406: };
! 1407:
! 1408:
! 1409:
! 1410: /* Follows code borrowed from zend_builtin_functions.c because the functions there are static */
! 1411:
! 1412: #if MYSQLND_UNICODE
! 1413: /* {{{ gettraceasstring() macros */
! 1414: #define TRACE_APPEND_CHR(chr) \
! 1415: *str = (char*)erealloc(*str, *len + 1 + 1); \
! 1416: (*str)[(*len)++] = chr
! 1417:
! 1418: #define TRACE_APPEND_STRL(val, vallen) \
! 1419: { \
! 1420: int l = vallen; \
! 1421: *str = (char*)erealloc(*str, *len + l + 1); \
! 1422: memcpy((*str) + *len, val, l); \
! 1423: *len += l; \
! 1424: }
! 1425:
! 1426: #define TRACE_APPEND_USTRL(val, vallen) \
! 1427: { \
! 1428: zval tmp, copy; \
! 1429: int use_copy; \
! 1430: ZVAL_UNICODEL(&tmp, val, vallen, 1); \
! 1431: zend_make_printable_zval(&tmp, ©, &use_copy); \
! 1432: TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
! 1433: zval_dtor(©); \
! 1434: zval_dtor(&tmp); \
! 1435: }
! 1436:
! 1437: #define TRACE_APPEND_ZVAL(zv) \
! 1438: if (Z_TYPE_P((zv)) == IS_UNICODE) { \
! 1439: zval copy; \
! 1440: int use_copy; \
! 1441: zend_make_printable_zval((zv), ©, &use_copy); \
! 1442: TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
! 1443: zval_dtor(©); \
! 1444: } else { \
! 1445: TRACE_APPEND_STRL(Z_STRVAL_P((zv)), Z_STRLEN_P((zv))); \
! 1446: }
! 1447:
! 1448: #define TRACE_APPEND_STR(val) \
! 1449: TRACE_APPEND_STRL(val, sizeof(val)-1)
! 1450:
! 1451: #define TRACE_APPEND_KEY(key) \
! 1452: if (zend_ascii_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
! 1453: if (Z_TYPE_PP(tmp) == IS_UNICODE) { \
! 1454: zval copy; \
! 1455: int use_copy; \
! 1456: zend_make_printable_zval(*tmp, ©, &use_copy); \
! 1457: TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
! 1458: zval_dtor(©); \
! 1459: } else { \
! 1460: TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \
! 1461: } \
! 1462: }
! 1463: /* }}} */
! 1464:
! 1465: /* {{{ mysqlnd_build_trace_args */
! 1466: static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
! 1467: {
! 1468: char **str;
! 1469: int *len;
! 1470:
! 1471: str = va_arg(args, char**);
! 1472: len = va_arg(args, int*);
! 1473:
! 1474: /* the trivial way would be to do:
! 1475: * conver_to_string_ex(arg);
! 1476: * append it and kill the now tmp arg.
! 1477: * but that could cause some E_NOTICE and also damn long lines.
! 1478: */
! 1479:
! 1480: switch (Z_TYPE_PP(arg)) {
! 1481: case IS_NULL:
! 1482: TRACE_APPEND_STR("NULL, ");
! 1483: break;
! 1484: case IS_STRING: {
! 1485: int l_added;
! 1486: TRACE_APPEND_CHR('\'');
! 1487: if (Z_STRLEN_PP(arg) > 15) {
! 1488: TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
! 1489: TRACE_APPEND_STR("...', ");
! 1490: l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
! 1491: } else {
! 1492: l_added = Z_STRLEN_PP(arg);
! 1493: TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
! 1494: TRACE_APPEND_STR("', ");
! 1495: l_added += 3 + 1;
! 1496: }
! 1497: while (--l_added) {
! 1498: if ((unsigned char)(*str)[*len - l_added] < 32) {
! 1499: (*str)[*len - l_added] = '?';
! 1500: }
! 1501: }
! 1502: break;
! 1503: }
! 1504: case IS_UNICODE: {
! 1505: int l_added;
! 1506:
! 1507: /*
! 1508: * We do not want to apply current error mode here, since
! 1509: * zend_make_printable_zval() uses output encoding converter.
! 1510: * Temporarily set output encoding converter to escape offending
! 1511: * chars with \uXXXX notation.
! 1512: */
! 1513: zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, ZEND_CONV_ERROR_ESCAPE_JAVA);
! 1514: TRACE_APPEND_CHR('\'');
! 1515: if (Z_USTRLEN_PP(arg) > 15) {
! 1516: TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), 15);
! 1517: TRACE_APPEND_STR("...', ");
! 1518: l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
! 1519: } else {
! 1520: l_added = Z_USTRLEN_PP(arg);
! 1521: TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), l_added);
! 1522: TRACE_APPEND_STR("', ");
! 1523: l_added += 3 + 1;
! 1524: }
! 1525: /*
! 1526: * Reset output encoding converter error mode.
! 1527: */
! 1528: zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, UG(from_error_mode));
! 1529: while (--l_added) {
! 1530: if ((unsigned char)(*str)[*len - l_added] < 32) {
! 1531: (*str)[*len - l_added] = '?';
! 1532: }
! 1533: }
! 1534: break;
! 1535: }
! 1536: case IS_BOOL:
! 1537: if (Z_LVAL_PP(arg)) {
! 1538: TRACE_APPEND_STR("true, ");
! 1539: } else {
! 1540: TRACE_APPEND_STR("false, ");
! 1541: }
! 1542: break;
! 1543: case IS_RESOURCE:
! 1544: TRACE_APPEND_STR("Resource id #");
! 1545: /* break; */
! 1546: case IS_LONG: {
! 1547: long lval = Z_LVAL_PP(arg);
! 1548: char s_tmp[MAX_LENGTH_OF_LONG + 1];
! 1549: int l_tmp = zend_sprintf(s_tmp, "%ld", lval); /* SAFE */
! 1550: TRACE_APPEND_STRL(s_tmp, l_tmp);
! 1551: TRACE_APPEND_STR(", ");
! 1552: break;
! 1553: }
! 1554: case IS_DOUBLE: {
! 1555: double dval = Z_DVAL_PP(arg);
! 1556: char *s_tmp;
! 1557: int l_tmp;
! 1558:
! 1559: s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
! 1560: l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval); /* SAFE */
! 1561: TRACE_APPEND_STRL(s_tmp, l_tmp);
! 1562: /* %G already handles removing trailing zeros from the fractional part, yay */
! 1563: efree(s_tmp);
! 1564: TRACE_APPEND_STR(", ");
! 1565: break;
! 1566: }
! 1567: case IS_ARRAY:
! 1568: TRACE_APPEND_STR("Array, ");
! 1569: break;
! 1570: case IS_OBJECT: {
! 1571: zval tmp;
! 1572: zstr class_name;
! 1573: zend_uint class_name_len;
! 1574: int dup;
! 1575:
! 1576: TRACE_APPEND_STR("Object(");
! 1577:
! 1578: dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
! 1579:
! 1580: ZVAL_UNICODEL(&tmp, class_name.u, class_name_len, 1);
! 1581: convert_to_string_with_converter(&tmp, ZEND_U_CONVERTER(UG(output_encoding_conv)));
! 1582: TRACE_APPEND_STRL(Z_STRVAL(tmp), Z_STRLEN(tmp));
! 1583: zval_dtor(&tmp);
! 1584:
! 1585: if(!dup) {
! 1586: efree(class_name.v);
! 1587: }
! 1588:
! 1589: TRACE_APPEND_STR("), ");
! 1590: break;
! 1591: }
! 1592: default:
! 1593: break;
! 1594: }
! 1595: return ZEND_HASH_APPLY_KEEP;
! 1596: }
! 1597: /* }}} */
! 1598:
! 1599:
! 1600: static int mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
! 1601: {
! 1602: char *s_tmp, **str;
! 1603: int *len, *num;
! 1604: long line;
! 1605: HashTable *ht = Z_ARRVAL_PP(frame);
! 1606: zval **file, **tmp;
! 1607: uint * level;
! 1608:
! 1609: level = va_arg(args, uint *);
! 1610: str = va_arg(args, char**);
! 1611: len = va_arg(args, int*);
! 1612: num = va_arg(args, int*);
! 1613:
! 1614: if (!*level) {
! 1615: return ZEND_HASH_APPLY_KEEP;
! 1616: }
! 1617: --*level;
! 1618:
! 1619: s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
! 1620: sprintf(s_tmp, "#%d ", (*num)++);
! 1621: TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
! 1622: efree(s_tmp);
! 1623: if (zend_ascii_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
! 1624: if (zend_ascii_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
! 1625: line = Z_LVAL_PP(tmp);
! 1626: } else {
! 1627: line = 0;
! 1628: }
! 1629: TRACE_APPEND_ZVAL(*file);
! 1630: s_tmp = emalloc(MAX_LENGTH_OF_LONG + 2 + 1);
! 1631: sprintf(s_tmp, "(%ld): ", line);
! 1632: TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
! 1633: efree(s_tmp);
! 1634: } else {
! 1635: TRACE_APPEND_STR("[internal function]: ");
! 1636: }
! 1637: TRACE_APPEND_KEY("class");
! 1638: TRACE_APPEND_KEY("type");
! 1639: TRACE_APPEND_KEY("function");
! 1640: TRACE_APPEND_CHR('(');
! 1641: if (zend_ascii_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
! 1642: int last_len = *len;
! 1643: zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
! 1644: if (last_len != *len) {
! 1645: *len -= 2; /* remove last ', ' */
! 1646: }
! 1647: }
! 1648: TRACE_APPEND_STR(")\n");
! 1649: return ZEND_HASH_APPLY_KEEP;
! 1650: }
! 1651: /* }}} */
! 1652:
! 1653:
! 1654: #else /* PHP 5*/
! 1655:
! 1656:
! 1657: /* {{{ gettraceasstring() macros */
! 1658: #define TRACE_APPEND_CHR(chr) \
! 1659: *str = (char*)erealloc(*str, *len + 1 + 1); \
! 1660: (*str)[(*len)++] = chr
! 1661:
! 1662: #define TRACE_APPEND_STRL(val, vallen) \
! 1663: { \
! 1664: int l = vallen; \
! 1665: *str = (char*)erealloc(*str, *len + l + 1); \
! 1666: memcpy((*str) + *len, val, l); \
! 1667: *len += l; \
! 1668: }
! 1669:
! 1670: #define TRACE_APPEND_STR(val) \
! 1671: TRACE_APPEND_STRL(val, sizeof(val)-1)
! 1672:
! 1673: #define TRACE_APPEND_KEY(key) \
! 1674: if (zend_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
! 1675: TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \
! 1676: }
! 1677:
! 1678: /* }}} */
! 1679:
! 1680:
! 1681: static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
! 1682: {
! 1683: char **str;
! 1684: int *len;
! 1685:
! 1686: str = va_arg(args, char**);
! 1687: len = va_arg(args, int*);
! 1688:
! 1689: /* the trivial way would be to do:
! 1690: * conver_to_string_ex(arg);
! 1691: * append it and kill the now tmp arg.
! 1692: * but that could cause some E_NOTICE and also damn long lines.
! 1693: */
! 1694:
! 1695: switch (Z_TYPE_PP(arg)) {
! 1696: case IS_NULL:
! 1697: TRACE_APPEND_STR("NULL, ");
! 1698: break;
! 1699: case IS_STRING: {
! 1700: int l_added;
! 1701: TRACE_APPEND_CHR('\'');
! 1702: if (Z_STRLEN_PP(arg) > 15) {
! 1703: TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
! 1704: TRACE_APPEND_STR("...', ");
! 1705: l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
! 1706: } else {
! 1707: l_added = Z_STRLEN_PP(arg);
! 1708: TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
! 1709: TRACE_APPEND_STR("', ");
! 1710: l_added += 3 + 1;
! 1711: }
! 1712: while (--l_added) {
! 1713: if ((*str)[*len - l_added] < 32) {
! 1714: (*str)[*len - l_added] = '?';
! 1715: }
! 1716: }
! 1717: break;
! 1718: }
! 1719: case IS_BOOL:
! 1720: if (Z_LVAL_PP(arg)) {
! 1721: TRACE_APPEND_STR("true, ");
! 1722: } else {
! 1723: TRACE_APPEND_STR("false, ");
! 1724: }
! 1725: break;
! 1726: case IS_RESOURCE:
! 1727: TRACE_APPEND_STR("Resource id #");
! 1728: /* break; */
! 1729: case IS_LONG: {
! 1730: long lval = Z_LVAL_PP(arg);
! 1731: char s_tmp[MAX_LENGTH_OF_LONG + 1];
! 1732: int l_tmp = zend_sprintf(s_tmp, "%ld", lval); /* SAFE */
! 1733: TRACE_APPEND_STRL(s_tmp, l_tmp);
! 1734: TRACE_APPEND_STR(", ");
! 1735: break;
! 1736: }
! 1737: case IS_DOUBLE: {
! 1738: double dval = Z_DVAL_PP(arg);
! 1739: char *s_tmp;
! 1740: int l_tmp;
! 1741:
! 1742: s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
! 1743: l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval); /* SAFE */
! 1744: TRACE_APPEND_STRL(s_tmp, l_tmp);
! 1745: /* %G already handles removing trailing zeros from the fractional part, yay */
! 1746: efree(s_tmp);
! 1747: TRACE_APPEND_STR(", ");
! 1748: break;
! 1749: }
! 1750: case IS_ARRAY:
! 1751: TRACE_APPEND_STR("Array, ");
! 1752: break;
! 1753: case IS_OBJECT: {
! 1754: char *class_name;
! 1755: zend_uint class_name_len;
! 1756: int dupl;
! 1757:
! 1758: TRACE_APPEND_STR("Object(");
! 1759:
! 1760: dupl = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
! 1761:
! 1762: TRACE_APPEND_STRL(class_name, class_name_len);
! 1763: if (!dupl) {
! 1764: efree(class_name);
! 1765: }
! 1766:
! 1767: TRACE_APPEND_STR("), ");
! 1768: break;
! 1769: }
! 1770: default:
! 1771: break;
! 1772: }
! 1773: return ZEND_HASH_APPLY_KEEP;
! 1774: }
! 1775: /* }}} */
! 1776:
! 1777: static int mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
! 1778: {
! 1779: char *s_tmp, **str;
! 1780: int *len, *num;
! 1781: long line;
! 1782: HashTable *ht = Z_ARRVAL_PP(frame);
! 1783: zval **file, **tmp;
! 1784: uint * level;
! 1785:
! 1786: level = va_arg(args, uint *);
! 1787: str = va_arg(args, char**);
! 1788: len = va_arg(args, int*);
! 1789: num = va_arg(args, int*);
! 1790:
! 1791: if (!*level) {
! 1792: return ZEND_HASH_APPLY_KEEP;
! 1793: }
! 1794: --*level;
! 1795:
! 1796: s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
! 1797: sprintf(s_tmp, "#%d ", (*num)++);
! 1798: TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
! 1799: efree(s_tmp);
! 1800: if (zend_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
! 1801: if (zend_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
! 1802: line = Z_LVAL_PP(tmp);
! 1803: } else {
! 1804: line = 0;
! 1805: }
! 1806: s_tmp = emalloc(Z_STRLEN_PP(file) + MAX_LENGTH_OF_LONG + 4 + 1);
! 1807: sprintf(s_tmp, "%s(%ld): ", Z_STRVAL_PP(file), line);
! 1808: TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
! 1809: efree(s_tmp);
! 1810: } else {
! 1811: TRACE_APPEND_STR("[internal function]: ");
! 1812: }
! 1813: TRACE_APPEND_KEY("class");
! 1814: TRACE_APPEND_KEY("type");
! 1815: TRACE_APPEND_KEY("function");
! 1816: TRACE_APPEND_CHR('(');
! 1817: if (zend_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
! 1818: int last_len = *len;
! 1819: zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
! 1820: if (last_len != *len) {
! 1821: *len -= 2; /* remove last ', ' */
! 1822: }
! 1823: }
! 1824: TRACE_APPEND_STR(")\n");
! 1825: return ZEND_HASH_APPLY_KEEP;
! 1826: }
! 1827: /* }}} */
! 1828: #endif
! 1829:
! 1830:
! 1831: PHPAPI char * mysqlnd_get_backtrace(uint max_levels, size_t * length TSRMLS_DC)
! 1832: {
! 1833: zval *trace;
! 1834: char *res = estrdup(""), **str = &res, *s_tmp;
! 1835: int res_len = 0, *len = &res_len, num = 0;
! 1836: if (max_levels == 0) {
! 1837: max_levels = 99999;
! 1838: }
! 1839:
! 1840: MAKE_STD_ZVAL(trace);
! 1841: zend_fetch_debug_backtrace(trace, 0, 0 TSRMLS_CC);
! 1842:
! 1843: 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);
! 1844: zval_ptr_dtor(&trace);
! 1845:
! 1846: if (max_levels) {
! 1847: s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1);
! 1848: sprintf(s_tmp, "#%d {main}", num);
! 1849: TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
! 1850: efree(s_tmp);
! 1851: }
! 1852:
! 1853: res[res_len] = '\0';
! 1854: *length = res_len;
! 1855:
! 1856: return res;
! 1857: }
! 1858:
! 1859: /*
! 1860: * Local variables:
! 1861: * tab-width: 4
! 1862: * c-basic-offset: 4
! 1863: * End:
! 1864: * vim600: noet sw=4 ts=4 fdm=marker
! 1865: * vim<600: noet sw=4 ts=4
! 1866: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>