StackTrace.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #include "StackTrace.h"
  2. #include <csignal>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #define cstr(x) x,sizeof(x)-1
  6. void StackTrace::AppendString(const char *input,int input_length,char *output_buffer,int max_buffer_length,int &bytes_in_buffer)
  7. {
  8. if ((input_length+bytes_in_buffer < max_buffer_length) && (output_buffer != nullptr))
  9. {
  10. memcpy(output_buffer+bytes_in_buffer,input,input_length);
  11. }
  12. bytes_in_buffer += input_length;
  13. return;
  14. }
  15. void StackTrace::AppendString(const char *input,char *output_buffer,int max_buffer_length,int &bytes_in_buffer)
  16. {
  17. char ch;
  18. if (output_buffer == nullptr) {
  19. while (true) {
  20. ch = *(input++);
  21. if (ch==0) {
  22. break;
  23. }
  24. bytes_in_buffer++;
  25. }
  26. } else {
  27. while (true) {
  28. ch = *(input++);
  29. if (ch == 0) {
  30. break;
  31. }
  32. if (bytes_in_buffer < max_buffer_length) {
  33. output_buffer[bytes_in_buffer] = ch;
  34. }
  35. bytes_in_buffer++;
  36. }
  37. }
  38. return;
  39. }
  40. int StackTrace::ToString(char *output_buffer,int max_buffer_length)
  41. {
  42. // Converts the stack trace to a string. Returns the length of the data.
  43. // If output_buffer is nullptr or too small, the actual needed length is returned.
  44. int lineNumberIndex;
  45. const char *file_name;
  46. const char *function_name;
  47. char buffer[40];
  48. int length;
  49. int bytes_in_buffer = 0;
  50. int lineNumber;
  51. // Show the stack trace:
  52. if (LineNumberStack < 0)
  53. {
  54. LineNumberStack = 0;
  55. }
  56. if (LineNumberStack > CALL_STACK_SIZE)
  57. {
  58. LineNumberStack = CALL_STACK_SIZE;
  59. }
  60. for(lineNumberIndex=0;lineNumberIndex<LineNumberStack;lineNumberIndex++)
  61. {
  62. lineNumber = SavedLineNumbers[lineNumberIndex];
  63. if (lineNumber != 0)
  64. {
  65. AppendString(cstr("\n"),output_buffer,max_buffer_length,bytes_in_buffer);
  66. file_name = FileNames[lineNumberIndex];
  67. if (file_name !=nullptr) {
  68. AppendString(cstr(" in file "),output_buffer,max_buffer_length,bytes_in_buffer);
  69. file_name = basename(file_name);
  70. AppendString(file_name,output_buffer,max_buffer_length,bytes_in_buffer);
  71. }
  72. function_name = FunctionNames[lineNumberIndex];
  73. if (function_name != nullptr) {
  74. AppendString(cstr(" in function "),output_buffer,max_buffer_length,bytes_in_buffer);
  75. AppendString(function_name,output_buffer,max_buffer_length,bytes_in_buffer);
  76. }
  77. AppendString(cstr(" in line "),output_buffer,max_buffer_length,bytes_in_buffer);
  78. length = Itoa(lineNumber,buffer);
  79. AppendString(buffer,length,output_buffer,max_buffer_length,bytes_in_buffer);
  80. }
  81. }
  82. if (buffer != nullptr) {
  83. buffer[bytes_in_buffer < max_buffer_length ? bytes_in_buffer : max_buffer_length-1] = 0;
  84. }
  85. return bytes_in_buffer;
  86. }
  87. void StackTrace::DisplayErrorMessage(const char *message,int message_length)
  88. {
  89. int lineNumberIndex;
  90. const char *file_name;
  91. const char *function_name;
  92. char buffer[40];
  93. int length;
  94. int lineNumber;
  95. if ((message == nullptr) || (message_length <=0)) {
  96. printf("Error");
  97. } else {
  98. printf("%s",message);
  99. }
  100. // Show the stack trace:
  101. if (LineNumberStack < 0)
  102. {
  103. LineNumberStack = 0;
  104. }
  105. if (LineNumberStack > CALL_STACK_SIZE)
  106. {
  107. LineNumberStack = CALL_STACK_SIZE;
  108. }
  109. for(lineNumberIndex=0;lineNumberIndex<LineNumberStack;lineNumberIndex++)
  110. {
  111. lineNumber = SavedLineNumbers[lineNumberIndex];
  112. if (lineNumber != 0)
  113. {
  114. printf("\n");
  115. file_name = FileNames[lineNumberIndex];
  116. if (file_name != nullptr) {
  117. file_name = basename(file_name);
  118. printf(" in file %s",file_name);
  119. }
  120. function_name = FunctionNames[lineNumberIndex];
  121. if (function_name != nullptr) {
  122. printf(" in function %s",function_name);
  123. }
  124. printf(" in line %d",lineNumber);
  125. }
  126. }
  127. printf("\n");
  128. return;
  129. }
  130. void StackTrace::DisplayErrorMessage(int val)
  131. {
  132. const char *error;
  133. int error_length;
  134. // Show the error description based on the signal number:
  135. switch (val) {
  136. case SIGFPE: {
  137. error = "Division by zero error";
  138. error_length = 22;
  139. break; }
  140. case SIGILL: {
  141. error = "Illegal instruction error";
  142. error_length = 25;
  143. break; }
  144. case SIGSEGV: {
  145. error = "Bad memory read/write error";
  146. error_length = 27;
  147. break; }
  148. case SIGBUS: {
  149. error = "Access misalligned memory or non-existent memory error";
  150. error_length = 54;
  151. break; }
  152. case SIGTERM: {
  153. error = "Terminate signal from linux kill -SIGTERM <pid>";
  154. error_length = 49;
  155. break; }
  156. case SIGTSTP: {
  157. error = "Terminate signal from keyboard CTRL Z";
  158. error_length = 37;
  159. break; }
  160. case SIGINT: {
  161. error = "Terminate signal from keyboard CTRL C.";
  162. error_length = 37;
  163. break; }
  164. default: {
  165. error = "Unknown signal error";
  166. error_length = 20;
  167. break; }
  168. }
  169. DisplayErrorMessage(error,error_length);
  170. return;
  171. }
  172. int StackTrace::Itoa(int value,char *buffer)
  173. {
  174. char *pos = buffer;
  175. int divisor = 1000000000;
  176. int digit;
  177. if (value < 0)
  178. {
  179. *(pos++) = '-';
  180. value = -value;
  181. }
  182. if (value == 0)
  183. {
  184. *(pos++) = '0';
  185. } else
  186. {
  187. while (divisor > value)
  188. {
  189. divisor /= 10;
  190. }
  191. while(divisor > 0)
  192. {
  193. digit = value / divisor;
  194. value -= digit * divisor;
  195. *(pos++) = digit + '0';
  196. divisor /= 10;
  197. }
  198. }
  199. *pos = 0;
  200. return pos - buffer;
  201. }
  202. const char *StackTrace::basename(const char *filename)
  203. {
  204. const char *loop;
  205. const char *basename;
  206. char ch;
  207. basename = filename;
  208. loop = filename;
  209. do {
  210. ch = *(loop++);
  211. if ((ch == '/') || (ch == '\\')) {
  212. basename = loop;
  213. }
  214. } while (ch != 0);
  215. return basename;
  216. }