utrace.cpp 16 KB

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