Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_bt.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 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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>