Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_bt.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | PHP Version 5                                                        |
                      4:   +----------------------------------------------------------------------+
1.1.1.2 ! misho       5:   | Copyright (c) 2006-2013 The PHP Group                                |
1.1       misho       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>