StackTrace.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*******************************************************************************
  2. * Copyright (c) 2009, 2022 IBM Corp.
  3. *
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v2.0
  6. * and Eclipse Distribution License v1.0 which accompany this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. * https://www.eclipse.org/legal/epl-2.0/
  10. * and the Eclipse Distribution License is available at
  11. * http://www.eclipse.org/org/documents/edl-v10.php.
  12. *
  13. * Contributors:
  14. * Ian Craggs - initial API and implementation and/or initial documentation
  15. *******************************************************************************/
  16. #include "StackTrace.h"
  17. #include "Log.h"
  18. #include "LinkedList.h"
  19. #include "Clients.h"
  20. #include "Thread.h"
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #if defined(_WIN32) || defined(_WIN64)
  25. #define snprintf _snprintf
  26. #endif
  27. /*BE
  28. def STACKENTRY
  29. {
  30. n32 ptr STRING open "name"
  31. n32 dec "line"
  32. }
  33. defList(STACKENTRY)
  34. BE*/
  35. #define MAX_STACK_DEPTH 50
  36. #define MAX_FUNCTION_NAME_LENGTH 30
  37. #define MAX_THREADS 255
  38. typedef struct
  39. {
  40. thread_id_type threadid;
  41. char name[MAX_FUNCTION_NAME_LENGTH];
  42. int line;
  43. } stackEntry;
  44. typedef struct
  45. {
  46. thread_id_type id;
  47. int maxdepth;
  48. int current_depth;
  49. stackEntry callstack[MAX_STACK_DEPTH];
  50. } threadEntry;
  51. #include "StackTrace.h"
  52. #if !defined(NOSTACKTRACE)
  53. static int thread_count = 0;
  54. static threadEntry threads[MAX_THREADS];
  55. static threadEntry *my_thread = NULL;
  56. #if defined(_WIN32) || defined(_WIN64)
  57. mutex_type stack_mutex;
  58. #else
  59. static pthread_mutex_t stack_mutex_store = PTHREAD_MUTEX_INITIALIZER;
  60. static mutex_type stack_mutex = &stack_mutex_store;
  61. #endif
  62. int setStack(int create);
  63. int setStack(int create)
  64. {
  65. int i = -1;
  66. thread_id_type curid = Thread_getid();
  67. my_thread = NULL;
  68. for (i = 0; i < MAX_THREADS && i < thread_count; ++i)
  69. {
  70. if (threads[i].id == curid)
  71. {
  72. my_thread = &threads[i];
  73. break;
  74. }
  75. }
  76. if (my_thread == NULL && create && thread_count < MAX_THREADS)
  77. {
  78. my_thread = &threads[thread_count];
  79. my_thread->id = curid;
  80. my_thread->maxdepth = 0;
  81. my_thread->current_depth = 0;
  82. ++thread_count;
  83. }
  84. return my_thread != NULL; /* good == 1 */
  85. }
  86. void StackTrace_entry(const char* name, int line, enum LOG_LEVELS trace_level)
  87. {
  88. Thread_lock_mutex(stack_mutex);
  89. if (!setStack(1))
  90. goto exit;
  91. if (trace_level != -1)
  92. Log_stackTrace(trace_level, 9, my_thread->id, my_thread->current_depth, name, line, NULL);
  93. strncpy(my_thread->callstack[my_thread->current_depth].name, name, sizeof(my_thread->callstack[0].name)-1);
  94. my_thread->callstack[(my_thread->current_depth)++].line = line;
  95. if (my_thread->current_depth > my_thread->maxdepth)
  96. my_thread->maxdepth = my_thread->current_depth;
  97. if (my_thread->current_depth >= MAX_STACK_DEPTH)
  98. Log(LOG_FATAL, -1, "Max stack depth exceeded");
  99. exit:
  100. Thread_unlock_mutex(stack_mutex);
  101. }
  102. void StackTrace_exit(const char* name, int line, void* rc, enum LOG_LEVELS trace_level)
  103. {
  104. Thread_lock_mutex(stack_mutex);
  105. if (!setStack(0))
  106. goto exit;
  107. if (--(my_thread->current_depth) < 0)
  108. Log(LOG_FATAL, -1, "Minimum stack depth exceeded for thread %lu", my_thread->id);
  109. if (strncmp(my_thread->callstack[my_thread->current_depth].name, name, sizeof(my_thread->callstack[0].name)-1) != 0)
  110. Log(LOG_FATAL, -1, "Stack mismatch. Entry:%s Exit:%s\n", my_thread->callstack[my_thread->current_depth].name, name);
  111. if (trace_level != -1)
  112. {
  113. if (rc == NULL)
  114. Log_stackTrace(trace_level, 10, my_thread->id, my_thread->current_depth, name, line, NULL);
  115. else
  116. Log_stackTrace(trace_level, 11, my_thread->id, my_thread->current_depth, name, line, (int*)rc);
  117. }
  118. exit:
  119. Thread_unlock_mutex(stack_mutex);
  120. }
  121. void StackTrace_printStack(FILE* dest)
  122. {
  123. FILE* file = stdout;
  124. int t = 0;
  125. if (dest)
  126. file = dest;
  127. for (t = 0; t < thread_count; ++t)
  128. {
  129. threadEntry *cur_thread = &threads[t];
  130. if (cur_thread->id > 0)
  131. {
  132. int i = cur_thread->current_depth - 1;
  133. fprintf(file, "=========== Start of stack trace for thread %lu ==========\n", (unsigned long)cur_thread->id);
  134. if (i >= 0)
  135. {
  136. fprintf(file, "%s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
  137. while (--i >= 0)
  138. fprintf(file, " at %s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
  139. }
  140. fprintf(file, "=========== End of stack trace for thread %lu ==========\n\n", (unsigned long)cur_thread->id);
  141. }
  142. }
  143. if (file != stdout && file != stderr && file != NULL)
  144. fclose(file);
  145. }
  146. char* StackTrace_get(thread_id_type threadid, char* buf, int bufsize)
  147. {
  148. int t = 0;
  149. if (bufsize < 100)
  150. goto exit;
  151. buf[0] = '\0';
  152. for (t = 0; t < thread_count; ++t)
  153. {
  154. threadEntry *cur_thread = &threads[t];
  155. if (cur_thread->id == threadid)
  156. {
  157. int i = cur_thread->current_depth - 1;
  158. int curpos = 0;
  159. if (i >= 0)
  160. {
  161. curpos += snprintf(&buf[curpos], bufsize - curpos -1,
  162. "%s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
  163. while (--i >= 0)
  164. curpos += snprintf(&buf[curpos], bufsize - curpos -1, /* lgtm [cpp/overflowing-snprintf] */
  165. " at %s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
  166. if (buf[--curpos] == '\n')
  167. buf[curpos] = '\0';
  168. }
  169. break;
  170. }
  171. }
  172. exit:
  173. return buf;
  174. }
  175. #endif