Coverage Report

Created: 2023-06-07 07:17

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