tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

utrace.cpp (16357B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 *   Copyright (C) 2003-2014, International Business Machines
      6 *   Corporation and others.  All Rights Reserved.
      7 *******************************************************************************
      8 *   file name:  utrace.c
      9 *   encoding:   UTF-8
     10 *   tab size:   8 (not used)
     11 *   indentation:4
     12 */
     13 
     14 #include "unicode/utrace.h"
     15 #include "utracimp.h"
     16 #include "cstring.h"
     17 #include "uassert.h"
     18 #include "ucln_cmn.h"
     19 
     20 
     21 static UTraceEntry     *pTraceEntryFunc = nullptr;
     22 static UTraceExit      *pTraceExitFunc  = nullptr;
     23 static UTraceData      *pTraceDataFunc  = nullptr;
     24 static const void      *gTraceContext   = nullptr;
     25 
     26 /**
     27 * \var utrace_level
     28 * Trace level variable. Negative for "off".
     29 */
     30 static int32_t
     31 utrace_level = UTRACE_ERROR;
     32 
     33 U_CAPI void U_EXPORT2
     34 utrace_entry(int32_t fnNumber) {
     35    if (pTraceEntryFunc != nullptr) {
     36        (*pTraceEntryFunc)(gTraceContext, fnNumber);
     37    }
     38 }
     39 
     40 
     41 static const char gExitFmt[]             = "Returns.";
     42 static const char gExitFmtValue[]        = "Returns %d.";
     43 static const char gExitFmtStatus[]       = "Returns.  Status = %d.";
     44 static const char gExitFmtValueStatus[]  = "Returns %d.  Status = %d.";
     45 static const char gExitFmtPtrStatus[]    = "Returns %d.  Status = %p.";
     46 
     47 U_CAPI void U_EXPORT2
     48 utrace_exit(int32_t fnNumber, int32_t returnType, ...) {
     49    if (pTraceExitFunc != nullptr) {
     50        va_list     args;
     51        const char *fmt;
     52 
     53        switch (returnType) {
     54        case 0:
     55            fmt = gExitFmt;
     56            break;
     57        case UTRACE_EXITV_I32:
     58            fmt = gExitFmtValue;
     59            break;
     60        case UTRACE_EXITV_STATUS:
     61            fmt = gExitFmtStatus;
     62            break;
     63        case UTRACE_EXITV_I32 | UTRACE_EXITV_STATUS:
     64            fmt = gExitFmtValueStatus;
     65            break;
     66        case UTRACE_EXITV_PTR | UTRACE_EXITV_STATUS:
     67            fmt = gExitFmtPtrStatus;
     68            break;
     69        default:
     70            UPRV_UNREACHABLE_EXIT;
     71        }
     72 
     73        va_start(args, returnType);
     74        (*pTraceExitFunc)(gTraceContext, fnNumber, fmt, args);
     75        va_end(args);
     76    }
     77 }
     78 
     79 
     80 
     81 U_CAPI void U_EXPORT2 
     82 utrace_data(int32_t fnNumber, int32_t level, const char *fmt, ...) {
     83    if (pTraceDataFunc != nullptr) {
     84           va_list args;
     85           va_start(args, fmt ); 
     86           (*pTraceDataFunc)(gTraceContext, fnNumber, level, fmt, args);
     87           va_end(args);
     88    }
     89 }
     90 
     91 
     92 static void outputChar(char c, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) {
     93    int32_t i;
     94    /* Check whether a start of line indenting is needed.  Three cases:
     95     *   1.  At the start of the first line  (output index == 0).
     96     *   2.  At the start of subsequent lines  (preceding char in buffer == '\n')
     97     *   3.  When preflighting buffer len (buffer capacity is exceeded), when
     98     *       a \n is output.  Ideally we wouldn't do the indent until the following char
     99     *       is received, but that won't work because there's no place to remember that
    100     *       the preceding char was \n.  Meaning that we may overstimate the
    101     *       buffer size needed.  No harm done.
    102     */
    103    if (*outIx==0 ||   /* case 1. */
    104        (c!='\n' && c!=0 && *outIx < capacity && outBuf[(*outIx)-1]=='\n') ||  /* case 2. */
    105        (c=='\n' && *outIx>=capacity))    /* case 3 */
    106    {
    107        /* At the start of a line.  Indent. */
    108        for(i=0; i<indent; i++) {
    109            if (*outIx < capacity) {
    110                outBuf[*outIx] = ' ';
    111            }
    112            (*outIx)++;
    113        }
    114    }
    115 
    116    if (*outIx < capacity) {
    117        outBuf[*outIx] = c;
    118    }
    119    if (c != 0) {
    120        /* NULs only appear as end-of-string terminators.  Move them to the output
    121         *  buffer, but do not update the length of the buffer, so that any
    122         *  following output will overwrite the NUL. */
    123        (*outIx)++;
    124    }
    125 }
    126 
    127 static void outputHexBytes(int64_t val, int32_t charsToOutput,
    128                           char *outBuf, int32_t *outIx, int32_t capacity) {
    129    static const char gHexChars[] = "0123456789abcdef";
    130    int32_t shiftCount;
    131    for  (shiftCount=(charsToOutput-1)*4; shiftCount >= 0; shiftCount-=4) {
    132        char c = gHexChars[(val >> shiftCount) & 0xf];
    133        outputChar(c, outBuf, outIx, capacity, 0);
    134    }
    135 }
    136 
    137 /* Output a pointer value in hex.  Work with any size of pointer   */
    138 static void outputPtrBytes(void *val, char *outBuf, int32_t *outIx, int32_t capacity) {
    139    uint32_t  i;
    140    int32_t  incVal = 1;              /* +1 for big endian, -1 for little endian          */
    141    char* p = reinterpret_cast<char*>(&val); /* point to current byte to output in the ptr val  */
    142 
    143 #if !U_IS_BIG_ENDIAN
    144    /* Little Endian.  Move p to most significant end of the value      */
    145    incVal = -1;
    146    p += sizeof(void *) - 1;
    147 #endif
    148 
    149    /* Loop through the bytes of the ptr as it sits in memory, from 
    150     * most significant to least significant end                    */
    151    for (i=0; i<sizeof(void *); i++) {
    152        outputHexBytes(*p, 2, outBuf, outIx, capacity);
    153        p += incVal;
    154    }
    155 }
    156 
    157 static void outputString(const char *s, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) {
    158    int32_t i = 0;
    159    char    c;
    160    if (s==nullptr) {
    161        s = "*NULL*";
    162    }
    163    do {
    164        c = s[i++];
    165        outputChar(c, outBuf, outIx, capacity, indent);
    166    } while (c != 0);
    167 }
    168        
    169 
    170 
    171 static void outputUString(const char16_t *s, int32_t len,
    172                          char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) {
    173    int32_t i = 0;
    174    char16_t   c;
    175    if (s==nullptr) {
    176        outputString(nullptr, outBuf, outIx, capacity, indent);
    177        return;
    178    }
    179 
    180    for (i=0; i<len || len==-1; i++) {
    181        c = s[i];
    182        outputHexBytes(c, 4, outBuf, outIx, capacity);
    183        outputChar(' ', outBuf, outIx, capacity, indent);
    184        if (len == -1 && c==0) {
    185            break;
    186        }
    187    }
    188 }
    189        
    190 U_CAPI int32_t U_EXPORT2
    191 utrace_vformat(char *outBuf, int32_t capacity, int32_t indent, const char *fmt, va_list args) {
    192    int32_t   outIx  = 0;
    193    int32_t   fmtIx  = 0;
    194    char      fmtC;
    195    char      c;
    196    int32_t   intArg;
    197    int64_t   longArg = 0;
    198    char      *ptrArg;
    199 
    200    /*   Loop runs once for each character in the format string.
    201     */
    202    for (;;) {
    203        fmtC = fmt[fmtIx++];
    204        if (fmtC != '%') {
    205            /* Literal character, not part of a %sequence.  Just copy it to the output. */
    206            outputChar(fmtC, outBuf, &outIx, capacity, indent);
    207            if (fmtC == 0) {
    208                /* We hit the NUL that terminates the format string.
    209                 * This is the normal (and only) exit from the loop that
    210                 * interprets the format
    211                 */
    212                break;
    213            }
    214            continue;
    215        }
    216 
    217        /* We encountered a '%'.  Pick up the following format char */
    218        fmtC = fmt[fmtIx++];
    219 
    220        switch (fmtC) {
    221        case 'c':
    222            /* single 8 bit char   */
    223            c = (char)va_arg(args, int32_t);
    224            outputChar(c, outBuf, &outIx, capacity, indent);
    225            break;
    226 
    227        case 's':
    228            /* char * string, NUL terminated.  */
    229            ptrArg = va_arg(args, char *);
    230            outputString((const char *)ptrArg, outBuf, &outIx, capacity, indent);
    231            break;
    232 
    233        case 'S':
    234            /* char16_t * string, with length, len==-1 for NUL terminated. */
    235            ptrArg = va_arg(args, char *);             /* Ptr    */
    236            intArg = va_arg(args, int32_t);            /* Length */
    237            outputUString((const char16_t *)ptrArg, intArg, outBuf, &outIx, capacity, indent);
    238            break;
    239 
    240        case 'b':
    241            /*  8 bit int  */
    242            intArg = va_arg(args, int);
    243            outputHexBytes(intArg, 2, outBuf, &outIx, capacity);
    244            break;
    245 
    246        case 'h':
    247            /*  16 bit int  */
    248            intArg = va_arg(args, int);
    249            outputHexBytes(intArg, 4, outBuf, &outIx, capacity);
    250            break;
    251 
    252        case 'd':
    253            /*  32 bit int  */
    254            intArg = va_arg(args, int);
    255            outputHexBytes(intArg, 8, outBuf, &outIx, capacity);
    256            break;
    257 
    258        case 'l':
    259            /*  64 bit long  */
    260            longArg = va_arg(args, int64_t);
    261            outputHexBytes(longArg, 16, outBuf, &outIx, capacity);
    262            break;
    263            
    264        case 'p':
    265            /*  Pointers.   */
    266            ptrArg = va_arg(args, char *);
    267            outputPtrBytes(ptrArg, outBuf, &outIx, capacity);
    268            break;
    269 
    270        case 0:
    271            /* Single '%' at end of fmt string.  Output as literal '%'.   
    272             * Back up index into format string so that the terminating NUL will be
    273             * re-fetched in the outer loop, causing it to terminate.
    274             */
    275            outputChar('%', outBuf, &outIx, capacity, indent);
    276            fmtIx--;
    277            break;
    278 
    279        case 'v':
    280            {
    281                /* Vector of values, e.g. %vh */
    282                char     vectorType;
    283                int32_t  vectorLen;
    284                const char   *i8Ptr;
    285                int16_t  *i16Ptr;
    286                int32_t  *i32Ptr;
    287                int64_t  *i64Ptr;
    288                void     **ptrPtr;
    289                int32_t   charsToOutput = 0;
    290                int32_t   i;
    291                
    292                vectorType = fmt[fmtIx];    /* b, h, d, l, p, etc. */
    293                if (vectorType != 0) {
    294                    fmtIx++;
    295                }
    296                i8Ptr = (const char *)va_arg(args, void*);
    297                i16Ptr = (int16_t *)i8Ptr;
    298                i32Ptr = (int32_t *)i8Ptr;
    299                i64Ptr = (int64_t *)i8Ptr;
    300                ptrPtr = (void **)i8Ptr;
    301                vectorLen = va_arg(args, int32_t);
    302                if (ptrPtr == nullptr) {
    303                    outputString("*NULL* ", outBuf, &outIx, capacity, indent);
    304                } else {
    305                    for (i=0; i<vectorLen || vectorLen==-1; i++) { 
    306                        switch (vectorType) {
    307                        case 'b':
    308                            charsToOutput = 2;
    309                            longArg = *i8Ptr++;
    310                            break;
    311                        case 'h':
    312                            charsToOutput = 4;
    313                            longArg = *i16Ptr++;
    314                            break;
    315                        case 'd':
    316                            charsToOutput = 8;
    317                            longArg = *i32Ptr++;
    318                            break;
    319                        case 'l':
    320                            charsToOutput = 16;
    321                            longArg = *i64Ptr++;
    322                            break;
    323                        case 'p':
    324                            charsToOutput = 0;
    325                            outputPtrBytes(*ptrPtr, outBuf, &outIx, capacity);
    326                            longArg = *ptrPtr==nullptr? 0: 1;    /* test for nullptr terminated array. */
    327                            ptrPtr++;
    328                            break;
    329                        case 'c':
    330                            charsToOutput = 0;
    331                            outputChar(*i8Ptr, outBuf, &outIx, capacity, indent);
    332                            longArg = *i8Ptr;    /* for test for nullptr terminated array. */
    333                            i8Ptr++;
    334                            break;
    335                        case 's':
    336                            charsToOutput = 0;
    337                            outputString((const char *)*ptrPtr, outBuf, &outIx, capacity, indent);
    338                            outputChar('\n', outBuf, &outIx, capacity, indent);
    339                            longArg = *ptrPtr==nullptr? 0: 1;   /* for test for nullptr term. array. */
    340                            ptrPtr++;
    341                            break;
    342 
    343                        case 'S':
    344                            charsToOutput = 0;
    345                            outputUString((const char16_t *)*ptrPtr, -1, outBuf, &outIx, capacity, indent);
    346                            outputChar('\n', outBuf, &outIx, capacity, indent);
    347                            longArg = *ptrPtr==nullptr? 0: 1;   /* for test for nullptr term. array. */
    348                            ptrPtr++;
    349                            break;
    350 
    351                            
    352                        }
    353                        if (charsToOutput > 0) {
    354                            outputHexBytes(longArg, charsToOutput, outBuf, &outIx, capacity);
    355                            outputChar(' ', outBuf, &outIx, capacity, indent);
    356                        }
    357                        if (vectorLen == -1 && longArg == 0) {
    358                            break;
    359                        }
    360                    }
    361                }
    362                outputChar('[', outBuf, &outIx, capacity, indent);
    363                outputHexBytes(vectorLen, 8, outBuf, &outIx, capacity);
    364                outputChar(']', outBuf, &outIx, capacity, indent);
    365            }
    366            break;
    367 
    368 
    369        default:
    370            /* %. in format string, where . is some character not in the set
    371             *    of recognized format chars.  Just output it as if % wasn't there.
    372             *    (Covers "%%" outputting a single '%')
    373             */
    374             outputChar(fmtC, outBuf, &outIx, capacity, indent);
    375        }
    376    }
    377    outputChar(0, outBuf, &outIx, capacity, indent);  /* Make sure that output is NUL terminated   */
    378    return outIx + 1;     /* outIx + 1 because outIx does not increment when outputting final NUL. */
    379 }
    380 
    381 
    382 
    383 
    384 U_CAPI int32_t U_EXPORT2
    385 utrace_format(char *outBuf, int32_t capacity,
    386                int32_t indent, const char *fmt,  ...) {
    387    int32_t retVal;
    388    va_list args;
    389    va_start(args, fmt ); 
    390    retVal = utrace_vformat(outBuf, capacity, indent, fmt, args);
    391    va_end(args);
    392    return retVal;
    393 }
    394 
    395 
    396 U_CAPI void U_EXPORT2
    397 utrace_setFunctions(const void *context,
    398                    UTraceEntry *e, UTraceExit *x, UTraceData *d) {
    399    pTraceEntryFunc = e;
    400    pTraceExitFunc  = x;
    401    pTraceDataFunc  = d;
    402    gTraceContext   = context;
    403 }
    404 
    405 
    406 U_CAPI void U_EXPORT2
    407 utrace_getFunctions(const void **context,
    408                    UTraceEntry **e, UTraceExit **x, UTraceData **d) {
    409    *e = pTraceEntryFunc;
    410    *x = pTraceExitFunc;
    411    *d = pTraceDataFunc;
    412    *context = gTraceContext;
    413 }
    414 
    415 U_CAPI void U_EXPORT2
    416 utrace_setLevel(int32_t level) {
    417    if (level < UTRACE_OFF) {
    418        level = UTRACE_OFF;
    419    }
    420    if (level > UTRACE_VERBOSE) {
    421        level = UTRACE_VERBOSE;
    422    }
    423    utrace_level = level;
    424 }
    425 
    426 U_CAPI int32_t U_EXPORT2
    427 utrace_getLevel() {
    428    return utrace_level;
    429 }
    430 
    431 
    432 U_CFUNC UBool 
    433 utrace_cleanup() {
    434    pTraceEntryFunc = nullptr;
    435    pTraceExitFunc  = nullptr;
    436    pTraceDataFunc  = nullptr;
    437    utrace_level    = UTRACE_OFF;
    438    gTraceContext   = nullptr;
    439    return true;
    440 }
    441 
    442 
    443 static const char * const
    444 trFnName[] = {
    445    "u_init",
    446    "u_cleanup",
    447    nullptr
    448 };
    449 
    450 
    451 static const char * const
    452 trConvNames[] = {
    453    "ucnv_open",
    454    "ucnv_openPackage",
    455    "ucnv_openAlgorithmic",
    456    "ucnv_clone",
    457    "ucnv_close",
    458    "ucnv_flushCache",
    459    "ucnv_load",
    460    "ucnv_unload",
    461    nullptr
    462 };
    463 
    464    
    465 static const char * const
    466 trCollNames[] = {
    467    "ucol_open",
    468    "ucol_close",
    469    "ucol_strcoll",
    470    "ucol_getSortKey",
    471    "ucol_getLocale",
    472    "ucol_nextSortKeyPart",
    473    "ucol_strcollIter",
    474    "ucol_openFromShortString",
    475    "ucol_strcollUTF8",
    476    nullptr
    477 };
    478 
    479 
    480 static const char* const
    481 trResDataNames[] = {
    482    "resc",
    483    "bundle-open",
    484    "file-open",
    485    "res-open",
    486    nullptr
    487 };
    488 
    489                
    490 U_CAPI const char * U_EXPORT2
    491 utrace_functionName(int32_t fnNumber) {
    492    if(UTRACE_FUNCTION_START <= fnNumber && fnNumber < UTRACE_FUNCTION_LIMIT) {
    493        return trFnName[fnNumber];
    494    } else if(UTRACE_CONVERSION_START <= fnNumber && fnNumber < UTRACE_CONVERSION_LIMIT) {
    495        return trConvNames[fnNumber - UTRACE_CONVERSION_START];
    496    } else if(UTRACE_COLLATION_START <= fnNumber && fnNumber < UTRACE_COLLATION_LIMIT){
    497        return trCollNames[fnNumber - UTRACE_COLLATION_START];
    498    } else if(UTRACE_UDATA_START <= fnNumber && fnNumber < UTRACE_RES_DATA_LIMIT){
    499        return trResDataNames[fnNumber - UTRACE_UDATA_START];
    500    } else {
    501        return "[BOGUS Trace Function Number]";
    502    }
    503 }