StackTrace.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright (c) 2009, 2020 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 
17 #include "StackTrace.h"
18 #include "Log.h"
19 #include "LinkedList.h"
20 
21 #include "Clients.h"
22 #include "Thread.h"
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 
28 #if defined(_WIN32) || defined(_WIN64)
29 #define snprintf _snprintf
30 #endif
31 
32 /*BE
33 def STACKENTRY
34 {
35  n32 ptr STRING open "name"
36  n32 dec "line"
37 }
38 
39 defList(STACKENTRY)
40 BE*/
41 
42 #define MAX_STACK_DEPTH 50
43 #define MAX_FUNCTION_NAME_LENGTH 30
44 #define MAX_THREADS 255
45 
46 typedef struct
47 {
50  int line;
51 } stackEntry;
52 
53 typedef struct
54 {
56  int maxdepth;
59 } threadEntry;
60 
61 #include "StackTrace.h"
62 
63 #if !defined(NOSTACKTRACE)
64 
65 static int thread_count = 0;
67 static threadEntry *my_thread = NULL;
68 
69 #if defined(_WIN32) || defined(_WIN64)
71 #else
72 static pthread_mutex_t stack_mutex_store = PTHREAD_MUTEX_INITIALIZER;
74 #endif
75 
76 
77 int setStack(int create);
78 
79 
80 int setStack(int create)
81 {
82  int i = -1;
83  thread_id_type curid = Thread_getid();
84 
85  my_thread = NULL;
86  for (i = 0; i < MAX_THREADS && i < thread_count; ++i)
87  {
88  if (threads[i].id == curid)
89  {
90  my_thread = &threads[i];
91  break;
92  }
93  }
94 
95  if (my_thread == NULL && create && thread_count < MAX_THREADS)
96  {
97  my_thread = &threads[thread_count];
98  my_thread->id = curid;
99  my_thread->maxdepth = 0;
100  my_thread->current_depth = 0;
101  ++thread_count;
102  }
103  return my_thread != NULL; /* good == 1 */
104 }
105 
106 void StackTrace_entry(const char* name, int line, enum LOG_LEVELS trace_level)
107 {
109  if (!setStack(1))
110  goto exit;
111  if (trace_level != -1)
112  Log_stackTrace(trace_level, 9, (int)my_thread->id, my_thread->current_depth, name, line, NULL);
113  strncpy(my_thread->callstack[my_thread->current_depth].name, name, sizeof(my_thread->callstack[0].name)-1);
114  my_thread->callstack[(my_thread->current_depth)++].line = line;
115  if (my_thread->current_depth > my_thread->maxdepth)
116  my_thread->maxdepth = my_thread->current_depth;
117  if (my_thread->current_depth >= MAX_STACK_DEPTH)
118  Log(LOG_FATAL, -1, "Max stack depth exceeded");
119 exit:
121 }
122 
123 
124 void StackTrace_exit(const char* name, int line, void* rc, enum LOG_LEVELS trace_level)
125 {
127  if (!setStack(0))
128  goto exit;
129  if (--(my_thread->current_depth) < 0)
130  Log(LOG_FATAL, -1, "Minimum stack depth exceeded for thread %lu", my_thread->id);
131  if (strncmp(my_thread->callstack[my_thread->current_depth].name, name, sizeof(my_thread->callstack[0].name)-1) != 0)
132  Log(LOG_FATAL, -1, "Stack mismatch. Entry:%s Exit:%s\n", my_thread->callstack[my_thread->current_depth].name, name);
133  if (trace_level != -1)
134  {
135  if (rc == NULL)
136  Log_stackTrace(trace_level, 10, (int)my_thread->id, my_thread->current_depth, name, line, NULL);
137  else
138  Log_stackTrace(trace_level, 11, (int)my_thread->id, my_thread->current_depth, name, line, (int*)rc);
139  }
140 exit:
142 }
143 
144 
145 void StackTrace_printStack(FILE* dest)
146 {
147  FILE* file = stdout;
148  int t = 0;
149 
150  if (dest)
151  file = dest;
152  for (t = 0; t < thread_count; ++t)
153  {
154  threadEntry *cur_thread = &threads[t];
155 
156  if (cur_thread->id > 0)
157  {
158  int i = cur_thread->current_depth - 1;
159 
160  fprintf(file, "=========== Start of stack trace for thread %lu ==========\n", (unsigned long)cur_thread->id);
161  if (i >= 0)
162  {
163  fprintf(file, "%s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
164  while (--i >= 0)
165  fprintf(file, " at %s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
166  }
167  fprintf(file, "=========== End of stack trace for thread %lu ==========\n\n", (unsigned long)cur_thread->id);
168  }
169  }
170  if (file != stdout && file != stderr && file != NULL)
171  fclose(file);
172 }
173 
174 
175 char* StackTrace_get(thread_id_type threadid, char* buf, int bufsize)
176 {
177  int t = 0;
178 
179  if (bufsize < 100)
180  goto exit;
181  buf[0] = '\0';
182  for (t = 0; t < thread_count; ++t)
183  {
184  threadEntry *cur_thread = &threads[t];
185 
186  if (cur_thread->id == threadid)
187  {
188  int i = cur_thread->current_depth - 1;
189  int curpos = 0;
190 
191  if (i >= 0)
192  {
193  curpos += snprintf(&buf[curpos], bufsize - curpos -1,
194  "%s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
195  while (--i >= 0)
196  curpos += snprintf(&buf[curpos], bufsize - curpos -1, /* lgtm [cpp/overflowing-snprintf] */
197  " at %s (%d)\n", cur_thread->callstack[i].name, cur_thread->callstack[i].line);
198  if (buf[--curpos] == '\n')
199  buf[curpos] = '\0';
200  }
201  break;
202  }
203  }
204 exit:
205  return buf;
206 }
207 
208 #endif
Definition: Log.h:43
void StackTrace_exit(const char *name, int line, void *rc, enum LOG_LEVELS trace_level)
Definition: StackTrace.c:124
LOG_LEVELS
Definition: Log.h:35
stackEntry callstack[MAX_STACK_DEPTH]
Definition: StackTrace.c:58
int Thread_lock_mutex(mutex_type mutex)
Definition: Thread.c:112
static int thread_count
Definition: StackTrace.c:65
void StackTrace_entry(const char *name, int line, enum LOG_LEVELS trace_level)
Definition: StackTrace.c:106
thread_id_type threadid
Definition: StackTrace.c:48
char * StackTrace_get(thread_id_type threadid, char *buf, int bufsize)
Definition: StackTrace.c:175
static mutex_type stack_mutex
Definition: StackTrace.c:73
#define MAX_THREADS
Definition: StackTrace.c:44
int maxdepth
Definition: StackTrace.c:56
static pthread_mutex_t stack_mutex_store
Definition: StackTrace.c:72
int Thread_unlock_mutex(mutex_type mutex)
Definition: Thread.c:133
#define MAX_FUNCTION_NAME_LENGTH
Definition: StackTrace.c:43
thread_id_type id
Definition: StackTrace.c:55
void Log(enum LOG_LEVELS log_level, int msgno, const char *format,...)
Definition: Log.c:417
#define mutex_type
Definition: mutex_type.h:22
int setStack(int create)
Definition: StackTrace.c:80
void Log_stackTrace(enum LOG_LEVELS log_level, int msgno, int thread_id, int current_depth, const char *name, int line, int *rc)
Definition: Log.c:448
const char * name
static threadEntry * my_thread
Definition: StackTrace.c:67
thread_id_type Thread_getid(void)
Definition: Thread.c:176
int current_depth
Definition: StackTrace.c:57
void StackTrace_printStack(FILE *dest)
Definition: StackTrace.c:145
const new_table create
Definition: sol.hpp:7100
#define thread_id_type
Definition: Thread.h:43
char name[MAX_FUNCTION_NAME_LENGTH]
Definition: StackTrace.c:49
enum MQTTReasonCodes rc
Definition: test10.c:1112
#define MAX_STACK_DEPTH
Definition: StackTrace.c:42
static threadEntry threads[MAX_THREADS]
Definition: StackTrace.c:66


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 04:02:47