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