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, &copy, &use_copy); \
        !            48:                TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
        !            49:                zval_dtor(&copy); \
        !            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), &copy, &use_copy); \
        !            58:                TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
        !            59:                zval_dtor(&copy); \
        !            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, &copy, &use_copy); \
        !            73:                        TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
        !            74:                        zval_dtor(&copy); \
        !            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>